Index: contrib/isl/.gitignore =================================================================== --- /dev/null +++ contrib/isl/.gitignore @@ -0,0 +1,56 @@ +# ignore objects and archives +*.[oa] +*.lo +*.la + +.deps/ +.libs/ +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +config.guess +isl_config.h +isl_config.h.in +isl_config.h.in~ +compile +config.log +config.status +config.sub +configure +depcomp +doc/Makefile +doc/Makefile.in +gitversion.h +include/isl/config.h +include/isl/stdint.h +include/stamp-h2 +include/isl/stamp-h2 +install-sh +isl-uninstalled.pc +isl-uninstalled.sh +isl.pc +isl.pc.in +isl_bound +isl_cat +isl_closure +isl_pip +isl_polyhedron_detect_equalities +isl_polyhedron_minimize +isl_polyhedron_sample +isl_polytope_scan +isl_test +libtool +ltmain.sh +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +missing +stamp-h1 +test-driver + +isl_srcdir.c +bound_test.sh +pip_test.sh Index: contrib/isl/.gitmodules =================================================================== --- /dev/null +++ contrib/isl/.gitmodules @@ -0,0 +1,3 @@ +[submodule "imath"] + path = imath + url = https://github.com/creachadair/imath.git Index: contrib/isl/AUTHORS =================================================================== --- /dev/null +++ contrib/isl/AUTHORS @@ -0,0 +1,46 @@ +isl was written by + + Sven Verdoolaege +2006-2007 Leiden Institute of Advanced Computer Science + Universiteit Leiden + Niels Bohrweg 1 + 2333 CA Leiden + The Netherlands +2008-2009 K.U.Leuven + Departement Computerwetenschappen + Celestijnenlaan 200A + B-3001 Leuven + Belgium +2010-2011 INRIA Saclay - Ile-de-France + Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod + 91893 Orsay + France +2011-2012 consultant for Leiden Institute of Advanced Computer Science +2012-2014 Ecole Normale Superieure + 45 rue d'Ulm, 75230 Paris + France +2014-2015 INRIA Rocquencourt + Domaine de Voluceau - Rocquencourt, B.P. 105 + 78153 Le Chesnay + France +2015-2016 Polly Labs + +Contributions by + +Mythri Alle +Riyadh Baghdadi +Serge Belyshev +Ray Donnelly +Johannes Doerfert +Tobias Grosser +Alexandre Isoard +Andreas Kloeckner +Michael Kruse +Sebastian Pop +Louis-Noel Pouchet +Benoit Pradelle +Uday Kumar Reddy +Andreas Simbuerger +Sven van Haastregt + +The merge sort implementation was written by Jeffrey Stedfast. Index: contrib/isl/ChangeLog =================================================================== --- /dev/null +++ contrib/isl/ChangeLog @@ -0,0 +1,193 @@ +version: 0.18 +date: Sun Dec 18 11:01:58 CET 2016 +changes: + - improve elimination of redundant existentially quantified variables + - improve coalescing + - improve parametric integer programming + - preserve isolate option in isl_schedule_node_band_split + - print AST nodes in YAML format + - minor improvements to Python bindings +--- +version: 0.17.1 +date: Fri May 6 12:02:48 CEST 2016 +changes: + - fix bug in coalescing treatment +--- +version: 0.17 +date: Tue May 3 14:26:43 CEST 2016 +changes: + - optionally combine SCCs incrementally in scheduler + - optionally maximize coincidence in scheduler + - optionally avoid loop coalescing in scheduler + - fix handling of nested integer divisions + - optionally detect min/max expressions during AST generation + - minor AST generator improvements + - simplify stride constraints + - improve support for expansions in schedule trees +--- +version: 0.16.1 +date: Thu Jan 14 18:08:06 CET 2016 +changes: + - fix bug in simplification +--- +version: 0.16 +date: Tue Jan 12 09:56:16 CET 2016 +changes: + - add 32 bit integer optimization for IMath + - minor AST generator improvements + - add isl_union_flow_get_full_{may,must}_dependence + - minor improvements to Python bindings + - minor improvements to set and map printing +--- +version: 0.15 +date: Thu Jun 11 12:45:33 CEST 2015 +changes: + - improve coalescing + - add isl_union_access_info_compute_flow + - add mark nodes in AST + - add isl_union_pw_aff and isl_multi_union_pw_aff + - add schedule trees + - deprecate band forests + - deprecate separation_class AST generation option + - introduce isl_bool and isl_stat types +--- +version: 0.14.1 +date: Thu Apr 9 12:57:23 CEST 2015 +changes: + - fix bug in affine expression normalization + - fix handling of conditional validity constraints +--- +version: 0.14 +date: Sat Oct 25 16:08:47 CEST 2014 +changes: + - support IMath as an optional replacement for GMP + - minor AST generator improvements +--- +version: 0.13 +date: Mon Apr 14 11:08:45 CEST 2014 +changes: + - deprecate isl_int + - improved support for multi piecewise quasi-affine expressions + - allow the user to impose a bound on the number of low-level operations + - add isl_id_to_ast_expr and isl_id_to_pw_aff + - add isl_schedule_constraints + - hide internal structure of isl_vec + - remove support for piplib +--- +version: 0.12.2 +date: Sun Jan 12 12:09:46 CET 2014 +changes: + - MinGW-w64 build fix + - fix simplification bug +--- +version: 0.12.1 +date: Wed Jul 24 12:54:46 CEST 2013 +changes: + - handle malloc returning NULL on zero-size allocation + - fix regression in AST generator +--- +version: 0.12 +date: Sun Jun 23 20:23:05 CEST 2013 +changes: + - add isl_val abstraction +--- +version: 0.11.2 +date: Tue Apr 9 18:45:10 CEST 2013 +changes: + - make code generation output the same on Solaris + - fix some hard to trigger bugs +--- +version: 0.11.1 +date: Mon Dec 10 11:55:30 CET 2012 +changes: + - add LICENSE file to distribution + - make code generation output independent of endianness +--- +version: 0.11 +date: Mon Dec 3 08:17:18 CET 2012 +changes: + - change license from LGPL 2.1 to MIT + - add support for multi piecewise quasi-affine expressions + - add code generation + - various minor bug fixes +--- +version: 0.10 +date: Sun Jun 3 18:00:16 CEST 2012 +changes: + - support for interaction with dependence analysis + - add public API for vectors + - improved support for (piecewise) multi quasi-affine expressions + - various minor bug fixes +--- +version: 0.09 +date: Sat Dec 17 18:19:26 CET 2011 +changes: + - improved argument parsing + - hide internal structure of isl_options + - improved support for parameter sets + - configurable scheduling +--- +version: 0.08 +date: Fri Oct 21 12:36:20 CEST 2011 +changes: + - improved parsing + - drop isl_div abstraction + - rename isl_dim to isl_space + - |- + explicitly differentiate between spaces of maps, + sets and parameter sets + - add support for identifiers + - add support for (piecewise) multi quasi-affine expressions + - preliminary Python bindings +--- +version: 0.07 +date: Tue Jul 12 19:34:51 CEST 2011 +changes: + - hide internal structures of isl_div and isl_constraint + - preliminary scheduling + - add support for local spaces and (piecewise) quasi-affine expressions +--- +version: 0.06 +date: Fri Mar 18 15:59:16 CET 2011 +changes: + - improved parsing + - consistency changes in API + - hide internal structure of isl_ctx +--- +version: 0.05.1 +date: Wed Jan 5 10:21:42 CET 2011 +changes: + - fix simple symmetry detection in parametric integer programming +--- +version: 0.05 +date: Thu Dec 23 17:03:14 CET 2010 +changes: + - rename header files from isl_header.h to isl/header.h + - add higher level interface for dependence analysis + - improved argument parsing + - optionally triangulate domains during Bernstein expansion + - support extended PolyLib format + - hide internal structure of some data types + - improved coalescing + - add simple symmetry detection in parametric integer programming +--- +version: 0.04 +date: Fri Sep 10 12:57:50 CEST 2010 +changes: + - rename isl_pw_qpolynomial_fold_add + - add isl_map_apply_pw_qpolynomial_fold + - support named and nested spaces + - support union sets and maps + - add public API for matrices +--- +version: 0.03 +date: Tue Jun 29 13:16:46 CEST 2010 +changes: + - new printing functions + - support for "may" accesses in dependence analysis + - improved coalescing + - improved transitive closure + - fix several hard to trigger bugs + - improved argument parsing + - support parametric vertex enumeration for barvinok + - optionally use Bernstein expansion to compute bounds Index: contrib/isl/LICENSE =================================================================== --- /dev/null +++ contrib/isl/LICENSE @@ -0,0 +1,19 @@ +MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. Index: contrib/isl/Makefile.am =================================================================== --- /dev/null +++ contrib/isl/Makefile.am @@ -0,0 +1,420 @@ +if HAVE_CLANG + MAYBE_INTERFACE = interface +endif +SUBDIRS = . $(MAYBE_INTERFACE) doc +DIST_SUBDIRS = $(MAYBE_INTERFACE) doc + +ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = nostdinc subdir-objects + +lib_LTLIBRARIES = libisl.la +noinst_PROGRAMS = isl_test isl_polyhedron_sample isl_pip \ + isl_polyhedron_minimize isl_polytope_scan \ + isl_polyhedron_detect_equalities isl_cat \ + isl_closure isl_bound isl_schedule isl_codegen isl_test_int \ + isl_flow isl_flow_cmp isl_schedule_cmp +TESTS = isl_test codegen_test.sh pip_test.sh bound_test.sh isl_test_int \ + flow_test.sh schedule_test.sh + +if IMATH_FOR_MP + +MP_SRC = \ + isl_imath.c \ + isl_imath.h \ + isl_int_imath.h \ + imath_wrap/gmp_compat.h \ + imath_wrap/imath.h \ + imath_wrap/imrat.h \ + imath_wrap/wrap.h \ + imath_wrap/gmp_compat.c \ + imath_wrap/imath.c \ + imath_wrap/imrat.c + +noinst_PROGRAMS += isl_test_imath +TESTS += isl_test_imath + +if SMALL_INT_OPT +MP_SRC += isl_int_sioimath.h \ + isl_int_sioimath.c \ + isl_val_sioimath.c +else +MP_SRC += isl_val_imath.c +endif + +MP_INCLUDE_H = +endif + +if GMP_FOR_MP +if NEED_GET_MEMORY_FUNCTIONS +GET_MEMORY_FUNCTIONS=mp_get_memory_functions.c +endif + +MP_SRC = \ + $(GET_MEMORY_FUNCTIONS) \ + isl_int_gmp.h \ + isl_gmp.c \ + isl_val_gmp.c + +MP_INCLUDE_H = include/isl/val_gmp.h +endif + +AM_CPPFLAGS = -I. -I$(srcdir) -I$(srcdir)/include -Iinclude/ @MP_CPPFLAGS@ +AM_CFLAGS = @WARNING_FLAGS@ + +libisl_la_SOURCES = \ + $(MP_SRC) \ + isl_aff.c \ + isl_aff_private.h \ + isl_affine_hull.c \ + isl_arg.c \ + isl_ast.c \ + isl_ast_private.h \ + isl_ast_build.c \ + isl_ast_build_private.h \ + isl_ast_build_expr.c \ + isl_ast_build_expr.h \ + isl_ast_codegen.c \ + isl_ast_graft.c \ + isl_ast_graft_private.h \ + isl_basis_reduction.h \ + basis_reduction_tab.c \ + isl_bernstein.c \ + isl_bernstein.h \ + isl_blk.c \ + isl_blk.h \ + isl_bound.c \ + isl_bound.h \ + isl_coalesce.c \ + isl_constraint.c \ + isl_constraint_private.h \ + isl_convex_hull.c \ + isl_ctx.c \ + isl_ctx_private.h \ + isl_deprecated.c \ + isl_dim_map.h \ + isl_dim_map.c \ + isl_equalities.c \ + isl_equalities.h \ + isl_factorization.c \ + isl_factorization.h \ + isl_farkas.c \ + isl_ffs.c \ + isl_flow.c \ + isl_fold.c \ + isl_hash.c \ + isl_hash_private.h \ + isl_id_to_ast_expr.c \ + isl_id_to_id.c \ + isl_id_to_pw_aff.c \ + isl_ilp.c \ + isl_ilp_private.h \ + isl_input.c \ + isl_int.h \ + isl_local.h \ + isl_local.c \ + isl_local_space_private.h \ + isl_local_space.c \ + isl_lp.c \ + isl_lp_private.h \ + isl_map.c \ + isl_map_list.c \ + isl_map_simplify.c \ + isl_map_subtract.c \ + isl_map_private.h \ + isl_map_to_basic_set.c \ + isl_mat.c \ + isl_mat_private.h \ + isl_morph.c \ + isl_morph.h \ + isl_id.c \ + isl_id_private.h \ + isl_obj.c \ + isl_options.c \ + isl_options_private.h \ + isl_output.c \ + isl_output_private.h \ + isl_point_private.h \ + isl_point.c \ + isl_polynomial_private.h \ + isl_polynomial.c \ + isl_printer_private.h \ + isl_printer.c \ + print.c \ + isl_range.c \ + isl_range.h \ + isl_reordering.c \ + isl_reordering.h \ + isl_sample.h \ + isl_sample.c \ + isl_scan.c \ + isl_scan.h \ + isl_schedule.c \ + isl_schedule_band.c \ + isl_schedule_band.h \ + isl_schedule_node.c \ + isl_schedule_node_private.h \ + isl_schedule_read.c \ + isl_schedule_tree.c \ + isl_schedule_tree.h \ + isl_schedule_private.h \ + isl_schedule_constraints.c \ + isl_schedule_constraints.h \ + isl_scheduler.c \ + isl_set_list.c \ + isl_sort.c \ + isl_sort.h \ + isl_space.c \ + isl_space_private.h \ + isl_stream.c \ + isl_stream_private.h \ + isl_seq.c \ + isl_seq.h \ + isl_tab.c \ + isl_tab.h \ + isl_tab_pip.c \ + isl_tarjan.c \ + isl_tarjan.h \ + isl_transitive_closure.c \ + isl_union_map.c \ + isl_union_map_private.h \ + isl_union_set_private.h \ + isl_val.c \ + isl_val_private.h \ + isl_vec_private.h \ + isl_vec.c \ + isl_version.c \ + isl_vertices_private.h \ + isl_vertices.c \ + isl_yaml.h +libisl_la_LIBADD = @MP_LIBS@ +libisl_la_LDFLAGS = -version-info @versioninfo@ \ + @MP_LDFLAGS@ + +isl_test_LDFLAGS = @MP_LDFLAGS@ +isl_test_LDADD = libisl.la @MP_LIBS@ + +isl_test_int_LDFLAGS = @MP_LDFLAGS@ +isl_test_int_LDADD = libisl.la @MP_LIBS@ + +if IMATH_FOR_MP +isl_test_imath_LDFLAGS = @MP_LDFLAGS@ +isl_test_imath_LDADD = libisl.la @MP_LIBS@ +endif + +isl_polyhedron_sample_LDADD = libisl.la +isl_polyhedron_sample_SOURCES = \ + polyhedron_sample.c + +isl_pip_LDFLAGS = @MP_LDFLAGS@ +isl_pip_LDADD = libisl.la @MP_LIBS@ +isl_pip_SOURCES = \ + pip.c + +isl_schedule_LDFLAGS = @MP_LDFLAGS@ +isl_schedule_LDADD = libisl.la @MP_LIBS@ +isl_schedule_SOURCES = \ + schedule.c + +isl_schedule_cmp_LDFLAGS = @MP_LDFLAGS@ +isl_schedule_cmp_LDADD = libisl.la @MP_LIBS@ +isl_schedule_cmp_SOURCES = \ + schedule_cmp.c + +isl_flow_LDFLAGS = @MP_LDFLAGS@ +isl_flow_LDADD = libisl.la @MP_LIBS@ +isl_flow_SOURCES = \ + flow.c + +isl_flow_cmp_LDFLAGS = @MP_LDFLAGS@ +isl_flow_cmp_LDADD = libisl.la @MP_LIBS@ +isl_flow_cmp_SOURCES = \ + flow_cmp.c + +isl_codegen_LDFLAGS = @MP_LDFLAGS@ +isl_codegen_LDADD = libisl.la @MP_LIBS@ +isl_codegen_SOURCES = \ + codegen.c + +isl_bound_LDFLAGS = @MP_LDFLAGS@ +isl_bound_LDADD = libisl.la @MP_LIBS@ +isl_bound_SOURCES = \ + bound.c + +isl_polyhedron_minimize_LDFLAGS = @MP_LDFLAGS@ +isl_polyhedron_minimize_LDADD = libisl.la @MP_LIBS@ +isl_polyhedron_minimize_SOURCES = \ + polyhedron_minimize.c + +isl_polytope_scan_LDADD = libisl.la +isl_polytope_scan_SOURCES = \ + polytope_scan.c + +isl_polyhedron_detect_equalities_LDADD = libisl.la +isl_polyhedron_detect_equalities_SOURCES = \ + polyhedron_detect_equalities.c + +isl_cat_LDADD = libisl.la +isl_cat_SOURCES = \ + cat.c + +isl_closure_LDADD = libisl.la +isl_closure_SOURCES = \ + closure.c + +nodist_pkginclude_HEADERS = \ + include/isl/stdint.h +pkginclude_HEADERS = \ + $(MP_INCLUDE_H) \ + include/isl/aff.h \ + include/isl/aff_type.h \ + include/isl/arg.h \ + include/isl/ast.h \ + include/isl/ast_type.h \ + include/isl/ast_build.h \ + include/isl/constraint.h \ + include/isl/ctx.h \ + include/isl/flow.h \ + include/isl/id.h \ + include/isl/id_to_ast_expr.h \ + include/isl/id_to_id.h \ + include/isl/id_to_pw_aff.h \ + include/isl/ilp.h \ + include/isl/hash.h \ + include/isl/hmap.h \ + include/isl/hmap_templ.c \ + include/isl/list.h \ + include/isl/local_space.h \ + include/isl/lp.h \ + include/isl/mat.h \ + include/isl/map.h \ + include/isl/map_to_basic_set.h \ + include/isl/map_type.h \ + include/isl/maybe.h \ + include/isl/maybe_ast_expr.h \ + include/isl/maybe_basic_set.h \ + include/isl/maybe_id.h \ + include/isl/maybe_pw_aff.h \ + include/isl/maybe_templ.h \ + include/isl/multi.h \ + include/isl/obj.h \ + include/isl/options.h \ + include/isl/point.h \ + include/isl/polynomial.h \ + include/isl/polynomial_type.h \ + include/isl/printer.h \ + include/isl/printer_type.h \ + include/isl/schedule.h \ + include/isl/schedule_node.h \ + include/isl/schedule_type.h \ + include/isl/set.h \ + include/isl/set_type.h \ + include/isl/space.h \ + include/isl/stream.h \ + include/isl/union_map.h \ + include/isl/union_map_type.h \ + include/isl/union_set.h \ + include/isl/union_set_type.h \ + include/isl/val.h \ + include/isl/vec.h \ + include/isl/version.h \ + include/isl/vertices.h + +BUILT_SOURCES = gitversion.h + +CLEANFILES = \ + gitversion.h + +DISTCLEANFILES = \ + isl-uninstalled.sh \ + isl-uninstalled.pc \ + isl.pc \ + isl.pc.in \ + include/isl/stdint.h + +EXTRA_DIST = \ + LICENSE \ + isl_config_post.h \ + basis_reduction_templ.c \ + bset_to_bmap.c \ + bset_from_bmap.c \ + extract_key.c \ + isl_list_templ.c \ + isl_list_templ.h \ + isl_map_lexopt_templ.c \ + isl_maybe_map.h \ + isl_multi_macro.h \ + isl_multi_templ.c \ + isl_multi_templ.h \ + isl_multi_apply_templ.c \ + isl_multi_apply_set.c \ + isl_multi_apply_union_set.c \ + isl_multi_cmp.c \ + isl_multi_coalesce.c \ + isl_multi_floor.c \ + isl_multi_gist.c \ + isl_multi_hash.c \ + isl_multi_intersect.c \ + print_templ.c \ + print_templ_yaml.c \ + isl_power_templ.c \ + isl_pw_macro.h \ + isl_pw_templ.c \ + isl_pw_hash.c \ + isl_pw_union_opt.c \ + read_in_string_templ.c \ + set_to_map.c \ + set_from_map.c \ + isl_tab_lexopt_templ.c \ + isl_union_macro.h \ + isl_union_templ.c \ + isl_union_single.c \ + isl_union_multi.c \ + isl_union_eval.c \ + isl_union_neg.c \ + isl.py \ + doc/CodingStyle \ + doc/SubmittingPatches \ + doc/implementation.tex \ + doc/isl.bib \ + doc/mypod2latex \ + doc/manual.tex \ + doc/reading.tex \ + doc/user.pod \ + imath/gmp_compat.c \ + imath/gmp_compat.h \ + imath/imath.c \ + imath/imath.h \ + imath/imrat.c \ + imath/imrat.h \ + interface/all.h \ + interface/isl-noexceptions.h.top \ + interface/isl.py.top \ + test_inputs + +dist-hook: + echo @GIT_HEAD_VERSION@ > $(distdir)/GIT_HEAD_ID + (cd doc; make manual.pdf) + cp doc/manual.pdf $(distdir)/doc/ + +pkgconfigdir=$(pkgconfig_libdir) +pkgconfig_DATA = $(pkgconfig_libfile) + +gitversion.h: @GIT_HEAD@ + $(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;}" \ + $(builddir)/libisl.la`; \ + case $$libisl in \ + '') echo Cannot find isl library name. GDB bindings not installed.;; \ + *) echo $(INSTALL_DATA) $(srcdir)/isl.py \ + $(DESTDIR)$(libdir)/$$libisl-gdb.py; \ + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"; \ + $(INSTALL_DATA) $(srcdir)/isl.py $(DESTDIR)$(libdir)/$$libisl-gdb.py; esac + +uninstall-local: + @libisl=`sed -ne "/^library_names=/{s/.*='//;s/'$$//;s/ .*//;p;}" \ + $(builddir)/libisl.la`; \ + if test -n "$${libisl}"; then \ + rm -f $(DESTDIR)$(libdir)/$$libisl-gdb.py; \ + fi Index: contrib/isl/README =================================================================== --- /dev/null +++ contrib/isl/README @@ -0,0 +1,53 @@ +isl is a thread-safe C library for manipulating sets and relations +of integer points bounded by affine constraints. The descriptions of +the sets and relations may involve both parameters and existentially +quantified variables. All computations are performed in exact integer +arithmetic using GMP. + +isl is released under the MIT license, but depends on the LGPL GMP +library. + +Minimal compilation instructions: + + ./configure + make + make install + +If you are taking the source from the git repository, then you first +need to do + + git clone git://repo.or.cz/isl.git + ./autogen.sh + +For more information, see doc/user.pod or the generated documentation. + +New releases are announced on http://freecode.com/projects/isl + +If you use isl, you can let me know by stacking +https://www.ohloh.net/p/isl on ohloh. + +For bug reports, feature requests and questions, +contact http://groups.google.com/group/isl-development + +Whenever you report a bug, please mention the exact version of isl +that you are using (output of "./isl_cat --version"). If you are unable +to compile isl, then report the git version (output of "git describe") +or the version included in the name of the tarball. + +If you use isl for your research, you are invited do cite +the following paper and/or the paper(s) describing the specific +operations you use. + +@incollection{Verdoolaege2010isl, + author = {Verdoolaege, Sven}, + title = {isl: An Integer Set Library for the Polyhedral Model}, + booktitle = {Mathematical Software - ICMS 2010}, + series = {Lecture Notes in Computer Science}, + editor = {Fukuda, Komei and Hoeven, Joris and Joswig, Michael and + Takayama, Nobuki}, + publisher = {Springer}, + isbn = {978-3-642-15581-9}, + pages = {299-302}, + volume = {6327}, + year = {2010} +} Index: contrib/isl/autogen.sh =================================================================== --- /dev/null +++ contrib/isl/autogen.sh @@ -0,0 +1,2 @@ +#!/bin/sh +autoreconf -i Index: contrib/isl/basis_reduction_tab.c =================================================================== --- /dev/null +++ contrib/isl/basis_reduction_tab.c @@ -0,0 +1,293 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include "isl_tab.h" +#include +#include + +struct tab_lp { + struct isl_ctx *ctx; + struct isl_vec *row; + struct isl_tab *tab; + struct isl_tab_undo **stack; + isl_int *obj; + isl_int opt; + isl_int opt_denom; + isl_int tmp; + isl_int tmp2; + int neq; + unsigned dim; + /* number of constraints in initial product tableau */ + int con_offset; + /* objective function has fixed or no integer value */ + int is_fixed; +}; + +#ifdef USE_GMP_FOR_MP +#define GBR_type mpq_t +#define GBR_init(v) mpq_init(v) +#define GBR_clear(v) mpq_clear(v) +#define GBR_set(a,b) mpq_set(a,b) +#define GBR_set_ui(a,b) mpq_set_ui(a,b,1) +#define GBR_mul(a,b,c) mpq_mul(a,b,c) +#define GBR_lt(a,b) (mpq_cmp(a,b) < 0) +#define GBR_is_zero(a) (mpq_sgn(a) == 0) +#define GBR_numref(a) mpq_numref(a) +#define GBR_denref(a) mpq_denref(a) +#define GBR_floor(a,b) mpz_fdiv_q(a,GBR_numref(b),GBR_denref(b)) +#define GBR_ceil(a,b) mpz_cdiv_q(a,GBR_numref(b),GBR_denref(b)) +#define GBR_set_num_neg(a, b) mpz_neg(GBR_numref(*a), b); +#define GBR_set_den(a, b) mpz_set(GBR_denref(*a), b); +#endif /* USE_GMP_FOR_MP */ + +#ifdef USE_IMATH_FOR_MP +#include + +#define GBR_type mp_rat +#define GBR_init(v) v = mp_rat_alloc() +#define GBR_clear(v) mp_rat_free(v) +#define GBR_set(a,b) mp_rat_copy(b,a) +#define GBR_set_ui(a,b) mp_rat_set_uvalue(a,b,1) +#define GBR_mul(a,b,c) mp_rat_mul(b,c,a) +#define GBR_lt(a,b) (mp_rat_compare(a,b) < 0) +#define GBR_is_zero(a) (mp_rat_compare_zero(a) == 0) +#ifdef USE_SMALL_INT_OPT +#define GBR_numref(a) isl_sioimath_encode_big(mp_rat_numer_ref(a)) +#define GBR_denref(a) isl_sioimath_encode_big(mp_rat_denom_ref(a)) +#define GBR_floor(a, b) isl_sioimath_fdiv_q((a), GBR_numref(b), GBR_denref(b)) +#define GBR_ceil(a, b) isl_sioimath_cdiv_q((a), GBR_numref(b), GBR_denref(b)) +#define GBR_set_num_neg(a, b) \ + do { \ + isl_sioimath_scratchspace_t scratch; \ + impz_neg(mp_rat_numer_ref(*a), \ + isl_sioimath_bigarg_src(*b, &scratch));\ + } while (0) +#define GBR_set_den(a, b) \ + do { \ + isl_sioimath_scratchspace_t scratch; \ + impz_set(mp_rat_denom_ref(*a), \ + isl_sioimath_bigarg_src(*b, &scratch));\ + } while (0) +#else /* USE_SMALL_INT_OPT */ +#define GBR_numref(a) mp_rat_numer_ref(a) +#define GBR_denref(a) mp_rat_denom_ref(a) +#define GBR_floor(a,b) impz_fdiv_q(a,GBR_numref(b),GBR_denref(b)) +#define GBR_ceil(a,b) impz_cdiv_q(a,GBR_numref(b),GBR_denref(b)) +#define GBR_set_num_neg(a, b) impz_neg(GBR_numref(*a), b) +#define GBR_set_den(a, b) impz_set(GBR_denref(*a), b) +#endif /* USE_SMALL_INT_OPT */ +#endif /* USE_IMATH_FOR_MP */ + +static struct tab_lp *init_lp(struct isl_tab *tab); +static void set_lp_obj(struct tab_lp *lp, isl_int *row, int dim); +static int solve_lp(struct tab_lp *lp); +static void get_obj_val(struct tab_lp* lp, GBR_type *F); +static void delete_lp(struct tab_lp *lp); +static int add_lp_row(struct tab_lp *lp, isl_int *row, int dim); +static void get_alpha(struct tab_lp* lp, int row, GBR_type *alpha); +static int del_lp_row(struct tab_lp *lp) WARN_UNUSED; +static int cut_lp_to_hyperplane(struct tab_lp *lp, isl_int *row); + +#define GBR_LP struct tab_lp +#define GBR_lp_init(P) init_lp(P) +#define GBR_lp_set_obj(lp, obj, dim) set_lp_obj(lp, obj, dim) +#define GBR_lp_solve(lp) solve_lp(lp) +#define GBR_lp_get_obj_val(lp, F) get_obj_val(lp, F) +#define GBR_lp_delete(lp) delete_lp(lp) +#define GBR_lp_next_row(lp) lp->neq +#define GBR_lp_add_row(lp, row, dim) add_lp_row(lp, row, dim) +#define GBR_lp_get_alpha(lp, row, alpha) get_alpha(lp, row, alpha) +#define GBR_lp_del_row(lp) del_lp_row(lp) +#define GBR_lp_is_fixed(lp) (lp)->is_fixed +#define GBR_lp_cut(lp, obj) cut_lp_to_hyperplane(lp, obj) +#include "basis_reduction_templ.c" + +/* Set up a tableau for the Cartesian product of bset with itself. + * This could be optimized by first setting up a tableau for bset + * and then performing the Cartesian product on the tableau. + */ +static struct isl_tab *gbr_tab(struct isl_tab *tab, struct isl_vec *row) +{ + unsigned dim; + struct isl_tab *prod; + + if (!tab || !row) + return NULL; + + dim = tab->n_var; + prod = isl_tab_product(tab, tab); + if (isl_tab_extend_cons(prod, 3 * dim + 1) < 0) { + isl_tab_free(prod); + return NULL; + } + return prod; +} + +static struct tab_lp *init_lp(struct isl_tab *tab) +{ + struct tab_lp *lp = NULL; + + if (!tab) + return NULL; + + lp = isl_calloc_type(tab->mat->ctx, struct tab_lp); + if (!lp) + return NULL; + + isl_int_init(lp->opt); + isl_int_init(lp->opt_denom); + isl_int_init(lp->tmp); + isl_int_init(lp->tmp2); + + lp->dim = tab->n_var; + + lp->ctx = tab->mat->ctx; + isl_ctx_ref(lp->ctx); + + lp->stack = isl_alloc_array(lp->ctx, struct isl_tab_undo *, lp->dim); + + lp->row = isl_vec_alloc(lp->ctx, 1 + 2 * lp->dim); + if (!lp->row) + goto error; + lp->tab = gbr_tab(tab, lp->row); + if (!lp->tab) + goto error; + lp->con_offset = lp->tab->n_con; + lp->obj = NULL; + lp->neq = 0; + + return lp; +error: + delete_lp(lp); + return NULL; +} + +static void set_lp_obj(struct tab_lp *lp, isl_int *row, int dim) +{ + lp->obj = row; +} + +static int solve_lp(struct tab_lp *lp) +{ + enum isl_lp_result res; + unsigned flags = 0; + + lp->is_fixed = 0; + + isl_int_set_si(lp->row->el[0], 0); + isl_seq_cpy(lp->row->el + 1, lp->obj, lp->dim); + isl_seq_neg(lp->row->el + 1 + lp->dim, lp->obj, lp->dim); + if (lp->neq) + flags = ISL_TAB_SAVE_DUAL; + res = isl_tab_min(lp->tab, lp->row->el, lp->ctx->one, + &lp->opt, &lp->opt_denom, flags); + isl_int_mul_ui(lp->opt_denom, lp->opt_denom, 2); + if (isl_int_abs_lt(lp->opt, lp->opt_denom)) { + struct isl_vec *sample = isl_tab_get_sample_value(lp->tab); + if (!sample) + return -1; + isl_seq_inner_product(lp->obj, sample->el + 1, lp->dim, &lp->tmp); + isl_seq_inner_product(lp->obj, sample->el + 1 + lp->dim, lp->dim, &lp->tmp2); + isl_int_cdiv_q(lp->tmp, lp->tmp, sample->el[0]); + isl_int_fdiv_q(lp->tmp2, lp->tmp2, sample->el[0]); + if (isl_int_ge(lp->tmp, lp->tmp2)) + lp->is_fixed = 1; + isl_vec_free(sample); + } + isl_int_divexact_ui(lp->opt_denom, lp->opt_denom, 2); + if (res < 0) + return -1; + if (res != isl_lp_ok) + isl_die(lp->ctx, isl_error_internal, + "unexpected missing (bounded) solution", return -1); + return 0; +} + +/* The current objective function has a fixed (or no) integer value. + * Cut the tableau to the hyperplane that fixes this value in + * both halves of the tableau. + * Return 1 if the resulting tableau is empty. + */ +static int cut_lp_to_hyperplane(struct tab_lp *lp, isl_int *row) +{ + enum isl_lp_result res; + + isl_int_set_si(lp->row->el[0], 0); + isl_seq_cpy(lp->row->el + 1, row, lp->dim); + isl_seq_clr(lp->row->el + 1 + lp->dim, lp->dim); + res = isl_tab_min(lp->tab, lp->row->el, lp->ctx->one, + &lp->tmp, NULL, 0); + if (res != isl_lp_ok) + return -1; + + isl_int_neg(lp->row->el[0], lp->tmp); + if (isl_tab_add_eq(lp->tab, lp->row->el) < 0) + return -1; + + isl_seq_cpy(lp->row->el + 1 + lp->dim, row, lp->dim); + isl_seq_clr(lp->row->el + 1, lp->dim); + if (isl_tab_add_eq(lp->tab, lp->row->el) < 0) + return -1; + + lp->con_offset += 2; + + return lp->tab->empty; +} + +static void get_obj_val(struct tab_lp* lp, GBR_type *F) +{ + GBR_set_num_neg(F, lp->opt); + GBR_set_den(F, lp->opt_denom); +} + +static void delete_lp(struct tab_lp *lp) +{ + if (!lp) + return; + + isl_int_clear(lp->opt); + isl_int_clear(lp->opt_denom); + isl_int_clear(lp->tmp); + isl_int_clear(lp->tmp2); + isl_vec_free(lp->row); + free(lp->stack); + isl_tab_free(lp->tab); + isl_ctx_deref(lp->ctx); + free(lp); +} + +static int add_lp_row(struct tab_lp *lp, isl_int *row, int dim) +{ + lp->stack[lp->neq] = isl_tab_snap(lp->tab); + + isl_int_set_si(lp->row->el[0], 0); + isl_seq_cpy(lp->row->el + 1, row, lp->dim); + isl_seq_neg(lp->row->el + 1 + lp->dim, row, lp->dim); + + if (isl_tab_add_valid_eq(lp->tab, lp->row->el) < 0) + return -1; + + return lp->neq++; +} + +static void get_alpha(struct tab_lp* lp, int row, GBR_type *alpha) +{ + row += lp->con_offset; + GBR_set_num_neg(alpha, lp->tab->dual->el[1 + row]); + GBR_set_den(alpha, lp->tab->dual->el[0]); +} + +static int del_lp_row(struct tab_lp *lp) +{ + lp->neq--; + return isl_tab_rollback(lp->tab, lp->stack[lp->neq]); +} Index: contrib/isl/basis_reduction_templ.c =================================================================== --- /dev/null +++ contrib/isl/basis_reduction_templ.c @@ -0,0 +1,357 @@ +/* + * Copyright 2006-2007 Universiteit Leiden + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science, + * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands + * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A, + * B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include +#include +#include "isl_basis_reduction.h" + +static void save_alpha(GBR_LP *lp, int first, int n, GBR_type *alpha) +{ + int i; + + for (i = 0; i < n; ++i) + GBR_lp_get_alpha(lp, first + i, &alpha[i]); +} + +/* Compute a reduced basis for the set represented by the tableau "tab". + * tab->basis, which must be initialized by the calling function to an affine + * unimodular basis, is updated to reflect the reduced basis. + * The first tab->n_zero rows of the basis (ignoring the constant row) + * are assumed to correspond to equalities and are left untouched. + * tab->n_zero is updated to reflect any additional equalities that + * have been detected in the first rows of the new basis. + * The final tab->n_unbounded rows of the basis are assumed to correspond + * to unbounded directions and are also left untouched. + * In particular this means that the remaining rows are assumed to + * correspond to bounded directions. + * + * This function implements the algorithm described in + * "An Implementation of the Generalized Basis Reduction Algorithm + * for Integer Programming" of Cook el al. to compute a reduced basis. + * We use \epsilon = 1/4. + * + * If ctx->opt->gbr_only_first is set, the user is only interested + * in the first direction. In this case we stop the basis reduction when + * the width in the first direction becomes smaller than 2. + */ +struct isl_tab *isl_tab_compute_reduced_basis(struct isl_tab *tab) +{ + unsigned dim; + struct isl_ctx *ctx; + struct isl_mat *B; + int i; + GBR_LP *lp = NULL; + GBR_type F_old, alpha, F_new; + int row; + isl_int tmp; + struct isl_vec *b_tmp; + GBR_type *F = NULL; + GBR_type *alpha_buffer[2] = { NULL, NULL }; + GBR_type *alpha_saved; + GBR_type F_saved; + int use_saved = 0; + isl_int mu[2]; + GBR_type mu_F[2]; + GBR_type two; + GBR_type one; + int empty = 0; + int fixed = 0; + int fixed_saved = 0; + int mu_fixed[2]; + int n_bounded; + int gbr_only_first; + + if (!tab) + return NULL; + + if (tab->empty) + return tab; + + ctx = tab->mat->ctx; + gbr_only_first = ctx->opt->gbr_only_first; + dim = tab->n_var; + B = tab->basis; + if (!B) + return tab; + + n_bounded = dim - tab->n_unbounded; + if (n_bounded <= tab->n_zero + 1) + return tab; + + isl_int_init(tmp); + isl_int_init(mu[0]); + isl_int_init(mu[1]); + + GBR_init(alpha); + GBR_init(F_old); + GBR_init(F_new); + GBR_init(F_saved); + GBR_init(mu_F[0]); + GBR_init(mu_F[1]); + GBR_init(two); + GBR_init(one); + + b_tmp = isl_vec_alloc(ctx, dim); + if (!b_tmp) + goto error; + + F = isl_alloc_array(ctx, GBR_type, n_bounded); + alpha_buffer[0] = isl_alloc_array(ctx, GBR_type, n_bounded); + alpha_buffer[1] = isl_alloc_array(ctx, GBR_type, n_bounded); + alpha_saved = alpha_buffer[0]; + + if (!F || !alpha_buffer[0] || !alpha_buffer[1]) + goto error; + + for (i = 0; i < n_bounded; ++i) { + GBR_init(F[i]); + GBR_init(alpha_buffer[0][i]); + GBR_init(alpha_buffer[1][i]); + } + + GBR_set_ui(two, 2); + GBR_set_ui(one, 1); + + lp = GBR_lp_init(tab); + if (!lp) + goto error; + + i = tab->n_zero; + + GBR_lp_set_obj(lp, B->row[1+i]+1, dim); + ctx->stats->gbr_solved_lps++; + if (GBR_lp_solve(lp) < 0) + goto error; + GBR_lp_get_obj_val(lp, &F[i]); + + if (GBR_lt(F[i], one)) { + if (!GBR_is_zero(F[i])) { + empty = GBR_lp_cut(lp, B->row[1+i]+1); + if (empty) + goto done; + GBR_set_ui(F[i], 0); + } + tab->n_zero++; + } + + do { + if (i+1 == tab->n_zero) { + GBR_lp_set_obj(lp, B->row[1+i+1]+1, dim); + ctx->stats->gbr_solved_lps++; + if (GBR_lp_solve(lp) < 0) + goto error; + GBR_lp_get_obj_val(lp, &F_new); + fixed = GBR_lp_is_fixed(lp); + GBR_set_ui(alpha, 0); + } else + if (use_saved) { + row = GBR_lp_next_row(lp); + GBR_set(F_new, F_saved); + fixed = fixed_saved; + GBR_set(alpha, alpha_saved[i]); + } else { + row = GBR_lp_add_row(lp, B->row[1+i]+1, dim); + GBR_lp_set_obj(lp, B->row[1+i+1]+1, dim); + ctx->stats->gbr_solved_lps++; + if (GBR_lp_solve(lp) < 0) + goto error; + GBR_lp_get_obj_val(lp, &F_new); + fixed = GBR_lp_is_fixed(lp); + + GBR_lp_get_alpha(lp, row, &alpha); + + if (i > 0) + save_alpha(lp, row-i, i, alpha_saved); + + if (GBR_lp_del_row(lp) < 0) + goto error; + } + GBR_set(F[i+1], F_new); + + GBR_floor(mu[0], alpha); + GBR_ceil(mu[1], alpha); + + if (isl_int_eq(mu[0], mu[1])) + isl_int_set(tmp, mu[0]); + else { + int j; + + for (j = 0; j <= 1; ++j) { + isl_int_set(tmp, mu[j]); + isl_seq_combine(b_tmp->el, + ctx->one, B->row[1+i+1]+1, + tmp, B->row[1+i]+1, dim); + GBR_lp_set_obj(lp, b_tmp->el, dim); + ctx->stats->gbr_solved_lps++; + if (GBR_lp_solve(lp) < 0) + goto error; + GBR_lp_get_obj_val(lp, &mu_F[j]); + mu_fixed[j] = GBR_lp_is_fixed(lp); + if (i > 0) + save_alpha(lp, row-i, i, alpha_buffer[j]); + } + + if (GBR_lt(mu_F[0], mu_F[1])) + j = 0; + else + j = 1; + + isl_int_set(tmp, mu[j]); + GBR_set(F_new, mu_F[j]); + fixed = mu_fixed[j]; + alpha_saved = alpha_buffer[j]; + } + isl_seq_combine(B->row[1+i+1]+1, ctx->one, B->row[1+i+1]+1, + tmp, B->row[1+i]+1, dim); + + if (i+1 == tab->n_zero && fixed) { + if (!GBR_is_zero(F[i+1])) { + empty = GBR_lp_cut(lp, B->row[1+i+1]+1); + if (empty) + goto done; + GBR_set_ui(F[i+1], 0); + } + tab->n_zero++; + } + + GBR_set(F_old, F[i]); + + use_saved = 0; + /* mu_F[0] = 4 * F_new; mu_F[1] = 3 * F_old */ + GBR_set_ui(mu_F[0], 4); + GBR_mul(mu_F[0], mu_F[0], F_new); + GBR_set_ui(mu_F[1], 3); + GBR_mul(mu_F[1], mu_F[1], F_old); + if (GBR_lt(mu_F[0], mu_F[1])) { + B = isl_mat_swap_rows(B, 1 + i, 1 + i + 1); + if (i > tab->n_zero) { + use_saved = 1; + GBR_set(F_saved, F_new); + fixed_saved = fixed; + if (GBR_lp_del_row(lp) < 0) + goto error; + --i; + } else { + GBR_set(F[tab->n_zero], F_new); + if (gbr_only_first && GBR_lt(F[tab->n_zero], two)) + break; + + if (fixed) { + if (!GBR_is_zero(F[tab->n_zero])) { + empty = GBR_lp_cut(lp, B->row[1+tab->n_zero]+1); + if (empty) + goto done; + GBR_set_ui(F[tab->n_zero], 0); + } + tab->n_zero++; + } + } + } else { + GBR_lp_add_row(lp, B->row[1+i]+1, dim); + ++i; + } + } while (i < n_bounded - 1); + + if (0) { +done: + if (empty < 0) { +error: + isl_mat_free(B); + B = NULL; + } + } + + GBR_lp_delete(lp); + + if (alpha_buffer[1]) + for (i = 0; i < n_bounded; ++i) { + GBR_clear(F[i]); + GBR_clear(alpha_buffer[0][i]); + GBR_clear(alpha_buffer[1][i]); + } + free(F); + free(alpha_buffer[0]); + free(alpha_buffer[1]); + + isl_vec_free(b_tmp); + + GBR_clear(alpha); + GBR_clear(F_old); + GBR_clear(F_new); + GBR_clear(F_saved); + GBR_clear(mu_F[0]); + GBR_clear(mu_F[1]); + GBR_clear(two); + GBR_clear(one); + + isl_int_clear(tmp); + isl_int_clear(mu[0]); + isl_int_clear(mu[1]); + + tab->basis = B; + + return tab; +} + +/* Compute an affine form of a reduced basis of the given basic + * non-parametric set, which is assumed to be bounded and not + * include any integer divisions. + * The first column and the first row correspond to the constant term. + * + * If the input contains any equalities, we first create an initial + * basis with the equalities first. Otherwise, we start off with + * the identity matrix. + */ +__isl_give isl_mat *isl_basic_set_reduced_basis(__isl_keep isl_basic_set *bset) +{ + struct isl_mat *basis; + struct isl_tab *tab; + + if (!bset) + return NULL; + + if (isl_basic_set_dim(bset, isl_dim_div) != 0) + isl_die(bset->ctx, isl_error_invalid, + "no integer division allowed", return NULL); + if (isl_basic_set_dim(bset, isl_dim_param) != 0) + isl_die(bset->ctx, isl_error_invalid, + "no parameters allowed", return NULL); + + tab = isl_tab_from_basic_set(bset, 0); + if (!tab) + return NULL; + + if (bset->n_eq == 0) + tab->basis = isl_mat_identity(bset->ctx, 1 + tab->n_var); + else { + isl_mat *eq; + unsigned nvar = isl_basic_set_total_dim(bset); + 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); + tab->n_zero = bset->n_eq; + isl_mat_free(eq); + } + tab = isl_tab_compute_reduced_basis(tab); + if (!tab) + return NULL; + + basis = isl_mat_copy(tab->basis); + + isl_tab_free(tab); + + return basis; +} Index: contrib/isl/bound.c =================================================================== --- /dev/null +++ contrib/isl/bound.c @@ -0,0 +1,285 @@ +#include +#include +#include +#include +#include +#include +#include + +struct bound_options { + struct isl_options *isl; + unsigned verify; + int print_all; + int continue_on_error; +}; + +ISL_ARGS_START(struct bound_options, bound_options_args) +ISL_ARG_CHILD(struct bound_options, isl, "isl", &isl_options_args, + "isl options") +ISL_ARG_BOOL(struct bound_options, verify, 'T', "verify", 0, NULL) +ISL_ARG_BOOL(struct bound_options, print_all, 'A', "print-all", 0, NULL) +ISL_ARG_BOOL(struct bound_options, continue_on_error, '\0', "continue-on-error", 0, NULL) +ISL_ARGS_END + +ISL_ARG_DEF(bound_options, struct bound_options, bound_options_args) + +static __isl_give isl_set *set_bounds(__isl_take isl_set *set) +{ + unsigned nparam; + int i, r; + isl_point *pt, *pt2; + isl_set *box; + + nparam = isl_set_dim(set, isl_dim_param); + r = nparam >= 8 ? 5 : nparam >= 5 ? 15 : 50; + + pt = isl_set_sample_point(isl_set_copy(set)); + pt2 = isl_point_copy(pt); + + for (i = 0; i < nparam; ++i) { + pt = isl_point_add_ui(pt, isl_dim_param, i, r); + pt2 = isl_point_sub_ui(pt2, isl_dim_param, i, r); + } + + box = isl_set_box_from_points(pt, pt2); + + return isl_set_intersect(set, box); +} + +struct verify_point_bound { + struct bound_options *options; + int stride; + int n; + int exact; + int error; + + isl_pw_qpolynomial_fold *pwf; + isl_pw_qpolynomial_fold *bound; +}; + +static isl_stat verify_point(__isl_take isl_point *pnt, void *user) +{ + int i; + unsigned nparam; + struct verify_point_bound *vpb = (struct verify_point_bound *) user; + isl_val *v; + isl_ctx *ctx; + isl_pw_qpolynomial_fold *pwf; + isl_val *bound = NULL; + isl_val *opt = NULL; + isl_set *dom = NULL; + isl_printer *p; + const char *minmax; + isl_bool bounded; + int sign; + int ok; + FILE *out = vpb->options->print_all ? stdout : stderr; + + vpb->n--; + + if (1) { + minmax = "ub"; + sign = 1; + } else { + minmax = "lb"; + sign = -1; + } + + ctx = isl_point_get_ctx(pnt); + p = isl_printer_to_file(ctx, out); + + pwf = isl_pw_qpolynomial_fold_copy(vpb->pwf); + + nparam = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_param); + for (i = 0; i < nparam; ++i) { + v = isl_point_get_coordinate_val(pnt, isl_dim_param, i); + pwf = isl_pw_qpolynomial_fold_fix_val(pwf, isl_dim_param, i, v); + } + + bound = isl_pw_qpolynomial_fold_eval( + isl_pw_qpolynomial_fold_copy(vpb->bound), + isl_point_copy(pnt)); + + dom = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf)); + bounded = isl_set_is_bounded(dom); + + if (bounded < 0) + goto error; + + if (!bounded) + opt = isl_pw_qpolynomial_fold_eval( + isl_pw_qpolynomial_fold_copy(pwf), + isl_set_sample_point(isl_set_copy(dom))); + else if (sign > 0) + opt = isl_pw_qpolynomial_fold_max(isl_pw_qpolynomial_fold_copy(pwf)); + else + opt = isl_pw_qpolynomial_fold_min(isl_pw_qpolynomial_fold_copy(pwf)); + + if (vpb->exact && bounded) + ok = isl_val_eq(opt, bound); + else if (sign > 0) + ok = isl_val_le(opt, bound); + else + ok = isl_val_le(bound, opt); + if (ok < 0) + goto error; + + if (vpb->options->print_all || !ok) { + p = isl_printer_print_str(p, minmax); + p = isl_printer_print_str(p, "("); + for (i = 0; i < nparam; ++i) { + if (i) + p = isl_printer_print_str(p, ", "); + v = isl_point_get_coordinate_val(pnt, isl_dim_param, i); + p = isl_printer_print_val(p, v); + isl_val_free(v); + } + p = isl_printer_print_str(p, ") = "); + p = isl_printer_print_val(p, bound); + p = isl_printer_print_str(p, ", "); + p = isl_printer_print_str(p, bounded ? "opt" : "sample"); + p = isl_printer_print_str(p, " = "); + p = isl_printer_print_val(p, opt); + if (ok) + p = isl_printer_print_str(p, ". OK"); + else + p = isl_printer_print_str(p, ". NOT OK"); + p = isl_printer_end_line(p); + } else if ((vpb->n % vpb->stride) == 0) { + p = isl_printer_print_str(p, "o"); + p = isl_printer_flush(p); + } + + if (0) { +error: + ok = 0; + } + + isl_pw_qpolynomial_fold_free(pwf); + isl_val_free(bound); + isl_val_free(opt); + isl_point_free(pnt); + isl_set_free(dom); + + isl_printer_free(p); + + if (!ok) + vpb->error = 1; + + if (vpb->options->continue_on_error) + ok = 1; + + return (vpb->n >= 1 && ok) ? isl_stat_ok : isl_stat_error; +} + +static int check_solution(__isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_pw_qpolynomial_fold *bound, int exact, + struct bound_options *options) +{ + struct verify_point_bound vpb; + isl_int count, max; + isl_set *dom; + isl_set *context; + int i, r, n; + + dom = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf)); + context = isl_set_params(isl_set_copy(dom)); + context = isl_set_remove_divs(context); + context = set_bounds(context); + + isl_int_init(count); + isl_int_init(max); + + isl_int_set_si(max, 200); + r = isl_set_count_upto(context, max, &count); + assert(r >= 0); + n = isl_int_get_si(count); + + isl_int_clear(max); + isl_int_clear(count); + + vpb.options = options; + vpb.pwf = pwf; + vpb.bound = bound; + vpb.n = n; + vpb.stride = n > 70 ? 1 + (n + 1)/70 : 1; + vpb.error = 0; + vpb.exact = exact; + + if (!options->print_all) { + for (i = 0; i < vpb.n; i += vpb.stride) + printf("."); + printf("\r"); + fflush(stdout); + } + + isl_set_foreach_point(context, verify_point, &vpb); + + isl_set_free(context); + isl_set_free(dom); + isl_pw_qpolynomial_fold_free(pwf); + isl_pw_qpolynomial_fold_free(bound); + + if (!options->print_all) + printf("\n"); + + if (vpb.error) { + fprintf(stderr, "Check failed !\n"); + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + isl_ctx *ctx; + isl_pw_qpolynomial_fold *copy; + isl_pw_qpolynomial_fold *pwf; + isl_stream *s; + struct isl_obj obj; + struct bound_options *options; + int exact; + int r = 0; + + options = bound_options_new_with_defaults(); + assert(options); + argc = bound_options_parse(options, argc, argv, ISL_ARG_ALL); + + ctx = isl_ctx_alloc_with_options(&bound_options_args, options); + + s = isl_stream_new_file(ctx, stdin); + obj = isl_stream_read_obj(s); + if (obj.type == isl_obj_pw_qpolynomial) + pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max, + obj.v); + else if (obj.type == isl_obj_pw_qpolynomial_fold) + pwf = obj.v; + else { + obj.type->free(obj.v); + isl_die(ctx, isl_error_invalid, "invalid input", goto error); + } + + if (options->verify) + copy = isl_pw_qpolynomial_fold_copy(pwf); + + pwf = isl_pw_qpolynomial_fold_bound(pwf, &exact); + pwf = isl_pw_qpolynomial_fold_coalesce(pwf); + + if (options->verify) { + r = check_solution(copy, pwf, exact, options); + } else { + if (!exact) + printf("# NOT exact\n"); + isl_pw_qpolynomial_fold_print(pwf, stdout, 0); + fprintf(stdout, "\n"); + isl_pw_qpolynomial_fold_free(pwf); + } + +error: + isl_stream_free(s); + + isl_ctx_free(ctx); + + return r; +} Index: contrib/isl/bound_test.sh.in =================================================================== --- /dev/null +++ contrib/isl/bound_test.sh.in @@ -0,0 +1,36 @@ +#!/bin/sh + +EXEEXT=@EXEEXT@ +srcdir=@srcdir@ + +BOUND_TESTS="\ + basicLinear2.pwqp \ + basicLinear.pwqp \ + basicTestParameterPosNeg.pwqp \ + basicTest.pwqp \ + devos.pwqp \ + equality1.pwqp \ + equality2.pwqp \ + equality3.pwqp \ + equality4.pwqp \ + equality5.pwqp \ + faddeev.pwqp \ + linearExample.pwqp \ + neg.pwqp \ + philippe3vars3pars.pwqp \ + philippe3vars.pwqp \ + philippeNeg.pwqp \ + philippePolynomialCoeff1P.pwqp \ + philippePolynomialCoeff.pwqp \ + philippe.pwqp \ + product.pwqp \ + split.pwqp \ + test3Deg3Var.pwqp \ + toplas.pwqp \ + unexpanded.pwqp" + +for i in $BOUND_TESTS; do + echo $i; + ./isl_bound$EXEEXT -T --bound=bernstein < $srcdir/test_inputs/$i || exit + ./isl_bound$EXEEXT -T --bound=range < $srcdir/test_inputs/$i || exit +done Index: contrib/isl/bset_from_bmap.c =================================================================== --- /dev/null +++ contrib/isl/bset_from_bmap.c @@ -0,0 +1,8 @@ +#include + +/* Return the basic set that was treated as the basic map "bmap". + */ +static __isl_give isl_basic_set *bset_from_bmap(__isl_take isl_basic_map *bmap) +{ + return (isl_basic_set *) bmap; +} Index: contrib/isl/bset_to_bmap.c =================================================================== --- /dev/null +++ contrib/isl/bset_to_bmap.c @@ -0,0 +1,10 @@ +#include + +/* Treat "bset" as a basic map. + * Internally, isl_basic_set is defined to isl_basic_map, so in practice, + * this function performs a redundant cast. + */ +static __isl_give isl_basic_map *bset_to_bmap(__isl_take isl_basic_set *bset) +{ + return (isl_basic_map *) bset; +} Index: contrib/isl/cat.c =================================================================== --- /dev/null +++ contrib/isl/cat.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +struct isl_arg_choice cat_format[] = { + {"isl", ISL_FORMAT_ISL}, + {"omega", ISL_FORMAT_OMEGA}, + {"polylib", ISL_FORMAT_POLYLIB}, + {"ext-polylib", ISL_FORMAT_EXT_POLYLIB}, + {"latex", ISL_FORMAT_LATEX}, + {0} +}; + +struct isl_arg_choice cat_yaml_style[] = { + { "block", ISL_YAML_STYLE_BLOCK }, + { "flow", ISL_YAML_STYLE_FLOW }, + { 0 } +}; + +struct cat_options { + struct isl_options *isl; + unsigned format; + unsigned yaml_style; +}; + +ISL_ARGS_START(struct cat_options, cat_options_args) +ISL_ARG_CHILD(struct cat_options, isl, "isl", &isl_options_args, "isl options") +ISL_ARG_CHOICE(struct cat_options, format, 0, "format", \ + cat_format, ISL_FORMAT_ISL, "output format") +ISL_ARG_CHOICE(struct cat_options, yaml_style, 0, "yaml-style", \ + cat_yaml_style, ISL_YAML_STYLE_BLOCK, "output YAML style") +ISL_ARGS_END + +ISL_ARG_DEF(cat_options, struct cat_options, cat_options_args) + +int main(int argc, char **argv) +{ + struct isl_ctx *ctx; + isl_stream *s; + struct isl_obj obj; + struct cat_options *options; + isl_printer *p; + + options = cat_options_new_with_defaults(); + assert(options); + argc = cat_options_parse(options, argc, argv, ISL_ARG_ALL); + + ctx = isl_ctx_alloc_with_options(&cat_options_args, options); + + s = isl_stream_new_file(ctx, stdin); + obj = isl_stream_read_obj(s); + isl_stream_free(s); + + p = isl_printer_to_file(ctx, stdout); + p = isl_printer_set_output_format(p, options->format); + p = isl_printer_set_yaml_style(p, options->yaml_style); + p = obj.type->print(p, obj.v); + p = isl_printer_end_line(p); + isl_printer_free(p); + + obj.type->free(obj.v); + + isl_ctx_free(ctx); + + return 0; +} Index: contrib/isl/closure.c =================================================================== --- /dev/null +++ contrib/isl/closure.c @@ -0,0 +1,39 @@ +#include +#include +#include + +int main(int argc, char **argv) +{ + struct isl_ctx *ctx; + struct isl_map *map; + struct isl_options *options; + isl_printer *p; + int exact; + + options = isl_options_new_with_defaults(); + assert(options); + argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL); + + ctx = isl_ctx_alloc_with_options(&isl_options_args, options); + + p = isl_printer_to_file(ctx, stdout); + + map = isl_map_read_from_file(ctx, stdin); + map = isl_map_transitive_closure(map, &exact); + if (!exact) + p = isl_printer_print_str(p, "# NOT exact\n"); + p = isl_printer_print_map(p, map); + p = isl_printer_end_line(p); + map = isl_map_compute_divs(map); + map = isl_map_coalesce(map); + p = isl_printer_print_str(p, "# coalesced\n"); + p = isl_printer_print_map(p, map); + p = isl_printer_end_line(p); + isl_map_free(map); + + isl_printer_free(p); + + isl_ctx_free(ctx); + + return 0; +} Index: contrib/isl/codegen.c =================================================================== --- /dev/null +++ contrib/isl/codegen.c @@ -0,0 +1,245 @@ +/* + * Copyright 2012,2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +/* This program prints an AST that scans the domain elements of + * the domain of a given schedule in the order specified by + * the schedule tree or by their image(s) in the schedule map. + * + * The input consists of either a schedule tree or + * a sequence of three sets/relations. + * - a schedule map + * - a context + * - a relation describing AST generation options + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct options { + struct isl_options *isl; + unsigned atomic; + unsigned separate; +}; + +ISL_ARGS_START(struct options, options_args) +ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options") +ISL_ARG_BOOL(struct options, atomic, 0, "atomic", 0, + "globally set the atomic option") +ISL_ARG_BOOL(struct options, separate, 0, "separate", 0, + "globally set the separate option") +ISL_ARGS_END + +ISL_ARG_DEF(cg_options, struct options, options_args) +ISL_ARG_CTX_DEF(cg_options, struct options, options_args) + +/* Return a universal, 1-dimensional set with the given name. + */ +static __isl_give isl_union_set *universe(isl_ctx *ctx, const char *name) +{ + isl_space *space; + + space = isl_space_set_alloc(ctx, 0, 1); + space = isl_space_set_tuple_name(space, isl_dim_set, name); + return isl_union_set_from_set(isl_set_universe(space)); +} + +/* Set the "name" option for the entire schedule domain. + */ +static __isl_give isl_union_map *set_universe(__isl_take isl_union_map *opt, + __isl_keep isl_union_map *schedule, const char *name) +{ + isl_ctx *ctx; + isl_union_set *domain, *target; + isl_union_map *option; + + ctx = isl_union_map_get_ctx(opt); + + domain = isl_union_map_range(isl_union_map_copy(schedule)); + domain = isl_union_set_universe(domain); + target = universe(ctx, name); + option = isl_union_map_from_domain_and_range(domain, target); + opt = isl_union_map_union(opt, option); + + return opt; +} + +/* Update the build options based on the user-specified options. + * + * If the --separate or --atomic options were specified, then + * we clear any separate or atomic options that may already exist in "opt". + */ +static __isl_give isl_ast_build *set_options(__isl_take isl_ast_build *build, + __isl_take isl_union_map *opt, struct options *options, + __isl_keep isl_union_map *schedule) +{ + if (options->separate || options->atomic) { + isl_ctx *ctx; + isl_union_set *target; + + ctx = isl_union_map_get_ctx(schedule); + + target = universe(ctx, "separate"); + opt = isl_union_map_subtract_range(opt, target); + target = universe(ctx, "atomic"); + opt = isl_union_map_subtract_range(opt, target); + } + + if (options->separate) + opt = set_universe(opt, schedule, "separate"); + if (options->atomic) + opt = set_universe(opt, schedule, "atomic"); + + build = isl_ast_build_set_options(build, opt); + + return build; +} + +/* Construct an AST in case the schedule is specified by a union map. + * + * We read the context and the options from "s" and construct the AST. + */ +static __isl_give isl_ast_node *construct_ast_from_union_map( + __isl_take isl_union_map *schedule, __isl_keep isl_stream *s) +{ + isl_set *context; + isl_union_map *options_map; + isl_ast_build *build; + isl_ast_node *tree; + struct options *options; + + options = isl_ctx_peek_cg_options(isl_stream_get_ctx(s)); + + context = isl_stream_read_set(s); + options_map = isl_stream_read_union_map(s); + + build = isl_ast_build_from_context(context); + build = set_options(build, options_map, options, schedule); + tree = isl_ast_build_node_from_schedule_map(build, schedule); + isl_ast_build_free(build); + + return tree; +} + +/* If "node" is a band node, then replace the AST build options + * by "options". + */ +static __isl_give isl_schedule_node *node_set_options( + __isl_take isl_schedule_node *node, void *user) +{ + enum isl_ast_loop_type *type = user; + int i, n; + + if (isl_schedule_node_get_type(node) != isl_schedule_node_band) + return node; + + n = isl_schedule_node_band_n_member(node); + for (i = 0; i < n; ++i) + node = isl_schedule_node_band_member_set_ast_loop_type(node, + i, *type); + return node; +} + +/* Replace the AST build options on all band nodes if requested + * by the user. + */ +static __isl_give isl_schedule *schedule_set_options( + __isl_take isl_schedule *schedule, struct options *options) +{ + enum isl_ast_loop_type type; + + if (!options->separate && !options->atomic) + return schedule; + + type = options->separate ? isl_ast_loop_separate : isl_ast_loop_atomic; + schedule = isl_schedule_map_schedule_node_bottom_up(schedule, + &node_set_options, &type); + + return schedule; +} + +/* Construct an AST in case the schedule is specified by a schedule tree. + */ +static __isl_give isl_ast_node *construct_ast_from_schedule( + __isl_take isl_schedule *schedule) +{ + isl_ast_build *build; + isl_ast_node *tree; + struct options *options; + + options = isl_ctx_peek_cg_options(isl_schedule_get_ctx(schedule)); + + build = isl_ast_build_alloc(isl_schedule_get_ctx(schedule)); + schedule = schedule_set_options(schedule, options); + tree = isl_ast_build_node_from_schedule(build, schedule); + isl_ast_build_free(build); + + return tree; +} + +/* Read an object from stdin. + * If it is a (union) map, then assume an input specified by + * schedule map, context and options and construct an AST from + * those elements + * If it is a schedule object, then construct the AST from the schedule. + */ +int main(int argc, char **argv) +{ + isl_ctx *ctx; + isl_stream *s; + isl_ast_node *tree = NULL; + struct options *options; + isl_printer *p; + struct isl_obj obj; + int r = EXIT_SUCCESS; + + options = cg_options_new_with_defaults(); + assert(options); + ctx = isl_ctx_alloc_with_options(&options_args, options); + isl_options_set_ast_build_detect_min_max(ctx, 1); + argc = cg_options_parse(options, argc, argv, ISL_ARG_ALL); + + s = isl_stream_new_file(ctx, stdin); + obj = isl_stream_read_obj(s); + if (obj.v == NULL) { + r = EXIT_FAILURE; + } else if (obj.type == isl_obj_map) { + isl_union_map *umap; + + umap = isl_union_map_from_map(obj.v); + tree = construct_ast_from_union_map(umap, s); + } else if (obj.type == isl_obj_union_map) { + tree = construct_ast_from_union_map(obj.v, s); + } else if (obj.type == isl_obj_schedule) { + tree = construct_ast_from_schedule(obj.v); + } else { + obj.type->free(obj.v); + isl_die(ctx, isl_error_invalid, "unknown input", + r = EXIT_FAILURE); + } + isl_stream_free(s); + + p = isl_printer_to_file(ctx, stdout); + p = isl_printer_set_output_format(p, ISL_FORMAT_C); + p = isl_printer_print_ast_node(p, tree); + isl_printer_free(p); + + isl_ast_node_free(tree); + + isl_ctx_free(ctx); + return r; +} Index: contrib/isl/codegen_test.sh.in =================================================================== --- /dev/null +++ contrib/isl/codegen_test.sh.in @@ -0,0 +1,30 @@ +#!/bin/sh + +EXEEXT=@EXEEXT@ +srcdir=@srcdir@ + +failed=0 + +for i in $srcdir/test_inputs/codegen/*.st \ + $srcdir/test_inputs/codegen/cloog/*.st; do + echo $i; + base=`basename $i .st` + test=test-$base.c + dir=`dirname $i` + ref=$dir/$base.c + (./isl_codegen$EXEEXT < $i > $test && + diff -uw $ref $test && rm $test) || failed=1 +done +for i in $srcdir/test_inputs/codegen/*.in \ + $srcdir/test_inputs/codegen/omega/*.in \ + $srcdir/test_inputs/codegen/pldi2012/*.in; do + echo $i; + base=`basename $i .in` + test=test-$base.c + dir=`dirname $i` + ref=$dir/$base.c + (./isl_codegen$EXEEXT < $i > $test && + diff -uw $ref $test && rm $test) || failed=1 +done + +test $failed -eq 0 || exit Index: contrib/isl/configure.ac =================================================================== --- /dev/null +++ contrib/isl/configure.ac @@ -0,0 +1,149 @@ +AC_INIT([isl], [0.18], [isl-development@googlegroups.com]) +AC_CONFIG_AUX_DIR([.]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([foreign]) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) +AC_SUBST(versioninfo) +versioninfo=18:0:3 + +if test "x$prefix" != "xNONE"; then + prefix_wd=`cd $prefix && pwd` + srcdir_wd=`cd $srcdir && pwd` + wd=`pwd` + if test "x$prefix_wd" = "x$srcdir_wd"; then + AC_MSG_ERROR(Installation in source directory not supported) + fi + if test "x$prefix_wd" = "x$wd"; then + AC_MSG_ERROR(Installation in build directory not supported) + fi +fi + +AC_PROG_CC +AC_PROG_CXX + +AX_CC_MAXOPT +AX_GCC_WARN_UNUSED_RESULT +AX_C___ATTRIBUTE__ + +# CXX11FLAGS contains the flags (if any) added by AX_CXX_COMPILE_STDCXX_11 +# Original state of CXX and CXXCPP is preserved because CXX11FLAGS +# is only needed for compiling interface/isl_test_cpp +AC_SUBST(CXX11FLAGS) +ac_save_CXX="$CXX" +ac_save_CXXCPP="$CXXCPP" +AX_CXX_COMPILE_STDCXX_11([noext], [optional]) +CXX11FLAGS=${CXX#$ac_save_CXX} +CXX="$ac_save_CXX" +CXXCPP="$ac_save_CXXCPP" + +AC_PROG_GREP +AC_PROG_LIBTOOL +AC_PROG_SED + +AC_CHECK_PROG(PERL, perl, perl, []) +AC_CHECK_PROG(PDFLATEX, pdflatex, pdflatex, []) +AC_CHECK_PROG(POD2HTML, pod2html, pod2html, []) + +AM_CONDITIONAL(GENERATE_DOC, test -n "$PERL" -a -n "$PDFLATEX" -a -n "$POD2HTML") + +AX_CREATE_STDINT_H(include/isl/stdint.h) + +AC_ARG_WITH([int], + [AS_HELP_STRING([--with-int=gmp|imath|imath-32], + [Which package to use to represent + multi-precision integers [default=gmp]])], + [], [with_int=gmp]) +case "$with_int" in +gmp|imath|imath-32) + ;; +*) + AC_MSG_ERROR( + [bad value ${withval} for --with-int (use gmp, imath or imath-32)]) +esac + +AC_SUBST(MP_CPPFLAGS) +AC_SUBST(MP_LDFLAGS) +AC_SUBST(MP_LIBS) +case "$with_int" in +gmp) + AX_DETECT_GMP + ;; +imath|imath-32) + AX_DETECT_IMATH + ;; +esac +if test "x$with_int" = "ximath-32" -a "x$GCC" = "xyes"; then + MP_CPPFLAGS="-std=gnu99 $MP_CPPFLAGS" +fi + +AM_CONDITIONAL(IMATH_FOR_MP, test x$with_int = ximath -o x$with_int = ximath-32) +AM_CONDITIONAL(GMP_FOR_MP, test x$with_int = xgmp) + +AM_CONDITIONAL(HAVE_CXX11, test "x$HAVE_CXX11" = "x1") +AM_CONDITIONAL(SMALL_INT_OPT, test "x$with_int" == "ximath-32") +AS_IF([test "x$with_int" == "ximath-32"], [ + AC_DEFINE([USE_SMALL_INT_OPT], [], [Use small integer optimization]) +]) + +AC_CHECK_DECLS(ffs,[],[],[#include ]) +AC_CHECK_DECLS(__builtin_ffs,[],[],[]) +AC_CHECK_DECLS([_BitScanForward],[],[],[#include ]) +if test "x$ac_cv_have_decl_ffs" = xno -a \ + "x$ac_cv_have_decl___builtin_ffs" = xno -a \ + "x$ac_cv_have_decl__BitScanForward" = xno; then + AC_MSG_ERROR([No ffs implementation found]) +fi +AC_CHECK_DECLS([strcasecmp,strncasecmp],[],[],[#include ]) +AC_CHECK_DECLS([_stricmp,_strnicmp],[],[],[#include ]) +if test "x$ac_cv_have_decl_strcasecmp" = xno -a \ + "x$ac_cv_have_decl__stricmp" = xno; then + AC_MSG_ERROR([No strcasecmp implementation found]) +fi +if test "x$ac_cv_have_decl_strncasecmp" = xno -a \ + "x$ac_cv_have_decl__strnicmp" = xno; then + AC_MSG_ERROR([No strncasecmp implementation found]) +fi +AC_CHECK_DECLS([snprintf,_snprintf],[],[],[#include ]) +if test "x$ac_cv_have_decl_snprintf" = xno -a \ + "x$ac_cv_have_decl__snprintf" = xno; then + AC_MSG_ERROR([No snprintf implementation found]) +fi + +AX_SUBMODULE(clang,system|no,no) +case "$with_clang" in +system) + AX_DETECT_CLANG + ;; +esac +AM_CONDITIONAL(HAVE_CLANG, test $with_clang = system) + +AX_SET_WARNING_FLAGS + +AC_SUBST(WARNING_FLAGS) + +PACKAGE_CFLAGS="$MP_CPPFLAGS" +PACKAGE_LDFLAGS="$MP_LDFLAGS" +PACKAGE_LIBS="-lisl $MP_LIBS" +AX_CREATE_PKGCONFIG_INFO + +AX_DETECT_GIT_HEAD + +AH_BOTTOM([#include ]) +AC_CONFIG_HEADERS(isl_config.h) +AC_CONFIG_FILES(isl_srcdir.c) +AC_CONFIG_FILES(Makefile) +AC_CONFIG_FILES(doc/Makefile) +if test $with_clang = system; then + AC_CONFIG_FILES(interface/Makefile) +fi +AC_CONFIG_FILES([bound_test.sh], [chmod +x bound_test.sh]) +AC_CONFIG_FILES([codegen_test.sh], [chmod +x codegen_test.sh]) +AC_CONFIG_FILES([pip_test.sh], [chmod +x pip_test.sh]) +AC_CONFIG_FILES([flow_test.sh], [chmod +x flow_test.sh]) +AC_CONFIG_FILES([schedule_test.sh], [chmod +x schedule_test.sh]) +AC_CONFIG_COMMANDS_POST([ + dnl pass on arguments to subdir configures, but don't + dnl add them to config.status + ac_configure_args="$ac_configure_args $isl_configure_args" +]) +AC_OUTPUT Index: contrib/isl/doc/CodingStyle =================================================================== --- /dev/null +++ contrib/isl/doc/CodingStyle @@ -0,0 +1,42 @@ +This document describes some aspects of the coding style of isl, +which is similar to that of the linux kernel and git. + +The general rule is to use the same style as that of the surrounding code. + +More specific rules: + - every line should have at most 80 columns + - use tabs for indentation, where a tab counts for 8 characters + - use single spaces around binary operators such as '+', '-', '=', '!=' + - no space after unary operators such as '!' + - use a single space after a comma and a semicolon + (except at the end of a line) + - no space between function name and arguments + - use a single space after control keywords such as if, for and while + - use a single space between the type of a cast and the value + that is being cast + - no whitespace at the end of a line + - opening brace of a function is placed on a new line + - opening brace of other blocks stays on the same line + - the body of a control statement is placed on the next line(s) + - an else appears on the same line as the closing brace of + the then branch, if there is such a closing brace + - if either the then or the else branch of an if has braces, + then they both have braces + - no parentheses around argument of return keyword + - use only C style comments (/* ... */) + - no comments inside function bodies; + if some part of a function deserves additional comments, then + extract it out into a separate function first + - no #ifs inside function bodies + - variables are declared at the start of a block, before any + other statements + +There are some exceptions to the general rule of using +the same style as the surrounding code, most notably +when the surrounding code is very old. +In particular, an "isl_space" used to be called "isl_dim" and +some variables of this type are still called "dim" or some variant thereof. +New variables of this type should be called "space" or a more specific name. +Some old functions do not have memory management annotations yet. +All new functions should have memory management annotations, +whenever appropriate Index: contrib/isl/doc/Makefile.am =================================================================== --- /dev/null +++ contrib/isl/doc/Makefile.am @@ -0,0 +1,32 @@ + +CLEANFILES = \ + manual.toc \ + manual.bbl \ + version.tex \ + user.tex \ + manual.pdf \ + manual.aux \ + manual.out \ + manual.blg \ + manual.log \ + manual.brf \ + manual.bcf \ + manual.run.xml + +if GENERATE_DOC +export TEXINPUTS := $(srcdir):$(TEXINPUTS) +export BIBINPUTS := $(srcdir):$(BIBINPUTS) +export BSTINPUTS := $(srcdir):$(BSTINPUTS) + +user.tex: user.pod + $(PERL) $(srcdir)/mypod2latex $< $@ +manual.pdf: manual.tex user.tex $(srcdir)/implementation.tex reading.tex + (cd ..; echo "@GIT_HEAD_VERSION@") > version.tex + $(PDFLATEX) $< + biber manual + $(PDFLATEX) $< + $(PDFLATEX) $< +user.html: user.pod + (cd ..; echo "@GIT_HEAD_VERSION@") > version + $(POD2HTML) --infile=$< --outfile=$@ --title="Integer Set Library: Manual [version `cat version`]" +endif Index: contrib/isl/doc/SubmittingPatches =================================================================== --- /dev/null +++ contrib/isl/doc/SubmittingPatches @@ -0,0 +1,52 @@ +[Mostly copied from git's SubmittingPatches] + + Commits: + + - make commits of logical units + - check for unnecessary whitespace with "git diff --check" + before committing + - do not check in commented out code or unneeded files + - the first line of the commit message should be a short + description and should skip the full stop + - the body should provide a meaningful commit message, which + includes motivation for the change, and contrasts + its implementation with previous behaviour + - if you want your work included in isl.git, add a + "Signed-off-by: Your Name " line to the + commit message (or just use the option "-s" when + committing) to confirm that you agree to the Developer's + Certificate of Origin + - make sure that you have tests for the bug you are fixing + - make sure that the test suite passes after your commit + + Patch: + + - use "git format-patch -M" to create the patch + - do not PGP sign your patch + - send a single patch per mail, e.g., using git-send-email(1) + - do not attach your patch, but read in the mail + body, unless you cannot teach your mailer to + leave the formatting of the patch alone. + - be careful doing cut & paste into your mailer, not to + corrupt whitespaces. + - provide additional information (which is unsuitable for + the commit message) between the "---" and the diffstat + - if you change, add, or remove a command line option or + make some other user interface change, the associated + documentation should be updated as well. + - if your name is not writable in ASCII, make sure that + you send off a message in the correct encoding. + - send the patch to the development mailing list + (isl-development@googlegroups.com). If you use + git-send-email(1), please test it first by sending email + to yourself. + + Revisions: + + - add the revision number inside square brackets to + the subject line (e.g., use --subject-prefix='PATCH v2' + when creating the patch) + - recall the major issues discovered during the previous + review and explain how you addressed them or why you + disagree. Do so either in a cover letter, between the + "---" and the diffstat or in a separate message. Index: contrib/isl/doc/implementation.tex =================================================================== --- /dev/null +++ contrib/isl/doc/implementation.tex @@ -0,0 +1,2049 @@ +\section{Sets and Relations} + +\begin{definition}[Polyhedral Set] +A {\em polyhedral set}\index{polyhedral set} $S$ is a finite union of basic sets +$S = \bigcup_i S_i$, each of which can be represented using affine +constraints +$$ +S_i : \Z^n \to 2^{\Z^d} : \vec s \mapsto +S_i(\vec s) = +\{\, \vec x \in \Z^d \mid \exists \vec z \in \Z^e : +A \vec x + B \vec s + D \vec z + \vec c \geq \vec 0 \,\} +, +$$ +with $A \in \Z^{m \times d}$, +$B \in \Z^{m \times n}$, +$D \in \Z^{m \times e}$ +and $\vec c \in \Z^m$. +\end{definition} + +\begin{definition}[Parameter Domain of a Set] +Let $S \in \Z^n \to 2^{\Z^d}$ be a set. +The {\em parameter domain} of $S$ is the set +$$\pdom S \coloneqq \{\, \vec s \in \Z^n \mid S(\vec s) \ne \emptyset \,\}.$$ +\end{definition} + +\begin{definition}[Polyhedral Relation] +A {\em polyhedral relation}\index{polyhedral relation} +$R$ is a finite union of basic relations +$R = \bigcup_i R_i$ of type +$\Z^n \to 2^{\Z^{d_1+d_2}}$, +each of which can be represented using affine +constraints +$$ +R_i = \vec s \mapsto +R_i(\vec s) = +\{\, \vec x_1 \to \vec x_2 \in \Z^{d_1} \times \Z^{d_2} +\mid \exists \vec z \in \Z^e : +A_1 \vec x_1 + A_2 \vec x_2 + B \vec s + D \vec z + \vec c \geq \vec 0 \,\} +, +$$ +with $A_i \in \Z^{m \times d_i}$, +$B \in \Z^{m \times n}$, +$D \in \Z^{m \times e}$ +and $\vec c \in \Z^m$. +\end{definition} + +\begin{definition}[Parameter Domain of a Relation] +Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation. +The {\em parameter domain} of $R$ is the set +$$\pdom R \coloneqq \{\, \vec s \in \Z^n \mid R(\vec s) \ne \emptyset \,\}.$$ +\end{definition} + +\begin{definition}[Domain of a Relation] +Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation. +The {\em domain} of $R$ is the polyhedral set +$$\domain R \coloneqq \vec s \mapsto +\{\, \vec x_1 \in \Z^{d_1} \mid \exists \vec x_2 \in \Z^{d_2} : +(\vec x_1, \vec x_2) \in R(\vec s) \,\} +. +$$ +\end{definition} + +\begin{definition}[Range of a Relation] +Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation. +The {\em range} of $R$ is the polyhedral set +$$ +\range R \coloneqq \vec s \mapsto +\{\, \vec x_2 \in \Z^{d_2} \mid \exists \vec x_1 \in \Z^{d_1} : +(\vec x_1, \vec x_2) \in R(\vec s) \,\} +. +$$ +\end{definition} + +\begin{definition}[Composition of Relations] +Let $R \in \Z^n \to 2^{\Z^{d_1+d_2}}$ and +$S \in \Z^n \to 2^{\Z^{d_2+d_3}}$ be two relations, +then the composition of +$R$ and $S$ is defined as +$$ +S \circ R \coloneqq +\vec s \mapsto +\{\, \vec x_1 \to \vec x_3 \in \Z^{d_1} \times \Z^{d_3} +\mid \exists \vec x_2 \in \Z^{d_2} : +\vec x_1 \to \vec x_2 \in R(\vec s) \wedge +\vec x_2 \to \vec x_3 \in S(\vec s) +\,\} +. +$$ +\end{definition} + +\begin{definition}[Difference Set of a Relation] +Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation. +The difference set ($\Delta \, R$) of $R$ is the set +of differences between image elements and the corresponding +domain elements, +$$ +\diff R \coloneqq +\vec s \mapsto +\{\, \vec \delta \in \Z^{d} \mid \exists \vec x \to \vec y \in R : +\vec \delta = \vec y - \vec x +\,\} +$$ +\end{definition} + +\section{Simple Hull}\label{s:simple hull} + +It is sometimes useful to have a single +basic set or basic relation that contains a given set or relation. +For rational sets, the obvious choice would be to compute the +(rational) convex hull. For integer sets, the obvious choice +would be the integer hull. +However, {\tt isl} currently does not support an integer hull operation +and even if it did, it would be fairly expensive to compute. +The convex hull operation is supported, but it is also fairly +expensive to compute given only an implicit representation. + +Usually, it is not required to compute the exact integer hull, +and an overapproximation of this hull is sufficient. +The ``simple hull'' of a set is such an overapproximation +and it is defined as the (inclusion-wise) smallest basic set +that is described by constraints that are translates of +the constraints in the input set. +This means that the simple hull is relatively cheap to compute +and that the number of constraints in the simple hull is no +larger than the number of constraints in the input. +\begin{definition}[Simple Hull of a Set] +The {\em simple hull} of a set +$S = \bigcup_{1 \le i \le v} S_i$, with +$$ +S : \Z^n \to 2^{\Z^d} : \vec s \mapsto +S(\vec s) = +\left\{\, \vec x \in \Z^d \mid \exists \vec z \in \Z^e : +\bigvee_{1 \le i \le v} +A_i \vec x + B_i \vec s + D_i \vec z + \vec c_i \geq \vec 0 \,\right\} +$$ +is the set +$$ +H : \Z^n \to 2^{\Z^d} : \vec s \mapsto +S(\vec s) = +\left\{\, \vec x \in \Z^d \mid \exists \vec z \in \Z^e : +\bigwedge_{1 \le i \le v} +A_i \vec x + B_i \vec s + D_i \vec z + \vec c_i + \vec K_i \geq \vec 0 +\,\right\} +, +$$ +with $\vec K_i$ the (component-wise) smallest non-negative integer vectors +such that $S \subseteq H$. +\end{definition} +The $\vec K_i$ can be obtained by solving a number of +LP problems, one for each element of each $\vec K_i$. +If any LP problem is unbounded, then the corresponding constraint +is dropped. + +\section{Parametric Integer Programming} + +\subsection{Introduction}\label{s:intro} + +Parametric integer programming \parencite{Feautrier88parametric} +is used to solve many problems within the context of the polyhedral model. +Here, we are mainly interested in dependence analysis \parencite{Fea91} +and in computing a unique representation for existentially quantified +variables. The latter operation has been used for counting elements +in sets involving such variables +\parencite{BouletRe98,Verdoolaege2005experiences} and lies at the core +of the internal representation of {\tt isl}. + +Parametric integer programming was first implemented in \texttt{PipLib}. +An alternative method for parametric integer programming +was later implemented in {\tt barvinok} \cite{barvinok-0.22}. +This method is not based on Feautrier's algorithm, but on rational +generating functions \cite{Woods2003short} and was inspired by the +``digging'' technique of \textcite{DeLoera2004Three} for solving +non-parametric integer programming problems. + +In the following sections, we briefly recall the dual simplex +method combined with Gomory cuts and describe some extensions +and optimizations. The main algorithm is applied to a matrix +data structure known as a tableau. In case of parametric problems, +there are two tableaus, one for the main problem and one for +the constraints on the parameters, known as the context tableau. +The handling of the context tableau is described in \autoref{s:context}. + +\subsection{The Dual Simplex Method} + +Tableaus can be represented in several slightly different ways. +In {\tt isl}, the dual simplex method uses the same representation +as that used by its incremental LP solver based on the \emph{primal} +simplex method. The implementation of this LP solver is based +on that of {\tt Simplify} \parencite{Detlefs2005simplify}, which, in turn, +was derived from the work of \textcite{Nelson1980phd}. +In the original \parencite{Nelson1980phd}, the tableau was implemented +as a sparse matrix, but neither {\tt Simplify} nor the current +implementation of {\tt isl} does so. + +Given some affine constraints on the variables, +$A \vec x + \vec b \ge \vec 0$, the tableau represents the relationship +between the variables $\vec x$ and non-negative variables +$\vec y = A \vec x + \vec b$ corresponding to the constraints. +The initial tableau contains $\begin{pmatrix} +\vec b & A +\end{pmatrix}$ and expresses the constraints $\vec y$ in the rows in terms +of the variables $\vec x$ in the columns. The main operation defined +on a tableau exchanges a column and a row variable and is called a pivot. +During this process, some coefficients may become rational. +As in the \texttt{PipLib} implementation, +{\tt isl} maintains a shared denominator per row. +The sample value of a tableau is one where each column variable is assigned +zero and each row variable is assigned the constant term of the row. +This sample value represents a valid solution if each constraint variable +is assigned a non-negative value, i.e., if the constant terms of +rows corresponding to constraints are all non-negative. + +The dual simplex method starts from an initial sample value that +may be invalid, but that is known to be (lexicographically) no +greater than any solution, and gradually increments this sample value +through pivoting until a valid solution is obtained. +In particular, each pivot exchanges a row variable +$r = -n + \sum_i a_i \, c_i$ with negative +sample value $-n$ with a column variable $c_j$ +such that $a_j > 0$. Since $c_j = (n + r - \sum_{i\ne j} a_i \, c_i)/a_j$, +the new row variable will have a positive sample value $n$. +If no such column can be found, then the problem is infeasible. +By always choosing the column that leads to the (lexicographically) +smallest increment in the variables $\vec x$, +the first solution found is guaranteed to be the (lexicographically) +minimal solution \cite{Feautrier88parametric}. +In order to be able to determine the smallest increment, the tableau +is (implicitly) extended with extra rows defining the original +variables in terms of the column variables. +If we assume that all variables are non-negative, then we know +that the zero vector is no greater than the minimal solution and +then the initial extended tableau looks as follows. +$$ +\begin{tikzpicture} +\matrix (m) [matrix of math nodes] +{ +& {} & 1 & \vec c \\ +\vec x && |(top)| \vec 0 & I \\ +\vec r && \vec b & |(bottom)|A \\ +}; +\begin{pgfonlayer}{background} +\node (core) [inner sep=0pt,fill=black!20,right delimiter=),left delimiter=(,fit=(top)(bottom)] {}; +\end{pgfonlayer} +\end{tikzpicture} +$$ +Each column in this extended tableau is lexicographically positive +and will remain so because of the column choice explained above. +It is then clear that the value of $\vec x$ will increase in each step. +Note that there is no need to store the extra rows explicitly. +If a given $x_i$ is a column variable, then the corresponding row +is the unit vector $e_i$. If, on the other hand, it is a row variable, +then the row already appears somewhere else in the tableau. + +In case of parametric problems, the sign of the constant term +may depend on the parameters. Each time the constant term of a constraint row +changes, we therefore need to check whether the new term can attain +negative and/or positive values over the current set of possible +parameter values, i.e., the context. +If all these terms can only attain non-negative values, the current +state of the tableau represents a solution. If one of the terms +can only attain non-positive values and is not identically zero, +the corresponding row can be pivoted. +Otherwise, we pick one of the terms that can attain both positive +and negative values and split the context into a part where +it only attains non-negative values and a part where it only attains +negative values. + +\subsection{Gomory Cuts} + +The solution found by the dual simplex method may have +non-integral coordinates. If so, some rational solutions +(including the current sample value), can be cut off by +applying a (parametric) Gomory cut. +Let $r = b(\vec p) + \sp {\vec a} {\vec c}$ be the row +corresponding to the first non-integral coordinate of $\vec x$, +with $b(\vec p)$ the constant term, an affine expression in the +parameters $\vec p$, i.e., $b(\vec p) = \sp {\vec f} {\vec p} + g$. +Note that only row variables can attain +non-integral values as the sample value of the column variables is zero. +Consider the expression +$b(\vec p) - \ceil{b(\vec p)} + \sp {\fract{\vec a}} {\vec c}$, +with $\ceil\cdot$ the ceiling function and $\fract\cdot$ the +fractional part. This expression is negative at the sample value +since $\vec c = \vec 0$ and $r = b(\vec p)$ is fractional, i.e., +$\ceil{b(\vec p)} > b(\vec p)$. On the other hand, for each integral +value of $r$ and $\vec c \ge 0$, the expression is non-negative +because $b(\vec p) - \ceil{b(\vec p)} > -1$. +Imposing this expression to be non-negative therefore does not +invalidate any integral solutions, while it does cut away the current +fractional sample value. To be able to formulate this constraint, +a new variable $q = \floor{-b(\vec p)} = - \ceil{b(\vec p)}$ is added +to the context. This integral variable is uniquely defined by the constraints +$0 \le -d \, b(\vec p) - d \, q \le d - 1$, with $d$ the common +denominator of $\vec f$ and $g$. In practice, the variable +$q' = \floor{\sp {\fract{-f}} {\vec p} + \fract{-g}}$ is used instead +and the coefficients of the new constraint are adjusted accordingly. +The sign of the constant term of this new constraint need not be determined +as it is non-positive by construction. +When several of these extra context variables are added, it is important +to avoid adding duplicates. +Recent versions of {\tt PipLib} also check for such duplicates. + +\subsection{Negative Unknowns and Maximization} + +There are two places in the above algorithm where the unknowns $\vec x$ +are assumed to be non-negative: the initial tableau starts from +sample value $\vec x = \vec 0$ and $\vec c$ is assumed to be non-negative +during the construction of Gomory cuts. +To deal with negative unknowns, \textcite[Appendix A.2]{Fea91} +proposed to use a ``big parameter'', say $M$, that is taken to be +an arbitrarily large positive number. Instead of looking for the +lexicographically minimal value of $\vec x$, we search instead +for the lexicographically minimal value of $\vec x' = \vec M + \vec x$. +The sample value $\vec x' = \vec 0$ of the initial tableau then +corresponds to $\vec x = -\vec M$, which is clearly not greater than +any potential solution. The sign of the constant term of a row +is determined lexicographically, with the coefficient of $M$ considered +first. That is, if the coefficient of $M$ is not zero, then its sign +is the sign of the entire term. Otherwise, the sign is determined +by the remaining affine expression in the parameters. +If the original problem has a bounded optimum, then the final sample +value will be of the form $\vec M + \vec v$ and the optimal value +of the original problem is then $\vec v$. +Maximization problems can be handled in a similar way by computing +the minimum of $\vec M - \vec x$. + +When the optimum is unbounded, the optimal value computed for +the original problem will involve the big parameter. +In the original implementation of {\tt PipLib}, the big parameter could +even appear in some of the extra variables $\vec q$ created during +the application of a Gomory cut. The final result could then contain +implicit conditions on the big parameter through conditions on such +$\vec q$ variables. This problem was resolved in later versions +of {\tt PipLib} by taking $M$ to be divisible by any positive number. +The big parameter can then never appear in any $\vec q$ because +$\fract {\alpha M } = 0$. It should be noted, though, that an unbounded +problem usually (but not always) +indicates an incorrect formulation of the problem. + +The original version of {\tt PipLib} required the user to ``manually'' +add a big parameter, perform the reformulation and interpret the result +\parencite{Feautrier02}. Recent versions allow the user to simply +specify that the unknowns may be negative or that the maximum should +be computed and then these transformations are performed internally. +Although there are some application, e.g., +that of \textcite{Feautrier92multi}, +where it is useful to have explicit control over the big parameter, +negative unknowns and maximization are by far the most common applications +of the big parameter and we believe that the user should not be bothered +with such implementation issues. +The current version of {\tt isl} therefore does not +provide any interface for specifying big parameters. Instead, the user +can specify whether a maximum needs to be computed and no assumptions +are made on the sign of the unknowns. Instead, the sign of the unknowns +is checked internally and a big parameter is automatically introduced when +needed. For compatibility with {\tt PipLib}, the {\tt isl\_pip} tool +does explicitly add non-negativity constraints on the unknowns unless +the \verb+Urs_unknowns+ option is specified. +Currently, there is also no way in {\tt isl} of expressing a big +parameter in the output. Even though +{\tt isl} makes the same divisibility assumption on the big parameter +as recent versions of {\tt PipLib}, it will therefore eventually +produce an error if the problem turns out to be unbounded. + +\subsection{Preprocessing} + +In this section, we describe some transformations that are +or can be applied in advance to reduce the running time +of the actual dual simplex method with Gomory cuts. + +\subsubsection{Feasibility Check and Detection of Equalities} + +Experience with the original {\tt PipLib} has shown that Gomory cuts +do not perform very well on problems that are (non-obviously) empty, +i.e., problems with rational solutions, but no integer solutions. +In {\tt isl}, we therefore first perform a feasibility check on +the original problem considered as a non-parametric problem +over the combined space of unknowns and parameters. +In fact, we do not simply check the feasibility, but we also +check for implicit equalities among the integer points by computing +the integer affine hull. The algorithm used is the same as that +described in \autoref{s:GBR} below. +Computing the affine hull is fairly expensive, but it can +bring huge benefits if any equalities can be found or if the problem +turns out to be empty. + +\subsubsection{Constraint Simplification} + +If the coefficients of the unknown and parameters in a constraint +have a common factor, then this factor should be removed, possibly +rounding down the constant term. For example, the constraint +$2 x - 5 \ge 0$ should be simplified to $x - 3 \ge 0$. +{\tt isl} performs such simplifications on all sets and relations. +Recent versions of {\tt PipLib} also perform this simplification +on the input. + +\subsubsection{Exploiting Equalities}\label{s:equalities} + +If there are any (explicit) equalities in the input description, +{\tt PipLib} converts each into a pair of inequalities. +It is also possible to write $r$ equalities as $r+1$ inequalities +\parencite{Feautrier02}, but it is even better to \emph{exploit} the +equalities to reduce the dimensionality of the problem. +Given an equality involving at least one unknown, we pivot +the row corresponding to the equality with the column corresponding +to the last unknown with non-zero coefficient. The new column variable +can then be removed completely because it is identically zero, +thereby reducing the dimensionality of the problem by one. +The last unknown is chosen to ensure that the columns of the initial +tableau remain lexicographically positive. In particular, if +the equality is of the form $b + \sum_{i \le j} a_i \, x_i = 0$ with +$a_j \ne 0$, then the (implicit) top rows of the initial tableau +are changed as follows +$$ +\begin{tikzpicture} +\matrix [matrix of math nodes] +{ + & {} & |(top)| 0 & I_1 & |(j)| & \\ +j && 0 & & 1 & \\ + && 0 & & & |(bottom)|I_2 \\ +}; +\node[overlay,above=2mm of j,anchor=south]{j}; +\begin{pgfonlayer}{background} +\node (m) [inner sep=0pt,fill=black!20,right delimiter=),left delimiter=(,fit=(top)(bottom)] {}; +\end{pgfonlayer} +\begin{scope}[xshift=4cm] +\matrix [matrix of math nodes] +{ + & {} & |(top)| 0 & I_1 & \\ +j && |(left)| -b/a_j & -a_i/a_j & \\ + && 0 & & |(bottom)|I_2 \\ +}; +\begin{pgfonlayer}{background} +\node (m2) [inner sep=0pt,fill=black!20,right delimiter=),left delimiter=(,fit=(top)(bottom)(left)] {}; +\end{pgfonlayer} +\end{scope} + \draw [shorten >=7mm,-to,thick,decorate, + decoration={snake,amplitude=.4mm,segment length=2mm, + pre=moveto,pre length=5mm,post length=8mm}] + (m) -- (m2); +\end{tikzpicture} +$$ +Currently, {\tt isl} also eliminates equalities involving only parameters +in a similar way, provided at least one of the coefficients is equal to one. +The application of parameter compression (see below) +would obviate the need for removing parametric equalities. + +\subsubsection{Offline Symmetry Detection}\label{s:offline} + +Some problems, notably those of \textcite{Bygde2010licentiate}, +have a collection of constraints, say +$b_i(\vec p) + \sp {\vec a} {\vec x} \ge 0$, +that only differ in their (parametric) constant terms. +These constant terms will be non-negative on different parts +of the context and this context may have to be split for each +of the constraints. In the worst case, the basic algorithm may +have to consider all possible orderings of the constant terms. +Instead, {\tt isl} introduces a new parameter, say $u$, and +replaces the collection of constraints by the single +constraint $u + \sp {\vec a} {\vec x} \ge 0$ along with +context constraints $u \le b_i(\vec p)$. +Any solution to the new system is also a solution +to the original system since +$\sp {\vec a} {\vec x} \ge -u \ge -b_i(\vec p)$. +Conversely, $m = \min_i b_i(\vec p)$ satisfies the constraints +on $u$ and therefore extends a solution to the new system. +It can also be plugged into a new solution. +See \autoref{s:post} for how this substitution is currently performed +in {\tt isl}. +The method described in this section can only detect symmetries +that are explicitly available in the input. +See \autoref{s:online} for the detection +and exploitation of symmetries that appear during the course of +the dual simplex method. + +Note that the replacement of the $b_i(\vec p)$ by $u$ may lose +information if the parameters that occur in $b_i(\vec p)$ also +occur in other constraints. The replacement is therefore currently +only applied when all the parameters in all of the $b_i(\vec p)$ +only occur in a single constraint, i.e., the one in which +the parameter is removed. +This is the case for the examples from \textcite{Bygde2010licentiate} +in \autoref{t:comparison}. +The version of {\tt isl} that was used during the experiments +of \autoref{s:pip:experiments} did not take into account +this single-occurrence constraint. + +\subsubsection{Parameter Compression}\label{s:compression} + +It may in some cases be apparent from the equalities in the problem +description that there can only be a solution for a sublattice +of the parameters. In such cases ``parameter compression'' +\parencite{Meister2004PhD,Meister2008} can be used to replace +the parameters by alternative ``dense'' parameters. +For example, if there is a constraint $2x = n$, then the system +will only have solutions for even values of $n$ and $n$ can be replaced +by $2n'$. Similarly, the parameters $n$ and $m$ in a system with +the constraint $2n = 3m$ can be replaced by a single parameter $n'$ +with $n=3n'$ and $m=2n'$. +It is also possible to perform a similar compression on the unknowns, +but it would be more complicated as the compression would have to +preserve the lexicographical order. Moreover, due to our handling +of equalities described above there should be +no need for such variable compression. +Although parameter compression has been implemented in {\tt isl}, +it is currently not yet used during parametric integer programming. + +\subsection{Postprocessing}\label{s:post} + +The output of {\tt PipLib} is a quast (quasi-affine selection tree). +Each internal node in this tree corresponds to a split of the context +based on a parametric constant term in the main tableau with indeterminate +sign. Each of these nodes may introduce extra variables in the context +corresponding to integer divisions. Each leaf of the tree prescribes +the solution in that part of the context that satisfies all the conditions +on the path leading to the leaf. +Such a quast is a very economical way of representing the solution, but +it would not be suitable as the (only) internal representation of +sets and relations in {\tt isl}. Instead, {\tt isl} represents +the constraints of a set or relation in disjunctive normal form. +The result of a parametric integer programming problem is then also +converted to this internal representation. Unfortunately, the conversion +to disjunctive normal form can lead to an explosion of the size +of the representation. +In some cases, this overhead would have to be paid anyway in subsequent +operations, but in other cases, especially for outside users that just +want to solve parametric integer programming problems, we would like +to avoid this overhead in future. That is, we are planning on introducing +quasts or a related representation as one of several possible internal +representations and on allowing the output of {\tt isl\_pip} to optionally +be printed as a quast. + +Currently, {\tt isl} also does not have an internal representation +for expressions such as $\min_i b_i(\vec p)$ from the offline +symmetry detection of \autoref{s:offline}. +Assume that one of these expressions has $n$ bounds $b_i(\vec p)$. +If the expression +does not appear in the affine expression describing the solution, +but only in the constraints, and if moreover, the expression +only appears with a positive coefficient, i.e., +$\min_i b_i(\vec p) \ge f_j(\vec p)$, then each of these constraints +can simply be reduplicated $n$ times, once for each of the bounds. +Otherwise, a conversion to disjunctive normal form +leads to $n$ cases, each described as $u = b_i(\vec p)$ with constraints +$b_i(\vec p) \le b_j(\vec p)$ for $j > i$ +and +$b_i(\vec p) < b_j(\vec p)$ for $j < i$. +Note that even though this conversion leads to a size increase +by a factor of $n$, not detecting the symmetry could lead to +an increase by a factor of $n!$ if all possible orderings end up being +considered. + +\subsection{Context Tableau}\label{s:context} + +The main operation that a context tableau needs to provide is a test +on the sign of an affine expression over the elements of the context. +This sign can be determined by solving two integer linear feasibility +problems, one with a constraint added to the context that enforces +the expression to be non-negative and one where the expression is +negative. As already mentioned by \textcite{Feautrier88parametric}, +any integer linear feasibility solver could be used, but the {\tt PipLib} +implementation uses a recursive call to the dual simplex with Gomory +cuts algorithm to determine the feasibility of a context. +In {\tt isl}, two ways of handling the context have been implemented, +one that performs the recursive call and one, used by default, that +uses generalized basis reduction. +We start with some optimizations that are shared between the two +implementations and then discuss additional details of each of them. + +\subsubsection{Maintaining Witnesses}\label{s:witness} + +A common feature of both integer linear feasibility solvers is that +they will not only say whether a set is empty or not, but if the set +is non-empty, they will also provide a \emph{witness} for this result, +i.e., a point that belongs to the set. By maintaining a list of such +witnesses, we can avoid many feasibility tests during the determination +of the signs of affine expressions. In particular, if the expression +evaluates to a positive number on some of these points and to a negative +number on some others, then no feasibility test needs to be performed. +If all the evaluations are non-negative, we only need to check for the +possibility of a negative value and similarly in case of all +non-positive evaluations. Finally, in the rare case that all points +evaluate to zero or at the start, when no points have been collected yet, +one or two feasibility tests need to be performed depending on the result +of the first test. + +When a new constraint is added to the context, the points that +violate the constraint are temporarily removed. They are reconsidered +when we backtrack over the addition of the constraint, as they will +satisfy the negation of the constraint. It is only when we backtrack +over the addition of the points that they are finally removed completely. +When an extra integer division is added to the context, +the new coordinates of the +witnesses can easily be computed by evaluating the integer division. +The idea of keeping track of witnesses was first used in {\tt barvinok}. + +\subsubsection{Choice of Constant Term on which to Split} + +Recall that if there are no rows with a non-positive constant term, +but there are rows with an indeterminate sign, then the context +needs to be split along the constant term of one of these rows. +If there is more than one such row, then we need to choose which row +to split on first. {\tt PipLib} uses a heuristic based on the (absolute) +sizes of the coefficients. In particular, it takes the largest coefficient +of each row and then selects the row where this largest coefficient is smaller +than those of the other rows. + +In {\tt isl}, we take that row for which non-negativity of its constant +term implies non-negativity of as many of the constant terms of the other +rows as possible. The intuition behind this heuristic is that on the +positive side, we will have fewer negative and indeterminate signs, +while on the negative side, we need to perform a pivot, which may +affect any number of rows meaning that the effect on the signs +is difficult to predict. This heuristic is of course much more +expensive to evaluate than the heuristic used by {\tt PipLib}. +More extensive tests are needed to evaluate whether the heuristic is worthwhile. + +\subsubsection{Dual Simplex + Gomory Cuts} + +When a new constraint is added to the context, the first steps +of the dual simplex method applied to this new context will be the same +or at least very similar to those taken on the original context, i.e., +before the constraint was added. In {\tt isl}, we therefore apply +the dual simplex method incrementally on the context and backtrack +to a previous state when a constraint is removed again. +An initial implementation that was never made public would also +keep the Gomory cuts, but the current implementation backtracks +to before the point where Gomory cuts are added before adding +an extra constraint to the context. +Keeping the Gomory cuts has the advantage that the sample value +is always an integer point and that this point may also satisfy +the new constraint. However, due to the technique of maintaining +witnesses explained above, +we would not perform a feasibility test in such cases and then +the previously added cuts may be redundant, possibly resulting +in an accumulation of a large number of cuts. + +If the parameters may be negative, then the same big parameter trick +used in the main tableau is applied to the context. This big parameter +is of course unrelated to the big parameter from the main tableau. +Note that it is not a requirement for this parameter to be ``big'', +but it does allow for some code reuse in {\tt isl}. +In {\tt PipLib}, the extra parameter is not ``big'', but this may be because +the big parameter of the main tableau also appears +in the context tableau. + +Finally, it was reported by \textcite{Galea2009personal}, who +worked on a parametric integer programming implementation +in {\tt PPL} \parencite{PPL}, +that it is beneficial to add cuts for \emph{all} rational coordinates +in the context tableau. Based on this report, +the initial {\tt isl} implementation was adapted accordingly. + +\subsubsection{Generalized Basis Reduction}\label{s:GBR} + +The default algorithm used in {\tt isl} for feasibility checking +is generalized basis reduction \parencite{Cook1991implementation}. +This algorithm is also used in the {\tt barvinok} implementation. +The algorithm is fairly robust, but it has some overhead. +We therefore try to avoid calling the algorithm in easy cases. +In particular, we incrementally keep track of points for which +the entire unit hypercube positioned at that point lies in the context. +This set is described by translates of the constraints of the context +and if (rationally) non-empty, any rational point +in the set can be rounded up to yield an integer point in the context. + +A restriction of the algorithm is that it only works on bounded sets. +The affine hull of the recession cone therefore needs to be projected +out first. As soon as the algorithm is invoked, we then also +incrementally keep track of this recession cone. The reduced basis +found by one call of the algorithm is also reused as initial basis +for the next call. + +Some problems lead to the +introduction of many integer divisions. Within a given context, +some of these integer divisions may be equal to each other, even +if the expressions are not identical, or they may be equal to some +affine combination of other variables. +To detect such cases, we compute the affine hull of the context +each time a new integer division is added. The algorithm used +for computing this affine hull is that of \textcite{Karr1976affine}, +while the points used in this algorithm are obtained by performing +integer feasibility checks on that part of the context outside +the current approximation of the affine hull. +The list of witnesses is used to construct an initial approximation +of the hull, while any extra points found during the construction +of the hull is added to this list. +Any equality found in this way that expresses an integer division +as an \emph{integer} affine combination of other variables is +propagated to the main tableau, where it is used to eliminate that +integer division. + +\subsection{Experiments}\label{s:pip:experiments} + +\autoref{t:comparison} compares the execution times of {\tt isl} +(with both types of context tableau) +on some more difficult instances to those of other tools, +run on an Intel Xeon W3520 @ 2.66GHz. +These instances are available in the \lstinline{testsets/pip} directory +of the {\tt isl} distribution. +Easier problems such as the +test cases distributed with {\tt Pip\-Lib} can be solved so quickly +that we would only be measuring overhead such as input/output and conversions +and not the running time of the actual algorithm. +We compare the following versions: +{\tt piplib-1.4.0-5-g0132fd9}, +{\tt barvinok-0.32.1-73-gc5d7751}, +{\tt isl-0.05.1-82-g3a37260} +and {\tt PPL} version 0.11.2. + +The first test case is the following dependence analysis problem +originating from the Phideo project \parencite{Verhaegh1995PhD} +that was communicated to us by Bart Kienhuis: +\begin{lstlisting}[flexiblecolumns=true,breaklines=true]{} +lexmax { [j1,j2] -> [i1,i2,i3,i4,i5,i6,i7,i8,i9,i10] : 1 <= i1,j1 <= 8 and 1 <= i2,i3,i4,i5,i6,i7,i8,i9,i10 <= 2 and 1 <= j2 <= 128 and i1-1 = j1-1 and i2-1+2*i3-2+4*i4-4+8*i5-8+16*i6-16+32*i7-32+64*i8-64+128*i9-128+256*i10-256=3*j2-3+66 }; +\end{lstlisting} +This problem was the main inspiration +for some of the optimizations in \autoref{s:GBR}. +The second group of test cases are projections used during counting. +The first nine of these come from \textcite{Seghir2006minimizing}. +The remaining two come from \textcite{Verdoolaege2005experiences} and +were used to drive the first, Gomory cuts based, implementation +in {\tt isl}. +The third and final group of test cases are borrowed from +\textcite{Bygde2010licentiate} and inspired the offline symmetry detection +of \autoref{s:offline}. Without symmetry detection, the running times +are 11s and 5.9s. +All running times of {\tt barvinok} and {\tt isl} include a conversion +to disjunctive normal form. Without this conversion, the final two +cases can be solved in 0.07s and 0.21s. +The {\tt PipLib} implementation has some fixed limits and will +sometimes report the problem to be too complex (TC), while on some other +problems it will run out of memory (OOM). +The {\tt barvinok} implementation does not support problems +with a non-trivial lineality space (line) nor maximization problems (max). +The Gomory cuts based {\tt isl} implementation was terminated after 1000 +minutes on the first problem. The gbr version introduces some +overhead on some of the easier problems, but is overall the clear winner. + +\begin{table} +\begin{center} +\begin{tabular}{lrrrrr} + & {\tt PipLib} & {\tt barvinok} & {\tt isl} cut & {\tt isl} gbr & {\tt PPL} \\ +\hline +\hline +% bart.pip +Phideo & TC & 793m & $>$999m & 2.7s & 372m \\ +\hline +e1 & 0.33s & 3.5s & 0.08s & 0.11s & 0.18s \\ +e3 & 0.14s & 0.13s & 0.10s & 0.10s & 0.17s \\ +e4 & 0.24s & 9.1s & 0.09s & 0.11s & 0.70s \\ +e5 & 0.12s & 6.0s & 0.06s & 0.14s & 0.17s \\ +e6 & 0.10s & 6.8s & 0.17s & 0.08s & 0.21s \\ +e7 & 0.03s & 0.27s & 0.04s & 0.04s & 0.03s \\ +e8 & 0.03s & 0.18s & 0.03s & 0.04s & 0.01s \\ +e9 & OOM & 70m & 2.6s & 0.94s & 22s \\ +vd & 0.04s & 0.10s & 0.03s & 0.03s & 0.03s \\ +bouleti & 0.25s & line & 0.06s & 0.06s & 0.15s \\ +difficult & OOM & 1.3s & 1.7s & 0.33s & 1.4s \\ +\hline +cnt/sum & TC & max & 2.2s & 2.2s & OOM \\ +jcomplex & TC & max & 3.7s & 3.9s & OOM \\ +\end{tabular} +\caption{Comparison of Execution Times} +\label{t:comparison} +\end{center} +\end{table} + +\subsection{Online Symmetry Detection}\label{s:online} + +Manual experiments on small instances of the problems of +\textcite{Bygde2010licentiate} and an analysis of the results +by the approximate MPA method developed by \textcite{Bygde2010licentiate} +have revealed that these problems contain many more symmetries +than can be detected using the offline method of \autoref{s:offline}. +In this section, we present an online detection mechanism that has +not been implemented yet, but that has shown promising results +in manual applications. + +Let us first consider what happens when we do not perform offline +symmetry detection. At some point, one of the +$b_i(\vec p) + \sp {\vec a} {\vec x} \ge 0$ constraints, +say the $j$th constraint, appears as a column +variable, say $c_1$, while the other constraints are represented +as rows of the form $b_i(\vec p) - b_j(\vec p) + c$. +The context is then split according to the relative order of +$b_j(\vec p)$ and one of the remaining $b_i(\vec p)$. +The offline method avoids this split by replacing all $b_i(\vec p)$ +by a single newly introduced parameter that represents the minimum +of these $b_i(\vec p)$. +In the online method the split is similarly avoided by the introduction +of a new parameter. In particular, a new parameter is introduced +that represents +$\left| b_j(\vec p) - b_i(\vec p) \right|_+ = +\max(b_j(\vec p) - b_i(\vec p), 0)$. + +In general, let $r = b(\vec p) + \sp {\vec a} {\vec c}$ be a row +of the tableau such that the sign of $b(\vec p)$ is indeterminate +and such that exactly one of the elements of $\vec a$ is a $1$, +while all remaining elements are non-positive. +That is, $r = b(\vec p) + c_j - f$ with $f = -\sum_{i\ne j} a_i c_i \ge 0$. +We introduce a new parameter $t$ with +context constraints $t \ge -b(\vec p)$ and $t \ge 0$ and replace +the column variable $c_j$ by $c' + t$. The row $r$ is now equal +to $b(\vec p) + t + c' - f$. The constant term of this row is always +non-negative because any negative value of $b(\vec p)$ is compensated +by $t \ge -b(\vec p)$ while and non-negative value remains non-negative +because $t \ge 0$. + +We need to show that this transformation does not eliminate any valid +solutions and that it does not introduce any spurious solutions. +Given a valid solution for the original problem, we need to find +a non-negative value of $c'$ satisfying the constraints. +If $b(\vec p) \ge 0$, we can take $t = 0$ so that +$c' = c_j - t = c_j \ge 0$. +If $b(\vec p) < 0$, we can take $t = -b(\vec p)$. +Since $r = b(\vec p) + c_j - f \ge 0$ and $f \ge 0$, we have +$c' = c_j + b(\vec p) \ge 0$. +Note that these choices amount to plugging in +$t = \left|-b(\vec p)\right|_+ = \max(-b(\vec p), 0)$. +Conversely, given a solution to the new problem, we need to find +a non-negative value of $c_j$, but this is easy since $c_j = c' + t$ +and both of these are non-negative. + +Plugging in $t = \max(-b(\vec p), 0)$ can be performed as in +\autoref{s:post}, but, as in the case of offline symmetry detection, +it may be better to provide a direct representation for such +expressions in the internal representation of sets and relations +or at least in a quast-like output format. + +\section{Coalescing}\label{s:coalescing} + +See \textcite{Verdoolaege2015impact} for details on integer set coalescing. + +\section{Transitive Closure} + +\subsection{Introduction} + +\begin{definition}[Power of a Relation] +Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation and +$k \in \Z_{\ge 1}$ +a positive number, then power $k$ of relation $R$ is defined as +\begin{equation} +\label{eq:transitive:power} +R^k \coloneqq +\begin{cases} +R & \text{if $k = 1$} +\\ +R \circ R^{k-1} & \text{if $k \ge 2$} +. +\end{cases} +\end{equation} +\end{definition} + +\begin{definition}[Transitive Closure of a Relation] +Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation, +then the transitive closure $R^+$ of $R$ is the union +of all positive powers of $R$, +$$ +R^+ \coloneqq \bigcup_{k \ge 1} R^k +. +$$ +\end{definition} +Alternatively, the transitive closure may be defined +inductively as +\begin{equation} +\label{eq:transitive:inductive} +R^+ \coloneqq R \cup \left(R \circ R^+\right) +. +\end{equation} + +Since the transitive closure of a polyhedral relation +may no longer be a polyhedral relation \parencite{Kelly1996closure}, +we can, in the general case, only compute an approximation +of the transitive closure. +Whereas \textcite{Kelly1996closure} compute underapproximations, +we, like \textcite{Beletska2009}, compute overapproximations. +That is, given a relation $R$, we will compute a relation $T$ +such that $R^+ \subseteq T$. Of course, we want this approximation +to be as close as possible to the actual transitive closure +$R^+$ and we want to detect the cases where the approximation is +exact, i.e., where $T = R^+$. + +For computing an approximation of the transitive closure of $R$, +we follow the same general strategy as \textcite{Beletska2009} +and first compute an approximation of $R^k$ for $k \ge 1$ and then project +out the parameter $k$ from the resulting relation. + +\begin{example} +As a trivial example, consider the relation +$R = \{\, x \to x + 1 \,\}$. The $k$th power of this map +for arbitrary $k$ is +$$ +R^k = k \mapsto \{\, x \to x + k \mid k \ge 1 \,\} +. +$$ +The transitive closure is then +$$ +\begin{aligned} +R^+ & = \{\, x \to y \mid \exists k \in \Z_{\ge 1} : y = x + k \,\} +\\ +& = \{\, x \to y \mid y \ge x + 1 \,\} +. +\end{aligned} +$$ +\end{example} + +\subsection{Computing an Approximation of $R^k$} +\label{s:power} + +There are some special cases where the computation of $R^k$ is very easy. +One such case is that where $R$ does not compose with itself, +i.e., $R \circ R = \emptyset$ or $\domain R \cap \range R = \emptyset$. +In this case, $R^k$ is only non-empty for $k=1$ where it is equal +to $R$ itself. + +In general, it is impossible to construct a closed form +of $R^k$ as a polyhedral relation. +We will therefore need to make some approximations. +As a first approximations, we will consider each of the basic +relations in $R$ as simply adding one or more offsets to a domain element +to arrive at an image element and ignore the fact that some of these +offsets may only be applied to some of the domain elements. +That is, we will only consider the difference set $\Delta\,R$ of the relation. +In particular, we will first construct a collection $P$ of paths +that move through +a total of $k$ offsets and then intersect domain and range of this +collection with those of $R$. +That is, +\begin{equation} +\label{eq:transitive:approx} +K = P \cap \left(\domain R \to \range R\right) +, +\end{equation} +with +\begin{equation} +\label{eq:transitive:path} +P = \vec s \mapsto \{\, \vec x \to \vec y \mid +\exists k_i \in \Z_{\ge 0}, \vec\delta_i \in k_i \, \Delta_i(\vec s) : +\vec y = \vec x + \sum_i \vec\delta_i +\wedge +\sum_i k_i = k > 0 +\,\} +\end{equation} +and with $\Delta_i$ the basic sets that compose +the difference set $\Delta\,R$. +Note that the number of basic sets $\Delta_i$ need not be +the same as the number of basic relations in $R$. +Also note that since addition is commutative, it does not +matter in which order we add the offsets and so we are allowed +to group them as we did in \eqref{eq:transitive:path}. + +If all the $\Delta_i$s are singleton sets +$\Delta_i = \{\, \vec \delta_i \,\}$ with $\vec \delta_i \in \Z^d$, +then \eqref{eq:transitive:path} simplifies to +\begin{equation} +\label{eq:transitive:singleton} +P = \{\, \vec x \to \vec y \mid +\exists k_i \in \Z_{\ge 0} : +\vec y = \vec x + \sum_i k_i \, \vec \delta_i +\wedge +\sum_i k_i = k > 0 +\,\} +\end{equation} +and then the approximation computed in \eqref{eq:transitive:approx} +is essentially the same as that of \textcite{Beletska2009}. +If some of the $\Delta_i$s are not singleton sets or if +some of $\vec \delta_i$s are parametric, then we need +to resort to further approximations. + +To ease both the exposition and the implementation, we will for +the remainder of this section work with extended offsets +$\Delta_i' = \Delta_i \times \{\, 1 \,\}$. +That is, each offset is extended with an extra coordinate that is +set equal to one. The paths constructed by summing such extended +offsets have the length encoded as the difference of their +final coordinates. The path $P'$ can then be decomposed into +paths $P_i'$, one for each $\Delta_i$, +\begin{equation} +\label{eq:transitive:decompose} +P' = \left( +(P_m' \cup \identity) \circ \cdots \circ +(P_2' \cup \identity) \circ +(P_1' \cup \identity) +\right) \cap +\{\, +\vec x' \to \vec y' \mid y_{d+1} - x_{d+1} = k > 0 +\,\} +, +\end{equation} +with +$$ +P_i' = \vec s \mapsto \{\, \vec x' \to \vec y' \mid +\exists k \in \Z_{\ge 1}, \vec \delta \in k \, \Delta_i'(\vec s) : +\vec y' = \vec x' + \vec \delta +\,\} +. +$$ +Note that each $P_i'$ contains paths of length at least one. +We therefore need to take the union with the identity relation +when composing the $P_i'$s to allow for paths that do not contain +any offsets from one or more $\Delta_i'$. +The path that consists of only identity relations is removed +by imposing the constraint $y_{d+1} - x_{d+1} > 0$. +Taking the union with the identity relation means that +that the relations we compose in \eqref{eq:transitive:decompose} +each consist of two basic relations. If there are $m$ +disjuncts in the input relation, then a direct application +of the composition operation may therefore result in a relation +with $2^m$ disjuncts, which is prohibitively expensive. +It is therefore crucial to apply coalescing (\autoref{s:coalescing}) +after each composition. + +Let us now consider how to compute an overapproximation of $P_i'$. +Those that correspond to singleton $\Delta_i$s are grouped together +and handled as in \eqref{eq:transitive:singleton}. +Note that this is just an optimization. The procedure described +below would produce results that are at least as accurate. +For simplicity, we first assume that no constraint in $\Delta_i'$ +involves any existentially quantified variables. +We will return to existentially quantified variables at the end +of this section. +Without existentially quantified variables, we can classify +the constraints of $\Delta_i'$ as follows +\begin{enumerate} +\item non-parametric constraints +\begin{equation} +\label{eq:transitive:non-parametric} +A_1 \vec x + \vec c_1 \geq \vec 0 +\end{equation} +\item purely parametric constraints +\begin{equation} +\label{eq:transitive:parametric} +B_2 \vec s + \vec c_2 \geq \vec 0 +\end{equation} +\item negative mixed constraints +\begin{equation} +\label{eq:transitive:mixed} +A_3 \vec x + B_3 \vec s + \vec c_3 \geq \vec 0 +\end{equation} +such that for each row $j$ and for all $\vec s$, +$$ +\Delta_i'(\vec s) \cap +\{\, \vec \delta' \mid B_{3,j} \vec s + c_{3,j} > 0 \,\} += \emptyset +$$ +\item positive mixed constraints +$$ +A_4 \vec x + B_4 \vec s + \vec c_4 \geq \vec 0 +$$ +such that for each row $j$, there is at least one $\vec s$ such that +$$ +\Delta_i'(\vec s) \cap +\{\, \vec \delta' \mid B_{4,j} \vec s + c_{4,j} > 0 \,\} +\ne \emptyset +$$ +\end{enumerate} +We will use the following approximation $Q_i$ for $P_i'$: +\begin{equation} +\label{eq:transitive:Q} +\begin{aligned} +Q_i = \vec s \mapsto +\{\, +\vec x' \to \vec y' +\mid {} & \exists k \in \Z_{\ge 1}, \vec f \in \Z^d : +\vec y' = \vec x' + (\vec f, k) +\wedge {} +\\ +& +A_1 \vec f + k \vec c_1 \geq \vec 0 +\wedge +B_2 \vec s + \vec c_2 \geq \vec 0 +\wedge +A_3 \vec f + B_3 \vec s + \vec c_3 \geq \vec 0 +\,\} +. +\end{aligned} +\end{equation} +To prove that $Q_i$ is indeed an overapproximation of $P_i'$, +we need to show that for every $\vec s \in \Z^n$, for every +$k \in \Z_{\ge 1}$ and for every $\vec f \in k \, \Delta_i(\vec s)$ +we have that +$(\vec f, k)$ satisfies the constraints in \eqref{eq:transitive:Q}. +If $\Delta_i(\vec s)$ is non-empty, then $\vec s$ must satisfy +the constraints in \eqref{eq:transitive:parametric}. +Each element $(\vec f, k) \in k \, \Delta_i'(\vec s)$ is a sum +of $k$ elements $(\vec f_j, 1)$ in $\Delta_i'(\vec s)$. +Each of these elements satisfies the constraints in +\eqref{eq:transitive:non-parametric}, i.e., +$$ +\left[ +\begin{matrix} +A_1 & \vec c_1 +\end{matrix} +\right] +\left[ +\begin{matrix} +\vec f_j \\ 1 +\end{matrix} +\right] +\ge \vec 0 +. +$$ +The sum of these elements therefore satisfies the same set of inequalities, +i.e., $A_1 \vec f + k \vec c_1 \geq \vec 0$. +Finally, the constraints in \eqref{eq:transitive:mixed} are such +that for any $\vec s$ in the parameter domain of $\Delta$, +we have $-\vec r(\vec s) \coloneqq B_3 \vec s + \vec c_3 \le \vec 0$, +i.e., $A_3 \vec f_j \ge \vec r(\vec s) \ge \vec 0$ +and therefore also $A_3 \vec f \ge \vec r(\vec s)$. +Note that if there are no mixed constraints and if the +rational relaxation of $\Delta_i(\vec s)$, i.e., +$\{\, \vec x \in \Q^d \mid A_1 \vec x + \vec c_1 \ge \vec 0\,\}$, +has integer vertices, then the approximation is exact, i.e., +$Q_i = P_i'$. In this case, the vertices of $\Delta'_i(\vec s)$ +generate the rational cone +$\{\, \vec x' \in \Q^{d+1} \mid \left[ +\begin{matrix} +A_1 & \vec c_1 +\end{matrix} +\right] \vec x' \,\}$ and therefore $\Delta'_i(\vec s)$ is +a Hilbert basis of this cone \parencite[Theorem~16.4]{Schrijver1986}. + +Note however that, as pointed out by \textcite{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 +of the parameters and others. The first set can be treated +as parameters and the second as variables. Constraints involving +the other existentially quantified variables are removed. + +\begin{example} +Consider the relation +$$ +R = +n \to \{\, x \to y \mid \exists \, \alpha_0, \alpha_1: 7\alpha_0 = -2 + n \wedge 5\alpha_1 = -1 - x + y \wedge y \ge 6 + x \,\} +. +$$ +The difference set of this relation is +$$ +\Delta = \Delta \, R = +n \to \{\, x \mid \exists \, \alpha_0, \alpha_1: 7\alpha_0 = -2 + n \wedge 5\alpha_1 = -1 + x \wedge x \ge 6 \,\} +. +$$ +The existentially quantified variables can be defined in terms +of the parameters and variables as +$$ +\alpha_0 = \floor{\frac{-2 + n}7} +\qquad +\text{and} +\qquad +\alpha_1 = \floor{\frac{-1 + x}5} +. +$$ +$\alpha_0$ can therefore be treated as a parameter, +while $\alpha_1$ can be treated as a variable. +This in turn means that $7\alpha_0 = -2 + n$ can be treated as +a purely parametric constraint, while the other two constraints are +non-parametric. +The corresponding $Q$~\eqref{eq:transitive:Q} is therefore +$$ +\begin{aligned} +n \to \{\, (x,z) \to (y,w) \mid +\exists\, \alpha_0, \alpha_1, k, f : {} & +k \ge 1 \wedge +y = x + f \wedge +w = z + k \wedge {} \\ +& +7\alpha_0 = -2 + n \wedge +5\alpha_1 = -k + x \wedge +x \ge 6 k +\,\} +. +\end{aligned} +$$ +Projecting out the final coordinates encoding the length of the paths, +results in the exact transitive closure +$$ +R^+ = +n \to \{\, x \to y \mid \exists \, \alpha_0, \alpha_1: 7\alpha_1 = -2 + n \wedge 6\alpha_0 \ge -x + y \wedge 5\alpha_0 \le -1 - x + y \,\} +. +$$ +\end{example} + +The fact that we ignore some impure constraints clearly leads +to a loss of accuracy. In some cases, some of this loss can be recovered +by not considering the parameters in a special way. +That is, instead of considering the set +$$ +\Delta = \diff R = +\vec s \mapsto +\{\, \vec \delta \in \Z^{d} \mid \exists \vec x \to \vec y \in R : +\vec \delta = \vec y - \vec x +\,\} +$$ +we consider the set +$$ +\Delta' = \diff R' = +\{\, \vec \delta \in \Z^{n+d} \mid \exists +(\vec s, \vec x) \to (\vec s, \vec y) \in R' : +\vec \delta = (\vec s - \vec s, \vec y - \vec x) +\,\} +. +$$ +The first $n$ coordinates of every element in $\Delta'$ are zero. +Projecting out these zero coordinates from $\Delta'$ is equivalent +to projecting out the parameters in $\Delta$. +The result is obviously a superset of $\Delta$, but all its constraints +are of type \eqref{eq:transitive:non-parametric} and they can therefore +all be used in the construction of $Q_i$. + +\begin{example} +Consider the relation +$$ +% [n] -> { [x, y] -> [1 + x, 1 - n + y] | n >= 2 } +R = n \to \{\, (x, y) \to (1 + x, 1 - n + y) \mid n \ge 2 \,\} +. +$$ +We have +$$ +\diff R = n \to \{\, (1, 1 - n) \mid n \ge 2 \,\} +$$ +and so, by treating the parameters in a special way, we obtain +the following approximation for $R^+$: +$$ +n \to \{\, (x, y) \to (x', y') \mid n \ge 2 \wedge y' \le 1 - n + y \wedge x' \ge 1 + x \,\} +. +$$ +If we consider instead +$$ +R' = \{\, (n, x, y) \to (n, 1 + x, 1 - n + y) \mid n \ge 2 \,\} +$$ +then +$$ +\diff R' = \{\, (0, 1, y) \mid y \le -1 \,\} +$$ +and we obtain the approximation +$$ +n \to \{\, (x, y) \to (x', y') \mid n \ge 2 \wedge x' \ge 1 + x \wedge y' \le x + y - x' \,\} +. +$$ +If we consider both $\diff R$ and $\diff R'$, then we obtain +$$ +n \to \{\, (x, y) \to (x', y') \mid n \ge 2 \wedge y' \le 1 - n + y \wedge x' \ge 1 + x \wedge y' \le x + y - x' \,\} +. +$$ +Note, however, that this is not the most accurate affine approximation that +can be obtained. That would be +$$ +n \to \{\, (x, y) \to (x', y') \mid y' \le 2 - n + x + y - x' \wedge n \ge 2 \wedge x' \ge 1 + x \,\} +. +$$ +\end{example} + +\subsection{Checking Exactness} + +The approximation $T$ for the transitive closure $R^+$ can be obtained +by projecting out the parameter $k$ from the approximation $K$ +\eqref{eq:transitive:approx} of the power $R^k$. +Since $K$ is an overapproximation of $R^k$, $T$ will also be an +overapproximation of $R^+$. +To check whether the results are exact, we need to consider two +cases depending on whether $R$ is {\em cyclic}, where $R$ is defined +to be cyclic if $R^+$ maps any element to itself, i.e., +$R^+ \cap \identity \ne \emptyset$. +If $R$ is acyclic, then the inductive definition of +\eqref{eq:transitive:inductive} is equivalent to its completion, +i.e., +$$ +R^+ = R \cup \left(R \circ R^+\right) +$$ +is a defining property. +Since $T$ is known to be an overapproximation, we only need to check +whether +$$ +T \subseteq R \cup \left(R \circ T\right) +. +$$ +This is essentially Theorem~5 of \textcite{Kelly1996closure}. +The only difference is that they only consider lexicographically +forward relations, a special case of acyclic relations. + +If, on the other hand, $R$ is cyclic, then we have to resort +to checking whether the approximation $K$ of the power is exact. +Note that $T$ may be exact even if $K$ is not exact, so the check +is sound, but incomplete. +To check exactness of the power, we simply need to check +\eqref{eq:transitive:power}. Since again $K$ is known +to be an overapproximation, we only need to check whether +$$ +\begin{aligned} +K'|_{y_{d+1} - x_{d+1} = 1} & \subseteq R' +\\ +K'|_{y_{d+1} - x_{d+1} \ge 2} & \subseteq R' \circ K'|_{y_{d+1} - x_{d+1} \ge 1} +, +\end{aligned} +$$ +where $R' = \{\, \vec x' \to \vec y' \mid \vec x \to \vec y \in R +\wedge y_{d+1} - x_{d+1} = 1\,\}$, i.e., $R$ extended with path +lengths equal to 1. + +All that remains is to explain how to check the cyclicity of $R$. +Note that the exactness on the power is always sound, even +in the acyclic case, so we only need to be careful that we find +all cyclic cases. Now, if $R$ is cyclic, i.e., +$R^+ \cap \identity \ne \emptyset$, then, since $T$ is +an overapproximation of $R^+$, also +$T \cap \identity \ne \emptyset$. This in turn means +that $\Delta \, K'$ contains a point whose first $d$ coordinates +are zero and whose final coordinate is positive. +In the implementation we currently perform this test on $P'$ instead of $K'$. +Note that if $R^+$ is acyclic and $T$ is not, then the approximation +is clearly not exact and the approximation of the power $K$ +will not be exact either. + +\subsection{Decomposing $R$ into strongly connected components} + +If the input relation $R$ is a union of several basic relations +that can be partially ordered +then the accuracy of the approximation may be improved by computing +an approximation of each strongly connected components separately. +For example, if $R = R_1 \cup R_2$ and $R_1 \circ R_2 = \emptyset$, +then we know that any path that passes through $R_2$ cannot later +pass through $R_1$, i.e., +\begin{equation} +\label{eq:transitive:components} +R^+ = R_1^+ \cup R_2^+ \cup \left(R_2^+ \circ R_1^+\right) +. +\end{equation} +We can therefore compute (approximations of) transitive closures +of $R_1$ and $R_2$ separately. +Note, however, that the condition $R_1 \circ R_2 = \emptyset$ +is actually too strong. +If $R_1 \circ R_2$ is a subset of $R_2 \circ R_1$ +then we can reorder the segments +in any path that moves through both $R_1$ and $R_2$ to +first move through $R_1$ and then through $R_2$. + +This idea can be generalized to relations that are unions +of more than two basic relations by constructing the +strongly connected components in the graph with as vertices +the basic relations and an edge between two basic relations +$R_i$ and $R_j$ if $R_i$ needs to follow $R_j$ in some paths. +That is, there is an edge from $R_i$ to $R_j$ iff +\begin{equation} +\label{eq:transitive:edge} +R_i \circ R_j +\not\subseteq +R_j \circ R_i +. +\end{equation} +The components can be obtained from the graph by applying +Tarjan's algorithm \parencite{Tarjan1972}. + +In practice, we compute the (extended) powers $K_i'$ of each component +separately and then compose them as in \eqref{eq:transitive:decompose}. +Note, however, that in this case the order in which we apply them is +important and should correspond to a topological ordering of the +strongly connected components. Simply applying Tarjan's +algorithm will produce topologically sorted strongly connected components. +The graph on which Tarjan's algorithm is applied is constructed on-the-fly. +That is, whenever the algorithm checks if there is an edge between +two vertices, we evaluate \eqref{eq:transitive:edge}. +The exactness check is performed on each component separately. +If the approximation turns out to be inexact for any of the components, +then the entire result is marked inexact and the exactness check +is skipped on the components that still need to be handled. + +It should be noted that \eqref{eq:transitive:components} +is only valid for exact transitive closures. +If overapproximations are computed in the right hand side, then the result will +still be an overapproximation of the left hand side, but this result +may not be transitively closed. If we only separate components based +on the condition $R_i \circ R_j = \emptyset$, then there is no problem, +as this condition will still hold on the computed approximations +of the transitive closures. If, however, we have exploited +\eqref{eq:transitive:edge} during the decomposition and if the +result turns out not to be exact, then we check whether +the result is transitively closed. If not, we recompute +the transitive closure, skipping the decomposition. +Note that testing for transitive closedness on the result may +be fairly expensive, so we may want to make this check +configurable. + +\begin{figure} +\begin{center} +\begin{tikzpicture}[x=0.5cm,y=0.5cm,>=stealth,shorten >=1pt] +\foreach \x in {1,...,10}{ + \foreach \y in {1,...,10}{ + \draw[->] (\x,\y) -- (\x,\y+1); + } +} +\foreach \x in {1,...,20}{ + \foreach \y in {5,...,15}{ + \draw[->] (\x,\y) -- (\x+1,\y); + } +} +\end{tikzpicture} +\end{center} +\caption{The relation from \autoref{ex:closure4}} +\label{f:closure4} +\end{figure} +\begin{example} +\label{ex:closure4} +Consider the relation in example {\tt closure4} that comes with +the Omega calculator~\parencite{Omega_calc}, $R = R_1 \cup R_2$, +with +$$ +\begin{aligned} +R_1 & = \{\, (x,y) \to (x,y+1) \mid 1 \le x,y \le 10 \,\} +\\ +R_2 & = \{\, (x,y) \to (x+1,y) \mid 1 \le x \le 20 \wedge 5 \le y \le 15 \,\} +. +\end{aligned} +$$ +This relation is shown graphically in \autoref{f:closure4}. +We have +$$ +\begin{aligned} +R_1 \circ R_2 &= +\{\, (x,y) \to (x+1,y+1) \mid 1 \le x \le 9 \wedge 5 \le y \le 10 \,\} +\\ +R_2 \circ R_1 &= +\{\, (x,y) \to (x+1,y+1) \mid 1 \le x \le 10 \wedge 4 \le y \le 10 \,\} +. +\end{aligned} +$$ +Clearly, $R_1 \circ R_2 \subseteq R_2 \circ R_1$ and so +$$ +\left( +R_1 \cup R_2 +\right)^+ += +\left(R_2^+ \circ R_1^+\right) +\cup R_1^+ +\cup R_2^+ +. +$$ +\end{example} + +\begin{figure} +\newcounter{n} +\newcounter{t1} +\newcounter{t2} +\newcounter{t3} +\newcounter{t4} +\begin{center} +\begin{tikzpicture}[>=stealth,shorten >=1pt] +\setcounter{n}{7} +\foreach \i in {1,...,\value{n}}{ + \foreach \j in {1,...,\value{n}}{ + \setcounter{t1}{2 * \j - 4 - \i + 1} + \setcounter{t2}{\value{n} - 3 - \i + 1} + \setcounter{t3}{2 * \i - 1 - \j + 1} + \setcounter{t4}{\value{n} - \j + 1} + \ifnum\value{t1}>0\ifnum\value{t2}>0 + \ifnum\value{t3}>0\ifnum\value{t4}>0 + \draw[thick,->] (\i,\j) to[out=20] (\i+3,\j); + \fi\fi\fi\fi + \setcounter{t1}{2 * \j - 1 - \i + 1} + \setcounter{t2}{\value{n} - \i + 1} + \setcounter{t3}{2 * \i - 4 - \j + 1} + \setcounter{t4}{\value{n} - 3 - \j + 1} + \ifnum\value{t1}>0\ifnum\value{t2}>0 + \ifnum\value{t3}>0\ifnum\value{t4}>0 + \draw[thick,->] (\i,\j) to[in=-20,out=20] (\i,\j+3); + \fi\fi\fi\fi + \setcounter{t1}{2 * \j - 1 - \i + 1} + \setcounter{t2}{\value{n} - 1 - \i + 1} + \setcounter{t3}{2 * \i - 1 - \j + 1} + \setcounter{t4}{\value{n} - 1 - \j + 1} + \ifnum\value{t1}>0\ifnum\value{t2}>0 + \ifnum\value{t3}>0\ifnum\value{t4}>0 + \draw[thick,->] (\i,\j) to (\i+1,\j+1); + \fi\fi\fi\fi + } +} +\end{tikzpicture} +\end{center} +\caption{The relation from \autoref{ex:decomposition}} +\label{f:decomposition} +\end{figure} +\begin{example} +\label{ex:decomposition} +Consider the relation on the right of \textcite[Figure~2]{Beletska2009}, +reproduced in \autoref{f:decomposition}. +The relation can be described as $R = R_1 \cup R_2 \cup R_3$, +with +$$ +\begin{aligned} +R_1 &= n \mapsto \{\, (i,j) \to (i+3,j) \mid +i \le 2 j - 4 \wedge +i \le n - 3 \wedge +j \le 2 i - 1 \wedge +j \le n \,\} +\\ +R_2 &= n \mapsto \{\, (i,j) \to (i,j+3) \mid +i \le 2 j - 1 \wedge +i \le n \wedge +j \le 2 i - 4 \wedge +j \le n - 3 \,\} +\\ +R_3 &= n \mapsto \{\, (i,j) \to (i+1,j+1) \mid +i \le 2 j - 1 \wedge +i \le n - 1 \wedge +j \le 2 i - 1 \wedge +j \le n - 1\,\} +. +\end{aligned} +$$ +The figure shows this relation for $n = 7$. +Both +$R_3 \circ R_1 \subseteq R_1 \circ R_3$ +and +$R_3 \circ R_2 \subseteq R_2 \circ R_3$, +which the reader can verify using the {\tt iscc} calculator: +\begin{verbatim} +R1 := [n] -> { [i,j] -> [i+3,j] : i <= 2 j - 4 and i <= n - 3 and + j <= 2 i - 1 and j <= n }; +R2 := [n] -> { [i,j] -> [i,j+3] : i <= 2 j - 1 and i <= n and + j <= 2 i - 4 and j <= n - 3 }; +R3 := [n] -> { [i,j] -> [i+1,j+1] : i <= 2 j - 1 and i <= n - 1 and + j <= 2 i - 1 and j <= n - 1 }; +(R1 . R3) - (R3 . R1); +(R2 . R3) - (R3 . R2); +\end{verbatim} +$R_3$ can therefore be moved forward in any path. +For the other two basic relations, we have both +$R_2 \circ R_1 \not\subseteq R_1 \circ R_2$ +and +$R_1 \circ R_2 \not\subseteq R_2 \circ R_1$ +and so $R_1$ and $R_2$ form a strongly connected component. +By computing the power of $R_3$ and $R_1 \cup R_2$ separately +and composing the results, the power of $R$ can be computed exactly +using \eqref{eq:transitive:singleton}. +As explained by \textcite{Beletska2009}, applying the same formula +to $R$ directly, without a decomposition, would result in +an overapproximation of the power. +\end{example} + +\subsection{Partitioning the domains and ranges of $R$} + +The algorithm of \autoref{s:power} assumes that the input relation $R$ +can be treated as a union of translations. +This is a reasonable assumption if $R$ maps elements of a given +abstract domain to the same domain. +However, if $R$ is a union of relations that map between different +domains, then this assumption no longer holds. +In particular, when an entire dependence graph is encoded +in a single relation, as is done by, e.g., +\textcite[Section~6.1]{Barthou2000MSE}, then it does not make +sense to look at differences between iterations of different domains. +Now, arguably, a modified Floyd-Warshall algorithm should +be applied to the dependence graph, as advocated by +\textcite{Kelly1996closure}, with the transitive closure operation +only being applied to relations from a given domain to itself. +However, it is also possible to detect disjoint domains and ranges +and to apply Floyd-Warshall internally. + +\LinesNumbered +\begin{algorithm} +\caption{The modified Floyd-Warshall algorithm of +\protect\textcite{Kelly1996closure}} +\label{a:Floyd} +\SetKwInput{Input}{Input} +\SetKwInput{Output}{Output} +\Input{Relations $R_{pq}$, $0 \le p, q < n$} +\Output{Updated relations $R_{pq}$ such that each relation +$R_{pq}$ contains all indirect paths from $p$ to $q$ in the input graph} +% +\BlankLine +\SetAlgoVlined +\DontPrintSemicolon +% +\For{$r \in [0, n-1]$}{ + $R_{rr} \coloneqq R_{rr}^+$ \nllabel{l:Floyd:closure}\; + \For{$p \in [0, n-1]$}{ + \For{$q \in [0, n-1]$}{ + \If{$p \ne r$ or $q \ne r$}{ + $R_{pq} \coloneqq R_{pq} \cup \left(R_{rq} \circ R_{pr}\right) + \cup \left(R_{rq} \circ R_{rr} \circ R_{pr}\right)$ + \nllabel{l:Floyd:update} + } + } + } +} +\end{algorithm} + +Let the input relation $R$ be a union of $m$ basic relations $R_i$. +Let $D_{2i}$ be the domains of $R_i$ and $D_{2i+1}$ the ranges of $R_i$. +The first step is to group overlapping $D_j$ until a partition is +obtained. If the resulting partition consists of a single part, +then we continue with the algorithm of \autoref{s:power}. +Otherwise, we apply Floyd-Warshall on the graph with as vertices +the parts of the partition and as edges the $R_i$ attached to +the appropriate pairs of vertices. +In particular, let there be $n$ parts $P_k$ in the partition. +We construct $n^2$ relations +$$ +R_{pq} \coloneqq \bigcup_{i \text{ s.t. } \domain R_i \subseteq P_p \wedge + \range R_i \subseteq P_q} R_i +, +$$ +apply \autoref{a:Floyd} and return the union of all resulting +$R_{pq}$ as the transitive closure of $R$. +Each iteration of the $r$-loop in \autoref{a:Floyd} updates +all relations $R_{pq}$ to include paths that go from $p$ to $r$, +possibly stay there for a while, and then go from $r$ to $q$. +Note that paths that ``stay in $r$'' include all paths that +pass through earlier vertices since $R_{rr}$ itself has been updated +accordingly in previous iterations of the outer loop. +In principle, it would be sufficient to use the $R_{pr}$ +and $R_{rq}$ computed in the previous iteration of the +$r$-loop in Line~\ref{l:Floyd:update}. +However, from an implementation perspective, it is easier +to allow either or both of these to have been updated +in the same iteration of the $r$-loop. +This may result in duplicate paths, but these can usually +be removed by coalescing (\autoref{s:coalescing}) the result of the union +in Line~\ref{l:Floyd:update}, which should be done in any case. +The transitive closure in Line~\ref{l:Floyd:closure} +is performed using a recursive call. This recursive call +includes the partitioning step, but the resulting partition will +usually be a singleton. +The result of the recursive call will either be exact or an +overapproximation. The final result of Floyd-Warshall is therefore +also exact or an overapproximation. + +\begin{figure} +\begin{center} +\begin{tikzpicture}[x=1cm,y=1cm,>=stealth,shorten >=3pt] +\foreach \x/\y in {0/0,1/1,3/2} { + \fill (\x,\y) circle (2pt); +} +\foreach \x/\y in {0/1,2/2,3/3} { + \draw (\x,\y) circle (2pt); +} +\draw[->] (0,0) -- (0,1); +\draw[->] (0,1) -- (1,1); +\draw[->] (2,2) -- (3,2); +\draw[->] (3,2) -- (3,3); +\draw[->,dashed] (2,2) -- (3,3); +\draw[->,dotted] (0,0) -- (1,1); +\end{tikzpicture} +\end{center} +\caption{The relation (solid arrows) on the right of Figure~1 of +\protect\textcite{Beletska2009} and its transitive closure} +\label{f:COCOA:1} +\end{figure} +\begin{example} +Consider the relation on the right of Figure~1 of +\textcite{Beletska2009}, +reproduced in \autoref{f:COCOA:1}. +This relation can be described as +$$ +\begin{aligned} +\{\, (x, y) \to (x_2, y_2) \mid {} & (3y = 2x \wedge x_2 = x \wedge 3y_2 = 3 + 2x \wedge x \ge 0 \wedge x \le 3) \vee {} \\ +& (x_2 = 1 + x \wedge y_2 = y \wedge x \ge 0 \wedge 3y \ge 2 + 2x \wedge x \le 2 \wedge 3y \le 3 + 2x) \,\} +. +\end{aligned} +$$ +Note that the domain of the upward relation overlaps with the range +of the rightward relation and vice versa, but that the domain +of neither relation overlaps with its own range or the domain of +the other relation. +The domains and ranges can therefore be partitioned into two parts, +$P_0$ and $P_1$, shown as the white and black dots in \autoref{f:COCOA:1}, +respectively. +Initially, we have +$$ +\begin{aligned} +R_{00} & = \emptyset +\\ +R_{01} & = +\{\, (x, y) \to (x+1, y) \mid +(x \ge 0 \wedge 3y \ge 2 + 2x \wedge x \le 2 \wedge 3y \le 3 + 2x) \,\} +\\ +R_{10} & = +\{\, (x, y) \to (x_2, y_2) \mid (3y = 2x \wedge x_2 = x \wedge 3y_2 = 3 + 2x \wedge x \ge 0 \wedge x \le 3) \,\} +\\ +R_{11} & = \emptyset +. +\end{aligned} +$$ +In the first iteration, $R_{00}$ remains the same ($\emptyset^+ = \emptyset$). +$R_{01}$ and $R_{10}$ are therefore also unaffected, but +$R_{11}$ is updated to include $R_{01} \circ R_{10}$, i.e., +the dashed arrow in the figure. +This new $R_{11}$ is obviously transitively closed, so it is not +changed in the second iteration and it does not have an effect +on $R_{01}$ and $R_{10}$. However, $R_{00}$ is updated to +include $R_{10} \circ R_{01}$, i.e., the dotted arrow in the figure. +The transitive closure of the original relation is then equal to +$R_{00} \cup R_{01} \cup R_{10} \cup R_{11}$. +\end{example} + +\subsection{Incremental Computation} +\label{s:incremental} + +In some cases it is possible and useful to compute the transitive closure +of union of basic relations incrementally. In particular, +if $R$ is a union of $m$ basic maps, +$$ +R = \bigcup_j R_j +, +$$ +then we can pick some $R_i$ and compute the transitive closure of $R$ as +\begin{equation} +\label{eq:transitive:incremental} +R^+ = R_i^+ \cup +\left( +\bigcup_{j \ne i} +R_i^* \circ R_j \circ R_i^* +\right)^+ +. +\end{equation} +For this approach to be successful, it is crucial that each +of the disjuncts in the argument of the second transitive +closure in \eqref{eq:transitive:incremental} be representable +as a single basic relation, i.e., without a union. +If this condition holds, then by using \eqref{eq:transitive:incremental}, +the number of disjuncts in the argument of the transitive closure +can be reduced by one. +Now, $R_i^* = R_i^+ \cup \identity$, but in some cases it is possible +to relax the constraints of $R_i^+$ to include part of the identity relation, +say on domain $D$. We will use the notation +${\cal C}(R_i,D) = R_i^+ \cup \identity_D$ to represent +this relaxed version of $R^+$. +\textcite{Kelly1996closure} use the notation $R_i^?$. +${\cal C}(R_i,D)$ can be computed by allowing $k$ to attain +the value $0$ in \eqref{eq:transitive:Q} and by using +$$ +P \cap \left(D \to D\right) +$$ +instead of \eqref{eq:transitive:approx}. +Typically, $D$ will be a strict superset of both $\domain R_i$ +and $\range R_i$. We therefore need to check that domain +and range of the transitive closure are part of ${\cal C}(R_i,D)$, +i.e., the part that results from the paths of positive length ($k \ge 1$), +are equal to the domain and range of $R_i$. +If not, then the incremental approach cannot be applied for +the given choice of $R_i$ and $D$. + +In order to be able to replace $R^*$ by ${\cal C}(R_i,D)$ +in \eqref{eq:transitive:incremental}, $D$ should be chosen +to include both $\domain R$ and $\range R$, i.e., such +that $\identity_D \circ R_j \circ \identity_D = R_j$ for all $j\ne i$. +\textcite{Kelly1996closure} say that they use +$D = \domain R_i \cup \range R_i$, but presumably they mean that +they use $D = \domain R \cup \range R$. +Now, this expression of $D$ contains a union, so it not directly usable. +\textcite{Kelly1996closure} do not explain how they avoid this union. +Apparently, in their implementation, +they are using the convex hull of $\domain R \cup \range R$ +or at least an approximation of this convex hull. +We use the simple hull (\autoref{s:simple hull}) of $\domain R \cup \range R$. + +It is also possible to use a domain $D$ that does {\em not\/} +include $\domain R \cup \range R$, but then we have to +compose with ${\cal C}(R_i,D)$ more selectively. +In particular, if we have +\begin{equation} +\label{eq:transitive:right} +\text{for each $j \ne i$ either } +\domain R_j \subseteq D \text{ or } \domain R_j \cap \range R_i = \emptyset +\end{equation} +and, similarly, +\begin{equation} +\label{eq:transitive:left} +\text{for each $j \ne i$ either } +\range R_j \subseteq D \text{ or } \range R_j \cap \domain R_i = \emptyset +\end{equation} +then we can refine \eqref{eq:transitive:incremental} to +$$ +R_i^+ \cup +\left( +\left( +\bigcup_{\shortstack{$\scriptstyle\domain R_j \subseteq D $\\ + $\scriptstyle\range R_j \subseteq D$}} +{\cal C} \circ R_j \circ {\cal C} +\right) +\cup +\left( +\bigcup_{\shortstack{$\scriptstyle\domain R_j \cap \range R_i = \emptyset$\\ + $\scriptstyle\range R_j \subseteq D$}} +\!\!\!\!\! +{\cal C} \circ R_j +\right) +\cup +\left( +\bigcup_{\shortstack{$\scriptstyle\domain R_j \subseteq D $\\ + $\scriptstyle\range R_j \cap \domain R_i = \emptyset$}} +\!\!\!\!\! +R_j \circ {\cal C} +\right) +\cup +\left( +\bigcup_{\shortstack{$\scriptstyle\domain R_j \cap \range R_i = \emptyset$\\ + $\scriptstyle\range R_j \cap \domain R_i = \emptyset$}} +\!\!\!\!\! +R_j +\right) +\right)^+ +. +$$ +If only property~\eqref{eq:transitive:right} holds, +we can use +$$ +R_i^+ \cup +\left( +\left( +R_i^+ \cup \identity +\right) +\circ +\left( +\left( +\bigcup_{\shortstack{$\scriptstyle\domain R_j \subseteq D $}} +R_j \circ {\cal C} +\right) +\cup +\left( +\bigcup_{\shortstack{$\scriptstyle\domain R_j \cap \range R_i = \emptyset$}} +\!\!\!\!\! +R_j +\right) +\right)^+ +\right) +, +$$ +while if only property~\eqref{eq:transitive:left} holds, +we can use +$$ +R_i^+ \cup +\left( +\left( +\left( +\bigcup_{\shortstack{$\scriptstyle\range R_j \subseteq D $}} +{\cal C} \circ R_j +\right) +\cup +\left( +\bigcup_{\shortstack{$\scriptstyle\range R_j \cap \domain R_i = \emptyset$}} +\!\!\!\!\! +R_j +\right) +\right)^+ +\circ +\left( +R_i^+ \cup \identity +\right) +\right) +. +$$ + +It should be noted that if we want the result of the incremental +approach to be transitively closed, then we can only apply it +if all of the transitive closure operations involved are exact. +If, say, the second transitive closure in \eqref{eq:transitive:incremental} +contains extra elements, then the result does not necessarily contain +the composition of these extra elements with powers of $R_i$. + +\subsection{An {\tt Omega}-like implementation} + +While the main algorithm of \textcite{Kelly1996closure} is +designed to compute and underapproximation of the transitive closure, +the authors mention that they could also compute overapproximations. +In this section, we describe our implementation of an algorithm +that is based on their ideas. +Note that the {\tt Omega} library computes underapproximations +\parencite[Section 6.4]{Omega_lib}. + +The main tool is Equation~(2) of \textcite{Kelly1996closure}. +The input relation $R$ is first overapproximated by a ``d-form'' relation +$$ +\{\, \vec i \to \vec j \mid \exists \vec \alpha : +\vec L \le \vec j - \vec i \le \vec U +\wedge +(\forall p : j_p - i_p = M_p \alpha_p) +\,\} +, +$$ +where $p$ ranges over the dimensions and $\vec L$, $\vec U$ and +$\vec M$ are constant integer vectors. The elements of $\vec U$ +may be $\infty$, meaning that there is no upper bound corresponding +to that element, and similarly for $\vec L$. +Such an overapproximation can be obtained by computing strides, +lower and upper bounds on the difference set $\Delta \, R$. +The transitive closure of such a ``d-form'' relation is +\begin{equation} +\label{eq:omega} +\{\, \vec i \to \vec j \mid \exists \vec \alpha, k : +k \ge 1 \wedge +k \, \vec L \le \vec j - \vec i \le k \, \vec U +\wedge +(\forall p : j_p - i_p = M_p \alpha_p) +\,\} +. +\end{equation} +The domain and range of this transitive closure are then +intersected with those of the input relation. +This is a special case of the algorithm in \autoref{s:power}. + +In their algorithm for computing lower bounds, the authors +use the above algorithm as a substep on the disjuncts in the relation. +At the end, they say +\begin{quote} +If an upper bound is required, it can be calculated in a manner +similar to that of a single conjunct [sic] relation. +\end{quote} +Presumably, the authors mean that a ``d-form'' approximation +of the whole input relation should be used. +However, the accuracy can be improved by also trying to +apply the incremental technique from the same paper, +which is explained in more detail in \autoref{s:incremental}. +In this case, ${\cal C}(R_i,D)$ can be obtained by +allowing the value zero for $k$ in \eqref{eq:omega}, +i.e., by computing +$$ +\{\, \vec i \to \vec j \mid \exists \vec \alpha, k : +k \ge 0 \wedge +k \, \vec L \le \vec j - \vec i \le k \, \vec U +\wedge +(\forall p : j_p - i_p = M_p \alpha_p) +\,\} +. +$$ +In our implementation we take as $D$ the simple hull +(\autoref{s:simple hull}) of $\domain R \cup \range R$. +To determine whether it is safe to use ${\cal C}(R_i,D)$, +we check the following conditions, as proposed by +\textcite{Kelly1996closure}: +${\cal C}(R_i,D) - R_i^+$ is not a union and for each $j \ne i$ +the condition +$$ +\left({\cal C}(R_i,D) - R_i^+\right) +\circ +R_j +\circ +\left({\cal C}(R_i,D) - R_i^+\right) += +R_j +$$ +holds. Index: contrib/isl/doc/interface =================================================================== --- /dev/null +++ contrib/isl/doc/interface @@ -0,0 +1,27 @@ +Design guidelines for the isl interfaces +======================================== + +# Constructors + +A function that constructs an isl object can be exposed in two ways, as +an unnamed constructor or as a named static function. Aiming for an interface +that is explicit and close to the isl C interface, all such functions +are exported as named static functions, except in the following cases. +Unnamed constructors are generated for functions where even without the +function name an object is identified uniquely by its arguments. For +example, there is a single isl_val that corresponds to a given integer +(isl_val_int_from_si), but both a NaN or a zero value can be constructed +from an isl_local_space (isl_aff_zero_on_domain and isl_aff_nan_on_domain). +Only function that create objects that are fully constructed by the function +and do not require further information to be added for typical use cases +are exposed as unnamed constructors. +Functions that commonly require more information to be provided +(isl_union_access_info_from_sink, isl_schedule_constraints_on_domain) +are exported as named static functions. +Typical examples of function that are generated as unnamed constructors +are the following: + +- Conversion constructors +- Constructors from std::string +- Constructors where all arguments by themselves uniquely identify + a complete object (e.g., isl_val_int_from_si) Index: contrib/isl/doc/isl.bib =================================================================== --- /dev/null +++ contrib/isl/doc/isl.bib @@ -0,0 +1,485 @@ +@inproceedings{Kelly1996closure, + author = {Wayne Kelly and + William Pugh and + Evan Rosser and + Tatiana Shpeisman}, + title = {Transitive Closure of Infinite Graphs and Its Applications}, + pages = {126-140}, + editor = {Chua-Huang Huang and + P. Sadayappan and + Utpal Banerjee and + David Gelernter and + Alexandru Nicolau and + David A. Padua}, + booktitle = {Languages and Compilers for Parallel Computing, 8th International + Workshop, LCPC'95, Columbus, Ohio, USA, August 10-12, 1995, + Proceedings}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {1033}, + year = {1996}, + isbn = {3-540-60765-X}, + doi = "10.1007/BFb0014196", +} + +@inproceedings{Beletska2009, + author = {Beletska, Anna and Barthou, Denis and Bielecki, Wlodzimierz and Cohen, Albert}, + title = {Computing the Transitive Closure of a Union of Affine Integer Tuple Relations}, + booktitle = {COCOA '09: Proceedings of the 3rd International Conference on Combinatorial Optimization and Applications}, + year = {2009}, + isbn = {978-3-642-02025-4}, + pages = {98--109}, + location = {Huangshan, China}, + doi = {10.1007/978-3-642-02026-1_9}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, +} + +@book{Schrijver1986, + author = "Schrijver, Alexander", + title = "Theory of Linear and Integer Programming", + publisher = "John Wiley \& Sons", + year = 1986 +} + +@article{Tarjan1972, + author = {Tarjan, Robert}, + journal = {SIAM Journal on Computing}, + number = {2}, + pages = {146--160}, + publisher = {SIAM}, + title = {Depth-First Search and Linear Graph Algorithms}, + volume = {1}, + year = {1972}, + doi = "10.1137/0201010", +} + +@TechReport{ Omega_calc, + author = "Wayne Kelly and Vadim Maslov and William Pugh and Evan Rosser and Tatiana Shpeisman and Dave Wonnacott", + title = "The {Omega} Calculator and Library", + month = nov, + institution = "University of Maryland", + year = 1996 +} + +@TechReport{ Omega_lib, + author = "Wayne Kelly and Vadim Maslov and William Pugh and Evan Rosser and Tatiana Shpeisman and Dave Wonnacott", + title = "The {Omega} Library", + month = nov, + institution = "University of Maryland", + year = 1996 +} + +@unpublished{Verdoolaege2009isl, + author = "Verdoolaege, Sven", + title = "An integer set library for program analysis", + note = "Advances in the Theory of Integer Linear Optimization and its Extensions,AMS 2009 Spring Western Section Meeting, San Francisco, California, 25-26 April 2009", + month = Apr, + year = "2009", + url = "https://lirias.kuleuven.be/handle/123456789/228373", +} + +@article{Barthou2000MSE, + author = {Barthou, Denis and Cohen, Albert and Collard, Jean-Fran\c{c}ois}, + title = {Maximal Static Expansion}, + journal = {Int. J. Parallel Program.}, + volume = {28}, + number = {3}, + year = {2000}, + issn = {0885-7458}, + pages = {213--243}, + doi = {10.1023/A:1007500431910}, + publisher = {Kluwer Academic Publishers}, + address = {Norwell, MA, USA}, +} + +@article{ Feautrier88parametric, + author = "P. Feautrier", + title = "Parametric Integer Programming", + journal = "RAIRO Recherche Op\'erationnelle", + volume = "22", + number = "3", + pages = "243--268", + year = "1988", +} + +@Article{ Fea91, + author = {Feautrier, P.}, + title = {Dataflow analysis of array and scalar references}, + journal = {International Journal of Parallel Programming}, + year = {1991}, + OPTkey = {}, + volume = {20}, + number = {1}, + OPTmonth = {}, + pages = {23--53}, + OPTnote = {}, + OPTannote = {}, + doi = "10.1007/BF01407931", +} + +@INPROCEEDINGS{BouletRe98, + AUTHOR = {Pierre Boulet and Xavier Redon}, + TITLE = {Communication Pre-evaluation in {HPF}}, + BOOKTITLE = {EUROPAR'98}, + PAGES = {263--272}, + YEAR = 1998, + VOLUME = 1470, + series = {Lecture Notes in Computer Science}, + PUBLISHER = {Springer-Verlag, Berlin}, + ABSTRACT = { Parallel computers are difficult to program efficiently. We believe + that a good way to help programmers write efficient programs is to + provide them with tools that show them how their programs behave on + a parallel computer. Data distribution is the major performance + factor of data-parallel programs and so automatic data layout for + HPF programs has been studied by many researchers recently. The + communication volume induced by a data distribution is a good + estimator of the efficiency of this data distribution. + + We present here a symbolic method to compute the communication + volume generated by a given data distribution during the program + writing phase (before compilation). We stay machine-independent to + assure portability. Our goal is to help the programmer understand + the data movements its program generates and thus find a good data + distribution. Our method is based on parametric polyhedral + computations. It can be applied to a large class of regular codes.}, + doi = "10.1007/BFb0057861", +} + +@INPROCEEDINGS {Verdoolaege2005experiences, + AUTHOR = "Verdoolaege, Sven and Beyls, Kristof and Bruynooghe, Maurice and Catthoor, Francky", + TITLE = {{E}xperiences with enumeration of integer projections of parametric polytopes}, + BOOKTITLE = {{P}roceedings of 14th {I}nternational {C}onference on {C}ompiler {C}onstruction, {E}dinburgh, {S}cotland}, + YEAR = {2005}, + EDITOR = {Bodik, R.}, + VOLUME = 3443, + pages = "91-105", + series = "Lecture Notes in Computer Science", + publisher = "Springer-Verlag", + address = "Berlin", + doi = "10.1007/b107108", +} + +@article{Detlefs2005simplify, + author = {David Detlefs and Greg Nelson and James B. Saxe}, + title = {Simplify: a theorem prover for program checking}, + journal = {J. ACM}, + volume = {52}, + number = {3}, + year = {2005}, + issn = {0004-5411}, + pages = {365--473}, + doi = {10.1145/1066100.1066102}, + publisher = {ACM}, + address = {New York, NY, USA}, + } + +@phdthesis{Nelson1980phd, + author = {Charles Gregory Nelson}, + title = {Techniques for program verification}, + year = {1980}, + order_no = {AAI8011683}, + school = {Stanford University}, + address = {Stanford, CA, USA}, + } + +@article{Woods2003short, + year = 2003, + Journal = "J. Amer. Math. Soc.", + volume = 16, + pages = "957--979", + month = apr, + title = {{Short rational generating functions for lattice point + problems}}, + author = {Alexander Barvinok and Kevin Woods}, + doi = "10.1090/S0894-0347-03-00428-4", +} + +@misc{barvinok-0.22, + author = {Sven Verdoolaege}, + title = {{\texttt{barvinok}}, version 0.22}, + howpublished = {Available from \url{http://barvinok.gforge.inria.fr/}}, + year = 2006 +} + +@inproceedings{DeLoera2004Three, + title = "Three Kinds of Integer Programming Algorithms based on Barvinok's Rational Functions", + author = "De Loera, J. A. and D. Haws and R. Hemmecke and P. Huggins and R. Yoshida", + booktitle = "Integer Programming and Combinatorial Optimization: 10th International IPCO Conference", + year = "2004", + month = jan, + series = "Lecture Notes in Computer Science", + Volume = 3064, + Pages = "244-255", + doi = "10.1007/978-3-540-25960-2_19", +} + +@TechReport{Feautrier02, + author = {P. Feautrier and J. Collard and C. Bastoul}, + title = {Solving systems of affine (in)equalities}, + institution = {PRiSM, Versailles University}, + year = 2002 +} + +@article{ Feautrier92multi, + author = "Paul Feautrier", + title = "Some Efficient Solutions to the Affine Scheduling Problem. {P}art {II}. Multidimensional Time", + journal = "International Journal of Parallel Programming", + volume = "21", + number = "6", + pages = "389--420", + year = "1992", + month = dec, + url = "citeseer.nj.nec.com/article/feautrier92some.html", + doi = "10.1007/BF01379404", +} + +@misc{Bygde2010licentiate, + author = {Stefan Bygde}, + title = {Static {WCET} Analysis based on Abstract Interpretation and Counting of Elements}, + month = {March}, + year = {2010}, + howpublished = {Licentiate thesis}, + publisher = {M{\"{a}}lardalen University Press}, + url = {http://www.mrtc.mdh.se/index.php?choice=publications&id=2144}, +} + +@phdthesis{Meister2004PhD, + title = {Stating and Manipulating Periodicity in the Polytope Model. Applications to Program Analysis and Optimization}, + author= {Beno\^it Meister}, + school = {Universit\'e Louis Pasteur}, + month = Dec, + year = {2004}, +} + +@inproceedings{Meister2008, + author = {Beno\^it Meister and Sven Verdoolaege}, + title = {Polynomial Approximations in the Polytope Model: Bringing the Power + of Quasi-Polynomials to the Masses}, + year = {2008}, + booktitle = {Digest of the 6th Workshop on Optimization for DSP and Embedded Systems, ODES-6}, + editor = "Jagadeesh Sankaran and Vander Aa, Tom", + month = apr, +} + +@misc{Galea2009personal, + author = "Fran\c{c}ois Galea", + title = "personal communication", + year = 2009, + month = nov, +} + +@misc{PPL, + author = "R. Bagnara and P. M. Hill and E. Zaffanella", + title = "The {Parma Polyhedra Library}", + howpublished = {\url{http://www.cs.unipr.it/ppl/}}, +} + +@TECHREPORT{Cook1991implementation, +AUTHOR={William Cook and Thomas Rutherford and Herbert E. Scarf and David F. Shallcross}, +TITLE={An Implementation of the Generalized Basis Reduction Algorithm for Integer Programming}, +YEAR=1991, +MONTH=Aug, +INSTITUTION={Cowles Foundation, Yale University}, +TYPE={Cowles Foundation Discussion Papers}, +NOTE={available at \url{http://ideas.repec.org/p/cwl/cwldpp/990.html}}, +NUMBER={990}, +} + + @article{Karr1976affine, +author={ Michael Karr}, +title={ Affine Relationships Among Variables of a Program }, +journal={Acta Informatica}, +Volume={6}, +pages={133-151}, +year={1976}, +publisher={Springer-Verlag}, +ignore={ }, + doi = "10.1007/BF00268497", +} + +@PhdThesis{Verhaegh1995PhD, + title = "Multidimensional Periodic Scheduling", + author = "Wim F. J. Verhaegh", + school = "Technische Universiteit Eindhoven", + year = 1995, +} + +@INPROCEEDINGS{Seghir2006minimizing, + AUTHOR = "Rachid Seghir and Vincent Loechner", + TITLE = {Memory Optimization by Counting Points in Integer Transformations of Parametric Polytopes}, + BOOKTITLE = {{P}roceedings of the {I}nternational {C}onference on {C}ompilers, {A}rchitectures, and {S}ynthesis for {E}mbedded Systems, CASES 2006, {S}eoul, {K}orea}, + month = oct, + YEAR = {2006}, + doi = {10.1145/1176760.1176771}, +} + +@misc{DeSmet2010personal, + author = "De Smet, Sven", + title = "personal communication", + year = 2010, + month = apr, +} + +@inproceedings{Verdoolaege2015impact, + author = {Verdoolaege, Sven}, + title = {Integer Set Coalescing}, + booktitle = {Proceedings of the 5th International Workshop on + Polyhedral Compilation Techniques}, + year = 2015, + month = Jan, + address = {Amsterdam, The Netherlands}, + abstract = { +In polyhedral compilation, various core concepts such as the set +of statement instances, the access relations, the dependences and +the schedule are represented or approximated using sets and binary +relations of sequences of integers bounded by (quasi-)affine constraints. +When these sets and relations are represented in disjunctive normal form, +it is important to keep the number of disjuncts small, both for efficiency +and to improve the computation of transitive closure overapproximations +and AST generation. This paper describes the set coalescing operation +of isl that looks for opportunities to combine several disjuncts into +a single disjunct without affecting the elements in the set. The main +purpose of the paper is to explain the various heuristics and to prove +their correctness. + }, + doi = "10.13140/2.1.1313.6968", +} + +@misc{Verdoolaege2016tutorial, + author = "Sven Verdoolaege", + title = "Presburger Formulas and Polyhedral Compilation", + year = 2016, + doi = "10.13140/RG.2.1.1174.6323", +} + +@inproceedings{Verdoolaege2009equivalence, + author = "Sven Verdoolaege and Gerda Janssens and Maurice Bruynooghe", + title = "Equivalence checking of static affine programs using widening to handle recurrences", + booktitle = "Computer Aided Verification 21", + month = Jun, + year = 2009, + pages = "599--613", + publisher = "Springer", + doi = "10.1007/978-3-642-02658-4_44", +} + +@incollection{Verdoolaege2010isl, + author = {Verdoolaege, Sven}, + title = {isl: An Integer Set Library for the Polyhedral Model}, + booktitle = {Mathematical Software - ICMS 2010}, + series = {Lecture Notes in Computer Science}, + editor = {Fukuda, Komei and Hoeven, Joris and Joswig, Michael and Takayama, Nobuki}, + publisher = {Springer}, + isbn = {}, + pages = {299-302}, + volume = {6327}, + year = {2010}, + doi = {10.1007/978-3-642-15582-6_49}, +} + +@incollection{Verdoolaege2010networks, + author = "Verdoolaege, Sven", + title = "Polyhedral process networks", + editor = "Bhattacharrya, Shuvra and Deprettere, Ed and Leupers, Rainer and Takala, Jarmo", + publisher = "Springer", + year = "2010", + doi = "10.1007/978-1-4419-6345-1\_{}33", + pages = "931--965", + booktitle = "Handbook of Signal Processing Systems", + url = "https://lirias.kuleuven.be/handle/123456789/235370", + doi = "10.1007/978-1-4419-6345-1_33", +} + +@InProceedings{Verdoolaege2011iscc, + author = {Sven Verdoolaege}, + title = {Counting Affine Calculator and Applications}, + booktitle = { First International Workshop on Polyhedral Compilation Techniques (IMPACT'11)}, + address = { Chamonix, France}, + month = apr, + year = {2011}, + doi = "10.13140/RG.2.1.2959.5601", +} + +@inproceedings{Verdoolaege2011closure, + author = {Verdoolaege, Sven and Cohen, Albert and Beletska, Anna}, + title = {Transitive Closures of Affine Integer Tuple Relations and Their Overapproximations}, + booktitle = {Proceedings of the 18th International Conference on Static Analysis}, + series = {SAS'11}, + year = {2011}, + isbn = {978-3-642-23701-0}, + location = {Venice, Italy}, + pages = {216--232}, + numpages = {17}, + acmid = {2041570}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, + doi = "10.1007/978-3-642-23702-7_18", +} + +@article{Verdoolaege2013PPCG, + title={Polyhedral parallel code generation for {CUDA}}, + author={Verdoolaege, Sven and Juega, Juan Carlos and Cohen, Albert and G{\'o}mez, Jos{\'e} Ignacio and Tenllado, Christian and Catthoor, Francky}, + journal = {ACM Trans. Archit. Code Optim.}, + volume={9}, + number={4}, + pages={54}, + year={2013}, + publisher={ACM}, + doi = {10.1145/2400682.2400713}, +} + +@inproceedings{Verdoolaege2014impact, + author = {Verdoolaege, Sven and Guelton, Serge and + Grosser, Tobias and Cohen, Albert}, + title = {Schedule Trees}, + booktitle = {Proceedings of the 4th International Workshop on Polyhedral Compilation Techniques}, + year = 2014, + month = Jan, + address = {Vienna, Austria}, + url = {http://impact.gforge.inria.fr/impact2014/papers/impact2014-verdoolaege.pdf}, + abstract = { + Schedules in the polyhedral model, both those that represent the original +execution order and those produced by scheduling algorithms, naturally have the +form of a tree. Generic schedule representations proposed in the literature +encode this tree structure such that it is only implicitly available. +Following the internal representation of isl , we propose to represent +schedules as explicit trees and further extend the concept by introducing +different kinds of nodes. We compare our schedule trees to other +representations in detail and illustrate how they have been successfully used +to simplify the implementation of a non-trivial polyhedral compiler. + }, + DOI = {10.13140/RG.2.1.4475.6001}, +} + +@article{Grosser2015AST, + author = "Tobias Grosser and Sven Verdoolaege and Albert Cohen", + title = "Polyhedral {AST} generation is more than scanning polyhedra", + journal = "ACM Transactions on Programming Languages and Systems", + issue_date = {August 2015}, + volume = {37}, + number = {4}, + month = jul, + year = {2015}, + issn = {0164-0925}, + pages = {12:1--12:50}, + articleno = {12}, + numpages = {50}, + url = {http://doi.acm.org/10.1145/2743016}, + doi = {10.1145/2743016}, + acmid = {2743016}, + publisher = {ACM}, + address = {New York, NY, USA}, + keywords = {Polyhedral compilation, Presburger relations, code generation, index set splitting, unrolling}, +} + +@inproceedings{Verdoolaege2016reordering, + author = {Sven Verdoolaege and Albert Cohen}, + title = "Live-Range Reordering", + booktitle = {Proceedings of the sixth International Workshop on + Polyhedral Compilation Techniques}, + year = 2016, + month = Jan, + address = {Prague, Czech Republic}, + doi = "10.13140/RG.2.1.3272.9680", +} Index: contrib/isl/doc/manual.tex =================================================================== --- /dev/null +++ contrib/isl/doc/manual.tex @@ -0,0 +1,95 @@ +\documentclass{report} +\usepackage[T1]{fontenc} +\usepackage[plainpages=false,pdfpagelabels,breaklinks]{hyperref} +\usepackage[backend=biber,isbn=false,url=false,doi=true,% +maxbibnames=99,style=authoryear,sortcites=true,sorting=nyt,backref=true,% +indexing=true,mincitenames=2,maxcitenames=2,datelabel=comp,dashed=false,% +useprefix=true]{biblatex} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{txfonts} +\usepackage{aliascnt} +\usepackage{tikz} +\usepackage{calc} +\usepackage[ruled]{algorithm2e} +\usetikzlibrary{matrix,fit,backgrounds,decorations.pathmorphing,positioning} +\usepackage{listings} + +\addbibresource{isl.bib} + +\renewbibmacro*{finentry}{\iflistundef{pageref}{}{\renewcommand{\finentrypunct}{}}\finentry} +\renewbibmacro*{pageref}{% + \iflistundef{pageref} + {} + {\setunit{\adddot\addspace}\printtext{% + \mbox{}\penalty100\hfill\hbox{[\printlist[pageref][-\value{listtotal}]{pageref}]}}}} + +\lstset{basicstyle=\tt,flexiblecolumns=false} + +\def\vec#1{\mathchoice{\mbox{\boldmath$\displaystyle\bf#1$}} +{\mbox{\boldmath$\textstyle\bf#1$}} +{\mbox{\boldmath$\scriptstyle\bf#1$}} +{\mbox{\boldmath$\scriptscriptstyle\bf#1$}}} + +\providecommand{\fract}[1]{\left\{#1\right\}} +\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} +\newtheorem{example}[example]{Example} +\newaliascnt{def}{theorem} +\newtheorem{definition}[def]{Definition} +\aliascntresetthe{example} +\aliascntresetthe{def} +\numberwithin{theorem}{section} +\numberwithin{def}{section} +\numberwithin{example}{section} + +\newcommand{\algocflineautorefname}{Algorithm} +\newcommand{\exampleautorefname}{Example} +\newcommand{\lstnumberautorefname}{Line} +\renewcommand{\sectionautorefname}{Section} +\renewcommand{\subsectionautorefname}{Section} +\renewcommand{\algorithmautorefname}{Algorithm} + +\DeclareFieldFormat{date}{\hypertarget{\thefield{entrykey}}{#1}} +\def\isl{\hyperlink{Verdoolaege2010isl}{\texttt{isl}}\xspace} + +\def\Z{\mathbb{Z}} +\def\Q{\mathbb{Q}} + +\def\pdom{\mathop{\rm pdom}\nolimits} +\def\domain{\mathop{\rm dom}\nolimits} +\def\range{\mathop{\rm ran}\nolimits} +\def\identity{\mathop{\rm Id}\nolimits} +\def\diff{\mathop{\Delta}\nolimits} + +\providecommand{\floor}[1]{\left\lfloor#1\right\rfloor} + +\begin{document} + +\title{Integer Set Library: Manual\\ +\small Version: \input{version} } +\author{Sven Verdoolaege} + +\maketitle +\tableofcontents + +\chapter{User Manual} + +\input{user} + +\chapter{Implementation Details} + +\input{implementation} + +\chapter{Further Reading} + +\input{reading} + +\printbibliography + +\end{document} Index: contrib/isl/doc/mypod2latex =================================================================== --- /dev/null +++ contrib/isl/doc/mypod2latex @@ -0,0 +1,14 @@ +#!/usr/bin/perl + +use strict; +use Pod::LaTeX; + +my ($in, $out) = @ARGV; + +my $parser = new Pod::LaTeX( + AddPreamble => 0, + AddPostamble => 0, + LevelNoNum => 5, + ); + +$parser->parse_from_file($in, $out); Index: contrib/isl/doc/reading.tex =================================================================== --- /dev/null +++ contrib/isl/doc/reading.tex @@ -0,0 +1,46 @@ +\textcite{Verdoolaege2016tutorial} describes the concepts behind +\isl in some detail, mainly focusing on Presburger formulas, +but also including some information on polyhedral compilation, +especially on dependence analysis. +Individual aspects of \isl are described in the following publications. +\begin{itemize} +\item +\textcite{Verdoolaege2009equivalence} introduce \isl as a library +for manipulating sets of integers defined by linear inequalities and +integer divisions that is used in their equivalence checker. + +\item +\textcite{Verdoolaege2010isl} provides a more detailed description +of \isl at the time and still stands as the official reference for +\isl. However, many features were only added later on and one or +more of the publications below may be more appropriate as +a reference to these features. + +\item +\textcite[Section 5.1]{Verdoolaege2010networks} provides some +details on the dataflow analysis step, but also see +\textcite[Chapter 6]{Verdoolaege2016tutorial} and +\textcite{Verdoolaege2016reordering} for a more recent treatment. + +\item The concepts of structured and named spaces and the manipulation +of sets containing elements in different spaces were introduced +by \textcite{Verdoolaege2011iscc}. + +\item The transitive closure operation is described +by \textcite{Verdoolaege2011closure}. + +\item The scheduler is briefly described by +\textcite[Section 6.2]{Verdoolaege2013PPCG} and +\textcite[Section 2.4]{Verdoolaege2016reordering}. + +\item Schedule trees started out as ``trees of bands'' +\parencite[Section 6.2]{Verdoolaege2013PPCG}, were formally +introduced by \textcite{Verdoolaege2014impact}, and were +slightly refined by \textcite{Grosser2015AST}. + +\item The coalescing operation is described by +\textcite{Verdoolaege2015impact}. + +\item The AST generator is described by \textcite{Grosser2015AST}. + +\end{itemize} Index: contrib/isl/doc/user.pod =================================================================== --- /dev/null +++ contrib/isl/doc/user.pod @@ -0,0 +1,10939 @@ +=head1 Introduction + +C is a thread-safe C library for manipulating +sets and relations of integer points bounded by affine constraints. +The descriptions of the sets and relations may involve +both parameters and existentially quantified variables. +All computations are performed in exact integer arithmetic +using C or C. +The C library offers functionality that is similar +to that offered by the C and C libraries, +but the underlying algorithms are in most cases completely different. + +The library is by no means complete and some fairly basic +functionality is still missing. +Still, even in its current form, the library has been successfully +used as a backend polyhedral library for the polyhedral +scanner C and as part of an equivalence checker of +static affine programs. +For bug reports, feature requests and questions, +visit the discussion group at +L. + +=head2 Backward Incompatible Changes + +=head3 Changes since isl-0.02 + +=over + +=item * The old printing functions have been deprecated +and replaced by C functions, see L. + +=item * Most functions related to dependence analysis have acquired +an extra C argument. To obtain the old behavior, this argument +should be given the value 1. See L. + +=back + +=head3 Changes since isl-0.03 + +=over + +=item * The function C has been +renamed to C. +Similarly, C has been +renamed to C. + +=back + +=head3 Changes since isl-0.04 + +=over + +=item * All header files have been renamed from C +to C. + +=back + +=head3 Changes since isl-0.05 + +=over + +=item * The functions C and +C no longer print a newline. + +=item * The functions C +and C now return +the accesses for which no source could be found instead of +the iterations where those accesses occur. + +=item * The functions C and +C now take a B space as input. An old call +C can be rewritten to +C. + +=item * The function C no longer takes +a parameter position as input. Instead, the exponent +is now expressed as the domain of the resulting relation. + +=back + +=head3 Changes since isl-0.06 + +=over + +=item * The format of C's +C output has changed. +Use C to obtain the old output. + +=item * The C<*_fast_*> functions have been renamed to C<*_plain_*>. +Some of the old names have been kept for backward compatibility, +but they will be removed in the future. + +=back + +=head3 Changes since isl-0.07 + +=over + +=item * The function C has been renamed to +C. +Similarly, the function C has been renamed to +C. + +=item * The C type has been renamed to C +along with the associated functions. +Some of the old names have been kept for backward compatibility, +but they will be removed in the future. + +=item * Spaces of maps, sets and parameter domains are now +treated differently. The distinction between map spaces and set spaces +has always been made on a conceptual level, but proper use of such spaces +was never checked. Furthermore, up until isl-0.07 there was no way +of explicitly creating a parameter space. These can now be created +directly using C or from other spaces using +C. + +=item * The space in which C, C, C, +C, C and C +objects live is now a map space +instead of a set space. This means, for example, that the dimensions +of the domain of an C are now considered to be of type +C instead of C. Extra functions have been +added to obtain the domain space. Some of the constructors still +take a domain space and have therefore been renamed. + +=item * The functions C and C +now take an C instead of an C. +An C can be created from an C +using C. + +=item * The C type has been removed. Functions that used +to return an C now return an C. +Note that the space of an C is that of relation. +When replacing a call to C by a call to +C any C argument needs +to be replaced by C. +A call to C can be replaced by a call +to C. +A call to C call be replaced by +the nested call + + isl_qpolynomial_from_aff(isl_aff_floor(div)) + +The function C has also been renamed +to C. + +=item * The C argument has been removed from +C and similar functions. +When reading input in the original PolyLib format, +the result will have no parameters. +If parameters are expected, the caller may want to perform +dimension manipulation on the result. + +=back + +=head3 Changes since isl-0.09 + +=over + +=item * The C option has been replaced +by the C option. + +=item * The first argument of C is now +an C instead of an C. +A call C can be replaced by + + isl_pw_aff_cond(isl_set_indicator_function(a), b, c) + +=back + +=head3 Changes since isl-0.10 + +=over + +=item * The functions C and +C have been renamed to +C and +C. +The new C and +C have slightly different meanings. + +=back + +=head3 Changes since isl-0.12 + +=over + +=item * C has been replaced by C. +Some of the old functions are still available in C +but they will be removed in the future. + +=item * The functions C, +C, C +and C have been changed to return +an C instead of an C. + +=item * The function C +has been removed. Essentially the same functionality is available +through C, except that it requires +setting up coincidence constraints. +The option C has accordingly been +replaced by the option C. + +=item * The function C has been changed +to return an C instead of a rational C. +The function C has been changed to return +a regular basic set, rather than a rational basic set. + +=back + +=head3 Changes since isl-0.14 + +=over + +=item * The function C now consistently +computes the sum on the shared definition domain. +The function C has been added +to compute the sum on the union of definition domains. +The original behavior of C was +confused and is no longer available. + +=item * Band forests have been replaced by schedule trees. + +=item * The function C has been +replaced by the function C. +Note that the may dependence relation returned by +C is the union of +the two dependence relations returned by +C. Similarly for the no source relations. +The function C is still available +for backward compatibility, but it will be removed in the future. + +=item * The function C has been +deprecated. + +=item * The function C has been +renamed to C. +The original name is still available +for backward compatibility, but it will be removed in the future. + +=item * The C AST generation option has been +deprecated. + +=item * The functions C and C +have been renamed to C and +C. The original names have been +kept for backward compatibility, but they will be removed in the future. + +=item * The C option has been replaced +by the C option. The effect +of setting the C option to C +is now obtained by turning on the C option. + +=back + +=head3 Changes since isl-0.17 + +=over + +=item * The function C no longer prints +in C format by default. To print in C format, the output format +of the printer needs to have been explicitly set to C. +As a result, the function C no longer prints +the expression in C format. Use C instead. + +=item * The functions C and C +have been deprecated. The function C has an effect +that is similar to C and could in some cases +be used as an alternative. + +=back + +=head1 License + +C is released under the MIT license. + +=over + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=back + +Note that by default C requires C, which is released +under the GNU Lesser General Public License (LGPL). This means +that code linked against C is also linked against LGPL code. + +When configuring with C<--with-int=imath> or C<--with-int=imath-32>, C +will link against C, a library for exact integer arithmetic released +under the MIT license. + +=head1 Installation + +The source of C can be obtained either as a tarball +or from the git repository. Both are available from +L. +The installation process depends on how you obtained +the source. + +=head2 Installation from the git repository + +=over + +=item 1 Clone or update the repository + +The first time the source is obtained, you need to clone +the repository. + + git clone git://repo.or.cz/isl.git + +To obtain updates, you need to pull in the latest changes + + git pull + +=item 2 Optionally get C submodule + +To build C with C, you need to obtain the C +submodule by running in the git source tree of C + + git submodule init + git submodule update + +This will fetch the required version of C in a subdirectory of C. + +=item 2 Generate C + + ./autogen.sh + +=back + +After performing the above steps, continue +with the L. + +=head2 Common installation instructions + +=over + +=item 1 Obtain C + +By default, building C requires C, including its headers files. +Your distribution may not provide these header files by default +and you may need to install a package called C or something +similar. Alternatively, C can be built from +source, available from L. +C is not needed if you build C with C. + +=item 2 Configure + +C uses the standard C C script. +To run it, just type + + ./configure + +optionally followed by some configure options. +A complete list of options can be obtained by running + + ./configure --help + +Below we discuss some of the more common options. + +=over + +=item C<--prefix> + +Installation prefix for C + +=item C<--with-int=[gmp|imath|imath-32]> + +Select the integer library to be used by C, the default is C. +With C, C will use 32 bit integers, but fall back to C +for values out of the 32 bit range. In most applications, C will run +fastest with the C option, followed by C and C, the +slowest. + +=item C<--with-gmp-prefix> + +Installation prefix for C (architecture-independent files). + +=item C<--with-gmp-exec-prefix> + +Installation prefix for C (architecture-dependent files). + +=back + +=item 3 Compile + + make + +=item 4 Install (optional) + + make install + +=back + +=head1 Integer Set Library + +=head2 Memory Management + +Since a high-level operation on isl objects usually involves +several substeps and since the user is usually not interested in +the intermediate results, most functions that return a new object +will also release all the objects passed as arguments. +If the user still wants to use one or more of these arguments +after the function call, she should pass along a copy of the +object rather than the object itself. +The user is then responsible for making sure that the original +object gets used somewhere else or is explicitly freed. + +The arguments and return values of all documented functions are +annotated to make clear which arguments are released and which +arguments are preserved. In particular, the following annotations +are used + +=over + +=item C<__isl_give> + +C<__isl_give> means that a new object is returned. +The user should make sure that the returned pointer is +used exactly once as a value for an C<__isl_take> argument. +In between, it can be used as a value for as many +C<__isl_keep> arguments as the user likes. +There is one exception, and that is the case where the +pointer returned is C. Is this case, the user +is free to use it as an C<__isl_take> argument or not. +When applied to a C, the returned pointer needs to be +freed using C. + +=item C<__isl_null> + +C<__isl_null> means that a C value is returned. + +=item C<__isl_take> + +C<__isl_take> means that the object the argument points to +is taken over by the function and may no longer be used +by the user as an argument to any other function. +The pointer value must be one returned by a function +returning an C<__isl_give> pointer. +If the user passes in a C value, then this will +be treated as an error in the sense that the function will +not perform its usual operation. However, it will still +make sure that all the other C<__isl_take> arguments +are released. + +=item C<__isl_keep> + +C<__isl_keep> means that the function will only use the object +temporarily. After the function has finished, the user +can still use it as an argument to other functions. +A C value will be treated in the same way as +a C value for an C<__isl_take> argument. +This annotation may also be used on return values of +type C, in which case the returned pointer should +not be freed by the user and is only valid until the object +from which it was derived is updated or freed. + +=back + +=head2 Initialization + +All manipulations of integer sets and relations occur within +the context of an C. +A given C can only be used within a single thread. +All arguments of a function are required to have been allocated +within the same context. +There are currently no functions available for moving an object +from one C to another C. This means that +there is currently no way of safely moving an object from one +thread to another, unless the whole C is moved. + +An C can be allocated using C and +freed using C. +All objects allocated within an C should be freed +before the C itself is freed. + + isl_ctx *isl_ctx_alloc(); + void isl_ctx_free(isl_ctx *ctx); + +The user can impose a bound on the number of low-level I +that can be performed by an C. This bound can be set and +retrieved using the following functions. A bound of zero means that +no bound is imposed. The number of operations performed can be +reset using C. Note that the number +of low-level operations needed to perform a high-level computation +may differ significantly across different versions +of C, but it should be the same across different platforms +for the same version of C. + +Warning: This feature is experimental. C has good support to abort and +bail out during the computation, but this feature may exercise error code paths +that are normally not used that much. Consequently, it is not unlikely that +hidden bugs will be exposed. + + void isl_ctx_set_max_operations(isl_ctx *ctx, + unsigned long max_operations); + unsigned long isl_ctx_get_max_operations(isl_ctx *ctx); + void isl_ctx_reset_operations(isl_ctx *ctx); + +In order to be able to create an object in the same context +as another object, most object types (described later in +this document) provide a function to obtain the context +in which the object was created. + + #include + isl_ctx *isl_val_get_ctx(__isl_keep isl_val *val); + isl_ctx *isl_multi_val_get_ctx( + __isl_keep isl_multi_val *mv); + + #include + isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id); + + #include + isl_ctx *isl_local_space_get_ctx( + __isl_keep isl_local_space *ls); + + #include + isl_ctx *isl_set_list_get_ctx( + __isl_keep isl_set_list *list); + + #include + isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff); + isl_ctx *isl_multi_aff_get_ctx( + __isl_keep isl_multi_aff *maff); + isl_ctx *isl_pw_aff_get_ctx(__isl_keep isl_pw_aff *pa); + isl_ctx *isl_pw_multi_aff_get_ctx( + __isl_keep isl_pw_multi_aff *pma); + isl_ctx *isl_multi_pw_aff_get_ctx( + __isl_keep isl_multi_pw_aff *mpa); + isl_ctx *isl_union_pw_aff_get_ctx( + __isl_keep isl_union_pw_aff *upa); + isl_ctx *isl_union_pw_multi_aff_get_ctx( + __isl_keep isl_union_pw_multi_aff *upma); + isl_ctx *isl_multi_union_pw_aff_get_ctx( + __isl_keep isl_multi_union_pw_aff *mupa); + + #include + isl_ctx *isl_id_to_ast_expr_get_ctx( + __isl_keep isl_id_to_ast_expr *id2expr); + + #include + isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt); + + #include + isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec); + + #include + isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat); + + #include + isl_ctx *isl_vertices_get_ctx( + __isl_keep isl_vertices *vertices); + isl_ctx *isl_vertex_get_ctx(__isl_keep isl_vertex *vertex); + isl_ctx *isl_cell_get_ctx(__isl_keep isl_cell *cell); + + #include + isl_ctx *isl_restriction_get_ctx( + __isl_keep isl_restriction *restr); + isl_ctx *isl_union_access_info_get_ctx( + __isl_keep isl_union_access_info *access); + isl_ctx *isl_union_flow_get_ctx( + __isl_keep isl_union_flow *flow); + + #include + isl_ctx *isl_schedule_get_ctx( + __isl_keep isl_schedule *sched); + isl_ctx *isl_schedule_constraints_get_ctx( + __isl_keep isl_schedule_constraints *sc); + + #include + isl_ctx *isl_schedule_node_get_ctx( + __isl_keep isl_schedule_node *node); + + #include + isl_ctx *isl_ast_build_get_ctx( + __isl_keep isl_ast_build *build); + + #include + isl_ctx *isl_ast_expr_get_ctx( + __isl_keep isl_ast_expr *expr); + isl_ctx *isl_ast_node_get_ctx( + __isl_keep isl_ast_node *node); + +=head2 Return Types + +C uses two special return types for functions that either return +a boolean or that in principle do not return anything. +In particular, the C type has three possible values: +C (a positive integer value), indicating I or I; +C (the integer value zero), indicating I or I; and +C (a negative integer value), indicating that something +went wrong. The following function can be used to negate an C, +where the negation of C is C again. + + #include + isl_bool isl_bool_not(isl_bool b); + +The C type has two possible values: +C (the integer value zero), indicating a successful +operation; and +C (a negative integer value), indicating that something +went wrong. +See L for more information on +C and C. + +=head2 Values + +An C represents an integer value, a rational value +or one of three special values, infinity, negative infinity and NaN. +Some predefined values can be created using the following functions. + + #include + __isl_give isl_val *isl_val_zero(isl_ctx *ctx); + __isl_give isl_val *isl_val_one(isl_ctx *ctx); + __isl_give isl_val *isl_val_negone(isl_ctx *ctx); + __isl_give isl_val *isl_val_nan(isl_ctx *ctx); + __isl_give isl_val *isl_val_infty(isl_ctx *ctx); + __isl_give isl_val *isl_val_neginfty(isl_ctx *ctx); + +Specific integer values can be created using the following functions. + + #include + __isl_give isl_val *isl_val_int_from_si(isl_ctx *ctx, + long i); + __isl_give isl_val *isl_val_int_from_ui(isl_ctx *ctx, + unsigned long u); + __isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, + size_t n, size_t size, const void *chunks); + +The function C constructs an C +from the C I, each consisting of C bytes, stored at C. +The least significant digit is assumed to be stored first. + +Value objects can be copied and freed using the following functions. + + #include + __isl_give isl_val *isl_val_copy(__isl_keep isl_val *v); + __isl_null isl_val *isl_val_free(__isl_take isl_val *v); + +They can be inspected using the following functions. + + #include + long isl_val_get_num_si(__isl_keep isl_val *v); + long isl_val_get_den_si(__isl_keep isl_val *v); + __isl_give isl_val *isl_val_get_den_val( + __isl_keep isl_val *v); + double isl_val_get_d(__isl_keep isl_val *v); + size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, + size_t size); + int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, + size_t size, void *chunks); + +C returns the number of I +of C bytes needed to store the absolute value of the +numerator of C. +C stores these digits at C, +which is assumed to have been preallocated by the caller. +The least significant digit is stored first. +Note that C, C, +C, C +and C can only be applied to rational values. + +An C can be modified using the following function. + + #include + __isl_give isl_val *isl_val_set_si(__isl_take isl_val *v, + long i); + +The following unary properties are defined on Cs. + + #include + int isl_val_sgn(__isl_keep isl_val *v); + isl_bool isl_val_is_zero(__isl_keep isl_val *v); + isl_bool isl_val_is_one(__isl_keep isl_val *v); + isl_bool isl_val_is_negone(__isl_keep isl_val *v); + isl_bool isl_val_is_nonneg(__isl_keep isl_val *v); + isl_bool isl_val_is_nonpos(__isl_keep isl_val *v); + isl_bool isl_val_is_pos(__isl_keep isl_val *v); + isl_bool isl_val_is_neg(__isl_keep isl_val *v); + isl_bool isl_val_is_int(__isl_keep isl_val *v); + isl_bool isl_val_is_rat(__isl_keep isl_val *v); + isl_bool isl_val_is_nan(__isl_keep isl_val *v); + isl_bool isl_val_is_infty(__isl_keep isl_val *v); + isl_bool isl_val_is_neginfty(__isl_keep isl_val *v); + +Note that the sign of NaN is undefined. + +The following binary properties are defined on pairs of Cs. + + #include + isl_bool isl_val_lt(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + isl_bool isl_val_le(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + isl_bool isl_val_gt(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + isl_bool isl_val_ge(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + isl_bool isl_val_eq(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + isl_bool isl_val_ne(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + isl_bool isl_val_abs_eq(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + +Comparisons to NaN always return false. +That is, a NaN is not considered to hold any relative position +with respect to any value. In particular, a NaN +is neither considered to be equal to nor to be different from +any value (including another NaN). +The function C checks whether its two arguments +are equal in absolute value. + +For integer Cs we additionally have the following binary property. + + #include + isl_bool isl_val_is_divisible_by(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + +An C can also be compared to an integer using the following +function. The result is undefined for NaN. + + #include + int isl_val_cmp_si(__isl_keep isl_val *v, long i); + +The following unary operations are available on Cs. + + #include + __isl_give isl_val *isl_val_abs(__isl_take isl_val *v); + __isl_give isl_val *isl_val_neg(__isl_take isl_val *v); + __isl_give isl_val *isl_val_floor(__isl_take isl_val *v); + __isl_give isl_val *isl_val_ceil(__isl_take isl_val *v); + __isl_give isl_val *isl_val_trunc(__isl_take isl_val *v); + __isl_give isl_val *isl_val_inv(__isl_take isl_val *v); + __isl_give isl_val *isl_val_2exp(__isl_take isl_val *v); + +The following binary operations are available on Cs. + + #include + __isl_give isl_val *isl_val_min(__isl_take isl_val *v1, + __isl_take isl_val *v2); + __isl_give isl_val *isl_val_max(__isl_take isl_val *v1, + __isl_take isl_val *v2); + __isl_give isl_val *isl_val_add(__isl_take isl_val *v1, + __isl_take isl_val *v2); + __isl_give isl_val *isl_val_add_ui(__isl_take isl_val *v1, + unsigned long v2); + __isl_give isl_val *isl_val_sub(__isl_take isl_val *v1, + __isl_take isl_val *v2); + __isl_give isl_val *isl_val_sub_ui(__isl_take isl_val *v1, + unsigned long v2); + __isl_give isl_val *isl_val_mul(__isl_take isl_val *v1, + __isl_take isl_val *v2); + __isl_give isl_val *isl_val_mul_ui(__isl_take isl_val *v1, + unsigned long v2); + __isl_give isl_val *isl_val_div(__isl_take isl_val *v1, + __isl_take isl_val *v2); + __isl_give isl_val *isl_val_div_ui(__isl_take isl_val *v1, + unsigned long v2); + +On integer values, we additionally have the following operations. + + #include + __isl_give isl_val *isl_val_2exp(__isl_take isl_val *v); + __isl_give isl_val *isl_val_mod(__isl_take isl_val *v1, + __isl_take isl_val *v2); + __isl_give isl_val *isl_val_gcd(__isl_take isl_val *v1, + __isl_take isl_val *v2); + __isl_give isl_val *isl_val_gcdext(__isl_take isl_val *v1, + __isl_take isl_val *v2, __isl_give isl_val **x, + __isl_give isl_val **y); + +The function C returns the greatest common divisor g +of C and C as well as two integers C<*x> and C<*y> such +that C<*x> * C + C<*y> * C = g. + +=head3 GMP specific functions + +These functions are only available if C has been compiled with C +support. + +Specific integer and rational values can be created from C values using +the following functions. + + #include + __isl_give isl_val *isl_val_int_from_gmp(isl_ctx *ctx, + mpz_t z); + __isl_give isl_val *isl_val_from_gmp(isl_ctx *ctx, + const mpz_t n, const mpz_t d); + +The numerator and denominator of a rational value can be extracted as +C values using the following functions. + + #include + int isl_val_get_num_gmp(__isl_keep isl_val *v, mpz_t z); + int isl_val_get_den_gmp(__isl_keep isl_val *v, mpz_t z); + +=head2 Sets and Relations + +C uses six types of objects for representing sets and relations, +C, C, C, C, +C and C. +C and C represent sets and relations that +can be described as a conjunction of affine constraints, while +C and C represent unions of +Cs and Cs, respectively. +However, all Cs or Cs in the union need +to live in the same space. Cs and Cs +represent unions of Cs or Cs in I spaces, +where spaces are considered different if they have a different number +of dimensions and/or different names (see L<"Spaces">). +The difference between sets and relations (maps) is that sets have +one set of variables, while relations have two sets of variables, +input variables and output variables. + +=head2 Error Handling + +C supports different ways to react in case a runtime error is triggered. +Runtime errors arise, e.g., if a function such as C is called +with two maps that have incompatible spaces. There are three possible ways +to react on error: to warn, to continue or to abort. + +The default behavior is to warn. In this mode, C prints a warning, stores +the last error in the corresponding C and the function in which the +error was triggered returns a value indicating that some error has +occurred. In case of functions returning a pointer, this value is +C. In case of functions returning an C or an +C, this valus is C or C. +An error does not corrupt internal state, +such that isl can continue to be used. C also provides functions to +read the last error and to reset the memory that stores the last error. The +last error is only stored for information purposes. Its presence does not +change the behavior of C. Hence, resetting an error is not required to +continue to use isl, but only to observe new errors. + + #include + enum isl_error isl_ctx_last_error(isl_ctx *ctx); + void isl_ctx_reset_error(isl_ctx *ctx); + +Another option is to continue on error. This is similar to warn on error mode, +except that C does not print any warning. This allows a program to +implement its own error reporting. + +The last option is to directly abort the execution of the program from within +the isl library. This makes it obviously impossible to recover from an error, +but it allows to directly spot the error location. By aborting on error, +debuggers break at the location the error occurred and can provide a stack +trace. Other tools that automatically provide stack traces on abort or that do +not want to continue execution after an error was triggered may also prefer to +abort on error. + +The on error behavior of isl can be specified by calling +C or by setting the command line option +C<--isl-on-error>. Valid arguments for the function call are +C, C and C. The +choices for the command line option are C, C and C. +It is also possible to query the current error mode. + + #include + isl_stat isl_options_set_on_error(isl_ctx *ctx, int val); + int isl_options_get_on_error(isl_ctx *ctx); + +=head2 Identifiers + +Identifiers are used to identify both individual dimensions +and tuples of dimensions. They consist of an optional name and an optional +user pointer. The name and the user pointer cannot both be C, however. +Identifiers with the same name but different pointer values +are considered to be distinct. +Similarly, identifiers with different names but the same pointer value +are also considered to be distinct. +Equal identifiers are represented using the same object. +Pairs of identifiers can therefore be tested for equality using the +C<==> operator. +Identifiers can be constructed, copied, freed, inspected and printed +using the following functions. + + #include + __isl_give isl_id *isl_id_alloc(isl_ctx *ctx, + __isl_keep const char *name, void *user); + __isl_give isl_id *isl_id_set_free_user( + __isl_take isl_id *id, + void (*free_user)(void *user)); + __isl_give isl_id *isl_id_copy(isl_id *id); + __isl_null isl_id *isl_id_free(__isl_take isl_id *id); + + void *isl_id_get_user(__isl_keep isl_id *id); + __isl_keep const char *isl_id_get_name(__isl_keep isl_id *id); + + __isl_give isl_printer *isl_printer_print_id( + __isl_take isl_printer *p, __isl_keep isl_id *id); + +The callback set by C is called on the user +pointer when the last reference to the C is freed. +Note that C returns a pointer to some internal +data structure, so the result can only be used while the +corresponding C is alive. + +=head2 Spaces + +Whenever a new set, relation or similar object is created from scratch, +the space in which it lives needs to be specified using an C. +Each space involves zero or more parameters and zero, one or two +tuples of set or input/output dimensions. The parameters and dimensions +are identified by an C and a position. +The type C refers to parameters, +the type C refers to set dimensions (for spaces +with a single tuple of dimensions) and the types C +and C refer to input and output dimensions +(for spaces with two tuples of dimensions). +Local spaces (see L) also contain dimensions +of type C. +Note that parameters are only identified by their position within +a given object. Across different objects, parameters are (usually) +identified by their names or identifiers. Only unnamed parameters +are identified by their positions across objects. The use of unnamed +parameters is discouraged. + + #include + __isl_give isl_space *isl_space_alloc(isl_ctx *ctx, + unsigned nparam, unsigned n_in, unsigned n_out); + __isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, + unsigned nparam); + __isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx, + unsigned nparam, unsigned dim); + __isl_give isl_space *isl_space_copy(__isl_keep isl_space *space); + __isl_null isl_space *isl_space_free(__isl_take isl_space *space); + +The space used for creating a parameter domain +needs to be created using C. +For other sets, the space +needs to be created using C, while +for a relation, the space +needs to be created using C. + +To check whether a given space is that of a set or a map +or whether it is a parameter space, use these functions: + + #include + isl_bool isl_space_is_params(__isl_keep isl_space *space); + isl_bool isl_space_is_set(__isl_keep isl_space *space); + isl_bool isl_space_is_map(__isl_keep isl_space *space); + +Spaces can be compared using the following functions: + + #include + isl_bool isl_space_is_equal(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); + isl_bool isl_space_has_equal_params( + __isl_keep isl_space *space1, + __isl_keep isl_space *space2); + isl_bool isl_space_has_equal_tuples( + __isl_keep isl_space *space1, + __isl_keep isl_space *space2); + isl_bool isl_space_is_domain(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); + isl_bool isl_space_is_range(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); + isl_bool isl_space_tuple_is_equal( + __isl_keep isl_space *space1, + enum isl_dim_type type1, + __isl_keep isl_space *space2, + enum isl_dim_type type2); + +C checks whether the first argument is equal +to the domain of the second argument. This requires in particular that +the first argument is a set space and that the second argument +is a map space. C checks whether the given +tuples (C, C or C) of the given +spaces are the same. That is, it checks if they have the same +identifier (if any), the same dimension and the same internal structure +(if any). +The function +C checks whether two spaces +have the same parameters in the same order. +C check whether two spaces have +the same tuples. In contrast to C below, +it does not check the +parameters. This is useful because many C functions align the +parameters before they perform their operations, such that equivalence +is not necessary. +C checks whether two spaces are identical, +meaning that they have the same parameters and the same tuples. +That is, it checks whether both C and +C hold. + +It is often useful to create objects that live in the +same space as some other object. This can be accomplished +by creating the new objects +(see L or +L) based on the space +of the original object. + + #include + __isl_give isl_space *isl_basic_set_get_space( + __isl_keep isl_basic_set *bset); + __isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set); + + #include + __isl_give isl_space *isl_union_set_get_space( + __isl_keep isl_union_set *uset); + + #include + __isl_give isl_space *isl_basic_map_get_space( + __isl_keep isl_basic_map *bmap); + __isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map); + + #include + __isl_give isl_space *isl_union_map_get_space( + __isl_keep isl_union_map *umap); + + #include + __isl_give isl_space *isl_constraint_get_space( + __isl_keep isl_constraint *constraint); + + #include + __isl_give isl_space *isl_qpolynomial_get_domain_space( + __isl_keep isl_qpolynomial *qp); + __isl_give isl_space *isl_qpolynomial_get_space( + __isl_keep isl_qpolynomial *qp); + __isl_give isl_space * + isl_qpolynomial_fold_get_domain_space( + __isl_keep isl_qpolynomial_fold *fold); + __isl_give isl_space *isl_qpolynomial_fold_get_space( + __isl_keep isl_qpolynomial_fold *fold); + __isl_give isl_space *isl_pw_qpolynomial_get_domain_space( + __isl_keep isl_pw_qpolynomial *pwqp); + __isl_give isl_space *isl_pw_qpolynomial_get_space( + __isl_keep isl_pw_qpolynomial *pwqp); + __isl_give isl_space *isl_pw_qpolynomial_fold_get_domain_space( + __isl_keep isl_pw_qpolynomial_fold *pwf); + __isl_give isl_space *isl_pw_qpolynomial_fold_get_space( + __isl_keep isl_pw_qpolynomial_fold *pwf); + __isl_give isl_space *isl_union_pw_qpolynomial_get_space( + __isl_keep isl_union_pw_qpolynomial *upwqp); + __isl_give isl_space *isl_union_pw_qpolynomial_fold_get_space( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + + #include + __isl_give isl_space *isl_multi_val_get_space( + __isl_keep isl_multi_val *mv); + + #include + __isl_give isl_space *isl_aff_get_domain_space( + __isl_keep isl_aff *aff); + __isl_give isl_space *isl_aff_get_space( + __isl_keep isl_aff *aff); + __isl_give isl_space *isl_pw_aff_get_domain_space( + __isl_keep isl_pw_aff *pwaff); + __isl_give isl_space *isl_pw_aff_get_space( + __isl_keep isl_pw_aff *pwaff); + __isl_give isl_space *isl_multi_aff_get_domain_space( + __isl_keep isl_multi_aff *maff); + __isl_give isl_space *isl_multi_aff_get_space( + __isl_keep isl_multi_aff *maff); + __isl_give isl_space *isl_pw_multi_aff_get_domain_space( + __isl_keep isl_pw_multi_aff *pma); + __isl_give isl_space *isl_pw_multi_aff_get_space( + __isl_keep isl_pw_multi_aff *pma); + __isl_give isl_space *isl_union_pw_aff_get_space( + __isl_keep isl_union_pw_aff *upa); + __isl_give isl_space *isl_union_pw_multi_aff_get_space( + __isl_keep isl_union_pw_multi_aff *upma); + __isl_give isl_space *isl_multi_pw_aff_get_domain_space( + __isl_keep isl_multi_pw_aff *mpa); + __isl_give isl_space *isl_multi_pw_aff_get_space( + __isl_keep isl_multi_pw_aff *mpa); + __isl_give isl_space * + isl_multi_union_pw_aff_get_domain_space( + __isl_keep isl_multi_union_pw_aff *mupa); + __isl_give isl_space * + isl_multi_union_pw_aff_get_space( + __isl_keep isl_multi_union_pw_aff *mupa); + + #include + __isl_give isl_space *isl_point_get_space( + __isl_keep isl_point *pnt); + +The number of dimensions of a given type of space +may be read off from a space or an object that lives +in a space using the following functions. +In case of C, type may be +C, C (only for relations), +C (only for relations), C +(only for sets) or C. + + #include + unsigned isl_space_dim(__isl_keep isl_space *space, + enum isl_dim_type type); + + #include + int isl_local_space_dim(__isl_keep isl_local_space *ls, + enum isl_dim_type type); + + #include + unsigned isl_basic_set_dim(__isl_keep isl_basic_set *bset, + enum isl_dim_type type); + unsigned isl_set_dim(__isl_keep isl_set *set, + enum isl_dim_type type); + + #include + unsigned isl_union_set_dim(__isl_keep isl_union_set *uset, + enum isl_dim_type type); + + #include + unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type); + unsigned isl_map_dim(__isl_keep isl_map *map, + enum isl_dim_type type); + + #include + unsigned isl_union_map_dim(__isl_keep isl_union_map *umap, + enum isl_dim_type type); + + #include + unsigned isl_multi_val_dim(__isl_keep isl_multi_val *mv, + enum isl_dim_type type); + + #include + int isl_aff_dim(__isl_keep isl_aff *aff, + enum isl_dim_type type); + unsigned isl_multi_aff_dim(__isl_keep isl_multi_aff *maff, + enum isl_dim_type type); + unsigned isl_pw_aff_dim(__isl_keep isl_pw_aff *pwaff, + enum isl_dim_type type); + unsigned isl_pw_multi_aff_dim( + __isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); + unsigned isl_multi_pw_aff_dim( + __isl_keep isl_multi_pw_aff *mpa, + enum isl_dim_type type); + unsigned isl_union_pw_aff_dim( + __isl_keep isl_union_pw_aff *upa, + enum isl_dim_type type); + unsigned isl_union_pw_multi_aff_dim( + __isl_keep isl_union_pw_multi_aff *upma, + enum isl_dim_type type); + unsigned isl_multi_union_pw_aff_dim( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); + + #include + unsigned isl_union_pw_qpolynomial_dim( + __isl_keep isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type); + unsigned isl_union_pw_qpolynomial_fold_dim( + __isl_keep isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type); + +Note that an C, an C, +an C, +an C and +an C +only have parameters. + +The identifiers or names of the individual dimensions of spaces +may be set or read off using the following functions on spaces +or objects that live in spaces. +These functions are mostly useful to obtain the identifiers, positions +or names of the parameters. Identifiers of individual dimensions are +essentially only useful for printing. They are ignored by all other +operations and may not be preserved across those operations. + + #include + __isl_give isl_space *isl_space_set_dim_id( + __isl_take isl_space *space, + enum isl_dim_type type, unsigned pos, + __isl_take isl_id *id); + isl_bool isl_space_has_dim_id(__isl_keep isl_space *space, + enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_space_get_dim_id( + __isl_keep isl_space *space, + enum isl_dim_type type, unsigned pos); + __isl_give isl_space *isl_space_set_dim_name( + __isl_take isl_space *space, + enum isl_dim_type type, unsigned pos, + __isl_keep const char *name); + isl_bool isl_space_has_dim_name(__isl_keep isl_space *space, + enum isl_dim_type type, unsigned pos); + __isl_keep const char *isl_space_get_dim_name( + __isl_keep isl_space *space, + enum isl_dim_type type, unsigned pos); + + #include + __isl_give isl_local_space *isl_local_space_set_dim_id( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, + __isl_take isl_id *id); + isl_bool isl_local_space_has_dim_id( + __isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_local_space_get_dim_id( + __isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos); + __isl_give isl_local_space *isl_local_space_set_dim_name( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, const char *s); + isl_bool isl_local_space_has_dim_name( + __isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos) + const char *isl_local_space_get_dim_name( + __isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos); + + #include + const char *isl_constraint_get_dim_name( + __isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned pos); + + #include + __isl_give isl_id *isl_basic_set_get_dim_id( + __isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos); + __isl_give isl_set *isl_set_set_dim_id( + __isl_take isl_set *set, enum isl_dim_type type, + unsigned pos, __isl_take isl_id *id); + isl_bool isl_set_has_dim_id(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_set_get_dim_id( + __isl_keep isl_set *set, enum isl_dim_type type, + unsigned pos); + const char *isl_basic_set_get_dim_name( + __isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos); + isl_bool isl_set_has_dim_name(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + const char *isl_set_get_dim_name( + __isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + + #include + __isl_give isl_map *isl_map_set_dim_id( + __isl_take isl_map *map, enum isl_dim_type type, + unsigned pos, __isl_take isl_id *id); + isl_bool isl_basic_map_has_dim_id( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos); + isl_bool isl_map_has_dim_id(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_map_get_dim_id( + __isl_keep isl_map *map, enum isl_dim_type type, + unsigned pos); + __isl_give isl_id *isl_union_map_get_dim_id( + __isl_keep isl_union_map *umap, + enum isl_dim_type type, unsigned pos); + const char *isl_basic_map_get_dim_name( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos); + isl_bool isl_map_has_dim_name(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); + const char *isl_map_get_dim_name( + __isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); + + #include + __isl_give isl_multi_val *isl_multi_val_set_dim_id( + __isl_take isl_multi_val *mv, + enum isl_dim_type type, unsigned pos, + __isl_take isl_id *id); + __isl_give isl_id *isl_multi_val_get_dim_id( + __isl_keep isl_multi_val *mv, + enum isl_dim_type type, unsigned pos); + __isl_give isl_multi_val *isl_multi_val_set_dim_name( + __isl_take isl_multi_val *mv, + enum isl_dim_type type, unsigned pos, const char *s); + + #include + __isl_give isl_aff *isl_aff_set_dim_id( + __isl_take isl_aff *aff, enum isl_dim_type type, + unsigned pos, __isl_take isl_id *id); + __isl_give isl_multi_aff *isl_multi_aff_set_dim_id( + __isl_take isl_multi_aff *maff, + enum isl_dim_type type, unsigned pos, + __isl_take isl_id *id); + __isl_give isl_pw_aff *isl_pw_aff_set_dim_id( + __isl_take isl_pw_aff *pma, + enum isl_dim_type type, unsigned pos, + __isl_take isl_id *id); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_set_dim_id( + __isl_take isl_multi_pw_aff *mpa, + enum isl_dim_type type, unsigned pos, + __isl_take isl_id *id); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_dim_id( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, unsigned pos, + __isl_take isl_id *id); + __isl_give isl_id *isl_multi_aff_get_dim_id( + __isl_keep isl_multi_aff *ma, + enum isl_dim_type type, unsigned pos); + isl_bool isl_pw_aff_has_dim_id(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_pw_aff_get_dim_id( + __isl_keep isl_pw_aff *pa, + enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_pw_multi_aff_get_dim_id( + __isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_multi_pw_aff_get_dim_id( + __isl_keep isl_multi_pw_aff *mpa, + enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_multi_union_pw_aff_get_dim_id( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, unsigned pos); + __isl_give isl_aff *isl_aff_set_dim_name( + __isl_take isl_aff *aff, enum isl_dim_type type, + unsigned pos, const char *s); + __isl_give isl_multi_aff *isl_multi_aff_set_dim_name( + __isl_take isl_multi_aff *maff, + enum isl_dim_type type, unsigned pos, const char *s); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_set_dim_name( + __isl_take isl_multi_pw_aff *mpa, + enum isl_dim_type type, unsigned pos, const char *s); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_set_dim_name( + __isl_take isl_union_pw_aff *upa, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_set_dim_name( + __isl_take isl_union_pw_multi_aff *upma, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_dim_name( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, unsigned pos, + const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff, + enum isl_dim_type type, unsigned pos); + const char *isl_pw_aff_get_dim_name( + __isl_keep isl_pw_aff *pa, + enum isl_dim_type type, unsigned pos); + const char *isl_pw_multi_aff_get_dim_name( + __isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type, unsigned pos); + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_set_dim_name( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_set_dim_name( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_set_dim_name( + __isl_take isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_set_dim_name( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_set_dim_name( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, unsigned pos, + const char *s); + +Note that C returns a pointer to some internal +data structure, so the result can only be used while the +corresponding C is alive. +Also note that every function that operates on two sets or relations +requires that both arguments have the same parameters. This also +means that if one of the arguments has named parameters, then the +other needs to have named parameters too and the names need to match. +Pairs of C, C, C and/or C +arguments may have different parameters (as long as they are named), +in which case the result will have as parameters the union of the parameters of +the arguments. + +Given the identifier or name of a dimension (typically a parameter), +its position can be obtained from the following functions. + + #include + int isl_space_find_dim_by_id(__isl_keep isl_space *space, + enum isl_dim_type type, __isl_keep isl_id *id); + int isl_space_find_dim_by_name(__isl_keep isl_space *space, + enum isl_dim_type type, const char *name); + + #include + int isl_local_space_find_dim_by_name( + __isl_keep isl_local_space *ls, + enum isl_dim_type type, const char *name); + + #include + int isl_multi_val_find_dim_by_id( + __isl_keep isl_multi_val *mv, + enum isl_dim_type type, __isl_keep isl_id *id); + int isl_multi_val_find_dim_by_name( + __isl_keep isl_multi_val *mv, + enum isl_dim_type type, const char *name); + + #include + int isl_set_find_dim_by_id(__isl_keep isl_set *set, + enum isl_dim_type type, __isl_keep isl_id *id); + int isl_set_find_dim_by_name(__isl_keep isl_set *set, + enum isl_dim_type type, const char *name); + + #include + int isl_map_find_dim_by_id(__isl_keep isl_map *map, + enum isl_dim_type type, __isl_keep isl_id *id); + int isl_basic_map_find_dim_by_name( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type type, const char *name); + int isl_map_find_dim_by_name(__isl_keep isl_map *map, + enum isl_dim_type type, const char *name); + int isl_union_map_find_dim_by_name( + __isl_keep isl_union_map *umap, + enum isl_dim_type type, const char *name); + + #include + int isl_multi_aff_find_dim_by_id( + __isl_keep isl_multi_aff *ma, + enum isl_dim_type type, __isl_keep isl_id *id); + int isl_multi_pw_aff_find_dim_by_id( + __isl_keep isl_multi_pw_aff *mpa, + enum isl_dim_type type, __isl_keep isl_id *id); + int isl_multi_union_pw_aff_find_dim_by_id( + __isl_keep isl_union_multi_pw_aff *mupa, + enum isl_dim_type type, __isl_keep isl_id *id); + int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, + enum isl_dim_type type, const char *name); + int isl_multi_aff_find_dim_by_name( + __isl_keep isl_multi_aff *ma, + enum isl_dim_type type, const char *name); + int isl_pw_aff_find_dim_by_name(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type, const char *name); + int isl_multi_pw_aff_find_dim_by_name( + __isl_keep isl_multi_pw_aff *mpa, + enum isl_dim_type type, const char *name); + int isl_pw_multi_aff_find_dim_by_name( + __isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type, const char *name); + int isl_union_pw_aff_find_dim_by_name( + __isl_keep isl_union_pw_aff *upa, + enum isl_dim_type type, const char *name); + int isl_union_pw_multi_aff_find_dim_by_name( + __isl_keep isl_union_pw_multi_aff *upma, + enum isl_dim_type type, const char *name); + int isl_multi_union_pw_aff_find_dim_by_name( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, const char *name); + + #include + int isl_pw_qpolynomial_find_dim_by_name( + __isl_keep isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, const char *name); + int isl_pw_qpolynomial_fold_find_dim_by_name( + __isl_keep isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type type, const char *name); + int isl_union_pw_qpolynomial_find_dim_by_name( + __isl_keep isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, const char *name); + int isl_union_pw_qpolynomial_fold_find_dim_by_name( + __isl_keep isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, const char *name); + +The identifiers or names of entire spaces may be set or read off +using the following functions. + + #include + __isl_give isl_space *isl_space_set_tuple_id( + __isl_take isl_space *space, + enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_space *isl_space_reset_tuple_id( + __isl_take isl_space *space, enum isl_dim_type type); + isl_bool isl_space_has_tuple_id( + __isl_keep isl_space *space, + enum isl_dim_type type); + __isl_give isl_id *isl_space_get_tuple_id( + __isl_keep isl_space *space, enum isl_dim_type type); + __isl_give isl_space *isl_space_set_tuple_name( + __isl_take isl_space *space, + enum isl_dim_type type, const char *s); + isl_bool isl_space_has_tuple_name( + __isl_keep isl_space *space, + enum isl_dim_type type); + __isl_keep const char *isl_space_get_tuple_name( + __isl_keep isl_space *space, + enum isl_dim_type type); + + #include + __isl_give isl_local_space *isl_local_space_set_tuple_id( + __isl_take isl_local_space *ls, + enum isl_dim_type type, __isl_take isl_id *id); + + #include + __isl_give isl_basic_set *isl_basic_set_set_tuple_id( + __isl_take isl_basic_set *bset, + __isl_take isl_id *id); + __isl_give isl_set *isl_set_set_tuple_id( + __isl_take isl_set *set, __isl_take isl_id *id); + __isl_give isl_set *isl_set_reset_tuple_id( + __isl_take isl_set *set); + isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set); + __isl_give isl_id *isl_set_get_tuple_id( + __isl_keep isl_set *set); + __isl_give isl_basic_set *isl_basic_set_set_tuple_name( + __isl_take isl_basic_set *set, const char *s); + __isl_give isl_set *isl_set_set_tuple_name( + __isl_take isl_set *set, const char *s); + const char *isl_basic_set_get_tuple_name( + __isl_keep isl_basic_set *bset); + isl_bool isl_set_has_tuple_name(__isl_keep isl_set *set); + const char *isl_set_get_tuple_name( + __isl_keep isl_set *set); + + #include + __isl_give isl_basic_map *isl_basic_map_set_tuple_id( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_map *isl_map_set_tuple_id( + __isl_take isl_map *map, enum isl_dim_type type, + __isl_take isl_id *id); + __isl_give isl_map *isl_map_reset_tuple_id( + __isl_take isl_map *map, enum isl_dim_type type); + isl_bool isl_map_has_tuple_id(__isl_keep isl_map *map, + enum isl_dim_type type); + __isl_give isl_id *isl_map_get_tuple_id( + __isl_keep isl_map *map, enum isl_dim_type type); + __isl_give isl_map *isl_map_set_tuple_name( + __isl_take isl_map *map, + enum isl_dim_type type, const char *s); + const char *isl_basic_map_get_tuple_name( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type type); + __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); + isl_bool isl_map_has_tuple_name(__isl_keep isl_map *map, + enum isl_dim_type type); + const char *isl_map_get_tuple_name( + __isl_keep isl_map *map, + enum isl_dim_type type); + + #include + __isl_give isl_multi_val *isl_multi_val_set_tuple_id( + __isl_take isl_multi_val *mv, + enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_multi_val *isl_multi_val_reset_tuple_id( + __isl_take isl_multi_val *mv, + enum isl_dim_type type); + isl_bool isl_multi_val_has_tuple_id( + __isl_keep isl_multi_val *mv, + enum isl_dim_type type); + __isl_give isl_id *isl_multi_val_get_tuple_id( + __isl_keep isl_multi_val *mv, + enum isl_dim_type type); + __isl_give isl_multi_val *isl_multi_val_set_tuple_name( + __isl_take isl_multi_val *mv, + enum isl_dim_type type, const char *s); + const char *isl_multi_val_get_tuple_name( + __isl_keep isl_multi_val *mv, + enum isl_dim_type type); + + #include + __isl_give isl_aff *isl_aff_set_tuple_id( + __isl_take isl_aff *aff, + enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_multi_aff *isl_multi_aff_set_tuple_id( + __isl_take isl_multi_aff *maff, + enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_pw_aff *isl_pw_aff_set_tuple_id( + __isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_tuple_id( + __isl_take isl_pw_multi_aff *pma, + enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_tuple_id( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_multi_aff *isl_multi_aff_reset_tuple_id( + __isl_take isl_multi_aff *ma, + enum isl_dim_type type); + __isl_give isl_pw_aff *isl_pw_aff_reset_tuple_id( + __isl_take isl_pw_aff *pa, + enum isl_dim_type type); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_reset_tuple_id( + __isl_take isl_multi_pw_aff *mpa, + enum isl_dim_type type); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_reset_tuple_id( + __isl_take isl_pw_multi_aff *pma, + enum isl_dim_type type); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_reset_tuple_id( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); + isl_bool isl_multi_aff_has_tuple_id( + __isl_keep isl_multi_aff *ma, + enum isl_dim_type type); + __isl_give isl_id *isl_multi_aff_get_tuple_id( + __isl_keep isl_multi_aff *ma, + enum isl_dim_type type); + isl_bool isl_pw_aff_has_tuple_id(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type); + __isl_give isl_id *isl_pw_aff_get_tuple_id( + __isl_keep isl_pw_aff *pa, + enum isl_dim_type type); + isl_bool isl_pw_multi_aff_has_tuple_id( + __isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); + __isl_give isl_id *isl_pw_multi_aff_get_tuple_id( + __isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); + isl_bool isl_multi_pw_aff_has_tuple_id( + __isl_keep isl_multi_pw_aff *mpa, + enum isl_dim_type type); + __isl_give isl_id *isl_multi_pw_aff_get_tuple_id( + __isl_keep isl_multi_pw_aff *mpa, + enum isl_dim_type type); + isl_bool isl_multi_union_pw_aff_has_tuple_id( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); + __isl_give isl_id *isl_multi_union_pw_aff_get_tuple_id( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); + __isl_give isl_multi_aff *isl_multi_aff_set_tuple_name( + __isl_take isl_multi_aff *maff, + enum isl_dim_type type, const char *s); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_set_tuple_name( + __isl_take isl_multi_pw_aff *mpa, + enum isl_dim_type type, const char *s); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_tuple_name( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, const char *s); + const char *isl_multi_aff_get_tuple_name( + __isl_keep isl_multi_aff *multi, + enum isl_dim_type type); + isl_bool isl_pw_multi_aff_has_tuple_name( + __isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); + const char *isl_pw_multi_aff_get_tuple_name( + __isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); + const char *isl_multi_union_pw_aff_get_tuple_name( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); + +The C argument needs to be one of C, C +or C. As with C, +the C function returns a pointer to some internal +data structure. +Binary operations require the corresponding spaces of their arguments +to have the same name. + +To keep the names of all parameters and tuples, but reset the user pointers +of all the corresponding identifiers, use the following function. + + #include + __isl_give isl_space *isl_space_reset_user( + __isl_take isl_space *space); + + #include + __isl_give isl_set *isl_set_reset_user( + __isl_take isl_set *set); + + #include + __isl_give isl_map *isl_map_reset_user( + __isl_take isl_map *map); + + #include + __isl_give isl_union_set *isl_union_set_reset_user( + __isl_take isl_union_set *uset); + + #include + __isl_give isl_union_map *isl_union_map_reset_user( + __isl_take isl_union_map *umap); + + #include + __isl_give isl_multi_val *isl_multi_val_reset_user( + __isl_take isl_multi_val *mv); + + #include + __isl_give isl_multi_aff *isl_multi_aff_reset_user( + __isl_take isl_multi_aff *ma); + __isl_give isl_pw_aff *isl_pw_aff_reset_user( + __isl_take isl_pw_aff *pa); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_reset_user( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_user( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_union_pw_aff *isl_union_pw_aff_reset_user( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_reset_user( + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_reset_user( + __isl_take isl_union_pw_multi_aff *upma); + + #include + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_reset_user( + __isl_take isl_pw_qpolynomial *pwqp); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_reset_user( + __isl_take isl_union_pw_qpolynomial *upwqp); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_reset_user( + __isl_take isl_pw_qpolynomial_fold *pwf); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_reset_user( + __isl_take isl_union_pw_qpolynomial_fold *upwf); + +Spaces can be nested. In particular, the domain of a set or +the domain or range of a relation can be a nested relation. +This process is also called I. +The functions for detecting, constructing and deconstructing +such nested spaces can be found in the wrapping properties +of L, the wrapping operations +of L and the Cartesian product operations +of L. + +Spaces can be created from other spaces +using the functions described in L +and L. + +=head2 Local Spaces + +A local space is essentially a space with +zero or more existentially quantified variables. +The local space of various objects can be obtained +using the following functions. + + #include + __isl_give isl_local_space *isl_constraint_get_local_space( + __isl_keep isl_constraint *constraint); + + #include + __isl_give isl_local_space *isl_basic_set_get_local_space( + __isl_keep isl_basic_set *bset); + + #include + __isl_give isl_local_space *isl_basic_map_get_local_space( + __isl_keep isl_basic_map *bmap); + + #include + __isl_give isl_local_space *isl_aff_get_domain_local_space( + __isl_keep isl_aff *aff); + __isl_give isl_local_space *isl_aff_get_local_space( + __isl_keep isl_aff *aff); + +A new local space can be created from a space using + + #include + __isl_give isl_local_space *isl_local_space_from_space( + __isl_take isl_space *space); + +They can be inspected, modified, copied and freed using the following functions. + + #include + isl_bool isl_local_space_is_params( + __isl_keep isl_local_space *ls); + isl_bool isl_local_space_is_set( + __isl_keep isl_local_space *ls); + __isl_give isl_space *isl_local_space_get_space( + __isl_keep isl_local_space *ls); + __isl_give isl_aff *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); + __isl_null isl_local_space *isl_local_space_free( + __isl_take isl_local_space *ls); + +Note that C can only be used on local spaces +of sets. + +Two local spaces can be compared using + + isl_bool isl_local_space_is_equal( + __isl_keep isl_local_space *ls1, + __isl_keep isl_local_space *ls2); + +Local spaces can be created from other local spaces +using the functions described in L +and L. + +=head2 Creating New Sets and Relations + +C has functions for creating some standard sets and relations. + +=over + +=item * Empty sets and relations + + __isl_give isl_basic_set *isl_basic_set_empty( + __isl_take isl_space *space); + __isl_give isl_basic_map *isl_basic_map_empty( + __isl_take isl_space *space); + __isl_give isl_set *isl_set_empty( + __isl_take isl_space *space); + __isl_give isl_map *isl_map_empty( + __isl_take isl_space *space); + __isl_give isl_union_set *isl_union_set_empty( + __isl_take isl_space *space); + __isl_give isl_union_map *isl_union_map_empty( + __isl_take isl_space *space); + +For Cs and Cs, the space +is only used to specify the parameters. + +=item * Universe sets and relations + + __isl_give isl_basic_set *isl_basic_set_universe( + __isl_take isl_space *space); + __isl_give isl_basic_map *isl_basic_map_universe( + __isl_take isl_space *space); + __isl_give isl_set *isl_set_universe( + __isl_take isl_space *space); + __isl_give isl_map *isl_map_universe( + __isl_take isl_space *space); + __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 +functions below only contain non-negative values. + + __isl_give isl_basic_set *isl_basic_set_nat_universe( + __isl_take isl_space *space); + __isl_give isl_basic_map *isl_basic_map_nat_universe( + __isl_take isl_space *space); + __isl_give isl_set *isl_set_nat_universe( + __isl_take isl_space *space); + __isl_give isl_map *isl_map_nat_universe( + __isl_take isl_space *space); + +=item * Identity relations + + __isl_give isl_basic_map *isl_basic_map_identity( + __isl_take isl_space *space); + __isl_give isl_map *isl_map_identity( + __isl_take isl_space *space); + +The number of input and output dimensions in C needs +to be the same. + +=item * Lexicographic order + + __isl_give isl_map *isl_map_lex_lt( + __isl_take isl_space *set_space); + __isl_give isl_map *isl_map_lex_le( + __isl_take isl_space *set_space); + __isl_give isl_map *isl_map_lex_gt( + __isl_take isl_space *set_space); + __isl_give isl_map *isl_map_lex_ge( + __isl_take isl_space *set_space); + __isl_give isl_map *isl_map_lex_lt_first( + __isl_take isl_space *space, unsigned n); + __isl_give isl_map *isl_map_lex_le_first( + __isl_take isl_space *space, unsigned n); + __isl_give isl_map *isl_map_lex_gt_first( + __isl_take isl_space *space, unsigned n); + __isl_give isl_map *isl_map_lex_ge_first( + __isl_take isl_space *space, unsigned n); + +The first four functions take a space for a B +and return relations that express that the elements in the domain +are lexicographically less +(C), less or equal (C), +greater (C) or greater or equal (C) +than the elements in the range. +The last four functions take a space for a map +and return relations that express that the first C dimensions +in the domain are lexicographically less +(C), less or equal (C), +greater (C) or greater or equal (C) +than the first C dimensions in the range. + +=back + +A basic set or relation can be converted to a set or relation +using the following functions. + + __isl_give isl_set *isl_set_from_basic_set( + __isl_take isl_basic_set *bset); + __isl_give isl_map *isl_map_from_basic_map( + __isl_take isl_basic_map *bmap); + +Sets and relations can be converted to union sets and relations +using the following functions. + + __isl_give isl_union_set *isl_union_set_from_basic_set( + __isl_take isl_basic_set *bset); + __isl_give isl_union_map *isl_union_map_from_basic_map( + __isl_take isl_basic_map *bmap); + __isl_give isl_union_set *isl_union_set_from_set( + __isl_take isl_set *set); + __isl_give isl_union_map *isl_union_map_from_map( + __isl_take isl_map *map); + +The inverse conversions below can only be used if the input +union set or relation is known to contain elements in exactly one +space. + + __isl_give isl_set *isl_set_from_union_set( + __isl_take isl_union_set *uset); + __isl_give isl_map *isl_map_from_union_map( + __isl_take isl_union_map *umap); + +Sets and relations can be copied and freed again using the following +functions. + + __isl_give isl_basic_set *isl_basic_set_copy( + __isl_keep isl_basic_set *bset); + __isl_give isl_set *isl_set_copy(__isl_keep isl_set *set); + __isl_give isl_union_set *isl_union_set_copy( + __isl_keep isl_union_set *uset); + __isl_give isl_basic_map *isl_basic_map_copy( + __isl_keep isl_basic_map *bmap); + __isl_give isl_map *isl_map_copy(__isl_keep isl_map *map); + __isl_give isl_union_map *isl_union_map_copy( + __isl_keep isl_union_map *umap); + __isl_null isl_basic_set *isl_basic_set_free( + __isl_take isl_basic_set *bset); + __isl_null isl_set *isl_set_free(__isl_take isl_set *set); + __isl_null isl_union_set *isl_union_set_free( + __isl_take isl_union_set *uset); + __isl_null isl_basic_map *isl_basic_map_free( + __isl_take isl_basic_map *bmap); + __isl_null isl_map *isl_map_free(__isl_take isl_map *map); + __isl_null isl_union_map *isl_union_map_free( + __isl_take isl_union_map *umap); + +Other sets and relations can be constructed by starting +from a universe set or relation, adding equality and/or +inequality constraints and then projecting out the +existentially quantified variables, if any. +Constraints can be constructed, manipulated and +added to (or removed from) (basic) sets and relations +using the following functions. + + #include + __isl_give isl_constraint *isl_constraint_alloc_equality( + __isl_take isl_local_space *ls); + __isl_give isl_constraint *isl_constraint_alloc_inequality( + __isl_take isl_local_space *ls); + __isl_give isl_constraint *isl_constraint_set_constant_si( + __isl_take isl_constraint *constraint, int v); + __isl_give isl_constraint *isl_constraint_set_constant_val( + __isl_take isl_constraint *constraint, + __isl_take isl_val *v); + __isl_give isl_constraint *isl_constraint_set_coefficient_si( + __isl_take isl_constraint *constraint, + enum isl_dim_type type, int pos, int v); + __isl_give isl_constraint * + isl_constraint_set_coefficient_val( + __isl_take isl_constraint *constraint, + enum isl_dim_type type, int pos, + __isl_take isl_val *v); + __isl_give isl_basic_map *isl_basic_map_add_constraint( + __isl_take isl_basic_map *bmap, + __isl_take isl_constraint *constraint); + __isl_give isl_basic_set *isl_basic_set_add_constraint( + __isl_take isl_basic_set *bset, + __isl_take isl_constraint *constraint); + __isl_give isl_map *isl_map_add_constraint( + __isl_take isl_map *map, + __isl_take isl_constraint *constraint); + __isl_give isl_set *isl_set_add_constraint( + __isl_take isl_set *set, + __isl_take isl_constraint *constraint); + +For example, to create a set containing the even integers +between 10 and 42, you would use the following code. + + isl_space *space; + isl_local_space *ls; + isl_constraint *c; + isl_basic_set *bset; + + space = isl_space_set_alloc(ctx, 0, 2); + bset = isl_basic_set_universe(isl_space_copy(space)); + ls = isl_local_space_from_space(space); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, 2); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_inequality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, -10); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_inequality(ls); + c = isl_constraint_set_constant_si(c, 42); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 1); + +Or, alternatively, + + isl_basic_set *bset; + bset = isl_basic_set_read_from_str(ctx, + "{[i] : exists (a : i = 2a and i >= 10 and i <= 42)}"); + +A basic set or relation can also be constructed from two matrices +describing the equalities and the inequalities. + + __isl_give isl_basic_set *isl_basic_set_from_constraint_matrices( + __isl_take isl_space *space, + __isl_take isl_mat *eq, __isl_take isl_mat *ineq, + enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, + enum isl_dim_type c4); + __isl_give isl_basic_map *isl_basic_map_from_constraint_matrices( + __isl_take isl_space *space, + __isl_take isl_mat *eq, __isl_take isl_mat *ineq, + enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, + enum isl_dim_type c4, enum isl_dim_type c5); + +The C arguments indicate the order in which +different kinds of variables appear in the input matrices +and should be a permutation of C, C, +C and C for sets and +of C, C, +C, C and C for relations. + +A (basic or union) set or relation can also be constructed from a +(union) (piecewise) (multiple) affine expression +or a list of affine expressions +(See L), provided these affine expressions do not +involve any NaN. + + __isl_give isl_basic_map *isl_basic_map_from_aff( + __isl_take isl_aff *aff); + __isl_give isl_map *isl_map_from_aff( + __isl_take isl_aff *aff); + __isl_give isl_set *isl_set_from_pw_aff( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_map *isl_map_from_pw_aff( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_basic_map *isl_basic_map_from_aff_list( + __isl_take isl_space *domain_space, + __isl_take isl_aff_list *list); + __isl_give isl_basic_map *isl_basic_map_from_multi_aff( + __isl_take isl_multi_aff *maff) + __isl_give isl_map *isl_map_from_multi_aff( + __isl_take isl_multi_aff *maff) + __isl_give isl_set *isl_set_from_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_map *isl_map_from_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_set *isl_set_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_map *isl_map_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_union_map *isl_union_map_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_map * + isl_union_map_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_map * + isl_union_map_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); + +The C argument describes the domain of the resulting +basic relation. It is required because the C may consist +of zero affine expressions. +The C passed to C +is not allowed to be zero-dimensional. The domain of the result +is the shared domain of the union piecewise affine elements. + +=head2 Inspecting Sets and Relations + +Usually, the user should not have to care about the actual constraints +of the sets and maps, but should instead apply the abstract operations +explained in the following sections. +Occasionally, however, it may be required to inspect the individual +coefficients of the constraints. This section explains how to do so. +In these cases, it may also be useful to have C compute +an explicit representation of the existentially quantified variables. + + __isl_give isl_set *isl_set_compute_divs( + __isl_take isl_set *set); + __isl_give isl_map *isl_map_compute_divs( + __isl_take isl_map *map); + __isl_give isl_union_set *isl_union_set_compute_divs( + __isl_take isl_union_set *uset); + __isl_give isl_union_map *isl_union_map_compute_divs( + __isl_take isl_union_map *umap); + +This explicit representation defines the existentially quantified +variables as integer divisions of the other variables, possibly +including earlier existentially quantified variables. +An explicitly represented existentially quantified variable therefore +has a unique value when the values of the other variables are known. + +Alternatively, the existentially quantified variables can be removed +using the following functions, which compute an overapproximation. + + #include + __isl_give isl_basic_set *isl_basic_set_remove_divs( + __isl_take isl_basic_set *bset); + __isl_give isl_set *isl_set_remove_divs( + __isl_take isl_set *set); + + #include + __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); + + #include + __isl_give isl_union_set *isl_union_set_remove_divs( + __isl_take isl_union_set *bset); + + #include + __isl_give isl_union_map *isl_union_map_remove_divs( + __isl_take isl_union_map *bmap); + +It is also possible to only remove those divs that are defined +in terms of a given range of dimensions or only those for which +no explicit representation is known. + + __isl_give isl_basic_set * + isl_basic_set_remove_divs_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_basic_map * + isl_basic_map_remove_divs_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_set *isl_set_remove_divs_involving_dims( + __isl_take isl_set *set, enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_map *isl_map_remove_divs_involving_dims( + __isl_take isl_map *map, enum isl_dim_type type, + unsigned first, unsigned n); + + __isl_give isl_basic_set * + isl_basic_set_remove_unknown_divs( + __isl_take isl_basic_set *bset); + __isl_give isl_set *isl_set_remove_unknown_divs( + __isl_take isl_set *set); + __isl_give isl_map *isl_map_remove_unknown_divs( + __isl_take isl_map *map); + +To iterate over all the sets or maps in a union set or map, use + + #include + isl_stat isl_union_set_foreach_set( + __isl_keep isl_union_set *uset, + isl_stat (*fn)(__isl_take isl_set *set, void *user), + void *user); + + #include + isl_stat isl_union_map_foreach_map( + __isl_keep isl_union_map *umap, + isl_stat (*fn)(__isl_take isl_map *map, void *user), + void *user); + isl_bool isl_union_map_every_map( + __isl_keep isl_union_map *umap, + isl_bool (*test)(__isl_keep isl_map *map, + void *user), + void *user); + +These functions call the callback function once for each +(pair of) space(s) for which there are elements in the input. +The argument to the callback contains all elements in the input +with that (pair of) space(s). +The C variant check whether each +call to the callback returns true and stops checking as soon as one +of these calls returns false. + +The number of sets or maps in a union set or map can be obtained +from + + int isl_union_set_n_set(__isl_keep isl_union_set *uset); + int isl_union_map_n_map(__isl_keep isl_union_map *umap); + +To extract the set or map in a given space from a union, use + + __isl_give isl_set *isl_union_set_extract_set( + __isl_keep isl_union_set *uset, + __isl_take isl_space *space); + __isl_give isl_map *isl_union_map_extract_map( + __isl_keep isl_union_map *umap, + __isl_take isl_space *space); + +To iterate over all the basic sets or maps in a set or map, use + + isl_stat isl_set_foreach_basic_set(__isl_keep isl_set *set, + isl_stat (*fn)(__isl_take isl_basic_set *bset, + void *user), + void *user); + isl_stat isl_map_foreach_basic_map(__isl_keep isl_map *map, + isl_stat (*fn)(__isl_take isl_basic_map *bmap, + void *user), + void *user); + +The callback function C should return C if successful and +C if an error occurs. In the latter case, or if any other error +occurs, the above functions will return C. + +It should be noted that C does not guarantee that +the basic sets or maps passed to C are disjoint. +If this is required, then the user should call one of +the following functions first. + + __isl_give isl_set *isl_set_make_disjoint( + __isl_take isl_set *set); + __isl_give isl_map *isl_map_make_disjoint( + __isl_take isl_map *map); + +The number of basic sets in a set can be obtained +or the number of basic maps in a map can be obtained +from + + #include + int isl_set_n_basic_set(__isl_keep isl_set *set); + + #include + int isl_map_n_basic_map(__isl_keep isl_map *map); + +It is also possible to obtain a list of basic sets from a set +or union set + + #include + __isl_give isl_basic_set_list *isl_set_get_basic_set_list( + __isl_keep isl_set *set); + + #include + __isl_give isl_basic_set_list * + isl_union_set_get_basic_set_list( + __isl_keep isl_union_set *uset); + +The returned list can be manipulated using the functions in L<"Lists">. + +To iterate over the constraints of a basic set or map, use + + #include + + int isl_basic_set_n_constraint( + __isl_keep isl_basic_set *bset); + isl_stat isl_basic_set_foreach_constraint( + __isl_keep isl_basic_set *bset, + isl_stat (*fn)(__isl_take isl_constraint *c, + void *user), + void *user); + int isl_basic_map_n_constraint( + __isl_keep isl_basic_map *bmap); + isl_stat isl_basic_map_foreach_constraint( + __isl_keep isl_basic_map *bmap, + isl_stat (*fn)(__isl_take isl_constraint *c, + void *user), + void *user); + __isl_null isl_constraint *isl_constraint_free( + __isl_take isl_constraint *c); + +Again, the callback function C should return C +if successful and +C if an error occurs. In the latter case, or if any other error +occurs, the above functions will return C. +The constraint C represents either an equality or an inequality. +Use the following function to find out whether a constraint +represents an equality. If not, it represents an inequality. + + isl_bool isl_constraint_is_equality( + __isl_keep isl_constraint *constraint); + +It is also possible to obtain a list of constraints from a basic +map or set + + #include + __isl_give isl_constraint_list * + isl_basic_map_get_constraint_list( + __isl_keep isl_basic_map *bmap); + __isl_give isl_constraint_list * + isl_basic_set_get_constraint_list( + __isl_keep isl_basic_set *bset); + +These functions require that all existentially quantified variables +have an explicit representation. +The returned list can be manipulated using the functions in L<"Lists">. + +The coefficients of the constraints can be inspected using +the following functions. + + isl_bool isl_constraint_is_lower_bound( + __isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned pos); + isl_bool isl_constraint_is_upper_bound( + __isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned pos); + __isl_give isl_val *isl_constraint_get_constant_val( + __isl_keep isl_constraint *constraint); + __isl_give isl_val *isl_constraint_get_coefficient_val( + __isl_keep isl_constraint *constraint, + enum isl_dim_type type, int pos); + +The explicit representations of the existentially quantified +variables can be inspected using the following function. +Note that the user is only allowed to use this function +if the inspected set or map is the result of a call +to C or C. +The existentially quantified variable is equal to the floor +of the returned affine expression. The affine expression +itself can be inspected using the functions in +L. + + __isl_give isl_aff *isl_constraint_get_div( + __isl_keep isl_constraint *constraint, int pos); + +To obtain the constraints of a basic set or map in matrix +form, use the following functions. + + __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_inequalities_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_map_equalities_matrix( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, + enum isl_dim_type c4, enum isl_dim_type c5); + __isl_give isl_mat *isl_basic_map_inequalities_matrix( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, + enum isl_dim_type c4, enum isl_dim_type c5); + +The C arguments dictate the order in which +different kinds of variables appear in the resulting matrix. +For set inputs, they should be a permutation of +C, C, C and C. +For map inputs, they should be a permutation of +C, C, +C, C and C. + +=head2 Points + +Points are elements of a set. They can be used to construct +simple sets (boxes) or they can be used to represent the +individual elements of a set. +The zero point (the origin) can be created using + + __isl_give isl_point *isl_point_zero(__isl_take isl_space *space); + +The coordinates of a point can be inspected, set and changed +using + + __isl_give isl_val *isl_point_get_coordinate_val( + __isl_keep isl_point *pnt, + enum isl_dim_type type, int pos); + __isl_give isl_point *isl_point_set_coordinate_val( + __isl_take isl_point *pnt, + enum isl_dim_type type, int pos, + __isl_take isl_val *v); + + __isl_give isl_point *isl_point_add_ui( + __isl_take isl_point *pnt, + enum isl_dim_type type, int pos, unsigned val); + __isl_give isl_point *isl_point_sub_ui( + __isl_take isl_point *pnt, + enum isl_dim_type type, int pos, unsigned val); + +Points can be copied or freed using + + __isl_give isl_point *isl_point_copy( + __isl_keep isl_point *pnt); + __isl_null isl_point *isl_point_free( + __isl_take isl_point *pnt); + +A singleton set can be created from a point using + + __isl_give isl_basic_set *isl_basic_set_from_point( + __isl_take isl_point *pnt); + __isl_give isl_set *isl_set_from_point( + __isl_take isl_point *pnt); + __isl_give isl_union_set *isl_union_set_from_point( + __isl_take isl_point *pnt); + +and a box can be created from two opposite extremal points using + + __isl_give isl_basic_set *isl_basic_set_box_from_points( + __isl_take isl_point *pnt1, + __isl_take isl_point *pnt2); + __isl_give isl_set *isl_set_box_from_points( + __isl_take isl_point *pnt1, + __isl_take isl_point *pnt2); + +All elements of a B (union) set can be enumerated using +the following functions. + + isl_stat isl_set_foreach_point(__isl_keep isl_set *set, + isl_stat (*fn)(__isl_take isl_point *pnt, + void *user), + void *user); + isl_stat isl_union_set_foreach_point( + __isl_keep isl_union_set *uset, + isl_stat (*fn)(__isl_take isl_point *pnt, + void *user), + void *user); + +The function C is called for each integer point in +C with as second argument the last argument of +the C call. The function C +should return C on success and C on failure. +In the latter case, C will stop +enumerating and return C as well. +If the enumeration is performed successfully and to completion, +then C returns C. + +To obtain a single point of a (basic or union) set, use + + __isl_give isl_point *isl_basic_set_sample_point( + __isl_take isl_basic_set *bset); + __isl_give isl_point *isl_set_sample_point( + __isl_take isl_set *set); + __isl_give isl_point *isl_union_set_sample_point( + __isl_take isl_union_set *uset); + +If C does not contain any (integer) points, then the +resulting point will be ``void'', a property that can be +tested using + + isl_bool isl_point_is_void(__isl_keep isl_point *pnt); + +=head2 Functions + +Besides sets and relation, C also supports various types of functions. +Each of these types is derived from the value type (see L) +or from one of two primitive function types +through the application of zero or more type constructors. +We first describe the primitive type and then we describe +the types derived from these primitive types. + +=head3 Primitive Functions + +C support two primitive function types, quasi-affine +expressions and quasipolynomials. +A quasi-affine expression is defined either over a parameter +space or over a set and is composed of integer constants, +parameters and set variables, addition, subtraction and +integer division by an integer constant. +For example, the quasi-affine expression + + [n] -> { [x] -> [2*floor((4 n + x)/9] } + +maps C to C<2*floor((4 n + x)/9>. +A quasipolynomial is a polynomial expression in quasi-affine +expression. That is, it additionally allows for multiplication. +Note, though, that it is not allowed to construct an integer +division of an expression involving multiplications. +Here is an example of a quasipolynomial that is not +quasi-affine expression + + [n] -> { [x] -> (n*floor((4 n + x)/9) } + +Note that the external representations of quasi-affine expressions +and quasipolynomials are different. Quasi-affine expressions +use a notation with square brackets just like binary relations, +while quasipolynomials do not. This might change at some point. + +If a primitive function is defined over a parameter space, +then the space of the function itself is that of a set. +If it is defined over a set, then the space of the function +is that of a relation. In both cases, the set space (or +the output space) is single-dimensional, anonymous and unstructured. +To create functions with multiple dimensions or with other kinds +of set or output spaces, use multiple expressions +(see L). + +=over + +=item * Quasi-affine Expressions + +Besides the expressions described above, a quasi-affine +expression can also be set to NaN. Such expressions +typically represent a failure to represent a result +as a quasi-affine expression. + +The zero quasi affine expression or the quasi affine expression +that is equal to a given value or +a specified dimension on a given domain can be created using + + #include + __isl_give isl_aff *isl_aff_zero_on_domain( + __isl_take isl_local_space *ls); + __isl_give isl_aff *isl_aff_val_on_domain( + __isl_take isl_local_space *ls, + __isl_take isl_val *val); + __isl_give isl_aff *isl_aff_var_on_domain( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos); + __isl_give isl_aff *isl_aff_nan_on_domain( + __isl_take isl_local_space *ls); + +Quasi affine expressions can be copied and freed using + + #include + __isl_give isl_aff *isl_aff_copy( + __isl_keep isl_aff *aff); + __isl_null isl_aff *isl_aff_free( + __isl_take isl_aff *aff); + +A (rational) bound on a dimension can be extracted from an C +using the following function. The constraint is required to have +a non-zero coefficient for the specified dimension. + + #include + __isl_give isl_aff *isl_constraint_get_bound( + __isl_keep isl_constraint *constraint, + enum isl_dim_type type, int pos); + +The entire affine expression of the constraint can also be extracted +using the following function. + + #include + __isl_give isl_aff *isl_constraint_get_aff( + __isl_keep isl_constraint *constraint); + +Conversely, an equality constraint equating +the affine expression to zero or an inequality constraint enforcing +the affine expression to be non-negative, can be constructed using + + __isl_give isl_constraint *isl_equality_from_aff( + __isl_take isl_aff *aff); + __isl_give isl_constraint *isl_inequality_from_aff( + __isl_take isl_aff *aff); + +The coefficients and the integer divisions of an affine expression +can be inspected using the following functions. + + #include + __isl_give isl_val *isl_aff_get_constant_val( + __isl_keep isl_aff *aff); + __isl_give isl_val *isl_aff_get_coefficient_val( + __isl_keep isl_aff *aff, + enum isl_dim_type type, int pos); + int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff, + enum isl_dim_type type, int pos); + __isl_give isl_val *isl_aff_get_denominator_val( + __isl_keep isl_aff *aff); + __isl_give isl_aff *isl_aff_get_div( + __isl_keep isl_aff *aff, int pos); + +They can be modified using the following functions. + + #include + __isl_give isl_aff *isl_aff_set_constant_si( + __isl_take isl_aff *aff, int v); + __isl_give isl_aff *isl_aff_set_constant_val( + __isl_take isl_aff *aff, __isl_take isl_val *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_coefficient_val( + __isl_take isl_aff *aff, + enum isl_dim_type type, int pos, + __isl_take isl_val *v); + + __isl_give isl_aff *isl_aff_add_constant_si( + __isl_take isl_aff *aff, int v); + __isl_give isl_aff *isl_aff_add_constant_val( + __isl_take isl_aff *aff, __isl_take isl_val *v); + __isl_give isl_aff *isl_aff_add_constant_num_si( + __isl_take isl_aff *aff, 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_aff *isl_aff_add_coefficient_val( + __isl_take isl_aff *aff, + enum isl_dim_type type, int pos, + __isl_take isl_val *v); + +Note that C and C +set the I of the constant or coefficient, while +C and C set +the constant or coefficient as a whole. +The C and C functions add an integer +or rational value to +the possibly rational constant or coefficient. +The C functions add an integer value to +the numerator. + +=item * Quasipolynomials + +Some simple quasipolynomials can be created using the following functions. + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_zero_on_domain( + __isl_take isl_space *domain); + __isl_give isl_qpolynomial *isl_qpolynomial_one_on_domain( + __isl_take isl_space *domain); + __isl_give isl_qpolynomial *isl_qpolynomial_infty_on_domain( + __isl_take isl_space *domain); + __isl_give isl_qpolynomial *isl_qpolynomial_neginfty_on_domain( + __isl_take isl_space *domain); + __isl_give isl_qpolynomial *isl_qpolynomial_nan_on_domain( + __isl_take isl_space *domain); + __isl_give isl_qpolynomial *isl_qpolynomial_val_on_domain( + __isl_take isl_space *domain, + __isl_take isl_val *val); + __isl_give isl_qpolynomial *isl_qpolynomial_var_on_domain( + __isl_take isl_space *domain, + enum isl_dim_type type, unsigned pos); + __isl_give isl_qpolynomial *isl_qpolynomial_from_aff( + __isl_take isl_aff *aff); + +Recall that the space in which a quasipolynomial lives is a map space +with a one-dimensional range. The C argument in some of +the functions above corresponds to the domain of this map space. + +Quasipolynomials can be copied and freed again using the following +functions. + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_copy( + __isl_keep isl_qpolynomial *qp); + __isl_null isl_qpolynomial *isl_qpolynomial_free( + __isl_take isl_qpolynomial *qp); + +The constant term of a quasipolynomial can be extracted using + + __isl_give isl_val *isl_qpolynomial_get_constant_val( + __isl_keep isl_qpolynomial *qp); + +To iterate over all terms in a quasipolynomial, +use + + isl_stat isl_qpolynomial_foreach_term( + __isl_keep isl_qpolynomial *qp, + isl_stat (*fn)(__isl_take isl_term *term, + void *user), void *user); + +The terms themselves can be inspected and freed using +these functions + + unsigned isl_term_dim(__isl_keep isl_term *term, + enum isl_dim_type type); + __isl_give isl_val *isl_term_get_coefficient_val( + __isl_keep isl_term *term); + int isl_term_get_exp(__isl_keep isl_term *term, + enum isl_dim_type type, unsigned pos); + __isl_give isl_aff *isl_term_get_div( + __isl_keep isl_term *term, unsigned pos); + void isl_term_free(__isl_take isl_term *term); + +Each term is a product of parameters, set variables and +integer divisions. The function C +returns the exponent of a given dimensions in the given term. + +=back + +=head3 Reductions + +A reduction represents a maximum or a minimum of its +base expressions. +The only reduction type defined by C is +C. + +There are currently no functions to directly create such +objects, but they do appear in the piecewise quasipolynomial +reductions returned by the C function. +See +L. + +Reductions can be copied and freed using +the following functions. + + #include + __isl_give isl_qpolynomial_fold * + isl_qpolynomial_fold_copy( + __isl_keep isl_qpolynomial_fold *fold); + void isl_qpolynomial_fold_free( + __isl_take isl_qpolynomial_fold *fold); + +To iterate over all quasipolynomials in a reduction, use + + isl_stat isl_qpolynomial_fold_foreach_qpolynomial( + __isl_keep isl_qpolynomial_fold *fold, + isl_stat (*fn)(__isl_take isl_qpolynomial *qp, + void *user), void *user); + +=head3 Multiple Expressions + +A multiple expression represents a sequence of zero or +more base expressions, all defined on the same domain space. +The domain space of the multiple expression is the same +as that of the base expressions, but the range space +can be any space. In case the base expressions have +a set space, the corresponding multiple expression +also has a set space. +Objects of the value type do not have an associated space. +The space of a multiple value is therefore always a set space. +Similarly, the space of a multiple union piecewise +affine expression is always a set space. + +The multiple expression types defined by C +are C, C, C, +C. + +A multiple expression with the value zero for +each output (or set) dimension can be created +using the following functions. + + #include + __isl_give isl_multi_val *isl_multi_val_zero( + __isl_take isl_space *space); + + #include + __isl_give isl_multi_aff *isl_multi_aff_zero( + __isl_take isl_space *space); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_zero( + __isl_take isl_space *space); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_zero( + __isl_take isl_space *space); + +Since there is no canonical way of representing a zero +value of type C, the space passed +to C needs to be zero-dimensional. + +An identity function can be created using the following +functions. The space needs to be that of a relation +with the same number of input and output dimensions. + + #include + __isl_give isl_multi_aff *isl_multi_aff_identity( + __isl_take isl_space *space); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_identity( + __isl_take isl_space *space); + +A function that performs a projection on a universe +relation or set can be created using the following functions. +See also the corresponding +projection operations in L. + + #include + __isl_give isl_multi_aff *isl_multi_aff_domain_map( + __isl_take isl_space *space); + __isl_give isl_multi_aff *isl_multi_aff_range_map( + __isl_take isl_space *space); + __isl_give isl_multi_aff *isl_multi_aff_project_out_map( + __isl_take isl_space *space, + enum isl_dim_type type, + unsigned first, unsigned n); + +A multiple expression can be created from a single +base expression using the following functions. +The space of the created multiple expression is the same +as that of the base expression, except for +C where the input +lives in a parameter space and the output lives +in a single-dimensional set space. + + #include + __isl_give isl_multi_aff *isl_multi_aff_from_aff( + __isl_take isl_aff *aff); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_aff( + __isl_take isl_pw_aff *pa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); + +A multiple expression can be created from a list +of base expression in a specified space. +The domain of this space needs to be the same +as the domains of the base expressions in the list. +If the base expressions have a set space (or no associated space), +then this space also needs to be a set space. + + #include + __isl_give isl_multi_val *isl_multi_val_from_val_list( + __isl_take isl_space *space, + __isl_take isl_val_list *list); + + #include + __isl_give isl_multi_aff *isl_multi_aff_from_aff_list( + __isl_take isl_space *space, + __isl_take isl_aff_list *list); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_from_pw_aff_list( + __isl_take isl_space *space, + __isl_take isl_pw_aff_list *list); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_union_pw_aff_list( + __isl_take isl_space *space, + __isl_take isl_union_pw_aff_list *list); + +As a convenience, a multiple piecewise expression can +also be created from a multiple expression. +Each piecewise expression in the result has a single +universe cell. + + #include + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma); + +Similarly, a multiple union expression can be +created from a multiple expression. + + #include + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa); + +A multiple quasi-affine expression can be created from +a multiple value with a given domain space using the following +function. + + #include + __isl_give isl_multi_aff * + isl_multi_aff_multi_val_on_space( + __isl_take isl_space *space, + __isl_take isl_multi_val *mv); + +Similarly, +a multiple union piecewise affine expression can be created from +a multiple value with a given domain or +a multiple affine expression with a given domain +using the following functions. + + #include + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_multi_aff_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_multi_aff *ma); + +Multiple expressions can be copied and freed using +the following functions. + + #include + __isl_give isl_multi_val *isl_multi_val_copy( + __isl_keep isl_multi_val *mv); + __isl_null isl_multi_val *isl_multi_val_free( + __isl_take isl_multi_val *mv); + + #include + __isl_give isl_multi_aff *isl_multi_aff_copy( + __isl_keep isl_multi_aff *maff); + __isl_null isl_multi_aff *isl_multi_aff_free( + __isl_take isl_multi_aff *maff); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_copy( + __isl_keep isl_multi_pw_aff *mpa); + __isl_null isl_multi_pw_aff *isl_multi_pw_aff_free( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_copy( + __isl_keep isl_multi_union_pw_aff *mupa); + __isl_null isl_multi_union_pw_aff * + isl_multi_union_pw_aff_free( + __isl_take isl_multi_union_pw_aff *mupa); + +The base expression at a given position of a multiple +expression can be extracted using the following functions. + + #include + __isl_give isl_val *isl_multi_val_get_val( + __isl_keep isl_multi_val *mv, int pos); + + #include + __isl_give isl_aff *isl_multi_aff_get_aff( + __isl_keep isl_multi_aff *multi, int pos); + __isl_give isl_pw_aff *isl_multi_pw_aff_get_pw_aff( + __isl_keep isl_multi_pw_aff *mpa, int pos); + __isl_give isl_union_pw_aff * + isl_multi_union_pw_aff_get_union_pw_aff( + __isl_keep isl_multi_union_pw_aff *mupa, int pos); + +It can be replaced using the following functions. + + #include + __isl_give isl_multi_val *isl_multi_val_set_val( + __isl_take isl_multi_val *mv, int pos, + __isl_take isl_val *val); + + #include + __isl_give isl_multi_aff *isl_multi_aff_set_aff( + __isl_take isl_multi_aff *multi, int pos, + __isl_take isl_aff *aff); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa, int pos, + __isl_take isl_union_pw_aff *upa); + +As a convenience, a sequence of base expressions that have +their domains in a given space can be extracted from a sequence +of union expressions using the following function. + + #include + __isl_give isl_multi_pw_aff * + isl_multi_union_pw_aff_extract_multi_pw_aff( + __isl_keep isl_multi_union_pw_aff *mupa, + __isl_take isl_space *space); + +Note that there is a difference between C +and C objects. The first is a sequence +of unions of piecewise expressions, while the second is a union +of piecewise sequences. In particular, multiple affine expressions +in an C may live in different spaces, +while there is only a single multiple expression in +an C, which can therefore only live +in a single space. This means that not every +C can be converted to +an C. Conversely, a zero-dimensional +C carries no information +about any possible domain and therefore cannot be converted +to an C. Moreover, the elements +of an C may be defined over different domains, +while each multiple expression inside an C +has a single domain. The conversion of an C +of dimension greater than one may therefore not be exact. +The following functions can +be used to perform these conversions when they are possible. + + #include + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); + +=head3 Piecewise Expressions + +A piecewise expression is an expression that is described +using zero or more base expression defined over the same +number of cells in the domain space of the base expressions. +All base expressions are defined over the same +domain space and the cells are disjoint. +The space of a piecewise expression is the same as +that of the base expressions. +If the union of the cells is a strict subset of the domain +space, then the value of the piecewise expression outside +this union is different for types derived from quasi-affine +expressions and those derived from quasipolynomials. +Piecewise expressions derived from quasi-affine expressions +are considered to be undefined outside the union of their cells. +Piecewise expressions derived from quasipolynomials +are considered to be zero outside the union of their cells. + +Piecewise quasipolynomials are mainly used by the C +library for representing the number of elements in a parametric set or map. +For example, the piecewise quasipolynomial + + [n] -> { [x] -> ((1 + n) - x) : x <= n and x >= 0 } + +represents the number of points in the map + + [n] -> { [x] -> [y] : x,y >= 0 and 0 <= x + y <= n } + +The piecewise expression types defined by C +are C, C, +C and C. + +A piecewise expression with no cells can be created using +the following functions. + + #include + __isl_give isl_pw_aff *isl_pw_aff_empty( + __isl_take isl_space *space); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_empty( + __isl_take isl_space *space); + +A piecewise expression with a single universe cell can be +created using the following functions. + + #include + __isl_give isl_pw_aff *isl_pw_aff_from_aff( + __isl_take isl_aff *aff); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_from_multi_aff( + __isl_take isl_multi_aff *ma); + + #include + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_from_qpolynomial( + __isl_take isl_qpolynomial *qp); + +A piecewise expression with a single specified cell can be +created using the following functions. + + #include + __isl_give isl_pw_aff *isl_pw_aff_alloc( + __isl_take isl_set *set, __isl_take isl_aff *aff); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_alloc( + __isl_take isl_set *set, + __isl_take isl_multi_aff *maff); + + #include + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_alloc( + __isl_take isl_set *set, + __isl_take isl_qpolynomial *qp); + +The following convenience functions first create a base expression and +then create a piecewise expression over a universe domain. + + #include + __isl_give isl_pw_aff *isl_pw_aff_zero_on_domain( + __isl_take isl_local_space *ls); + __isl_give isl_pw_aff *isl_pw_aff_var_on_domain( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos); + __isl_give isl_pw_aff *isl_pw_aff_nan_on_domain( + __isl_take isl_local_space *ls); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero( + __isl_take isl_space *space); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity( + __isl_take isl_space *space); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map( + __isl_take isl_space *space); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_project_out_map( + __isl_take isl_space *space, + enum isl_dim_type type, + unsigned first, unsigned n); + + #include + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_zero( + __isl_take isl_space *space); + +The following convenience functions first create a base expression and +then create a piecewise expression over a given domain. + + #include + __isl_give isl_pw_aff *isl_pw_aff_val_on_domain( + __isl_take isl_set *domain, + __isl_take isl_val *v); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_multi_val_on_domain( + __isl_take isl_set *domain, + __isl_take isl_multi_val *mv); + +As a convenience, a piecewise multiple expression can +also be created from a piecewise expression. +Each multiple expression in the result is derived +from the corresponding base expression. + + #include + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff( + __isl_take isl_pw_aff *pa); + +Similarly, a piecewise quasipolynomial can be +created from a piecewise quasi-affine expression using +the following function. + + #include + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_from_pw_aff( + __isl_take isl_pw_aff *pwaff); + +Piecewise expressions can be copied and freed using the following functions. + + #include + __isl_give isl_pw_aff *isl_pw_aff_copy( + __isl_keep isl_pw_aff *pwaff); + __isl_null isl_pw_aff *isl_pw_aff_free( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_copy( + __isl_keep isl_pw_multi_aff *pma); + __isl_null isl_pw_multi_aff *isl_pw_multi_aff_free( + __isl_take isl_pw_multi_aff *pma); + + #include + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_copy( + __isl_keep isl_pw_qpolynomial *pwqp); + __isl_null isl_pw_qpolynomial *isl_pw_qpolynomial_free( + __isl_take isl_pw_qpolynomial *pwqp); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_copy( + __isl_keep isl_pw_qpolynomial_fold *pwf); + __isl_null isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_free( + __isl_take isl_pw_qpolynomial_fold *pwf); + +To iterate over the different cells of a piecewise expression, +use the following functions. + + #include + isl_bool isl_pw_aff_is_empty(__isl_keep isl_pw_aff *pwaff); + int isl_pw_aff_n_piece(__isl_keep isl_pw_aff *pwaff); + isl_stat isl_pw_aff_foreach_piece( + __isl_keep isl_pw_aff *pwaff, + isl_stat (*fn)(__isl_take isl_set *set, + __isl_take isl_aff *aff, + void *user), void *user); + int isl_pw_multi_aff_n_piece( + __isl_keep isl_pw_multi_aff *pma); + isl_stat isl_pw_multi_aff_foreach_piece( + __isl_keep isl_pw_multi_aff *pma, + isl_stat (*fn)(__isl_take isl_set *set, + __isl_take isl_multi_aff *maff, + void *user), void *user); + + #include + int isl_pw_qpolynomial_n_piece( + __isl_keep isl_pw_qpolynomial *pwqp); + isl_stat isl_pw_qpolynomial_foreach_piece( + __isl_keep isl_pw_qpolynomial *pwqp, + isl_stat (*fn)(__isl_take isl_set *set, + __isl_take isl_qpolynomial *qp, + void *user), void *user); + isl_stat isl_pw_qpolynomial_foreach_lifted_piece( + __isl_keep isl_pw_qpolynomial *pwqp, + isl_stat (*fn)(__isl_take isl_set *set, + __isl_take isl_qpolynomial *qp, + void *user), void *user); + int isl_pw_qpolynomial_fold_n_piece( + __isl_keep isl_pw_qpolynomial_fold *pwf); + isl_stat isl_pw_qpolynomial_fold_foreach_piece( + __isl_keep isl_pw_qpolynomial_fold *pwf, + isl_stat (*fn)(__isl_take isl_set *set, + __isl_take isl_qpolynomial_fold *fold, + void *user), void *user); + isl_stat isl_pw_qpolynomial_fold_foreach_lifted_piece( + __isl_keep isl_pw_qpolynomial_fold *pwf, + isl_stat (*fn)(__isl_take isl_set *set, + __isl_take isl_qpolynomial_fold *fold, + void *user), void *user); + +As usual, the function C should return C on success +and C on failure. The difference between +C and +C is that +C will first +compute unique representations for all existentially quantified +variables and then turn these existentially quantified variables +into extra set variables, adapting the associated quasipolynomial +accordingly. This means that the C passed to C +will not have any existentially quantified variables, but that +the dimensions of the sets may be different for different +invocations of C. +Similarly for C +and C. + +A piecewise expression consisting of the expressions at a given +position of a piecewise multiple expression can be extracted +using the following function. + + #include + __isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff( + __isl_keep isl_pw_multi_aff *pma, int pos); + +These expressions can be replaced using the following function. + + #include + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff( + __isl_take isl_pw_multi_aff *pma, unsigned pos, + __isl_take isl_pw_aff *pa); + +Note that there is a difference between C and +C objects. The first is a sequence of piecewise +affine expressions, while the second is a piecewise sequence +of affine expressions. In particular, each of the piecewise +affine expressions in an C may have a different +domain, while all multiple expressions associated to a cell +in an C have the same domain. +It is possible to convert between the two, but when converting +an C to an C, the domain +of the result is the intersection of the domains of the input. +The reverse conversion is exact. + + #include + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_from_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma); + +=head3 Union Expressions + +A union expression collects base expressions defined +over different domains. The space of a union expression +is that of the shared parameter space. + +The union expression types defined by C +are C, C, +C and C. +In case of +C, +C and C, +there can be at most one base expression for a given domain space. +In case of +C, +there can be multiple such expressions for a given domain space, +but the domains of these expressions need to be disjoint. + +An empty union expression can be created using the following functions. + + #include + __isl_give isl_union_pw_aff *isl_union_pw_aff_empty( + __isl_take isl_space *space); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_empty( + __isl_take isl_space *space); + + #include + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_zero( + __isl_take isl_space *space); + +A union expression containing a single base expression +can be created using the following functions. + + #include + __isl_give isl_union_pw_aff * + isl_union_pw_aff_from_pw_aff( + __isl_take isl_pw_aff *pa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_aff( + __isl_take isl_aff *aff); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma); + + #include + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_from_pw_qpolynomial( + __isl_take isl_pw_qpolynomial *pwqp); + +The following functions create a base expression on each +of the sets in the union set and collect the results. + + #include + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_pw_aff * + isl_union_pw_multi_aff_get_union_pw_aff( + __isl_keep isl_union_pw_multi_aff *upma, int pos); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_val_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_val *v); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_multi_val *mv); + +An C that is equal to a (parametric) affine +expression on a given domain can be created using the following +function. + + #include + __isl_give isl_union_pw_aff * + isl_union_pw_aff_aff_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_aff *aff); + +A base expression can be added to a union expression using +the following functions. + + #include + __isl_give isl_union_pw_aff * + isl_union_pw_aff_add_pw_aff( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_pw_aff *pa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_add_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_pw_multi_aff *pma); + + #include + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_add_pw_qpolynomial( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_pw_qpolynomial *pwqp); + +Union expressions can be copied and freed using +the following functions. + + #include + __isl_give isl_union_pw_aff *isl_union_pw_aff_copy( + __isl_keep isl_union_pw_aff *upa); + __isl_null isl_union_pw_aff *isl_union_pw_aff_free( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_copy( + __isl_keep isl_union_pw_multi_aff *upma); + __isl_null isl_union_pw_multi_aff * + isl_union_pw_multi_aff_free( + __isl_take isl_union_pw_multi_aff *upma); + + #include + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_copy( + __isl_keep isl_union_pw_qpolynomial *upwqp); + __isl_null isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_free( + __isl_take isl_union_pw_qpolynomial *upwqp); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_copy( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + __isl_null isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_free( + __isl_take isl_union_pw_qpolynomial_fold *upwf); + +To iterate over the base expressions in a union expression, +use the following functions. + + #include + int isl_union_pw_aff_n_pw_aff( + __isl_keep isl_union_pw_aff *upa); + isl_stat isl_union_pw_aff_foreach_pw_aff( + __isl_keep isl_union_pw_aff *upa, + isl_stat (*fn)(__isl_take isl_pw_aff *pa, + void *user), void *user); + int isl_union_pw_multi_aff_n_pw_multi_aff( + __isl_keep isl_union_pw_multi_aff *upma); + isl_stat isl_union_pw_multi_aff_foreach_pw_multi_aff( + __isl_keep isl_union_pw_multi_aff *upma, + isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, + void *user), void *user); + + #include + int isl_union_pw_qpolynomial_n_pw_qpolynomial( + __isl_keep isl_union_pw_qpolynomial *upwqp); + isl_stat isl_union_pw_qpolynomial_foreach_pw_qpolynomial( + __isl_keep isl_union_pw_qpolynomial *upwqp, + isl_stat (*fn)(__isl_take isl_pw_qpolynomial *pwqp, + void *user), void *user); + int isl_union_pw_qpolynomial_fold_n_pw_qpolynomial_fold( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + isl_stat isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold( + __isl_keep isl_union_pw_qpolynomial_fold *upwf, + isl_stat (*fn)(__isl_take isl_pw_qpolynomial_fold *pwf, + void *user), void *user); + +To extract the base expression in a given space from a union, use +the following functions. + + #include + __isl_give isl_pw_aff *isl_union_pw_aff_extract_pw_aff( + __isl_keep isl_union_pw_aff *upa, + __isl_take isl_space *space); + __isl_give isl_pw_multi_aff * + isl_union_pw_multi_aff_extract_pw_multi_aff( + __isl_keep isl_union_pw_multi_aff *upma, + __isl_take isl_space *space); + + #include + __isl_give isl_pw_qpolynomial * + isl_union_pw_qpolynomial_extract_pw_qpolynomial( + __isl_keep isl_union_pw_qpolynomial *upwqp, + __isl_take isl_space *space); + +=head2 Input and Output + +For set and relation, +C supports its own input/output format, which is similar +to the C format, but also supports the C format +in some cases. +For other object types, typically only an C format is supported. + +=head3 C format + +The C format is similar to that of C, but has a different +syntax for describing the parameters and allows for the definition +of an existentially quantified variable as the integer division +of an affine expression. +For example, the set of integers C between C<0> and C +such that C can be described as + + [n] -> { [i] : exists (a = [i/10] : 0 <= i and i <= n and + i - 10 a <= 6) } + +A set or relation can have several disjuncts, separated +by the keyword C. Each disjunct is either a conjunction +of constraints or a projection (C) of a conjunction +of constraints. The constraints are separated by the keyword +C. + +=head3 C format + +If the represented set is a union, then the first line +contains a single number representing the number of disjuncts. +Otherwise, a line containing the number C<1> is optional. + +Each disjunct is represented by a matrix of constraints. +The first line contains two numbers representing +the number of rows and columns, +where the number of rows is equal to the number of constraints +and the number of columns is equal to two plus the number of variables. +The following lines contain the actual rows of the constraint matrix. +In each row, the first column indicates whether the constraint +is an equality (C<0>) or inequality (C<1>). The final column +corresponds to the constant term. + +If the set is parametric, then the coefficients of the parameters +appear in the last columns before the constant column. +The coefficients of any existentially quantified variables appear +between those of the set variables and those of the parameters. + +=head3 Extended C format + +The extended C format is nearly identical to the +C format. The only difference is that the line +containing the number of rows and columns of a constraint matrix +also contains four additional numbers: +the number of output dimensions, the number of input dimensions, +the number of local dimensions (i.e., the number of existentially +quantified variables) and the number of parameters. +For sets, the number of ``output'' dimensions is equal +to the number of set dimensions, while the number of ``input'' +dimensions is zero. + +=head3 Input + +Objects can be read from input using the following functions. + + #include + __isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx, + const char *str); + __isl_give isl_multi_val *isl_multi_val_read_from_str( + isl_ctx *ctx, const char *str); + + #include + __isl_give isl_basic_set *isl_basic_set_read_from_file( + isl_ctx *ctx, FILE *input); + __isl_give isl_basic_set *isl_basic_set_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_set *isl_set_read_from_file(isl_ctx *ctx, + FILE *input); + __isl_give isl_set *isl_set_read_from_str(isl_ctx *ctx, + const char *str); + + #include + __isl_give isl_basic_map *isl_basic_map_read_from_file( + isl_ctx *ctx, FILE *input); + __isl_give isl_basic_map *isl_basic_map_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_map *isl_map_read_from_file( + isl_ctx *ctx, FILE *input); + __isl_give isl_map *isl_map_read_from_str(isl_ctx *ctx, + const char *str); + + #include + __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( + isl_ctx *ctx, const char *str); + + #include + __isl_give isl_union_map *isl_union_map_read_from_file( + isl_ctx *ctx, FILE *input); + __isl_give isl_union_map *isl_union_map_read_from_str( + isl_ctx *ctx, const char *str); + + #include + __isl_give isl_aff *isl_aff_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_multi_aff *isl_multi_aff_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_pw_aff *isl_pw_aff_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_read_from_str( + isl_ctx *ctx, const char *str); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_read_from_str( + isl_ctx *ctx, const char *str); + + #include + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_read_from_str( + isl_ctx *ctx, const char *str); + +For sets and relations, +the input format is autodetected and may be either the C format +or the C format. + +=head3 Output + +Before anything can be printed, an C needs to +be created. + + __isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, + FILE *file); + __isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx); + __isl_null isl_printer *isl_printer_free( + __isl_take isl_printer *printer); + +C prints to the given file, while +C prints to a string that can be extracted +using the following function. + + #include + __isl_give char *isl_printer_get_str( + __isl_keep isl_printer *printer); + +The printer can be inspected using the following functions. + + FILE *isl_printer_get_file( + __isl_keep isl_printer *printer); + int isl_printer_get_output_format( + __isl_keep isl_printer *p); + int isl_printer_get_yaml_style(__isl_keep isl_printer *p); + +The behavior of the printer can be modified in various ways + + __isl_give isl_printer *isl_printer_set_output_format( + __isl_take isl_printer *p, int output_format); + __isl_give isl_printer *isl_printer_set_indent( + __isl_take isl_printer *p, int indent); + __isl_give isl_printer *isl_printer_set_indent_prefix( + __isl_take isl_printer *p, const char *prefix); + __isl_give isl_printer *isl_printer_indent( + __isl_take isl_printer *p, int indent); + __isl_give isl_printer *isl_printer_set_prefix( + __isl_take isl_printer *p, const char *prefix); + __isl_give isl_printer *isl_printer_set_suffix( + __isl_take isl_printer *p, const char *suffix); + __isl_give isl_printer *isl_printer_set_yaml_style( + __isl_take isl_printer *p, int yaml_style); + +The C may be either C, C, +C, C or C +and defaults to C. +Each line in the output is prefixed by C, +indented by C (set by C) spaces +(default: 0), prefixed by C and suffixed by C. +In the C format output, +the coefficients of the existentially quantified variables +appear between those of the set variables and those +of the parameters. +The function C increases the indentation +by the specified amount (which may be negative). +The YAML style may be either C or +C and when we are printing something +in YAML format. + +To actually print something, use + + #include + __isl_give isl_printer *isl_printer_print_double( + __isl_take isl_printer *p, double d); + + #include + __isl_give isl_printer *isl_printer_print_val( + __isl_take isl_printer *p, __isl_keep isl_val *v); + + #include + __isl_give isl_printer *isl_printer_print_basic_set( + __isl_take isl_printer *printer, + __isl_keep isl_basic_set *bset); + __isl_give isl_printer *isl_printer_print_set( + __isl_take isl_printer *printer, + __isl_keep isl_set *set); + + #include + __isl_give isl_printer *isl_printer_print_basic_map( + __isl_take isl_printer *printer, + __isl_keep isl_basic_map *bmap); + __isl_give isl_printer *isl_printer_print_map( + __isl_take isl_printer *printer, + __isl_keep isl_map *map); + + #include + __isl_give isl_printer *isl_printer_print_union_set( + __isl_take isl_printer *p, + __isl_keep isl_union_set *uset); + + #include + __isl_give isl_printer *isl_printer_print_union_map( + __isl_take isl_printer *p, + __isl_keep isl_union_map *umap); + + #include + __isl_give isl_printer *isl_printer_print_multi_val( + __isl_take isl_printer *p, + __isl_keep isl_multi_val *mv); + + #include + __isl_give isl_printer *isl_printer_print_aff( + __isl_take isl_printer *p, __isl_keep isl_aff *aff); + __isl_give isl_printer *isl_printer_print_multi_aff( + __isl_take isl_printer *p, + __isl_keep isl_multi_aff *maff); + __isl_give isl_printer *isl_printer_print_pw_aff( + __isl_take isl_printer *p, + __isl_keep isl_pw_aff *pwaff); + __isl_give isl_printer *isl_printer_print_pw_multi_aff( + __isl_take isl_printer *p, + __isl_keep isl_pw_multi_aff *pma); + __isl_give isl_printer *isl_printer_print_multi_pw_aff( + __isl_take isl_printer *p, + __isl_keep isl_multi_pw_aff *mpa); + __isl_give isl_printer *isl_printer_print_union_pw_aff( + __isl_take isl_printer *p, + __isl_keep isl_union_pw_aff *upa); + __isl_give isl_printer *isl_printer_print_union_pw_multi_aff( + __isl_take isl_printer *p, + __isl_keep isl_union_pw_multi_aff *upma); + __isl_give isl_printer * + isl_printer_print_multi_union_pw_aff( + __isl_take isl_printer *p, + __isl_keep isl_multi_union_pw_aff *mupa); + + #include + __isl_give isl_printer *isl_printer_print_qpolynomial( + __isl_take isl_printer *p, + __isl_keep isl_qpolynomial *qp); + __isl_give isl_printer *isl_printer_print_pw_qpolynomial( + __isl_take isl_printer *p, + __isl_keep isl_pw_qpolynomial *pwqp); + __isl_give isl_printer *isl_printer_print_union_pw_qpolynomial( + __isl_take isl_printer *p, + __isl_keep isl_union_pw_qpolynomial *upwqp); + + __isl_give isl_printer * + isl_printer_print_pw_qpolynomial_fold( + __isl_take isl_printer *p, + __isl_keep isl_pw_qpolynomial_fold *pwf); + __isl_give isl_printer * + isl_printer_print_union_pw_qpolynomial_fold( + __isl_take isl_printer *p, + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + +For C, +C and +C, +the output format of the printer +needs to be set to either C or C. +For C and +C, only C +is supported. +In case of printing in C, the user may want +to set the names of all dimensions first. + +C also provides limited support for printing YAML documents, +just enough for the internal use for printing such documents. + + #include + __isl_give isl_printer *isl_printer_yaml_start_mapping( + __isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_yaml_end_mapping( + __isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_yaml_start_sequence( + __isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_yaml_end_sequence( + __isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_yaml_next( + __isl_take isl_printer *p); + +A document is started by a call to either +C or C. +Anything printed to the printer after such a call belong to the +first key of the mapping or the first element in the sequence. +The function C moves to the value if +we are currently printing a mapping key, the next key if we +are printing a value or the next element if we are printing +an element in a sequence. +Nested mappings and sequences are initiated by the same +C or C. +Each call to these functions needs to have a corresponding call to +C or C. + +When called on a file printer, the following function flushes +the file. When called on a string printer, the buffer is cleared. + + __isl_give isl_printer *isl_printer_flush( + __isl_take isl_printer *p); + +The following functions allow the user to attach +notes to a printer in order to keep track of additional state. + + #include + isl_bool isl_printer_has_note(__isl_keep isl_printer *p, + __isl_keep isl_id *id); + __isl_give isl_id *isl_printer_get_note( + __isl_keep isl_printer *p, __isl_take isl_id *id); + __isl_give isl_printer *isl_printer_set_note( + __isl_take isl_printer *p, + __isl_take isl_id *id, __isl_take isl_id *note); + +C associates the given note to the given +identifier in the printer. +C retrieves a note associated to an +identifier, while +C checks if there is such a note. +C fails if the requested note does not exist. + +Alternatively, a string representation can be obtained +directly using the following functions, which always print +in isl format. + + #include + __isl_give char *isl_id_to_str( + __isl_keep isl_id *id); + + #include + __isl_give char *isl_space_to_str( + __isl_keep isl_space *space); + + #include + __isl_give char *isl_val_to_str(__isl_keep isl_val *v); + __isl_give char *isl_multi_val_to_str( + __isl_keep isl_multi_val *mv); + + #include + __isl_give char *isl_basic_set_to_str( + __isl_keep isl_basic_set *bset); + __isl_give char *isl_set_to_str( + __isl_keep isl_set *set); + + #include + __isl_give char *isl_union_set_to_str( + __isl_keep isl_union_set *uset); + + #include + __isl_give char *isl_basic_map_to_str( + __isl_keep isl_basic_map *bmap); + __isl_give char *isl_map_to_str( + __isl_keep isl_map *map); + + #include + __isl_give char *isl_union_map_to_str( + __isl_keep isl_union_map *umap); + + #include + __isl_give char *isl_aff_to_str(__isl_keep isl_aff *aff); + __isl_give char *isl_pw_aff_to_str( + __isl_keep isl_pw_aff *pa); + __isl_give char *isl_multi_aff_to_str( + __isl_keep isl_multi_aff *ma); + __isl_give char *isl_pw_multi_aff_to_str( + __isl_keep isl_pw_multi_aff *pma); + __isl_give char *isl_multi_pw_aff_to_str( + __isl_keep isl_multi_pw_aff *mpa); + __isl_give char *isl_union_pw_aff_to_str( + __isl_keep isl_union_pw_aff *upa); + __isl_give char *isl_union_pw_multi_aff_to_str( + __isl_keep isl_union_pw_multi_aff *upma); + __isl_give char *isl_multi_union_pw_aff_to_str( + __isl_keep isl_multi_union_pw_aff *mupa); + + #include + __isl_give char *isl_point_to_str( + __isl_keep isl_point *pnt); + + #include + __isl_give char *isl_pw_qpolynomial_to_str( + __isl_keep isl_pw_qpolynomial *pwqp); + __isl_give char *isl_union_pw_qpolynomial_to_str( + __isl_keep isl_union_pw_qpolynomial *upwqp); + +=head2 Properties + +=head3 Unary Properties + +=over + +=item * Emptiness + +The following functions test whether the given set or relation +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. + + #include + isl_bool isl_basic_set_plain_is_empty( + __isl_keep isl_basic_set *bset); + isl_bool isl_basic_set_is_empty( + __isl_keep isl_basic_set *bset); + isl_bool isl_set_plain_is_empty( + __isl_keep isl_set *set); + isl_bool isl_set_is_empty(__isl_keep isl_set *set); + + #include + isl_bool isl_union_set_is_empty( + __isl_keep isl_union_set *uset); + + #include + isl_bool isl_basic_map_plain_is_empty( + __isl_keep isl_basic_map *bmap); + isl_bool isl_basic_map_is_empty( + __isl_keep isl_basic_map *bmap); + isl_bool isl_map_plain_is_empty( + __isl_keep isl_map *map); + isl_bool isl_map_is_empty(__isl_keep isl_map *map); + + #include + isl_bool isl_union_map_plain_is_empty( + __isl_keep isl_union_map *umap); + isl_bool isl_union_map_is_empty( + __isl_keep isl_union_map *umap); + +=item * Universality + + isl_bool isl_basic_set_plain_is_universe( + __isl_keep isl_basic_set *bset); + isl_bool isl_basic_set_is_universe( + __isl_keep isl_basic_set *bset); + isl_bool isl_basic_map_plain_is_universe( + __isl_keep isl_basic_map *bmap); + isl_bool isl_basic_map_is_universe( + __isl_keep isl_basic_map *bmap); + isl_bool isl_set_plain_is_universe( + __isl_keep isl_set *set); + isl_bool isl_map_plain_is_universe( + __isl_keep isl_map *map); + +=item * Single-valuedness + + #include + isl_bool isl_set_is_singleton(__isl_keep isl_set *set); + + #include + isl_bool isl_basic_map_is_single_valued( + __isl_keep isl_basic_map *bmap); + isl_bool isl_map_plain_is_single_valued( + __isl_keep isl_map *map); + isl_bool isl_map_is_single_valued(__isl_keep isl_map *map); + + #include + isl_bool isl_union_map_is_single_valued( + __isl_keep isl_union_map *umap); + +=item * Injectivity + + isl_bool isl_map_plain_is_injective( + __isl_keep isl_map *map); + isl_bool isl_map_is_injective( + __isl_keep isl_map *map); + isl_bool isl_union_map_plain_is_injective( + __isl_keep isl_union_map *umap); + isl_bool isl_union_map_is_injective( + __isl_keep isl_union_map *umap); + +=item * Bijectivity + + isl_bool isl_map_is_bijective( + __isl_keep isl_map *map); + isl_bool isl_union_map_is_bijective( + __isl_keep isl_union_map *umap); + +=item * Identity + +The following functions test whether the given relation +only maps elements to themselves. + + #include + isl_bool isl_map_is_identity( + __isl_keep isl_map *map); + + #include + isl_bool isl_union_map_is_identity( + __isl_keep isl_union_map *umap); + +=item * Position + + __isl_give isl_val * + isl_basic_map_plain_get_val_if_fixed( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos); + __isl_give isl_val *isl_set_plain_get_val_if_fixed( + __isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + __isl_give isl_val *isl_map_plain_get_val_if_fixed( + __isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); + +If the set or relation obviously lies on a hyperplane where the given dimension +has a fixed value, then return that value. +Otherwise return NaN. + +=item * Stride + + isl_stat isl_set_dim_residue_class_val( + __isl_keep isl_set *set, + int pos, __isl_give isl_val **modulo, + __isl_give isl_val **residue); + +Check if the values of the given set dimension are equal to a fixed +value modulo some integer value. If so, assign the modulo to C<*modulo> +and the fixed value to C<*residue>. If the given dimension attains only +a single value, then assign C<0> to C<*modulo> and the fixed value to +C<*residue>. +If the dimension does not attain only a single value and if no modulo +can be found then assign C<1> to C<*modulo> and C<1> to C<*residue>. + +=item * Dependence + +To check whether the description of a set, relation or function depends +on one or more given dimensions, +the following functions can be used. + + #include + isl_bool isl_constraint_involves_dims( + __isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned first, unsigned n); + + #include + isl_bool isl_basic_set_involves_dims( + __isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); + isl_bool isl_set_involves_dims(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); + + #include + isl_bool isl_basic_map_involves_dims( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); + isl_bool isl_map_involves_dims(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); + + #include + isl_bool isl_union_map_involves_dims( + __isl_keep isl_union_map *umap, + enum isl_dim_type type, unsigned first, unsigned n); + + #include + isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n); + isl_bool isl_pw_aff_involves_dims( + __isl_keep isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned first, unsigned n); + isl_bool isl_multi_aff_involves_dims( + __isl_keep isl_multi_aff *ma, + enum isl_dim_type type, unsigned first, unsigned n); + isl_bool isl_multi_pw_aff_involves_dims( + __isl_keep isl_multi_pw_aff *mpa, + enum isl_dim_type type, unsigned first, unsigned n); + + #include + isl_bool isl_qpolynomial_involves_dims( + __isl_keep isl_qpolynomial *qp, + enum isl_dim_type type, unsigned first, unsigned n); + +Similarly, the following functions can be used to check whether +a given dimension is involved in any lower or upper bound. + + #include + isl_bool isl_set_dim_has_any_lower_bound( + __isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + isl_bool isl_set_dim_has_any_upper_bound( + __isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + +Note that these functions return true even if there is a bound on +the dimension on only some of the basic sets of C. +To check if they have a bound for all of the basic sets in C, +use the following functions instead. + + #include + isl_bool isl_set_dim_has_lower_bound( + __isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + isl_bool isl_set_dim_has_upper_bound( + __isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + +=item * Space + +To check whether a set is a parameter domain, use this function: + + isl_bool isl_set_is_params(__isl_keep isl_set *set); + isl_bool isl_union_set_is_params( + __isl_keep isl_union_set *uset); + +=item * Wrapping + +The following functions check whether the space of the given +(basic) set or relation domain and/or range is a wrapped relation. + + #include + isl_bool isl_space_is_wrapping( + __isl_keep isl_space *space); + isl_bool isl_space_domain_is_wrapping( + __isl_keep isl_space *space); + isl_bool isl_space_range_is_wrapping( + __isl_keep isl_space *space); + isl_bool isl_space_is_product( + __isl_keep isl_space *space); + + #include + isl_bool isl_basic_set_is_wrapping( + __isl_keep isl_basic_set *bset); + isl_bool isl_set_is_wrapping(__isl_keep isl_set *set); + + #include + isl_bool isl_map_domain_is_wrapping( + __isl_keep isl_map *map); + isl_bool isl_map_range_is_wrapping( + __isl_keep isl_map *map); + isl_bool isl_map_is_product(__isl_keep isl_map *map); + + #include + isl_bool isl_multi_val_range_is_wrapping( + __isl_keep isl_multi_val *mv); + + #include + isl_bool isl_multi_aff_range_is_wrapping( + __isl_keep isl_multi_aff *ma); + isl_bool isl_multi_pw_aff_range_is_wrapping( + __isl_keep isl_multi_pw_aff *mpa); + isl_bool isl_multi_union_pw_aff_range_is_wrapping( + __isl_keep isl_multi_union_pw_aff *mupa); + +The input to C should +be the space of a set, while that of +C and +C should be the space of a relation. +The input to C can be either the space +of a set or that of a binary relation. +In case the input is the space of a binary relation, it checks +whether both domain and range are wrapping. + +=item * Internal Product + + isl_bool isl_basic_map_can_zip( + __isl_keep isl_basic_map *bmap); + isl_bool isl_map_can_zip(__isl_keep isl_map *map); + +Check whether the product of domain and range of the given relation +can be computed, +i.e., whether both domain and range are nested relations. + +=item * Currying + + #include + isl_bool isl_space_can_curry( + __isl_keep isl_space *space); + + #include + isl_bool isl_basic_map_can_curry( + __isl_keep isl_basic_map *bmap); + isl_bool isl_map_can_curry(__isl_keep isl_map *map); + +Check whether the domain of the (basic) relation is a wrapped relation. + + #include + __isl_give isl_space *isl_space_uncurry( + __isl_take isl_space *space); + + #include + isl_bool isl_basic_map_can_uncurry( + __isl_keep isl_basic_map *bmap); + isl_bool isl_map_can_uncurry(__isl_keep isl_map *map); + +Check whether the range of the (basic) relation is a wrapped relation. + + #include + isl_bool isl_space_can_range_curry( + __isl_keep isl_space *space); + + #include + isl_bool isl_map_can_range_curry( + __isl_keep isl_map *map); + +Check whether the domain of the relation wrapped in the range of +the input is itself a wrapped relation. + +=item * Special Values + + #include + isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff); + isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff); + isl_bool isl_multi_pw_aff_is_cst( + __isl_keep isl_multi_pw_aff *mpa); + +Check whether the given expression is a constant. + + #include + isl_bool isl_multi_val_involves_nan( + __isl_keep isl_multi_val *mv); + + #include + isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff); + isl_bool isl_multi_aff_involves_nan( + __isl_keep isl_multi_aff *ma); + isl_bool isl_pw_aff_involves_nan( + __isl_keep isl_pw_aff *pa); + isl_bool isl_pw_multi_aff_involves_nan( + __isl_keep isl_pw_multi_aff *pma); + isl_bool isl_multi_pw_aff_involves_nan( + __isl_keep isl_multi_pw_aff *mpa); + isl_bool isl_union_pw_aff_involves_nan( + __isl_keep isl_union_pw_aff *upa); + isl_bool isl_union_pw_multi_aff_involves_nan( + __isl_keep isl_union_pw_multi_aff *upma); + isl_bool isl_multi_union_pw_aff_involves_nan( + __isl_keep isl_multi_union_pw_aff *mupa); + + #include + isl_bool isl_qpolynomial_is_nan( + __isl_keep isl_qpolynomial *qp); + isl_bool isl_qpolynomial_fold_is_nan( + __isl_keep isl_qpolynomial_fold *fold); + isl_bool isl_pw_qpolynomial_involves_nan( + __isl_keep isl_pw_qpolynomial *pwqp); + isl_bool isl_pw_qpolynomial_fold_involves_nan( + __isl_keep isl_pw_qpolynomial_fold *pwf); + isl_bool isl_union_pw_qpolynomial_involves_nan( + __isl_keep isl_union_pw_qpolynomial *upwqp); + isl_bool isl_union_pw_qpolynomial_fold_involves_nan( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + +Check whether the given expression is equal to or involves NaN. + + #include + isl_bool isl_aff_plain_is_zero( + __isl_keep isl_aff *aff); + +Check whether the affine expression is obviously zero. + +=back + +=head3 Binary Properties + +=over + +=item * Equality + +The following functions check whether two objects +represent the same set, relation or function. +The C variants only return true if the objects +are obviously the same. That is, they may return false +even if the objects are the same, but they will never +return true if the objects are not the same. + + #include + isl_bool isl_basic_set_plain_is_equal( + __isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2); + isl_bool isl_basic_set_is_equal( + __isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2); + isl_bool isl_set_plain_is_equal( + __isl_keep isl_set *set1, + __isl_keep isl_set *set2); + isl_bool isl_set_is_equal(__isl_keep isl_set *set1, + __isl_keep isl_set *set2); + + #include + isl_bool isl_basic_map_is_equal( + __isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); + isl_bool isl_map_is_equal(__isl_keep isl_map *map1, + __isl_keep isl_map *map2); + isl_bool isl_map_plain_is_equal( + __isl_keep isl_map *map1, + __isl_keep isl_map *map2); + + #include + isl_bool isl_union_set_is_equal( + __isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); + + #include + isl_bool isl_union_map_is_equal( + __isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); + + #include + isl_bool isl_aff_plain_is_equal( + __isl_keep isl_aff *aff1, + __isl_keep isl_aff *aff2); + isl_bool isl_multi_aff_plain_is_equal( + __isl_keep isl_multi_aff *maff1, + __isl_keep isl_multi_aff *maff2); + isl_bool isl_pw_aff_plain_is_equal( + __isl_keep isl_pw_aff *pwaff1, + __isl_keep isl_pw_aff *pwaff2); + isl_bool isl_pw_aff_is_equal( + __isl_keep isl_pw_aff *pa1, + __isl_keep isl_pw_aff *pa2); + isl_bool isl_pw_multi_aff_plain_is_equal( + __isl_keep isl_pw_multi_aff *pma1, + __isl_keep isl_pw_multi_aff *pma2); + isl_bool isl_pw_multi_aff_is_equal( + __isl_keep isl_pw_multi_aff *pma1, + __isl_keep isl_pw_multi_aff *pma2); + isl_bool isl_multi_pw_aff_plain_is_equal( + __isl_keep isl_multi_pw_aff *mpa1, + __isl_keep isl_multi_pw_aff *mpa2); + isl_bool isl_multi_pw_aff_is_equal( + __isl_keep isl_multi_pw_aff *mpa1, + __isl_keep isl_multi_pw_aff *mpa2); + isl_bool isl_union_pw_aff_plain_is_equal( + __isl_keep isl_union_pw_aff *upa1, + __isl_keep isl_union_pw_aff *upa2); + isl_bool isl_union_pw_multi_aff_plain_is_equal( + __isl_keep isl_union_pw_multi_aff *upma1, + __isl_keep isl_union_pw_multi_aff *upma2); + isl_bool isl_multi_union_pw_aff_plain_is_equal( + __isl_keep isl_multi_union_pw_aff *mupa1, + __isl_keep isl_multi_union_pw_aff *mupa2); + + #include + isl_bool isl_union_pw_qpolynomial_plain_is_equal( + __isl_keep isl_union_pw_qpolynomial *upwqp1, + __isl_keep isl_union_pw_qpolynomial *upwqp2); + isl_bool isl_union_pw_qpolynomial_fold_plain_is_equal( + __isl_keep isl_union_pw_qpolynomial_fold *upwf1, + __isl_keep isl_union_pw_qpolynomial_fold *upwf2); + +=item * Disjointness + + #include + isl_bool isl_basic_set_is_disjoint( + __isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2); + isl_bool isl_set_plain_is_disjoint( + __isl_keep isl_set *set1, + __isl_keep isl_set *set2); + isl_bool isl_set_is_disjoint(__isl_keep isl_set *set1, + __isl_keep isl_set *set2); + + #include + isl_bool isl_basic_map_is_disjoint( + __isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); + isl_bool isl_map_is_disjoint(__isl_keep isl_map *map1, + __isl_keep isl_map *map2); + + #include + isl_bool isl_union_set_is_disjoint( + __isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); + + #include + isl_bool isl_union_map_is_disjoint( + __isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); + +=item * Subset + + isl_bool isl_basic_set_is_subset( + __isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2); + isl_bool isl_set_is_subset(__isl_keep isl_set *set1, + __isl_keep isl_set *set2); + isl_bool isl_set_is_strict_subset( + __isl_keep isl_set *set1, + __isl_keep isl_set *set2); + isl_bool isl_union_set_is_subset( + __isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); + isl_bool isl_union_set_is_strict_subset( + __isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); + isl_bool isl_basic_map_is_subset( + __isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); + isl_bool isl_basic_map_is_strict_subset( + __isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); + isl_bool isl_map_is_subset( + __isl_keep isl_map *map1, + __isl_keep isl_map *map2); + isl_bool isl_map_is_strict_subset( + __isl_keep isl_map *map1, + __isl_keep isl_map *map2); + isl_bool isl_union_map_is_subset( + __isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); + isl_bool isl_union_map_is_strict_subset( + __isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); + +Check whether the first argument is a (strict) subset of the +second argument. + +=item * Order + +Every comparison function returns a negative value if the first +argument is considered smaller than the second, a positive value +if the first argument is considered greater and zero if the two +constraints are considered the same by the comparison criterion. + + #include + int isl_constraint_plain_cmp( + __isl_keep isl_constraint *c1, + __isl_keep isl_constraint *c2); + +This function is useful for sorting Cs. +The order depends on the internal representation of the inputs. +The order is fixed over different calls to the function (assuming +the internal representation of the inputs has not changed), but may +change over different versions of C. + + #include + int isl_constraint_cmp_last_non_zero( + __isl_keep isl_constraint *c1, + __isl_keep isl_constraint *c2); + +This function can be used to sort constraints that live in the same +local space. Constraints that involve ``earlier'' dimensions or +that have a smaller coefficient for the shared latest dimension +are considered smaller than other constraints. +This function only defines a B order. + + #include + int isl_set_plain_cmp(__isl_keep isl_set *set1, + __isl_keep isl_set *set2); + +This function is useful for sorting Cs. +The order depends on the internal representation of the inputs. +The order is fixed over different calls to the function (assuming +the internal representation of the inputs has not changed), but may +change over different versions of C. + + #include + int isl_multi_aff_plain_cmp( + __isl_keep isl_multi_aff *ma1, + __isl_keep isl_multi_aff *ma2); + int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1, + __isl_keep isl_pw_aff *pa2); + +The functions C and +C can be used to sort Cs and +Cs. The order is not strictly defined. +The current order sorts expressions that only involve +earlier dimensions before those that involve later dimensions. + +=back + +=head2 Unary Operations + +=over + +=item * Complement + + __isl_give isl_set *isl_set_complement( + __isl_take isl_set *set); + __isl_give isl_map *isl_map_complement( + __isl_take isl_map *map); + +=item * Inverse map + + #include + __isl_give isl_space *isl_space_reverse( + __isl_take isl_space *space); + + #include + __isl_give isl_basic_map *isl_basic_map_reverse( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_reverse( + __isl_take isl_map *map); + + #include + __isl_give isl_union_map *isl_union_map_reverse( + __isl_take isl_union_map *umap); + +=item * Projection + + #include + __isl_give isl_space *isl_space_domain( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_range( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_params( + __isl_take isl_space *space); + + #include + __isl_give isl_local_space *isl_local_space_domain( + __isl_take isl_local_space *ls); + __isl_give isl_local_space *isl_local_space_range( + __isl_take isl_local_space *ls); + + #include + __isl_give isl_basic_set *isl_basic_set_project_out( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_set *isl_set_project_out(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_map *isl_set_project_onto_map( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned first, + unsigned n); + __isl_give isl_basic_set *isl_basic_set_params( + __isl_take isl_basic_set *bset); + __isl_give isl_set *isl_set_params(__isl_take isl_set *set); + +The function C returns a relation +that projects the input set onto the given set dimensions. + + #include + __isl_give isl_basic_map *isl_basic_map_project_out( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_basic_set *isl_basic_map_domain( + __isl_take isl_basic_map *bmap); + __isl_give isl_basic_set *isl_basic_map_range( + __isl_take isl_basic_map *bmap); + __isl_give isl_set *isl_map_params(__isl_take isl_map *map); + __isl_give isl_set *isl_map_domain( + __isl_take isl_map *bmap); + __isl_give isl_set *isl_map_range( + __isl_take isl_map *map); + + #include + __isl_give isl_union_set *isl_union_set_project_out( + __isl_take isl_union_set *uset, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_set *isl_union_set_params( + __isl_take isl_union_set *uset); + +The function C can only project out +parameters. + + #include + __isl_give isl_union_map *isl_union_map_project_out( + __isl_take isl_union_map *umap, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_set *isl_union_map_params( + __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); + +The function C can only project out +parameters. + + #include + __isl_give isl_aff *isl_aff_project_domain_on_params( + __isl_take isl_aff *aff); + __isl_give isl_pw_aff * + isl_pw_aff_project_domain_on_params( + __isl_take isl_pw_aff *pa); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_project_domain_on_params( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_set *isl_pw_aff_domain( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_set *isl_pw_multi_aff_domain( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_set *isl_multi_pw_aff_domain( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_union_set *isl_union_pw_aff_domain( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_set *isl_union_pw_multi_aff_domain( + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_set * + isl_multi_union_pw_aff_domain( + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_set *isl_pw_aff_params( + __isl_take isl_pw_aff *pwa); + +The function C requires its +input to have at least one set dimension. + + #include + __isl_give isl_qpolynomial * + isl_qpolynomial_project_domain_on_params( + __isl_take isl_qpolynomial *qp); + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_project_domain_on_params( + __isl_take isl_pw_qpolynomial *pwqp); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_project_domain_on_params( + __isl_take isl_pw_qpolynomial_fold *pwf); + __isl_give isl_set *isl_pw_qpolynomial_domain( + __isl_take isl_pw_qpolynomial *pwqp); + __isl_give isl_union_set *isl_union_pw_qpolynomial_fold_domain( + __isl_take isl_union_pw_qpolynomial_fold *upwf); + __isl_give isl_union_set *isl_union_pw_qpolynomial_domain( + __isl_take isl_union_pw_qpolynomial *upwqp); + + #include + __isl_give isl_space *isl_space_domain_map( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_range_map( + __isl_take isl_space *space); + + #include + __isl_give isl_map *isl_set_wrapped_domain_map( + __isl_take isl_set *set); + __isl_give isl_basic_map *isl_basic_map_domain_map( + __isl_take isl_basic_map *bmap); + __isl_give isl_basic_map *isl_basic_map_range_map( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map); + __isl_give isl_map *isl_map_range_map(__isl_take isl_map *map); + + #include + __isl_give isl_union_map *isl_union_map_domain_map( + __isl_take isl_union_map *umap); + __isl_give isl_union_pw_multi_aff * + isl_union_map_domain_map_union_pw_multi_aff( + __isl_take isl_union_map *umap); + __isl_give isl_union_map *isl_union_map_range_map( + __isl_take isl_union_map *umap); + __isl_give isl_union_map * + isl_union_set_wrapped_domain_map( + __isl_take isl_union_set *uset); + +The functions above construct a (basic, regular or union) relation +that maps (a wrapped version of) the input relation to its domain or range. +C maps the input set to the domain +of its wrapped relation. + +=item * Elimination + + __isl_give isl_basic_set *isl_basic_set_eliminate( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_set *isl_set_eliminate( + __isl_take isl_set *set, enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_basic_map *isl_basic_map_eliminate( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_map *isl_map_eliminate( + __isl_take isl_map *map, enum isl_dim_type type, + unsigned first, unsigned n); + +Eliminate the coefficients for the given dimensions from the constraints, +without removing the dimensions. + +=item * Constructing a set from a parameter domain + +A zero-dimensional space or (basic) set can be constructed +on a given parameter domain using the following functions. + + #include + __isl_give isl_space *isl_space_set_from_params( + __isl_take isl_space *space); + + #include + __isl_give isl_basic_set *isl_basic_set_from_params( + __isl_take isl_basic_set *bset); + __isl_give isl_set *isl_set_from_params( + __isl_take isl_set *set); + +=item * Constructing a relation from one or two sets + +Create a relation with the given set(s) as domain and/or range. +If only the domain or the range is specified, then +the range or domain of the created relation is a zero-dimensional +flat anonymous space. + + #include + __isl_give isl_space *isl_space_from_domain( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_from_range( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_map_from_set( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_map_from_domain_and_range( + __isl_take isl_space *domain, + __isl_take isl_space *range); + + #include + __isl_give isl_local_space *isl_local_space_from_domain( + __isl_take isl_local_space *ls); + + #include + __isl_give isl_map *isl_map_from_domain( + __isl_take isl_set *set); + __isl_give isl_map *isl_map_from_range( + __isl_take isl_set *set); + + #include + __isl_give isl_union_map * + isl_union_map_from_domain_and_range( + __isl_take isl_union_set *domain, + __isl_take isl_union_set *range); + + #include + __isl_give isl_multi_val *isl_multi_val_from_range( + __isl_take isl_multi_val *mv); + + #include + __isl_give isl_multi_aff *isl_multi_aff_from_range( + __isl_take isl_multi_aff *ma); + __isl_give isl_pw_aff *isl_pw_aff_from_range( + __isl_take isl_pw_aff *pwa); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_range( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_range( + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain( + __isl_take isl_set *set); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_domain( + __isl_take isl_union_set *uset); + + #include + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_from_range( + __isl_take isl_pw_qpolynomial *pwqp); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_from_range( + __isl_take isl_pw_qpolynomial_fold *pwf); + +=item * Slicing + + #include + __isl_give isl_basic_set *isl_basic_set_fix_si( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_basic_set *isl_basic_set_fix_val( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, + __isl_take isl_val *v); + __isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_set *isl_set_fix_val( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, + __isl_take isl_val *v); + + #include + __isl_give isl_basic_map *isl_basic_map_fix_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_basic_map *isl_basic_map_fix_val( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, + __isl_take isl_val *v); + __isl_give isl_map *isl_map_fix_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_map *isl_map_fix_val( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, + __isl_take isl_val *v); + + #include + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_fix_si( + __isl_take isl_pw_multi_aff *pma, + enum isl_dim_type type, unsigned pos, int value); + + #include + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_fix_val( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned n, + __isl_take isl_val *v); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_fix_val( + __isl_take isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type type, unsigned n, + __isl_take isl_val *v); + +Intersect the set, relation or function domain +with the hyperplane where the given +dimension has the fixed given value. + + #include + __isl_give isl_basic_set * + isl_basic_set_lower_bound_val( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value); + __isl_give isl_basic_set * + isl_basic_set_upper_bound_val( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value); + __isl_give isl_set *isl_set_lower_bound_si( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_set *isl_set_lower_bound_val( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value); + __isl_give isl_set *isl_set_upper_bound_si( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_set *isl_set_upper_bound_val( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value); + + #include + __isl_give isl_basic_map *isl_basic_map_lower_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_basic_map *isl_basic_map_upper_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_map *isl_map_lower_bound_si( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value); + __isl_give isl_map *isl_map_upper_bound_si( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value); + +Intersect the set or relation with the half-space where the given +dimension has a value bounded by the fixed given integer value. + + __isl_give isl_set *isl_set_equate(__isl_take isl_set *set, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + __isl_give isl_basic_map *isl_basic_map_equate( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + __isl_give isl_map *isl_map_equate(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + +Intersect the set or relation with the hyperplane where the given +dimensions are equal to each other. + + __isl_give isl_map *isl_map_oppose(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + +Intersect the relation with the hyperplane where the given +dimensions have opposite values. + + __isl_give isl_map *isl_map_order_le( + __isl_take isl_map *map, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + __isl_give isl_basic_map *isl_basic_map_order_ge( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + __isl_give isl_map *isl_map_order_ge( + __isl_take isl_map *map, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + __isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + __isl_give isl_basic_map *isl_basic_map_order_gt( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + __isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2); + +Intersect the relation with the half-space where the given +dimensions satisfy the given ordering. + + #include + __isl_give isl_union_map *isl_union_map_remove_map_if( + __isl_take isl_union_map *umap, + isl_bool (*fn)(__isl_keep isl_map *map, + void *user), void *user); + +This function calls the callback function once for each +pair of spaces for which there are elements in the input. +If the callback returns C, then all those elements +are removed from the result. The only remaining elements in the output +are then those for which the callback returns C. + +=item * Locus + + #include + __isl_give isl_basic_set *isl_aff_zero_basic_set( + __isl_take isl_aff *aff); + __isl_give isl_basic_set *isl_aff_neg_basic_set( + __isl_take isl_aff *aff); + __isl_give isl_set *isl_pw_aff_pos_set( + __isl_take isl_pw_aff *pa); + __isl_give isl_set *isl_pw_aff_nonneg_set( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_set *isl_pw_aff_zero_set( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_set *isl_pw_aff_non_zero_set( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_union_set * + isl_union_pw_aff_zero_union_set( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_set * + isl_multi_union_pw_aff_zero_union_set( + __isl_take isl_multi_union_pw_aff *mupa); + +The function C returns a basic set +containing those elements in the domain space +of C where C is negative. +The function C returns a set +containing those elements in the domain +of C where C is non-negative. +The function C +returns a union set containing those elements +in the domains of its elements where they are all zero. + +=item * Identity + + __isl_give isl_map *isl_set_identity( + __isl_take isl_set *set); + __isl_give isl_union_map *isl_union_set_identity( + __isl_take isl_union_set *uset); + __isl_give isl_union_pw_multi_aff * + isl_union_set_identity_union_pw_multi_aff( + __isl_take isl_union_set *uset); + +Construct an identity relation on the given (union) set. + +=item * Function Extraction + +A piecewise quasi affine expression that is equal to 1 on a set +and 0 outside the set can be created using the following function. + + #include + __isl_give isl_pw_aff *isl_set_indicator_function( + __isl_take isl_set *set); + +A piecewise multiple quasi affine expression can be extracted +from an C or C, provided the C is a singleton +and the C is single-valued. +In case of a conversion from an C +to an C, these properties need to hold +in each domain space. +A conversion to a C additionally +requires that the input is non-empty and involves only a single +range space. + + #include + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set( + __isl_take isl_set *set); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map( + __isl_take isl_map *map); + + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_union_set( + __isl_take isl_union_set *uset); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_union_map( + __isl_take isl_union_map *umap); + + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_union_map( + __isl_take isl_union_map *umap); + +=item * Deltas + + __isl_give isl_basic_set *isl_basic_map_deltas( + __isl_take isl_basic_map *bmap); + __isl_give isl_set *isl_map_deltas(__isl_take isl_map *map); + __isl_give isl_union_set *isl_union_map_deltas( + __isl_take isl_union_map *umap); + +These functions return a (basic) set containing the differences +between image elements and corresponding domain elements in the input. + + __isl_give isl_basic_map *isl_basic_map_deltas_map( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_deltas_map( + __isl_take isl_map *map); + __isl_give isl_union_map *isl_union_map_deltas_map( + __isl_take isl_union_map *umap); + +The functions above construct a (basic, regular or union) relation +that maps (a wrapped version of) the input relation to its delta set. + +=item * Coalescing + +Simplify the representation of a set, relation or functions by trying +to combine pairs of basic sets or relations into a single +basic set or relation. + + #include + __isl_give isl_set *isl_set_coalesce(__isl_take isl_set *set); + + #include + __isl_give isl_map *isl_map_coalesce(__isl_take isl_map *map); + + #include + __isl_give isl_union_set *isl_union_set_coalesce( + __isl_take isl_union_set *uset); + + #include + __isl_give isl_union_map *isl_union_map_coalesce( + __isl_take isl_union_map *umap); + + #include + __isl_give isl_pw_aff *isl_pw_aff_coalesce( + __isl_take isl_pw_aff *pwqp); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_coalesce( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_coalesce( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_union_pw_aff *isl_union_pw_aff_coalesce( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_coalesce( + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_coalesce( + __isl_take isl_multi_union_pw_aff *aff); + + #include + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_coalesce( + __isl_take isl_pw_qpolynomial_fold *pwf); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_coalesce( + __isl_take isl_union_pw_qpolynomial *upwqp); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_coalesce( + __isl_take isl_union_pw_qpolynomial_fold *upwf); + +One of the methods for combining pairs of basic sets or relations +can result in coefficients that are much larger than those that appear +in the constraints of the input. By default, the coefficients are +not allowed to grow larger, but this can be changed by unsetting +the following option. + + isl_stat isl_options_set_coalesce_bounded_wrapping( + isl_ctx *ctx, int val); + int isl_options_get_coalesce_bounded_wrapping( + isl_ctx *ctx); + +=item * Detecting equalities + + __isl_give isl_basic_set *isl_basic_set_detect_equalities( + __isl_take isl_basic_set *bset); + __isl_give isl_basic_map *isl_basic_map_detect_equalities( + __isl_take isl_basic_map *bmap); + __isl_give isl_set *isl_set_detect_equalities( + __isl_take isl_set *set); + __isl_give isl_map *isl_map_detect_equalities( + __isl_take isl_map *map); + __isl_give isl_union_set *isl_union_set_detect_equalities( + __isl_take isl_union_set *uset); + __isl_give isl_union_map *isl_union_map_detect_equalities( + __isl_take isl_union_map *umap); + +Simplify the representation of a set or relation by detecting implicit +equalities. + +=item * Removing redundant constraints + + #include + __isl_give isl_basic_set *isl_basic_set_remove_redundancies( + __isl_take isl_basic_set *bset); + __isl_give isl_set *isl_set_remove_redundancies( + __isl_take isl_set *set); + + #include + __isl_give isl_union_set * + isl_union_set_remove_redundancies( + __isl_take isl_union_set *uset); + + #include + __isl_give isl_basic_map *isl_basic_map_remove_redundancies( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_remove_redundancies( + __isl_take isl_map *map); + + #include + __isl_give isl_union_map * + isl_union_map_remove_redundancies( + __isl_take isl_union_map *umap); + +=item * Convex hull + + __isl_give isl_basic_set *isl_set_convex_hull( + __isl_take isl_set *set); + __isl_give isl_basic_map *isl_map_convex_hull( + __isl_take isl_map *map); + +If the input set or relation has any existentially quantified +variables, then the result of these operations is currently undefined. + +=item * Simple hull + + #include + __isl_give isl_basic_set * + isl_set_unshifted_simple_hull( + __isl_take isl_set *set); + __isl_give isl_basic_set *isl_set_simple_hull( + __isl_take isl_set *set); + __isl_give isl_basic_set * + isl_set_plain_unshifted_simple_hull( + __isl_take isl_set *set); + __isl_give isl_basic_set * + isl_set_unshifted_simple_hull_from_set_list( + __isl_take isl_set *set, + __isl_take isl_set_list *list); + + #include + __isl_give isl_basic_map * + isl_map_unshifted_simple_hull( + __isl_take isl_map *map); + __isl_give isl_basic_map *isl_map_simple_hull( + __isl_take isl_map *map); + __isl_give isl_basic_map * + isl_map_plain_unshifted_simple_hull( + __isl_take isl_map *map); + __isl_give isl_basic_map * + isl_map_unshifted_simple_hull_from_map_list( + __isl_take isl_map *map, + __isl_take isl_map_list *list); + + #include + __isl_give isl_union_map *isl_union_map_simple_hull( + __isl_take isl_union_map *umap); + +These functions compute a single basic set or relation +that contains the whole input set or relation. +In particular, the output is described by translates +of the constraints describing the basic sets or relations in the input. +In case of C, only the original +constraints are used, without any translation. +In case of C and +C, the result is described +by original constraints that are obviously satisfied +by the entire input set or relation. +In case of C and +C, the +constraints are taken from the elements of the second argument. + +=begin latex + +(See \autoref{s:simple hull}.) + +=end latex + +=item * Affine hull + + __isl_give isl_basic_set *isl_basic_set_affine_hull( + __isl_take isl_basic_set *bset); + __isl_give isl_basic_set *isl_set_affine_hull( + __isl_take isl_set *set); + __isl_give isl_union_set *isl_union_set_affine_hull( + __isl_take isl_union_set *uset); + __isl_give isl_basic_map *isl_basic_map_affine_hull( + __isl_take isl_basic_map *bmap); + __isl_give isl_basic_map *isl_map_affine_hull( + __isl_take isl_map *map); + __isl_give isl_union_map *isl_union_map_affine_hull( + __isl_take isl_union_map *umap); + +In case of union sets and relations, the affine hull is computed +per space. + +=item * Polyhedral hull + + __isl_give isl_basic_set *isl_set_polyhedral_hull( + __isl_take isl_set *set); + __isl_give isl_basic_map *isl_map_polyhedral_hull( + __isl_take isl_map *map); + __isl_give isl_union_set *isl_union_set_polyhedral_hull( + __isl_take isl_union_set *uset); + __isl_give isl_union_map *isl_union_map_polyhedral_hull( + __isl_take isl_union_map *umap); + +These functions compute a single basic set or relation +not involving any existentially quantified variables +that contains the whole input set or relation. +In case of union sets and relations, the polyhedral hull is computed +per space. + +=item * Other approximations + + #include + __isl_give isl_basic_set * + isl_basic_set_drop_constraints_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_basic_set * + isl_basic_set_drop_constraints_not_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_set * + isl_set_drop_constraints_involving_dims( + __isl_take isl_set *set, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_set * + isl_set_drop_constraints_not_involving_dims( + __isl_take isl_set *set, + enum isl_dim_type type, + unsigned first, unsigned n); + + #include + __isl_give isl_basic_map * + isl_basic_map_drop_constraints_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_basic_map * + isl_basic_map_drop_constraints_not_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_map * + isl_map_drop_constraints_involving_dims( + __isl_take isl_map *map, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_map * + isl_map_drop_constraints_not_involving_dims( + __isl_take isl_map *map, + enum isl_dim_type type, + unsigned first, unsigned n); + +These functions drop any constraints (not) involving the specified dimensions. +Note that the result depends on the representation of the input. + + #include + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_to_polynomial( + __isl_take isl_pw_qpolynomial *pwqp, int sign); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_to_polynomial( + __isl_take isl_union_pw_qpolynomial *upwqp, int sign); + +Approximate each quasipolynomial by a polynomial. If C is positive, +the polynomial will be an overapproximation. If C is negative, +it will be an underapproximation. If C is zero, the approximation +will lie somewhere in between. + +=item * Feasibility + + __isl_give isl_basic_set *isl_basic_set_sample( + __isl_take isl_basic_set *bset); + __isl_give isl_basic_set *isl_set_sample( + __isl_take isl_set *set); + __isl_give isl_basic_map *isl_basic_map_sample( + __isl_take isl_basic_map *bmap); + __isl_give isl_basic_map *isl_map_sample( + __isl_take isl_map *map); + +If the input (basic) set or relation is non-empty, then return +a singleton subset of the input. Otherwise, return an empty set. + +=item * Optimization + + #include + __isl_give isl_val *isl_basic_set_max_val( + __isl_keep isl_basic_set *bset, + __isl_keep isl_aff *obj); + __isl_give isl_val *isl_set_min_val( + __isl_keep isl_set *set, + __isl_keep isl_aff *obj); + __isl_give isl_val *isl_set_max_val( + __isl_keep isl_set *set, + __isl_keep isl_aff *obj); + __isl_give isl_multi_val * + isl_union_set_min_multi_union_pw_aff( + __isl_keep isl_union_set *set, + __isl_keep isl_multi_union_pw_aff *obj); + +Compute the minimum or maximum of the integer affine expression C +over the points in C, returning the result in C. +The result is C in case of an error, the optimal value in case +there is one, negative infinity or infinity if the problem is unbounded and +NaN if the problem is empty. + +=item * Parametric optimization + + __isl_give isl_pw_aff *isl_set_dim_min( + __isl_take isl_set *set, int pos); + __isl_give isl_pw_aff *isl_set_dim_max( + __isl_take isl_set *set, int pos); + __isl_give isl_pw_aff *isl_map_dim_min( + __isl_take isl_map *map, int pos); + __isl_give isl_pw_aff *isl_map_dim_max( + __isl_take isl_map *map, int pos); + +Compute the minimum or maximum of the given set or output dimension +as a function of the parameters (and input dimensions), but independently +of the other set or output dimensions. +For lexicographic optimization, see L<"Lexicographic Optimization">. + +=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. + + #include + __isl_give isl_basic_set *isl_basic_set_coefficients( + __isl_take isl_basic_set *bset); + __isl_give isl_basic_set_list * + isl_basic_set_list_coefficients( + __isl_take isl_basic_set_list *list); + __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_fixed_power_val( + __isl_take isl_map *map, + __isl_take isl_val *exp); + __isl_give isl_union_map * + isl_union_map_fixed_power_val( + __isl_take isl_union_map *umap, + __isl_take isl_val *exp); + +Compute the given power of C, where C is assumed to be non-zero. +If the exponent C is negative, then the -C th power of the inverse +of C is computed. + + __isl_give isl_map *isl_map_power(__isl_take isl_map *map, + int *exact); + __isl_give isl_union_map *isl_union_map_power( + __isl_take isl_union_map *umap, int *exact); + +Compute a parametric representation for all positive powers I of C. +The result maps I to a nested relation corresponding to the +Ith power of C. +The result may be an overapproximation. If the result is known to be exact, +then C<*exact> is set to C<1>. + +=item * Transitive closure + + __isl_give isl_map *isl_map_transitive_closure( + __isl_take isl_map *map, int *exact); + __isl_give isl_union_map *isl_union_map_transitive_closure( + __isl_take isl_union_map *umap, int *exact); + +Compute the transitive closure of C. +The result may be an overapproximation. If the result is known to be exact, +then C<*exact> is set to C<1>. + +=item * Reaching path lengths + + __isl_give isl_map *isl_map_reaching_path_lengths( + __isl_take isl_map *map, int *exact); + +Compute a relation that maps each element in the range of C +to the lengths of all paths composed of edges in C that +end up in the given element. +The result may be an overapproximation. If the result is known to be exact, +then C<*exact> is set to C<1>. +To compute the I path length, the resulting relation +should be postprocessed by C. +In particular, if the input relation is a dependence relation +(mapping sources to sinks), then the maximal path length corresponds +to the free schedule. +Note, however, that C expects the maximum to be +finite, so if the path lengths are unbounded (possibly due to +the overapproximation), then you will get an error message. + +=item * Wrapping + + #include + __isl_give isl_space *isl_space_wrap( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_unwrap( + __isl_take isl_space *space); + + #include + __isl_give isl_local_space *isl_local_space_wrap( + __isl_take isl_local_space *ls); + + #include + __isl_give isl_basic_map *isl_basic_set_unwrap( + __isl_take isl_basic_set *bset); + __isl_give isl_map *isl_set_unwrap( + __isl_take isl_set *set); + + #include + __isl_give isl_basic_set *isl_basic_map_wrap( + __isl_take isl_basic_map *bmap); + __isl_give isl_set *isl_map_wrap( + __isl_take isl_map *map); + + #include + __isl_give isl_union_map *isl_union_set_unwrap( + __isl_take isl_union_set *uset); + + #include + __isl_give isl_union_set *isl_union_map_wrap( + __isl_take isl_union_map *umap); + +The input to C should +be the space of a set, while that of +C should be the space of a relation. +Conversely, the output of C is the space +of a relation, while that of C is the space of a set. + +=item * Flattening + +Remove any internal structure of domain (and range) of the given +set or relation. If there is any such internal structure in the input, +then the name of the space is also removed. + + #include + __isl_give isl_space *isl_space_flatten_domain( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_flatten_range( + __isl_take isl_space *space); + + #include + __isl_give isl_local_space * + isl_local_space_flatten_domain( + __isl_take isl_local_space *ls); + __isl_give isl_local_space * + isl_local_space_flatten_range( + __isl_take isl_local_space *ls); + + #include + __isl_give isl_basic_set *isl_basic_set_flatten( + __isl_take isl_basic_set *bset); + __isl_give isl_set *isl_set_flatten( + __isl_take isl_set *set); + + #include + __isl_give isl_basic_map *isl_basic_map_flatten_domain( + __isl_take isl_basic_map *bmap); + __isl_give isl_basic_map *isl_basic_map_flatten_range( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_flatten_range( + __isl_take isl_map *map); + __isl_give isl_map *isl_map_flatten_domain( + __isl_take isl_map *map); + __isl_give isl_basic_map *isl_basic_map_flatten( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_flatten( + __isl_take isl_map *map); + + #include + __isl_give isl_multi_val *isl_multi_val_flatten_range( + __isl_take isl_multi_val *mv); + + #include + __isl_give isl_multi_aff *isl_multi_aff_flatten_domain( + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_aff *isl_multi_aff_flatten_range( + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_flatten_range( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_flatten_range( + __isl_take isl_multi_union_pw_aff *mupa); + + #include + __isl_give isl_map *isl_set_flatten_map( + __isl_take isl_set *set); + +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. + + #include + __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); + +Given a local space that contains the existentially quantified +variables of a set, a basic relation that, when applied to +a basic set, has essentially the same effect as C, +can be constructed using the following function. + + #include + __isl_give isl_basic_map *isl_local_space_lifting( + __isl_take isl_local_space *ls); + + #include + __isl_give isl_multi_aff *isl_multi_aff_lift( + __isl_take isl_multi_aff *maff, + __isl_give isl_local_space **ls); + +If the C argument of C is not C, +then it is assigned the local space that lies at the basis of +the lifting applied. + +=item * Internal Product + + #include + __isl_give isl_space *isl_space_zip( + __isl_take isl_space *space); + + #include + __isl_give isl_basic_map *isl_basic_map_zip( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_zip( + __isl_take isl_map *map); + + #include + __isl_give isl_union_map *isl_union_map_zip( + __isl_take isl_union_map *umap); + +Given a relation with nested relations for domain and range, +interchange the range of the domain with the domain of the range. + +=item * Currying + + #include + __isl_give isl_space *isl_space_curry( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_uncurry( + __isl_take isl_space *space); + + #include + __isl_give isl_basic_map *isl_basic_map_curry( + __isl_take isl_basic_map *bmap); + __isl_give isl_basic_map *isl_basic_map_uncurry( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_curry( + __isl_take isl_map *map); + __isl_give isl_map *isl_map_uncurry( + __isl_take isl_map *map); + + #include + __isl_give isl_union_map *isl_union_map_curry( + __isl_take isl_union_map *umap); + __isl_give isl_union_map *isl_union_map_uncurry( + __isl_take isl_union_map *umap); + +Given a relation with a nested relation for domain, +the C functions +move the range of the nested relation out of the domain +and use it as the domain of a nested relation in the range, +with the original range as range of this nested relation. +The C functions perform the inverse operation. + + #include + __isl_give isl_space *isl_space_range_curry( + __isl_take isl_space *space); + + #include + __isl_give isl_map *isl_map_range_curry( + __isl_take isl_map *map); + + #include + __isl_give isl_union_map *isl_union_map_range_curry( + __isl_take isl_union_map *umap); + +These functions apply the currying to the relation that +is nested inside the range of the input. + +=item * Aligning parameters + +Change the order of the parameters of the given set, relation +or function +such that the first parameters match those of C. +This may involve the introduction of extra parameters. +All parameters need to be named. + + #include + __isl_give isl_space *isl_space_align_params( + __isl_take isl_space *space1, + __isl_take isl_space *space2) + + #include + __isl_give isl_basic_set *isl_basic_set_align_params( + __isl_take isl_basic_set *bset, + __isl_take isl_space *model); + __isl_give isl_set *isl_set_align_params( + __isl_take isl_set *set, + __isl_take isl_space *model); + + #include + __isl_give isl_basic_map *isl_basic_map_align_params( + __isl_take isl_basic_map *bmap, + __isl_take isl_space *model); + __isl_give isl_map *isl_map_align_params( + __isl_take isl_map *map, + __isl_take isl_space *model); + + #include + __isl_give isl_multi_val *isl_multi_val_align_params( + __isl_take isl_multi_val *mv, + __isl_take isl_space *model); + + #include + __isl_give isl_aff *isl_aff_align_params( + __isl_take isl_aff *aff, + __isl_take isl_space *model); + __isl_give isl_multi_aff *isl_multi_aff_align_params( + __isl_take isl_multi_aff *multi, + __isl_take isl_space *model); + __isl_give isl_pw_aff *isl_pw_aff_align_params( + __isl_take isl_pw_aff *pwaff, + __isl_take isl_space *model); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_align_params( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_space *model); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_align_params( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_space *model); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_align_params( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_space *model); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_align_params( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_space *model); + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_align_params( + __isl_take isl_qpolynomial *qp, + __isl_take isl_space *model); + +=item * Unary Arithmetic Operations + + #include + __isl_give isl_set *isl_set_neg( + __isl_take isl_set *set); + #include + __isl_give isl_map *isl_map_neg( + __isl_take isl_map *map); + +C constructs a set containing the opposites of +the elements in its argument. +The domain of the result of C is the same +as the domain of its argument. The corresponding range +elements are the opposites of the corresponding range +elements in the argument. + + #include + __isl_give isl_multi_val *isl_multi_val_neg( + __isl_take isl_multi_val *mv); + + #include + __isl_give isl_aff *isl_aff_neg( + __isl_take isl_aff *aff); + __isl_give isl_multi_aff *isl_multi_aff_neg( + __isl_take isl_multi_aff *ma); + __isl_give isl_pw_aff *isl_pw_aff_neg( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_neg( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_neg( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_union_pw_aff *isl_union_pw_aff_neg( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_neg( + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_neg( + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_aff *isl_aff_ceil( + __isl_take isl_aff *aff); + __isl_give isl_pw_aff *isl_pw_aff_ceil( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_aff *isl_aff_floor( + __isl_take isl_aff *aff); + __isl_give isl_multi_aff *isl_multi_aff_floor( + __isl_take isl_multi_aff *ma); + __isl_give isl_pw_aff *isl_pw_aff_floor( + __isl_take isl_pw_aff *pwaff); + __isl_give isl_union_pw_aff *isl_union_pw_aff_floor( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_floor( + __isl_take isl_multi_union_pw_aff *mupa); + + #include + __isl_give isl_pw_aff *isl_pw_aff_list_min( + __isl_take isl_pw_aff_list *list); + __isl_give isl_pw_aff *isl_pw_aff_list_max( + __isl_take isl_pw_aff_list *list); + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_neg( + __isl_take isl_qpolynomial *qp); + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_neg( + __isl_take isl_pw_qpolynomial *pwqp); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_neg( + __isl_take isl_union_pw_qpolynomial *upwqp); + __isl_give isl_qpolynomial *isl_qpolynomial_pow( + __isl_take isl_qpolynomial *qp, + unsigned exponent); + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_pow( + __isl_take isl_pw_qpolynomial *pwqp, + unsigned exponent); + +=item * Evaluation + +The following functions evaluate a function in a point. + + #include + __isl_give isl_val *isl_pw_qpolynomial_eval( + __isl_take isl_pw_qpolynomial *pwqp, + __isl_take isl_point *pnt); + __isl_give isl_val *isl_pw_qpolynomial_fold_eval( + __isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_point *pnt); + __isl_give isl_val *isl_union_pw_qpolynomial_eval( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_point *pnt); + __isl_give isl_val *isl_union_pw_qpolynomial_fold_eval( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_point *pnt); + +=item * Dimension manipulation + +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 functions below can be useful +to add new parameters, assuming +C and C +are not sufficient. + + #include + __isl_give isl_space *isl_space_add_dims( + __isl_take isl_space *space, + enum isl_dim_type type, unsigned n); + __isl_give isl_space *isl_space_insert_dims( + __isl_take isl_space *space, + enum isl_dim_type type, unsigned pos, unsigned n); + __isl_give isl_space *isl_space_drop_dims( + __isl_take isl_space *space, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_space *isl_space_move_dims( + __isl_take isl_space *space, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + + #include + __isl_give isl_local_space *isl_local_space_add_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned n); + __isl_give isl_local_space *isl_local_space_insert_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_local_space *isl_local_space_drop_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned first, unsigned n); + + #include + __isl_give isl_basic_set *isl_basic_set_add_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned n); + __isl_give isl_set *isl_set_add_dims( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned n); + __isl_give isl_basic_set *isl_basic_set_insert_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, + unsigned n); + __isl_give isl_set *isl_set_insert_dims( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, unsigned n); + __isl_give isl_basic_set *isl_basic_set_move_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + __isl_give isl_set *isl_set_move_dims( + __isl_take isl_set *set, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + + #include + __isl_give isl_basic_map *isl_basic_map_add_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned n); + __isl_give isl_map *isl_map_add_dims( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned n); + __isl_give isl_basic_map *isl_basic_map_insert_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, + unsigned n); + __isl_give isl_map *isl_map_insert_dims( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, unsigned n); + __isl_give isl_basic_map *isl_basic_map_move_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + __isl_give isl_map *isl_map_move_dims( + __isl_take isl_map *map, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + + #include + __isl_give isl_multi_val *isl_multi_val_insert_dims( + __isl_take isl_multi_val *mv, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_multi_val *isl_multi_val_add_dims( + __isl_take isl_multi_val *mv, + enum isl_dim_type type, unsigned n); + __isl_give isl_multi_val *isl_multi_val_drop_dims( + __isl_take isl_multi_val *mv, + enum isl_dim_type type, unsigned first, unsigned n); + + #include + __isl_give isl_aff *isl_aff_insert_dims( + __isl_take isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_multi_aff *isl_multi_aff_insert_dims( + __isl_take isl_multi_aff *ma, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_pw_aff *isl_pw_aff_insert_dims( + __isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_insert_dims( + __isl_take isl_multi_pw_aff *mpa, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_aff *isl_aff_add_dims( + __isl_take isl_aff *aff, + enum isl_dim_type type, unsigned n); + __isl_give isl_multi_aff *isl_multi_aff_add_dims( + __isl_take isl_multi_aff *ma, + enum isl_dim_type type, unsigned n); + __isl_give isl_pw_aff *isl_pw_aff_add_dims( + __isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned n); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_add_dims( + __isl_take isl_multi_pw_aff *mpa, + enum isl_dim_type type, unsigned n); + __isl_give isl_aff *isl_aff_drop_dims( + __isl_take isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_multi_aff *isl_multi_aff_drop_dims( + __isl_take isl_multi_aff *maff, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_pw_aff *isl_pw_aff_drop_dims( + __isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_drop_dims( + __isl_take isl_pw_multi_aff *pma, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_union_pw_aff *isl_union_pw_aff_drop_dims( + __isl_take isl_union_pw_aff *upa, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_drop_dims( + __isl_take isl_union_pw_multi_aff *upma, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_drop_dims( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, unsigned first, + unsigned n); + __isl_give isl_aff *isl_aff_move_dims( + __isl_take isl_aff *aff, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + __isl_give isl_multi_aff *isl_multi_aff_move_dims( + __isl_take isl_multi_aff *ma, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + __isl_give isl_pw_aff *isl_pw_aff_move_dims( + __isl_take isl_pw_aff *pa, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_move_dims( + __isl_take isl_multi_pw_aff *pma, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, + unsigned n); + + #include + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_drop_dims( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_drop_dims( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, + unsigned first, unsigned n); + +The operations on union expressions can only manipulate parameters. + +=back + +=head2 Binary Operations + +The two arguments of a binary operation not only need to live +in the same C, they currently also need to have +the same (number of) parameters. + +=head3 Basic Operations + +=over + +=item * Intersection + + #include + __isl_give isl_local_space *isl_local_space_intersect( + __isl_take isl_local_space *ls1, + __isl_take isl_local_space *ls2); + + #include + __isl_give isl_basic_set *isl_basic_set_intersect_params( + __isl_take isl_basic_set *bset1, + __isl_take isl_basic_set *bset2); + __isl_give isl_basic_set *isl_basic_set_intersect( + __isl_take isl_basic_set *bset1, + __isl_take isl_basic_set *bset2); + __isl_give isl_basic_set *isl_basic_set_list_intersect( + __isl_take struct isl_basic_set_list *list); + __isl_give isl_set *isl_set_intersect_params( + __isl_take isl_set *set, + __isl_take isl_set *params); + __isl_give isl_set *isl_set_intersect( + __isl_take isl_set *set1, + __isl_take isl_set *set2); + + #include + __isl_give isl_basic_map *isl_basic_map_intersect_domain( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *bset); + __isl_give isl_basic_map *isl_basic_map_intersect_range( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *bset); + __isl_give isl_basic_map *isl_basic_map_intersect( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_basic_map *isl_basic_map_list_intersect( + __isl_take isl_basic_map_list *list); + __isl_give isl_map *isl_map_intersect_params( + __isl_take isl_map *map, + __isl_take isl_set *params); + __isl_give isl_map *isl_map_intersect_domain( + __isl_take isl_map *map, + __isl_take isl_set *set); + __isl_give isl_map *isl_map_intersect_range( + __isl_take isl_map *map, + __isl_take isl_set *set); + __isl_give isl_map *isl_map_intersect( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + __isl_give isl_map * + isl_map_intersect_domain_factor_range( + __isl_take isl_map *map, + __isl_take isl_map *factor); + __isl_give isl_map * + isl_map_intersect_range_factor_range( + __isl_take isl_map *map, + __isl_take isl_map *factor); + + #include + __isl_give isl_union_set *isl_union_set_intersect_params( + __isl_take isl_union_set *uset, + __isl_take isl_set *set); + __isl_give isl_union_set *isl_union_set_intersect( + __isl_take isl_union_set *uset1, + __isl_take isl_union_set *uset2); + + #include + __isl_give isl_union_map *isl_union_map_intersect_params( + __isl_take isl_union_map *umap, + __isl_take isl_set *set); + __isl_give isl_union_map *isl_union_map_intersect_domain( + __isl_take isl_union_map *umap, + __isl_take isl_union_set *uset); + __isl_give isl_union_map *isl_union_map_intersect_range( + __isl_take isl_union_map *umap, + __isl_take isl_union_set *uset); + __isl_give isl_union_map *isl_union_map_intersect( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + __isl_give isl_union_map * + isl_union_map_intersect_range_factor_range( + __isl_take isl_union_map *umap, + __isl_take isl_union_map *factor); + + #include + __isl_give isl_pw_aff *isl_pw_aff_intersect_domain( + __isl_take isl_pw_aff *pa, + __isl_take isl_set *set); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_intersect_domain( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_set *domain); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_domain( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_set *set); + __isl_give isl_union_pw_aff *isl_union_pw_aff_intersect_domain( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_set *uset); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_intersect_domain( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_union_set *uset); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_intersect_domain( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_set *uset); + __isl_give isl_pw_aff *isl_pw_aff_intersect_params( + __isl_take isl_pw_aff *pa, + __isl_take isl_set *set); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_intersect_params( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_set *set); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_params( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_set *set); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_intersect_params( + __isl_take isl_union_pw_aff *upa, + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_intersect_params( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_set *set); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_intersect_params( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_set *params); + isl_multi_union_pw_aff_intersect_range( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_set *set); + + #include + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_intersect_domain( + __isl_take isl_pw_qpolynomial *pwpq, + __isl_take isl_set *set); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_intersect_domain( + __isl_take isl_union_pw_qpolynomial *upwpq, + __isl_take isl_union_set *uset); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_intersect_domain( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_set *uset); + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_intersect_params( + __isl_take isl_pw_qpolynomial *pwpq, + __isl_take isl_set *set); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_intersect_params( + __isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_set *set); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_intersect_params( + __isl_take isl_union_pw_qpolynomial *upwpq, + __isl_take isl_set *set); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_intersect_params( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_set *set); + +The second argument to the C<_params> functions needs to be +a parametric (basic) set. For the other functions, a parametric set +for either argument is only allowed if the other argument is +a parametric set as well. +The list passed to C needs to have +at least one element and all elements need to live in the same space. +The function C +restricts the input function to those shared domain elements +that map to the specified range. + +=item * Union + + #include + __isl_give isl_set *isl_basic_set_union( + __isl_take isl_basic_set *bset1, + __isl_take isl_basic_set *bset2); + __isl_give isl_set *isl_set_union( + __isl_take isl_set *set1, + __isl_take isl_set *set2); + __isl_give isl_set *isl_set_list_union( + __isl_take isl_set_list *list); + + #include + __isl_give isl_map *isl_basic_map_union( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_map *isl_map_union( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + + #include + __isl_give isl_union_set *isl_union_set_union( + __isl_take isl_union_set *uset1, + __isl_take isl_union_set *uset2); + __isl_give isl_union_set *isl_union_set_list_union( + __isl_take isl_union_set_list *list); + + #include + __isl_give isl_union_map *isl_union_map_union( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + +The list passed to C needs to have +at least one element and all elements need to live in the same space. + +=item * Set difference + + #include + __isl_give isl_set *isl_set_subtract( + __isl_take isl_set *set1, + __isl_take isl_set *set2); + + #include + __isl_give isl_map *isl_map_subtract( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + __isl_give isl_map *isl_map_subtract_domain( + __isl_take isl_map *map, + __isl_take isl_set *dom); + __isl_give isl_map *isl_map_subtract_range( + __isl_take isl_map *map, + __isl_take isl_set *dom); + + #include + __isl_give isl_union_set *isl_union_set_subtract( + __isl_take isl_union_set *uset1, + __isl_take isl_union_set *uset2); + + #include + __isl_give isl_union_map *isl_union_map_subtract( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + __isl_give isl_union_map *isl_union_map_subtract_domain( + __isl_take isl_union_map *umap, + __isl_take isl_union_set *dom); + __isl_give isl_union_map *isl_union_map_subtract_range( + __isl_take isl_union_map *umap, + __isl_take isl_union_set *dom); + + #include + __isl_give isl_pw_aff *isl_pw_aff_subtract_domain( + __isl_take isl_pw_aff *pa, + __isl_take isl_set *set); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_subtract_domain( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_set *set); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_subtract_domain( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_set *uset); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_subtract_domain( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_set *set); + + #include + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_subtract_domain( + __isl_take isl_pw_qpolynomial *pwpq, + __isl_take isl_set *set); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_subtract_domain( + __isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_set *set); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_subtract_domain( + __isl_take isl_union_pw_qpolynomial *upwpq, + __isl_take isl_union_set *uset); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_subtract_domain( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_set *uset); + +=item * Application + + #include + __isl_give isl_space *isl_space_join( + __isl_take isl_space *left, + __isl_take isl_space *right); + + #include + __isl_give isl_basic_set *isl_basic_set_apply( + __isl_take isl_basic_set *bset, + __isl_take isl_basic_map *bmap); + __isl_give isl_set *isl_set_apply( + __isl_take isl_set *set, + __isl_take isl_map *map); + __isl_give isl_union_set *isl_union_set_apply( + __isl_take isl_union_set *uset, + __isl_take isl_union_map *umap); + __isl_give isl_basic_map *isl_basic_map_apply_domain( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_basic_map *isl_basic_map_apply_range( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_map *isl_map_apply_domain( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + __isl_give isl_map *isl_map_apply_range( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + + #include + __isl_give isl_union_map *isl_union_map_apply_domain( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + __isl_give isl_union_map *isl_union_map_apply_range( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + + #include + __isl_give isl_union_pw_aff * + isl_multi_union_pw_aff_apply_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_aff *aff); + __isl_give isl_union_pw_aff * + isl_multi_union_pw_aff_apply_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_pw_aff *pa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_apply_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_apply_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_pw_multi_aff *pma); + +The result of C is defined +over the shared domain of the elements of the input. The dimension is +required to be greater than zero. +The C argument of +C is allowed to be zero-dimensional, +but only if the range of the C argument +is also zero-dimensional. +Similarly for C. + + #include + __isl_give isl_pw_qpolynomial_fold * + isl_set_apply_pw_qpolynomial_fold( + __isl_take isl_set *set, + __isl_take isl_pw_qpolynomial_fold *pwf, + int *tight); + __isl_give isl_pw_qpolynomial_fold * + isl_map_apply_pw_qpolynomial_fold( + __isl_take isl_map *map, + __isl_take isl_pw_qpolynomial_fold *pwf, + int *tight); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_set_apply_union_pw_qpolynomial_fold( + __isl_take isl_union_set *uset, + __isl_take isl_union_pw_qpolynomial_fold *upwf, + int *tight); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_map_apply_union_pw_qpolynomial_fold( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_qpolynomial_fold *upwf, + int *tight); + +The functions taking a map +compose the given map with the given piecewise quasipolynomial reduction. +That is, compute a bound (of the same type as C or C itself) +over all elements in the intersection of the range of the map +and the domain of the piecewise quasipolynomial reduction +as a function of an element in the domain of the map. +The functions taking a set compute a bound over all elements in the +intersection of the set and the domain of the +piecewise quasipolynomial reduction. + +=item * Preimage + + #include + __isl_give isl_basic_set * + isl_basic_set_preimage_multi_aff( + __isl_take isl_basic_set *bset, + __isl_take isl_multi_aff *ma); + __isl_give isl_set *isl_set_preimage_multi_aff( + __isl_take isl_set *set, + __isl_take isl_multi_aff *ma); + __isl_give isl_set *isl_set_preimage_pw_multi_aff( + __isl_take isl_set *set, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_set *isl_set_preimage_multi_pw_aff( + __isl_take isl_set *set, + __isl_take isl_multi_pw_aff *mpa); + + #include + __isl_give isl_union_set * + isl_union_set_preimage_multi_aff( + __isl_take isl_union_set *uset, + __isl_take isl_multi_aff *ma); + __isl_give isl_union_set * + isl_union_set_preimage_pw_multi_aff( + __isl_take isl_union_set *uset, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_union_set * + isl_union_set_preimage_union_pw_multi_aff( + __isl_take isl_union_set *uset, + __isl_take isl_union_pw_multi_aff *upma); + + #include + __isl_give isl_basic_map * + isl_basic_map_preimage_domain_multi_aff( + __isl_take isl_basic_map *bmap, + __isl_take isl_multi_aff *ma); + __isl_give isl_map *isl_map_preimage_domain_multi_aff( + __isl_take isl_map *map, + __isl_take isl_multi_aff *ma); + __isl_give isl_map *isl_map_preimage_range_multi_aff( + __isl_take isl_map *map, + __isl_take isl_multi_aff *ma); + __isl_give isl_map * + isl_map_preimage_domain_pw_multi_aff( + __isl_take isl_map *map, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_map * + isl_map_preimage_range_pw_multi_aff( + __isl_take isl_map *map, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_map * + isl_map_preimage_domain_multi_pw_aff( + __isl_take isl_map *map, + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_basic_map * + isl_basic_map_preimage_range_multi_aff( + __isl_take isl_basic_map *bmap, + __isl_take isl_multi_aff *ma); + + #include + __isl_give isl_union_map * + isl_union_map_preimage_domain_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_aff *ma); + __isl_give isl_union_map * + isl_union_map_preimage_range_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_aff *ma); + __isl_give isl_union_map * + isl_union_map_preimage_domain_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_union_map * + isl_union_map_preimage_range_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_union_map * + isl_union_map_preimage_domain_union_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_map * + isl_union_map_preimage_range_union_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_multi_aff *upma); + +These functions compute the preimage of the given set or map domain/range under +the given function. In other words, the expression is plugged +into the set description or into the domain/range of the map. + +=item * Pullback + + #include + __isl_give isl_aff *isl_aff_pullback_aff( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_aff *isl_aff_pullback_multi_aff( + __isl_take isl_aff *aff, + __isl_take isl_multi_aff *ma); + __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_aff( + __isl_take isl_pw_aff *pa, + __isl_take isl_multi_aff *ma); + __isl_give isl_pw_aff *isl_pw_aff_pullback_pw_multi_aff( + __isl_take isl_pw_aff *pa, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff( + __isl_take isl_pw_aff *pa, + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_pullback_multi_aff( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_pullback_multi_aff( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_multi_aff *ma); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_pullback_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_pullback_pw_multi_aff( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_pullback_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_pw_multi_aff *upma); + +These functions precompose the first expression by the second function. +In other words, the second function is plugged +into the first expression. + +=item * Locus + + #include + __isl_give isl_basic_set *isl_aff_eq_basic_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_set *isl_aff_eq_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_set *isl_aff_ne_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_basic_set *isl_aff_le_basic_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_set *isl_aff_le_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_basic_set *isl_aff_lt_basic_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_set *isl_aff_lt_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_basic_set *isl_aff_ge_basic_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_set *isl_aff_ge_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_basic_set *isl_aff_gt_basic_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_set *isl_aff_gt_set( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_set *isl_pw_aff_eq_set( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_set *isl_pw_aff_ne_set( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_set *isl_pw_aff_le_set( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_set *isl_pw_aff_lt_set( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_set *isl_pw_aff_ge_set( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_set *isl_pw_aff_gt_set( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + + __isl_give isl_set *isl_multi_aff_lex_le_set( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + __isl_give isl_set *isl_multi_aff_lex_lt_set( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + __isl_give isl_set *isl_multi_aff_lex_ge_set( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + __isl_give isl_set *isl_multi_aff_lex_gt_set( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + + __isl_give isl_set *isl_pw_aff_list_eq_set( + __isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); + __isl_give isl_set *isl_pw_aff_list_ne_set( + __isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); + __isl_give isl_set *isl_pw_aff_list_le_set( + __isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); + __isl_give isl_set *isl_pw_aff_list_lt_set( + __isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); + __isl_give isl_set *isl_pw_aff_list_ge_set( + __isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); + __isl_give isl_set *isl_pw_aff_list_gt_set( + __isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); + +The function C returns a basic set +containing those elements in the shared space +of C and C where C is greater than or equal to C. +The function C returns a set +containing those elements in the shared domain +of C and C where C is +greater than or equal to C. +The function C returns a set +containing those elements in the shared domain space +where C is lexicographically smaller than or +equal to C. +The functions operating on C apply the corresponding +C function to each pair of elements in the two lists. + + #include + __isl_give isl_map *isl_pw_aff_eq_map( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + __isl_give isl_map *isl_pw_aff_lt_map( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + __isl_give isl_map *isl_pw_aff_gt_map( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + + __isl_give isl_map *isl_multi_pw_aff_eq_map( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_map *isl_multi_pw_aff_lex_lt_map( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_map *isl_multi_pw_aff_lex_gt_map( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + +These functions return a map between domain elements of the arguments +where the function values satisfy the given relation. + + #include + __isl_give isl_union_map * + isl_union_map_eq_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_union_map * + isl_union_map_lex_lt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_union_map * + isl_union_map_lex_gt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); + +These functions select the subset of elements in the union map +that have an equal or lexicographically smaller function value. + +=item * Cartesian Product + + #include + __isl_give isl_space *isl_space_product( + __isl_take isl_space *space1, + __isl_take isl_space *space2); + __isl_give isl_space *isl_space_domain_product( + __isl_take isl_space *space1, + __isl_take isl_space *space2); + __isl_give isl_space *isl_space_range_product( + __isl_take isl_space *space1, + __isl_take isl_space *space2); + +The functions +C, C +and C take pairs or relation spaces and +produce a single relations space, where either the domain, the range +or both domain and range are wrapped spaces of relations between +the domains and/or ranges of the input spaces. +If the product is only constructed over the domain or the range +then the ranges or the domains of the inputs should be the same. +The function C also accepts a pair of set spaces, +in which case it returns a wrapped space of a relation between the +two input spaces. + + #include + __isl_give isl_set *isl_set_product( + __isl_take isl_set *set1, + __isl_take isl_set *set2); + + #include + __isl_give isl_basic_map *isl_basic_map_domain_product( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_basic_map *isl_basic_map_range_product( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_basic_map *isl_basic_map_product( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_map *isl_map_domain_product( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + __isl_give isl_map *isl_map_range_product( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + __isl_give isl_map *isl_map_product( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + + #include + __isl_give isl_union_set *isl_union_set_product( + __isl_take isl_union_set *uset1, + __isl_take isl_union_set *uset2); + + #include + __isl_give isl_union_map *isl_union_map_domain_product( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + __isl_give isl_union_map *isl_union_map_range_product( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + __isl_give isl_union_map *isl_union_map_product( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + + #include + __isl_give isl_multi_val *isl_multi_val_range_product( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); + __isl_give isl_multi_val *isl_multi_val_product( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); + + #include + __isl_give isl_multi_aff *isl_multi_aff_range_product( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + __isl_give isl_multi_aff *isl_multi_aff_product( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_range_product( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_product( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_range_product( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_product( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_range_product( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); + +The above functions compute the cross product of the given +sets, relations or functions. The domains and ranges of the results +are wrapped maps between domains and ranges of the inputs. +To obtain a ``flat'' product, use the following functions +instead. + + #include + __isl_give isl_basic_set *isl_basic_set_flat_product( + __isl_take isl_basic_set *bset1, + __isl_take isl_basic_set *bset2); + __isl_give isl_set *isl_set_flat_product( + __isl_take isl_set *set1, + __isl_take isl_set *set2); + + #include + __isl_give isl_basic_map *isl_basic_map_flat_range_product( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_map *isl_map_flat_domain_product( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + __isl_give isl_map *isl_map_flat_range_product( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + __isl_give isl_basic_map *isl_basic_map_flat_product( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); + __isl_give isl_map *isl_map_flat_product( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + + #include + __isl_give isl_union_map * + isl_union_map_flat_domain_product( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + __isl_give isl_union_map * + isl_union_map_flat_range_product( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + + #include + __isl_give isl_multi_val *isl_multi_val_flat_range_product( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_aff *mv2); + + #include + __isl_give isl_multi_aff *isl_multi_aff_flat_range_product( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_flat_range_product( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_flat_range_product( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_flat_range_product( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_flat_range_product( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); + + #include + __isl_give isl_space *isl_space_factor_domain( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_factor_range( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_domain_factor_domain( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_domain_factor_range( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_range_factor_domain( + __isl_take isl_space *space); + __isl_give isl_space *isl_space_range_factor_range( + __isl_take isl_space *space); + +The functions C and +C extract the two arguments from +the result of a call to C. + +The arguments of a call to a product can be extracted +from the result using the following functions. + + #include + __isl_give isl_map *isl_map_factor_domain( + __isl_take isl_map *map); + __isl_give isl_map *isl_map_factor_range( + __isl_take isl_map *map); + __isl_give isl_map *isl_map_domain_factor_domain( + __isl_take isl_map *map); + __isl_give isl_map *isl_map_domain_factor_range( + __isl_take isl_map *map); + __isl_give isl_map *isl_map_range_factor_domain( + __isl_take isl_map *map); + __isl_give isl_map *isl_map_range_factor_range( + __isl_take isl_map *map); + + #include + __isl_give isl_union_map *isl_union_map_factor_domain( + __isl_take isl_union_map *umap); + __isl_give isl_union_map *isl_union_map_factor_range( + __isl_take isl_union_map *umap); + __isl_give isl_union_map * + isl_union_map_domain_factor_domain( + __isl_take isl_union_map *umap); + __isl_give isl_union_map * + isl_union_map_domain_factor_range( + __isl_take isl_union_map *umap); + __isl_give isl_union_map * + isl_union_map_range_factor_domain( + __isl_take isl_union_map *umap); + __isl_give isl_union_map * + isl_union_map_range_factor_range( + __isl_take isl_union_map *umap); + + #include + __isl_give isl_multi_val *isl_multi_val_factor_range( + __isl_take isl_multi_val *mv); + __isl_give isl_multi_val * + isl_multi_val_range_factor_domain( + __isl_take isl_multi_val *mv); + __isl_give isl_multi_val * + isl_multi_val_range_factor_range( + __isl_take isl_multi_val *mv); + + #include + __isl_give isl_multi_aff *isl_multi_aff_factor_range( + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_aff * + isl_multi_aff_range_factor_domain( + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_aff * + isl_multi_aff_range_factor_range( + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_factor_range( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_range_factor_domain( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_range_factor_range( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_factor_range( + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_range_factor_domain( + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_range_factor_range( + __isl_take isl_multi_union_pw_aff *mupa); + +The splice functions are a generalization of the flat product functions, +where the second argument may be inserted at any position inside +the first argument rather than being placed at the end. +The functions C, +C, +C and +C +take functions that live in a set space. + + #include + __isl_give isl_multi_val *isl_multi_val_range_splice( + __isl_take isl_multi_val *mv1, unsigned pos, + __isl_take isl_multi_val *mv2); + + #include + __isl_give isl_multi_aff *isl_multi_aff_range_splice( + __isl_take isl_multi_aff *ma1, unsigned pos, + __isl_take isl_multi_aff *ma2); + __isl_give isl_multi_aff *isl_multi_aff_splice( + __isl_take isl_multi_aff *ma1, + unsigned in_pos, unsigned out_pos, + __isl_take isl_multi_aff *ma2); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_range_splice( + __isl_take isl_multi_pw_aff *mpa1, unsigned pos, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_splice( + __isl_take isl_multi_pw_aff *mpa1, + unsigned in_pos, unsigned out_pos, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_range_splice( + __isl_take isl_multi_union_pw_aff *mupa1, + unsigned pos, + __isl_take isl_multi_union_pw_aff *mupa2); + +=item * Simplification + +When applied to a set or relation, +the gist operation returns a set or relation that has the +same intersection with the context as the input set or relation. +Any implicit equality in the intersection is made explicit in the result, +while all inequalities that are redundant with respect to the intersection +are removed. +In case of union sets and relations, the gist operation is performed +per space. + +When applied to a function, +the gist operation applies the set gist operation to each of +the cells in the domain of the input piecewise expression. +The context is also exploited +to simplify the expression associated to each cell. + + #include + __isl_give isl_basic_set *isl_basic_set_gist( + __isl_take isl_basic_set *bset, + __isl_take isl_basic_set *context); + __isl_give isl_set *isl_set_gist(__isl_take isl_set *set, + __isl_take isl_set *context); + __isl_give isl_set *isl_set_gist_params( + __isl_take isl_set *set, + __isl_take isl_set *context); + + #include + __isl_give isl_basic_map *isl_basic_map_gist( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_map *context); + __isl_give isl_basic_map *isl_basic_map_gist_domain( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *context); + __isl_give isl_map *isl_map_gist(__isl_take isl_map *map, + __isl_take isl_map *context); + __isl_give isl_map *isl_map_gist_params( + __isl_take isl_map *map, + __isl_take isl_set *context); + __isl_give isl_map *isl_map_gist_domain( + __isl_take isl_map *map, + __isl_take isl_set *context); + __isl_give isl_map *isl_map_gist_range( + __isl_take isl_map *map, + __isl_take isl_set *context); + + #include + __isl_give isl_union_set *isl_union_set_gist( + __isl_take isl_union_set *uset, + __isl_take isl_union_set *context); + __isl_give isl_union_set *isl_union_set_gist_params( + __isl_take isl_union_set *uset, + __isl_take isl_set *set); + + #include + __isl_give isl_union_map *isl_union_map_gist( + __isl_take isl_union_map *umap, + __isl_take isl_union_map *context); + __isl_give isl_union_map *isl_union_map_gist_params( + __isl_take isl_union_map *umap, + __isl_take isl_set *set); + __isl_give isl_union_map *isl_union_map_gist_domain( + __isl_take isl_union_map *umap, + __isl_take isl_union_set *uset); + __isl_give isl_union_map *isl_union_map_gist_range( + __isl_take isl_union_map *umap, + __isl_take isl_union_set *uset); + + #include + __isl_give isl_aff *isl_aff_gist_params( + __isl_take isl_aff *aff, + __isl_take isl_set *context); + __isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff, + __isl_take isl_set *context); + __isl_give isl_multi_aff *isl_multi_aff_gist_params( + __isl_take isl_multi_aff *maff, + __isl_take isl_set *context); + __isl_give isl_multi_aff *isl_multi_aff_gist( + __isl_take isl_multi_aff *maff, + __isl_take isl_set *context); + __isl_give isl_pw_aff *isl_pw_aff_gist_params( + __isl_take isl_pw_aff *pwaff, + __isl_take isl_set *context); + __isl_give isl_pw_aff *isl_pw_aff_gist( + __isl_take isl_pw_aff *pwaff, + __isl_take isl_set *context); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist_params( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_set *set); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_set *set); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist_params( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_set *set); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_set *set); + __isl_give isl_union_pw_aff *isl_union_pw_aff_gist( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_set *context); + __isl_give isl_union_pw_aff *isl_union_pw_aff_gist_params( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_set *context); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_gist_params( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_set *context); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_gist( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_union_set *context); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_gist_params( + __isl_take isl_multi_union_pw_aff *aff, + __isl_take isl_set *context); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_gist( + __isl_take isl_multi_union_pw_aff *aff, + __isl_take isl_union_set *context); + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_gist_params( + __isl_take isl_qpolynomial *qp, + __isl_take isl_set *context); + __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_params( + __isl_take isl_qpolynomial_fold *fold, + __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); + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_gist_params( + __isl_take isl_pw_qpolynomial *pwqp, + __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); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_gist( + __isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_set *context); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_gist_params( + __isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_set *context); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_gist_params( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_set *context); + __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_gist( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_union_set *context); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_gist( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_set *context); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_gist_params( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_set *context); + +=item * Binary Arithmetic Operations + + #include + __isl_give isl_set *isl_set_sum( + __isl_take isl_set *set1, + __isl_take isl_set *set2); + #include + __isl_give isl_map *isl_map_sum( + __isl_take isl_map *map1, + __isl_take isl_map *map2); + +C computes the Minkowski sum of its two arguments, +i.e., the set containing the sums of pairs of elements from +C and C. +The domain of the result of C is the intersection +of the domains of its two arguments. The corresponding range +elements are the sums of the corresponding range elements +in the two arguments. + + #include + __isl_give isl_multi_val *isl_multi_val_add( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); + __isl_give isl_multi_val *isl_multi_val_sub( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); + + #include + __isl_give isl_aff *isl_aff_add( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_multi_aff *isl_multi_aff_add( + __isl_take isl_multi_aff *maff1, + __isl_take isl_multi_aff *maff2); + __isl_give isl_pw_aff *isl_pw_aff_add( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_add( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_add( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_union_pw_aff *isl_union_pw_aff_add( + __isl_take isl_union_pw_aff *upa1, + __isl_take isl_union_pw_aff *upa2); + __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_add( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_add( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); + __isl_give isl_pw_aff *isl_pw_aff_min( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_pw_aff *isl_pw_aff_max( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_aff *isl_aff_sub( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_multi_aff *isl_multi_aff_sub( + __isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + __isl_give isl_pw_aff *isl_pw_aff_sub( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_sub( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_union_pw_aff *isl_union_pw_aff_sub( + __isl_take isl_union_pw_aff *upa1, + __isl_take isl_union_pw_aff *upa2); + __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_sub( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_sub( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); + +C subtracts the second argument from the first. + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_add( + __isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2); + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2); + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_disjoint( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2); + __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add( + __isl_take isl_pw_qpolynomial_fold *pwf1, + __isl_take isl_pw_qpolynomial_fold *pwf2); + __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_add( + __isl_take isl_union_pw_qpolynomial *upwqp1, + __isl_take isl_union_pw_qpolynomial *upwqp2); + __isl_give isl_qpolynomial *isl_qpolynomial_sub( + __isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2); + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sub( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2); + __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sub( + __isl_take isl_union_pw_qpolynomial *upwqp1, + __isl_take isl_union_pw_qpolynomial *upwqp2); + __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold( + __isl_take isl_pw_qpolynomial_fold *pwf1, + __isl_take isl_pw_qpolynomial_fold *pwf2); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_fold( + __isl_take isl_union_pw_qpolynomial_fold *upwf1, + __isl_take isl_union_pw_qpolynomial_fold *upwf2); + + #include + __isl_give isl_pw_aff *isl_pw_aff_union_add( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_union_pw_aff *isl_union_pw_aff_union_add( + __isl_take isl_union_pw_aff *upa1, + __isl_take isl_union_pw_aff *upa2); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_union_add( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_union_add( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); + __isl_give isl_pw_aff *isl_pw_aff_union_min( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_pw_aff *isl_pw_aff_union_max( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + +The function C computes a piecewise quasi-affine +expression with a domain that is the union of those of C and +C and such that on each cell, the quasi-affine expression is +the maximum of those of C and C. If only one of +C or C is defined on a given cell, then the +associated expression is the defined one. +This in contrast to the C function, which is +only defined on the shared definition domain of the arguments. + + #include + __isl_give isl_multi_val *isl_multi_val_add_val( + __isl_take isl_multi_val *mv, + __isl_take isl_val *v); + __isl_give isl_multi_val *isl_multi_val_mod_val( + __isl_take isl_multi_val *mv, + __isl_take isl_val *v); + __isl_give isl_multi_val *isl_multi_val_scale_val( + __isl_take isl_multi_val *mv, + __isl_take isl_val *v); + __isl_give isl_multi_val *isl_multi_val_scale_down_val( + __isl_take isl_multi_val *mv, + __isl_take isl_val *v); + + #include + __isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff, + __isl_take isl_val *mod); + __isl_give isl_pw_aff *isl_pw_aff_mod_val( + __isl_take isl_pw_aff *pa, + __isl_take isl_val *mod); + __isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_val *f); + __isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff, + __isl_take isl_val *v); + __isl_give isl_multi_aff *isl_multi_aff_scale_val( + __isl_take isl_multi_aff *ma, + __isl_take isl_val *v); + __isl_give isl_pw_aff *isl_pw_aff_scale_val( + __isl_take isl_pw_aff *pa, __isl_take isl_val *v); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_scale_val( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_val *v); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_val( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_val *v); + __isl_give isl_union_pw_multi_aff * + __isl_give isl_union_pw_aff *isl_union_pw_aff_scale_val( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_val *f); + isl_union_pw_multi_aff_scale_val( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_val *val); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_scale_val( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_val *v); + __isl_give isl_aff *isl_aff_scale_down_ui( + __isl_take isl_aff *aff, unsigned f); + __isl_give isl_aff *isl_aff_scale_down_val( + __isl_take isl_aff *aff, __isl_take isl_val *v); + __isl_give isl_multi_aff *isl_multi_aff_scale_down_val( + __isl_take isl_multi_aff *ma, + __isl_take isl_val *v); + __isl_give isl_pw_aff *isl_pw_aff_scale_down_val( + __isl_take isl_pw_aff *pa, + __isl_take isl_val *f); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_scale_down_val( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_val *v); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_val( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_val *v); + __isl_give isl_union_pw_aff *isl_union_pw_aff_scale_down_val( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_val *v); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_scale_down_val( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_val *val); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_scale_down_val( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_val *v); + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_scale_val( + __isl_take isl_qpolynomial *qp, + __isl_take isl_val *v); + __isl_give isl_qpolynomial_fold * + isl_qpolynomial_fold_scale_val( + __isl_take isl_qpolynomial_fold *fold, + __isl_take isl_val *v); + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_scale_val( + __isl_take isl_pw_qpolynomial *pwqp, + __isl_take isl_val *v); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_scale_val( + __isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_val *v); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_scale_val( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_val *v); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_scale_val( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_val *v); + __isl_give isl_qpolynomial * + isl_qpolynomial_scale_down_val( + __isl_take isl_qpolynomial *qp, + __isl_take isl_val *v); + __isl_give isl_qpolynomial_fold * + isl_qpolynomial_fold_scale_down_val( + __isl_take isl_qpolynomial_fold *fold, + __isl_take isl_val *v); + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_scale_down_val( + __isl_take isl_pw_qpolynomial *pwqp, + __isl_take isl_val *v); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_scale_down_val( + __isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_val *v); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_scale_down_val( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_val *v); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_scale_down_val( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_val *v); + + #include + __isl_give isl_multi_val *isl_multi_val_mod_multi_val( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); + __isl_give isl_multi_val *isl_multi_val_scale_multi_val( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); + __isl_give isl_multi_val * + isl_multi_val_scale_down_multi_val( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); + + #include + __isl_give isl_multi_aff *isl_multi_aff_mod_multi_val( + __isl_take isl_multi_aff *ma, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_mod_multi_val( + __isl_take isl_multi_union_pw_aff *upma, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_mod_multi_val( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_aff *isl_multi_aff_scale_multi_val( + __isl_take isl_multi_aff *ma, + __isl_take isl_multi_val *mv); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_scale_multi_val( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_scale_multi_val( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_scale_multi_val( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_multi_val *mv); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_scale_multi_val( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_aff * + isl_multi_aff_scale_down_multi_val( + __isl_take isl_multi_aff *ma, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_scale_down_multi_val( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_scale_down_multi_val( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_multi_val *mv); + +C scales the elements of C +by the corresponding elements of C. + + #include + __isl_give isl_aff *isl_aff_mul( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_aff *isl_aff_div( + __isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + __isl_give isl_pw_aff *isl_pw_aff_mul( + __isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + __isl_give isl_pw_aff *isl_pw_aff_div( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + __isl_give isl_pw_aff *isl_pw_aff_tdiv_q( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + __isl_give isl_pw_aff *isl_pw_aff_tdiv_r( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + +When multiplying two affine expressions, at least one of the two needs +to be a constant. Similarly, when dividing an affine expression by another, +the second expression needs to be a constant. +C computes the quotient of an integer division with +rounding towards zero. C computes the corresponding +remainder. + + #include + __isl_give isl_qpolynomial *isl_qpolynomial_mul( + __isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2); + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2); + __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul( + __isl_take isl_union_pw_qpolynomial *upwqp1, + __isl_take isl_union_pw_qpolynomial *upwqp2); + +=back + +=head3 Lexicographic Optimization + +Given a (basic) set C (or C) and a zero-dimensional domain C, +the following functions +compute a set that contains the lexicographic minimum or maximum +of the elements in C (or C) for those values of the parameters +that satisfy C. +If C is not C, then C<*empty> is assigned a set +that contains the parameter values in C for which C (or C) +has no elements. +In other words, the union of the parameter values +for which the result is non-empty and of C<*empty> +is equal to C. + + #include + __isl_give isl_set *isl_basic_set_partial_lexmin( + __isl_take isl_basic_set *bset, + __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); + __isl_give isl_set *isl_basic_set_partial_lexmax( + __isl_take isl_basic_set *bset, + __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); + __isl_give isl_set *isl_set_partial_lexmin( + __isl_take isl_set *set, __isl_take isl_set *dom, + __isl_give isl_set **empty); + __isl_give isl_set *isl_set_partial_lexmax( + __isl_take isl_set *set, __isl_take isl_set *dom, + __isl_give isl_set **empty); + +Given a (basic) set C (or C), the following functions simply +return a set containing the lexicographic minimum or maximum +of the elements in C (or C). +In case of union sets, the optimum is computed per space. + + #include + __isl_give isl_set *isl_basic_set_lexmin( + __isl_take isl_basic_set *bset); + __isl_give isl_set *isl_basic_set_lexmax( + __isl_take isl_basic_set *bset); + __isl_give isl_set *isl_set_lexmin( + __isl_take isl_set *set); + __isl_give isl_set *isl_set_lexmax( + __isl_take isl_set *set); + __isl_give isl_union_set *isl_union_set_lexmin( + __isl_take isl_union_set *uset); + __isl_give isl_union_set *isl_union_set_lexmax( + __isl_take isl_union_set *uset); + +Given a (basic) relation C (or C) and a domain C, +the following functions +compute a relation that maps each element of C +to the single lexicographic minimum or maximum +of the elements that are associated to that same +element in C (or C). +If C is not C, then C<*empty> is assigned a set +that contains the elements in C that do not map +to any elements in C (or C). +In other words, the union of the domain of the result and of C<*empty> +is equal to C. + + #include + __isl_give isl_map *isl_basic_map_partial_lexmax( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); + __isl_give isl_map *isl_basic_map_partial_lexmin( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); + __isl_give isl_map *isl_map_partial_lexmax( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty); + __isl_give isl_map *isl_map_partial_lexmin( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty); + +Given a (basic) map C (or C), the following functions simply +return a map mapping each element in the domain of +C (or C) to the lexicographic minimum or maximum +of all elements associated to that element. +In case of union relations, the optimum is computed per space. + + #include + __isl_give isl_map *isl_basic_map_lexmin( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_basic_map_lexmax( + __isl_take isl_basic_map *bmap); + __isl_give isl_map *isl_map_lexmin( + __isl_take isl_map *map); + __isl_give isl_map *isl_map_lexmax( + __isl_take isl_map *map); + __isl_give isl_union_map *isl_union_map_lexmin( + __isl_take isl_union_map *umap); + __isl_give isl_union_map *isl_union_map_lexmax( + __isl_take isl_union_map *umap); + +The following functions return their result in the form of +a piecewise multi-affine expression, +but are otherwise equivalent to the corresponding functions +returning a basic set or relation. + + #include + __isl_give isl_pw_multi_aff * + isl_basic_set_partial_lexmin_pw_multi_aff( + __isl_take isl_basic_set *bset, + __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); + __isl_give isl_pw_multi_aff * + isl_basic_set_partial_lexmax_pw_multi_aff( + __isl_take isl_basic_set *bset, + __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); + __isl_give isl_pw_multi_aff *isl_set_lexmin_pw_multi_aff( + __isl_take isl_set *set); + __isl_give isl_pw_multi_aff *isl_set_lexmax_pw_multi_aff( + __isl_take isl_set *set); + + #include + __isl_give isl_pw_multi_aff * + isl_basic_map_lexmin_pw_multi_aff( + __isl_take isl_basic_map *bmap); + __isl_give isl_pw_multi_aff * + isl_basic_map_partial_lexmin_pw_multi_aff( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); + __isl_give isl_pw_multi_aff * + isl_basic_map_partial_lexmax_pw_multi_aff( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); + __isl_give isl_pw_multi_aff *isl_map_lexmin_pw_multi_aff( + __isl_take isl_map *map); + __isl_give isl_pw_multi_aff *isl_map_lexmax_pw_multi_aff( + __isl_take isl_map *map); + +The following functions return the lexicographic minimum or maximum +on the shared domain of the inputs and the single defined function +on those parts of the domain where only a single function is defined. + + #include + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + +If the input to a lexicographic optimization problem has +multiple constraints with the same coefficients for the optimized +variables, then, by default, this symmetry is exploited by +replacing those constraints by a single constraint with +an abstract bound, which is in turn bounded by the corresponding terms +in the original constraints. +Without this optimization, the solver would typically consider +all possible orderings of those original bounds, resulting in a needless +decomposition of the domain. +However, the optimization can also result in slowdowns since +an extra parameter is introduced that may get used in additional +integer divisions. +The following option determines whether symmetry detection is applied +during lexicographic optimization. + + #include + isl_stat isl_options_set_pip_symmetry(isl_ctx *ctx, + int val); + int isl_options_get_pip_symmetry(isl_ctx *ctx); + +=begin latex + +See also \autoref{s:offline}. + +=end latex + +=head2 Ternary Operations + + #include + __isl_give isl_pw_aff *isl_pw_aff_cond( + __isl_take isl_pw_aff *cond, + __isl_take isl_pw_aff *pwaff_true, + __isl_take isl_pw_aff *pwaff_false); + +The function C performs a conditional operator +and returns an expression that is equal to C +for elements where C is non-zero and equal to C for elements +where C is zero. + +=head2 Lists + +Lists are defined over several element types, including +C, C, C, C, C, +C, C, +C, C, C, C, C, +C, C and C. +Here we take lists of Cs as an example. +Lists can be created, copied, modified and freed using the following functions. + + #include + __isl_give isl_set_list *isl_set_list_from_set( + __isl_take isl_set *el); + __isl_give isl_set_list *isl_set_list_alloc( + isl_ctx *ctx, int n); + __isl_give isl_set_list *isl_set_list_copy( + __isl_keep isl_set_list *list); + __isl_give isl_set_list *isl_set_list_insert( + __isl_take isl_set_list *list, unsigned pos, + __isl_take isl_set *el); + __isl_give isl_set_list *isl_set_list_add( + __isl_take isl_set_list *list, + __isl_take isl_set *el); + __isl_give isl_set_list *isl_set_list_drop( + __isl_take isl_set_list *list, + unsigned first, unsigned n); + __isl_give isl_set_list *isl_set_list_set_set( + __isl_take isl_set_list *list, int index, + __isl_take isl_set *set); + __isl_give isl_set_list *isl_set_list_concat( + __isl_take isl_set_list *list1, + __isl_take isl_set_list *list2); + __isl_give isl_set_list *isl_set_list_map( + __isl_take isl_set_list *list, + __isl_give isl_set *(*fn)(__isl_take isl_set *el, + void *user), + void *user); + __isl_give isl_set_list *isl_set_list_sort( + __isl_take isl_set_list *list, + int (*cmp)(__isl_keep isl_set *a, + __isl_keep isl_set *b, void *user), + void *user); + __isl_null isl_set_list *isl_set_list_free( + __isl_take isl_set_list *list); + +C creates an empty list with an initial capacity +for C elements. C and C +add elements to a list, increasing its capacity as needed. +C creates a list with a single element. + +Lists can be inspected using the following functions. + + #include + int isl_set_list_n_set(__isl_keep isl_set_list *list); + __isl_give isl_set *isl_set_list_get_set( + __isl_keep isl_set_list *list, int index); + isl_stat isl_set_list_foreach(__isl_keep isl_set_list *list, + isl_stat (*fn)(__isl_take isl_set *el, void *user), + void *user); + isl_stat isl_set_list_foreach_scc( + __isl_keep isl_set_list *list, + isl_bool (*follows)(__isl_keep isl_set *a, + __isl_keep isl_set *b, void *user), + void *follows_user, + isl_stat (*fn)(__isl_take isl_set *el, void *user), + void *fn_user); + +The function C calls C on each of the +strongly connected components of the graph with as vertices the elements +of C and a directed edge from vertex C to vertex C +iff C returns C. The callbacks C and +C should return C or C on error. + +Lists can be printed using + + #include + __isl_give isl_printer *isl_printer_print_set_list( + __isl_take isl_printer *p, + __isl_keep isl_set_list *list); + +=head2 Associative arrays + +Associative arrays map isl objects of a specific type to isl objects +of some (other) specific type. They are defined for several pairs +of types, including (C, C), +(C, C), +(C, C) and +(C, C). +Here, we take associative arrays that map Cs to Cs +as an example. + +Associative arrays can be created, copied and freed using +the following functions. + + #include + __isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_alloc( + isl_ctx *ctx, int min_size); + __isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_copy( + __isl_keep isl_id_to_ast_expr *id2expr); + __isl_null isl_id_to_ast_expr *isl_id_to_ast_expr_free( + __isl_take isl_id_to_ast_expr *id2expr); + +The C argument to C can be used +to specify the expected size of the associative array. +The associative array will be grown automatically as needed. + +Associative arrays can be inspected using the following functions. + + #include + __isl_give isl_maybe_isl_ast_expr + isl_id_to_ast_expr_try_get( + __isl_keep isl_id_to_ast_expr *id2expr, + __isl_keep isl_id *key); + isl_bool isl_id_to_ast_expr_has( + __isl_keep isl_id_to_ast_expr *id2expr, + __isl_keep isl_id *key); + __isl_give isl_ast_expr *isl_id_to_ast_expr_get( + __isl_keep isl_id_to_ast_expr *id2expr, + __isl_take isl_id *key); + isl_stat isl_id_to_ast_expr_foreach( + __isl_keep isl_id_to_ast_expr *id2expr, + isl_stat (*fn)(__isl_take isl_id *key, + __isl_take isl_ast_expr *val, void *user), + void *user); + +The function C returns a structure +containing two elements, C and C. +If there is a value associated to the key, then C +is set to C and C contains a copy of +the associated value. Otherwise C is C and +C may be C or C depending +on whether some error has occurred or there simply is no associated value. +The function C returns the C field +in the structure and +the function C returns the C field. + +Associative arrays can be modified using the following functions. + + #include + __isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_set( + __isl_take isl_id_to_ast_expr *id2expr, + __isl_take isl_id *key, + __isl_take isl_ast_expr *val); + __isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_drop( + __isl_take isl_id_to_ast_expr *id2expr, + __isl_take isl_id *key); + +Associative arrays can be printed using the following function. + + #include + __isl_give isl_printer *isl_printer_print_id_to_ast_expr( + __isl_take isl_printer *p, + __isl_keep isl_id_to_ast_expr *id2expr); + +=head2 Vectors + +Vectors can be created, copied and freed using the following functions. + + #include + __isl_give isl_vec *isl_vec_alloc(isl_ctx *ctx, + unsigned size); + __isl_give isl_vec *isl_vec_zero(isl_ctx *ctx, + unsigned size); + __isl_give isl_vec *isl_vec_copy(__isl_keep isl_vec *vec); + __isl_null isl_vec *isl_vec_free(__isl_take isl_vec *vec); + +Note that the elements of a vector created by C +may have arbitrary values. +A vector created by C has elements with value zero. +The elements can be changed and inspected using the following functions. + + int isl_vec_size(__isl_keep isl_vec *vec); + __isl_give isl_val *isl_vec_get_element_val( + __isl_keep isl_vec *vec, int pos); + __isl_give isl_vec *isl_vec_set_element_si( + __isl_take isl_vec *vec, int pos, int v); + __isl_give isl_vec *isl_vec_set_element_val( + __isl_take isl_vec *vec, int pos, + __isl_take isl_val *v); + __isl_give isl_vec *isl_vec_set_si(__isl_take isl_vec *vec, + int v); + __isl_give isl_vec *isl_vec_set_val( + __isl_take isl_vec *vec, __isl_take isl_val *v); + int isl_vec_cmp_element(__isl_keep isl_vec *vec1, + __isl_keep isl_vec *vec2, int pos); + +C will return a negative value if anything went wrong. +In that case, the value of C<*v> is undefined. + +The following function can be used to concatenate two vectors. + + __isl_give isl_vec *isl_vec_concat(__isl_take isl_vec *vec1, + __isl_take isl_vec *vec2); + +=head2 Matrices + +Matrices can be created, copied and freed using the following functions. + + #include + __isl_give isl_mat *isl_mat_alloc(isl_ctx *ctx, + unsigned n_row, unsigned n_col); + __isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat); + __isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat); + +Note that the elements of a newly created matrix may have arbitrary values. +The elements can be changed and inspected using the following functions. + + int isl_mat_rows(__isl_keep isl_mat *mat); + int isl_mat_cols(__isl_keep isl_mat *mat); + __isl_give isl_val *isl_mat_get_element_val( + __isl_keep isl_mat *mat, int row, int col); + __isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat, + int row, int col, int v); + __isl_give isl_mat *isl_mat_set_element_val( + __isl_take isl_mat *mat, int row, int col, + __isl_take isl_val *v); + +The following function computes the rank of a matrix. +The return value may be -1 if some error occurred. + + #include + int isl_mat_rank(__isl_keep isl_mat *mat); + +The following function can be used to compute the (right) inverse +of a matrix, i.e., a matrix such that the product of the original +and the inverse (in that order) is a multiple of the identity matrix. +The input matrix is assumed to be of full row-rank. + + __isl_give isl_mat *isl_mat_right_inverse(__isl_take isl_mat *mat); + +The following function can be used to compute the (right) kernel +(or null space) of a matrix, i.e., a matrix such that the product of +the original and the kernel (in that order) is the zero matrix. + + __isl_give isl_mat *isl_mat_right_kernel(__isl_take isl_mat *mat); + +The following function computes a basis for the space spanned +by the rows of a matrix. + + __isl_give isl_mat *isl_mat_row_basis( + __isl_take isl_mat *mat); + +The following function computes rows that extend a basis of C +to a basis that also covers C. + + __isl_give isl_mat *isl_mat_row_basis_extension( + __isl_take isl_mat *mat1, + __isl_take isl_mat *mat2); + +The following function checks whether there is no linear dependence +among the combined rows of "mat1" and "mat2" that is not already present +in "mat1" or "mat2" individually. +If "mat1" and "mat2" have linearly independent rows by themselves, +then this means that there is no linear dependence among all rows together. + + isl_bool isl_mat_has_linearly_independent_rows( + __isl_keep isl_mat *mat1, + __isl_keep isl_mat *mat2); + +=head2 Bounds on Piecewise Quasipolynomials and Piecewise Quasipolynomial Reductions + +The following functions determine +an upper or lower bound on a quasipolynomial over its domain. + + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_bound( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_fold type, int *tight); + + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_bound( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_fold type, int *tight); + +The C argument may be either C or C. +If C is not C, then C<*tight> is set to C<1> +is the returned bound is known be tight, i.e., for each value +of the parameters there is at least +one element in the domain that reaches the bound. +If the domain of C is not wrapping, then the bound is computed +over all elements in that domain and the result has a purely parametric +domain. If the domain of C is wrapping, then the bound is +computed over the range of the wrapped relation. The domain of the +wrapped relation becomes the domain of the result. + +=head2 Parametric Vertex Enumeration + +The parametric vertex enumeration described in this section +is mainly intended to be used internally and by the C +library. + + #include + __isl_give isl_vertices *isl_basic_set_compute_vertices( + __isl_keep isl_basic_set *bset); + +The function C performs the +actual computation of the parametric vertices and the chamber +decomposition and stores the result in an C object. +This information can be queried by either iterating over all +the vertices or iterating over all the chambers or cells +and then iterating over all vertices that are active on the chamber. + + isl_stat isl_vertices_foreach_vertex( + __isl_keep isl_vertices *vertices, + isl_stat (*fn)(__isl_take isl_vertex *vertex, + void *user), void *user); + + isl_stat isl_vertices_foreach_cell( + __isl_keep isl_vertices *vertices, + isl_stat (*fn)(__isl_take isl_cell *cell, + void *user), void *user); + isl_stat isl_cell_foreach_vertex(__isl_keep isl_cell *cell, + isl_stat (*fn)(__isl_take isl_vertex *vertex, + void *user), void *user); + +Other operations that can be performed on an C object are +the following. + + int isl_vertices_get_n_vertices( + __isl_keep isl_vertices *vertices); + __isl_null isl_vertices *isl_vertices_free( + __isl_take isl_vertices *vertices); + +Vertices can be inspected and destroyed using the following functions. + + int isl_vertex_get_id(__isl_keep isl_vertex *vertex); + __isl_give isl_basic_set *isl_vertex_get_domain( + __isl_keep isl_vertex *vertex); + __isl_give isl_multi_aff *isl_vertex_get_expr( + __isl_keep isl_vertex *vertex); + void isl_vertex_free(__isl_take isl_vertex *vertex); + +C returns a multiple quasi-affine expression +describing the vertex in terms of the parameters, +while C returns the activity domain +of the vertex. + +Chambers can be inspected and destroyed using the following functions. + + __isl_give isl_basic_set *isl_cell_get_domain( + __isl_keep isl_cell *cell); + void isl_cell_free(__isl_take isl_cell *cell); + +=head1 Polyhedral Compilation Library + +This section collects functionality in C that has been specifically +designed for use during polyhedral compilation. + +=head2 Schedule Trees + +A schedule tree is a structured representation of a schedule, +assigning a relative order to a set of domain elements. +The relative order expressed by the schedule tree is +defined recursively. In particular, the order between +two domain elements is determined by the node that is closest +to the root that refers to both elements and that orders them apart. +Each node in the tree is of one of several types. +The root node is always of type C +(or C) +and it describes the (extra) domain elements to which the schedule applies. +The other types of nodes are as follows. + +=over + +=item C + +A band of schedule dimensions. Each schedule dimension is represented +by a union piecewise quasi-affine expression. If this expression +assigns a different value to two domain elements, while all previous +schedule dimensions in the same band assign them the same value, +then the two domain elements are ordered according to these two +different values. +Each expression is required to be total in the domain elements +that reach the band node. + +=item C + +An expansion node maps each of the domain elements that reach the node +to one or more domain elements. The image of this mapping forms +the set of domain elements that reach the child of the expansion node. +The function that maps each of the expanded domain elements +to the original domain element from which it was expanded +is called the contraction. + +=item C + +A filter node does not impose any ordering, but rather intersects +the set of domain elements that the current subtree refers to +with a given union set. The subtree of the filter node only +refers to domain elements in the intersection. +A filter node is typically only used as a child of a sequence or +set node. + +=item C + +A leaf of the schedule tree. Leaf nodes do not impose any ordering. + +=item C + +A mark node can be used to attach any kind of information to a subtree +of the schedule tree. + +=item C + +A sequence node has one or more children, each of which is a filter node. +The filters on these filter nodes form a partition of +the domain elements that the current subtree refers to. +If two domain elements appear in distinct filters then the sequence +node orders them according to the child positions of the corresponding +filter nodes. + +=item C + +A set node is similar to a sequence node, except that +it expresses that domain elements appearing in distinct filters +may have any order. The order of the children of a set node +is therefore also immaterial. + +=back + +The following node types are only supported by the AST generator. + +=over + +=item C + +The context describes constraints on the parameters and +the schedule dimensions of outer +bands that the AST generator may assume to hold. It is also the only +kind of node that may introduce additional parameters. +The space of the context is that of the flat product of the outer +band nodes. In particular, if there are no outer band nodes, then +this space is the unnamed zero-dimensional space. +Since a context node references the outer band nodes, any tree +containing a context node is considered to be anchored. + +=item C + +An extension node instructs the AST generator to add additional +domain elements that need to be scheduled. +The additional domain elements are described by the range of +the extension map in terms of the outer schedule dimensions, +i.e., the flat product of the outer band nodes. +Note that domain elements are added whenever the AST generator +reaches the extension node, meaning that there are still some +active domain elements for which an AST needs to be generated. +The conditions under which some domain elements are still active +may however not be completely described by the outer AST nodes +generated at that point. +Since an extension node references the outer band nodes, any tree +containing an extension node is considered to be anchored. + +An extension node may also appear as the root of a schedule tree, +when it is intended to be inserted into another tree +using C or C. +In this case, the domain of the extension node should +correspond to the flat product of the outer band nodes +in this other schedule tree at the point where the extension tree +will be inserted. + +=item C + +The guard describes constraints on the parameters and +the schedule dimensions of outer +bands that need to be enforced by the outer nodes +in the generated AST. +That is, the part of the AST that is generated from descendants +of the guard node can assume that these constraints are satisfied. +The space of the guard is that of the flat product of the outer +band nodes. In particular, if there are no outer band nodes, then +this space is the unnamed zero-dimensional space. +Since a guard node references the outer band nodes, any tree +containing a guard node is considered to be anchored. + +=back + +Except for the C nodes, +none of the nodes may introduce any parameters that were not +already present in the root domain node. + +A schedule tree is encapsulated in an C object. +The simplest such objects, those with a tree consisting of single domain node, +can be created using the following functions with either an empty +domain or a given domain. + + #include + __isl_give isl_schedule *isl_schedule_empty( + __isl_take isl_space *space); + __isl_give isl_schedule *isl_schedule_from_domain( + __isl_take isl_union_set *domain); + +The function C described +in L can also be used to construct schedules. + +C objects may be copied and freed using the following functions. + + #include + __isl_give isl_schedule *isl_schedule_copy( + __isl_keep isl_schedule *sched); + __isl_null isl_schedule *isl_schedule_free( + __isl_take isl_schedule *sched); + +The following functions checks whether two C objects +are obviously the same. + + #include + isl_bool isl_schedule_plain_is_equal( + __isl_keep isl_schedule *schedule1, + __isl_keep isl_schedule *schedule2); + +The domain of the schedule, i.e., the domain described by the root node, +can be obtained using the following function. + + #include + __isl_give isl_union_set *isl_schedule_get_domain( + __isl_keep isl_schedule *schedule); + +An extra top-level band node (right underneath the domain node) can +be introduced into the schedule using the following function. +The schedule tree is assumed not to have any anchored nodes. + + #include + __isl_give isl_schedule * + isl_schedule_insert_partial_schedule( + __isl_take isl_schedule *schedule, + __isl_take isl_multi_union_pw_aff *partial); + +A top-level context node (right underneath the domain node) can +be introduced into the schedule using the following function. + + #include + __isl_give isl_schedule *isl_schedule_insert_context( + __isl_take isl_schedule *schedule, + __isl_take isl_set *context) + +A top-level guard node (right underneath the domain node) can +be introduced into the schedule using the following function. + + #include + __isl_give isl_schedule *isl_schedule_insert_guard( + __isl_take isl_schedule *schedule, + __isl_take isl_set *guard) + +A schedule that combines two schedules either in the given +order or in an arbitrary order, i.e., with an C +or an C node, +can be created using the following functions. + + #include + __isl_give isl_schedule *isl_schedule_sequence( + __isl_take isl_schedule *schedule1, + __isl_take isl_schedule *schedule2); + __isl_give isl_schedule *isl_schedule_set( + __isl_take isl_schedule *schedule1, + __isl_take isl_schedule *schedule2); + +The domains of the two input schedules need to be disjoint. + +The following function can be used to restrict the domain +of a schedule with a domain node as root to be a subset of the given union set. +This operation may remove nodes in the tree that have become +redundant. + + #include + __isl_give isl_schedule *isl_schedule_intersect_domain( + __isl_take isl_schedule *schedule, + __isl_take isl_union_set *domain); + +The following function can be used to simplify the domain +of a schedule with a domain node as root with respect to the given +parameter domain. + + #include + __isl_give isl_schedule *isl_schedule_gist_domain_params( + __isl_take isl_schedule *schedule, + __isl_take isl_set *context); + +The following function resets the user pointers on all parameter +and tuple identifiers referenced by the nodes of the given schedule. + + #include + __isl_give isl_schedule *isl_schedule_reset_user( + __isl_take isl_schedule *schedule); + +The following function aligns the parameters of all nodes +in the given schedule to the given space. + + #include + __isl_give isl_schedule *isl_schedule_align_params( + __isl_take isl_schedule *schedule, + __isl_take isl_space *space); + +The following function allows the user to plug in a given function +in the iteration domains. The input schedule is not allowed to contain +any expansion nodes. + + #include + __isl_give isl_schedule * + isl_schedule_pullback_union_pw_multi_aff( + __isl_take isl_schedule *schedule, + __isl_take isl_union_pw_multi_aff *upma); + +The following function can be used to plug in the schedule C +in the leaves of C, where C describes how +the domain elements of C map to the domain elements +at the original leaves of C. +The resulting schedule will contain expansion nodes, unless +C is an identity function. + + #include + __isl_give isl_schedule *isl_schedule_expand( + __isl_take isl_schedule *schedule, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_schedule *expansion); + +An C representation of the schedule can be obtained +from an C using the following function. + + #include + __isl_give isl_union_map *isl_schedule_get_map( + __isl_keep isl_schedule *sched); + +The resulting relation encodes the same relative ordering as +the schedule by mapping the domain elements to a common schedule space. +If the schedule_separate_components option is set, then the order +of the children of a set node is explicitly encoded in the result. +If the tree contains any expansion nodes, then the relation +is formulated in terms of the expanded domain elements. + +Schedules can be read from input using the following functions. + + #include + __isl_give isl_schedule *isl_schedule_read_from_file( + isl_ctx *ctx, FILE *input); + __isl_give isl_schedule *isl_schedule_read_from_str( + isl_ctx *ctx, const char *str); + +A representation of the schedule can be printed using + + #include + __isl_give isl_printer *isl_printer_print_schedule( + __isl_take isl_printer *p, + __isl_keep isl_schedule *schedule); + __isl_give char *isl_schedule_to_str( + __isl_keep isl_schedule *schedule); + +C prints the schedule in flow format. + +The schedule tree can be traversed through the use of +C objects that point to a particular +position in the schedule tree. Whenever a C +is used to modify a node in the schedule tree, the original schedule +tree is left untouched and the modifications are performed to a copy +of the tree. The returned C then points to +this modified copy of the tree. + +The root of the schedule tree can be obtained using the following function. + + #include + __isl_give isl_schedule_node *isl_schedule_get_root( + __isl_keep isl_schedule *schedule); + +A pointer to a newly created schedule tree with a single domain +node can be created using the following functions. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_from_domain( + __isl_take isl_union_set *domain); + __isl_give isl_schedule_node * + isl_schedule_node_from_extension( + __isl_take isl_union_map *extension); + +C creates a tree with an extension +node as root. + +Schedule nodes can be copied and freed using the following functions. + + #include + __isl_give isl_schedule_node *isl_schedule_node_copy( + __isl_keep isl_schedule_node *node); + __isl_null isl_schedule_node *isl_schedule_node_free( + __isl_take isl_schedule_node *node); + +The following functions can be used to check if two schedule +nodes point to the same position in the same schedule. + + #include + isl_bool isl_schedule_node_is_equal( + __isl_keep isl_schedule_node *node1, + __isl_keep isl_schedule_node *node2); + +The following properties can be obtained from a schedule node. + + #include + enum isl_schedule_node_type isl_schedule_node_get_type( + __isl_keep isl_schedule_node *node); + enum isl_schedule_node_type + isl_schedule_node_get_parent_type( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule *isl_schedule_node_get_schedule( + __isl_keep isl_schedule_node *node); + +The function C returns the type of +the node, while C returns +type of the parent of the node, which is required to exist. +The function C returns a copy +to the schedule to which the node belongs. + +The following functions can be used to move the schedule node +to a different position in the tree or to check if such a position +exists. + + #include + isl_bool isl_schedule_node_has_parent( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_parent( + __isl_take isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_root( + __isl_take isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_ancestor( + __isl_take isl_schedule_node *node, + int generation); + int isl_schedule_node_n_children( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_child( + __isl_take isl_schedule_node *node, int pos); + isl_bool isl_schedule_node_has_children( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_first_child( + __isl_take isl_schedule_node *node); + isl_bool isl_schedule_node_has_previous_sibling( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_previous_sibling( + __isl_take isl_schedule_node *node); + isl_bool isl_schedule_node_has_next_sibling( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_next_sibling( + __isl_take isl_schedule_node *node); + +For C, the ancestor of generation 0 +is the node itself, the ancestor of generation 1 is its parent and so on. + +It is also possible to query the number of ancestors of a node, +the position of the current node +within the children of its parent, the position of the subtree +containing a node within the children of an ancestor +or to obtain a copy of a given +child without destroying the current node. +Given two nodes that point to the same schedule, their closest +shared ancestor can be obtained using +C. + + #include + int isl_schedule_node_get_tree_depth( + __isl_keep isl_schedule_node *node); + int isl_schedule_node_get_child_position( + __isl_keep isl_schedule_node *node); + int isl_schedule_node_get_ancestor_child_position( + __isl_keep isl_schedule_node *node, + __isl_keep isl_schedule_node *ancestor); + __isl_give isl_schedule_node *isl_schedule_node_get_child( + __isl_keep isl_schedule_node *node, int pos); + __isl_give isl_schedule_node * + isl_schedule_node_get_shared_ancestor( + __isl_keep isl_schedule_node *node1, + __isl_keep isl_schedule_node *node2); + +All nodes in a schedule tree or +all descendants of a specific node (including the node) can be visited +in depth-first pre-order using the following functions. + + #include + isl_stat isl_schedule_foreach_schedule_node_top_down( + __isl_keep isl_schedule *sched, + isl_bool (*fn)(__isl_keep isl_schedule_node *node, + void *user), void *user); + + #include + isl_stat isl_schedule_node_foreach_descendant_top_down( + __isl_keep isl_schedule_node *node, + isl_bool (*fn)(__isl_keep isl_schedule_node *node, + void *user), void *user); + +The callback function is slightly different from the usual +callbacks in that it not only indicates success (non-negative result) +or failure (negative result), but also indicates whether the children +of the given node should be visited. In particular, if the callback +returns a positive value, then the children are visited, but if +the callback returns zero, then the children are not visited. + +The following functions checks whether +all descendants of a specific node (including the node itself) +satisfy a user-specified test. + + #include + isl_bool isl_schedule_node_every_descendant( + __isl_keep isl_schedule_node *node, + isl_bool (*test)(__isl_keep isl_schedule_node *node, + void *user), void *user) + +The ancestors of a node in a schedule tree can be visited from +the root down to and including the parent of the node using +the following function. + + #include + isl_stat isl_schedule_node_foreach_ancestor_top_down( + __isl_keep isl_schedule_node *node, + isl_stat (*fn)(__isl_keep isl_schedule_node *node, + void *user), void *user); + +The following functions allows for a depth-first post-order +traversal of the nodes in a schedule tree or +of the descendants of a specific node (including the node +itself), where the user callback is allowed to modify the +visited node. + + #include + __isl_give isl_schedule * + isl_schedule_map_schedule_node_bottom_up( + __isl_take isl_schedule *schedule, + __isl_give isl_schedule_node *(*fn)( + __isl_take isl_schedule_node *node, + void *user), void *user); + + #include + __isl_give isl_schedule_node * + isl_schedule_node_map_descendant_bottom_up( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_node *(*fn)( + __isl_take isl_schedule_node *node, + void *user), void *user); + +The traversal continues from the node returned by the callback function. +It is the responsibility of the user to ensure that this does not +lead to an infinite loop. It is safest to always return a pointer +to the same position (same ancestors and child positions) as the input node. + +The following function removes a node (along with its descendants) +from a schedule tree and returns a pointer to the leaf at the +same position in the updated tree. +It is not allowed to remove the root of a schedule tree or +a child of a set or sequence node. + + #include + __isl_give isl_schedule_node *isl_schedule_node_cut( + __isl_take isl_schedule_node *node); + +The following function removes a single node +from a schedule tree and returns a pointer to the child +of the node, now located at the position of the original node +or to a leaf node at that position if there was no child. +It is not allowed to remove the root of a schedule tree, +a set or sequence node, a child of a set or sequence node or +a band node with an anchored subtree. + + #include + __isl_give isl_schedule_node *isl_schedule_node_delete( + __isl_take isl_schedule_node *node); + +Most nodes in a schedule tree only contain local information. +In some cases, however, a node may also refer to the schedule dimensions +of its outer band nodes. +This means that the position of the node within the tree should +not be changed, or at least that no changes are performed to the +outer band nodes. The following function can be used to test +whether the subtree rooted at a given node contains any such nodes. + + #include + isl_bool isl_schedule_node_is_subtree_anchored( + __isl_keep isl_schedule_node *node); + +The following function resets the user pointers on all parameter +and tuple identifiers referenced by the given schedule node. + + #include + __isl_give isl_schedule_node *isl_schedule_node_reset_user( + __isl_take isl_schedule_node *node); + +The following function aligns the parameters of the given schedule +node to the given space. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_align_params( + __isl_take isl_schedule_node *node, + __isl_take isl_space *space); + +Several node types have their own functions for querying +(and in some cases setting) some node type specific properties. + + #include + __isl_give isl_space *isl_schedule_node_band_get_space( + __isl_keep isl_schedule_node *node); + __isl_give isl_multi_union_pw_aff * + isl_schedule_node_band_get_partial_schedule( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_map * + isl_schedule_node_band_get_partial_schedule_union_map( + __isl_keep isl_schedule_node *node); + unsigned isl_schedule_node_band_n_member( + __isl_keep isl_schedule_node *node); + isl_bool isl_schedule_node_band_member_get_coincident( + __isl_keep isl_schedule_node *node, int pos); + __isl_give isl_schedule_node * + isl_schedule_node_band_member_set_coincident( + __isl_take isl_schedule_node *node, int pos, + int coincident); + isl_bool isl_schedule_node_band_get_permutable( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_band_set_permutable( + __isl_take isl_schedule_node *node, int permutable); + enum isl_ast_loop_type + isl_schedule_node_band_member_get_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos); + __isl_give isl_schedule_node * + isl_schedule_node_band_member_set_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type); + __isl_give isl_union_set * + enum isl_ast_loop_type + isl_schedule_node_band_member_get_isolate_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos); + __isl_give isl_schedule_node * + isl_schedule_node_band_member_set_isolate_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type); + isl_schedule_node_band_get_ast_build_options( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_band_set_ast_build_options( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set *options); + __isl_give isl_set * + isl_schedule_node_band_get_ast_isolate_option( + __isl_keep isl_schedule_node *node); + +The function C returns the space +of the partial schedule of the band. +The function C +returns a representation of the partial schedule of the band node +in the form of an C. +The coincident and permutable properties are set by +C on the schedule tree +it produces. +A scheduling dimension is considered to be ``coincident'' +if it satisfies the coincidence constraints within its band. +That is, if the dependence distances of the coincidence +constraints are all zero in that direction (for fixed +iterations of outer bands). +A band is marked permutable if it was produced using the Pluto-like scheduler. +Note that the scheduler may have to resort to a Feautrier style scheduling +step even if the default scheduler is used. +An C is one of C, +C, C or C. +For the meaning of these loop AST generation types and the difference +between the regular loop AST generation type and the isolate +loop AST generation type, see L. +The functions C +and C +may return C if an error occurs. +The AST build options govern how an AST is generated for +the individual schedule dimensions during AST generation. +See L. +The isolate option for the given node can be extracted from these +AST build options using the function +C. + + #include + __isl_give isl_set * + isl_schedule_node_context_get_context( + __isl_keep isl_schedule_node *node); + + #include + __isl_give isl_union_set * + isl_schedule_node_domain_get_domain( + __isl_keep isl_schedule_node *node); + + #include + __isl_give isl_union_map * + isl_schedule_node_expansion_get_expansion( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_pw_multi_aff * + isl_schedule_node_expansion_get_contraction( + __isl_keep isl_schedule_node *node); + + #include + __isl_give isl_union_map * + isl_schedule_node_extension_get_extension( + __isl_keep isl_schedule_node *node); + + #include + __isl_give isl_union_set * + isl_schedule_node_filter_get_filter( + __isl_keep isl_schedule_node *node); + + #include + __isl_give isl_set *isl_schedule_node_guard_get_guard( + __isl_keep isl_schedule_node *node); + + #include + __isl_give isl_id *isl_schedule_node_mark_get_id( + __isl_keep isl_schedule_node *node); + +The following functions can be used to obtain an C, +an C or C representation of +partial schedules related to the node. + + #include + __isl_give isl_multi_union_pw_aff * + isl_schedule_node_get_prefix_schedule_multi_union_pw_aff( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_pw_multi_aff * + isl_schedule_node_get_prefix_schedule_union_pw_multi_aff( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_map * + isl_schedule_node_get_prefix_schedule_union_map( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_map * + isl_schedule_node_get_prefix_schedule_relation( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_map * + isl_schedule_node_get_subtree_schedule_union_map( + __isl_keep isl_schedule_node *node); + +In particular, the functions +C, +C +and C +return a relative ordering on the domain elements that reach the given +node determined by its ancestors. +The function C +additionally includes the domain constraints in the result. +The function C +returns a representation of the partial schedule defined by the +subtree rooted at the given node. +If the tree contains any expansion nodes, then the subtree schedule +is formulated in terms of the expanded domain elements. +The tree passed to functions returning a prefix schedule +may only contain extension nodes if these would not affect +the result of these functions. That is, if one of the ancestors +is an extension node, then all of the domain elements that were +added by the extension node need to have been filtered out +by filter nodes between the extension node and the input node. +The tree passed to C +may not contain in extension nodes in the selected subtree. + +The expansion/contraction defined by an entire subtree, combining +the expansions/contractions +on the expansion nodes in the subtree, can be obtained using +the following functions. + + #include + __isl_give isl_union_map * + isl_schedule_node_get_subtree_expansion( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_pw_multi_aff * + isl_schedule_node_get_subtree_contraction( + __isl_keep isl_schedule_node *node); + +The total number of outer band members of given node, i.e., +the shared output dimension of the maps in the result +of C can be obtained +using the following function. + + #include + int isl_schedule_node_get_schedule_depth( + __isl_keep isl_schedule_node *node); + +The following functions return the elements that reach the given node +or the union of universes in the spaces that contain these elements. + + #include + __isl_give isl_union_set * + isl_schedule_node_get_domain( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_set * + isl_schedule_node_get_universe_domain( + __isl_keep isl_schedule_node *node); + +The input tree of C +may only contain extension nodes if these would not affect +the result of this function. That is, if one of the ancestors +is an extension node, then all of the domain elements that were +added by the extension node need to have been filtered out +by filter nodes between the extension node and the input node. + +The following functions can be used to introduce additional nodes +in the schedule tree. The new node is introduced at the point +in the tree where the C points to and +the results points to the new node. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_insert_partial_schedule( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *schedule); + +This function inserts a new band node with (the greatest integer +part of) the given partial schedule. +The subtree rooted at the given node is assumed not to have +any anchored nodes. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_insert_context( + __isl_take isl_schedule_node *node, + __isl_take isl_set *context); + +This function inserts a new context node with the given context constraints. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_insert_filter( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set *filter); + +This function inserts a new filter node with the given filter. +If the original node already pointed to a filter node, then the +two filter nodes are merged into one. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_insert_guard( + __isl_take isl_schedule_node *node, + __isl_take isl_set *guard); + +This function inserts a new guard node with the given guard constraints. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_insert_mark( + __isl_take isl_schedule_node *node, + __isl_take isl_id *mark); + +This function inserts a new mark node with the give mark identifier. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_insert_sequence( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters); + __isl_give isl_schedule_node * + isl_schedule_node_insert_set( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters); + +These functions insert a new sequence or set node with the given +filters as children. + + #include + __isl_give isl_schedule_node *isl_schedule_node_group( + __isl_take isl_schedule_node *node, + __isl_take isl_id *group_id); + +This function introduces an expansion node in between the current +node and its parent that expands instances of a space with tuple +identifier C to the original domain elements that reach +the node. The group instances are identified by the prefix schedule +of those domain elements. The ancestors of the node are adjusted +to refer to the group instances instead of the original domain +elements. The return value points to the same node in the updated +schedule tree as the input node, i.e., to the child of the newly +introduced expansion node. Grouping instances of different statements +ensures that they will be treated as a single statement by the +AST generator up to the point of the expansion node. + +The following function can be used to flatten a nested +sequence. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_sequence_splice_child( + __isl_take isl_schedule_node *node, int pos); + +That is, given a sequence node C that has another sequence node +in its child at position C (in particular, the child of that filter +node is a sequence node), attach the children of that other sequence +node as children of C, replacing the original child at position +C. + +The partial schedule of a band node can be scaled (down) or reduced using +the following functions. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_band_scale( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_val *mv); + __isl_give isl_schedule_node * + isl_schedule_node_band_scale_down( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_val *mv); + __isl_give isl_schedule_node * + isl_schedule_node_band_mod( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_val *mv); + +The spaces of the two arguments need to match. +After scaling, the partial schedule is replaced by its greatest +integer part to ensure that the schedule remains integral. + +The partial schedule of a band node can be shifted by an +C with a domain that is a superset +of the domain of the partial schedule using +the following function. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_band_shift( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *shift); + +A band node can be tiled using the following function. + + #include + __isl_give isl_schedule_node *isl_schedule_node_band_tile( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_val *sizes); + + isl_stat isl_options_set_tile_scale_tile_loops(isl_ctx *ctx, + int val); + int isl_options_get_tile_scale_tile_loops(isl_ctx *ctx); + isl_stat isl_options_set_tile_shift_point_loops(isl_ctx *ctx, + int val); + int isl_options_get_tile_shift_point_loops(isl_ctx *ctx); + +The C function tiles +the band using the given tile sizes inside its schedule. +A new child band node is created to represent the point loops and it is +inserted between the modified band and its children. +The subtree rooted at the given node is assumed not to have +any anchored nodes. +The C option specifies whether the tile +loops iterators should be scaled by the tile sizes. +If the C option is set, then the point loops +are shifted to start at zero. + +A band node can be split into two nested band nodes +using the following function. + + #include + __isl_give isl_schedule_node *isl_schedule_node_band_split( + __isl_take isl_schedule_node *node, int pos); + +The resulting outer band node contains the first C dimensions of +the schedule of C while the inner band contains the remaining dimensions. +The schedules of the two band nodes live in anonymous spaces. +The loop AST generation type options and the isolate option +are split over the two band nodes. + +A band node can be moved down to the leaves of the subtree rooted +at the band node using the following function. + + #include + __isl_give isl_schedule_node *isl_schedule_node_band_sink( + __isl_take isl_schedule_node *node); + +The subtree rooted at the given node is assumed not to have +any anchored nodes. +The result points to the node in the resulting tree that is in the same +position as the node pointed to by C in the original tree. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_order_before( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set *filter); + __isl_give isl_schedule_node * + isl_schedule_node_order_after( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set *filter); + +These functions split the domain elements that reach C +into those that satisfy C and those that do not and +arranges for the elements that do satisfy the filter to be +executed before (in case of C) +or after (in case of C) +those that do not. The order is imposed by +a sequence node, possibly reusing the grandparent of C +on two copies of the subtree attached to the original C. +Both copies are simplified with respect to their filter. + +Return a pointer to the copy of the subtree that does not +satisfy C. If there is no such copy (because all +reaching domain elements satisfy the filter), then return +the original pointer. + + #include + __isl_give isl_schedule_node * + isl_schedule_node_graft_before( + __isl_take isl_schedule_node *node, + __isl_take isl_schedule_node *graft); + __isl_give isl_schedule_node * + isl_schedule_node_graft_after( + __isl_take isl_schedule_node *node, + __isl_take isl_schedule_node *graft); + +This function inserts the C tree into the tree containing C +such that it is executed before (in case of C) +or after (in case of C) C. +The root node of C +should be an extension node where the domain of the extension +is the flat product of all outer band nodes of C. +The root node may also be a domain node. +The elements of the domain or the range of the extension may not +intersect with the domain elements that reach "node". +The schedule tree of C may not be anchored. + +The schedule tree of C is modified to include an extension node +corresponding to the root node of C as a child of the original +parent of C. The original node that C points to and the +child of the root node of C are attached to this extension node +through a sequence, with appropriate filters and with the child +of C appearing before or after the original C. + +If C already appears inside a sequence that is the child of +an extension node and if the spaces of the new domain elements +do not overlap with those of the original domain elements, +then that extension node is extended with the new extension +rather than introducing a new segment of extension and sequence nodes. + +Return a pointer to the same node in the modified tree that +C pointed to in the original tree. + +A representation of the schedule node can be printed using + + #include + __isl_give isl_printer *isl_printer_print_schedule_node( + __isl_take isl_printer *p, + __isl_keep isl_schedule_node *node); + __isl_give char *isl_schedule_node_to_str( + __isl_keep isl_schedule_node *node); + +C prints the schedule node in block format. + +=head2 Dependence Analysis + +C contains specialized functionality for performing +array dataflow analysis. That is, given a I access relation, +a collection of possible I accesses and +a collection of I accesses, +C can compute relations that describe +for each iteration of the sink access, which iterations +of which of the source access relations may have +accessed the same data element before the given iteration +of the sink access without any intermediate kill of that data element. +The resulting dependence relations map source iterations +to either the corresponding sink iterations or +pairs of corresponding sink iterations and accessed data elements. +To compute standard flow dependences, the sink should be +a read, while the sources should be writes. +If no kills are specified, +then memory based dependence analysis is performed. +If, on the other hand, all sources are also kills, +then value based dependence analysis is performed. +If any of the source accesses are marked as being I +accesses, then they are also treated as kills. +Furthermore, the specification of must-sources results +in the computation of must-dependences. +Only dependences originating in a must access not coscheduled +with any other access to the same element and without +any may accesses between the must access and the sink access +are considered to be must dependences. + +=head3 High-level Interface + +A high-level interface to dependence analysis is provided +by the following function. + + #include + __isl_give isl_union_flow * + isl_union_access_info_compute_flow( + __isl_take isl_union_access_info *access); + +The input C object describes the sink +access relations, the source access relations and a schedule, +while the output C object describes +the resulting dependence relations and the subsets of the +sink relations for which no source was found. + +An C is created, modified, copied and freed using +the following functions. + + #include + __isl_give isl_union_access_info * + isl_union_access_info_from_sink( + __isl_take isl_union_map *sink); + __isl_give isl_union_access_info * + isl_union_access_info_set_kill( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *kill); + __isl_give isl_union_access_info * + isl_union_access_info_set_may_source( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *may_source); + __isl_give isl_union_access_info * + isl_union_access_info_set_must_source( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *must_source); + __isl_give isl_union_access_info * + isl_union_access_info_set_schedule( + __isl_take isl_union_access_info *access, + __isl_take isl_schedule *schedule); + __isl_give isl_union_access_info * + isl_union_access_info_set_schedule_map( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *schedule_map); + __isl_give isl_union_access_info * + isl_union_access_info_copy( + __isl_keep isl_union_access_info *access); + __isl_null isl_union_access_info * + isl_union_access_info_free( + __isl_take isl_union_access_info *access); + +The may sources set by C +do not need to include the must sources set by +C as a subset. +The kills set by C may overlap +with the may-sources and/or must-sources. +The user is free not to call one (or more) of these functions, +in which case the corresponding set is kept to its empty default. +Similarly, the default schedule initialized by +C is empty. +The current schedule is determined by the last call to either +C or +C. +The domain of the schedule corresponds to the domains of +the access relations. In particular, the domains of the access +relations are effectively intersected with the domain of the schedule +and only the resulting accesses are considered by the dependence analysis. + +An C object can be read from input +using the following function. + + #include + __isl_give isl_union_access_info * + isl_union_access_info_read_from_file(isl_ctx *ctx, + FILE *input); + +A representation of the information contained in an object +of type C can be obtained using + + #include + __isl_give isl_printer * + isl_printer_print_union_access_info( + __isl_take isl_printer *p, + __isl_keep isl_union_access_info *access); + __isl_give char *isl_union_access_info_to_str( + __isl_keep isl_union_access_info *access); + +C prints the information in flow format. + +The output of C can be examined, +copied, and freed using the following functions. + + #include + __isl_give isl_union_map *isl_union_flow_get_must_dependence( + __isl_keep isl_union_flow *flow); + __isl_give isl_union_map *isl_union_flow_get_may_dependence( + __isl_keep isl_union_flow *flow); + __isl_give isl_union_map * + isl_union_flow_get_full_must_dependence( + __isl_keep isl_union_flow *flow); + __isl_give isl_union_map * + isl_union_flow_get_full_may_dependence( + __isl_keep isl_union_flow *flow); + __isl_give isl_union_map *isl_union_flow_get_must_no_source( + __isl_keep isl_union_flow *flow); + __isl_give isl_union_map *isl_union_flow_get_may_no_source( + __isl_keep isl_union_flow *flow); + __isl_give isl_union_flow *isl_union_flow_copy( + __isl_keep isl_union_flow *flow); + __isl_null isl_union_flow *isl_union_flow_free( + __isl_take isl_union_flow *flow); + +The relation returned by C +relates domain elements of must sources to domain elements of the sink. +The relation returned by C +relates domain elements of must or may sources to domain elements of the sink +and includes the previous relation as a subset. +The relation returned by C +relates domain elements of must sources to pairs of domain elements of the sink +and accessed data elements. +The relation returned by C +relates domain elements of must or may sources to pairs of +domain elements of the sink and accessed data elements. +This relation includes the previous relation as a subset. +The relation returned by C is the subset +of the sink relation for which no dependences have been found. +The relation returned by C is the subset +of the sink relation for which no definite dependences have been found. +That is, it contains those sink access that do not contribute to any +of the elements in the relation returned +by C. + +A representation of the information contained in an object +of type C can be obtained using + + #include + __isl_give isl_printer *isl_printer_print_union_flow( + __isl_take isl_printer *p, + __isl_keep isl_union_flow *flow); + __isl_give char *isl_union_flow_to_str( + __isl_keep isl_union_flow *flow); + +C prints the information in flow format. + +=head3 Low-level Interface + +A lower-level interface is provided by the following functions. + + #include + + typedef int (*isl_access_level_before)(void *first, void *second); + + __isl_give isl_access_info *isl_access_info_alloc( + __isl_take isl_map *sink, + void *sink_user, isl_access_level_before fn, + int max_source); + __isl_give isl_access_info *isl_access_info_add_source( + __isl_take isl_access_info *acc, + __isl_take isl_map *source, int must, + void *source_user); + __isl_null isl_access_info *isl_access_info_free( + __isl_take isl_access_info *acc); + + __isl_give isl_flow *isl_access_info_compute_flow( + __isl_take isl_access_info *acc); + + isl_stat isl_flow_foreach(__isl_keep isl_flow *deps, + isl_stat (*fn)(__isl_take isl_map *dep, int must, + void *dep_user, void *user), + void *user); + __isl_give isl_map *isl_flow_get_no_source( + __isl_keep isl_flow *deps, int must); + void isl_flow_free(__isl_take isl_flow *deps); + +The function C performs the actual +dependence analysis. The other functions are used to construct +the input for this function or to read off the output. + +The input is collected in an C, which can +be created through a call to C. +The arguments to this functions are the sink access relation +C, a token C used to identify the sink +access to the user, a callback function for specifying the +relative order of source and sink accesses, and the number +of source access relations that will be added. + +The callback function has type C. +The function is called with two user supplied tokens identifying +either a source or the sink and it should return the shared nesting +level and the relative order of the two accesses. +In particular, let I be the number of loops shared by +the two accesses. If C precedes C textually, +then the function should return I<2 * n + 1>; otherwise, +it should return I<2 * n>. +The low-level interface assumes that no sources are coscheduled. +If the information returned by the callback does not allow +the relative order to be determined, then one of the sources +is arbitrarily taken to be executed after the other(s). + +The sources can be added to the C object by performing +(at most) C calls to C. +C indicates whether the source is a I access +or a I access. Note that a multi-valued access relation +should only be marked I if every iteration in the domain +of the relation accesses I elements in its image. +The C token is again used to identify +the source access. The range of the source access relation +C should have the same dimension as the range +of the sink access relation. +The C function should usually not be +called explicitly, because it is already called implicitly by +C. + +The result of the dependence analysis is collected in an +C. There may be elements of +the sink access for which no preceding source access could be +found or for which all preceding sources are I accesses. +The relations containing these elements can be obtained through +calls to C, the first with C set +and the second with C unset. +In the case of standard flow dependence analysis, +with the sink a read and the sources I writes, +the first relation corresponds to the reads from uninitialized +array elements and the second relation is empty. +The actual flow dependences can be extracted using +C. This function will call the user-specified +callback function C for each B dependence between +a source and the sink. The callback function is called +with four arguments, the actual flow dependence relation +mapping source iterations to sink iterations, a boolean that +indicates whether it is a I or I dependence, a token +identifying the source and an additional C with value +equal to the third argument of the C call. +A dependence is marked I if it originates from a I +source and if it is not followed by any I sources. + +After finishing with an C, the user should call +C to free all associated memory. + +=head3 Interaction with the Low-level Interface + +During the dependence analysis, we frequently need to perform +the following operation. Given a relation between sink iterations +and potential source iterations from a particular source domain, +what is the last potential source iteration corresponding to each +sink iteration. It can sometimes be convenient to adjust +the set of potential source iterations before or after each such operation. +The prototypical example is fuzzy array dataflow analysis, +where we need to analyze if, based on data-dependent constraints, +the sink iteration can ever be executed without one or more of +the corresponding potential source iterations being executed. +If so, we can introduce extra parameters and select an unknown +but fixed source iteration from the potential source iterations. +To be able to perform such manipulations, C provides the following +function. + + #include + + typedef __isl_give isl_restriction *(*isl_access_restrict)( + __isl_keep isl_map *source_map, + __isl_keep isl_set *sink, void *source_user, + void *user); + __isl_give isl_access_info *isl_access_info_set_restrict( + __isl_take isl_access_info *acc, + isl_access_restrict fn, void *user); + +The function C should be called +before calling C and registers a callback function +that will be called any time C is about to compute the last +potential source. The first argument is the (reverse) proto-dependence, +mapping sink iterations to potential source iterations. +The second argument represents the sink iterations for which +we want to compute the last source iteration. +The third argument is the token corresponding to the source +and the final argument is the token passed to C. +The callback is expected to return a restriction on either the input or +the output of the operation computing the last potential source. +If the input needs to be restricted then restrictions are needed +for both the source and the sink iterations. The sink iterations +and the potential source iterations will be intersected with these sets. +If the output needs to be restricted then only a restriction on the source +iterations is required. +If any error occurs, the callback should return C. +An C object can be created, freed and inspected +using the following functions. + + #include + + __isl_give isl_restriction *isl_restriction_input( + __isl_take isl_set *source_restr, + __isl_take isl_set *sink_restr); + __isl_give isl_restriction *isl_restriction_output( + __isl_take isl_set *source_restr); + __isl_give isl_restriction *isl_restriction_none( + __isl_take isl_map *source_map); + __isl_give isl_restriction *isl_restriction_empty( + __isl_take isl_map *source_map); + __isl_null isl_restriction *isl_restriction_free( + __isl_take isl_restriction *restr); + +C and C are special +cases of C. C +is essentially equivalent to + + isl_restriction_input(isl_set_universe( + isl_space_range(isl_map_get_space(source_map))), + isl_set_universe( + isl_space_domain(isl_map_get_space(source_map)))); + +whereas C is essentially equivalent to + + isl_restriction_input(isl_set_empty( + isl_space_range(isl_map_get_space(source_map))), + isl_set_universe( + isl_space_domain(isl_map_get_space(source_map)))); + +=head2 Scheduling + + #include + __isl_give isl_schedule * + isl_schedule_constraints_compute_schedule( + __isl_take isl_schedule_constraints *sc); + +The function C can be +used to compute a schedule that satisfies the given schedule constraints. +These schedule constraints include the iteration domain for which +a schedule should be computed and dependences between pairs of +iterations. In particular, these dependences include +I dependences and I dependences. +By default, the algorithm used to construct the schedule is similar +to that of C. +Alternatively, Feautrier's multi-dimensional scheduling algorithm can +be selected. +The generated schedule respects all validity dependences. +That is, all dependence distances over these dependences in the +scheduled space are lexicographically positive. + +The default algorithm tries to ensure that the dependence distances +over coincidence constraints are zero and to minimize the +dependence distances over proximity dependences. +Moreover, it tries to obtain sequences (bands) of schedule dimensions +for groups of domains where the dependence distances over validity +dependences have only non-negative values. +Note that when minimizing the maximal dependence distance +over proximity dependences, a single affine expression in the parameters +is constructed that bounds all dependence distances. If no such expression +exists, then the algorithm will fail and resort to an alternative +scheduling algorithm. In particular, this means that adding proximity +dependences may eliminate valid solutions. A typical example where this +phenomenon may occur is when some subset of the proximity dependences +has no restriction on some parameter, forcing the coefficient of that +parameter to be zero, while some other subset forces the dependence +distance to depend on that parameter, requiring the same coefficient +to be non-zero. +When using Feautrier's algorithm, the coincidence and proximity constraints +are only taken into account during the extension to a +full-dimensional schedule. + +An C object can be constructed +and manipulated using the following functions. + + #include + __isl_give isl_schedule_constraints * + isl_schedule_constraints_copy( + __isl_keep isl_schedule_constraints *sc); + __isl_give isl_schedule_constraints * + isl_schedule_constraints_on_domain( + __isl_take isl_union_set *domain); + __isl_give isl_schedule_constraints * + isl_schedule_constraints_set_context( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_set *context); + __isl_give isl_schedule_constraints * + isl_schedule_constraints_set_validity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *validity); + __isl_give isl_schedule_constraints * + isl_schedule_constraints_set_coincidence( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *coincidence); + __isl_give isl_schedule_constraints * + isl_schedule_constraints_set_proximity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *proximity); + __isl_give isl_schedule_constraints * + isl_schedule_constraints_set_conditional_validity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *condition, + __isl_take isl_union_map *validity); + __isl_give isl_schedule_constraints * + isl_schedule_constraints_apply( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *umap); + __isl_null isl_schedule_constraints * + isl_schedule_constraints_free( + __isl_take isl_schedule_constraints *sc); + +The initial C object created by +C does not impose any constraints. +That is, it has an empty set of dependences. +The function C allows the user +to specify additional constraints on the parameters that may +be assumed to hold during the construction of the schedule. +The function C replaces the +validity dependences, mapping domain elements I to domain +elements that should be scheduled after I. +The function C replaces the +coincidence dependences, mapping domain elements I to domain +elements that should be scheduled together with I, if possible. +The function C replaces the +proximity dependences, mapping domain elements I to domain +elements that should be scheduled either before I +or as early as possible after I. + +The function C +replaces the conditional validity constraints. +A conditional validity constraint is only imposed when any of the corresponding +conditions is satisfied, i.e., when any of them is non-zero. +That is, the scheduler ensures that within each band if the dependence +distances over the condition constraints are not all zero +then all corresponding conditional validity constraints are respected. +A conditional validity constraint corresponds to a condition +if the two are adjacent, i.e., if the domain of one relation intersect +the range of the other relation. +The typical use case of conditional validity constraints is +to allow order constraints between live ranges to be violated +as long as the live ranges themselves are local to the band. +To allow more fine-grained control over which conditions correspond +to which conditional validity constraints, the domains and ranges +of these relations may include I. That is, the domains and +ranges of those relation may themselves be wrapped relations +where the iteration domain appears in the domain of those wrapped relations +and the range of the wrapped relations can be arbitrarily chosen +by the user. Conditions and conditional validity constraints are only +considered adjacent to each other if the entire wrapped relation matches. +In particular, a relation with a tag will never be considered adjacent +to a relation without a tag. + +The function C takes +schedule constraints that are defined on some set of domain elements +and transforms them to schedule constraints on the elements +to which these domain elements are mapped by the given transformation. + +An C object can be inspected +using the following functions. + + #include + __isl_give isl_union_set * + isl_schedule_constraints_get_domain( + __isl_keep isl_schedule_constraints *sc); + __isl_give isl_set *isl_schedule_constraints_get_context( + __isl_keep isl_schedule_constraints *sc); + __isl_give isl_union_map * + isl_schedule_constraints_get_validity( + __isl_keep isl_schedule_constraints *sc); + __isl_give isl_union_map * + isl_schedule_constraints_get_coincidence( + __isl_keep isl_schedule_constraints *sc); + __isl_give isl_union_map * + isl_schedule_constraints_get_proximity( + __isl_keep isl_schedule_constraints *sc); + __isl_give isl_union_map * + isl_schedule_constraints_get_conditional_validity( + __isl_keep isl_schedule_constraints *sc); + __isl_give isl_union_map * + isl_schedule_constraints_get_conditional_validity_condition( + __isl_keep isl_schedule_constraints *sc); + +An C object can be read from input +using the following functions. + + #include + __isl_give isl_schedule_constraints * + isl_schedule_constraints_read_from_str(isl_ctx *ctx, + const char *str); + __isl_give isl_schedule_constraints * + isl_schedule_constraints_read_from_file(isl_ctx *ctx, + FILE *input); + +The contents of an C object can be printed +using the following functions. + + #include + __isl_give isl_printer * + isl_printer_print_schedule_constraints( + __isl_take isl_printer *p, + __isl_keep isl_schedule_constraints *sc); + __isl_give char *isl_schedule_constraints_to_str( + __isl_keep isl_schedule_constraints *sc); + +The following function computes a schedule directly from +an iteration domain and validity and proximity dependences +and is implemented in terms of the functions described above. +The use of C is discouraged. + + #include + __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); + +The generated schedule represents a schedule tree. +For more information on schedule trees, see +L. + +=head3 Options + + #include + isl_stat isl_options_set_schedule_max_coefficient( + isl_ctx *ctx, int val); + int isl_options_get_schedule_max_coefficient( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_max_constant_term( + isl_ctx *ctx, int val); + int isl_options_get_schedule_max_constant_term( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_serialize_sccs( + isl_ctx *ctx, int val); + int isl_options_get_schedule_serialize_sccs(isl_ctx *ctx); + isl_stat isl_options_set_schedule_whole_component( + isl_ctx *ctx, int val); + int isl_options_get_schedule_whole_component( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_maximize_band_depth( + isl_ctx *ctx, int val); + int isl_options_get_schedule_maximize_band_depth( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_maximize_coincidence( + isl_ctx *ctx, int val); + int isl_options_get_schedule_maximize_coincidence( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_outer_coincidence( + isl_ctx *ctx, int val); + int isl_options_get_schedule_outer_coincidence( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_split_scaled( + isl_ctx *ctx, int val); + int isl_options_get_schedule_split_scaled( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_treat_coalescing( + isl_ctx *ctx, int val); + int isl_options_get_schedule_treat_coalescing( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_algorithm( + isl_ctx *ctx, int val); + int isl_options_get_schedule_algorithm( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_carry_self_first( + isl_ctx *ctx, int val); + int isl_options_get_schedule_carry_self_first( + isl_ctx *ctx); + isl_stat isl_options_set_schedule_separate_components( + isl_ctx *ctx, int val); + int isl_options_get_schedule_separate_components( + isl_ctx *ctx); + +=over + +=item * schedule_max_coefficient + +This option enforces that the coefficients for variable and parameter +dimensions in the calculated schedule are not larger than the specified value. +This option can significantly increase the speed of the scheduling calculation +and may also prevent fusing of unrelated dimensions. A value of -1 means that +this option does not introduce bounds on the variable or parameter +coefficients. + +=item * schedule_max_constant_term + +This option enforces that the constant coefficients in the calculated schedule +are not larger than the maximal constant term. This option can significantly +increase the speed of the scheduling calculation and may also prevent fusing of +unrelated dimensions. A value of -1 means that this option does not introduce +bounds on the constant coefficients. + +=item * schedule_serialize_sccs + +If this option is set, then all strongly connected components +in the dependence graph are serialized as soon as they are detected. +This means in particular that instances of statements will only +appear in the same band node if these statements belong +to the same strongly connected component at the point where +the band node is constructed. + +=item * schedule_whole_component + +If this option is set, then entire (weakly) connected +components in the dependence graph are scheduled together +as a whole. +Otherwise, each strongly connected component within +such a weakly connected component is first scheduled separately +and then combined with other strongly connected components. +This option has no effect if C is set. + +=item * schedule_maximize_band_depth + +If this option is set, then the scheduler tries to maximize +the width of the bands. Wider bands give more possibilities for tiling. +In particular, if the C option is set, +then bands are split if this might result in wider bands. +Otherwise, the effect of this option is to only allow +strongly connected components to be combined if this does +not reduce the width of the bands. +Note that if the C options is set, then +the C option therefore has no effect. + +=item * schedule_maximize_coincidence + +This option is only effective if the C +option is turned off. +If the C option is set, then (clusters of) +strongly connected components are only combined with each other +if this does not reduce the number of coincident band members. + +=item * schedule_outer_coincidence + +If this option is set, then we try to construct schedules +where the outermost scheduling dimension in each band +satisfies the coincidence constraints. + +=item * schedule_algorithm + +Selects the scheduling algorithm to be used. +Available scheduling algorithms are C +and C. + +=item * schedule_split_scaled + +If this option is set, then we try to construct schedules in which the +constant term is split off from the linear part if the linear parts of +the scheduling rows for all nodes in the graph have a common non-trivial +divisor. +The constant term is then dropped and the linear +part is reduced. +This option is only effective when the Feautrier style scheduler is +being used, either as the main scheduler or as a fallback for the +Pluto-like scheduler. + +=item * schedule_treat_coalescing + +If this option is set, then the scheduler will try and avoid +producing schedules that perform loop coalescing. +In particular, for the Pluto-like scheduler, this option places +bounds on the schedule coefficients based on the sizes of the instance sets. +For the Feautrier style scheduler, this option detects potentially +coalescing schedules and then tries to adjust the schedule to avoid +the coalescing. + +=item * schedule_carry_self_first + +If this option is set, then the Feautrier style scheduler +(when used as a fallback for the Pluto-like scheduler) will +first try to only carry self-dependences. + +=item * schedule_separate_components + +If this option is set then the function C +will treat set nodes in the same way as sequence nodes. + +=back + +=head2 AST Generation + +This section describes the C functionality for generating +ASTs that visit all the elements +in a domain in an order specified by a schedule tree or +a schedule map. +In case the schedule given as a C, an AST is generated +that visits all the elements in the domain of the C +according to the lexicographic order of the corresponding image +element(s). If the range of the C consists of +elements in more than one space, then each of these spaces is handled +separately in an arbitrary order. +It should be noted that the schedule tree or the image elements +in a schedule map only specify the I +in which the corresponding domain elements should be visited. +No direct relation between the partial schedule values +or the image elements on the one hand and the loop iterators +in the generated AST on the other hand should be assumed. + +Each AST is generated within a build. The initial build +simply specifies the constraints on the parameters (if any) +and can be created, inspected, copied and freed using the following functions. + + #include + __isl_give isl_ast_build *isl_ast_build_alloc( + isl_ctx *ctx); + __isl_give isl_ast_build *isl_ast_build_from_context( + __isl_take isl_set *set); + __isl_give isl_ast_build *isl_ast_build_copy( + __isl_keep isl_ast_build *build); + __isl_null isl_ast_build *isl_ast_build_free( + __isl_take isl_ast_build *build); + +The C argument is usually a parameter set with zero or more parameters. +In fact, when creating an AST using C, +this set is required to be a parameter set. +An C created using C does not +specify any parameter constraints. +More C functions are described in L +and L. +Finally, the AST itself can be constructed using one of the following +functions. + + #include + __isl_give isl_ast_node *isl_ast_build_node_from_schedule( + __isl_keep isl_ast_build *build, + __isl_take isl_schedule *schedule); + __isl_give isl_ast_node * + isl_ast_build_node_from_schedule_map( + __isl_keep isl_ast_build *build, + __isl_take isl_union_map *schedule); + +=head3 Inspecting the AST + +The basic properties of an AST node can be obtained as follows. + + #include + enum isl_ast_node_type isl_ast_node_get_type( + __isl_keep isl_ast_node *node); + +The type of an AST node is one of +C, +C, +C, +C or +C. +An C represents a for node. +An C represents an if node. +An C represents a compound node. +An C introduces a mark in the AST. +An C represents an expression statement. +An expression statement typically corresponds to a domain element, i.e., +one of the elements that is visited by the AST. + +Each type of node has its own additional properties. + + #include + __isl_give isl_ast_expr *isl_ast_node_for_get_iterator( + __isl_keep isl_ast_node *node); + __isl_give isl_ast_expr *isl_ast_node_for_get_init( + __isl_keep isl_ast_node *node); + __isl_give isl_ast_expr *isl_ast_node_for_get_cond( + __isl_keep isl_ast_node *node); + __isl_give isl_ast_expr *isl_ast_node_for_get_inc( + __isl_keep isl_ast_node *node); + __isl_give isl_ast_node *isl_ast_node_for_get_body( + __isl_keep isl_ast_node *node); + isl_bool isl_ast_node_for_is_degenerate( + __isl_keep isl_ast_node *node); + +An C is considered degenerate if it is known to execute +exactly once. + + #include + __isl_give isl_ast_expr *isl_ast_node_if_get_cond( + __isl_keep isl_ast_node *node); + __isl_give isl_ast_node *isl_ast_node_if_get_then( + __isl_keep isl_ast_node *node); + isl_bool isl_ast_node_if_has_else( + __isl_keep isl_ast_node *node); + __isl_give isl_ast_node *isl_ast_node_if_get_else( + __isl_keep isl_ast_node *node); + + __isl_give isl_ast_node_list * + isl_ast_node_block_get_children( + __isl_keep isl_ast_node *node); + + __isl_give isl_id *isl_ast_node_mark_get_id( + __isl_keep isl_ast_node *node); + __isl_give isl_ast_node *isl_ast_node_mark_get_node( + __isl_keep isl_ast_node *node); + +C returns the identifier of the mark. +C returns the child node that is being marked. + + #include + __isl_give isl_ast_expr *isl_ast_node_user_get_expr( + __isl_keep isl_ast_node *node); + +All descendants of a specific node in the AST (including the node itself) +can be visited +in depth-first pre-order using the following function. + + #include + isl_stat isl_ast_node_foreach_descendant_top_down( + __isl_keep isl_ast_node *node, + isl_bool (*fn)(__isl_keep isl_ast_node *node, + void *user), void *user); + +The callback function should return C if the children +of the given node should be visited and C if they should not. +It should return C in case of failure, in which case +the entire traversal is aborted. + +Each of the returned Cs can in turn be inspected using +the following functions. + + #include + enum isl_ast_expr_type isl_ast_expr_get_type( + __isl_keep isl_ast_expr *expr); + +The type of an AST expression is one of +C, +C or +C. +An C represents the result of an operation. +An C represents an identifier. +An C represents an integer value. + +Each type of expression has its own additional properties. + + #include + enum isl_ast_op_type isl_ast_expr_get_op_type( + __isl_keep isl_ast_expr *expr); + int isl_ast_expr_get_op_n_arg(__isl_keep isl_ast_expr *expr); + __isl_give isl_ast_expr *isl_ast_expr_get_op_arg( + __isl_keep isl_ast_expr *expr, int pos); + isl_stat isl_ast_expr_foreach_ast_op_type( + __isl_keep isl_ast_expr *expr, + isl_stat (*fn)(enum isl_ast_op_type type, + void *user), void *user); + isl_stat isl_ast_node_foreach_ast_op_type( + __isl_keep isl_ast_node *node, + isl_stat (*fn)(enum isl_ast_op_type type, + void *user), void *user); + +C returns the type of the operation +performed. C returns the number of +arguments. C returns the specified +argument. +C calls C for each distinct +C that appears in C. +C does the same for each distinct +C that appears in C. +The operation type is one of the following. + +=over + +=item C + +Logical I of two arguments. +Both arguments can be evaluated. + +=item C + +Logical I of two arguments. +The second argument can only be evaluated if the first evaluates to true. + +=item C + +Logical I of two arguments. +Both arguments can be evaluated. + +=item C + +Logical I of two arguments. +The second argument can only be evaluated if the first evaluates to false. + +=item C + +Maximum of two or more arguments. + +=item C + +Minimum of two or more arguments. + +=item C + +Change sign. + +=item C + +Sum of two arguments. + +=item C + +Difference of two arguments. + +=item C + +Product of two arguments. + +=item C + +Exact division. That is, the result is known to be an integer. + +=item C + +Result of integer division, rounded towards negative +infinity. + +=item C + +Result of integer division, where dividend is known to be non-negative. + +=item C + +Remainder of integer division, where dividend is known to be non-negative. + +=item C + +Equal to zero iff the remainder on integer division is zero. + +=item C + +Conditional operator defined on three arguments. +If the first argument evaluates to true, then the result +is equal to the second argument. Otherwise, the result +is equal to the third argument. +The second and third argument may only be evaluated if +the first argument evaluates to true and false, respectively. +Corresponds to C in C. + +=item C + +Conditional operator defined on three arguments. +If the first argument evaluates to true, then the result +is equal to the second argument. Otherwise, the result +is equal to the third argument. +The second and third argument may be evaluated independently +of the value of the first argument. +Corresponds to C in C. + +=item C + +Equality relation. + +=item C + +Less than or equal relation. + +=item C + +Less than relation. + +=item C + +Greater than or equal relation. + +=item C + +Greater than relation. + +=item C + +A function call. +The number of arguments of the C is one more than +the number of arguments in the function call, the first argument +representing the function being called. + +=item C + +An array access. +The number of arguments of the C is one more than +the number of index expressions in the array access, the first argument +representing the array being accessed. + +=item C + +A member access. +This operation has two arguments, a structure and the name of +the member of the structure being accessed. + +=back + + #include + __isl_give isl_id *isl_ast_expr_get_id( + __isl_keep isl_ast_expr *expr); + +Return the identifier represented by the AST expression. + + #include + __isl_give isl_val *isl_ast_expr_get_val( + __isl_keep isl_ast_expr *expr); + +Return the integer represented by the AST expression. + +=head3 Properties of ASTs + + #include + isl_bool isl_ast_expr_is_equal( + __isl_keep isl_ast_expr *expr1, + __isl_keep isl_ast_expr *expr2); + +Check if two Cs are equal to each other. + +=head3 Manipulating and printing the AST + +AST nodes can be copied and freed using the following functions. + + #include + __isl_give isl_ast_node *isl_ast_node_copy( + __isl_keep isl_ast_node *node); + __isl_null isl_ast_node *isl_ast_node_free( + __isl_take isl_ast_node *node); + +AST expressions can be copied and freed using the following functions. + + #include + __isl_give isl_ast_expr *isl_ast_expr_copy( + __isl_keep isl_ast_expr *expr); + __isl_null isl_ast_expr *isl_ast_expr_free( + __isl_take isl_ast_expr *expr); + +New AST expressions can be created either directly or within +the context of an C. + + #include + __isl_give isl_ast_expr *isl_ast_expr_from_val( + __isl_take isl_val *v); + __isl_give isl_ast_expr *isl_ast_expr_from_id( + __isl_take isl_id *id); + __isl_give isl_ast_expr *isl_ast_expr_neg( + __isl_take isl_ast_expr *expr); + __isl_give isl_ast_expr *isl_ast_expr_address_of( + __isl_take isl_ast_expr *expr); + __isl_give isl_ast_expr *isl_ast_expr_add( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_sub( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_mul( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_div( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_pdiv_q( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_pdiv_r( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_and( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) + __isl_give isl_ast_expr *isl_ast_expr_and_then( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) + __isl_give isl_ast_expr *isl_ast_expr_or( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) + __isl_give isl_ast_expr *isl_ast_expr_or_else( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) + __isl_give isl_ast_expr *isl_ast_expr_eq( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_le( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_lt( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_ge( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_gt( + __isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); + __isl_give isl_ast_expr *isl_ast_expr_access( + __isl_take isl_ast_expr *array, + __isl_take isl_ast_expr_list *indices); + __isl_give isl_ast_expr *isl_ast_expr_call( + __isl_take isl_ast_expr *function, + __isl_take isl_ast_expr_list *arguments); + +The function C can be applied to an +C of type C only. It is meant +to represent the address of the C. The function +C as well as C are short-circuit +versions of C and C, respectively. + + #include + __isl_give isl_ast_expr *isl_ast_build_expr_from_set( + __isl_keep isl_ast_build *build, + __isl_take isl_set *set); + __isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff( + __isl_keep isl_ast_build *build, + __isl_take isl_pw_aff *pa); + __isl_give isl_ast_expr * + isl_ast_build_access_from_pw_multi_aff( + __isl_keep isl_ast_build *build, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_ast_expr * + isl_ast_build_access_from_multi_pw_aff( + __isl_keep isl_ast_build *build, + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_ast_expr * + isl_ast_build_call_from_pw_multi_aff( + __isl_keep isl_ast_build *build, + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_ast_expr * + isl_ast_build_call_from_multi_pw_aff( + __isl_keep isl_ast_build *build, + __isl_take isl_multi_pw_aff *mpa); + +The set and +the domains of C, C and C should correspond +to the schedule space of C. +The tuple id of C or C is used as the array being accessed or +the function being called. +If the accessed space is a nested relation, then it is taken +to represent an access of the member specified by the range +of this nested relation of the structure specified by the domain +of the nested relation. + +The following functions can be used to modify an C. + + #include + __isl_give isl_ast_expr *isl_ast_expr_set_op_arg( + __isl_take isl_ast_expr *expr, int pos, + __isl_take isl_ast_expr *arg); + +Replace the argument of C at position C by C. + + #include + __isl_give isl_ast_expr *isl_ast_expr_substitute_ids( + __isl_take isl_ast_expr *expr, + __isl_take isl_id_to_ast_expr *id2expr); + +The function C replaces the +subexpressions of C of type C +by the corresponding expression in C, if there is any. + + +User specified data can be attached to an C and obtained +from the same C using the following functions. + + #include + __isl_give isl_ast_node *isl_ast_node_set_annotation( + __isl_take isl_ast_node *node, + __isl_take isl_id *annotation); + __isl_give isl_id *isl_ast_node_get_annotation( + __isl_keep isl_ast_node *node); + +Basic printing can be performed using the following functions. + + #include + __isl_give isl_printer *isl_printer_print_ast_expr( + __isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr); + __isl_give isl_printer *isl_printer_print_ast_node( + __isl_take isl_printer *p, + __isl_keep isl_ast_node *node); + __isl_give char *isl_ast_expr_to_str( + __isl_keep isl_ast_expr *expr); + __isl_give char *isl_ast_node_to_str( + __isl_keep isl_ast_node *node); + __isl_give char *isl_ast_expr_to_C_str( + __isl_keep isl_ast_expr *expr); + __isl_give char *isl_ast_node_to_C_str( + __isl_keep isl_ast_node *node); + +The functions C and +C are convenience functions +that return a string representation of the input in C format. + +More advanced printing can be performed using the following functions. + + #include + __isl_give isl_printer *isl_ast_op_type_set_print_name( + __isl_take isl_printer *p, + enum isl_ast_op_type type, + __isl_keep const char *name); + isl_stat isl_options_set_ast_print_macro_once( + isl_ctx *ctx, int val); + int isl_options_get_ast_print_macro_once(isl_ctx *ctx); + __isl_give isl_printer *isl_ast_op_type_print_macro( + enum isl_ast_op_type type, + __isl_take isl_printer *p); + __isl_give isl_printer *isl_ast_expr_print_macros( + __isl_keep isl_ast_expr *expr, + __isl_take isl_printer *p); + __isl_give isl_printer *isl_ast_node_print_macros( + __isl_keep isl_ast_node *node, + __isl_take isl_printer *p); + __isl_give isl_printer *isl_ast_node_print( + __isl_keep isl_ast_node *node, + __isl_take isl_printer *p, + __isl_take isl_ast_print_options *options); + __isl_give isl_printer *isl_ast_node_for_print( + __isl_keep isl_ast_node *node, + __isl_take isl_printer *p, + __isl_take isl_ast_print_options *options); + __isl_give isl_printer *isl_ast_node_if_print( + __isl_keep isl_ast_node *node, + __isl_take isl_printer *p, + __isl_take isl_ast_print_options *options); + +While printing an C in C, +C may print out an AST that makes use of macros such +as C, C and C. +The names of these macros may be modified by a call +to C. The user-specified +names are associated to the printer object. +C prints out the macro +corresponding to a specific C. +If the print-macro-once option is set, then a given macro definition +is only printed once to any given printer object. +C scans the C +for subexpressions where these macros would be used and prints +out the required macro definitions. +Essentially, C calls +C with C +as function argument. +C does the same +for expressions in its C argument. +C, C and +C print an C +in C, but allow for some extra control +through an C object. +This object can be created using the following functions. + + #include + __isl_give isl_ast_print_options * + isl_ast_print_options_alloc(isl_ctx *ctx); + __isl_give isl_ast_print_options * + isl_ast_print_options_copy( + __isl_keep isl_ast_print_options *options); + __isl_null isl_ast_print_options * + isl_ast_print_options_free( + __isl_take isl_ast_print_options *options); + + __isl_give isl_ast_print_options * + isl_ast_print_options_set_print_user( + __isl_take isl_ast_print_options *options, + __isl_give isl_printer *(*print_user)( + __isl_take isl_printer *p, + __isl_take isl_ast_print_options *options, + __isl_keep isl_ast_node *node, void *user), + void *user); + __isl_give isl_ast_print_options * + isl_ast_print_options_set_print_for( + __isl_take isl_ast_print_options *options, + __isl_give isl_printer *(*print_for)( + __isl_take isl_printer *p, + __isl_take isl_ast_print_options *options, + __isl_keep isl_ast_node *node, void *user), + void *user); + +The callback set by C +is called whenever a node of type C needs to +be printed. +The callback set by C +is called whenever a node of type C needs to +be printed. +Note that C will I call the +callback set by C on the node +on which C is called, but only on nested +nodes of type C. It is therefore safe to +call C from within the callback set by +C. + +The following option determines the type to be used for iterators +while printing the AST. + + isl_stat isl_options_set_ast_iterator_type( + isl_ctx *ctx, const char *val); + const char *isl_options_get_ast_iterator_type( + isl_ctx *ctx); + +The AST printer only prints body nodes as blocks if these +blocks cannot be safely omitted. +For example, a C node with one body node will not be +surrounded with braces in C. +A block will always be printed by setting the following option. + + isl_stat isl_options_set_ast_always_print_block(isl_ctx *ctx, + int val); + int isl_options_get_ast_always_print_block(isl_ctx *ctx); + +=head3 Options + + #include + isl_stat isl_options_set_ast_build_atomic_upper_bound( + isl_ctx *ctx, int val); + int isl_options_get_ast_build_atomic_upper_bound( + isl_ctx *ctx); + isl_stat isl_options_set_ast_build_prefer_pdiv(isl_ctx *ctx, + int val); + int isl_options_get_ast_build_prefer_pdiv(isl_ctx *ctx); + isl_stat isl_options_set_ast_build_detect_min_max( + isl_ctx *ctx, int val); + int isl_options_get_ast_build_detect_min_max( + isl_ctx *ctx); + isl_stat isl_options_set_ast_build_exploit_nested_bounds( + isl_ctx *ctx, int val); + int isl_options_get_ast_build_exploit_nested_bounds( + isl_ctx *ctx); + isl_stat isl_options_set_ast_build_group_coscheduled( + isl_ctx *ctx, int val); + int isl_options_get_ast_build_group_coscheduled( + isl_ctx *ctx); + isl_stat isl_options_set_ast_build_scale_strides( + isl_ctx *ctx, int val); + int isl_options_get_ast_build_scale_strides( + isl_ctx *ctx); + isl_stat isl_options_set_ast_build_allow_else(isl_ctx *ctx, + int val); + int isl_options_get_ast_build_allow_else(isl_ctx *ctx); + isl_stat isl_options_set_ast_build_allow_or(isl_ctx *ctx, + int val); + int isl_options_get_ast_build_allow_or(isl_ctx *ctx); + +=over + +=item * ast_build_atomic_upper_bound + +Generate loop upper bounds that consist of the current loop iterator, +an operator and an expression not involving the iterator. +If this option is not set, then the current loop iterator may appear +several times in the upper bound. +For example, when this option is turned off, AST generation +for the schedule + + [n] -> { A[i] -> [i] : 0 <= i <= 100, n } + +produces + + for (int c0 = 0; c0 <= 100 && n >= c0; c0 += 1) + A(c0); + +When the option is turned on, the following AST is generated + + for (int c0 = 0; c0 <= min(100, n); c0 += 1) + A(c0); + +=item * ast_build_prefer_pdiv + +If this option is turned off, then the AST generation will +produce ASTs that may only contain C +operators, but no C or +C operators. +If this option is turned on, then C will try to convert +some of the C operators to (expressions containing) +C or C operators. + +=item * ast_build_detect_min_max + +If this option is turned on, then C will try and detect +min or max-expressions when building AST expressions from +piecewise affine expressions. + +=item * ast_build_exploit_nested_bounds + +Simplify conditions based on bounds of nested for loops. +In particular, remove conditions that are implied by the fact +that one or more nested loops have at least one iteration, +meaning that the upper bound is at least as large as the lower bound. +For example, when this option is turned off, AST generation +for the schedule + + [N,M] -> { A[i,j] -> [i,j] : 0 <= i <= N and + 0 <= j <= M } + +produces + + if (M >= 0) + for (int c0 = 0; c0 <= N; c0 += 1) + for (int c1 = 0; c1 <= M; c1 += 1) + A(c0, c1); + +When the option is turned on, the following AST is generated + + for (int c0 = 0; c0 <= N; c0 += 1) + for (int c1 = 0; c1 <= M; c1 += 1) + A(c0, c1); + +=item * ast_build_group_coscheduled + +If two domain elements are assigned the same schedule point, then +they may be executed in any order and they may even appear in different +loops. If this options is set, then the AST generator will make +sure that coscheduled domain elements do not appear in separate parts +of the AST. This is useful in case of nested AST generation +if the outer AST generation is given only part of a schedule +and the inner AST generation should handle the domains that are +coscheduled by this initial part of the schedule together. +For example if an AST is generated for a schedule + + { A[i] -> [0]; B[i] -> [0] } + +then the C callback described +below may get called twice, once for each domain. +Setting this option ensures that the callback is only called once +on both domains together. + +=item * ast_build_separation_bounds + +This option specifies which bounds to use during separation. +If this option is set to C +then all (possibly implicit) bounds on the current dimension will +be used during separation. +If this option is set to C +then only those bounds that are explicitly available will +be used during separation. + +=item * ast_build_scale_strides + +This option specifies whether the AST generator is allowed +to scale down iterators of strided loops. + +=item * ast_build_allow_else + +This option specifies whether the AST generator is allowed +to construct if statements with else branches. + +=item * ast_build_allow_or + +This option specifies whether the AST generator is allowed +to construct if conditions with disjunctions. + +=back + +=head3 AST Generation Options (Schedule Tree) + +In case of AST construction from a schedule tree, the options +that control how an AST is created from the individual schedule +dimensions are stored in the band nodes of the tree +(see L). + +In particular, a schedule dimension can be handled in four +different ways, atomic, separate, unroll or the default. +This loop AST generation type can be set using +C. +Alternatively, +the first three can be selected by including a one-dimensional +element with as value the position of the schedule dimension +within the band and as name one of C, C +or C in the options +set by C. +Only one of these three may be specified for +any given schedule dimension within a band node. +If none of these is specified, then the default +is used. The meaning of the options is as follows. + +=over + +=item C + +When this option is specified, the AST generator will make +sure that a given domains space only appears in a single +loop at the specified level. + +For example, for the schedule tree + + domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }" + child: + schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]" + options: "{ atomic[x] }" + +the following AST will be generated + + for (int c0 = 0; c0 <= 10; c0 += 1) { + if (c0 >= 1) + b(c0 - 1); + if (c0 <= 9) + a(c0); + } + +On the other hand, for the schedule tree + + domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }" + child: + schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]" + options: "{ separate[x] }" + +the following AST will be generated + + { + a(0); + for (int c0 = 1; c0 <= 9; c0 += 1) { + b(c0 - 1); + a(c0); + } + b(9); + } + +If neither C nor C is specified, then the AST generator +may produce either of these two results or some intermediate form. + +=item C + +When this option is specified, the AST generator will +split the domain of the specified schedule dimension +into pieces with a fixed set of statements for which +instances need to be executed by the iterations in +the schedule domain part. This option tends to avoid +the generation of guards inside the corresponding loops. +See also the C option. + +=item C + +When this option is specified, the AST generator will +I unroll the corresponding schedule dimension. +It is the responsibility of the user to ensure that such +unrolling is possible. +To obtain a partial unrolling, the user should apply an additional +strip-mining to the schedule and fully unroll the inner schedule +dimension. + +=back + +The C option is a bit more involved. It allows the user +to isolate a range of schedule dimension values from smaller and +greater values. Additionally, the user may specify a different +atomic/separate/unroll choice for the isolated part and the remaining +parts. The typical use case of the C option is to isolate +full tiles from partial tiles. +The part that needs to be isolated may depend on outer schedule dimensions. +The option therefore needs to be able to reference those outer schedule +dimensions. In particular, the space of the C option is that +of a wrapped map with as domain the flat product of all outer band nodes +and as range the space of the current band node. +The atomic/separate/unroll choice for the isolated part is determined +by an option that lives in an unnamed wrapped space with as domain +a zero-dimensional C space and as range the regular +C, C or C space. +This option may also be set directly using +C. +The atomic/separate/unroll choice for the remaining part is determined +by the regular C, C or C option. +Since the C option references outer schedule dimensions, +its use in a band node causes any tree containing the node +to be considered anchored. + +As an example, consider the isolation of full tiles from partial tiles +in a tiling of a triangular domain. The original schedule is as follows. + + domain: "{ A[i,j] : 0 <= i,j and i + j <= 100 }" + child: + schedule: "[{ A[i,j] -> [floor(i/10)] }, \ + { A[i,j] -> [floor(j/10)] }, \ + { A[i,j] -> [i] }, { A[i,j] -> [j] }]" + +The output is + + for (int c0 = 0; c0 <= 10; c0 += 1) + for (int c1 = 0; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; + c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; + c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); + +Isolating the full tiles, we have the following input + + domain: "{ A[i,j] : 0 <= i,j and i + j <= 100 }" + child: + schedule: "[{ A[i,j] -> [floor(i/10)] }, \ + { A[i,j] -> [floor(j/10)] }, \ + { A[i,j] -> [i] }, { A[i,j] -> [j] }]" + options: "{ isolate[[] -> [a,b,c,d]] : 0 <= 10a,10b and \ + 10a+9+10b+9 <= 100 }" + +and output + + { + for (int c0 = 0; c0 <= 8; c0 += 1) { + for (int c1 = 0; c1 <= -c0 + 8; c1 += 1) + for (int c2 = 10 * c0; + c2 <= 10 * c0 + 9; c2 += 1) + for (int c3 = 10 * c1; + c3 <= 10 * c1 + 9; c3 += 1) + A(c2, c3); + for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; + c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; + c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); + } + for (int c0 = 9; c0 <= 10; c0 += 1) + for (int c1 = 0; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; + c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; + c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); + } + +We may then additionally unroll the innermost loop of the isolated part + + domain: "{ A[i,j] : 0 <= i,j and i + j <= 100 }" + child: + schedule: "[{ A[i,j] -> [floor(i/10)] }, \ + { A[i,j] -> [floor(j/10)] }, \ + { A[i,j] -> [i] }, { A[i,j] -> [j] }]" + options: "{ isolate[[] -> [a,b,c,d]] : 0 <= 10a,10b and \ + 10a+9+10b+9 <= 100; [isolate[] -> unroll[3]] }" + +to obtain + + { + for (int c0 = 0; c0 <= 8; c0 += 1) { + for (int c1 = 0; c1 <= -c0 + 8; c1 += 1) + for (int c2 = 10 * c0; c2 <= 10 * c0 + 9; c2 += 1) { + A(c2, 10 * c1); + A(c2, 10 * c1 + 1); + A(c2, 10 * c1 + 2); + A(c2, 10 * c1 + 3); + A(c2, 10 * c1 + 4); + A(c2, 10 * c1 + 5); + A(c2, 10 * c1 + 6); + A(c2, 10 * c1 + 7); + A(c2, 10 * c1 + 8); + A(c2, 10 * c1 + 9); + } + for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; + c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; + c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); + } + for (int c0 = 9; c0 <= 10; c0 += 1) + for (int c1 = 0; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; + c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; + c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); + } + + +=head3 AST Generation Options (Schedule Map) + +In case of AST construction using +C, the options +that control how an AST is created from the individual schedule +dimensions are stored in the C. +They can be set using the following function. + + #include + __isl_give isl_ast_build * + isl_ast_build_set_options( + __isl_take isl_ast_build *build, + __isl_take isl_union_map *options); + +The options are encoded in an C. +The domain of this union relation refers to the schedule domain, +i.e., the range of the schedule passed +to C. +In the case of nested AST generation (see L), +the domain of C should refer to the extra piece of the schedule. +That is, it should be equal to the range of the wrapped relation in the +range of the schedule. +The range of the options can consist of elements in one or more spaces, +the names of which determine the effect of the option. +The values of the range typically also refer to the schedule dimension +to which the option applies. In case of nested AST generation +(see L), these values refer to the position +of the schedule dimension within the innermost AST generation. +The constraints on the domain elements of +the option should only refer to this dimension and earlier dimensions. +We consider the following spaces. + +=over + +=item C + +B + +This space is a wrapped relation between two one dimensional spaces. +The input space represents the schedule dimension to which the option +applies and the output space represents the separation class. +While constructing a loop corresponding to the specified schedule +dimension(s), the AST generator will try to generate separate loops +for domain elements that are assigned different classes. +If only some of the elements are assigned a class, then those elements +that are not assigned any class will be treated as belonging to a class +that is separate from the explicitly assigned classes. +The typical use case for this option is to separate full tiles from +partial tiles. +The other options, described below, are applied after the separation +into classes. + +As an example, consider the separation into full and partial tiles +of a tiling of a triangular domain. +Take, for example, the domain + + { A[i,j] : 0 <= i,j and i + j <= 100 } + +and a tiling into tiles of 10 by 10. The input to the AST generator +is then the schedule + + { A[i,j] -> [([i/10]),[j/10],i,j] : 0 <= i,j and + i + j <= 100 } + +Without any options, the following AST is generated + + for (int c0 = 0; c0 <= 10; c0 += 1) + for (int c1 = 0; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; + c2 <= min(-10 * c1 + 100, 10 * c0 + 9); + c2 += 1) + for (int c3 = 10 * c1; + c3 <= min(10 * c1 + 9, -c2 + 100); + c3 += 1) + A(c2, c3); + +Separation into full and partial tiles can be obtained by assigning +a class, say C<0>, to the full tiles. The full tiles are represented by those +values of the first and second schedule dimensions for which there are +values of the third and fourth dimensions to cover an entire tile. +That is, we need to specify the following option + + { [a,b,c,d] -> separation_class[[0]->[0]] : + exists b': 0 <= 10a,10b' and + 10a+9+10b'+9 <= 100; + [a,b,c,d] -> separation_class[[1]->[0]] : + 0 <= 10a,10b and 10a+9+10b+9 <= 100 } + +which simplifies to + + { [a, b, c, d] -> separation_class[[1] -> [0]] : + a >= 0 and b >= 0 and b <= 8 - a; + [a, b, c, d] -> separation_class[[0] -> [0]] : + a >= 0 and a <= 8 } + +With this option, the generated AST is as follows + + { + for (int c0 = 0; c0 <= 8; c0 += 1) { + for (int c1 = 0; c1 <= -c0 + 8; c1 += 1) + for (int c2 = 10 * c0; + c2 <= 10 * c0 + 9; c2 += 1) + for (int c3 = 10 * c1; + c3 <= 10 * c1 + 9; c3 += 1) + A(c2, c3); + for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; + c2 <= min(-10 * c1 + 100, 10 * c0 + 9); + c2 += 1) + for (int c3 = 10 * c1; + c3 <= min(-c2 + 100, 10 * c1 + 9); + c3 += 1) + A(c2, c3); + } + for (int c0 = 9; c0 <= 10; c0 += 1) + for (int c1 = 0; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; + c2 <= min(-10 * c1 + 100, 10 * c0 + 9); + c2 += 1) + for (int c3 = 10 * c1; + c3 <= min(10 * c1 + 9, -c2 + 100); + c3 += 1) + A(c2, c3); + } + +=item C + +This is a single-dimensional space representing the schedule dimension(s) +to which ``separation'' should be applied. Separation tries to split +a loop into several pieces if this can avoid the generation of guards +inside the loop. +See also the C option. + +=item C + +This is a single-dimensional space representing the schedule dimension(s) +for which the domains should be considered ``atomic''. That is, the +AST generator will make sure that any given domain space will only appear +in a single loop at the specified level. + +Consider the following schedule + + { a[i] -> [i] : 0 <= i < 10; + b[i] -> [i+1] : 0 <= i < 10 } + +If the following option is specified + + { [i] -> separate[x] } + +then the following AST will be generated + + { + a(0); + for (int c0 = 1; c0 <= 9; c0 += 1) { + a(c0); + b(c0 - 1); + } + b(9); + } + +If, on the other hand, the following option is specified + + { [i] -> atomic[x] } + +then the following AST will be generated + + for (int c0 = 0; c0 <= 10; c0 += 1) { + if (c0 <= 9) + a(c0); + if (c0 >= 1) + b(c0 - 1); + } + +If neither C nor C is specified, then the AST generator +may produce either of these two results or some intermediate form. + +=item C + +This is a single-dimensional space representing the schedule dimension(s) +that should be I unrolled. +To obtain a partial unrolling, the user should apply an additional +strip-mining to the schedule and fully unroll the inner loop. + +=back + +=head3 Fine-grained Control over AST Generation + +Besides specifying the constraints on the parameters, +an C object can be used to control +various aspects of the AST generation process. +In case of AST construction using +C, +the most prominent way of control is through ``options'', +as explained above. + +Additional control is available through the following functions. + + #include + __isl_give isl_ast_build * + isl_ast_build_set_iterators( + __isl_take isl_ast_build *build, + __isl_take isl_id_list *iterators); + +The function C allows the user to +specify a list of iterator Cs to be used as iterators. +If the input schedule is injective, then +the number of elements in this list should be as large as the dimension +of the schedule space, but no direct correspondence should be assumed +between dimensions and elements. +If the input schedule is not injective, then an additional number +of Cs equal to the largest dimension of the input domains +may be required. +If the number of provided Cs is insufficient, then additional +names are automatically generated. + + #include + __isl_give isl_ast_build * + isl_ast_build_set_create_leaf( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)( + __isl_take isl_ast_build *build, + void *user), void *user); + +The +C function allows for the +specification of a callback that should be called whenever the AST +generator arrives at an element of the schedule domain. +The callback should return an AST node that should be inserted +at the corresponding position of the AST. The default action (when +the callback is not set) is to continue generating parts of the AST to scan +all the domain elements associated to the schedule domain element +and to insert user nodes, ``calling'' the domain element, for each of them. +The C argument contains the current state of the C. +To ease nested AST generation (see L), +all control information that is +specific to the current AST generation such as the options and +the callbacks has been removed from this C. +The callback would typically return the result of a nested +AST generation or a +user defined node created using the following function. + + #include + __isl_give isl_ast_node *isl_ast_node_alloc_user( + __isl_take isl_ast_expr *expr); + + #include + __isl_give isl_ast_build * + isl_ast_build_set_at_each_domain( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)( + __isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, + void *user), void *user); + __isl_give isl_ast_build * + isl_ast_build_set_before_each_for( + __isl_take isl_ast_build *build, + __isl_give isl_id *(*fn)( + __isl_keep isl_ast_build *build, + void *user), void *user); + __isl_give isl_ast_build * + isl_ast_build_set_after_each_for( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)( + __isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, + void *user), void *user); + __isl_give isl_ast_build * + isl_ast_build_set_before_each_mark( + __isl_take isl_ast_build *build, + isl_stat (*fn)(__isl_keep isl_id *mark, + __isl_keep isl_ast_build *build, + void *user), void *user); + __isl_give isl_ast_build * + isl_ast_build_set_after_each_mark( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)( + __isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, + void *user), void *user); + +The callback set by C will +be called for each domain AST node. +The callbacks set by C +and C will be called +for each for AST node. The first will be called in depth-first +pre-order, while the second will be called in depth-first post-order. +Since C is called before the for +node is actually constructed, it is only passed an C. +The returned C will be added as an annotation (using +C) to the constructed for node. +In particular, if the user has also specified an C +callback, then the annotation can be retrieved from the node passed to +that callback using C. +The callbacks set by C +and C will be called for each +mark AST node that is created, i.e., for each mark schedule node +in the input schedule tree. The first will be called in depth-first +pre-order, while the second will be called in depth-first post-order. +Since the callback set by C +is called before the mark AST node is actually constructed, it is passed +the identifier of the mark node. +All callbacks should C (or C) on failure. +The given C can be used to create new +C objects using C +or C. + +=head3 Nested AST Generation + +C allows the user to create an AST within the context +of another AST. These nested ASTs are created using the +same C function that is used to create +the outer AST. The C argument should be an C +passed to a callback set by +C. +The space of the range of the C argument should refer +to this build. In particular, the space should be a wrapped +relation and the domain of this wrapped relation should be the +same as that of the range of the schedule returned by +C below. +In practice, the new schedule is typically +created by calling C on the old schedule +and some extra piece of the schedule. +The space of the schedule domain is also available from +the C. + + #include + __isl_give isl_union_map *isl_ast_build_get_schedule( + __isl_keep isl_ast_build *build); + __isl_give isl_space *isl_ast_build_get_schedule_space( + __isl_keep isl_ast_build *build); + __isl_give isl_ast_build *isl_ast_build_restrict( + __isl_take isl_ast_build *build, + __isl_take isl_set *set); + +The C function returns a (partial) +schedule for the domains elements for which part of the AST still needs to +be generated in the current build. +In particular, the domain elements are mapped to those iterations of the loops +enclosing the current point of the AST generation inside which +the domain elements are executed. +No direct correspondence between +the input schedule and this schedule should be assumed. +The space obtained from C can be used +to create a set for C to intersect +with the current build. In particular, the set passed to +C can have additional parameters. +The ids of the set dimensions in the space returned by +C correspond to the +iterators of the already generated loops. +The user should not rely on the ids of the output dimensions +of the relations in the union relation returned by +C having any particular value. + +=head1 Applications + +Although C is mainly meant to be used as a library, +it also contains some basic applications that use some +of the functionality of C. +For applications that take one or more polytopes or polyhedra +as input, this input may be specified in either the L +or the L. + +=head2 C + +C takes a polyhedron as input and prints +an integer element of the polyhedron, if there is any. +The first column in the output is the denominator and is always +equal to 1. If the polyhedron contains no integer points, +then a vector of length zero is printed. + +=head2 C + +C takes the same input as the C program +from the C distribution, i.e., a set of constraints +on the parameters, a line containing only -1 and finally a set +of constraints on a parametric polyhedron. +The coefficients of the parameters appear in the last columns +(but before the final constant column). +The output is the lexicographic minimum of the parametric polyhedron. +As C currently does not have its own output format, the output +is just a dump of the internal state. + +=head2 C + +C computes the minimum of some linear +or affine objective function over the integer points in a polyhedron. +If an affine objective function +is given, then the constant should appear in the last column. + +=head2 C + +Given a polytope, C prints +all integer points in the polytope. + +=head2 C + +Given an C object as input, +C prints out the corresponding dependences, +as computed by C. + +=head2 C + +Given either a schedule tree or a sequence consisting of +a schedule map, a context set and an options relation, +C prints out an AST that scans the domain elements +of the schedule in the order of their image(s) taking into account +the constraints in the context set. + +=head2 C + +Given an C object as input, +C prints out a schedule that satisfies the given +constraints. Index: contrib/isl/extract_key.c =================================================================== --- /dev/null +++ contrib/isl/extract_key.c @@ -0,0 +1,62 @@ +/* + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include + +/* Extract a mapping key from the token "tok". + * Return KEY_ERROR on error, i.e., if "tok" does not + * correspond to any known key. + */ +static KEY extract_key(__isl_keep isl_stream *s, struct isl_token *tok) +{ + int type; + char *name; + KEY key; + isl_ctx *ctx; + + if (!tok) + return KEY_ERROR; + type = isl_token_get_type(tok); + if (type != ISL_TOKEN_IDENT && type != ISL_TOKEN_STRING) { + isl_stream_error(s, tok, "expecting key"); + return KEY_ERROR; + } + + ctx = isl_stream_get_ctx(s); + name = isl_token_get_str(ctx, tok); + if (!name) + return KEY_ERROR; + + for (key = 0; key < KEY_END; ++key) { + if (!strcmp(name, key_str[key])) + break; + } + free(name); + + if (key >= KEY_END) + isl_die(ctx, isl_error_invalid, "unknown key", + return KEY_ERROR); + return key; +} + +/* Read a key from "s" and return the corresponding enum. + * Return KEY_ERROR on error, i.e., if the first token + * on the stream does not correspond to any known key. + */ +static KEY get_key(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + KEY key; + + tok = isl_stream_next_token(s); + key = extract_key(s, tok); + isl_token_free(tok); + + return key; +} Index: contrib/isl/flow.c =================================================================== --- /dev/null +++ contrib/isl/flow.c @@ -0,0 +1,44 @@ +/* + * Copyright 2017 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege. + */ + +/* This program takes an isl_union_access_info object as input and + * prints the corresponding dependences. + */ + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + isl_ctx *ctx; + isl_printer *p; + isl_union_access_info *access; + isl_union_flow *flow; + struct isl_options *options; + + options = isl_options_new_with_defaults(); + argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL); + ctx = isl_ctx_alloc_with_options(&isl_options_args, options); + + access = isl_union_access_info_read_from_file(ctx, stdin); + flow = isl_union_access_info_compute_flow(access); + + p = isl_printer_to_file(ctx, stdout); + p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK); + p = isl_printer_print_union_flow(p, flow); + isl_printer_free(p); + + isl_union_flow_free(flow); + + isl_ctx_free(ctx); + + return 0; +} Index: contrib/isl/flow_cmp.c =================================================================== --- /dev/null +++ contrib/isl/flow_cmp.c @@ -0,0 +1,140 @@ +/* + * Copyright 2017 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege. + */ + +#include + +#include +#include +#include +#include + +struct options { + struct isl_options *isl; + char *flow1; + char *flow2; +}; + +ISL_ARGS_START(struct options, options_args) +ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options") +ISL_ARG_ARG(struct options, flow1, "flow1", NULL) +ISL_ARG_ARG(struct options, flow2, "flow2", NULL) +ISL_ARGS_END + +ISL_ARG_DEF(options, struct options, options_args) + +static void die(const char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(EXIT_FAILURE); +} + +static FILE *open_or_die(const char *filename) +{ + FILE *file; + + file = fopen(filename, "r"); + if (!file) { + fprintf(stderr, "Unable to open %s\n", filename); + exit(EXIT_FAILURE); + } + return file; +} + +#undef BASE +#define BASE union_map +#include "read_in_string_templ.c" + +/* Given two YAML descriptions of isl_union_flow objects, check whether + * they are equivalent. + * Return EXIT_SUCCESS if they are and EXIT_FAILURE if they are not + * or if anything else went wrong. + * + * The descriptions are checked field by field, meaning that the fields + * are expected to appear in the same order in both inputs. + */ +int main(int argc, char **argv) +{ + int more; + isl_ctx *ctx; + struct options *options; + FILE *input1, *input2; + isl_stream *s1, *s2; + + options = options_new_with_defaults(); + if (!options) + return EXIT_FAILURE; + + ctx = isl_ctx_alloc_with_options(&options_args, options); + argc = options_parse(options, argc, argv, ISL_ARG_ALL); + + input1 = open_or_die(options->flow1); + input2 = open_or_die(options->flow2); + s1 = isl_stream_new_file(ctx, input1); + s2 = isl_stream_new_file(ctx, input2); + + if (isl_stream_yaml_read_start_mapping(s1)) + isl_die(ctx, isl_error_unknown, "arg1 not a YAML mapping", + return EXIT_FAILURE); + if (isl_stream_yaml_read_start_mapping(s2)) + isl_die(ctx, isl_error_unknown, "arg2 not a YAML mapping", + return EXIT_FAILURE); + + while ((more = isl_stream_yaml_next(s1)) > 0) { + int more2; + isl_bool equal; + isl_union_map *umap1, *umap2; + + more2 = isl_stream_yaml_next(s2); + if (more2 < 0) + return EXIT_FAILURE; + if (!more2) + isl_die(ctx, isl_error_unknown, "arg2 shorter", + return EXIT_FAILURE); + if (isl_stream_eat(s1, ISL_TOKEN_IDENT) < 0) + return EXIT_FAILURE; + if (isl_stream_eat(s2, ISL_TOKEN_IDENT) < 0) + return EXIT_FAILURE; + more = isl_stream_yaml_next(s1); + more2 = isl_stream_yaml_next(s2); + if (more < 0 || more2 < 0) + return EXIT_FAILURE; + if (!more || !more2) + isl_die(ctx, isl_error_unknown, "missing value", + return EXIT_FAILURE); + + umap1 = read_union_map(s1); + umap2 = read_union_map(s2); + equal = isl_union_map_is_equal(umap1, umap2); + isl_union_map_free(umap1); + isl_union_map_free(umap2); + if (equal < 0) + return EXIT_FAILURE; + if (!equal) + die("field not equal"); + } + if (more < 0) + return EXIT_FAILURE; + + + if (isl_stream_yaml_read_end_mapping(s1) < 0) { + isl_stream_error(s1, NULL, "unexpected extra elements"); + return EXIT_FAILURE; + } + if (isl_stream_yaml_read_end_mapping(s2) < 0) { + isl_stream_error(s2, NULL, "unexpected extra elements"); + return EXIT_FAILURE; + } + + isl_stream_free(s1); + isl_stream_free(s2); + fclose(input1); + fclose(input2); + isl_ctx_free(ctx); + + return EXIT_SUCCESS; +} Index: contrib/isl/flow_test.sh.in =================================================================== --- /dev/null +++ contrib/isl/flow_test.sh.in @@ -0,0 +1,18 @@ +#!/bin/sh + +EXEEXT=@EXEEXT@ +srcdir=@srcdir@ + +failed=0 + +for i in $srcdir/test_inputs/flow/*.ai; do + echo $i; + base=`basename $i .ai` + test=test-$base.flow + dir=`dirname $i` + ref=$dir/$base.flow + (./isl_flow$EXEEXT < $i > $test && + ./isl_flow_cmp$EXEEXT $ref $test && rm $test) || failed=1 +done + +test $failed -eq 0 || exit Index: contrib/isl/imath/ChangeLog =================================================================== --- /dev/null +++ contrib/isl/imath/ChangeLog @@ -0,0 +1,382 @@ +1.0.1 + First released version. + +1.0.2 + Fixed a bug in mp_int_div() which would yield incorrect quotients + when the divisor was very close in value to a prefix of the + dividend. This is now fixed, and there are regression tests in + the tests directory. + + Added recursive multiplication and squaring (Karatsuba-Ofman) for + large input values. Integrated these with the existing code for + exponentiation, too. See the code for s_kmul() and s_ksqr() in + imath.c. Tests added and verified against GNU bc. + + Added documentation on mp_get_multiply_threshold() and the reason + why it exists. + +1.0.3 + Fixed a couple of bugs in pi.c that were causing incorrect values + to be computed for > 30 digits or so. Added a pi-computation test + to the default test suite (make test), checked against a static + file computed by bc (set scale=1024, compute 4 * atan(1)). Added + command line option to specify output radix for pi. + + Cleaned up a sign-related bug in mp_int_gcd(), which would cause + the sign of gcd(0, x) to be incorrect when x < 0. Test cases + added for future regression. + + Fixed a bug in s_reduce() which would give incorrect results for + powers of 2 in certain circumstances. Added tests to drive this + case for future regression. + + Added mp_int_exptmod_evalue() and mp_int_exptmod_bvalue() to make + it easier to work with small bases and small exponents. + + Set default recursive multiplication threshold to 50 digits, since + this seems to work best for the platforms I've tested so far. + + Added iprime.h and iprime.c to the distribution. + +1.0.4 + Added `findsizes.pl' to the distribution. + + Revised the type declarations in imath.h to use 32/64 bit + operations where the "long long" type is supported. + + Fixed a sign-related bug in mp_int_invmod(). + + Fixed several small bugs related to shifting which affect the use + of 32-bit digits. Many architectures cannot shift by 32 bits at a + time (e.g., MIPS), so I split each of these cases into two shifts + of half the size, which should scale properly for both the smaller + and larger cases. + + Fixed several arithmetic issues with 32-bit digits that arose due + to missing type-casts on the right-hand sides of assignments. + + Fixed s_print() and s_print_buf() to handle the sizes of digits + transparently. + +1.0.5 + Updated the Makefile to include the _GNU_SOURCE macro. For many + GCC systems, this is necessary to get the correct definition of + the ULLONG_MAX macro in . Also, you may now build with + the make option DEBUG=Y to enable debugging, e.g.: + + make DEBUG=Y imtest + + By default, the Makefile builds with the optimizer enabled. + + Cleaned up the definitions triggered by USE_LONG_LONG in imath.h, + and added an #error instruction in case the build is unable to + find a definition of ULLONG_MAX or ULONG_LONG_MAX in . + Also added the mp_int_to_unsigned(), mp_int_read_unsigned(), and + mp_int_unsigned_len() prototypes. + + Fixed a bug in s_qmul() [imath.c:2493] that would grow the value + being multiplied even if there was room in the existing digits to + hold the result. This was driving an (apparent) bug in the more + general mp_int_read_binary() routine. Added the routines + mentioned in the previous paragraph, and factored some common + code out into a static s_tobin(). + + Added reset_registers() to imdrover.{h,c}. Added new test + driver functions test_to_uns() and test_read_uns(). Renamed + test_read_bin to test_read_binary(). + + Silenced a sign-related warning in pi.c (related to printf). + + Added many new test vectors to tests/conv.t, including the + original bug proof-of-concept from Tom Wu, and a series of new + tests for the unsigned conversion routines. + + Updated `doc.txt' to reflect the changes described above. + +1.0.6 + Updated copyright notices, added LICENSE file explaining the + license I am using. This is basically the BSD license, so + you should have no trouble incorporating this code into other + open source projects. + + No new functionality in this release. + +1.0.7 + The mp_int_invmod(a, m, c) function would compute a negative value + for c when given a < 0. I added some code to insure that the value + returned is always the least non-negative member of the congruence + class, if the inverse exists. A test for this was added to invmod.t. + +1.0.8 + Fixed a small buffer-overrun in s_qmul(). Because it only + allocates an extra digit if it absolutely has to, the test for + whether it needs to carry a shift out into the "spare" digit had + to be written carefully; I missed a subtlety, which is now + fixed. Along the way, I fixed a minor performance-related bug in + the same routine. + + Added mp_int_error_string(), which converts mp_result values + into descriptive strings. These are statically allocated, so + you don't have to free them. + + This version also adds an "examples" subdirectory. Currently, + there is only one program there, but I will add more examples as + time permits me. You have to read the source to understand them + anyway, so I won't explain them here. + +1.1.0 + Added imrat.h and imrat.c, containing routines for rational number + arithmetic at arbitrary precision. Added support to the test driver, + in imath.c and included various tests in the tests/ subdirectory. + + Fixed a sign-of-zero bug in mp_int_mul(). Tests added to mul.t to + regress this fix. + +1.1.2 + Fixed a bug with leading zeroes after the decimal point in the + mp_rat_read_decimal() function (imrat.c). Along the way, I also + found a sign-related bug, in which -0.5 would be treated as if it + were positive, because the sign of zero is implicitly positive, + and the denominator is treated as unsigned always. + + Thanks to Eric Silva for pointing out the leading zeroes bug. + The solution isn't the most efficient possible. + +1.1.3 + Rewrote mp_int_to_decimal() to support new rounding modes. The + modes are documented in doc.txt. Some of the code sucked anyway, + so I rewrote pretty much the entire function. + + Added new rounding mode constants. + +1.1.4 + Added mixed rational/integer operations: + mp_rat_add_int, mp_rat_sub_int, mp_rat_mul_int, mp_rat_div_int + Added rational exponentiation (with integer exponents): + mp_rat_expt + + Tests for same were added to the tests/ subdirectory. + +1.1.5 + Added mp_rat_read_cdecimal() and mp_rat_read_ustring() + Updated the input.c example. + +1.1.6 + Fixed a bug in mp_int_read_cstring() which would read the string + "-0" with incorrect sign (MP_NEG instead of MP_ZPOS). This would + violate an invariant that zero is always signed with positives. + + Added some tests to tests/neg.t to catch this case. + +1.1.7 + Fixed a bug in s_udiv(), internal to imath.c, which caused + division to fail in some corner cases masked by the use of long + long as a word type. As a result, s_udiv() has now been wholly + rewritten. I also fixed a few lingering buffer-length errors in + s_kmul(), and added a "const" qualifier to the input buffers for + the mp_int_read_string() and mp_int_read_cstring() functions, + and their analogs in imrat.c. + +1.1.8 + Added mp_int_alloc() and mp_int_free(). + +1.1.9 + Added mp_rat_alloc() and mp_rat_free(). Fixed a couple of minor + bugs in the doc.txt file. Added mp_int_sqrt() to imath.{h,c} and + doc.txt. + +1.2 + Dropped bugfix component of revision number. Fixed rsakey.c + example program to be complete and work faster. + +1.3 + Replaced findsizes.pl with findsizes.py. Fixed two bugs in the + rsakey tool that were leading to incorrect output. + +1.4 + Fixed a bug in mp_int_alloc(), it was not returning NULL when out + of memory, but rather failing in assert() instead. Also, updated + the documentation to have better language about the return values + in various error conditions. + +1.5 + Changed the API for rational rounding. Removed the two functions + mp_rat_set_rounding() and mp_rat_get_rounding(), along with the + round_output global variable. Redefined the MP_ROUND_* constants + as an enumeration type (mp_round_mode). Added a new parameter to + the mp_rat_to_decimal() function to accept a rounding mode. Unit + tests and doc.txt updated suitably. + + This release also incorporates a small patch submitted by Jonathan + Shapiro to support compilation in C++. + +1.6 + Defined default_precision and multiply_threshold to be constant + and static. If IMATH_TEST is defined at compile time, these are + made global, and can be modified by the caller (the imtimer tool + makes use of this ability, for example). + + Implemented a single-digit optimization suggested by J. Shapiro. + Documentation updated. + +1.7 + Fixed a subtle casting problem in the use of the ctype macros that + would permit negative signed character values to produce illogical + behaviour in some configurations (e.g., NetBSD). Removed a dead + "return" statement. + + Added the -pedantic switch for gcc, to get more aggressive + warnings; to permit the nonstandard "long long" type to still be + used, I also added -Wno-long-long when building with long long + enabled (the standard configuration). + + Fixed a bug found by the Samba team running Valgrind on the + Heimdal project, and reported by Love Hörnquist Ă‚strand: One of + the intermediate values used during modular exponentiation could + be overflowed during recursive multiplication. Fixed by taking a + more conservative approach to buffer sizing. + + Added a "contrib" subdirectory, whose first entry is a Makefile + to build IMath with the MSVC++ "nmake" program, contributed by + Matus Horvath. + +1.8 + Fixed a bug in s_udiv() affecting the computation of quotient + digits. Thanks to Love Ă‚strand for isolating this bug. Also in + this release, defining USELLONG=Y or USELLONG=N on the command + line for make will switch support for the "long long" data type on + or off without having to edit the Makefile. The default is still + to permit use of "long long", even though the type is not standard + ANSI C90. + +1.9 + Increased the number of small primes used for primality testing to + 100 from 32. Removed an unwanted #define from imath.c, left over + from testing; added "static" to the declaration of the s_embar() + internal function since it is not used outside imath.c. Reduced + the quantity of feedback generated by rsakey.c during the prime + finding stage of key generation. + +1.10 + All primes less than 1000 are now used in iprime.c for preliminary + testing of prime candidates. Removed declaration of s_pad() from + rsakey.c example. Added imcalc.c example. + + Beginning with this release, defining the DEBUG preprocessor macro + when compiling imath.c causes all the normally-static helper + functions to be exported. This makes it easier to troubleshoot + bugs in the back end functions without manually editing the source + till you have found where the bug actually is. + + Fixed a memory leak in the test driver (imtest.c) where the input + buffers allocated for test specs were not released before being + released. No impact on the core routines, but nevertheless not a + good thing. + + Fixed several uninitialized memory reads and one subtle read past + the end of a buffer in s_kmul(), found during a run of Purify. + Thanks to Love Hörnquist Ă‚strand for finding this one, and + providing a good test case so I could isolate the problem. Also + fixed a buglet in s_kmul(), in which free() was being called + instead of s_free(), which would break if you provided a custom + version of s_alloc() and s_free() for your application. + +1.11 + Those functions which take int parameters to supply one or more of + the arithmetic values of the function have been converted to use a + typedef "mp_small". This is defined in imath.h, along with some + supporting macros. + + Added mp_int_to_uint() and mp_int_lcm() in imath.{h,c}, based on a + patch contributed by Hal Finkel. Added LCM tests as as well as + some more GCD tests in tests/lcm.t and tests/gcd.t + + Also at Hal Finkel's request, added mp_int_root() to compute the + integer nth root, i.e., \lfloor a^{1/b}\rfloor; replaced the old + mp_int_sqrt() function with a call to mp_int_root() via a macro. + The new implementation is probably slightly less efficient for + square roots, but more general. Added tests/root.t and moved the + sqrt tests there, also. + +1.12 + Added a new global constant MP_MINERR which is the value of the + smallest error code defined by IMath itself. This can be used by + clients who wish to define and use additional error codes, so that + those codes will not conflict with the existing set. + + Extended the imcalc example to include memory. + + Fixed a bug in mp_int_add() in which -1 + 1 = -0 (the sign of zero + was recorded incorrectly). Added tests to the regression suite + for this fix. + +1.13 + Cosmetic change -- updated all the files with my new web address. + + Fixed a buglet caught by Love Hörnquist Ă‚strand using the LLVM + static checker tools, in which a mp_int_copy() failure would be + silently ignored and cause an extra copy to be generated. + + Fixed a bug in the testing suite while building on MinGW. The pi + generation tests compare to static files and these tests fail if + CR/LF is output instead of just LF. The test script now strips + all CR and LF from the output and compares to files lacking them. + Reported by Chris Cole . + +1.14 + Instead of using the preprocessor to delete "static", the static + definitions in imath.c now use an explicit STATIC macro, that is + made null when DEBUG is defined. This avoids a subtle problem + with static variables defined inside functions (although no bugs + actually arose from it). + + Fixed a bug in s_udiv() while building on MinGW. When building + with short type digits, the routine was incorrectly discarding + overflow when computing the next quotient digit. + Reported by Paul DeMarco . + +1.15 + Fixed a bug in the definition of MP_DIGIT_MAX that caused errors + when IMath is built under 64-bit Linux. Reported by + Klaus Stengel . + + Unpacked the macro definitions in imath.c a bit, to make them more + readable. + + Added mp_int_expt_full() by request of Andrea Barberio + . + +1.16 + Fixed a bug in mp_int_to_uint() which was causing incorrect MP_RANGE + errors during small integer conversion. + Reported by Andrea Barberio + + Added mp_int_compare_uvalue(). + Added some new testing hooks in imtest.c, new unit tests. + + Made some code style changes that do not affect functionality. + +1.17 + Fixed a bug in mp_int_swap() where mpz_t structures using their single + field as storage would not get swapped correctly. + Reported by Andres Navarro + + Added regression test for this and some hooks for future + regressions in the tests/test.sh script. + +1.18 + Made mp_int_rat() use mp_int_init() to initialize numerator and + denominator instead of mp_int_init_size(). + Some minor code cleanup inside the testing code (imdrover.c). + + Fixed an off-by-one bug in s_udiv() which could cause the quotient + guessing loop to spin. Reported by Andres Navarro. Added + triggering example to div.t as a regression test. + +1.19 + Fix signedness error in compile. Reported by PaweĹ‚ Sikora. + +1.20 + Fix broken comments, apparently from a previous bad merge. + Remove emacs folding-mode comments throughout. + Some minor Makefile cleanup to make clang happier. Index: contrib/isl/imath/LICENSE =================================================================== --- /dev/null +++ contrib/isl/imath/LICENSE @@ -0,0 +1,20 @@ +IMath is Copyright © 2002-2009 Michael J. Fromberger +You may use it subject to the following Licensing Terms: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. Index: contrib/isl/imath/Makefile =================================================================== --- /dev/null +++ contrib/isl/imath/Makefile @@ -0,0 +1,135 @@ +## +## Name: Makefile +## Purpose: Makefile for imath library and associated tools +## Author: M. J. Fromberger +## +## Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to +## deal in the Software without restriction, including without limitation the +## rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +## sell copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in +## all copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +## IN THE SOFTWARE. +## + +# --- begin configuration section --- + +## Generic settings for systems with GCC (default) +## To build with debugging, add DEBUG=Y on the "make" command line. +## +## If building under MacOS 10.1.x, use CC=cc instead. +## +CC=gcc +CFLAGS+=-ansi -pedantic -Wall -Werror -Wno-error=unused-command-line-argument \ + -I. $(DFLAGS$(DEBUG)) $(SIZEFLAGS$(USELLONG)) +LIBFLAGS=-dynamiclib +LIBS=$(DLIBS$(DEBUG)) + +DFLAGS=-O3 -funroll-loops -finline-functions +DFLAGSN=$(DFLAGS) +DFLAGSY=-g -DDEBUG=1 +#DLIBS= +#DLIBSY=-lefence + +## If USELONG=N, disable the use of the "long long" data type; it is +## enabled by default even though it is non-standard. Define +## USELONG=Y to explicitly enable the use of "long long" +SIZEFLAGS = -std=c99 -DUSE_64BIT_WORDS +SIZEFLAGSN = -std=c99 +SIZEFLAGSY = $(SIZEFLAGS) + +# --- end of configuration section --- +VERS=1.20 + +REGRESSIONS=bug-swap +TARGETS=imtest imtimer pi bintest $(REGRESSIONS) +HDRS=imath.h imrat.h iprime.h imdrover.h rsamath.h gmp_compat.h +SRCS=$(HDRS:.h=.c) $(TARGETS:=.c) +OBJS=$(SRCS:.c=.o) +OTHER=LICENSE ChangeLog Makefile doc.txt findsizes.py \ + findthreshold.py imath-test.scm imath.py +VPATH += examples +EXAMPLES=basecvt findprime randprime imcalc input rounding rsakey + +.PHONY: all test clean distclean dist + +.c.o: + $(CC) $(CFLAGS) -c $< + +all: objs examples test + +objs: $(OBJS) + +check: test gmp-compat-test + @ echo "Completed running imath and gmp-compat unit tests" + +test: imtest pi bug-swap + @ echo "" + @ echo "Running tests, you should not see any 'FAILED' lines here." + @ echo "If you do, please see doc.txt for how to report a bug." + @ echo "" + (cd tests && ./test.sh) + +gmp-compat-test: libimath.so + @ echo "Running gmp-compat unit tests" + @ echo "Printing progress after every 100,000 tests" + make -C tests/gmp-compat-test TESTS="-p 100000 random.tests" + +$(EXAMPLES):%: imath.o imrat.o iprime.o %.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +$(REGRESSIONS):%: imath.o %.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +examples: $(EXAMPLES) + +libimath.so: imath.o imrat.o gmp_compat.o + $(CC) $(CFLAGS) $(LIBFLAGS) -o $@ $^ + +imtest: imtest.o imath.o imrat.o imdrover.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +imtimer: imath.c imtimer.c + $(CC) $(CFLAGS) -D_GNU_SOURCE -DIMATH_TEST -o $@ $^ $(LIBS) + +pi: pi.o imath.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +rtest: rtest.o imath.o rsamath.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +bintest: imath.o bintest.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +clean: + rm -f *.o *.pyc *~ core gmon.out tests/*~ tests/gmon.out examples/*~ + make -C tests/gmp-compat-test clean + +distclean: clean + rm -f $(TARGETS) imath-$(VERS).tar imath-$(VERS).tar.gz + rm -f $(EXAMPLES) + rm -f libimath.so + +dist: distclean + @ echo "Packing files for distribution" + @ tar -cf imtemp.tar --exclude .svn \ + $(HDRS) $(SRCS) $(OTHER) tests examples + @ mkdir imath-$(VERS) + @ (cd imath-$(VERS) && tar -xf ../imtemp.tar) + @ rm -f imtemp.tar + @ tar -cvf imath-$(VERS).tar imath-$(VERS) + @ echo "Compressing distribution file: " imath-$(VERS).tar + @ gzip -9v imath-$(VERS).tar + @ rm -rf imath-$(VERS) Index: contrib/isl/imath/README.md =================================================================== --- /dev/null +++ contrib/isl/imath/README.md @@ -0,0 +1,106 @@ +IMath +===== + +Arbitrary precision integer and rational arithmetic library. + +IMath is an open-source ANSI C arbitrary precision integer and rational +arithmetic library. + +IMath is copyright © 2002-2009 Michael J. Fromberger. + +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. + + +About IMath +----------- + +IMath is a library written in portable ANSI C that allows you to perform +arithmetic on integers and rational numbers of arbitrary precision. While many +programming languages, including Java, Perl, and Python provide arbitrary +precision numbers as a standard library or language feature, C does not. + +IMath was designed to be small, self-contained, easy to understand and use, and +as portable as possible across various platforms. The API is simple, and the +code should be comparatively easy to modify or extend. Simplicity and +portability are useful goals for some applications—however, IMath does +not attempt to break performance records. If you need the fastest possible +implementation, you might consider some other libraries, such as GNU MP (GMP), +MIRACL, or the bignum library from OpenSSL. + +Programming with IMath +---------------------- + +Detailed descriptions of the IMath API can be found in `doc.txt`. However, the +following is a brief synopsis of how to get started with some simple tasks. + +To do basic integer arithmetic, you must declare variables of type `mpz_t` in +your program, and call the functions defined in `imath.h` to operate on them. +Here is a simple example that reads one base-10 integer from the command line, +multiplies it by another (fixed) value, and prints the result to the standard +output in base-10 notation: + + #include + #include + #include "imath.h" + + int main(int argc, char *argv[]) + { + mpz_t a, b; + char *buf; + int len; + + if(argc < 2) { + fprintf(stderr, "Usage: testprogram \n"); + return 1; + } + + /* Initialize a new zero-valued mpz_t structure */ + mp_int_init(&a); + + /* Initialize a new mpz_t with a small integer value */ + mp_int_init_value(&b, 25101); + + /* Read a string value in the specified radix */ + mp_int_read_string(&a, 10, argv[1]); + + /* Multiply the two together... */ + mp_int_mul(&a, &b, &a); + + /* Print out the result */ + len = mp_int_string_len(&a, 10); + buf = calloc(len, sizeof(*buf)); + mp_int_to_string(&a, 10, buf, len); + printf("result = %s\n", buf); + free(buf); + + /* Release memory occupied by mpz_t structures when finished */ + mp_int_clear(&b); + mp_int_clear(&a); + + return 0; + } + +This simple example program does not do any error checking, but all the IMath +API functions return an `mp_result` value which can be used to detect various +problems like range errors, running out of memory, and undefined results. + +The IMath API also supports operations on arbitrary precision rational numbers. +The functions for creating and manipulating rational values (type `mpq_t`) are +defined in `imrat.h`, so that you need only include them in your project if you +wish to. Index: contrib/isl/imath/bintest.c =================================================================== --- /dev/null +++ contrib/isl/imath/bintest.c @@ -0,0 +1,106 @@ +/* + Name: bintest.c + Purpose: Test driver for binary input/output formats from IMath. + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include + +#include "imath.h" + +int main(int argc, char *argv[]) +{ + unsigned char buf[512]; + mpz_t v, w; + mp_result res; + int len; + + if(argc < 2 || argv[1][0] == '\0') { + fprintf(stderr, "Usage: bintest \n"); + return 1; + } + + mp_int_init(&v); + mp_int_init(&w); + res = mp_int_read_string(&v, 10, argv[1]); + printf("Result code from mp_int_read_string() = %d (%s)\n", + res, mp_error_string(res)); + + len = mp_int_binary_len(&v); + printf("%d bytes needed to write this value in 2's complement.\n", len); + + res = mp_int_to_binary(&v, buf, sizeof(buf)); + printf("Result code from mp_int_to_binary() = %d (%s)\n", + res, mp_error_string(res)); + if(res == MP_OK) { + int ix; + + for(ix = 0; ix < (len - 1); ++ix) + printf("%d.", buf[ix]); + + printf("%d\n", buf[ix]); + } else { + return 1; + } + + /* Try converting back... */ + res = mp_int_read_binary(&w, buf, len); + printf("Result code from mp_int_read_binary() = %d (%s)\n", + res, mp_error_string(res)); + if(res == MP_OK) { + mp_int_to_string(&w, 10, (char *) buf, sizeof(buf)); + + printf("[%s]\n\n", buf); + } + + len = mp_int_unsigned_len(&v); + printf("%d bytes needed to write this value as unsigned.\n", len); + + res = mp_int_to_unsigned(&v, buf, sizeof(buf)); + printf("Result code from mp_int_to_unsigned() = %d\n", res); + if(res == MP_OK) { + int ix; + + for(ix = 0; ix < (len - 1); ++ix) + printf("%d.", buf[ix]); + + printf("%d\n", buf[ix]); + } else { + return 1; + } + + res = mp_int_read_unsigned(&w, buf, len); + printf("Result code from mp_int_read_unsigned() = %d (%s)\n", + res, mp_error_string(res)); + if(res == MP_OK) { + mp_int_to_string(&w, 10, (char *) buf, sizeof(buf)); + + printf("[%s]\n\n", buf); + } + + mp_int_clear(&v); + mp_int_clear(&w); + return 0; +} Index: contrib/isl/imath/bug-swap.c =================================================================== --- /dev/null +++ contrib/isl/imath/bug-swap.c @@ -0,0 +1,25 @@ +/* Regression test for mp_int_swap() bug on self-stored values. */ +#include +#include "imath.h" + +int main(int argc, char* argv[]) { + mpz_t a, b; + int result; + + mp_int_init_value(&a, 1); + mp_int_init_value(&b, 16); + + mp_int_swap(&a, &b); + result = (a.digits == &(a.single) && + b.digits == &(b.single) && + a.digits[0] == 16 && + b.digits[0] == 1); + + printf("REGRESSION: mp_int_swap() on self-stored values: %s\n", + result ? "OK" : "FAILED"); + + mp_int_clear(&b); + mp_int_clear(&a); + return !result; +} + Index: contrib/isl/imath/contrib/Makefile.msvc =================================================================== --- /dev/null +++ contrib/isl/imath/contrib/Makefile.msvc @@ -0,0 +1,84 @@ +## +## Name: Makefile.msvc +## Purpose: Makefile for IMath library and associated tools +## for Microsoft Visual Studio 2005 +## Author: Matus Horvath +## +## Copyright (C) 2006 Matus Horvath. Permission has been granted to use, +## modify, and redistribute this file according to the terms of the IMath +## license. +## +## Usage: nmake /f Makefile.msvc +## + +# --- begin configuration section --- + +## Settings for Microsoft Windows systems using nmake. +## To build with debugging, add DEBUG=Y on the "nmake" command line. +CC=cl.exe +LD=link.exe +CFLAGS=$(CFLAGS) -nologo -I. -D_CRT_SECURE_NO_DEPRECATE $(DCFLAGS) +LDFLAGS=$(LDFLAGS) -nologo $(DLDFLAGS) +LIBS=$(DLIBS) + +!if "$(DEBUG)" == "Y" +DCFLAGS=-ZI -Od -DDEBUG=1 -DTRACEABLE_FREE=1 +DLDFLAGS=-DEBUG +#DLIBS=-lefence +!else +DCFLAGS=-O2 -Ob2 +DLDFLAGS= +#DLIBS= +!endif + +## Visual Studio C/C++ 2005 compiler supports "long long" 64-bit type. +CFLAGS=$(CFLAGS) -DUSE_LONG_LONG + +# --- end of configuration section --- +TARGETS=imtest.exe pi.exe bintest.exe findprime.exe +HDRS=imath.h imrat.h iprime.h imdrover.h rsamath.h +SRCS=$(HDRS:.h=.c) $(TARGETS:.exe=.c) +OBJS=$(SRCS:.c=.obj) +EXAMPLES=input.exe basecvt.exe rounding.exe + +.c.obj: + $(CC) $(CFLAGS) -c $< + +all: objs examples test + +objs: $(OBJS) + +# Because Visual Studio does not permit Unix shell syntax, you will +# have to run the tests manually once the "test" target is built. +test: imtest.exe pi.exe +# @ echo "" +# @ echo "Running tests, you should not see any 'FAILED' lines here." +# @ echo "If you do, please see doc.txt for how to report a bug." +# @ echo "" +# (cd tests && ./test.sh) + +$(EXAMPLES): imath.obj imrat.obj iprime.obj examples/$*.obj + @move $*.obj examples/$*.obj + $(LD) $(LDFLAGS) -out:$@ $** $(LIBS) + +examples: $(EXAMPLES) + +imtest.exe: imtest.obj imath.obj imrat.obj imdrover.obj + $(LD) $(LDFLAGS) -out:$@ $** $(LIBS) + +pi.exe: pi.obj imath.obj + $(LD) $(LDFLAGS) -out:$@ $** $(LIBS) + +findprime.exe: findprime.obj imath.obj iprime.obj + $(LD) $(LDFLAGS) -out:$@ $** $(LIBS) + +rtest.exe: rtest.obj imath.obj rsamath.obj + $(LD) $(LDFLAGS) -out:$@ $** $(LIBS) + +bintest.exe: imath.obj bintest.obj + $(LD) $(LDFLAGS) -out:$@ $** $(LIBS) + +clean: + del /q /f *.exe *.obj examples\*.obj + +# End of Makefile.msvc Index: contrib/isl/imath/contrib/README =================================================================== --- /dev/null +++ contrib/isl/imath/contrib/README @@ -0,0 +1,3 @@ +The files in this directory have been contributed to the IMath project +by other authors. + Index: contrib/isl/imath/divide.txt =================================================================== --- /dev/null +++ contrib/isl/imath/divide.txt @@ -0,0 +1,43 @@ +Algorithm for Arbitrary Precision Unsigned Division + +Inputs: + A = [a1 ... an] -- array representation + B = [b1 ... bm] + ai, bi \in {0,..radix} + +Preconditions: + n >= m + +Outputs: + Q, R satisfying A = QB + R with 0 <= R < B. + +let Q = [], j = n, i = 1, skip = 0 in + while j > 0 do + if B > A[j,..j + i + 1] then + decrement j + increment i + increment skip + if skip > 1 then + Q.append(0) + else + let pfx = A[j] in + if pfx < bm and j > 1 then + pfx := pfx * radix + A[j - 1] + + q := pfx div bm + if q >= radix then + if q > radix then + q = radix + else + q := 1 + + let t = B * q in + while t > A[j,..j + i + 1] do + t := t - B + decrement q + + Q.append(q) + skip := 0 + end + + result Q, A Index: contrib/isl/imath/doc.txt =================================================================== --- /dev/null +++ contrib/isl/imath/doc.txt @@ -0,0 +1,820 @@ +Name: doc.txt +Purpose: User documentation for IMath library +Author: M. J. Fromberger + +--- Installation: + +1. Edit Makefile to select compiler and options. The default uses gcc. If you + are building under MacOS 10.1.x, you will need to change CC to 'cc' instead + of 'gcc', but otherwise you can use the default GCC settings. + + By default, the Makefile assumes you can use the "long long" integer type, + even though it is not standard in ANSI C90. You can control this by setting + the USELLONG variable in your make command line. Setting USELLONG=Y enables + "long long"; USELLONG=N disables it. The default is Y. + + If the built-in types do not work for your particular platform, you can try + to find suitable integer type sizes by running the Python program + `findsizes.py'. This requires a Python interpreter, version 2.4.x or later. + +2. Type 'make' or 'make test' to build the test driver and run the unit tests. + None of these should fail. If they do, see below for how you can report + bugs. + + To build with debugging enabled (and optimization disabled), run make + DEBUG=Y. This sets the preprocessor macro DEBUG to 1, and several other + things (see Makefile for details). + +To use the library in your code, include "imath.h" wherever you intend to use +the library's routines. The integer library is just a single source file, so +you can compile it into your project in whatever way makes sense. If you wish +to use rational arithmetic, you will also need to include "imrat.h". + +--- Background: + +The basic types defined by the imath library are mpz_t, an arbitrary precision +signed integer, and mpq_t, an arbitrary precision signed rational number. The +type mp_int is a pointer to an mpz_t, and mp_rat is a pointer to an mpq_t. + +Most of the functions in the imath library return a value of type mp_result. +This is a signed integer type which can be used to convey status information +and also return small values. Any negative value is considered to be a status +message. The following constants are defined for processing these: + + MP_OK operation successful, all is well (= 0) + MP_FALSE boolean false (= MP_OK) + MP_TRUE boolean true + MP_MEMORY out of memory + MP_RANGE parameter out of range + MP_UNDEF result is undefined (e.g., division by zero) + MP_TRUNC output value was truncated + MP_BADARG an invalid parameter was passed + +If you obtain a zero or negative value of an mp_result, you can use the +mp_int_error_string() routine to obtain a pointer to a brief human readable +string describing the error. These strings are statically allocated, so they +need not be freed by the caller; the same strings are re-used from call to +call. + +Unless otherwise noted, it is legal to use the same parameter for both inputs +and output with most of the functions in this library. For example, you can +add a number to itself and replace the original by writing: + + mp_int_add(a, a, a); /* a = a + a */ + +Any cases in which this is not legal will be noted in the function summaries +below (if you discover that this is not so, please report it as a bug; I will +fix either the function or the documentation :) + +--- The IMath API + +Each of the API functions is documented here. The general format of the +entries is: + +return_type function_name(parameters ...) + English description. + +Unless otherwise noted, any API function that returns mp_result may be expected +to return MP_OK, MP_BADARG, or MP_MEMORY. Other return values should be +documented in the description. Please let me know if you discover this is not +the case. + +The following macros are defined in "imath.h", to define the sizes of the +various data types used in the library: + + MP_DIGIT_BIT : the number of bits in a single mpz_t digit. + MP_WORD_BIT : the number of bits in a mpz_t word. + MP_SMALL_MIN : the minimum value representable by an mp_small. + MP_SMALL_MAX : the maximum value representable by an mp_small. + MP_USMALL_MIN : the minimum value representable by an mp_usmall. + MP_USMALL_MAX : the maximum value representable by an mp_usmall. + MP_MIN_RADIX : the minimum radix accepted for base conversion. + MP_MAX_RADIX : the maximum radix accepted for base conversion. + +An mp_int must be initialized before use. This may be accomplished using the +following functions: + +mp_result mp_int_init(mp_int z); + Initializes z with a default precision, sets the value to zero. This + function cannot fail unless z is NULL. + +mp_int mp_int_alloc(); + Dynamically allocates an mpz_t, initializes it to the value zero, and + returns a pointer to it. Returns NULL in case of error (the only + error possible is MP_MEMORY in this case). + +mp_result mp_int_init_size(mp_int z, mp_size prec); + Initializes z with at least prec digits of storage, sets the value to + zero. If prec is zero, the default size is used, defined in imath.h + as MP_DEFAULT_PREC. The size is rounded up to the nearest word + boundary. + +mp_result mp_int_init_copy(mp_int z, mp_int old); + Initializes z to be a copy of an already-initialized mp_int in old. + They do not share storage. + +mp_result mp_int_init_value(mp_int z, mp_small value); + Initializes z with default precision and sets its value to the value + of the supplied integer. + +To copy one mp_int to another, use: + +mp_result mp_int_copy(mp_int a, mp_int c); + Copies the value of a into c. Does not allocate new memory unless a + has more significant digits than c has room for. + +When you are finished with an mp_int, you must free the memory it uses: + +void mp_int_clear(mp_int z); + Releases the storage used by z. + +void mp_int_free(mp_int z); + Releases the storage used by z, and frees the mpz_t structure z + points to. This should only be used for values allocated by + mp_int_alloc(). + +To set an mp_int, which has already been initialized, to a small integer value, +use the following: + +mp_result mp_int_set_value(mp_int z, mp_small value); + Sets the value of z to the value of the supplied integer. + +By default, an mp_int is initialized with a certain minimum amount of storage +for digits. This storage is expanded automatically as needed. + +- The arithmetic functions are: + +int mp_int_is_odd(mp_int z); + Returns true if z is an odd integer (z = 1 (mod 2)) + [currently implemented as a macro] + +int mp_int_is_even(mp_int z); + Returns true if z is an even integer (z = 0 (mod 2)) + [currently implemented as a macro] + +void mp_int_zero(mp_int z); + Sets z to zero. + +mp_result mp_int_abs(mp_int a, mp_int c); + Sets c to the absolute value of a. + If a < 0, c = -a, else c = a. + +mp_result mp_int_neg(mp_int a, mp_int c); + Sets c to be the additive inverse of a, c = -a. + +mp_result mp_int_add(mp_int a, mp_int b, mp_int c); + Computes c = a + b. + +mp_result mp_int_add_value(mp_int a, mp_small value, mp_int c); + Computes c = a + value, where value is a small integer. + +mp_result mp_int_sub(mp_int a, mp_int b, mp_int c); + Computes c = a - b. + +mp_result mp_int_sub_value(mp_int a, mp_small value, mp_int c); + Computes c = a - value, where value is a small integer. + +mp_result mp_int_mul(mp_int a, mp_int b, mp_int c); + Computes c = a * b + +mp_result mp_int_mul_value(mp_int a, mp_small value, mp_int c); + Computes c = a * value, where value is a small integer. + +mp_result mp_int_mul_pow2(mp_int a, mp_small p2, mp_int c); + Computes c = a * 2^p2, where p2 >= 0. + +mp_result mp_int_sqr(mp_int a, mp_int c); + Computes c = a * a. Faster than using mp_int_mul(a, a, c). + +mp_result mp_int_root(mp_int a, mp_small b, mp_int c); + Computes c = floor(a^{1/b}). Returns MP_UNDEF if the root is + undefined, i.e., if a < 0 and b is even. Uses Newton's method to + obtain the root. + +mp_result mp_int_sqrt(mp_int a, mp_int c); + Computes c = floor(sqrt(a)) if a >= 0. Returns MP_UNDEF if + a < 0. + [currently implemented as a macro] + +mp_result mp_int_div(mp_int a, mp_int b, mp_int q, mp_int r); + Computes q, r such that a = bq + r and 0 <= r < b. + + Pass NULL for q or r if you don't need its value. Detects and + handles division by powers of two in an efficient manner. Returns + MP_UNDEF if b = 0. If both q and r point to the same non-NULL + location, their values on output will be arbitrary (usually + incorrect). + +mp_result mp_int_div_value(mp_int a, mp_small v, mp_int q, mp_small *r); + Computes q, r such that a = qv + r and 0 <= r < v, where v is a small + integer. Pass NULL for q or r if you don't need its value. + +mp_result mp_int_div_pow2(mp_int a, mp_small p2, mp_int q, mp_int r); + Computes q, r such that a = q * 2^p2 + r. This is a special case for + division by powers of two that is much more efficient than using the + regular division algorithm. Note that mp_int_div() will + automatically handle this case if b = 2^k for some k >= 0; + mp_int_div_pow2() is for when you have only the exponent, not the + expanded value. + +mp_result mp_int_mod(mp_int a, mp_int m, mp_int c); + Computes the least non-negative residue of a (mod m), and assigns the + result to c. + +mp_result mp_int_mod_value(mp_int a, mp_int value, mp_small *r); + Computes the least non-negative residue of a (mod value), where value + is a small integer, and assigns the result to r. + +mp_result mp_int_expt(mp_int a, mp_small b, mp_int c); + Raises a to the b power, and assigns the result to c. It is an error + if b < 0. + +mp_result mp_int_expt_value(mp_small a, mp_small b, mp_int c); + Raises a to the b power, and assigns the result to c. It is an error + if b < 0. + +mp_result mp_int_expt_full(mp_int a, mp_int b, mp_int c); + Raises a to the b power, and assigns the result to c. It is an error + if b < 0. + +- Comparison functions: + +Unless otherwise specified, comparison between values x and y returns a value < +0 if x is less than y, = 0 if x is equal to y, and > 0 if x is greater than y. + +int mp_int_compare(mp_int a, mp_int b); + Signed comparison of a and b. + +int mp_int_compare_unsigned(mp_int a, mp_int b); + Unsigned (magnitude) comparison of a and b. The signs of a and b are + not modified. + +int mp_int_compare_zero(mp_int z); + Compare z to zero. + +int mp_int_compare_value(mp_int z, mp_small value); +int mp_int_compare_uvalue(mp_int z, mp_usmall value); + Compare z to small signed (value) or unsigned (uvalue) integer value. + +int mp_int_divisible_value(mp_int a, mp_small v); + Returns true (nonzero) if a is divisible by small integer v, + otherwise false (zero) + +int mp_int_is_pow2(mp_int z); + Returns k >= 0 such that z = 2^k, if such a k exists; otherwise a + value < 0 is returned. + +- Other useful functions: + +mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m, mp_int c); + Efficiently computes c = a^b (mod m). + Returns MP_UNDEF if m = 0; returns MP_RANGE if b < 0. + +mp_result mp_int_exptmod_evalue(mp_int a, mp_small v, mp_int m, mp_int c); + Efficiently computes c = a^v (mod m). +mp_result mp_int_exptmod_bvalue(mp_small v, mp_int b, mp_int m, mp_int c); + Efficiently computes c = v^b (mod m). + + Note: These routines use Barrett's algorithm for modular reduction. + It is widely held (probably correctly) that using Peter Montgomery's + multiplication algorithm would make this operation faster; but that + algorithm has the restriction that a and m must be coprime, so I have + not implemented it here. + +mp_result mp_int_exptmod_known(mp_int a, mp_int b, mp_int m, mp_int mu, + mp_int c); + Efficiently computes c = a^b (mod m), given a precomputed reduction + constant mu, as defined for Barrett's modular reduction algorithm. + Returns MP_UNDEF if m = 0; returns MP_RANGE if b < 0. + +mp_result mp_int_redux_const(mp_int m, mp_int c); + Computes reduction constant mu for Barrett reduction by modulus m, + stores the result in c. + +mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c); + Computes the modular inverse of a (mod m), if it exists, and assigns + the result to c. Returns the least non-negative representative of + the congruence class (mod m) containing this inverse. Returns + MP_UNDEF if the inverse does not exist; returns MP_RANGE if a = 0 or + m <= 0. + +mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c); + Compute the greatest common divisor if a and b, and assign the result + to c. Returns MP_UNDEF if the GCD is not defined (e.g., if a = 0 and + b = 0). + +mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c, mp_int x, mp_int y); + Compute the greatest common divisor of a and b, and assign the result + to c. Also computes x and y satisfying Bezout's identity, namely (a, + b) = ax + by. Returns MP_UNDEF if the GCD is not defined (e.g., if a + = b = 0). + +mp_result mp_int_lcm(mp_int a, mp_int b, mp_int c) + Compute the least common multiple of a and b, and assign the result + to c. Returns MP_UNDEF if the LCM is not defined (e.g., if a = 0 and + b = 0). + +- Conversion of values: + +mp_result mp_int_to_int(mp_int z, mp_small *out); + Convert z to an int type, if it is representable as such. Returns + MP_RANGE if z cannot be represented as an value of type mp_small. If + out is NULL no value is stored, but the return value will still be + correct. + +mp_result mp_int_to_uint(mp_int z, mp_usmall *out); + Convert z to an unsigned int type, if it is representable as such. + Returns MP_RANGE if z cannot be represented as a value of type + mp_usmall. If out is NULL no value is stored, but the return value + will still be correct. + +mp_result mp_int_to_string(mp_int z, mp_size radix, char *str, int limit); + Convert z to a zero-terminated string of characters in the given + radix, writing at most 'limit' characters including the terminating + NUL value. A leading '-' is used to indicate a negative value. + + Returns MP_RANGE if radix < MP_MIN_RADIX or radix > MP_MAX_RADIX. + Returns MP_TRUNC if limit is too small to write out all of z. + +mp_result mp_int_string_len(mp_int z, mp_size radix); + Return the minimum number of characters required to represent z as a + zero-terminated string of characters in the given radix. May + over-estimate (but generally will not). + + Returns MP_RANGE if radix < MP_MIN_RADIX or radix > MP_MAX_RADIX. + +mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str); +mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, + char **end); + Read a string of ASCII digits in the specified radix from the + zero-terminated string provided, and assign z to the corresponding + value. For radices greater than 10, the ASCII letters 'A' .. 'Z' or + 'a' .. 'z' are used. Letters are interpreted without respect to + case. + + Leading whitespace is ignored, and a leading '+' or '-' is + interpreted as a sign flag. Processing stops when ASCII NUL or any + character which is out of range for a digit in the given radix is + encountered. + + If the whole string was processed, MP_OK is returned; otherwise, + MP_TRUNC is returned. + + Returns MP_RANGE if radix < MP_MIN_RADIX or radix > MP_MAX_RADIX. + + With mp_int_read_cstring(), if end is not NULL, the target pointer is + set to point to the first unconsumed character of the input string + (the NUL byte, if the whole string was consumed). This emulates the + behavior of the standard C strtol() function. + +mp_result mp_int_count_bits(mp_int z); + Returns the number of significant bits in z. + +mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit); + Convert z to 2's complement binary, writing at most 'limit' bytes + into the given buffer. Returns MP_TRUNC if the buffer limit was too + small to contain the whole value. If this occurs, the contents of + buf will be effectively garbage, as the function uses the buffer as + scratch space. + + The binary representation of z is in base-256 with digits ordered + from most significant to least significant (network byte ordering). + The high-order bit of the first byte is set for negative values, + clear for non-negative values. + + As a result, non-negative values will be padded with a leading zero + byte if the high-order byte of the base-256 magnitude is set. This + extra byte is accounted for by the mp_int_binary_len() function + described below. + +mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len); + Read a 2's complement binary value into z, where the length of the + buffer is given as 'len'. The contents of 'buf' may be overwritten + during processing, although they will be restored when the function + returns. + +mp_result mp_int_binary_len(mp_int z); + Return the number of bytes required to represent z in 2's complement + binary. + +mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit); + Convert |z| to unsigned binary, writing at most 'limit' bytes into + the given buffer. The sign of z is ignored, but z is not modified. + Returns MP_TRUNC if the buffer limit was too small to contain the + whole value. If this occurs, the contents of buf will be effectively + garbage, as the function uses the buffer as scratch space during + conversion. + + The binary representation of z is in base-256 with digits ordered + from most significant to least significant (network byte ordering). + +mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len); + Read an unsigned binary value into z, where the length of the buffer + is given as 'len'. The contents of 'buf' will not be modified during + processing. + +mp_result mp_int_unsigned_len(mp_int z); + Return the number of bytes required to represent z as an unsigned + binary value using mp_int_to_unsigned(). + +- Other functions: + +Ordinarily, integer multiplication and squaring are done using the simple +quadratic "schoolbook" algorithm. However, for sufficiently large values, +there is a more efficient algorithm usually attributed to Karatsuba and Ofman +that is usually faster. See Knuth Vol. 2 for more details about how this +algorithm works. + +The breakpoint between the "normal" and the recursive algorithm is controlled +by a static constant "multiply_threshold" defined in imath.c, which contains +the number of significant digits below which the standard algorithm should be +used. This is initialized to the value of the compile-time constant +MP_MULT_THRESH from imath.h. If you wish to be able to modify this value at +runtime, compile imath.c with IMATH_TEST defined true in the preprocessor, and +declare + + extern mp_size multiply_threshold; + +When IMATH_TEST is defined, this variable is defined as a mutable global, and +can be changed. Otherwise, it is defined as an immutable static constant. The +`imtimer' program and the `findthreshold.py' script (Python) can help you find +a suitable value for MP_MULT_THRESH for your particular platform. + +const char *mp_int_error_string(mp_result res); + Return a pointer to a brief string describing 'res'. These strings + are defined as a constant array in `imath.c', if you wish to change + them for your application. + +--- Rational Arithmetic: + +mp_result mp_rat_init(mp_rat r); + Initialize a new zero-valued rational number in r. + +mp_result mp_rat_reduce(mp_rat r); + Reduce a rational to canonical form. + Removes common factors from the numerator and denomenator and makes + the denomenator positive. + +mp_result mp_rat_init_size(mp_rat r, mp_size n_prec, mp_size d_prec); + As mp_rat_init(), but specifies the number of long digits of + precision for numerator (n_prec) and denominator (d_prec). Use this + if you wish to preallocate storage for operations of known output + size. + +mp_result mp_rat_init_copy(mp_rat r, mp_rat old); + As mp_rat_init(), but initializes a copy of an existing rational + value. + +mp_result mp_rat_set_value(mp_rat r, mp_small numer, mp_small denom); + Set the value of the given rational to a ratio specified as ordinary + signed integers (denom != 0). Returns MP_UNDEF if denom = 0. + +void mp_rat_clear(mp_rat r); + Release the memory occupied by the given rational number. + +mp_result mp_rat_numer(mp_rat r, mp_int z); + Extract the numerator of r as an mp_int, and store it in z. + +mp_result mp_rat_denom(mp_rat r, mp_int z); + Extract the denominator of r as an mp_int, and store it in z. + +mp_sign mp_rat_sign(mp_rat r); + Return the sign of the rational number. Note that an mpq_t + is always stored so that the sign of the numerator is the + correct sign of the whole value. + +mp_result mp_rat_copy(mp_rat a, mp_rat c); + Copy a to c. Avoids unnecessary allocations. + +void mp_rat_zero(mp_rat r); + Set r to have the value zero (canonical with denominator 1). + +mp_result mp_rat_abs(mp_rat a, mp_rat c); + Set c to the absolute value of a. + +mp_result mp_rat_neg(mp_rat a, mp_rat c); + Set c to the negative (additive inverse) of a. + +mp_result mp_rat_recip(mp_rat a, mp_rat c); + Take the reciprocal of a and store it in c, if defined. + Returns MP_UNDEF if a/c = 0. + +mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c); + Add a + b and store the result in c. + +mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c); + Subtract a - b and store the result in c. + +mp_result mp_rat_mul(mp_rat a, mp_rat b, mp_rat c); + Multiply a * b and store the result in c. + +mp_result mp_rat_div(mp_rat a, mp_rat b, mp_rat c); + Divide a / b, if possible, and store the result in c. + Returns MP_UNDEF if b = 0. + +mp_result mp_rat_add_int(mp_rat a, mp_int b, mp_rat c); + Add a + b and store the result in c. Note: b is an integer. + +mp_result mp_rat_sub_int(mp_rat a, mp_int b, mp_rat c); + Subtract a - b and store the result in c. Note: b is an integer. + +mp_result mp_rat_mul_int(mp_rat a, mp_int b, mp_rat c); + Multiply a * b and store the result in c. Note: b is an integer. + +mp_result mp_rat_div_int(mp_rat a, mp_int b, mp_rat c); + Divide a / b, if possible, and store the result in c. + Note: b is an integer. + Returns MP_UNDEF if b = 0. + +mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c); + Raise a to the b power, where b >= 0, and store the result in c. + +int mp_rat_compare(mp_rat a, mp_rat b); + Full signed comparison of rational values. + +int mp_rat_compare_unsigned(mp_rat a, mp_rat b); + Compare the absolute values of a and b. + +int mp_rat_compare_zero(mp_rat r); + Compare r to zero. + +int mp_rat_compare_value(mp_rat r, mp_small n, mp_small d); + Compare r to the ratio n/d. + +int mp_rat_is_integer(mp_rat r); + Returns true if r can be represented by an integer (i.e., + its denominator is one). + +mp_result mp_rat_to_ints(mp_rat r, mp_small *num, mp_small *den); + If it is possible to do so, extract the numerator and the denominator + of r as regular (signed) integers. Returns MP_RANGE if either cannot + be so represented. + +mp_result mp_rat_to_string(mp_rat r, mp_size radix, char *str, int limit); + Convert the value of r to a string of the format "n/d" with n and d + in the specified radix, writing no more than "limit" bytes of data to + the given output buffer. Includes sign flag. + +mp_result mp_rat_to_decimal(mp_rat r, mp_size radix, mp_size prec, + mp_round_mode rmode, char *str, int limit); + Convert the value of r to a string in decimal-point notation with the + specified radix, writing no more than "limit" bytes of data to the + given output buffer. Generates "prec" digits of precision. + + Values numbers may be rounded when they are being converted for + output as a decimal value. There are four rounding modes currently + supported: + + MP_ROUND_DOWN + Truncates the value toward zero. + Example: 12.009 to 2dp becomes 12.00 + + MP_ROUND_UP + Rounds the value away from zero: + Example: 12.001 to 2dp becomes 12.01, but + 12.000 to 2dp remains 12.00 + + MP_ROUND_HALF_DOWN + Rounds the value to nearest digit, half goes toward zero. + Example: 12.005 to 2dp becomes 12.00, but + 12.006 to 2dp becomes 12.01 + + MP_ROUND_HALF_UP + Rounds the value to nearest digit, half rounds upward. + Example: 12.005 to 2dp becomes 12.01, but + 12.004 to 2dp becomes 12.00 + +mp_result mp_rat_string_len(mp_rat r, mp_size radix); + Return the length of buffer required to convert r using the + mp_rat_to_string() function. May over-estimate slightly. + +mp_result mp_rat_decimal_len(mp_rat r, mp_size radix, mp_size prec); + Return the length of buffer required to convert r using the + mp_rat_to_decimal() function. May over-estimate slightly. + +mp_result mp_rat_read_string(mp_rat r, mp_size radix, char *str); + Read a zero-terminated string in the format "n/d" (including sign + flag), and replace the value of r with it. + +mp_result mp_rat_read_cstring(mp_rat r, mp_size radix, char *str, char **end); + Like mp_rat_read_string(), but with a similar interface to the + strtoul() library function. Used as the back end for the + mp_rat_read_string() function. Returns MP_UNDEF if the denominator + read has value zero. + +mp_result mp_rat_read_ustring(mp_rat r, mp_size radix, char *str, char **end); + A "universal" reader. Capable of reading plain integers, rational + number written in a/b notation, and decimal values in z.f format. + The end parameter works as for mp_int_read_cstring(). + +mp_result mp_rat_read_decimal(mp_rat r, mp_size radix, char *str); + A wrapper around mp_rat_read_cdecimal(), which discards the resulting + end pointer. + +mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, char *str, char **end); + Read a zero-terminated string in the format "z.f" (including sign + flag), and replace r with its value. If end is not NULL, a pointer + to the first unconsumed character of the string is returned. + +--- Representation Details + + NOTE: You do not need to read this section to use IMath. This is provided + for the benefit of developers wishing to extend or modify the + internals of the library. + +IMath uses a signed magnitude representation for arbitrary precision integers. +The magnitude is represented as an array of radix-R digits in increasing order +of significance; the value of R is chosen to be half the size of the largest +available unsigned integer type, so typically 16 or 32 bits. Digits are +represented as mp_digit, which must be an unsigned integral type. + +Digit arrays are allocated using malloc(3) and realloc(3). Because this can be +an expensive operation, the library takes pains to avoid allocation as much as +possible. For this reason, the mpz_t structure distinguishes between how many +digits are allocated and how many digits are actually consumed by the +representation. The fields of an mpz_t are: + + mp_digit single; /* single-digit value (see note) */ + mp_digit *digits; /* array of digits */ + mp_size alloc; /* how many digits are allocated */ + mp_size used; /* how many digits are in use */ + mp_sign sign; /* the sign of the value */ + +The elements of "digits" at indices less than "used" are the significant +figures of the value; the elements at indices greater than or equal to "used" +are undefined (and may contain garbage). At all times, "used" must be at least +1 and at most "alloc". + +To avoid interaction with the memory allocator, single-digit values are stored +directly in the mpz_t structure, in the .single field. The semantics of access +are the same as the more general case. + +The number of digits allocated for an mpz_t is referred to in the library +documentation as its "precision". Operations that affect an mpz_t cause +precision to increase as needed. In any case, all allocations are measured in +digits, and rounded up to the nearest mp_word boundary. There is a default +minimum precision stored as a static constant default_precision (imath.c); its +value is set to MP_DEFAULT_PREC (imath.h). If the preprocessor symbol +IMATH_TEST is defined, this value becomes global and modifiable. + +Note that the allocated size of an mpz_t can only grow; the library never +reallocates in order to decrease the size. A simple way to do so explicitly is +to use mp_int_init_copy(), as in: + + mpz_t big, new; + + /* ... */ + mp_int_init_copy(&new, &big); + mp_int_swap(&new, &big); + mp_int_clear(&new); + +The value of "sign" is 0 for positive values and zero, 1 for negative values. +Constants MP_ZPOS and MP_NEG are defined for these; no other sign values are +used. + +If you are adding to this library, you should be careful to preserve the +convention that inputs and outputs can overlap, as described above. So, for +example, mp_int_add(a, a, a) is legal. Often, this means you must maintain one +or more temporary mpz_t structures for intermediate values. The private macros +SETUP(E, C) and TEMP(K) can be used to enforce a conventional structure like +this: + + { + mpz_t temp[NUM_TEMPS]; /* declare how many you need here */ + int last = 0; /* number of in-use temps */ + mp_result res; /* used for checking results */ + ... + + /* Initialization phase */ + SETUP(mp_int_init(TEMP(0)), last); + SETUP(mp_int_init_copy(TEMP(1), x), last); + ... + SETUP(mp_int_init_value(TEMP(7), 3), last); + + /* Work phase */ + ... + + CLEANUP: + while(--last >= 0) + mp_int_clear(TEMP(last)); + + return res; + } + +The names "temp" and "res" are fixed -- the SETUP and TEMP macros assume they +exist. TEMP(k) returns a pointer to the kth entry of temp. This structure +insures that even if a failure occurs during the "initialization phase", no +memory is leaked. + +"Small" integer values are represented by the types mp_small and mp_usmall, +which are mapped to appropriately-sized types on the host system. The default +for mp_small is "long" and the default for mp_usmall is "unsigned long". You +may change these, provided you insure that mp_small is signed and mp_usmall is +unsigned. You will also need to adjust the size macros: + + MP_SMALL_MIN, MP_SMALL_MAX + MP_USMALL_MIN, MP_USMALL_MAX + +... which are defined in , if you change these. + +Rational numbers are represented using a pair of arbitrary precision integers, +with the convention that the sign of the numerator is the sign of the rational +value, and that the result of any rational operation is always represented in +lowest terms. The canonical representation for rational zero is 0/1. See +"imrat.h". + +--- Testing and Reporting of Bugs: + +Test vectors are included in the 'tests' subdirectory of the imath +distribution. When you run 'make test', it builds the imtest program and runs +all available test vectors. If any tests fail, you will get a line like this: + + x y FAILED v + +Here, x is the line number of the test which failed, y is index of the test +within the file, and v is the value(s) actually computed. The name of the file +is printed at the beginning of each test, so you can find out what test vector +failed by executing the following (with x, y, and v replaced by the above +values, and where "foo.t" is the name of the test file that was being processed +at the time): + + % tail +x tests/foo.t | head -1 + +None of the tests should fail [but see Note 2]; if any do, it probably +indicates a bug in the library (or at the very least, some assumption I made +which I shouldn't have). Please send a bug report to the address below, which +includes the FAILED test line above, as well as the output of the above 'tail' +command (so I know what inputs caused the failure). + +If you build with the preprocessor symbol DEBUG defined as a positive integer, +you will have access to several things: + + 1. The static functions defined in imath.c are made globally visible so that + you can call them from a test driver. + + 2. The s_print() and s_print_buf() routines are defined; these make it easier + to dump the contents of an mpz_t to text. + + 3. If DEBUG > 1, the digit allocators (s_alloc, s_realloc) fill all new + buffers with the value 0xDEADBEEF, or as much of it as will fit in a digit, + so that you can more easily catch uninitialized reads in the debugger. + +--- Notes: + +1. You can generally use the same variables for both input and output. One + exception is that you may not use the same variable for both the quotient + and the remainder of mp_int_div(). + +2. Many of the tests for this library were written under the assumption that + the mp_small type is 32 bits or more. If you compile with a smaller type, + you may see MP_RANGE errors in some of the tests that otherwise pass (due to + conversion failures). Also, the pi generator (pi.c) will not work correctly + if mp_small is too short, as its algorithm for arc tangent is fairly + simple-minded. + +--- Contacts: + +The IMath library was written by +Michael J. Fromberger + +If you discover any bugs or testing failures, please send e-mail to +the following address: + + + +Please be sure to include, with any bug report, a complete description of what +goes wrong, and if possible, a test vector for imtest or a minimal test program +that will demonstrate the bug on your system. Please also let me know what +hardware, operating system, and compiler you're using. + +--- Acknowledgements: + +The algorithms used in this library came from Vol. 2 of Donald Knuth's "The Art +of Computer Programming" (Seminumerical Algorithms). Thanks to Nelson Bolyard, +Bryan Olson, Tom St. Denis, Tushar Udeshi, and Eric Silva for excellent +feedback on earlier versions of this code. Special thanks to Jonathan Shapiro +for some very helpful design advice, as well as feedback and some clever ideas +for improving performance in some common use cases. + +--- License and Disclaimers: + +IMath is Copyright 2002-2009 Michael J. Fromberger +You may use it subject to the following Licensing Terms: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. Index: contrib/isl/imath/examples/basecvt.c =================================================================== --- /dev/null +++ contrib/isl/imath/examples/basecvt.c @@ -0,0 +1,121 @@ +/* + Name: basecvt.c + Purpose: Convert integers and rationals from one base to another. + Author: M. J. Fromberger + Info: $Id: basecvt.c 635 2008-01-08 18:19:40Z sting $ + + Copyright (C) 2004-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include +#include + +#include "imath.h" +#include "imrat.h" + +int main(int argc, char *argv[]) +{ + mp_size in_rdx, out_rdx; + mpq_t value; + mp_result res; + int ix; + + if(argc < 4) { + fprintf(stderr, "Usage: basecvt +\n"); + return 1; + } + + in_rdx = atoi(argv[1]); + out_rdx = atoi(argv[2]); + + if(in_rdx < MP_MIN_RADIX || in_rdx > MP_MAX_RADIX) { + fprintf(stderr, + "basecvt: input radix %u not allowed (minimum %u, " + "maximum %u)\n", in_rdx, MP_MIN_RADIX, MP_MAX_RADIX); + return 3; + } + if(out_rdx < MP_MIN_RADIX || out_rdx > MP_MAX_RADIX) { + fprintf(stderr, + "basecvt: output radix %u not allowed (minimum %u, " + "maximum %u)\n", out_rdx, MP_MIN_RADIX, MP_MAX_RADIX); + return 3; + } + + if((res = mp_rat_init(&value)) != MP_OK) { + fprintf(stderr, "basecvt: out of memory\n"); + return 2; + } + + for(ix = 3; ix < argc; ++ix) { + char *buf, *endp = NULL; + mp_result len; + int is_int; + + if((res = mp_rat_read_ustring(&value, in_rdx, argv[ix], &endp)) != MP_OK && + res != MP_TRUNC) { + fprintf(stderr, "basecvt: error reading argument %d: %s\n", ix, + mp_error_string(res)); + break; + } + else if(*endp != '\0') { + fprintf(stderr, "basecvt: argument %d contains '%s' not in base %u\n", + ix, endp, in_rdx); + continue; + } + + if((is_int = mp_rat_is_integer(&value)) != 0) { + len = mp_int_string_len(MP_NUMER_P(&value), out_rdx); + } + else { + len = mp_rat_string_len(&value, out_rdx); + } + + if((buf = malloc(len)) == NULL) { + fprintf(stderr, "basecvt: out of memory\n"); + break; + } + + if(is_int) { + res = mp_int_to_string(MP_NUMER_P(&value), out_rdx, buf, len); + } + else { + res = mp_rat_to_string(&value, out_rdx, buf, len); + } + + if(res != MP_OK) { + fprintf(stderr, "basecvt: error converting argument %d: %s\n", ix, + mp_error_string(res)); + free(buf); + break; + } + + printf("%s\n", buf); + free(buf); + } + + mp_rat_clear(&value); + + return (res != MP_OK); +} + +/* Here there be dragons */ Index: contrib/isl/imath/examples/findprime.c =================================================================== --- /dev/null +++ contrib/isl/imath/examples/findprime.c @@ -0,0 +1,72 @@ +/* + Name: findprime.c + Purpose: Find probable primes. + Author: M. J. Fromberger + Info: $Id: findprime.c 635 2008-01-08 18:19:40Z sting $ + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Notes: + Find the first prime number in sequence starting from the given value. + Demonstrates the use of mp_int_find_prime(). + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include + +#include "iprime.h" + +int main(int argc, char *argv[]) +{ + char buf[4096]; + mpz_t seed; + mp_result res; + + if(argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + mp_int_init(&seed); + if((res = mp_int_read_string(&seed, 10, argv[1])) != MP_OK) { + fprintf(stderr, "%s: error reading `%s': %d\n", + argv[0], argv[1], res); + return 2; + } + + if(mp_int_compare_value(&seed, 131) <= 0) { + fprintf(stderr, "%s: please enter a start value > 131\n", + argv[0]); + return 1; + } + + if((res = mp_int_find_prime(&seed)) != MP_TRUE) { + fprintf(stderr, "%s: error finding prime: %d\n", + argv[0], res); + return 2; + } + + mp_int_to_string(&seed, 10, buf, sizeof(buf)); + printf("=> %s\n", buf); + + mp_int_clear(&seed); + + return 0; +} Index: contrib/isl/imath/examples/imcalc.c =================================================================== --- /dev/null +++ contrib/isl/imath/examples/imcalc.c @@ -0,0 +1,1231 @@ +/* + Name: imcalc.c + Purpose: Simple RPN calculator based on IMath library. + Author: M. J. Fromberger + + This is a very simplistic RPN calculator that will let you test the features + of the IMath built-in functions. + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "imath.h" +#include "imrat.h" +#include "iprime.h" + +/* A cstate_t represents a stack of operands; numeric operands are pushed on + the stack, and commands cause them to be consumed in various ways. + */ +typedef struct { + /* Operand stack */ + mp_int *elts; + mp_size alloc; /* number of slots available */ + mp_size used; /* number of slots free */ + + /* Named variables */ + mp_int *mem; /* named memory slots */ + char **names; /* names of memory slots */ + mp_size mslots; /* number of memory slots */ + mp_size mused; /* number of used memories */ + + /* I/O components */ + FILE *ifp; /* input file handle */ + char *ibuf; /* input scratch buffer */ + int buflen; /* size of scratch buffer */ +} cstate_t; + +static mp_result state_init(cstate_t *sp, mp_size n_elts); +static void state_clear(cstate_t *sp); +static void stack_flush(cstate_t *sp); +static mp_result stack_push(cstate_t *sp, mp_int elt); +static mp_result stack_pop(cstate_t *sp); +static mp_result mem_insert(cstate_t *sp, const char *name, mp_int value); +static mp_result mem_recall(cstate_t *sp, const char *name, mp_int value); +static mp_result mem_clear(cstate_t *sp); + +typedef mp_result (*op_func)(cstate_t *); + +static mp_result cf_abs(cstate_t *sp); +static mp_result cf_neg(cstate_t *sp); +static mp_result cf_add(cstate_t *sp); +static mp_result cf_sub(cstate_t *sp); +static mp_result cf_mul(cstate_t *sp); +static mp_result cf_divmod(cstate_t *sp); +static mp_result cf_div(cstate_t *sp); +static mp_result cf_mod(cstate_t *sp); +static mp_result cf_expt(cstate_t *sp); +static mp_result cf_exptmod(cstate_t *sp); +static mp_result cf_square(cstate_t *sp); +static mp_result cf_invmod(cstate_t *sp); +static mp_result cf_gcd(cstate_t *sp); +static mp_result cf_xgcd(cstate_t *sp); +static mp_result cf_sqrt(cstate_t *sp); +static mp_result cf_root(cstate_t *sp); +static mp_result cf_cmplt(cstate_t *sp); +static mp_result cf_cmpgt(cstate_t *sp); +static mp_result cf_cmple(cstate_t *sp); +static mp_result cf_cmpge(cstate_t *sp); +static mp_result cf_cmpeq(cstate_t *sp); +static mp_result cf_cmpne(cstate_t *sp); +static mp_result cf_inc(cstate_t *sp); +static mp_result cf_dec(cstate_t *sp); +static mp_result cf_fact(cstate_t *sp); +static mp_result cf_pprint(cstate_t *sp); +static mp_result cf_print(cstate_t *sp); +static mp_result cf_pstack(cstate_t *sp); +static mp_result cf_clstk(cstate_t *sp); +static mp_result cf_pop(cstate_t *sp); +static mp_result cf_dup(cstate_t *sp); +static mp_result cf_copy(cstate_t *sp); +static mp_result cf_swap(cstate_t *sp); +static mp_result cf_rot(cstate_t *sp); +static mp_result cf_pick(cstate_t *sp); +static mp_result cf_setr(cstate_t *sp); +static mp_result cf_setbin(cstate_t *sp); +static mp_result cf_help(cstate_t *sp); +static mp_result cf_store(cstate_t *sp); +static mp_result cf_recall(cstate_t *sp); +static mp_result cf_cmem(cstate_t *sp); +static mp_result cf_pmem(cstate_t *sp); +static mp_result cf_qrecall(cstate_t *sp); + +typedef struct { + char *name; /* The name of the operator. */ + int stack_size; /* Number of stack arguments required. */ + op_func handler; /* Function implementing operation. */ + char *descript; /* Human-readable description. */ +} calcop_t; + +static calcop_t g_ops[] = { + { "abs", 1, cf_abs, "x -- |x|" }, + { "neg", 1, cf_neg, "x -- (-x)" }, + { "+", 2, cf_add, "x y -- (x+y)" }, + { "add", 2, cf_add, "x y -- (x+y)" }, + { "-", 2, cf_sub, "x y -- (x-y)" }, + { "sub", 2, cf_sub, "x y -- (x-y)" }, + { "*", 2, cf_mul, "x y -- (x*y)" }, + { "mul", 2, cf_mul, "x y -- (x*y)" }, + { "/", 2, cf_divmod, "x y -- q r ; x = yq + r, 0 <= r < y" }, + { "//", 2, cf_div, "x y -- (x div y)" }, + { "div", 2, cf_div, "x y -- (x div y)" }, + { "%", 2, cf_mod, "x y -- (x mod y)" }, + { "mod", 2, cf_mod, "x y -- (x mod y)" }, + { "^", 2, cf_expt, "x y -- (x^y)" }, + { "expt", 2, cf_expt, "x y -- (x^y)" }, + { "^^", 3, cf_exptmod, "x y m -- (x^y mod m)" }, + { "emod", 3, cf_exptmod, "x y m -- (x^y mod m)" }, + { "sqr", 1, cf_square, "x -- (x*x)" }, + { "inv", 2, cf_invmod, "x m -- (1/x mod m)" }, + { "gcd", 2, cf_gcd, "x y -- gcd(x, y)" }, + { "xgcd", 2, cf_xgcd, "x y -- g u v ; g = ux + vy" }, + { "sqrt", 1, cf_sqrt, "x -- floor(sqrt(x))" }, + { "root", 2, cf_root, "x y -- floor(x^{1/y}) ; y > 0" }, + { "<", 2, cf_cmplt, "x y -- (x", 2, cf_cmpgt, "x y -- (x>y)" }, + { "<=", 2, cf_cmple, "x y -- (x<=y)" }, + { ">=", 2, cf_cmpge, "x y -- (x>=y)" }, + { "=", 2, cf_cmpeq, "x y -- (x=y)" }, + { "<>", 2, cf_cmpne, "x y -- (x<>y)" }, + { "inc", 1, cf_inc, "x -- (x+1)" }, + { "dec", 1, cf_dec, "x -- (x-1)" }, + { "!", 1, cf_fact, "x -- x!" }, + { "fact", 1, cf_fact, "x -- x!" }, + + { ".", 1, cf_pprint, "x -- ; print x in current output mode" }, + { ";", 1, cf_print, "x -- x ; print x in current output mode" }, + { "?", 0, cf_pstack, "-- ; print stack" }, + { "cls", 0, cf_clstk, "... -- ; clear stack" }, + { "$", 1, cf_pop, "x --" }, + { "drop", 1, cf_pop, "x --" }, + { "dup", 1, cf_dup, "x -- x x" }, + { "copy", 2, cf_copy, "vn ... v1 v0 n -- vn ... v0 vn ... v0" }, + { "swap", 2, cf_swap, "x y -- y x" }, + { "rot", 3, cf_rot, "a b c -- b c a" }, + { "pick", 2, cf_pick, "... v2 v1 v0 n -- ... v2 v1 v0 vn" }, + + { ">>", 1, cf_store, "x -- ; save in named variable" }, + { "<<", 0, cf_recall, "-- x ; recall from named variable" }, + { "clm", 0, cf_cmem, "-- ; clear memory" }, + { "??", 0, cf_pmem, "-- ; print memory" }, + + { "out", 1, cf_setr, "r -- ; set output radix to r" }, + { "bin", 0, cf_setbin, "-- ; set output format to binary" }, + { "help", 0, cf_help, "-- ; print help message" }, + + /* This is the end-marker, but it is also used to catch implicit + variable lookups from memory. + */ + { NULL, 0, cf_qrecall, "-- x ; recall from named variable" }, +}; + +#define BUFFER_SIZE 16384 /* max. length of input values, in chars */ + +/* Token types from the primitive lexical analyzer */ +typedef enum { t_eof, t_symbol, t_number, t_error } token_t; + +static token_t next_token(FILE *ifp, char *buf, int size); +static mp_result read_number(char *buf, mp_int *out); +static int find_command(cstate_t *ops); +static void print_value(mp_int v); +static mp_result run_file(FILE *ifp, cstate_t *op_state); + +/* Error code used internally to signal input problems. */ +static mp_result MP_INPUT; + +static int g_output_radix = 10; /* output radix */ +static FILE *g_output_file = NULL; + +int main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + + int opt, errs = 0; + FILE *ifp; + + cstate_t op_state; + mp_result res; + + MP_INPUT = MP_MINERR - 1; + + g_output_file = stdout; + while((opt = getopt(argc, argv, "ho:")) != EOF) { + switch(opt) { + case 'h': + fprintf(stderr, + "Usage: imcalc [-h] [-o ] input*\n\n" + "Options:\n" + " -h : display this help message.\n" + " -o : send output to file.\n\n" + + "If no input files are given, the standard input is read. The\n" + "special file name \"-\" is interpreted to mean the standard input.\n" + "Output goes to standard output unless \"-o\" is used.\n\n"); + return 0; + + case 'o': + if((g_output_file = fopen(optarg, "wt")) == NULL) { + fprintf(stderr, "Unable to open \"%s\" for writing: %s\n", + optarg, strerror(errno)); + return 1; + } + break; + + default: + fprintf(stderr, + "Usage: imcalc [-h] [-o ] input*\n" + " [use \"imcalc -h\" to get help]\n\n"); + return 1; + } + } + + if((res = state_init(&op_state, 1)) != MP_OK) { + fprintf(stderr, "Error: state_init: %s\n", + mp_error_string(res)); + return 1; + } + + if(optind < argc) { + int ix; + + for(ix = optind; ix < argc; ++ix) { + if(strcmp(argv[ix], "-") == 0) + ifp = stdin; + else if((ifp = fopen(argv[optind], "rt")) == NULL) { + fprintf(stderr, "Unable to open \"%s\" for reading: %s\n", + argv[optind], strerror(errno)); + return 1; + } + + if(run_file(ifp, &op_state) != MP_OK) + ++errs; + } + + state_clear(&op_state); + return errs > 0; + } + else { + int rv = 1 - (run_file(stdin, &op_state) == MP_OK); + state_clear(&op_state); + return rv; + } +} + +static token_t next_token(FILE *ifp, char *buf, int size) +{ + int ch, pos = 0; + token_t res; + + assert(buf != NULL && size > 0); + + while((ch = fgetc(ifp)) != EOF && isspace(ch)) + /* empty */; + + if(ch == EOF) { + buf[0] = '\0'; + return t_eof; + } + + if(ch == '-') { + int next = fgetc(ifp); + if(next == EOF || !isdigit(next)) + res = t_symbol; + else + res = t_number; + ungetc(next, ifp); + } + else if(isdigit(ch) || ch == '#') + res = t_number; + else + res = t_symbol; + + buf[pos++] = ch; + while((ch = fgetc(ifp)) != EOF) { + if((res == t_number && ispunct(ch) && ch != '-') || + (res == t_symbol && isdigit(ch)) || + isspace(ch)) { + ungetc(ch, ifp); + break; + } + else if(pos + 1 >= size) { + res = t_error; + break; + } + buf[pos++] = ch; + } + + buf[pos] = '\0'; + return res; +} + +static mp_result read_number(char *buf, mp_int *out) +{ + int radix = 10, pos = 0; + mp_result res; + mp_int value; + + assert(buf != NULL && out != NULL); + + if(buf[pos] == '#') { + switch(buf[1]) { + case 'b': case 'B': + radix = 2; + break; + case 'd': case 'D': + radix = 10; + break; + case 'o': case 'O': + radix = 8; + break; + case 'x': case 'X': + radix = 16; + break; + default: + return MP_BADARG; + } + + pos += 2; + } + + if((value = mp_int_alloc()) == NULL) { + *out = NULL; + return MP_MEMORY; + } + + if((res = mp_int_read_string(value, radix, buf + pos)) != MP_OK) { + mp_int_free(value); + *out = NULL; + return res; + } + + *out = value; + return res; +} + +static int find_command(cstate_t *op) +{ + int ix, jx; + char *buf = op->ibuf; + + /* First, try to find the command by name */ + for(ix = 0; g_ops[ix].name != NULL; ++ix) { + if(strcasecmp(buf, g_ops[ix].name) == 0) + return ix; + } + + /* If we don't find the command, try a variable lookup */ + for(jx = 0; jx < op->mused; ++jx) { + if(strcmp(buf, op->names[jx]) == 0) + return ix; /* sentinel */ + } + + /* If variable lookup fails, report command not found */ + return -1; +} + +static void print_value(mp_int v) +{ + if(g_output_radix == 0) { + mp_result len = mp_int_binary_len(v); + unsigned char *buf = malloc(len); + int ix; + + if(buf != NULL) { + mp_int_to_binary(v, buf, len); + for(ix = 0; ix < len - 1; ++ix) { + fprintf(g_output_file, "%02x.", buf[ix]); + } + fprintf(g_output_file, "%02x\n", buf[ix]); + free(buf); + } + else + fprintf(g_output_file, "\n"); + } + else { + mp_result len = mp_int_string_len(v, g_output_radix); + char *buf = malloc(len); + + if(buf != NULL) { + mp_int_to_string(v, g_output_radix, buf, len); + fputs(buf, g_output_file); + fputc('\n', g_output_file); + free(buf); + } + else + fprintf(g_output_file, "\n"); + } +} + +static mp_result run_file(FILE *ifp, cstate_t *op_state) +{ + mp_result res = MP_OK; + token_t next; + + op_state->ifp = ifp; + while((next = next_token(ifp, op_state->ibuf, op_state->buflen)) != t_eof) { + mp_int value = NULL; + int cpos; + + switch(next) { + case t_number: + if((res = read_number(op_state->ibuf, &value)) != MP_OK) + fprintf(stderr, "error: invalid number syntax: %s\n", op_state->ibuf); + else if((res = stack_push(op_state, value)) != MP_OK) + goto EXIT; + break; + case t_symbol: + if((cpos = find_command(op_state)) < 0) + fprintf(stderr, "error: command not understood: %s\n", op_state->ibuf); + else if(op_state->used < g_ops[cpos].stack_size) { + fprintf(stderr, "error: not enough arguments (have %d, want %d)\n", + op_state->used, g_ops[cpos].stack_size); + } + else if((res = (g_ops[cpos].handler)(op_state)) != MP_OK) { + if(res == MP_INPUT) + fprintf(stderr, "error: incorrect input format\n"); + else + fprintf(stderr, "error: %s\n", mp_error_string(res)); + } + break; + default: + fprintf(stderr, "error: invalid input token: %s\n", op_state->ibuf); + res = MP_BADARG; + goto EXIT; + } + } + + EXIT: + return res; +} + +static mp_result state_init(cstate_t *sp, mp_size n_elts) +{ + int ix; + + assert(sp != NULL && n_elts > 0); + + if((sp->elts = malloc(n_elts * sizeof(*(sp->elts)))) == NULL) + return MP_MEMORY; + if((sp->mem = malloc(n_elts * sizeof(*(sp->mem)))) == NULL) { + free(sp->elts); + return MP_MEMORY; + } + if((sp->names = malloc(n_elts * sizeof(*(sp->names)))) == NULL) { + free(sp->mem); + free(sp->elts); + return MP_MEMORY; + } + if((sp->ibuf = malloc(BUFFER_SIZE * sizeof(char))) == NULL) { + free(sp->names); + free(sp->mem); + free(sp->elts); + return MP_MEMORY; + } + + for(ix = 0; ix < n_elts; ++ix) { + sp->elts[ix] = NULL; + sp->mem[ix] = NULL; + sp->names[ix] = NULL; + } + + sp->alloc = n_elts; + sp->used = 0; + sp->mslots = n_elts; + sp->mused = 0; + sp->buflen = BUFFER_SIZE; + + return MP_OK; +} + +static void state_clear(cstate_t *sp) +{ + assert(sp != NULL); + + if(sp->elts != NULL) { + int ix; + + for(ix = 0; ix < sp->used; ++ix) { + mp_int_clear(sp->elts[ix]); + sp->elts[ix] = NULL; + } + + free(sp->elts); + sp->elts = NULL; + sp->alloc = 0; + sp->used = 0; + } + if(sp->mem != NULL) { + int ix; + + for(ix = 0; ix < sp->mused; ++ix) { + mp_int_free(sp->mem[ix]); + sp->mem[ix] = NULL; + free(sp->names[ix]); + sp->names[ix] = NULL; + } + + free(sp->mem); + sp->mem = NULL; + free(sp->names); + sp->names = NULL; + + sp->mslots = 0; + sp->mused = 0; + } + if(sp->ibuf != NULL) { + free(sp->ibuf); + sp->buflen = 0; + } + if(sp->ifp != NULL) { + fclose(sp->ifp); + sp->ifp = NULL; + } +} + +static void stack_flush(cstate_t *sp) +{ + int ix; + + assert(sp != NULL && sp->elts != NULL); + + for(ix = 0; ix < sp->used; ++ix) { + mp_int_clear(sp->elts[ix]); + sp->elts[ix] = NULL; + } + + sp->used = 0; +} + +static mp_result stack_push(cstate_t *sp, mp_int elt) +{ + if(sp->used >= sp->alloc) { + mp_size nsize = 2 * sp->alloc; + mp_int *tmp; + int ix; + + if((tmp = malloc(nsize * sizeof(*(sp->elts)))) == NULL) + return MP_MEMORY; + + for(ix = 0; ix < sp->used; ++ix) + tmp[ix] = sp->elts[ix]; + + free(sp->elts); + sp->elts = tmp; + sp->alloc = nsize; + } + + sp->elts[sp->used++] = elt; + return MP_OK; +} + +static mp_result stack_pop(cstate_t *sp) +{ + assert(sp != NULL && sp->elts != NULL); + + if(sp->used == 0) + return MP_UNDEF; + + sp->used -= 1; + mp_int_clear(sp->elts[sp->used]); + sp->elts[sp->used] = NULL; + + return MP_OK; +} + +static mp_result mem_insert(cstate_t *sp, const char *name, mp_int value) +{ + int ix; + + for(ix = 0; ix < sp->mused; ++ix) { + if(strcmp(name, sp->names[ix]) == 0) + break; + } + + /* Two cases: + ix < sp->mused ==> replacing existing entry. + otherwise ==> adding new entry, may need to grow dictionary. + */ + if(ix < sp->mused) { + mp_int_free(sp->mem[ix]); /* fall through to the end */ + } + else { + if(sp->mused >= sp->mslots) { + mp_size nsize = 2 * sp->mslots; + mp_int *tz; + char **tc; + int jx; + + if((tz = malloc(nsize * sizeof(*(sp->mem)))) == NULL) + return MP_MEMORY; + if((tc = malloc(nsize * sizeof(*(sp->names)))) == NULL) { + free(tz); + return MP_MEMORY; + } + + for(jx = 0; jx < sp->mused; ++jx) { + tz[jx] = sp->mem[jx]; + tc[jx] = sp->names[jx]; + } + + free(sp->mem); + sp->mem = tz; + free(sp->names); + sp->names = tc; + + sp->mslots = nsize; + } + + sp->mused += 1; + sp->names[ix] = malloc(1 + strlen(name)); + strcpy(sp->names[ix], name); + } + + sp->mem[ix] = mp_int_alloc(); + return mp_int_copy(value, sp->mem[ix]); +} + +static mp_result mem_recall(cstate_t *sp, const char *name, mp_int value) +{ + int ix; + + for(ix = 0; ix < sp->mused; ++ix) { + if(strcmp(name, sp->names[ix]) == 0) { + return mp_int_copy(sp->mem[ix], value); + } + } + + return MP_UNDEF; /* not found */ +} + +static mp_result mem_clear(cstate_t *sp) +{ + int ix; + + for(ix = 0; ix < sp->mused; ++ix) { + mp_int_free(sp->mem[ix]); + free(sp->names[ix]); + } + sp->mused = 0; + + return MP_OK; +} + +static mp_result cf_abs(cstate_t *sp) +{ + mp_int a = sp->elts[sp->used - 1]; + + return mp_int_abs(a, a); +} + +static mp_result cf_neg(cstate_t *sp) +{ + mp_int a = sp->elts[sp->used - 1]; + + return mp_int_neg(a, a); +} + +static mp_result cf_add(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res = mp_int_add(a, b, a); + + if(res == MP_OK) + stack_pop(sp); + + return res; +} + +static mp_result cf_sub(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res = mp_int_sub(a, b, a); + + if(res == MP_OK) + stack_pop(sp); + + return res; +} + +static mp_result cf_mul(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res = mp_int_mul(a, b, a); + + if(res == MP_OK) + stack_pop(sp); + + return res; +} + +static mp_result cf_divmod(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + + return mp_int_div(a, b, a, b); +} + +static mp_result cf_div(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res = mp_int_div(a, b, a, NULL); + + if(res == MP_OK) + stack_pop(sp); + + return res; +} + +static mp_result cf_mod(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res = mp_int_mod(a, b, a); + + if(res == MP_OK) + stack_pop(sp); + + return res; +} + +static mp_result cf_expt(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res; + mp_small bval; + + if((res = mp_int_to_int(b, &bval)) != MP_OK) + return res; + + stack_pop(sp); + return mp_int_expt(a, bval, a); +} + +static mp_result cf_exptmod(cstate_t *sp) +{ + mp_int m = sp->elts[sp->used - 1]; + mp_int b = sp->elts[sp->used - 2]; + mp_int a = sp->elts[sp->used - 3]; + mp_result res = mp_int_exptmod(a, b, m, a); + + if(res == MP_OK) { + stack_pop(sp); + stack_pop(sp); + } + + return res; +} + +static mp_result cf_square(cstate_t *sp) +{ + mp_int a = sp->elts[sp->used - 1]; + + return mp_int_sqr(a, a); +} + +static mp_result cf_invmod(cstate_t *sp) +{ + mp_int m = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res = mp_int_invmod(a, m, a); + + stack_pop(sp); + + return res; +} + +static mp_result cf_gcd(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res = mp_int_gcd(a, b, a); + + if(res == MP_OK) + stack_pop(sp); + + return res; +} + +static mp_result cf_xgcd(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_int t; + mp_result res; + + if((t = mp_int_alloc()) == NULL) + return MP_MEMORY; + if((res = mp_int_egcd(a, b, a, b, t)) != MP_OK) { + mp_int_free(t); + return res; + } + + if((res = stack_push(sp, t)) != MP_OK) + mp_int_free(t); + + return res; +} + +static mp_result cf_sqrt(cstate_t *sp) +{ + mp_int a = sp->elts[sp->used - 1]; + + return mp_int_sqrt(a, a); +} + +static mp_result cf_root(cstate_t *sp) +{ + mp_int a = sp->elts[sp->used - 2]; + mp_int bp = sp->elts[sp->used - 1]; + mp_small b; + mp_result res; + + if((res = mp_int_to_int(bp, &b)) != MP_OK) + return res; + + stack_pop(sp); + return mp_int_root(a, b, a); +} + +static mp_result cf_cmplt(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res; + + res = mp_int_set_value(a, (mp_int_compare(a, b) < 0)); + stack_pop(sp); + return res; +} + +static mp_result cf_cmpgt(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res; + + res = mp_int_set_value(a, (mp_int_compare(a, b) > 0)); + stack_pop(sp); + return res; +} + +static mp_result cf_cmple(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res; + + res = mp_int_set_value(a, (mp_int_compare(a, b) <= 0)); + stack_pop(sp); + return res; +} + +static mp_result cf_cmpge(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res; + + res = mp_int_set_value(a, (mp_int_compare(a, b) >= 0)); + stack_pop(sp); + return res; +} + +static mp_result cf_cmpeq(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res; + + res = mp_int_set_value(a, (mp_int_compare(a, b) == 0)); + stack_pop(sp); + return res; +} + +static mp_result cf_cmpne(cstate_t *sp) +{ + mp_int b = sp->elts[sp->used - 1]; + mp_int a = sp->elts[sp->used - 2]; + mp_result res; + + res = mp_int_set_value(a, (mp_int_compare(a, b) != 0)); + stack_pop(sp); + return res; +} + +static mp_result cf_inc(cstate_t *sp) +{ + mp_int a = sp->elts[sp->used - 1]; + + return mp_int_add_value(a, 1, a); +} + +static mp_result cf_dec(cstate_t *sp) +{ + mp_int a = sp->elts[sp->used - 1]; + + return mp_int_sub_value(a, 1, a); +} + +static mp_result cf_fact(cstate_t *sp) +{ + mpz_t tmp; + mp_int x = sp->elts[sp->used - 1]; + mp_result res = MP_OK; + + if (mp_int_compare_zero(x) < 0) + return MP_UNDEF; + + (void) mp_int_init_value(&tmp, 1); + + while (mp_int_compare_value(x, 1) > 0) { + if ((res = mp_int_mul(&tmp, x, &tmp)) != MP_OK) + goto CLEANUP; + if ((res = mp_int_sub_value(x, 1, x)) != MP_OK) + goto CLEANUP; + } + + res = mp_int_copy(&tmp, x); + + CLEANUP: + mp_int_clear(&tmp); + return res; +} + +static mp_result cf_pprint(cstate_t *sp) +{ + print_value(sp->elts[sp->used - 1]); + stack_pop(sp); + return MP_OK; +} + +static mp_result cf_print(cstate_t *sp) +{ + print_value(sp->elts[sp->used - 1]); + return MP_OK; +} + +static mp_result cf_pstack(cstate_t *sp) +{ + int ix; + + if(sp->used == 0) { + fprintf(g_output_file, "\n"); + } + else { + for(ix = 0; ix < sp->used; ++ix) { + fprintf(g_output_file, "%2d: ", ix); + print_value(sp->elts[sp->used - 1 - ix]); + } + } + + return MP_OK; +} + +static mp_result cf_clstk(cstate_t *sp) +{ + stack_flush(sp); + + return MP_OK; +} + +static mp_result cf_pop(cstate_t *sp) +{ + return stack_pop(sp); +} + +static mp_result cf_dup(cstate_t *sp) +{ + mp_int cp = mp_int_alloc(); + mp_result res; + + if(cp == NULL) + return MP_MEMORY; + + if((res = mp_int_copy(sp->elts[sp->used - 1], cp)) != MP_OK) { + mp_int_free(cp); + return res; + } + + if((res = stack_push(sp, cp)) != MP_OK) + mp_int_free(cp); + + return res; +} + +static mp_result cf_copy(cstate_t *sp) +{ + mp_int n = sp->elts[sp->used - 1]; + mp_result res; + mp_small ncopy; + int ix; + + if((res = mp_int_to_int(n, &ncopy)) != MP_OK) + return res; + + if(ncopy < 1 || ncopy >= sp->used) + return MP_RANGE; + + stack_pop(sp); + + for(ix = 0; ix < ncopy; ++ix) { + mp_int old = sp->elts[sp->used - ncopy]; + mp_int new = mp_int_alloc(); + + if(new == NULL) + return MP_MEMORY; + + if((res = mp_int_copy(old, new)) != MP_OK) { + mp_int_free(new); + return res; + } + if((res = stack_push(sp, new)) != MP_OK) + return res; + } + + return MP_OK; +} + +static mp_result cf_swap(cstate_t *sp) +{ + mp_int t = sp->elts[sp->used - 1]; + + sp->elts[sp->used - 1] = sp->elts[sp->used - 2]; + sp->elts[sp->used - 2] = t; + + return MP_OK; +} + +static mp_result cf_rot(cstate_t *sp) +{ + mp_int t = sp->elts[sp->used - 3]; + + sp->elts[sp->used - 3] = sp->elts[sp->used - 2]; + sp->elts[sp->used - 2] = sp->elts[sp->used - 1]; + sp->elts[sp->used - 1] = t; + + return MP_OK; +} + +static mp_result cf_pick(cstate_t *sp) +{ + mp_int n = sp->elts[sp->used - 1]; + mp_result res; + mp_small pos = 0; + + if((res = mp_int_to_int(n, &pos)) != MP_OK) + return res; + + if(pos < 0 || pos >= sp->used - 1) + return MP_RANGE; + + return mp_int_copy(sp->elts[sp->used - 2 - pos], n); +} + +static mp_result cf_setr(cstate_t *sp) +{ + mp_int a = sp->elts[sp->used - 1]; + mp_result res; + mp_small rdx = 0; + + if((res = mp_int_to_int(a, &rdx)) != MP_OK) + return res; + + if(rdx < MP_MIN_RADIX || rdx > MP_MAX_RADIX) + return MP_RANGE; + + g_output_radix = rdx; + stack_pop(sp); + return MP_OK; +} + +static mp_result cf_setbin(cstate_t *sp) +{ + g_output_radix = 0; + return MP_OK; +} + +static mp_result cf_help(cstate_t *sp) +{ + int ix, maxlen = 10; /* minimum width */ + + for(ix = 0; g_ops[ix].name != NULL; ++ix) { + int len = strlen(g_ops[ix].name); + + if(len > maxlen) + maxlen = len; + } + + fprintf(stderr, "Operators understood:\n"); + for(ix = 0; g_ops[ix].name != NULL; ++ix) { + int len = strlen(g_ops[ix].name); + + fputs(g_ops[ix].name, stderr); + while(len++ <= maxlen) + fputc(' ', stderr); + + fprintf(stderr, "%s\n", g_ops[ix].descript); + } + fputc('\n', stderr); + + return MP_OK; +} + +static mp_result cf_store(cstate_t *sp) +{ + mp_result res; + + if(next_token(sp->ifp, sp->ibuf, sp->buflen) != t_symbol) + return MP_INPUT; + + if((res = mem_insert(sp, sp->ibuf, sp->elts[sp->used - 1])) != MP_OK) + return res; + + return stack_pop(sp); +} + +static mp_result cf_recall(cstate_t *sp) +{ + mp_result res; + mp_int val; + + if(next_token(sp->ifp, sp->ibuf, sp->buflen) != t_symbol) + return MP_INPUT; + + if((val = mp_int_alloc()) == NULL) + return MP_MEMORY; + if((res = mem_recall(sp, sp->ibuf, val)) != MP_OK) { + mp_int_free(val); + return res; + } + + return stack_push(sp, val); +} + +static mp_result cf_cmem(cstate_t *sp) +{ + return mem_clear(sp); +} + +static mp_result cf_pmem(cstate_t *sp) +{ + int ix, max_len = 0; + + if(sp->mused == 0) { + fprintf(g_output_file, "\n"); + return MP_OK; + } + + for(ix = 0; ix < sp->mused; ++ix) { + int ln = strlen(sp->names[ix]); + + if(ln > max_len) + max_len = ln; + } + + max_len += 1; /* allow for a padding space */ + + for(ix = 0; ix < sp->mused; ++ix) { + int ln = strlen(sp->names[ix]); + + fprintf(g_output_file, "%s:", sp->names[ix]); + + while(ln++ < max_len) + fputc(' ', g_output_file); + + print_value(sp->mem[ix]); + } + + return MP_OK; +} + +static mp_result cf_qrecall(cstate_t *sp) +{ + mp_result res; + mp_int val; + + if((val = mp_int_alloc()) == NULL) + return MP_MEMORY; + + if((res = mem_recall(sp, sp->ibuf, val)) != MP_OK) { + mp_int_free(val); + return res; + } + + return stack_push(sp, val); +} + +/* Here there be dragons */ Index: contrib/isl/imath/examples/input.c =================================================================== --- /dev/null +++ contrib/isl/imath/examples/input.c @@ -0,0 +1,120 @@ +/* + input.c + + Demonstrates basic input and output of arbitrary precision integers using + IMath. + + by Michael J. Fromberger + Copyright (C) 2003-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include + +#include "imrat.h" + +int main(int argc, char *argv[]) +{ + mp_size radix = 10; /* Default output radix */ + mpq_t value; + mp_result res; + char *endp; + + if(argc < 2) { + fprintf(stderr, "Usage: input [output-base]\n"); + return 1; + } + if(argc > 2) { + if((radix = atoi(argv[2])) < MP_MIN_RADIX || + (radix > MP_MAX_RADIX)) { + fprintf(stderr, "Error: Specified radix is out of range (%d)\n", + radix); + return 1; + } + } + + /* Initialize a new value, initially zero; illustrates how to check + for errors (e.g., out of memory) and display a message. */ + if((res = mp_rat_init(&value)) != MP_OK) { + fprintf(stderr, "Error in mp_rat_init(): %s\n", + mp_error_string(res)); + return 1; + } + + /* Read value in base 10 */ + if((res = mp_rat_read_ustring(&value, 0, argv[1], &endp)) != MP_OK) { + fprintf(stderr, "Error in mp_rat_read_ustring(): %s\n", + mp_error_string(res)); + + if(res == MP_TRUNC) + fprintf(stderr, " -- remaining input is: %s\n", endp); + + mp_rat_clear(&value); + return 1; + } + + printf("Here is your value in base %d\n", radix); + { + mp_result buf_size, res; + char *obuf; + + if(mp_rat_is_integer(&value)) { + /* Allocate a buffer big enough to hold the given value, including + sign and zero terminator. */ + buf_size = mp_int_string_len(MP_NUMER_P(&value), radix); + obuf = malloc(buf_size); + + /* Convert the value to a string in the desired radix. */ + if((res = mp_int_to_string(MP_NUMER_P(&value), radix, + obuf, buf_size)) != MP_OK) { + fprintf(stderr, "Converstion to base %d failed: %s\n", + radix, mp_error_string(res)); + mp_rat_clear(&value); + return 1; + } + } + else { + /* Allocate a buffer big enough to hold the given value, including + sign and zero terminator. */ + buf_size = mp_rat_string_len(&value, radix); + obuf = malloc(buf_size); + + /* Convert the value to a string in the desired radix. */ + if((res = mp_rat_to_string(&value, radix, obuf, buf_size)) != MP_OK) { + fprintf(stderr, "Conversion to base %d failed: %s\n", + radix, mp_error_string(res)); + mp_rat_clear(&value); + return 1; + } + } + fputs(obuf, stdout); + fputc('\n', stdout); + free(obuf); + } + + /* When you are done with a value, it must be "cleared" to release + the memory it occupies */ + mp_rat_clear(&value); + return 0; +} + +/* Here there be dragons */ Index: contrib/isl/imath/examples/randprime.c =================================================================== --- /dev/null +++ contrib/isl/imath/examples/randprime.c @@ -0,0 +1,245 @@ +/* + Name: randprime.c + Purpose: Generate a probable prime at random. + Author: M. J. Fromberger + + Usage: randprime [-s] [] + + Generate a randomly-chosen probable prime having significant bits, and + write it to the specified output file or to the standard output. If the "-s" + option is given, a prime p is chosen such that (p - 1) / 2 is also prime. + + A prime is obtained by reading random bits from /dev/random, setting the + low-order bit, and testing for primality. If the first candidate is not + prime, successive odd candidates are tried until a probable prime is found. + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +#include "imath.h" +#include "iprime.h" + +/* Load the specified buffer with random bytes */ +int randomize(unsigned char *buf, size_t len); + +/* Overwrite the specified value with n_bits random bits */ +mp_result mp_int_randomize(mp_int a, mp_size n_bits); + +/* Find a prime starting from the given odd seed */ +mp_result find_prime(mp_int seed, FILE *fb); +mp_result find_strong_prime(mp_int seed, FILE *fb); + +typedef mp_result (*find_f)(mp_int, FILE *); + +int main(int argc, char *argv[]) +{ + int opt, modbits; + FILE *ofp = stdout; + mp_result res; + find_f find_func = find_prime; + char tag = 'p'; + mpz_t value; + + /* Process command-line arguments */ + while((opt = getopt(argc, argv, "s")) != EOF) { + switch(opt) { + case 's': + find_func = find_strong_prime; + tag = 'P'; + break; + default: + fprintf(stderr, "Usage: randprime [-s] []\n"); + return 1; + } + } + + if(optind >= argc) { + fprintf(stderr, "Error: You must specify the number of significant bits.\n"); + fprintf(stderr, "Usage: randprime [-s] []\n"); + return 1; + } + modbits = (int) strtol(argv[optind++], NULL, 0); + if(modbits < CHAR_BIT) { + fprintf(stderr, "Error: Invalid value for number of significant bits.\n"); + return 1; + } + if(modbits % 2 == 1) + ++modbits; + + /* Check if output file is specified */ + if(optind < argc) { + if((ofp = fopen(argv[optind], "wt")) == NULL) { + fprintf(stderr, "Error: Unable to open output file for writing.\n" + " - Filename: %s\n" + " - Error: %s\n", argv[optind], strerror(errno)); + return 1; + } + } + + mp_int_init(&value); + if ((res = mp_int_randomize(&value, modbits - 1)) != MP_OK) { + fprintf(stderr, "Error: Unable to generate random start value.\n" + " - %s (%d)\n", mp_error_string(res), res); + goto EXIT; + } + fprintf(stderr, "%c: ", tag); + find_func(&value, stderr); + fputc('\n', stderr); + + /* Write the completed value to the specified output file */ + { + int len; + char *obuf; + + len = mp_int_string_len(&value, 10); + obuf = malloc(len); + mp_int_to_string(&value, 10, obuf, len); + fputs(obuf, ofp); + fputc('\n', ofp); + + free(obuf); + } + + EXIT: + fclose(ofp); + mp_int_clear(&value); + return 0; +} + +int randomize(unsigned char *buf, size_t len) +{ + FILE *rnd = fopen("/dev/random", "rb"); + size_t nr; + + if(rnd == NULL) + return -1; + + nr = fread(buf, sizeof(*buf), len, rnd); + fclose(rnd); + + return (int) nr; +} + +mp_result mp_int_randomize(mp_int a, mp_size n_bits) +{ + mp_size n_bytes = (n_bits + CHAR_BIT - 1) / CHAR_BIT; + unsigned char *buf; + mp_result res = MP_OK; + + if((buf = malloc(n_bytes)) == NULL) + return MP_MEMORY; + + if(randomize(buf, n_bytes) != n_bytes) { + res = MP_TRUNC; + goto CLEANUP; + } + + /* Clear bits beyond the number requested */ + if(n_bits % CHAR_BIT != 0) { + unsigned char b_mask = (1 << (n_bits % CHAR_BIT)) - 1; + unsigned char t_mask = (1 << (n_bits % CHAR_BIT)) >> 1; + + buf[0] &= b_mask; + buf[0] |= t_mask; + } + + /* Set low-order bit to insure value is odd */ + buf[n_bytes - 1] |= 1; + + res = mp_int_read_unsigned(a, buf, n_bytes); + + CLEANUP: + memset(buf, 0, n_bytes); + free(buf); + + return res; +} + +mp_result find_prime(mp_int seed, FILE *fb) +{ + mp_result res; + int count = 0; + + if(mp_int_is_even(seed)) + if((res = mp_int_add_value(seed, 1, seed)) != MP_OK) + return res; + + while((res = mp_int_is_prime(seed)) == MP_FALSE) { + ++count; + + if(fb != NULL && (count % 50) == 0) + fputc('.', fb); + + if((res = mp_int_add_value(seed, 2, seed)) != MP_OK) + return res; + } + + if(res == MP_TRUE && fb != NULL) + fputc('+', fb); + + return res; +} + +mp_result find_strong_prime(mp_int seed, FILE *fb) +{ + mp_result res; + mpz_t t; + + mp_int_init(&t); + for(;;) { + if ((res = find_prime(seed, fb)) != MP_TRUE) + break; + if ((res = mp_int_copy(seed, &t)) != MP_OK) + break; + + if ((res = mp_int_mul_pow2(&t, 1, &t)) != MP_OK || + (res = mp_int_add_value(&t, 1, &t)) != MP_OK) + break; + + if ((res = mp_int_is_prime(&t)) == MP_TRUE) { + if (fb != NULL) + fputc('!', fb); + + res = mp_int_copy(&t, seed); + break; + } + else if (res != MP_FALSE) + break; + + if (fb != NULL) + fputc('x', fb); + if ((res = mp_int_add_value(seed, 2, seed)) != MP_OK) + break; + } + + mp_int_clear(&t); + return res; +} + +/* Here there be dragons */ Index: contrib/isl/imath/examples/rounding.c =================================================================== --- /dev/null +++ contrib/isl/imath/examples/rounding.c @@ -0,0 +1,83 @@ +/* + Name: rounding.c + Purpose: Demonstrates rounding modes. + Author: M. J. Fromberger + + Bugs: The rounding mode can only be specified by value, not name. + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ +#include +#include +#include +#include + +#include "imath.h" +#include "imrat.h" + +int main(int argc, char *argv[]) +{ + mp_result mode, len, res = 0; + mp_size prec, radix; + mpq_t value; + char *buf; + + if(argc < 5) { + fprintf(stderr, "Usage: rounding \n"); + return 1; + } + + if((res = mp_rat_init(&value)) != MP_OK) { + fprintf(stderr, "Error initializing: %s\n", mp_error_string(res)); + return 2; + } + + mode = atoi(argv[1]); + prec = atoi(argv[2]); + radix = atoi(argv[3]); + + printf("Rounding mode: %d\n" + "Precision: %u digits\n" + "Radix: %u\n" + "Input string: \"%s\"\n", mode, prec, radix, argv[4]); + + if((res = mp_rat_read_decimal(&value, radix, argv[4])) != MP_OK) { + fprintf(stderr, "Error reading input string: %s\n", + mp_error_string(res)); + goto CLEANUP; + } + + len = mp_rat_decimal_len(&value, radix, prec); + buf = malloc(len); + + if((res = mp_rat_to_decimal(&value, radix, prec, mode, buf, len)) != MP_OK) + fprintf(stderr, "Error converting output: %s\n", + mp_error_string(res)); + + printf("Result string: \"%s\"\n", buf); + free(buf); + + CLEANUP: + mp_rat_clear(&value); + return res; +} + +/* Here there be dragons */ Index: contrib/isl/imath/examples/rsakey.c =================================================================== --- /dev/null +++ contrib/isl/imath/examples/rsakey.c @@ -0,0 +1,301 @@ +/* + Name: rsakey.c + Purpose: Generate keys for the RSA cryptosystem. + Author: M. J. Fromberger + + Usage: rsakey [-e ] [] + + Generates an RSA key pair with a modulus having significant bits, + and writes it to the specified output file, or to the standard output. The + -e option allows the user to specify an encryption exponent; otherwise, an + encryption exponent is chosen at random. + + Primes p and q are obtained by reading random bits from /dev/random, setting + the low-order bit, and testing for primality. If the first candidate is not + prime, successive odd candidates are tried until a probable prime is found. + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +#include "imath.h" +#include "iprime.h" + +typedef struct { + mpz_t p; + mpz_t q; + mpz_t n; + mpz_t e; + mpz_t d; +} rsa_key; + +/* Load the specified buffer with random bytes */ +int randomize(unsigned char *buf, size_t len); + +/* Overwrite the specified value with n_bits random bits */ +mp_result mp_int_randomize(mp_int a, mp_size n_bits); + +/* Find a prime starting from the given odd seed */ +mp_result find_prime(mp_int seed, FILE *fb); + +/* Initialize/destroy an rsa_key structure */ +mp_result rsa_key_init(rsa_key *kp); +void rsa_key_clear(rsa_key *kp); +void rsa_key_write(rsa_key *kp, FILE *ofp); + +int main(int argc, char *argv[]) +{ + int opt, modbits; + FILE *ofp = stdout; + char *expt = NULL; + rsa_key the_key; + mp_result res; + + /* Process command-line arguments */ + while((opt = getopt(argc, argv, "e:")) != EOF) { + switch(opt) { + case 'e': + expt = optarg; + break; + default: + fprintf(stderr, "Usage: rsakey [-e ] []\n"); + return 1; + } + } + + if(optind >= argc) { + fprintf(stderr, "Error: You must specify the number of modulus bits.\n"); + fprintf(stderr, "Usage: rsakey [-e ] []\n"); + return 1; + } + modbits = (int) strtol(argv[optind++], NULL, 0); + if(modbits < CHAR_BIT) { + fprintf(stderr, "Error: Invalid value for number of modulus bits.\n"); + return 1; + } + if(modbits % 2 == 1) + ++modbits; + + /* Check if output file is specified */ + if(optind < argc) { + if((ofp = fopen(argv[optind], "wt")) == NULL) { + fprintf(stderr, "Error: Unable to open output file for writing.\n" + " - Filename: %s\n" + " - Error: %s\n", argv[optind], strerror(errno)); + return 1; + } + } + + if((res = rsa_key_init(&the_key)) != MP_OK) { + fprintf(stderr, "Error initializing RSA key structure:\n" + " - %s (%d)\n", mp_error_string(res), res); + return 1; + } + + /* If specified, try to load the key exponent */ + if(expt != NULL) { + if((res = mp_int_read_string(&(the_key.e), 10, expt)) != MP_OK) { + fprintf(stderr, "Error: Invalid value for encryption exponent.\n" + " - %s (%d)\n", mp_error_string(res), res); + goto EXIT; + } + } + + if((res = mp_int_randomize(&(the_key.p), (modbits / 2))) != MP_OK) { + fprintf(stderr, "Error: Unable to randomize first prime.\n" + " - %s (%d)\n", mp_error_string(res), res); + goto EXIT; + } + fprintf(stderr, "p: "); + find_prime(&(the_key.p), stderr); + + if((res = mp_int_randomize(&(the_key.q), (modbits / 2))) != MP_OK) { + fprintf(stderr, "Error: Unable to randomize second prime.\n" + " - %s (%d)\n", mp_error_string(res), res); + goto EXIT; + } + fprintf(stderr, "\nq: "); + find_prime(&(the_key.q), stderr); + fputc('\n', stderr); + + /* Temporarily, the key's "n" field will be (p - 1) * (q - 1) for + purposes of computing the decryption exponent. + */ + mp_int_mul(&(the_key.p), &(the_key.q), &(the_key.n)); + mp_int_sub(&(the_key.n), &(the_key.p), &(the_key.n)); + mp_int_sub(&(the_key.n), &(the_key.q), &(the_key.n)); + mp_int_add_value(&(the_key.n), 1, &(the_key.n)); + + if(expt == NULL && + (res = mp_int_randomize(&(the_key.e), (modbits / 2))) != MP_OK) { + fprintf(stderr, "Error: Unable to randomize encryption exponent.\n" + " - %s (%d)\n", mp_error_string(res), res); + goto EXIT; + } + while((res = mp_int_invmod(&(the_key.e), &(the_key.n), + &(the_key.d))) != MP_OK) { + if(expt != NULL) { + fprintf(stderr, "Error: Unable to compute decryption exponent.\n" + " - %s (%d)\n", mp_error_string(res), res); + goto EXIT; + } + if((res = mp_int_randomize(&(the_key.e), (modbits / 2))) != MP_OK) { + fprintf(stderr, "Error: Unable to re-randomize encryption exponent.\n" + " - %s (%d)\n", mp_error_string(res), res); + goto EXIT; + } + } + + /* Recompute the real modulus, now that exponents are done. */ + mp_int_mul(&(the_key.p), &(the_key.q), &(the_key.n)); + + /* Write completed key to the specified output file */ + rsa_key_write(&the_key, ofp); + + EXIT: + fclose(ofp); + rsa_key_clear(&the_key); + return 0; +} + +int randomize(unsigned char *buf, size_t len) +{ + FILE *rnd = fopen("/dev/random", "rb"); + size_t nr; + + if(rnd == NULL) + return -1; + + nr = fread(buf, sizeof(*buf), len, rnd); + fclose(rnd); + + return (int) nr; +} + +mp_result mp_int_randomize(mp_int a, mp_size n_bits) +{ + mp_size n_bytes = (n_bits + CHAR_BIT - 1) / CHAR_BIT; + unsigned char *buf; + mp_result res = MP_OK; + + if((buf = malloc(n_bytes)) == NULL) + return MP_MEMORY; + + if(randomize(buf, n_bytes) != n_bytes) { + res = MP_TRUNC; + goto CLEANUP; + } + + /* Clear bits beyond the number requested */ + if(n_bits % CHAR_BIT != 0) { + unsigned char b_mask = (1 << (n_bits % CHAR_BIT)) - 1; + unsigned char t_mask = (1 << (n_bits % CHAR_BIT)) >> 1; + + buf[0] &= b_mask; + buf[0] |= t_mask; + } + + /* Set low-order bit to insure value is odd */ + buf[n_bytes - 1] |= 1; + + res = mp_int_read_unsigned(a, buf, n_bytes); + + CLEANUP: + memset(buf, 0, n_bytes); + free(buf); + + return res; +} + +mp_result find_prime(mp_int seed, FILE *fb) +{ + mp_result res; + int count = 0; + + if(mp_int_is_even(seed)) + if((res = mp_int_add_value(seed, 1, seed)) != MP_OK) + return res; + + while((res = mp_int_is_prime(seed)) == MP_FALSE) { + ++count; + + if(fb != NULL && (count % 50) == 0) + fputc('.', fb); + + if((res = mp_int_add_value(seed, 2, seed)) != MP_OK) + return res; + } + + if(res == MP_TRUE && fb != NULL) + fputc('+', fb); + + return res; +} + +mp_result rsa_key_init(rsa_key *kp) +{ + mp_int_init(&(kp->p)); + mp_int_init(&(kp->q)); + mp_int_init(&(kp->n)); + mp_int_init(&(kp->e)); + mp_int_init(&(kp->d)); + + return MP_OK; +} + +void rsa_key_clear(rsa_key *kp) +{ + mp_int_clear(&(kp->p)); + mp_int_clear(&(kp->q)); + mp_int_clear(&(kp->n)); + mp_int_clear(&(kp->e)); + mp_int_clear(&(kp->d)); +} + +void rsa_key_write(rsa_key *kp, FILE *ofp) +{ + int len; + char *obuf; + + len = mp_int_string_len(&(kp->n), 10); + obuf = malloc(len); + mp_int_to_string(&(kp->p), 10, obuf, len); + fprintf(ofp, "p = %s\n", obuf); + mp_int_to_string(&(kp->q), 10, obuf, len); + fprintf(ofp, "q = %s\n", obuf); + mp_int_to_string(&(kp->e), 10, obuf, len); + fprintf(ofp, "e = %s\n", obuf); + mp_int_to_string(&(kp->d), 10, obuf, len); + fprintf(ofp, "d = %s\n", obuf); + mp_int_to_string(&(kp->n), 10, obuf, len); + fprintf(ofp, "n = %s\n", obuf); + + free(obuf); +} + +/* Here there be dragons */ Index: contrib/isl/imath/findsizes.py =================================================================== --- /dev/null +++ contrib/isl/imath/findsizes.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python +## +## Name: findsizes.py +## Purpose: Find acceptable digit and word types for IMath. +## Author: M. J. Fromberger +## +## Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. +## +## Permission is hereby granted, free of charge, to any person obtaining a +## copy of this software and associated documentation files (the "Software"), +## to deal in the Software without restriction, including without limitation +## the rights to use, copy, modify, merge, publish, distribute, sublicense, +## and/or sell copies of the Software, and to permit persons to whom the +## Software is furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in +## all copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +## DEALINGS IN THE SOFTWARE. +## +import getopt, os, re, subprocess, sys, tempfile + +# These are the type names to test for suitability. If your compiler +# does not support "long long", e.g., it is strict ANSI C90, then you +# should remove "long long" from this list. +try_types = [ "unsigned %s" % s for s in + ("char", "short", "int", "long", "long long") ] + +def main(args): + """Scan the Makefile to find appropriate compiler settings, and then + compile a test program to emit the sizes of the various types that are + considered candidates. The -L (--nolonglong) command line option disables + the use of the"long long" type, which is not standard ANSI C90; by default, + "long long" is considered. + """ + try: + opts, args = getopt.getopt(args, 'L', ('nolonglong',)) + except getopt.GetoptError, e: + print >> sys.stderr, "Usage: findsizes.py [-L/--nolonglong]" + sys.exit(1) + + for opt, arg in opts: + if opt in ('-L', '--nolonglong'): + try: + try_types.pop(try_types.index("unsigned long long")) + except ValueError: pass + + vars = get_make_info() + sizes = get_type_sizes(try_types, vars.get('CC', 'cc'), + vars.get('CFLAGS', '').split()) + + stypes = sorted(sizes.keys(), key = lambda k: sizes[k], reverse = True) + word_type = stypes[0] + for t in stypes[1:]: + if sizes[t] <= sizes[word_type] / 2: + digit_type = t + break + else: + print >> sys.stderr, "Unable to find a compatible digit type." + sys.exit(1) + + print "typedef %-20s mp_word; /* %d bytes */\n" \ + "typedef %-20s mp_digit; /* %d bytes */" % \ + (word_type, sizes[word_type], digit_type, sizes[digit_type]) + +def get_type_sizes(types, cc, cflags = ()): + """Return a dictionary mapping the names of the specified types to + their sizes in bytes, based on the output of the C compiler whose + path and arguments are given. + """ + fd, tpath = tempfile.mkstemp(suffix = '.c') + fp = os.fdopen(fd, 'r+') + fp.seek(0) + + fp.write("#include \n\nint main(void)\n{\n") + for t in types: + fp.write(' printf("%%lu\\t%%s\\n", (unsigned long) sizeof(%s), ' + '\"%s\");\n' % (t, t)) + fp.write('\n return 0;\n}\n') + fp.close() + + print >> sys.stderr, \ + "Compiler: %s\n" \ + "Flags: %s\n" \ + "Source: %s\n" % (cc, ' '.join(cflags), tpath) + + cmd = [cc] + list(cflags) + [tpath] + if subprocess.call(cmd) <> 0: + raise ValueError("Error while running '%s'" % ' '.join(cmd)) + + os.unlink(tpath) + if not os.path.isfile('a.out'): + raise ValueError("No executable a.out found") + + result = subprocess.Popen(['./a.out'], + stdout = subprocess.PIPE).communicate()[0] + + out = {} + for line in result.split('\n'): + if line.strip() == '': + continue + size, type = re.split(r'\s+', line, 1) + out[type] = int(size) + + os.unlink("a.out") + return out + +def sub_make_vars(input, vars): + """Perform Make style variable substitution in the given input + string, using vars as a dictionary of variables to substitute. + """ + def frep(m): + try: + return vars[m.group(1).strip()] + except KeyError: + return ' ' + + expr = re.compile(r'\$\((\s*\w+\s*)\)') + out = input + while True: + next = expr.sub(frep, out) + if next == out: + break + out = next + + return out + +def get_make_info(target = None, makefile = None, makepath = "make", + defs = ()): + """Extract a listing of all of the variables defined by Make. + Returns a dictionary mapping variable names to their string + values. + + Optional arguments: + target -- the name of the target to request that Make build. + makefile -- the path to the Makefile. + makepath -- the path to the make executable. + defs -- a sequence of strings, additional make arguments. + """ + cmd = [makepath] + if defs: + cmd.extend(defs) + cmd.extend(("-p", "-n")) + if makefile is not None: + cmd.extend(["-f", makefile]) + if target is not None: + cmd.append(target) + + output = subprocess.Popen(cmd, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE).communicate()[0] + vrule = re.compile(r'^(\w+)\s*=\s*(.*)$') + + vars = {} + for line in output.split('\n'): + m = vrule.match(line) + if m: + vars[m.group(1)] = m.group(2) + + for key, val in vars.iteritems(): + vars[key] = sub_make_vars(val, vars) + + return vars + +if __name__ == "__main__": + main(sys.argv[1:]) + +# Here there be dragons Index: contrib/isl/imath/findthreshold.py =================================================================== --- /dev/null +++ contrib/isl/imath/findthreshold.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +## +## Name: findthreshold.py +## Purpose: Find a good threshold for recursive multiplication. +## Author: M. J. Fromberger +## Info: $Id: findthreshold.py 456 2006-08-16 14:24:06Z sting $ +## +## This tool computes some timing statistics to help you select a suitable +## recursive multiplication breakpoint. It uses the imtimer tool to run a +## series of tests varying precision and breakpoint, and prints out a summary +## of the "best" values for each category. Each summary line contains the +## following fields, tab-separated: +## +## prec -- the precision of the operands (in digits). +## thresh -- the threshold for recursive multiplication (digits). +## trec -- total time using recursive algorithm (sec). +## tnorm -- total time without recursive algorithm (sec). +## ratio -- speedup (ratio of tnorm/trec). +## +## You are responsible for reading and interpreting the resulting table to +## obtain a useful value for your workload. Change the value of MP_MULT_THRESH +## in imath.h once you have a satisfactory result. +## +import math, os, random, sys, time + +def get_timing_stats(num_tests, precision, threshold, seed = None): + """Obtain timing statistics for multiplication. + + num_tests -- number of tests to run. + precision -- number of digits per operand. + threshold -- threshold in digits for recursive multiply. + seed -- random seed; if None, the clock is used. + + Returns a tuple of (seed, bits, time) where seed is the random seed used, + bits is the number of bits per operand, and time is a float giving the + total time taken for the test run. + """ + if seed is None: + seed = int(time.time()) + + line = os.popen('./imtimer -mn -p %d -t %d -s %d %d' % + (precision, threshold, seed, num_tests), 'r').readline() + + count, prec, bits, thresh, status = line.strip().split('\t') + kind, total, unit = status.split() + + return seed, int(bits), float(total) + +def check_binary(name): + if not os.path.exists(name): + os.system('make %s' % name) + if not os.path.exists(name): + raise ValueError("Unable to build %s" % name) + elif not os.path.isfile(name): + raise ValueError("Path exists with wrong type") + +def compute_stats(): + check_binary('imtimer') + seed = int(time.time()) + + print >> sys.stderr, "Computing timer statistics (this may take a while)" + stats = {} + for prec in (32, 40, 64, 80, 128, 150, 256, 384, 512, 600, 768, 1024): + sys.stderr.write('%-4d ' % prec) + stats[prec] = (None, 1000000., 0.) + + for thresh in xrange(16, 65, 2): + s, b, t = get_timing_stats(1000, prec, thresh, seed) + sp, bp, tp = get_timing_stats(1000, prec, prec + 1, seed) + + if t < stats[prec][1]: + stats[prec] = (thresh, t, tp) + sys.stderr.write('+') + else: + sys.stderr.write('.') + sys.stderr.write('\n') + + return list((p, h, t, tp) for p, (h, t, tp) in stats.iteritems()) + +if __name__ == "__main__": + stats = compute_stats() + stats.sort(key = lambda s: s[3]/s[2]) + for prec, thresh, trec, tnorm in stats: + print "%d\t%d\t%.3f\t%.3f\t%.4f" % (prec, thresh, trec, tnorm, + tnorm / trec) + + print + +# Here there be dragons Index: contrib/isl/imath/gmp_compat.h =================================================================== --- /dev/null +++ contrib/isl/imath/gmp_compat.h @@ -0,0 +1,229 @@ +/* + Name: gmp_compat.h + Purpose: Provide GMP compatiable routines for imath library + Author: David Peixotto + + Copyright (c) 2012 Qualcomm Innovation Center, Inc. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#ifndef IMATH_GMP_COMPAT_H_ +#define IMATH_GMP_COMPAT_H_ +#include "imath.h" +#include "imrat.h" +#include + +#define GMPZAPI(fun) impz_ ## fun +#define GMPQAPI(fun) impq_ ## fun + +#ifdef __cplusplus +extern "C" { +#endif +/************************************************************************* + * + * Functions with direct translations + * + *************************************************************************/ +/* gmp: mpq_clear */ +void GMPQAPI(clear)(mp_rat x); + +/* gmp: mpq_cmp */ +int GMPQAPI(cmp)(mp_rat op1, mp_rat op2); + +/* gmp: mpq_init */ +void GMPQAPI(init)(mp_rat x); + +/* gmp: mpq_mul */ +void GMPQAPI(mul)(mp_rat product, mp_rat multiplier, mp_rat multiplicand); + +/* gmp: mpq_set */ +void GMPQAPI(set)(mp_rat rop, mp_rat op); + +/* gmp: mpz_abs */ +void GMPZAPI(abs)(mp_int rop, mp_int op); + +/* gmp: mpz_add */ +void GMPZAPI(add)(mp_int rop, mp_int op1, mp_int op2); + +/* gmp: mpz_clear */ +void GMPZAPI(clear)(mp_int x); + +/* gmp: mpz_cmp_si */ +int GMPZAPI(cmp_si)(mp_int op1, long op2); + +/* gmp: mpz_cmpabs */ +int GMPZAPI(cmpabs)(mp_int op1, mp_int op2); + +/* gmp: mpz_cmp */ +int GMPZAPI(cmp)(mp_int op1, mp_int op2); + +/* gmp: mpz_init */ +void GMPZAPI(init)(mp_int x); + +/* gmp: mpz_mul */ +void GMPZAPI(mul)(mp_int rop, mp_int op1, mp_int op2); + +/* gmp: mpz_neg */ +void GMPZAPI(neg)(mp_int rop, mp_int op); + +/* gmp: mpz_set_si */ +void GMPZAPI(set_si)(mp_int rop, long op); + +/* gmp: mpz_set */ +void GMPZAPI(set)(mp_int rop, mp_int op); + +/* gmp: mpz_sub */ +void GMPZAPI(sub)(mp_int rop, mp_int op1, mp_int op2); + +/* gmp: mpz_swap */ +void GMPZAPI(swap)(mp_int rop1, mp_int rop2); + +/* gmp: mpq_sgn */ +int GMPQAPI(sgn)(mp_rat op); + +/* gmp: mpz_sgn */ +int GMPZAPI(sgn)(mp_int op); + +/* gmp: mpq_set_ui */ +void GMPQAPI(set_ui)(mp_rat rop, unsigned long op1, unsigned long op2); + +/* gmp: mpz_set_ui */ +void GMPZAPI(set_ui)(mp_int rop, unsigned long op); + +/* gmp: mpq_den_ref */ +mp_int GMPQAPI(denref)(mp_rat op); + +/* gmp: mpq_num_ref */ +mp_int GMPQAPI(numref)(mp_rat op); + +/* gmp: mpq_canonicalize */ +void GMPQAPI(canonicalize)(mp_rat op); + +/************************************************************************* + * + * Functions that can be implemented as a combination of imath functions + * + *************************************************************************/ +/* gmp: mpz_addmul */ +void GMPZAPI(addmul)(mp_int rop, mp_int op1, mp_int op2); + +/* gmp: mpz_divexact */ +void GMPZAPI(divexact)(mp_int q, mp_int n, mp_int d); + +/* gmp: mpz_divisible_p */ +int GMPZAPI(divisible_p)(mp_int n, mp_int d); + +/* gmp: mpz_submul */ +void GMPZAPI(submul)(mp_int rop, mp_int op1, mp_int op2); + +/* gmp: mpz_add_ui */ +void GMPZAPI(add_ui)(mp_int rop, mp_int op1, unsigned long op2); + +/* gmp: mpz_divexact_ui */ +void GMPZAPI(divexact_ui)(mp_int q, mp_int n, unsigned long d); + +/* gmp: mpz_mul_ui */ +void GMPZAPI(mul_ui)(mp_int rop, mp_int op1, unsigned long op2); + +/* gmp: mpz_pow_ui */ +void GMPZAPI(pow_ui)(mp_int rop, mp_int base, unsigned long exp); + +/* gmp: mpz_sub_ui */ +void GMPZAPI(sub_ui)(mp_int rop, mp_int op1, unsigned long op2); + +/* gmp: mpz_fdiv_q_ui */ +unsigned long GMPZAPI(fdiv_q_ui)(mp_int q, mp_int n, unsigned long d); + +/* gmp: mpz_sizeinbase */ +size_t GMPZAPI(sizeinbase)(mp_int op, int base); + +/************************************************************************* + * + * Functions with different behavior in corner cases + * + *************************************************************************/ +/* gmp: mpz_gcd */ +/* gmp: When op1 = 0 and op2 = 0, return 0.*/ +void GMPZAPI(gcd)(mp_int rop, mp_int op1, mp_int op2); + +/* gmp: mpz_get_str */ +/* gmp: If str is NULL then allocate space using the default allocator. */ +char* GMPZAPI(get_str)(char *str, int radix, mp_int op); + +/* gmp: mpq_get_str */ +/* gmp: If str is NULL then allocate space using the default allocator. */ +/* gmp: If value is a whole number do not print denomenator. */ +/* TODO: Need to handle 0 values better. GMP prints 0/4 instead of 0.*/ +char* GMPQAPI(get_str)(char *str, int radix, mp_rat op); + +/* gmp: mpz_set_str */ +/* gmp: Allow and ignore spaces in string. */ +int GMPZAPI(set_str)(mp_int rop, char *str, int base); + +/* gmp: mpq_set_str */ +int GMPQAPI(set_str)(mp_rat rop, char *str, int base); + +/* gmp: mpz_get_ui */ +/* gmp: Return least significant bits if value is too big for a long. */ +unsigned long GMPZAPI(get_ui)(mp_int op); + +/* gmp: mpz_get_si */ +/* gmp: Return least significant bits if value is too bit for a long. */ +/* gmp: If value is too big for long, return the least significant + (8*sizeof(long)-1) bits from the op and set the sign bit according to + the sign of the op. */ +long GMPZAPI(get_si)(mp_int op); + +/* gmp: mpz_lcm */ +/* gmp: When op1 = 0 or op2 = 0, return 0.*/ +/* gmp: The resutl of lcm(a,b) is always positive. */ +void GMPZAPI(lcm)(mp_int rop, mp_int op1, mp_int op2); + +/* gmp: mpz_mul_2exp */ +/* gmp: allow big values for op2 when op1 == 0 */ +void GMPZAPI(mul_2exp)(mp_int rop, mp_int op1, unsigned long op2); + +/************************************************************************* + * + * Functions needing expanded functionality + * + *************************************************************************/ +/* gmp: mpz_cdiv_q */ +void GMPZAPI(cdiv_q)(mp_int q, mp_int n, mp_int d); + +/* gmp: mpz_fdiv_q */ +void GMPZAPI(fdiv_q)(mp_int q, mp_int n, mp_int d); + +/* gmp: mpz_fdiv_r */ +void GMPZAPI(fdiv_r)(mp_int r, mp_int n, mp_int d); + +/* gmp: mpz_tdiv_q */ +void GMPZAPI(tdiv_q)(mp_int q, mp_int n, mp_int d); + +/* gmp: mpz_export */ +void* GMPZAPI(export)(void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, mp_int op); + +/* gmp: mpz_import */ +void GMPZAPI(import)(mp_int rop, size_t count, int order, size_t size, int endian, size_t nails, const void* op); + +#ifdef __cplusplus +} +#endif +#endif /* end IMATH_GMP_COMPAT_H_ */ Index: contrib/isl/imath/gmp_compat.c =================================================================== --- /dev/null +++ contrib/isl/imath/gmp_compat.c @@ -0,0 +1,857 @@ +/* + Name: gmp_compat.c + Purpose: Provide GMP compatiable routines for imath library + Author: David Peixotto + + Copyright (c) 2012 Qualcomm Innovation Center, Inc. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ +#include "gmp_compat.h" +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + +#ifdef NDEBUG +#define CHECK(res) (res) +#else +#define CHECK(res) assert(((res) == MP_OK) && "expected MP_OK") +#endif + +/* *(signed char *)&endian_test will thus either be: + * 0b00000001 = 1 on big-endian + * 0b11111111 = -1 on little-endian */ +static const uint16_t endian_test = 0x1FF; +#define HOST_ENDIAN (*(signed char *)&endian_test) + +/************************************************************************* + * + * Functions with direct translations + * + *************************************************************************/ +/* gmp: mpq_clear */ +void GMPQAPI(clear)(mp_rat x) { + mp_rat_clear(x); +} + +/* gmp: mpq_cmp */ +int GMPQAPI(cmp)(mp_rat op1, mp_rat op2) { + return mp_rat_compare(op1, op2); +} + +/* gmp: mpq_init */ +void GMPQAPI(init)(mp_rat x) { + CHECK(mp_rat_init(x)); +} + +/* gmp: mpq_mul */ +void GMPQAPI(mul)(mp_rat product, mp_rat multiplier, mp_rat multiplicand) { + CHECK(mp_rat_mul(multiplier, multiplicand, product)); +} + +/* gmp: mpq_set*/ +void GMPQAPI(set)(mp_rat rop, mp_rat op) { + CHECK(mp_rat_copy(op, rop)); +} + +/* gmp: mpz_abs */ +void GMPZAPI(abs)(mp_int rop, mp_int op) { + CHECK(mp_int_abs(op, rop)); +} + +/* gmp: mpz_add */ +void GMPZAPI(add)(mp_int rop, mp_int op1, mp_int op2) { + CHECK(mp_int_add(op1, op2, rop)); +} + +/* gmp: mpz_clear */ +void GMPZAPI(clear)(mp_int x) { + mp_int_clear(x); +} + +/* gmp: mpz_cmp_si */ +int GMPZAPI(cmp_si)(mp_int op1, long op2) { + return mp_int_compare_value(op1, op2); +} + +/* gmp: mpz_cmpabs */ +int GMPZAPI(cmpabs)(mp_int op1, mp_int op2) { + return mp_int_compare_unsigned(op1, op2); +} + +/* gmp: mpz_cmp */ +int GMPZAPI(cmp)(mp_int op1, mp_int op2) { + return mp_int_compare(op1, op2); +} + +/* gmp: mpz_init */ +void GMPZAPI(init)(mp_int x) { + CHECK(mp_int_init(x)); +} + +/* gmp: mpz_mul */ +void GMPZAPI(mul)(mp_int rop, mp_int op1, mp_int op2) { + CHECK(mp_int_mul(op1, op2, rop)); +} + +/* gmp: mpz_neg */ +void GMPZAPI(neg)(mp_int rop, mp_int op) { + CHECK(mp_int_neg(op, rop)); +} + +/* gmp: mpz_set_si */ +void GMPZAPI(set_si)(mp_int rop, long op) { + CHECK(mp_int_set_value(rop, op)); +} + +/* gmp: mpz_set */ +void GMPZAPI(set)(mp_int rop, mp_int op) { + CHECK(mp_int_copy(op, rop)); +} + +/* gmp: mpz_sub */ +void GMPZAPI(sub)(mp_int rop, mp_int op1, mp_int op2) { + CHECK(mp_int_sub(op1, op2, rop)); +} + +/* gmp: mpz_swap */ +void GMPZAPI(swap)(mp_int rop1, mp_int rop2) { + mp_int_swap(rop1, rop2); +} + +/* gmp: mpq_sgn */ +int GMPQAPI(sgn)(mp_rat op) { + return mp_rat_compare_zero(op); +} + +/* gmp: mpz_sgn */ +int GMPZAPI(sgn)(mp_int op) { + return mp_int_compare_zero(op); +} + +/* gmp: mpq_set_ui */ +void GMPQAPI(set_ui)(mp_rat rop, unsigned long op1, unsigned long op2) { + CHECK(mp_rat_set_uvalue(rop, op1, op2)); +} + +/* gmp: mpz_set_ui */ +void GMPZAPI(set_ui)(mp_int rop, unsigned long op) { + CHECK(mp_int_set_uvalue(rop, op)); +} + +/* gmp: mpq_den_ref */ +mp_int GMPQAPI(denref)(mp_rat op) { + return mp_rat_denom_ref(op); +} + +/* gmp: mpq_num_ref */ +mp_int GMPQAPI(numref)(mp_rat op) { + return mp_rat_numer_ref(op); +} + +/* gmp: mpq_canonicalize */ +void GMPQAPI(canonicalize)(mp_rat op) { + CHECK(mp_rat_reduce(op)); +} + +/************************************************************************* + * + * Functions that can be implemented as a combination of imath functions + * + *************************************************************************/ +/* gmp: mpz_addmul */ +/* gmp: rop = rop + (op1 * op2) */ +void GMPZAPI(addmul)(mp_int rop, mp_int op1, mp_int op2) { + mpz_t tempz; + mp_int temp = &tempz; + mp_int_init(temp); + + CHECK(mp_int_mul(op1, op2, temp)); + CHECK(mp_int_add(rop, temp, rop)); + mp_int_clear(temp); +} + +/* gmp: mpz_divexact */ +/* gmp: only produces correct results when d divides n */ +void GMPZAPI(divexact)(mp_int q, mp_int n, mp_int d) { + CHECK(mp_int_div(n, d, q, NULL)); +} + +/* gmp: mpz_divisible_p */ +/* gmp: return 1 if d divides n, 0 otherwise */ +/* gmp: 0 is considered to divide only 0 */ +int GMPZAPI(divisible_p)(mp_int n, mp_int d) { + /* variables to hold remainder */ + mpz_t rz; + mp_int r = &rz; + int r_is_zero; + + /* check for d = 0 */ + int n_is_zero = mp_int_compare_zero(n) == 0; + int d_is_zero = mp_int_compare_zero(d) == 0; + if (d_is_zero) + return n_is_zero; + + /* return true if remainder is 0 */ + CHECK(mp_int_init(r)); + CHECK(mp_int_div(n, d, NULL, r)); + r_is_zero = mp_int_compare_zero(r) == 0; + mp_int_clear(r); + + return r_is_zero; +} + +/* gmp: mpz_submul */ +/* gmp: rop = rop - (op1 * op2) */ +void GMPZAPI(submul)(mp_int rop, mp_int op1, mp_int op2) { + mpz_t tempz; + mp_int temp = &tempz; + mp_int_init(temp); + + CHECK(mp_int_mul(op1, op2, temp)); + CHECK(mp_int_sub(rop, temp, rop)); + + mp_int_clear(temp); +} + +/* gmp: mpz_add_ui */ +void GMPZAPI(add_ui)(mp_int rop, mp_int op1, unsigned long op2) { + mpz_t tempz; + mp_int temp = &tempz; + CHECK(mp_int_init_uvalue(temp, op2)); + + CHECK(mp_int_add(op1, temp, rop)); + + mp_int_clear(temp); +} + +/* gmp: mpz_divexact_ui */ +/* gmp: only produces correct results when d divides n */ +void GMPZAPI(divexact_ui)(mp_int q, mp_int n, unsigned long d) { + mpz_t tempz; + mp_int temp = &tempz; + CHECK(mp_int_init_uvalue(temp, d)); + + CHECK(mp_int_div(n, temp, q, NULL)); + + mp_int_clear(temp); +} + +/* gmp: mpz_mul_ui */ +void GMPZAPI(mul_ui)(mp_int rop, mp_int op1, unsigned long op2) { + mpz_t tempz; + mp_int temp = &tempz; + CHECK(mp_int_init_uvalue(temp, op2)); + + CHECK(mp_int_mul(op1, temp, rop)); + + mp_int_clear(temp); +} + +/* gmp: mpz_pow_ui */ +/* gmp: 0^0 = 1 */ +void GMPZAPI(pow_ui)(mp_int rop, mp_int base, unsigned long exp) { + mpz_t tempz; + mp_int temp = &tempz; + + /* check for 0^0 */ + if (exp == 0 && mp_int_compare_zero(base) == 0) { + CHECK(mp_int_set_value(rop, 1)); + return; + } + + /* rop = base^exp */ + CHECK(mp_int_init_uvalue(temp, exp)); + CHECK(mp_int_expt_full(base, temp, rop)); + mp_int_clear(temp); +} + +/* gmp: mpz_sub_ui */ +void GMPZAPI(sub_ui)(mp_int rop, mp_int op1, unsigned long op2) { + mpz_t tempz; + mp_int temp = &tempz; + CHECK(mp_int_init_uvalue(temp, op2)); + + CHECK(mp_int_sub(op1, temp, rop)); + + mp_int_clear(temp); +} + +/************************************************************************* + * + * Functions with different behavior in corner cases + * + *************************************************************************/ + +/* gmp: mpz_gcd */ +void GMPZAPI(gcd)(mp_int rop, mp_int op1, mp_int op2) { + int op1_is_zero = mp_int_compare_zero(op1) == 0; + int op2_is_zero = mp_int_compare_zero(op2) == 0; + + if (op1_is_zero && op2_is_zero) { + mp_int_zero(rop); + return; + } + + CHECK(mp_int_gcd(op1, op2, rop)); +} + +/* gmp: mpz_get_str */ +char* GMPZAPI(get_str)(char *str, int radix, mp_int op) { + int i, r, len; + + /* Support negative radix like gmp */ + r = radix; + if (r < 0) + r = -r; + + /* Compute the length of the string needed to hold the int */ + len = mp_int_string_len(op, r); + if (str == NULL) { + str = malloc(len); + } + + /* Convert to string using imath function */ + CHECK(mp_int_to_string(op, r, str, len)); + + /* Change case to match gmp */ + for (i = 0; i < len - 1; i++) + if (radix < 0) + str[i] = toupper(str[i]); + else + str[i] = tolower(str[i]); + return str; +} + +/* gmp: mpq_get_str */ +char* GMPQAPI(get_str)(char *str, int radix, mp_rat op) { + int i, r, len; + + /* Only print numerator if it is a whole number */ + if (mp_int_compare_value(mp_rat_denom_ref(op), 1) == 0) + return GMPZAPI(get_str)(str, radix, mp_rat_numer_ref(op)); + + /* Support negative radix like gmp */ + r = radix; + if (r < 0) + r = -r; + + /* Compute the length of the string needed to hold the int */ + len = mp_rat_string_len(op, r); + if (str == NULL) { + str = malloc(len); + } + + /* Convert to string using imath function */ + CHECK(mp_rat_to_string(op, r, str, len)); + + /* Change case to match gmp */ + for (i = 0; i < len; i++) + if (radix < 0) + str[i] = toupper(str[i]); + else + str[i] = tolower(str[i]); + + return str; +} + +/* gmp: mpz_set_str */ +int GMPZAPI(set_str)(mp_int rop, char *str, int base) { + mp_result res = mp_int_read_string(rop, base, str); + return ((res == MP_OK) ? 0 : -1); +} + +/* gmp: mpq_set_str */ +int GMPQAPI(set_str)(mp_rat rop, char *s, int base) { + char *slash; + char *str; + mp_result resN; + mp_result resD; + int res = 0; + + /* Copy string to temporary storage so we can modify it below */ + str = malloc(strlen(s)+1); + strcpy(str, s); + + /* Properly format the string as an int by terminating at the / */ + slash = strchr(str, '/'); + if (slash) + *slash = '\0'; + + /* Parse numerator */ + resN = mp_int_read_string(mp_rat_numer_ref(rop), base, str); + + /* Parse denomenator if given or set to 1 if not */ + if (slash) + resD = mp_int_read_string(mp_rat_denom_ref(rop), base, slash+1); + else + resD = mp_int_set_uvalue(mp_rat_denom_ref(rop), 1); + + /* Return failure if either parse failed */ + if (resN != MP_OK || resD != MP_OK) + res = -1; + + free(str); + return res; +} + +static unsigned long get_long_bits(mp_int op) { + /* Deal with integer that does not fit into unsigned long. We want to grab + * the least significant digits that will fit into the long. Read the digits + * into the long starting at the most significant digit that fits into a + * long. The long is shifted over by MP_DIGIT_BIT before each digit is added. + * The shift is decomposed into two steps to follow the patten used in the + * rest of the imath library. The two step shift is used to accomedate + * architectures that don't deal well with 32-bit shifts. */ + mp_size num_digits_in_long = sizeof(unsigned long) / sizeof(mp_digit); + mp_digit *digits = MP_DIGITS(op); + unsigned long out = 0; + int i; + + for (i = num_digits_in_long - 1; i >= 0; i--) { + out <<= (MP_DIGIT_BIT/2); + out <<= (MP_DIGIT_BIT/2); + out |= digits[i]; + } + + return out; +} + +/* gmp: mpz_get_ui */ +unsigned long GMPZAPI(get_ui)(mp_int op) { + unsigned long out; + + /* Try a standard conversion that fits into an unsigned long */ + mp_result res = mp_int_to_uint(op, &out); + if (res == MP_OK) + return out; + + /* Abort the try if we don't have a range error in the conversion. + * The range error indicates that the value cannot fit into a long. */ + CHECK(res == MP_RANGE ? MP_OK : MP_RANGE); + if (res != MP_RANGE) + return 0; + + return get_long_bits(op); +} + +/* gmp: mpz_get_si */ +long GMPZAPI(get_si)(mp_int op) { + long out; + unsigned long uout; + int long_msb; + + /* Try a standard conversion that fits into a long */ + mp_result res = mp_int_to_int(op, &out); + if (res == MP_OK) + return out; + + /* Abort the try if we don't have a range error in the conversion. + * The range error indicates that the value cannot fit into a long. */ + CHECK(res == MP_RANGE ? MP_OK : MP_RANGE); + if (res != MP_RANGE) + return 0; + + /* get least significant bits into an unsigned long */ + uout = get_long_bits(op); + + /* clear the top bit */ + long_msb = (sizeof(unsigned long) * 8) - 1; + uout &= (~(1UL << long_msb)); + + /* convert to negative if needed based on sign of op */ + if (MP_SIGN(op) == MP_NEG) + uout = 0 - uout; + + out = (long) uout; + return out; +} + +/* gmp: mpz_lcm */ +void GMPZAPI(lcm)(mp_int rop, mp_int op1, mp_int op2) { + int op1_is_zero = mp_int_compare_zero(op1) == 0; + int op2_is_zero = mp_int_compare_zero(op2) == 0; + + if (op1_is_zero || op2_is_zero) { + mp_int_zero(rop); + return; + } + + CHECK(mp_int_lcm(op1, op2, rop)); + CHECK(mp_int_abs(rop, rop)); +} + +/* gmp: mpz_mul_2exp */ +/* gmp: allow big values for op2 when op1 == 0 */ +void GMPZAPI(mul_2exp)(mp_int rop, mp_int op1, unsigned long op2) { + if (mp_int_compare_zero(op1) == 0) + mp_int_zero(rop); + else + CHECK(mp_int_mul_pow2(op1, op2, rop)); +} + +/************************************************************************* + * + * Functions needing expanded functionality + * + *************************************************************************/ +/* [Note]Overview of division implementation + + All division operations (N / D) compute q and r such that + + N = q * D + r, with 0 <= abs(r) < abs(d) + + The q and r values are not uniquely specified by N and D. To specify which q + and r values should be used, GMP implements three different rounding modes + for integer division: + + ceiling - round q twords +infinity, r has opposite sign as d + floor - round q twords -infinity, r has same sign as d + truncate - round q twords zero, r has same sign as n + + The imath library only supports truncate as a rounding mode. We need to + implement the other rounding modes in terms of truncating division. We first + perform the division in trucate mode and then adjust q accordingly. Once we + know q, we can easily compute the correct r according the the formula above + by computing: + + r = N - q * D + + The main task is to compute q. We can compute the correct q from a trucated + version as follows. + + For ceiling rounding mode, if q is less than 0 then the truncated rounding + mode is the same as the ceiling rounding mode. If q is greater than zero + then we need to round q up by one because the truncated version was rounded + down to zero. If q equals zero then check to see if the result of the + divison is positive. A positive result needs to increment q to one. + + For floor rounding mode, if q is greater than 0 then the trucated rounding + mode is the same as the floor rounding mode. If q is less than zero then we + need to round q down by one because the trucated mode rounded q up by one + twords zero. If q is zero then we need to check to see if the result of the + division is negative. A negative result needs to decrement q to negative + one. + */ + +/* gmp: mpz_cdiv_q */ +void GMPZAPI(cdiv_q)(mp_int q, mp_int n, mp_int d) { + mpz_t rz; + mp_int r = &rz; + int qsign, rsign, nsign, dsign; + CHECK(mp_int_init(r)); + + /* save signs before division because q can alias with n or d */ + nsign = mp_int_compare_zero(n); + dsign = mp_int_compare_zero(d); + + /* truncating division */ + CHECK(mp_int_div(n, d, q, r)); + + /* see: [Note]Overview of division implementation */ + qsign = mp_int_compare_zero(q); + rsign = mp_int_compare_zero(r); + if (qsign > 0) { /* q > 0 */ + if (rsign != 0) { /* r != 0 */ + CHECK(mp_int_add_value(q, 1, q)); + } + } + else if (qsign == 0) { /* q == 0 */ + if (rsign != 0) { /* r != 0 */ + if ((nsign > 0 && dsign > 0) || (nsign < 0 && dsign < 0)) { + CHECK(mp_int_set_value(q, 1)); + } + } + } + mp_int_clear(r); +} + +/* gmp: mpz_fdiv_q */ +void GMPZAPI(fdiv_q)(mp_int q, mp_int n, mp_int d) { + mpz_t rz; + mp_int r = &rz; + int qsign, rsign, nsign, dsign; + CHECK(mp_int_init(r)); + + /* save signs before division because q can alias with n or d */ + nsign = mp_int_compare_zero(n); + dsign = mp_int_compare_zero(d); + + /* truncating division */ + CHECK(mp_int_div(n, d, q, r)); + + /* see: [Note]Overview of division implementation */ + qsign = mp_int_compare_zero(q); + rsign = mp_int_compare_zero(r); + if (qsign < 0) { /* q < 0 */ + if (rsign != 0) { /* r != 0 */ + CHECK(mp_int_sub_value(q, 1, q)); + } + } + else if (qsign == 0) { /* q == 0 */ + if (rsign != 0) { /* r != 0 */ + if ((nsign < 0 && dsign > 0) || (nsign > 0 && dsign < 0)) { + CHECK(mp_int_set_value(q, -1)); + } + } + } + mp_int_clear(r); +} + +/* gmp: mpz_fdiv_r */ +void GMPZAPI(fdiv_r)(mp_int r, mp_int n, mp_int d) { + mpz_t qz; + mpz_t tempz; + mpz_t orig_dz; + mpz_t orig_nz; + mp_int q = &qz; + mp_int temp = &tempz; + mp_int orig_d = &orig_dz; + mp_int orig_n = &orig_nz; + CHECK(mp_int_init(q)); + CHECK(mp_int_init(temp)); + /* Make a copy of n in case n and d in case they overlap with q */ + CHECK(mp_int_init_copy(orig_d, d)); + CHECK(mp_int_init_copy(orig_n, n)); + + /* floor division */ + GMPZAPI(fdiv_q)(q, n, d); + + /* see: [Note]Overview of division implementation */ + /* n = q * d + r ==> r = n - q * d */ + mp_int_mul(q, orig_d, temp); + mp_int_sub(orig_n, temp, r); + + mp_int_clear(q); + mp_int_clear(temp); + mp_int_clear(orig_d); + mp_int_clear(orig_n); +} + +/* gmp: mpz_tdiv_q */ +void GMPZAPI(tdiv_q)(mp_int q, mp_int n, mp_int d) { + /* truncating division*/ + CHECK(mp_int_div(n, d, q, NULL)); +} + +/* gmp: mpz_fdiv_q_ui */ +unsigned long GMPZAPI(fdiv_q_ui)(mp_int q, mp_int n, unsigned long d) { + mpz_t tempz; + mp_int temp = &tempz; + mpz_t rz; + mp_int r = &rz; + mpz_t orig_nz; + mp_int orig_n = &orig_nz; + unsigned long rl; + CHECK(mp_int_init_uvalue(temp, d)); + CHECK(mp_int_init(r)); + /* Make a copy of n in case n and q overlap */ + CHECK(mp_int_init_copy(orig_n, n)); + + /* use floor division mode to compute q and r */ + GMPZAPI(fdiv_q)(q, n, temp); + GMPZAPI(fdiv_r)(r, orig_n, temp); + CHECK(mp_int_to_uint(r, &rl)); + + mp_int_clear(temp); + mp_int_clear(r); + mp_int_clear(orig_n); + + return rl; +} + +/* gmp: mpz_export */ +void* GMPZAPI(export)(void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, mp_int op) { + int i, j; + int num_used_bytes; + size_t num_words, num_missing_bytes; + ssize_t word_offset; + unsigned char* dst; + mp_digit* src; + int src_bits; + + /* We do not have a complete implementation. Assert to ensure our + * restrictions are in place. */ + assert(nails == 0 && "Do not support non-full words"); + assert(endian == 1 || endian == 0 || endian == -1); + assert(order == 1 || order == -1); + + /* Test for zero */ + if (mp_int_compare_zero(op) == 0) { + if (countp) + *countp = 0; + return rop; + } + + /* Calculate how many words we need */ + num_used_bytes = mp_int_unsigned_len(op); + num_words = (num_used_bytes + (size-1)) / size; /* ceil division */ + assert(num_used_bytes > 0); + + /* Check to see if we will have missing bytes in the last word. + + Missing bytes can only occur when the size of words we output is + greater than the size of words used internally by imath. The number of + missing bytes is the number of bytes needed to fill out the last word. If + this number is greater than the size of a single mp_digit, then we need to + pad the word with extra zeros. Otherwise, the missing bytes can be filled + directly from the zeros in the last digit in the number. + */ + num_missing_bytes = (size * num_words) - num_used_bytes; + assert(num_missing_bytes < size); + + /* Allocate space for the result if needed */ + if (rop == NULL) { + rop = malloc(num_words * size); + } + + if (endian == 0) { + endian = HOST_ENDIAN; + } + + /* Initialize dst and src pointers */ + dst = (unsigned char *) rop + (order >= 0 ? (num_words-1) * size : 0) + (endian >= 0 ? size-1 : 0); + src = MP_DIGITS(op); + src_bits = MP_DIGIT_BIT; + + word_offset = (endian >= 0 ? size : -size) + (order < 0 ? size : -size); + + for (i = 0; i < num_words; i++) { + for (j = 0; j < size && i * size + j < num_used_bytes; j++) { + if (src_bits == 0) { + ++src; + src_bits = MP_DIGIT_BIT; + } + *dst = (*src >> (MP_DIGIT_BIT - src_bits)) & 0xFF; + src_bits -= 8; + dst -= endian; + } + for (; j < size; j++) { + *dst = 0; + dst -= endian; + } + dst += word_offset; + } + + if (countp) + *countp = num_words; + return rop; +} + +/* gmp: mpz_import */ +void GMPZAPI(import)(mp_int rop, size_t count, int order, size_t size, int endian, size_t nails, const void* op) { + mpz_t tmpz; + mp_int tmp = &tmpz; + size_t total_size; + size_t num_digits; + ssize_t word_offset; + const unsigned char *src; + mp_digit *dst; + int dst_bits; + int i, j; + if (count == 0 || op == NULL) + return; + + /* We do not have a complete implementation. Assert to ensure our + * restrictions are in place. */ + assert(nails == 0 && "Do not support non-full words"); + assert(endian == 1 || endian == 0 || endian == -1); + assert(order == 1 || order == -1); + + if (endian == 0) { + endian = HOST_ENDIAN; + } + + /* Compute number of needed digits by ceil division */ + total_size = count * size; + num_digits = (total_size + sizeof(mp_digit) - 1) / sizeof(mp_digit); + + /* Init temporary */ + mp_int_init_size(tmp, num_digits); + for (i = 0; i < num_digits; i++) + tmp->digits[i] = 0; + + /* Copy bytes */ + src = (const unsigned char *) op + (order >= 0 ? (count-1) * size : 0) + (endian >= 0 ? size-1 : 0); + dst = MP_DIGITS(tmp); + dst_bits = 0; + + word_offset = (endian >= 0 ? size : -size) + (order < 0 ? size : -size); + + for (i = 0; i < count; i++) { + for (j = 0; j < size; j++) { + if (dst_bits == MP_DIGIT_BIT) { + ++dst; + dst_bits = 0; + } + *dst |= ((mp_digit)*src) << dst_bits; + dst_bits += 8; + src -= endian; + } + src += word_offset; + } + + MP_USED(tmp) = num_digits; + + /* Remove leading zeros from number */ + { + mp_size uz_ = MP_USED(tmp); + mp_digit *dz_ = MP_DIGITS(tmp) + uz_ -1; + while (uz_ > 1 && (*dz_-- == 0)) + --uz_; + MP_USED(tmp) = uz_; + } + + /* Copy to destination */ + mp_int_copy(tmp, rop); + mp_int_clear(tmp); +} + +/* gmp: mpz_sizeinbase */ +size_t GMPZAPI(sizeinbase)(mp_int op, int base) { + mp_result res; + size_t size; + + /* If op == 0, return 1 */ + if (mp_int_compare_zero(op) == 0) + return 1; + + /* Compute string length in base */ + res = mp_int_string_len(op, base); + CHECK((res > 0) == MP_OK); + + /* Now adjust the final size by getting rid of string artifacts */ + size = res; + + /* subtract one for the null terminator */ + size -= 1; + + /* subtract one for the negative sign */ + if (mp_int_compare_zero(op) < 0) + size -= 1; + + return size; +} Index: contrib/isl/imath/imath.h =================================================================== --- /dev/null +++ contrib/isl/imath/imath.h @@ -0,0 +1,232 @@ +/* + Name: imath.h + Purpose: Arbitrary precision integer arithmetic routines. + Author: M. J. Fromberger + + Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#ifndef IMATH_H_ +#define IMATH_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char mp_sign; +typedef unsigned int mp_size; +typedef int mp_result; +typedef long mp_small; /* must be a signed type */ +typedef unsigned long mp_usmall; /* must be an unsigned type */ + +/* Force building with uint64_t so that the library builds consistently + * whether we build from the makefile or by embedding imath in another project. + */ +#undef USE_64BIT_WORDS +#define USE_64BIT_WORDS +#ifdef USE_64BIT_WORDS +typedef uint32_t mp_digit; +typedef uint64_t mp_word; +#else +typedef uint16_t mp_digit; +typedef uint32_t mp_word; +#endif + +typedef struct mpz { + mp_digit single; + mp_digit *digits; + mp_size alloc; + mp_size used; + mp_sign sign; +} mpz_t, *mp_int; + +#define MP_DIGITS(Z) ((Z)->digits) +#define MP_ALLOC(Z) ((Z)->alloc) +#define MP_USED(Z) ((Z)->used) +#define MP_SIGN(Z) ((Z)->sign) + +extern const mp_result MP_OK; +extern const mp_result MP_FALSE; +extern const mp_result MP_TRUE; +extern const mp_result MP_MEMORY; +extern const mp_result MP_RANGE; +extern const mp_result MP_UNDEF; +extern const mp_result MP_TRUNC; +extern const mp_result MP_BADARG; +extern const mp_result MP_MINERR; + +#define MP_DIGIT_BIT (sizeof(mp_digit) * CHAR_BIT) +#define MP_WORD_BIT (sizeof(mp_word) * CHAR_BIT) +#define MP_SMALL_MIN LONG_MIN +#define MP_SMALL_MAX LONG_MAX +#define MP_USMALL_MIN ULONG_MIN +#define MP_USMALL_MAX ULONG_MAX + +#ifdef USE_64BIT_WORDS +# define MP_DIGIT_MAX (UINT32_MAX * UINT64_C(1)) +# define MP_WORD_MAX (UINT64_MAX) +#else +# define MP_DIGIT_MAX (UINT16_MAX * 1UL) +# define MP_WORD_MAX (UINT32_MAX * 1UL) +#endif + +#define MP_MIN_RADIX 2 +#define MP_MAX_RADIX 36 + +/* Values with fewer than this many significant digits use the standard + multiplication algorithm; otherwise, a recursive algorithm is used. + Choose a value to suit your platform. + */ +#define MP_MULT_THRESH 22 + +#define MP_DEFAULT_PREC 8 /* default memory allocation, in digits */ + +extern const mp_sign MP_NEG; +extern const mp_sign MP_ZPOS; + +#define mp_int_is_odd(Z) ((Z)->digits[0] & 1) +#define mp_int_is_even(Z) !((Z)->digits[0] & 1) + +mp_result mp_int_init(mp_int z); +mp_int mp_int_alloc(void); +mp_result mp_int_init_size(mp_int z, mp_size prec); +mp_result mp_int_init_copy(mp_int z, mp_int old); +mp_result mp_int_init_value(mp_int z, mp_small value); +mp_result mp_int_init_uvalue(mp_int z, mp_usmall uvalue); +mp_result mp_int_set_value(mp_int z, mp_small value); +mp_result mp_int_set_uvalue(mp_int z, mp_usmall uvalue); +void mp_int_clear(mp_int z); +void mp_int_free(mp_int z); + +mp_result mp_int_copy(mp_int a, mp_int c); /* c = a */ +void mp_int_swap(mp_int a, mp_int c); /* swap a, c */ +void mp_int_zero(mp_int z); /* z = 0 */ +mp_result mp_int_abs(mp_int a, mp_int c); /* c = |a| */ +mp_result mp_int_neg(mp_int a, mp_int c); /* c = -a */ +mp_result mp_int_add(mp_int a, mp_int b, mp_int c); /* c = a + b */ +mp_result mp_int_add_value(mp_int a, mp_small value, mp_int c); +mp_result mp_int_sub(mp_int a, mp_int b, mp_int c); /* c = a - b */ +mp_result mp_int_sub_value(mp_int a, mp_small value, mp_int c); +mp_result mp_int_mul(mp_int a, mp_int b, mp_int c); /* c = a * b */ +mp_result mp_int_mul_value(mp_int a, mp_small value, mp_int c); +mp_result mp_int_mul_pow2(mp_int a, mp_small p2, mp_int c); +mp_result mp_int_sqr(mp_int a, mp_int c); /* c = a * a */ +mp_result mp_int_div(mp_int a, mp_int b, /* q = a / b */ + mp_int q, mp_int r); /* r = a % b */ +mp_result mp_int_div_value(mp_int a, mp_small value, /* q = a / value */ + mp_int q, mp_small *r); /* r = a % value */ +mp_result mp_int_div_pow2(mp_int a, mp_small p2, /* q = a / 2^p2 */ + mp_int q, mp_int r); /* r = q % 2^p2 */ +mp_result mp_int_mod(mp_int a, mp_int m, mp_int c); /* c = a % m */ +#define mp_int_mod_value(A, V, R) mp_int_div_value((A), (V), 0, (R)) +mp_result mp_int_expt(mp_int a, mp_small b, mp_int c); /* c = a^b */ +mp_result mp_int_expt_value(mp_small a, mp_small b, mp_int c); /* c = a^b */ +mp_result mp_int_expt_full(mp_int a, mp_int b, mp_int c); /* c = a^b */ + +int mp_int_compare(mp_int a, mp_int b); /* a <=> b */ +int mp_int_compare_unsigned(mp_int a, mp_int b); /* |a| <=> |b| */ +int mp_int_compare_zero(mp_int z); /* a <=> 0 */ +int mp_int_compare_value(mp_int z, mp_small v); /* a <=> v */ +int mp_int_compare_uvalue(mp_int z, mp_usmall uv); /* a <=> uv */ + +/* Returns true if v|a, false otherwise (including errors) */ +int mp_int_divisible_value(mp_int a, mp_small v); + +/* Returns k >= 0 such that z = 2^k, if one exists; otherwise < 0 */ +int mp_int_is_pow2(mp_int z); + +mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m, + mp_int c); /* c = a^b (mod m) */ +mp_result mp_int_exptmod_evalue(mp_int a, mp_small value, + mp_int m, mp_int c); /* c = a^v (mod m) */ +mp_result mp_int_exptmod_bvalue(mp_small value, mp_int b, + mp_int m, mp_int c); /* c = v^b (mod m) */ +mp_result mp_int_exptmod_known(mp_int a, mp_int b, + mp_int m, mp_int mu, + mp_int c); /* c = a^b (mod m) */ +mp_result mp_int_redux_const(mp_int m, mp_int c); + +mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c); /* c = 1/a (mod m) */ + +mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c); /* c = gcd(a, b) */ + +mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */ + mp_int x, mp_int y); /* c = ax + by */ + +mp_result mp_int_lcm(mp_int a, mp_int b, mp_int c); /* c = lcm(a, b) */ + +mp_result mp_int_root(mp_int a, mp_small b, mp_int c); /* c = floor(a^{1/b}) */ +#define mp_int_sqrt(a, c) mp_int_root(a, 2, c) /* c = floor(sqrt(a)) */ + +/* Convert to a small int, if representable; else MP_RANGE */ +mp_result mp_int_to_int(mp_int z, mp_small *out); +mp_result mp_int_to_uint(mp_int z, mp_usmall *out); + +/* Convert to nul-terminated string with the specified radix, writing at + most limit characters including the nul terminator */ +mp_result mp_int_to_string(mp_int z, mp_size radix, + char *str, int limit); + +/* Return the number of characters required to represent + z in the given radix. May over-estimate. */ +mp_result mp_int_string_len(mp_int z, mp_size radix); + +/* Read zero-terminated string into z */ +mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str); +mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, + char **end); + +/* Return the number of significant bits in z */ +mp_result mp_int_count_bits(mp_int z); + +/* Convert z to two's complement binary, writing at most limit bytes */ +mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit); + +/* Read a two's complement binary value into z from the given buffer */ +mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len); + +/* Return the number of bytes required to represent z in binary. */ +mp_result mp_int_binary_len(mp_int z); + +/* Convert z to unsigned binary, writing at most limit bytes */ +mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit); + +/* Read an unsigned binary value into z from the given buffer */ +mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len); + +/* Return the number of bytes required to represent z as unsigned output */ +mp_result mp_int_unsigned_len(mp_int z); + +/* Return a statically allocated string describing error code res */ +const char *mp_error_string(mp_result res); + +#if DEBUG +void s_print(char *tag, mp_int z); +void s_print_buf(char *tag, mp_digit *buf, mp_size num); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* end IMATH_H_ */ Index: contrib/isl/imath/imath.c =================================================================== --- /dev/null +++ contrib/isl/imath/imath.c @@ -0,0 +1,3156 @@ +/* + Name: imath.c + Purpose: Arbitrary precision integer arithmetic routines. + Author: M. J. Fromberger + + Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include "imath.h" + +#if DEBUG +#include +#endif + +#include +#include +#include + +#include + +#if DEBUG +#define STATIC /* public */ +#else +#define STATIC static +#endif + +const mp_result MP_OK = 0; /* no error, all is well */ +const mp_result MP_FALSE = 0; /* boolean false */ +const mp_result MP_TRUE = -1; /* boolean true */ +const mp_result MP_MEMORY = -2; /* out of memory */ +const mp_result MP_RANGE = -3; /* argument out of range */ +const mp_result MP_UNDEF = -4; /* result undefined */ +const mp_result MP_TRUNC = -5; /* output truncated */ +const mp_result MP_BADARG = -6; /* invalid null argument */ +const mp_result MP_MINERR = -6; + +const mp_sign MP_NEG = 1; /* value is strictly negative */ +const mp_sign MP_ZPOS = 0; /* value is non-negative */ + +STATIC const char *s_unknown_err = "unknown result code"; +STATIC const char *s_error_msg[] = { + "error code 0", + "boolean true", + "out of memory", + "argument out of range", + "result undefined", + "output truncated", + "invalid argument", + NULL +}; + +/* Argument checking macros + Use CHECK() where a return value is required; NRCHECK() elsewhere */ +#define CHECK(TEST) assert(TEST) +#define NRCHECK(TEST) assert(TEST) + +/* The ith entry of this table gives the value of log_i(2). + + An integer value n requires ceil(log_i(n)) digits to be represented + in base i. Since it is easy to compute lg(n), by counting bits, we + can compute log_i(n) = lg(n) * log_i(2). + + The use of this table eliminates a dependency upon linkage against + the standard math libraries. + + If MP_MAX_RADIX is increased, this table should be expanded too. + */ +STATIC const double s_log2[] = { + 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* (D)(D) 2 3 */ + 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ + 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ + 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ + 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ + 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ + 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ + 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ + 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ + 0.193426404, /* 36 */ +}; + + + +/* Return the number of digits needed to represent a static value */ +#define MP_VALUE_DIGITS(V) \ +((sizeof(V)+(sizeof(mp_digit)-1))/sizeof(mp_digit)) + +/* Round precision P to nearest word boundary */ +#define ROUND_PREC(P) ((mp_size)(2*(((P)+1)/2))) + +/* Set array P of S digits to zero */ +#define ZERO(P, S) \ +do{ \ + mp_size i__ = (S) * sizeof(mp_digit); \ + mp_digit *p__ = (P); \ + memset(p__, 0, i__); \ +} while(0) + +/* Copy S digits from array P to array Q */ +#define COPY(P, Q, S) \ +do{ \ + mp_size i__ = (S) * sizeof(mp_digit); \ + mp_digit *p__ = (P), *q__ = (Q); \ + memcpy(q__, p__, i__); \ +} while(0) + +/* Reverse N elements of type T in array A */ +#define REV(T, A, N) \ +do{ \ + T *u_ = (A), *v_ = u_ + (N) - 1; \ + while (u_ < v_) { \ + T xch = *u_; \ + *u_++ = *v_; \ + *v_-- = xch; \ + } \ +} while(0) + +#define CLAMP(Z) \ +do{ \ + mp_int z_ = (Z); \ + mp_size uz_ = MP_USED(z_); \ + mp_digit *dz_ = MP_DIGITS(z_) + uz_ -1; \ + while (uz_ > 1 && (*dz_-- == 0)) \ + --uz_; \ + MP_USED(z_) = uz_; \ +} while(0) + +/* Select min/max. Do not provide expressions for which multiple + evaluation would be problematic, e.g. x++ */ +#define MIN(A, B) ((B)<(A)?(B):(A)) +#define MAX(A, B) ((B)>(A)?(B):(A)) + +/* Exchange lvalues A and B of type T, e.g. + SWAP(int, x, y) where x and y are variables of type int. */ +#define SWAP(T, A, B) \ +do{ \ + T t_ = (A); \ + A = (B); \ + B = t_; \ +} while(0) + +/* Used to set up and access simple temp stacks within functions. */ +#define DECLARE_TEMP(N) \ + mpz_t temp[(N)]; \ + int last__ = 0 +#define CLEANUP_TEMP() \ + CLEANUP: \ + while (--last__ >= 0) \ + mp_int_clear(TEMP(last__)) +#define TEMP(K) (temp + (K)) +#define LAST_TEMP() TEMP(last__) +#define SETUP(E) \ +do{ \ + if ((res = (E)) != MP_OK) \ + goto CLEANUP; \ + ++(last__); \ +} while(0) + +/* Compare value to zero. */ +#define CMPZ(Z) \ +(((Z)->used==1&&(Z)->digits[0]==0)?0:((Z)->sign==MP_NEG)?-1:1) + +/* Multiply X by Y into Z, ignoring signs. Requires that Z have + enough storage preallocated to hold the result. */ +#define UMUL(X, Y, Z) \ +do{ \ + mp_size ua_ = MP_USED(X), ub_ = MP_USED(Y); \ + mp_size o_ = ua_ + ub_; \ + ZERO(MP_DIGITS(Z), o_); \ + (void) s_kmul(MP_DIGITS(X), MP_DIGITS(Y), MP_DIGITS(Z), ua_, ub_); \ + MP_USED(Z) = o_; \ + CLAMP(Z); \ +} while(0) + +/* Square X into Z. Requires that Z have enough storage to hold the + result. */ +#define USQR(X, Z) \ +do{ \ + mp_size ua_ = MP_USED(X), o_ = ua_ + ua_; \ + ZERO(MP_DIGITS(Z), o_); \ + (void) s_ksqr(MP_DIGITS(X), MP_DIGITS(Z), ua_); \ + MP_USED(Z) = o_; \ + CLAMP(Z); \ +} while(0) + +#define UPPER_HALF(W) ((mp_word)((W) >> MP_DIGIT_BIT)) +#define LOWER_HALF(W) ((mp_digit)(W)) +#define HIGH_BIT_SET(W) ((W) >> (MP_WORD_BIT - 1)) +#define ADD_WILL_OVERFLOW(W, V) ((MP_WORD_MAX - (V)) < (W)) + + + +/* Default number of digits allocated to a new mp_int */ +#if IMATH_TEST +mp_size default_precision = MP_DEFAULT_PREC; +#else +STATIC const mp_size default_precision = MP_DEFAULT_PREC; +#endif + +/* Minimum number of digits to invoke recursive multiply */ +#if IMATH_TEST +mp_size multiply_threshold = MP_MULT_THRESH; +#else +STATIC const mp_size multiply_threshold = MP_MULT_THRESH; +#endif + +/* Allocate a buffer of (at least) num digits, or return + NULL if that couldn't be done. */ +STATIC mp_digit *s_alloc(mp_size num); + +/* Release a buffer of digits allocated by s_alloc(). */ +STATIC void s_free(void *ptr); + +/* Insure that z has at least min digits allocated, resizing if + necessary. Returns true if successful, false if out of memory. */ +STATIC int s_pad(mp_int z, mp_size min); + +/* Fill in a "fake" mp_int on the stack with a given value */ +STATIC void s_fake(mp_int z, mp_small value, mp_digit vbuf[]); +STATIC void s_ufake(mp_int z, mp_usmall value, mp_digit vbuf[]); + +/* Compare two runs of digits of given length, returns <0, 0, >0 */ +STATIC int s_cdig(mp_digit *da, mp_digit *db, mp_size len); + +/* Pack the unsigned digits of v into array t */ +STATIC int s_uvpack(mp_usmall v, mp_digit t[]); + +/* Compare magnitudes of a and b, returns <0, 0, >0 */ +STATIC int s_ucmp(mp_int a, mp_int b); + +/* Compare magnitudes of a and v, returns <0, 0, >0 */ +STATIC int s_vcmp(mp_int a, mp_small v); +STATIC int s_uvcmp(mp_int a, mp_usmall uv); + +/* Unsigned magnitude addition; assumes dc is big enough. + Carry out is returned (no memory allocated). */ +STATIC mp_digit s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b); + +/* Unsigned magnitude subtraction. Assumes dc is big enough. */ +STATIC void s_usub(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b); + +/* Unsigned recursive multiplication. Assumes dc is big enough. */ +STATIC int s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b); + +/* Unsigned magnitude multiplication. Assumes dc is big enough. */ +STATIC void s_umul(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b); + +/* Unsigned recursive squaring. Assumes dc is big enough. */ +STATIC int s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a); + +/* Unsigned magnitude squaring. Assumes dc is big enough. */ +STATIC void s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a); + +/* Single digit addition. Assumes a is big enough. */ +STATIC void s_dadd(mp_int a, mp_digit b); + +/* Single digit multiplication. Assumes a is big enough. */ +STATIC void s_dmul(mp_int a, mp_digit b); + +/* Single digit multiplication on buffers; assumes dc is big enough. */ +STATIC void s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc, + mp_size size_a); + +/* Single digit division. Replaces a with the quotient, + returns the remainder. */ +STATIC mp_digit s_ddiv(mp_int a, mp_digit b); + +/* Quick division by a power of 2, replaces z (no allocation) */ +STATIC void s_qdiv(mp_int z, mp_size p2); + +/* Quick remainder by a power of 2, replaces z (no allocation) */ +STATIC void s_qmod(mp_int z, mp_size p2); + +/* Quick multiplication by a power of 2, replaces z. + Allocates if necessary; returns false in case this fails. */ +STATIC int s_qmul(mp_int z, mp_size p2); + +/* Quick subtraction from a power of 2, replaces z. + Allocates if necessary; returns false in case this fails. */ +STATIC int s_qsub(mp_int z, mp_size p2); + +/* Return maximum k such that 2^k divides z. */ +STATIC int s_dp2k(mp_int z); + +/* Return k >= 0 such that z = 2^k, or -1 if there is no such k. */ +STATIC int s_isp2(mp_int z); + +/* Set z to 2^k. May allocate; returns false in case this fails. */ +STATIC int s_2expt(mp_int z, mp_small k); + +/* Normalize a and b for division, returns normalization constant */ +STATIC int s_norm(mp_int a, mp_int b); + +/* Compute constant mu for Barrett reduction, given modulus m, result + replaces z, m is untouched. */ +STATIC mp_result s_brmu(mp_int z, mp_int m); + +/* Reduce a modulo m, using Barrett's algorithm. */ +STATIC int s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2); + +/* Modular exponentiation, using Barrett reduction */ +STATIC mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c); + +/* Unsigned magnitude division. Assumes |a| > |b|. Allocates temporaries; + overwrites a with quotient, b with remainder. */ +STATIC mp_result s_udiv_knuth(mp_int a, mp_int b); + +/* Compute the number of digits in radix r required to represent the given + value. Does not account for sign flags, terminators, etc. */ +STATIC int s_outlen(mp_int z, mp_size r); + +/* Guess how many digits of precision will be needed to represent a radix r + value of the specified number of digits. Returns a value guaranteed to be + no smaller than the actual number required. */ +STATIC mp_size s_inlen(int len, mp_size r); + +/* Convert a character to a digit value in radix r, or + -1 if out of range */ +STATIC int s_ch2val(char c, int r); + +/* Convert a digit value to a character */ +STATIC char s_val2ch(int v, int caps); + +/* Take 2's complement of a buffer in place */ +STATIC void s_2comp(unsigned char *buf, int len); + +/* Convert a value to binary, ignoring sign. On input, *limpos is the bound on + how many bytes should be written to buf; on output, *limpos is set to the + number of bytes actually written. */ +STATIC mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad); + +#if DEBUG +/* Dump a representation of the mp_int to standard output */ +void s_print(char *tag, mp_int z); +void s_print_buf(char *tag, mp_digit *buf, mp_size num); +#endif + +mp_result mp_int_init(mp_int z) +{ + if (z == NULL) + return MP_BADARG; + + z->single = 0; + z->digits = &(z->single); + z->alloc = 1; + z->used = 1; + z->sign = MP_ZPOS; + + return MP_OK; +} + +mp_int mp_int_alloc(void) +{ + mp_int out = malloc(sizeof(mpz_t)); + + if (out != NULL) + mp_int_init(out); + + return out; +} + +mp_result mp_int_init_size(mp_int z, mp_size prec) +{ + CHECK(z != NULL); + + if (prec == 0) + prec = default_precision; + else if (prec == 1) + return mp_int_init(z); + else + prec = (mp_size) ROUND_PREC(prec); + + if ((MP_DIGITS(z) = s_alloc(prec)) == NULL) + return MP_MEMORY; + + z->digits[0] = 0; + MP_USED(z) = 1; + MP_ALLOC(z) = prec; + MP_SIGN(z) = MP_ZPOS; + + return MP_OK; +} + +mp_result mp_int_init_copy(mp_int z, mp_int old) +{ + mp_result res; + mp_size uold; + + CHECK(z != NULL && old != NULL); + + uold = MP_USED(old); + if (uold == 1) { + mp_int_init(z); + } + else { + mp_size target = MAX(uold, default_precision); + + if ((res = mp_int_init_size(z, target)) != MP_OK) + return res; + } + + MP_USED(z) = uold; + MP_SIGN(z) = MP_SIGN(old); + COPY(MP_DIGITS(old), MP_DIGITS(z), uold); + + return MP_OK; +} + +mp_result mp_int_init_value(mp_int z, mp_small value) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + return mp_int_init_copy(z, &vtmp); +} + +mp_result mp_int_init_uvalue(mp_int z, mp_usmall uvalue) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(uvalue)]; + + s_ufake(&vtmp, uvalue, vbuf); + return mp_int_init_copy(z, &vtmp); +} + +mp_result mp_int_set_value(mp_int z, mp_small value) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + return mp_int_copy(&vtmp, z); +} + +mp_result mp_int_set_uvalue(mp_int z, mp_usmall uvalue) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(uvalue)]; + + s_ufake(&vtmp, uvalue, vbuf); + return mp_int_copy(&vtmp, z); +} + +void mp_int_clear(mp_int z) +{ + if (z == NULL) + return; + + if (MP_DIGITS(z) != NULL) { + if (MP_DIGITS(z) != &(z->single)) + s_free(MP_DIGITS(z)); + + MP_DIGITS(z) = NULL; + } +} + +void mp_int_free(mp_int z) +{ + NRCHECK(z != NULL); + + mp_int_clear(z); + free(z); /* note: NOT s_free() */ +} + +mp_result mp_int_copy(mp_int a, mp_int c) +{ + CHECK(a != NULL && c != NULL); + + if (a != c) { + mp_size ua = MP_USED(a); + mp_digit *da, *dc; + + if (!s_pad(c, ua)) + return MP_MEMORY; + + da = MP_DIGITS(a); dc = MP_DIGITS(c); + COPY(da, dc, ua); + + MP_USED(c) = ua; + MP_SIGN(c) = MP_SIGN(a); + } + + return MP_OK; +} + +void mp_int_swap(mp_int a, mp_int c) +{ + if (a != c) { + mpz_t tmp = *a; + + *a = *c; + *c = tmp; + + if (MP_DIGITS(a) == &(c->single)) + MP_DIGITS(a) = &(a->single); + if (MP_DIGITS(c) == &(a->single)) + MP_DIGITS(c) = &(c->single); + } +} + +void mp_int_zero(mp_int z) +{ + NRCHECK(z != NULL); + + z->digits[0] = 0; + MP_USED(z) = 1; + MP_SIGN(z) = MP_ZPOS; +} + +mp_result mp_int_abs(mp_int a, mp_int c) +{ + mp_result res; + + CHECK(a != NULL && c != NULL); + + if ((res = mp_int_copy(a, c)) != MP_OK) + return res; + + MP_SIGN(c) = MP_ZPOS; + return MP_OK; +} + +mp_result mp_int_neg(mp_int a, mp_int c) +{ + mp_result res; + + CHECK(a != NULL && c != NULL); + + if ((res = mp_int_copy(a, c)) != MP_OK) + return res; + + if (CMPZ(c) != 0) + MP_SIGN(c) = 1 - MP_SIGN(a); + + return MP_OK; +} + +mp_result mp_int_add(mp_int a, mp_int b, mp_int c) +{ + mp_size ua, ub, uc, max; + + CHECK(a != NULL && b != NULL && c != NULL); + + ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c); + max = MAX(ua, ub); + + if (MP_SIGN(a) == MP_SIGN(b)) { + /* Same sign -- add magnitudes, preserve sign of addends */ + mp_digit carry; + + if (!s_pad(c, max)) + return MP_MEMORY; + + carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub); + uc = max; + + if (carry) { + if (!s_pad(c, max + 1)) + return MP_MEMORY; + + c->digits[max] = carry; + ++uc; + } + + MP_USED(c) = uc; + MP_SIGN(c) = MP_SIGN(a); + + } + else { + /* Different signs -- subtract magnitudes, preserve sign of greater */ + mp_int x, y; + int cmp = s_ucmp(a, b); /* magnitude comparision, sign ignored */ + + /* Set x to max(a, b), y to min(a, b) to simplify later code. + A special case yields zero for equal magnitudes. + */ + if (cmp == 0) { + mp_int_zero(c); + return MP_OK; + } + else if (cmp < 0) { + x = b; y = a; + } + else { + x = a; y = b; + } + + if (!s_pad(c, MP_USED(x))) + return MP_MEMORY; + + /* Subtract smaller from larger */ + s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y)); + MP_USED(c) = MP_USED(x); + CLAMP(c); + + /* Give result the sign of the larger */ + MP_SIGN(c) = MP_SIGN(x); + } + + return MP_OK; +} + +mp_result mp_int_add_value(mp_int a, mp_small value, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_add(a, &vtmp, c); +} + +mp_result mp_int_sub(mp_int a, mp_int b, mp_int c) +{ + mp_size ua, ub, uc, max; + + CHECK(a != NULL && b != NULL && c != NULL); + + ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c); + max = MAX(ua, ub); + + if (MP_SIGN(a) != MP_SIGN(b)) { + /* Different signs -- add magnitudes and keep sign of a */ + mp_digit carry; + + if (!s_pad(c, max)) + return MP_MEMORY; + + carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub); + uc = max; + + if (carry) { + if (!s_pad(c, max + 1)) + return MP_MEMORY; + + c->digits[max] = carry; + ++uc; + } + + MP_USED(c) = uc; + MP_SIGN(c) = MP_SIGN(a); + + } + else { + /* Same signs -- subtract magnitudes */ + mp_int x, y; + mp_sign osign; + int cmp = s_ucmp(a, b); + + if (!s_pad(c, max)) + return MP_MEMORY; + + if (cmp >= 0) { + x = a; y = b; osign = MP_ZPOS; + } + else { + x = b; y = a; osign = MP_NEG; + } + + if (MP_SIGN(a) == MP_NEG && cmp != 0) + osign = 1 - osign; + + s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y)); + MP_USED(c) = MP_USED(x); + CLAMP(c); + + MP_SIGN(c) = osign; + } + + return MP_OK; +} + +mp_result mp_int_sub_value(mp_int a, mp_small value, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_sub(a, &vtmp, c); +} + +mp_result mp_int_mul(mp_int a, mp_int b, mp_int c) +{ + mp_digit *out; + mp_size osize, ua, ub, p = 0; + mp_sign osign; + + CHECK(a != NULL && b != NULL && c != NULL); + + /* If either input is zero, we can shortcut multiplication */ + if (mp_int_compare_zero(a) == 0 || mp_int_compare_zero(b) == 0) { + mp_int_zero(c); + return MP_OK; + } + + /* Output is positive if inputs have same sign, otherwise negative */ + osign = (MP_SIGN(a) == MP_SIGN(b)) ? MP_ZPOS : MP_NEG; + + /* If the output is not identical to any of the inputs, we'll write the + results directly; otherwise, allocate a temporary space. */ + ua = MP_USED(a); ub = MP_USED(b); + osize = MAX(ua, ub); + osize = 4 * ((osize + 1) / 2); + + if (c == a || c == b) { + p = ROUND_PREC(osize); + p = MAX(p, default_precision); + + if ((out = s_alloc(p)) == NULL) + return MP_MEMORY; + } + else { + if (!s_pad(c, osize)) + return MP_MEMORY; + + out = MP_DIGITS(c); + } + ZERO(out, osize); + + if (!s_kmul(MP_DIGITS(a), MP_DIGITS(b), out, ua, ub)) + return MP_MEMORY; + + /* If we allocated a new buffer, get rid of whatever memory c was already + using, and fix up its fields to reflect that. + */ + if (out != MP_DIGITS(c)) { + if ((void *) MP_DIGITS(c) != (void *) c) + s_free(MP_DIGITS(c)); + MP_DIGITS(c) = out; + MP_ALLOC(c) = p; + } + + MP_USED(c) = osize; /* might not be true, but we'll fix it ... */ + CLAMP(c); /* ... right here */ + MP_SIGN(c) = osign; + + return MP_OK; +} + +mp_result mp_int_mul_value(mp_int a, mp_small value, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_mul(a, &vtmp, c); +} + +mp_result mp_int_mul_pow2(mp_int a, mp_small p2, mp_int c) +{ + mp_result res; + CHECK(a != NULL && c != NULL && p2 >= 0); + + if ((res = mp_int_copy(a, c)) != MP_OK) + return res; + + if (s_qmul(c, (mp_size) p2)) + return MP_OK; + else + return MP_MEMORY; +} + +mp_result mp_int_sqr(mp_int a, mp_int c) +{ + mp_digit *out; + mp_size osize, p = 0; + + CHECK(a != NULL && c != NULL); + + /* Get a temporary buffer big enough to hold the result */ + osize = (mp_size) 4 * ((MP_USED(a) + 1) / 2); + if (a == c) { + p = ROUND_PREC(osize); + p = MAX(p, default_precision); + + if ((out = s_alloc(p)) == NULL) + return MP_MEMORY; + } + else { + if (!s_pad(c, osize)) + return MP_MEMORY; + + out = MP_DIGITS(c); + } + ZERO(out, osize); + + s_ksqr(MP_DIGITS(a), out, MP_USED(a)); + + /* Get rid of whatever memory c was already using, and fix up its fields to + reflect the new digit array it's using + */ + if (out != MP_DIGITS(c)) { + if ((void *) MP_DIGITS(c) != (void *) c) + s_free(MP_DIGITS(c)); + MP_DIGITS(c) = out; + MP_ALLOC(c) = p; + } + + MP_USED(c) = osize; /* might not be true, but we'll fix it ... */ + CLAMP(c); /* ... right here */ + MP_SIGN(c) = MP_ZPOS; + + return MP_OK; +} + +mp_result mp_int_div(mp_int a, mp_int b, mp_int q, mp_int r) +{ + int cmp, lg; + mp_result res = MP_OK; + mp_int qout, rout; + mp_sign sa = MP_SIGN(a), sb = MP_SIGN(b); + DECLARE_TEMP(2); + + CHECK(a != NULL && b != NULL && q != r); + + if (CMPZ(b) == 0) + return MP_UNDEF; + else if ((cmp = s_ucmp(a, b)) < 0) { + /* If |a| < |b|, no division is required: + q = 0, r = a + */ + if (r && (res = mp_int_copy(a, r)) != MP_OK) + return res; + + if (q) + mp_int_zero(q); + + return MP_OK; + } + else if (cmp == 0) { + /* If |a| = |b|, no division is required: + q = 1 or -1, r = 0 + */ + if (r) + mp_int_zero(r); + + if (q) { + mp_int_zero(q); + q->digits[0] = 1; + + if (sa != sb) + MP_SIGN(q) = MP_NEG; + } + + return MP_OK; + } + + /* When |a| > |b|, real division is required. We need someplace to store + quotient and remainder, but q and r are allowed to be NULL or to overlap + with the inputs. + */ + if ((lg = s_isp2(b)) < 0) { + if (q && b != q) { + if ((res = mp_int_copy(a, q)) != MP_OK) + goto CLEANUP; + else + qout = q; + } + else { + qout = LAST_TEMP(); + SETUP(mp_int_init_copy(LAST_TEMP(), a)); + } + + if (r && a != r) { + if ((res = mp_int_copy(b, r)) != MP_OK) + goto CLEANUP; + else + rout = r; + } + else { + rout = LAST_TEMP(); + SETUP(mp_int_init_copy(LAST_TEMP(), b)); + } + + if ((res = s_udiv_knuth(qout, rout)) != MP_OK) goto CLEANUP; + } + else { + if (q && (res = mp_int_copy(a, q)) != MP_OK) goto CLEANUP; + if (r && (res = mp_int_copy(a, r)) != MP_OK) goto CLEANUP; + + if (q) s_qdiv(q, (mp_size) lg); qout = q; + if (r) s_qmod(r, (mp_size) lg); rout = r; + } + + /* Recompute signs for output */ + if (rout) { + MP_SIGN(rout) = sa; + if (CMPZ(rout) == 0) + MP_SIGN(rout) = MP_ZPOS; + } + if (qout) { + MP_SIGN(qout) = (sa == sb) ? MP_ZPOS : MP_NEG; + if (CMPZ(qout) == 0) + MP_SIGN(qout) = MP_ZPOS; + } + + if (q && (res = mp_int_copy(qout, q)) != MP_OK) goto CLEANUP; + if (r && (res = mp_int_copy(rout, r)) != MP_OK) goto CLEANUP; + + CLEANUP_TEMP(); + return res; +} + +mp_result mp_int_mod(mp_int a, mp_int m, mp_int c) +{ + mp_result res; + mpz_t tmp; + mp_int out; + + if (m == c) { + mp_int_init(&tmp); + out = &tmp; + } + else { + out = c; + } + + if ((res = mp_int_div(a, m, NULL, out)) != MP_OK) + goto CLEANUP; + + if (CMPZ(out) < 0) + res = mp_int_add(out, m, c); + else + res = mp_int_copy(out, c); + + CLEANUP: + if (out != c) + mp_int_clear(&tmp); + + return res; +} + +mp_result mp_int_div_value(mp_int a, mp_small value, mp_int q, mp_small *r) +{ + mpz_t vtmp, rtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + mp_result res; + + mp_int_init(&rtmp); + s_fake(&vtmp, value, vbuf); + + if ((res = mp_int_div(a, &vtmp, q, &rtmp)) != MP_OK) + goto CLEANUP; + + if (r) + (void) mp_int_to_int(&rtmp, r); /* can't fail */ + + CLEANUP: + mp_int_clear(&rtmp); + return res; +} + +mp_result mp_int_div_pow2(mp_int a, mp_small p2, mp_int q, mp_int r) +{ + mp_result res = MP_OK; + + CHECK(a != NULL && p2 >= 0 && q != r); + + if (q != NULL && (res = mp_int_copy(a, q)) == MP_OK) + s_qdiv(q, (mp_size) p2); + + if (res == MP_OK && r != NULL && (res = mp_int_copy(a, r)) == MP_OK) + s_qmod(r, (mp_size) p2); + + return res; +} + +mp_result mp_int_expt(mp_int a, mp_small b, mp_int c) +{ + mpz_t t; + mp_result res; + unsigned int v = labs(b); + + CHECK(c != NULL); + if (b < 0) + return MP_RANGE; + + if ((res = mp_int_init_copy(&t, a)) != MP_OK) + return res; + + (void) mp_int_set_value(c, 1); + while (v != 0) { + if (v & 1) { + if ((res = mp_int_mul(c, &t, c)) != MP_OK) + goto CLEANUP; + } + + v >>= 1; + if (v == 0) break; + + if ((res = mp_int_sqr(&t, &t)) != MP_OK) + goto CLEANUP; + } + + CLEANUP: + mp_int_clear(&t); + return res; +} + +mp_result mp_int_expt_value(mp_small a, mp_small b, mp_int c) +{ + mpz_t t; + mp_result res; + unsigned int v = labs(b); + + CHECK(c != NULL); + if (b < 0) + return MP_RANGE; + + if ((res = mp_int_init_value(&t, a)) != MP_OK) + return res; + + (void) mp_int_set_value(c, 1); + while (v != 0) { + if (v & 1) { + if ((res = mp_int_mul(c, &t, c)) != MP_OK) + goto CLEANUP; + } + + v >>= 1; + if (v == 0) break; + + if ((res = mp_int_sqr(&t, &t)) != MP_OK) + goto CLEANUP; + } + + CLEANUP: + mp_int_clear(&t); + return res; +} + +mp_result mp_int_expt_full(mp_int a, mp_int b, mp_int c) +{ + mpz_t t; + mp_result res; + unsigned ix, jx; + + CHECK(a != NULL && b != NULL && c != NULL); + if (MP_SIGN(b) == MP_NEG) + return MP_RANGE; + + if ((res = mp_int_init_copy(&t, a)) != MP_OK) + return res; + + (void) mp_int_set_value(c, 1); + for (ix = 0; ix < MP_USED(b); ++ix) { + mp_digit d = b->digits[ix]; + + for (jx = 0; jx < MP_DIGIT_BIT; ++jx) { + if (d & 1) { + if ((res = mp_int_mul(c, &t, c)) != MP_OK) + goto CLEANUP; + } + + d >>= 1; + if (d == 0 && ix + 1 == MP_USED(b)) + break; + if ((res = mp_int_sqr(&t, &t)) != MP_OK) + goto CLEANUP; + } + } + + CLEANUP: + mp_int_clear(&t); + return res; +} + +int mp_int_compare(mp_int a, mp_int b) +{ + mp_sign sa; + + CHECK(a != NULL && b != NULL); + + sa = MP_SIGN(a); + if (sa == MP_SIGN(b)) { + int cmp = s_ucmp(a, b); + + /* If they're both zero or positive, the normal comparison applies; if both + negative, the sense is reversed. */ + if (sa == MP_ZPOS) + return cmp; + else + return -cmp; + + } + else { + if (sa == MP_ZPOS) + return 1; + else + return -1; + } +} + +int mp_int_compare_unsigned(mp_int a, mp_int b) +{ + NRCHECK(a != NULL && b != NULL); + + return s_ucmp(a, b); +} + +int mp_int_compare_zero(mp_int z) +{ + NRCHECK(z != NULL); + + if (MP_USED(z) == 1 && z->digits[0] == 0) + return 0; + else if (MP_SIGN(z) == MP_ZPOS) + return 1; + else + return -1; +} + +int mp_int_compare_value(mp_int z, mp_small value) +{ + mp_sign vsign = (value < 0) ? MP_NEG : MP_ZPOS; + int cmp; + + CHECK(z != NULL); + + if (vsign == MP_SIGN(z)) { + cmp = s_vcmp(z, value); + + return (vsign == MP_ZPOS) ? cmp : -cmp; + } + else { + return (value < 0) ? 1 : -1; + } +} + +int mp_int_compare_uvalue(mp_int z, mp_usmall uv) +{ + CHECK(z != NULL); + + if (MP_SIGN(z) == MP_NEG) + return -1; + else + return s_uvcmp(z, uv); +} + +mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m, mp_int c) +{ + mp_result res; + mp_size um; + mp_int s; + DECLARE_TEMP(3); + + CHECK(a != NULL && b != NULL && c != NULL && m != NULL); + + /* Zero moduli and negative exponents are not considered. */ + if (CMPZ(m) == 0) + return MP_UNDEF; + if (CMPZ(b) < 0) + return MP_RANGE; + + um = MP_USED(m); + SETUP(mp_int_init_size(TEMP(0), 2 * um)); + SETUP(mp_int_init_size(TEMP(1), 2 * um)); + + if (c == b || c == m) { + SETUP(mp_int_init_size(TEMP(2), 2 * um)); + s = TEMP(2); + } + else { + s = c; + } + + if ((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP; + + if ((res = s_brmu(TEMP(1), m)) != MP_OK) goto CLEANUP; + + if ((res = s_embar(TEMP(0), b, m, TEMP(1), s)) != MP_OK) + goto CLEANUP; + + res = mp_int_copy(s, c); + + CLEANUP_TEMP(); + return res; +} + +mp_result mp_int_exptmod_evalue(mp_int a, mp_small value, mp_int m, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_exptmod(a, &vtmp, m, c); +} + +mp_result mp_int_exptmod_bvalue(mp_small value, mp_int b, + mp_int m, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_exptmod(&vtmp, b, m, c); +} + +mp_result mp_int_exptmod_known(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c) +{ + mp_result res; + mp_size um; + mp_int s; + DECLARE_TEMP(2); + + CHECK(a && b && m && c); + + /* Zero moduli and negative exponents are not considered. */ + if (CMPZ(m) == 0) + return MP_UNDEF; + if (CMPZ(b) < 0) + return MP_RANGE; + + um = MP_USED(m); + SETUP(mp_int_init_size(TEMP(0), 2 * um)); + + if (c == b || c == m) { + SETUP(mp_int_init_size(TEMP(1), 2 * um)); + s = TEMP(1); + } + else { + s = c; + } + + if ((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP; + + if ((res = s_embar(TEMP(0), b, m, mu, s)) != MP_OK) + goto CLEANUP; + + res = mp_int_copy(s, c); + + CLEANUP_TEMP(); + return res; +} + +mp_result mp_int_redux_const(mp_int m, mp_int c) +{ + CHECK(m != NULL && c != NULL && m != c); + + return s_brmu(c, m); +} + +mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c) +{ + mp_result res; + mp_sign sa; + DECLARE_TEMP(2); + + CHECK(a != NULL && m != NULL && c != NULL); + + if (CMPZ(a) == 0 || CMPZ(m) <= 0) + return MP_RANGE; + + sa = MP_SIGN(a); /* need this for the result later */ + + for (last__ = 0; last__ < 2; ++last__) + mp_int_init(LAST_TEMP()); + + if ((res = mp_int_egcd(a, m, TEMP(0), TEMP(1), NULL)) != MP_OK) + goto CLEANUP; + + if (mp_int_compare_value(TEMP(0), 1) != 0) { + res = MP_UNDEF; + goto CLEANUP; + } + + /* It is first necessary to constrain the value to the proper range */ + if ((res = mp_int_mod(TEMP(1), m, TEMP(1))) != MP_OK) + goto CLEANUP; + + /* Now, if 'a' was originally negative, the value we have is actually the + magnitude of the negative representative; to get the positive value we + have to subtract from the modulus. Otherwise, the value is okay as it + stands. + */ + if (sa == MP_NEG) + res = mp_int_sub(m, TEMP(1), c); + else + res = mp_int_copy(TEMP(1), c); + + CLEANUP_TEMP(); + return res; +} + +/* Binary GCD algorithm due to Josef Stein, 1961 */ +mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c) +{ + int ca, cb, k = 0; + mpz_t u, v, t; + mp_result res; + + CHECK(a != NULL && b != NULL && c != NULL); + + ca = CMPZ(a); + cb = CMPZ(b); + if (ca == 0 && cb == 0) + return MP_UNDEF; + else if (ca == 0) + return mp_int_abs(b, c); + else if (cb == 0) + return mp_int_abs(a, c); + + mp_int_init(&t); + if ((res = mp_int_init_copy(&u, a)) != MP_OK) + goto U; + if ((res = mp_int_init_copy(&v, b)) != MP_OK) + goto V; + + MP_SIGN(&u) = MP_ZPOS; MP_SIGN(&v) = MP_ZPOS; + + { /* Divide out common factors of 2 from u and v */ + int div2_u = s_dp2k(&u), div2_v = s_dp2k(&v); + + k = MIN(div2_u, div2_v); + s_qdiv(&u, (mp_size) k); + s_qdiv(&v, (mp_size) k); + } + + if (mp_int_is_odd(&u)) { + if ((res = mp_int_neg(&v, &t)) != MP_OK) + goto CLEANUP; + } + else { + if ((res = mp_int_copy(&u, &t)) != MP_OK) + goto CLEANUP; + } + + for (;;) { + s_qdiv(&t, s_dp2k(&t)); + + if (CMPZ(&t) > 0) { + if ((res = mp_int_copy(&t, &u)) != MP_OK) + goto CLEANUP; + } + else { + if ((res = mp_int_neg(&t, &v)) != MP_OK) + goto CLEANUP; + } + + if ((res = mp_int_sub(&u, &v, &t)) != MP_OK) + goto CLEANUP; + + if (CMPZ(&t) == 0) + break; + } + + if ((res = mp_int_abs(&u, c)) != MP_OK) + goto CLEANUP; + if (!s_qmul(c, (mp_size) k)) + res = MP_MEMORY; + + CLEANUP: + mp_int_clear(&v); + V: mp_int_clear(&u); + U: mp_int_clear(&t); + + return res; +} + +/* This is the binary GCD algorithm again, but this time we keep track of the + elementary matrix operations as we go, so we can get values x and y + satisfying c = ax + by. + */ +mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c, + mp_int x, mp_int y) +{ + int k, ca, cb; + mp_result res; + DECLARE_TEMP(8); + + CHECK(a != NULL && b != NULL && c != NULL && + (x != NULL || y != NULL)); + + ca = CMPZ(a); + cb = CMPZ(b); + if (ca == 0 && cb == 0) + return MP_UNDEF; + else if (ca == 0) { + if ((res = mp_int_abs(b, c)) != MP_OK) return res; + mp_int_zero(x); (void) mp_int_set_value(y, 1); return MP_OK; + } + else if (cb == 0) { + if ((res = mp_int_abs(a, c)) != MP_OK) return res; + (void) mp_int_set_value(x, 1); mp_int_zero(y); return MP_OK; + } + + /* Initialize temporaries: + A:0, B:1, C:2, D:3, u:4, v:5, ou:6, ov:7 */ + for (last__ = 0; last__ < 4; ++last__) + mp_int_init(LAST_TEMP()); + TEMP(0)->digits[0] = 1; + TEMP(3)->digits[0] = 1; + + SETUP(mp_int_init_copy(TEMP(4), a)); + SETUP(mp_int_init_copy(TEMP(5), b)); + + /* We will work with absolute values here */ + MP_SIGN(TEMP(4)) = MP_ZPOS; + MP_SIGN(TEMP(5)) = MP_ZPOS; + + { /* Divide out common factors of 2 from u and v */ + int div2_u = s_dp2k(TEMP(4)), div2_v = s_dp2k(TEMP(5)); + + k = MIN(div2_u, div2_v); + s_qdiv(TEMP(4), k); + s_qdiv(TEMP(5), k); + } + + SETUP(mp_int_init_copy(TEMP(6), TEMP(4))); + SETUP(mp_int_init_copy(TEMP(7), TEMP(5))); + + for (;;) { + while (mp_int_is_even(TEMP(4))) { + s_qdiv(TEMP(4), 1); + + if (mp_int_is_odd(TEMP(0)) || mp_int_is_odd(TEMP(1))) { + if ((res = mp_int_add(TEMP(0), TEMP(7), TEMP(0))) != MP_OK) + goto CLEANUP; + if ((res = mp_int_sub(TEMP(1), TEMP(6), TEMP(1))) != MP_OK) + goto CLEANUP; + } + + s_qdiv(TEMP(0), 1); + s_qdiv(TEMP(1), 1); + } + + while (mp_int_is_even(TEMP(5))) { + s_qdiv(TEMP(5), 1); + + if (mp_int_is_odd(TEMP(2)) || mp_int_is_odd(TEMP(3))) { + if ((res = mp_int_add(TEMP(2), TEMP(7), TEMP(2))) != MP_OK) + goto CLEANUP; + if ((res = mp_int_sub(TEMP(3), TEMP(6), TEMP(3))) != MP_OK) + goto CLEANUP; + } + + s_qdiv(TEMP(2), 1); + s_qdiv(TEMP(3), 1); + } + + if (mp_int_compare(TEMP(4), TEMP(5)) >= 0) { + if ((res = mp_int_sub(TEMP(4), TEMP(5), TEMP(4))) != MP_OK) goto CLEANUP; + if ((res = mp_int_sub(TEMP(0), TEMP(2), TEMP(0))) != MP_OK) goto CLEANUP; + if ((res = mp_int_sub(TEMP(1), TEMP(3), TEMP(1))) != MP_OK) goto CLEANUP; + } + else { + if ((res = mp_int_sub(TEMP(5), TEMP(4), TEMP(5))) != MP_OK) goto CLEANUP; + if ((res = mp_int_sub(TEMP(2), TEMP(0), TEMP(2))) != MP_OK) goto CLEANUP; + if ((res = mp_int_sub(TEMP(3), TEMP(1), TEMP(3))) != MP_OK) goto CLEANUP; + } + + if (CMPZ(TEMP(4)) == 0) { + if (x && (res = mp_int_copy(TEMP(2), x)) != MP_OK) goto CLEANUP; + if (y && (res = mp_int_copy(TEMP(3), y)) != MP_OK) goto CLEANUP; + if (c) { + if (!s_qmul(TEMP(5), k)) { + res = MP_MEMORY; + goto CLEANUP; + } + + res = mp_int_copy(TEMP(5), c); + } + + break; + } + } + + CLEANUP_TEMP(); + return res; +} + +mp_result mp_int_lcm(mp_int a, mp_int b, mp_int c) +{ + mpz_t lcm; + mp_result res; + + CHECK(a != NULL && b != NULL && c != NULL); + + /* Since a * b = gcd(a, b) * lcm(a, b), we can compute + lcm(a, b) = (a / gcd(a, b)) * b. + + This formulation insures everything works even if the input + variables share space. + */ + if ((res = mp_int_init(&lcm)) != MP_OK) + return res; + if ((res = mp_int_gcd(a, b, &lcm)) != MP_OK) + goto CLEANUP; + if ((res = mp_int_div(a, &lcm, &lcm, NULL)) != MP_OK) + goto CLEANUP; + if ((res = mp_int_mul(&lcm, b, &lcm)) != MP_OK) + goto CLEANUP; + + res = mp_int_copy(&lcm, c); + + CLEANUP: + mp_int_clear(&lcm); + + return res; +} + +int mp_int_divisible_value(mp_int a, mp_small v) +{ + mp_small rem = 0; + + if (mp_int_div_value(a, v, NULL, &rem) != MP_OK) + return 0; + + return rem == 0; +} + +int mp_int_is_pow2(mp_int z) +{ + CHECK(z != NULL); + + return s_isp2(z); +} + +/* Implementation of Newton's root finding method, based loosely on a patch + contributed by Hal Finkel + modified by M. J. Fromberger. + */ +mp_result mp_int_root(mp_int a, mp_small b, mp_int c) +{ + mp_result res = MP_OK; + int flips = 0; + DECLARE_TEMP(5); + + CHECK(a != NULL && c != NULL && b > 0); + + if (b == 1) { + return mp_int_copy(a, c); + } + if (MP_SIGN(a) == MP_NEG) { + if (b % 2 == 0) + return MP_UNDEF; /* root does not exist for negative a with even b */ + else + flips = 1; + } + + SETUP(mp_int_init_copy(LAST_TEMP(), a)); + SETUP(mp_int_init_copy(LAST_TEMP(), a)); + SETUP(mp_int_init(LAST_TEMP())); + SETUP(mp_int_init(LAST_TEMP())); + SETUP(mp_int_init(LAST_TEMP())); + + (void) mp_int_abs(TEMP(0), TEMP(0)); + (void) mp_int_abs(TEMP(1), TEMP(1)); + + for (;;) { + if ((res = mp_int_expt(TEMP(1), b, TEMP(2))) != MP_OK) + goto CLEANUP; + + if (mp_int_compare_unsigned(TEMP(2), TEMP(0)) <= 0) + break; + + if ((res = mp_int_sub(TEMP(2), TEMP(0), TEMP(2))) != MP_OK) + goto CLEANUP; + if ((res = mp_int_expt(TEMP(1), b - 1, TEMP(3))) != MP_OK) + goto CLEANUP; + if ((res = mp_int_mul_value(TEMP(3), b, TEMP(3))) != MP_OK) + goto CLEANUP; + if ((res = mp_int_div(TEMP(2), TEMP(3), TEMP(4), NULL)) != MP_OK) + goto CLEANUP; + if ((res = mp_int_sub(TEMP(1), TEMP(4), TEMP(4))) != MP_OK) + goto CLEANUP; + + if (mp_int_compare_unsigned(TEMP(1), TEMP(4)) == 0) { + if ((res = mp_int_sub_value(TEMP(4), 1, TEMP(4))) != MP_OK) + goto CLEANUP; + } + if ((res = mp_int_copy(TEMP(4), TEMP(1))) != MP_OK) + goto CLEANUP; + } + + if ((res = mp_int_copy(TEMP(1), c)) != MP_OK) + goto CLEANUP; + + /* If the original value of a was negative, flip the output sign. */ + if (flips) + (void) mp_int_neg(c, c); /* cannot fail */ + + CLEANUP_TEMP(); + return res; +} + +mp_result mp_int_to_int(mp_int z, mp_small *out) +{ + mp_usmall uv = 0; + mp_size uz; + mp_digit *dz; + mp_sign sz; + + CHECK(z != NULL); + + /* Make sure the value is representable as a small integer */ + sz = MP_SIGN(z); + if ((sz == MP_ZPOS && mp_int_compare_value(z, MP_SMALL_MAX) > 0) || + mp_int_compare_value(z, MP_SMALL_MIN) < 0) + return MP_RANGE; + + uz = MP_USED(z); + dz = MP_DIGITS(z) + uz - 1; + + while (uz > 0) { + uv <<= MP_DIGIT_BIT/2; + uv = (uv << (MP_DIGIT_BIT/2)) | *dz--; + --uz; + } + + if (out) + *out = (mp_small)((sz == MP_NEG) ? -uv : uv); + + return MP_OK; +} + +mp_result mp_int_to_uint(mp_int z, mp_usmall *out) +{ + mp_usmall uv = 0; + mp_size uz; + mp_digit *dz; + mp_sign sz; + + CHECK(z != NULL); + + /* Make sure the value is representable as an unsigned small integer */ + sz = MP_SIGN(z); + if (sz == MP_NEG || mp_int_compare_uvalue(z, MP_USMALL_MAX) > 0) + return MP_RANGE; + + uz = MP_USED(z); + dz = MP_DIGITS(z) + uz - 1; + + while (uz > 0) { + uv <<= MP_DIGIT_BIT/2; + uv = (uv << (MP_DIGIT_BIT/2)) | *dz--; + --uz; + } + + if (out) + *out = uv; + + return MP_OK; +} + +mp_result mp_int_to_string(mp_int z, mp_size radix, + char *str, int limit) +{ + mp_result res; + int cmp = 0; + + CHECK(z != NULL && str != NULL && limit >= 2); + + if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) + return MP_RANGE; + + if (CMPZ(z) == 0) { + *str++ = s_val2ch(0, 1); + } + else { + mpz_t tmp; + char *h, *t; + + if ((res = mp_int_init_copy(&tmp, z)) != MP_OK) + return res; + + if (MP_SIGN(z) == MP_NEG) { + *str++ = '-'; + --limit; + } + h = str; + + /* Generate digits in reverse order until finished or limit reached */ + for (/* */; limit > 0; --limit) { + mp_digit d; + + if ((cmp = CMPZ(&tmp)) == 0) + break; + + d = s_ddiv(&tmp, (mp_digit)radix); + *str++ = s_val2ch(d, 1); + } + t = str - 1; + + /* Put digits back in correct output order */ + while (h < t) { + char tc = *h; + *h++ = *t; + *t-- = tc; + } + + mp_int_clear(&tmp); + } + + *str = '\0'; + if (cmp == 0) + return MP_OK; + else + return MP_TRUNC; +} + +mp_result mp_int_string_len(mp_int z, mp_size radix) +{ + int len; + + CHECK(z != NULL); + + if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) + return MP_RANGE; + + len = s_outlen(z, radix) + 1; /* for terminator */ + + /* Allow for sign marker on negatives */ + if (MP_SIGN(z) == MP_NEG) + len += 1; + + return len; +} + +/* Read zero-terminated string into z */ +mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str) +{ + return mp_int_read_cstring(z, radix, str, NULL); +} + +mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, char **end) +{ + int ch; + + CHECK(z != NULL && str != NULL); + + if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) + return MP_RANGE; + + /* Skip leading whitespace */ + while (isspace((int)*str)) + ++str; + + /* Handle leading sign tag (+/-, positive default) */ + switch (*str) { + case '-': + MP_SIGN(z) = MP_NEG; + ++str; + break; + case '+': + ++str; /* fallthrough */ + default: + MP_SIGN(z) = MP_ZPOS; + break; + } + + /* Skip leading zeroes */ + while ((ch = s_ch2val(*str, radix)) == 0) + ++str; + + /* Make sure there is enough space for the value */ + if (!s_pad(z, s_inlen(strlen(str), radix))) + return MP_MEMORY; + + MP_USED(z) = 1; z->digits[0] = 0; + + while (*str != '\0' && ((ch = s_ch2val(*str, radix)) >= 0)) { + s_dmul(z, (mp_digit)radix); + s_dadd(z, (mp_digit)ch); + ++str; + } + + CLAMP(z); + + /* Override sign for zero, even if negative specified. */ + if (CMPZ(z) == 0) + MP_SIGN(z) = MP_ZPOS; + + if (end != NULL) + *end = (char *)str; + + /* Return a truncation error if the string has unprocessed characters + remaining, so the caller can tell if the whole string was done */ + if (*str != '\0') + return MP_TRUNC; + else + return MP_OK; +} + +mp_result mp_int_count_bits(mp_int z) +{ + mp_size nbits = 0, uz; + mp_digit d; + + CHECK(z != NULL); + + uz = MP_USED(z); + if (uz == 1 && z->digits[0] == 0) + return 1; + + --uz; + nbits = uz * MP_DIGIT_BIT; + d = z->digits[uz]; + + while (d != 0) { + d >>= 1; + ++nbits; + } + + return nbits; +} + +mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit) +{ + static const int PAD_FOR_2C = 1; + + mp_result res; + int limpos = limit; + + CHECK(z != NULL && buf != NULL); + + res = s_tobin(z, buf, &limpos, PAD_FOR_2C); + + if (MP_SIGN(z) == MP_NEG) + s_2comp(buf, limpos); + + return res; +} + +mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len) +{ + mp_size need, i; + unsigned char *tmp; + mp_digit *dz; + + CHECK(z != NULL && buf != NULL && len > 0); + + /* Figure out how many digits are needed to represent this value */ + need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT; + if (!s_pad(z, need)) + return MP_MEMORY; + + mp_int_zero(z); + + /* If the high-order bit is set, take the 2's complement before reading the + value (it will be restored afterward) */ + if (buf[0] >> (CHAR_BIT - 1)) { + MP_SIGN(z) = MP_NEG; + s_2comp(buf, len); + } + + dz = MP_DIGITS(z); + for (tmp = buf, i = len; i > 0; --i, ++tmp) { + s_qmul(z, (mp_size) CHAR_BIT); + *dz |= *tmp; + } + + /* Restore 2's complement if we took it before */ + if (MP_SIGN(z) == MP_NEG) + s_2comp(buf, len); + + return MP_OK; +} + +mp_result mp_int_binary_len(mp_int z) +{ + mp_result res = mp_int_count_bits(z); + int bytes = mp_int_unsigned_len(z); + + if (res <= 0) + return res; + + bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT; + + /* If the highest-order bit falls exactly on a byte boundary, we need to pad + with an extra byte so that the sign will be read correctly when reading it + back in. */ + if (bytes * CHAR_BIT == res) + ++bytes; + + return bytes; +} + +mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit) +{ + static const int NO_PADDING = 0; + + CHECK(z != NULL && buf != NULL); + + return s_tobin(z, buf, &limit, NO_PADDING); +} + +mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len) +{ + mp_size need, i; + unsigned char *tmp; + + CHECK(z != NULL && buf != NULL && len > 0); + + /* Figure out how many digits are needed to represent this value */ + need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT; + if (!s_pad(z, need)) + return MP_MEMORY; + + mp_int_zero(z); + + for (tmp = buf, i = len; i > 0; --i, ++tmp) { + (void) s_qmul(z, CHAR_BIT); + *MP_DIGITS(z) |= *tmp; + } + + return MP_OK; +} + +mp_result mp_int_unsigned_len(mp_int z) +{ + mp_result res = mp_int_count_bits(z); + int bytes; + + if (res <= 0) + return res; + + bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT; + + return bytes; +} + +const char *mp_error_string(mp_result res) +{ + int ix; + if (res > 0) + return s_unknown_err; + + res = -res; + for (ix = 0; ix < res && s_error_msg[ix] != NULL; ++ix) + ; + + if (s_error_msg[ix] != NULL) + return s_error_msg[ix]; + else + return s_unknown_err; +} + +/*------------------------------------------------------------------------*/ +/* Private functions for internal use. These make assumptions. */ + +STATIC mp_digit *s_alloc(mp_size num) +{ + mp_digit *out = malloc(num * sizeof(mp_digit)); + + assert(out != NULL); /* for debugging */ +#if DEBUG > 1 + { + mp_digit v = (mp_digit) 0xdeadbeef; + int ix; + + for (ix = 0; ix < num; ++ix) + out[ix] = v; + } +#endif + + return out; +} + +STATIC mp_digit *s_realloc(mp_digit *old, mp_size osize, mp_size nsize) +{ +#if DEBUG > 1 + mp_digit *new = s_alloc(nsize); + int ix; + + for (ix = 0; ix < nsize; ++ix) + new[ix] = (mp_digit) 0xdeadbeef; + + memcpy(new, old, osize * sizeof(mp_digit)); +#else + mp_digit *new = realloc(old, nsize * sizeof(mp_digit)); + + assert(new != NULL); /* for debugging */ +#endif + return new; +} + +STATIC void s_free(void *ptr) +{ + free(ptr); +} + +STATIC int s_pad(mp_int z, mp_size min) +{ + if (MP_ALLOC(z) < min) { + mp_size nsize = ROUND_PREC(min); + mp_digit *tmp; + + if ((void *)z->digits == (void *)z) { + if ((tmp = s_alloc(nsize)) == NULL) + return 0; + + COPY(MP_DIGITS(z), tmp, MP_USED(z)); + } + else if ((tmp = s_realloc(MP_DIGITS(z), MP_ALLOC(z), nsize)) == NULL) + return 0; + + MP_DIGITS(z) = tmp; + MP_ALLOC(z) = nsize; + } + + return 1; +} + +/* Note: This will not work correctly when value == MP_SMALL_MIN */ +STATIC void s_fake(mp_int z, mp_small value, mp_digit vbuf[]) +{ + mp_usmall uv = (mp_usmall) (value < 0) ? -value : value; + s_ufake(z, uv, vbuf); + if (value < 0) + z->sign = MP_NEG; +} + +STATIC void s_ufake(mp_int z, mp_usmall value, mp_digit vbuf[]) +{ + mp_size ndig = (mp_size) s_uvpack(value, vbuf); + + z->used = ndig; + z->alloc = MP_VALUE_DIGITS(value); + z->sign = MP_ZPOS; + z->digits = vbuf; +} + +STATIC int s_cdig(mp_digit *da, mp_digit *db, mp_size len) +{ + mp_digit *dat = da + len - 1, *dbt = db + len - 1; + + for (/* */; len != 0; --len, --dat, --dbt) { + if (*dat > *dbt) + return 1; + else if (*dat < *dbt) + return -1; + } + + return 0; +} + +STATIC int s_uvpack(mp_usmall uv, mp_digit t[]) +{ + int ndig = 0; + + if (uv == 0) + t[ndig++] = 0; + else { + while (uv != 0) { + t[ndig++] = (mp_digit) uv; + uv >>= MP_DIGIT_BIT/2; + uv >>= MP_DIGIT_BIT/2; + } + } + + return ndig; +} + +STATIC int s_ucmp(mp_int a, mp_int b) +{ + mp_size ua = MP_USED(a), ub = MP_USED(b); + + if (ua > ub) + return 1; + else if (ub > ua) + return -1; + else + return s_cdig(MP_DIGITS(a), MP_DIGITS(b), ua); +} + +STATIC int s_vcmp(mp_int a, mp_small v) +{ + mp_usmall uv = (v < 0) ? -(mp_usmall) v : (mp_usmall) v; + return s_uvcmp(a, uv); +} + +STATIC int s_uvcmp(mp_int a, mp_usmall uv) +{ + mpz_t vtmp; + mp_digit vdig[MP_VALUE_DIGITS(uv)]; + + s_ufake(&vtmp, uv, vdig); + return s_ucmp(a, &vtmp); +} + +STATIC mp_digit s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b) +{ + mp_size pos; + mp_word w = 0; + + /* Insure that da is the longer of the two to simplify later code */ + if (size_b > size_a) { + SWAP(mp_digit *, da, db); + SWAP(mp_size, size_a, size_b); + } + + /* Add corresponding digits until the shorter number runs out */ + for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) { + w = w + (mp_word) *da + (mp_word) *db; + *dc = LOWER_HALF(w); + w = UPPER_HALF(w); + } + + /* Propagate carries as far as necessary */ + for (/* */; pos < size_a; ++pos, ++da, ++dc) { + w = w + *da; + + *dc = LOWER_HALF(w); + w = UPPER_HALF(w); + } + + /* Return carry out */ + return (mp_digit)w; +} + +STATIC void s_usub(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b) +{ + mp_size pos; + mp_word w = 0; + + /* We assume that |a| >= |b| so this should definitely hold */ + assert(size_a >= size_b); + + /* Subtract corresponding digits and propagate borrow */ + for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) { + w = ((mp_word)MP_DIGIT_MAX + 1 + /* MP_RADIX */ + (mp_word)*da) - w - (mp_word)*db; + + *dc = LOWER_HALF(w); + w = (UPPER_HALF(w) == 0); + } + + /* Finish the subtraction for remaining upper digits of da */ + for (/* */; pos < size_a; ++pos, ++da, ++dc) { + w = ((mp_word)MP_DIGIT_MAX + 1 + /* MP_RADIX */ + (mp_word)*da) - w; + + *dc = LOWER_HALF(w); + w = (UPPER_HALF(w) == 0); + } + + /* If there is a borrow out at the end, it violates the precondition */ + assert(w == 0); +} + +STATIC int s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b) +{ + mp_size bot_size; + + /* Make sure b is the smaller of the two input values */ + if (size_b > size_a) { + SWAP(mp_digit *, da, db); + SWAP(mp_size, size_a, size_b); + } + + /* Insure that the bottom is the larger half in an odd-length split; the code + below relies on this being true. + */ + bot_size = (size_a + 1) / 2; + + /* If the values are big enough to bother with recursion, use the Karatsuba + algorithm to compute the product; otherwise use the normal multiplication + algorithm + */ + if (multiply_threshold && + size_a >= multiply_threshold && + size_b > bot_size) { + + mp_digit *t1, *t2, *t3, carry; + + mp_digit *a_top = da + bot_size; + mp_digit *b_top = db + bot_size; + + mp_size at_size = size_a - bot_size; + mp_size bt_size = size_b - bot_size; + mp_size buf_size = 2 * bot_size; + + /* Do a single allocation for all three temporary buffers needed; each + buffer must be big enough to hold the product of two bottom halves, and + one buffer needs space for the completed product; twice the space is + plenty. + */ + if ((t1 = s_alloc(4 * buf_size)) == NULL) return 0; + t2 = t1 + buf_size; + t3 = t2 + buf_size; + ZERO(t1, 4 * buf_size); + + /* t1 and t2 are initially used as temporaries to compute the inner product + (a1 + a0)(b1 + b0) = a1b1 + a1b0 + a0b1 + a0b0 + */ + carry = s_uadd(da, a_top, t1, bot_size, at_size); /* t1 = a1 + a0 */ + t1[bot_size] = carry; + + carry = s_uadd(db, b_top, t2, bot_size, bt_size); /* t2 = b1 + b0 */ + t2[bot_size] = carry; + + (void) s_kmul(t1, t2, t3, bot_size + 1, bot_size + 1); /* t3 = t1 * t2 */ + + /* Now we'll get t1 = a0b0 and t2 = a1b1, and subtract them out so that + we're left with only the pieces we want: t3 = a1b0 + a0b1 + */ + ZERO(t1, buf_size); + ZERO(t2, buf_size); + (void) s_kmul(da, db, t1, bot_size, bot_size); /* t1 = a0 * b0 */ + (void) s_kmul(a_top, b_top, t2, at_size, bt_size); /* t2 = a1 * b1 */ + + /* Subtract out t1 and t2 to get the inner product */ + s_usub(t3, t1, t3, buf_size + 2, buf_size); + s_usub(t3, t2, t3, buf_size + 2, buf_size); + + /* Assemble the output value */ + COPY(t1, dc, buf_size); + carry = s_uadd(t3, dc + bot_size, dc + bot_size, + buf_size + 1, buf_size); + assert(carry == 0); + + carry = s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size, + buf_size, buf_size); + assert(carry == 0); + + s_free(t1); /* note t2 and t3 are just internal pointers to t1 */ + } + else { + s_umul(da, db, dc, size_a, size_b); + } + + return 1; +} + +STATIC void s_umul(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b) +{ + mp_size a, b; + mp_word w; + + for (a = 0; a < size_a; ++a, ++dc, ++da) { + mp_digit *dct = dc; + mp_digit *dbt = db; + + if (*da == 0) + continue; + + w = 0; + for (b = 0; b < size_b; ++b, ++dbt, ++dct) { + w = (mp_word)*da * (mp_word)*dbt + w + (mp_word)*dct; + + *dct = LOWER_HALF(w); + w = UPPER_HALF(w); + } + + *dct = (mp_digit)w; + } +} + +STATIC int s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a) +{ + if (multiply_threshold && size_a > multiply_threshold) { + mp_size bot_size = (size_a + 1) / 2; + mp_digit *a_top = da + bot_size; + mp_digit *t1, *t2, *t3, carry; + mp_size at_size = size_a - bot_size; + mp_size buf_size = 2 * bot_size; + + if ((t1 = s_alloc(4 * buf_size)) == NULL) return 0; + t2 = t1 + buf_size; + t3 = t2 + buf_size; + ZERO(t1, 4 * buf_size); + + (void) s_ksqr(da, t1, bot_size); /* t1 = a0 ^ 2 */ + (void) s_ksqr(a_top, t2, at_size); /* t2 = a1 ^ 2 */ + + (void) s_kmul(da, a_top, t3, bot_size, at_size); /* t3 = a0 * a1 */ + + /* Quick multiply t3 by 2, shifting left (can't overflow) */ + { + int i, top = bot_size + at_size; + mp_word w, save = 0; + + for (i = 0; i < top; ++i) { + w = t3[i]; + w = (w << 1) | save; + t3[i] = LOWER_HALF(w); + save = UPPER_HALF(w); + } + t3[i] = LOWER_HALF(save); + } + + /* Assemble the output value */ + COPY(t1, dc, 2 * bot_size); + carry = s_uadd(t3, dc + bot_size, dc + bot_size, + buf_size + 1, buf_size); + assert(carry == 0); + + carry = s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size, + buf_size, buf_size); + assert(carry == 0); + + s_free(t1); /* note that t2 and t2 are internal pointers only */ + + } + else { + s_usqr(da, dc, size_a); + } + + return 1; +} + +STATIC void s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a) +{ + mp_size i, j; + mp_word w; + + for (i = 0; i < size_a; ++i, dc += 2, ++da) { + mp_digit *dct = dc, *dat = da; + + if (*da == 0) + continue; + + /* Take care of the first digit, no rollover */ + w = (mp_word)*dat * (mp_word)*dat + (mp_word)*dct; + *dct = LOWER_HALF(w); + w = UPPER_HALF(w); + ++dat; ++dct; + + for (j = i + 1; j < size_a; ++j, ++dat, ++dct) { + mp_word t = (mp_word)*da * (mp_word)*dat; + mp_word u = w + (mp_word)*dct, ov = 0; + + /* Check if doubling t will overflow a word */ + if (HIGH_BIT_SET(t)) + ov = 1; + + w = t + t; + + /* Check if adding u to w will overflow a word */ + if (ADD_WILL_OVERFLOW(w, u)) + ov = 1; + + w += u; + + *dct = LOWER_HALF(w); + w = UPPER_HALF(w); + if (ov) { + w += MP_DIGIT_MAX; /* MP_RADIX */ + ++w; + } + } + + w = w + *dct; + *dct = (mp_digit)w; + while ((w = UPPER_HALF(w)) != 0) { + ++dct; w = w + *dct; + *dct = LOWER_HALF(w); + } + + assert(w == 0); + } +} + +STATIC void s_dadd(mp_int a, mp_digit b) +{ + mp_word w = 0; + mp_digit *da = MP_DIGITS(a); + mp_size ua = MP_USED(a); + + w = (mp_word)*da + b; + *da++ = LOWER_HALF(w); + w = UPPER_HALF(w); + + for (ua -= 1; ua > 0; --ua, ++da) { + w = (mp_word)*da + w; + + *da = LOWER_HALF(w); + w = UPPER_HALF(w); + } + + if (w) { + *da = (mp_digit)w; + MP_USED(a) += 1; + } +} + +STATIC void s_dmul(mp_int a, mp_digit b) +{ + mp_word w = 0; + mp_digit *da = MP_DIGITS(a); + mp_size ua = MP_USED(a); + + while (ua > 0) { + w = (mp_word)*da * b + w; + *da++ = LOWER_HALF(w); + w = UPPER_HALF(w); + --ua; + } + + if (w) { + *da = (mp_digit)w; + MP_USED(a) += 1; + } +} + +STATIC void s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc, mp_size size_a) +{ + mp_word w = 0; + + while (size_a > 0) { + w = (mp_word)*da++ * (mp_word)b + w; + + *dc++ = LOWER_HALF(w); + w = UPPER_HALF(w); + --size_a; + } + + if (w) + *dc = LOWER_HALF(w); +} + +STATIC mp_digit s_ddiv(mp_int a, mp_digit b) +{ + mp_word w = 0, qdigit; + mp_size ua = MP_USED(a); + mp_digit *da = MP_DIGITS(a) + ua - 1; + + for (/* */; ua > 0; --ua, --da) { + w = (w << MP_DIGIT_BIT) | *da; + + if (w >= b) { + qdigit = w / b; + w = w % b; + } + else { + qdigit = 0; + } + + *da = (mp_digit)qdigit; + } + + CLAMP(a); + return (mp_digit)w; +} + +STATIC void s_qdiv(mp_int z, mp_size p2) +{ + mp_size ndig = p2 / MP_DIGIT_BIT, nbits = p2 % MP_DIGIT_BIT; + mp_size uz = MP_USED(z); + + if (ndig) { + mp_size mark; + mp_digit *to, *from; + + if (ndig >= uz) { + mp_int_zero(z); + return; + } + + to = MP_DIGITS(z); from = to + ndig; + + for (mark = ndig; mark < uz; ++mark) + *to++ = *from++; + + MP_USED(z) = uz - ndig; + } + + if (nbits) { + mp_digit d = 0, *dz, save; + mp_size up = MP_DIGIT_BIT - nbits; + + uz = MP_USED(z); + dz = MP_DIGITS(z) + uz - 1; + + for (/* */; uz > 0; --uz, --dz) { + save = *dz; + + *dz = (*dz >> nbits) | (d << up); + d = save; + } + + CLAMP(z); + } + + if (MP_USED(z) == 1 && z->digits[0] == 0) + MP_SIGN(z) = MP_ZPOS; +} + +STATIC void s_qmod(mp_int z, mp_size p2) +{ + mp_size start = p2 / MP_DIGIT_BIT + 1, rest = p2 % MP_DIGIT_BIT; + mp_size uz = MP_USED(z); + mp_digit mask = (1u << rest) - 1; + + if (start <= uz) { + MP_USED(z) = start; + z->digits[start - 1] &= mask; + CLAMP(z); + } +} + +STATIC int s_qmul(mp_int z, mp_size p2) +{ + mp_size uz, need, rest, extra, i; + mp_digit *from, *to, d; + + if (p2 == 0) + return 1; + + uz = MP_USED(z); + need = p2 / MP_DIGIT_BIT; rest = p2 % MP_DIGIT_BIT; + + /* Figure out if we need an extra digit at the top end; this occurs if the + topmost `rest' bits of the high-order digit of z are not zero, meaning + they will be shifted off the end if not preserved */ + extra = 0; + if (rest != 0) { + mp_digit *dz = MP_DIGITS(z) + uz - 1; + + if ((*dz >> (MP_DIGIT_BIT - rest)) != 0) + extra = 1; + } + + if (!s_pad(z, uz + need + extra)) + return 0; + + /* If we need to shift by whole digits, do that in one pass, then + to back and shift by partial digits. + */ + if (need > 0) { + from = MP_DIGITS(z) + uz - 1; + to = from + need; + + for (i = 0; i < uz; ++i) + *to-- = *from--; + + ZERO(MP_DIGITS(z), need); + uz += need; + } + + if (rest) { + d = 0; + for (i = need, from = MP_DIGITS(z) + need; i < uz; ++i, ++from) { + mp_digit save = *from; + + *from = (*from << rest) | (d >> (MP_DIGIT_BIT - rest)); + d = save; + } + + d >>= (MP_DIGIT_BIT - rest); + if (d != 0) { + *from = d; + uz += extra; + } + } + + MP_USED(z) = uz; + CLAMP(z); + + return 1; +} + +/* Compute z = 2^p2 - |z|; requires that 2^p2 >= |z| + The sign of the result is always zero/positive. + */ +STATIC int s_qsub(mp_int z, mp_size p2) +{ + mp_digit hi = (1 << (p2 % MP_DIGIT_BIT)), *zp; + mp_size tdig = (p2 / MP_DIGIT_BIT), pos; + mp_word w = 0; + + if (!s_pad(z, tdig + 1)) + return 0; + + for (pos = 0, zp = MP_DIGITS(z); pos < tdig; ++pos, ++zp) { + w = ((mp_word) MP_DIGIT_MAX + 1) - w - (mp_word)*zp; + + *zp = LOWER_HALF(w); + w = UPPER_HALF(w) ? 0 : 1; + } + + w = ((mp_word) MP_DIGIT_MAX + 1 + hi) - w - (mp_word)*zp; + *zp = LOWER_HALF(w); + + assert(UPPER_HALF(w) != 0); /* no borrow out should be possible */ + + MP_SIGN(z) = MP_ZPOS; + CLAMP(z); + + return 1; +} + +STATIC int s_dp2k(mp_int z) +{ + int k = 0; + mp_digit *dp = MP_DIGITS(z), d; + + if (MP_USED(z) == 1 && *dp == 0) + return 1; + + while (*dp == 0) { + k += MP_DIGIT_BIT; + ++dp; + } + + d = *dp; + while ((d & 1) == 0) { + d >>= 1; + ++k; + } + + return k; +} + +STATIC int s_isp2(mp_int z) +{ + mp_size uz = MP_USED(z), k = 0; + mp_digit *dz = MP_DIGITS(z), d; + + while (uz > 1) { + if (*dz++ != 0) + return -1; + k += MP_DIGIT_BIT; + --uz; + } + + d = *dz; + while (d > 1) { + if (d & 1) + return -1; + ++k; d >>= 1; + } + + return (int) k; +} + +STATIC int s_2expt(mp_int z, mp_small k) +{ + mp_size ndig, rest; + mp_digit *dz; + + ndig = (k + MP_DIGIT_BIT) / MP_DIGIT_BIT; + rest = k % MP_DIGIT_BIT; + + if (!s_pad(z, ndig)) + return 0; + + dz = MP_DIGITS(z); + ZERO(dz, ndig); + *(dz + ndig - 1) = (1 << rest); + MP_USED(z) = ndig; + + return 1; +} + +STATIC int s_norm(mp_int a, mp_int b) +{ + mp_digit d = b->digits[MP_USED(b) - 1]; + int k = 0; + + while (d < (1u << (mp_digit)(MP_DIGIT_BIT - 1))) { /* d < (MP_RADIX / 2) */ + d <<= 1; + ++k; + } + + /* These multiplications can't fail */ + if (k != 0) { + (void) s_qmul(a, (mp_size) k); + (void) s_qmul(b, (mp_size) k); + } + + return k; +} + +STATIC mp_result s_brmu(mp_int z, mp_int m) +{ + mp_size um = MP_USED(m) * 2; + + if (!s_pad(z, um)) + return MP_MEMORY; + + s_2expt(z, MP_DIGIT_BIT * um); + return mp_int_div(z, m, z, NULL); +} + +STATIC int s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2) +{ + mp_size um = MP_USED(m), umb_p1, umb_m1; + + umb_p1 = (um + 1) * MP_DIGIT_BIT; + umb_m1 = (um - 1) * MP_DIGIT_BIT; + + if (mp_int_copy(x, q1) != MP_OK) + return 0; + + /* Compute q2 = floor((floor(x / b^(k-1)) * mu) / b^(k+1)) */ + s_qdiv(q1, umb_m1); + UMUL(q1, mu, q2); + s_qdiv(q2, umb_p1); + + /* Set x = x mod b^(k+1) */ + s_qmod(x, umb_p1); + + /* Now, q is a guess for the quotient a / m. + Compute x - q * m mod b^(k+1), replacing x. This may be off + by a factor of 2m, but no more than that. + */ + UMUL(q2, m, q1); + s_qmod(q1, umb_p1); + (void) mp_int_sub(x, q1, x); /* can't fail */ + + /* The result may be < 0; if it is, add b^(k+1) to pin it in the proper + range. */ + if ((CMPZ(x) < 0) && !s_qsub(x, umb_p1)) + return 0; + + /* If x > m, we need to back it off until it is in range. This will be + required at most twice. */ + if (mp_int_compare(x, m) >= 0) { + (void) mp_int_sub(x, m, x); + if (mp_int_compare(x, m) >= 0) + (void) mp_int_sub(x, m, x); + } + + /* At this point, x has been properly reduced. */ + return 1; +} + +/* Perform modular exponentiation using Barrett's method, where mu is the + reduction constant for m. Assumes a < m, b > 0. */ +STATIC mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c) +{ + mp_digit *db, *dbt, umu, d; + mp_result res; + DECLARE_TEMP(3); + + umu = MP_USED(mu); db = MP_DIGITS(b); dbt = db + MP_USED(b) - 1; + + while (last__ < 3) { + SETUP(mp_int_init_size(LAST_TEMP(), 4 * umu)); + ZERO(MP_DIGITS(TEMP(last__ - 1)), MP_ALLOC(TEMP(last__ - 1))); + } + + (void) mp_int_set_value(c, 1); + + /* Take care of low-order digits */ + while (db < dbt) { + int i; + + for (d = *db, i = MP_DIGIT_BIT; i > 0; --i, d >>= 1) { + if (d & 1) { + /* The use of a second temporary avoids allocation */ + UMUL(c, a, TEMP(0)); + if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) { + res = MP_MEMORY; goto CLEANUP; + } + mp_int_copy(TEMP(0), c); + } + + + USQR(a, TEMP(0)); + assert(MP_SIGN(TEMP(0)) == MP_ZPOS); + if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) { + res = MP_MEMORY; goto CLEANUP; + } + assert(MP_SIGN(TEMP(0)) == MP_ZPOS); + mp_int_copy(TEMP(0), a); + } + + ++db; + } + + /* Take care of highest-order digit */ + d = *dbt; + for (;;) { + if (d & 1) { + UMUL(c, a, TEMP(0)); + if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) { + res = MP_MEMORY; goto CLEANUP; + } + mp_int_copy(TEMP(0), c); + } + + d >>= 1; + if (!d) break; + + USQR(a, TEMP(0)); + if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) { + res = MP_MEMORY; goto CLEANUP; + } + (void) mp_int_copy(TEMP(0), a); + } + + CLEANUP_TEMP(); + return res; +} + +/* Division of nonnegative integers + + This function implements division algorithm for unsigned multi-precision + integers. The algorithm is based on Algorithm D from Knuth's "The Art of + Computer Programming", 3rd ed. 1998, pg 272-273. + + We diverge from Knuth's algorithm in that we do not perform the subtraction + from the remainder until we have determined that we have the correct + quotient digit. This makes our algorithm less efficient that Knuth because + we might have to perform multiple multiplication and comparison steps before + the subtraction. The advantage is that it is easy to implement and ensure + correctness without worrying about underflow from the subtraction. + + inputs: u a n+m digit integer in base b (b is 2^MP_DIGIT_BIT) + v a n digit integer in base b (b is 2^MP_DIGIT_BIT) + n >= 1 + m >= 0 + outputs: u / v stored in u + u % v stored in v + */ +STATIC mp_result s_udiv_knuth(mp_int u, mp_int v) { + mpz_t q, r, t; + mp_result + res = MP_OK; + int k,j; + mp_size m,n; + + /* Force signs to positive */ + MP_SIGN(u) = MP_ZPOS; + MP_SIGN(v) = MP_ZPOS; + + /* Use simple division algorithm when v is only one digit long */ + if (MP_USED(v) == 1) { + mp_digit d, rem; + d = v->digits[0]; + rem = s_ddiv(u, d); + mp_int_set_value(v, rem); + return MP_OK; + } + + /* Algorithm D + + The n and m variables are defined as used by Knuth. + u is an n digit number with digits u_{n-1}..u_0. + v is an n+m digit number with digits from v_{m+n-1}..v_0. + We require that n > 1 and m >= 0 + */ + n = MP_USED(v); + m = MP_USED(u) - n; + assert(n > 1); + assert(m >= 0); + + /* D1: Normalize. + The normalization step provides the necessary condition for Theorem B, + which states that the quotient estimate for q_j, call it qhat + + qhat = u_{j+n}u_{j+n-1} / v_{n-1} + + is bounded by + + qhat - 2 <= q_j <= qhat. + + That is, qhat is always greater than the actual quotient digit q, + and it is never more than two larger than the actual quotient digit. + */ + k = s_norm(u, v); + + /* Extend size of u by one if needed. + + The algorithm begins with a value of u that has one more digit of input. + The normalization step sets u_{m+n}..u_0 = 2^k * u_{m+n-1}..u_0. If the + multiplication did not increase the number of digits of u, we need to add + a leading zero here. + */ + if (k == 0 || MP_USED(u) != m + n + 1) { + if (!s_pad(u, m+n+1)) + return MP_MEMORY; + u->digits[m+n] = 0; + u->used = m+n+1; + } + + /* Add a leading 0 to v. + + The multiplication in step D4 multiplies qhat * 0v_{n-1}..v_0. We need to + add the leading zero to v here to ensure that the multiplication will + produce the full n+1 digit result. + */ + if (!s_pad(v, n+1)) return MP_MEMORY; v->digits[n] = 0; + + /* Initialize temporary variables q and t. + q allocates space for m+1 digits to store the quotient digits + t allocates space for n+1 digits to hold the result of q_j*v + */ + if ((res = mp_int_init_size(&q, m + 1)) != MP_OK) return res; + if ((res = mp_int_init_size(&t, n + 1)) != MP_OK) goto CLEANUP; + + /* D2: Initialize j */ + j = m; + r.digits = MP_DIGITS(u) + j; /* The contents of r are shared with u */ + r.used = n + 1; + r.sign = MP_ZPOS; + r.alloc = MP_ALLOC(u); + ZERO(t.digits, t.alloc); + + /* Calculate the m+1 digits of the quotient result */ + for (; j >= 0; j--) { + /* D3: Calculate q' */ + /* r->digits is aligned to position j of the number u */ + mp_word pfx, qhat; + pfx = r.digits[n]; + pfx <<= MP_DIGIT_BIT / 2; + pfx <<= MP_DIGIT_BIT / 2; + pfx |= r.digits[n-1]; /* pfx = u_{j+n}{j+n-1} */ + + qhat = pfx / v->digits[n-1]; + /* Check to see if qhat > b, and decrease qhat if so. + Theorem B guarantess that qhat is at most 2 larger than the + actual value, so it is possible that qhat is greater than + the maximum value that will fit in a digit */ + if (qhat > MP_DIGIT_MAX) + qhat = MP_DIGIT_MAX; + + /* D4,D5,D6: Multiply qhat * v and test for a correct value of q + + We proceed a bit different than the way described by Knuth. This way is + simpler but less efficent. Instead of doing the multiply and subtract + then checking for underflow, we first do the multiply of qhat * v and + see if it is larger than the current remainder r. If it is larger, we + decrease qhat by one and try again. We may need to decrease qhat one + more time before we get a value that is smaller than r. + + This way is less efficent than Knuth becuase we do more multiplies, but + we do not need to worry about underflow this way. + */ + /* t = qhat * v */ + s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1); t.used = n + 1; + CLAMP(&t); + + /* Clamp r for the comparison. Comparisons do not like leading zeros. */ + CLAMP(&r); + if (s_ucmp(&t, &r) > 0) { /* would the remainder be negative? */ + qhat -= 1; /* try a smaller q */ + s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1); + t.used = n + 1; CLAMP(&t); + if (s_ucmp(&t, &r) > 0) { /* would the remainder be negative? */ + assert(qhat > 0); + qhat -= 1; /* try a smaller q */ + s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1); + t.used = n + 1; CLAMP(&t); + } + assert(s_ucmp(&t, &r) <= 0 && "The mathematics failed us."); + } + /* Unclamp r. The D algorithm expects r = u_{j+n}..u_j to always be n+1 + digits long. */ + r.used = n + 1; + + /* D4: Multiply and subtract + + Note: The multiply was completed above so we only need to subtract here. + */ + s_usub(r.digits, t.digits, r.digits, r.used, t.used); + + /* D5: Test remainder + + Note: Not needed because we always check that qhat is the correct value + before performing the subtract. Value cast to mp_digit to prevent + warning, qhat has been clamped to MP_DIGIT_MAX + */ + q.digits[j] = (mp_digit)qhat; + + /* D6: Add back + Note: Not needed because we always check that qhat is the correct value + before performing the subtract. + */ + + /* D7: Loop on j */ + r.digits--; + ZERO(t.digits, t.alloc); + } + + /* Get rid of leading zeros in q */ + q.used = m + 1; + CLAMP(&q); + + /* Denormalize the remainder */ + CLAMP(u); /* use u here because the r.digits pointer is off-by-one */ + if (k != 0) + s_qdiv(u, k); + + mp_int_copy(u, v); /* ok: 0 <= r < v */ + mp_int_copy(&q, u); /* ok: q <= u */ + + mp_int_clear(&t); + CLEANUP: + mp_int_clear(&q); + return res; +} + +STATIC int s_outlen(mp_int z, mp_size r) +{ + mp_result bits; + double raw; + + assert(r >= MP_MIN_RADIX && r <= MP_MAX_RADIX); + + bits = mp_int_count_bits(z); + raw = (double)bits * s_log2[r]; + + return (int)(raw + 0.999999); +} + +STATIC mp_size s_inlen(int len, mp_size r) +{ + double raw = (double)len / s_log2[r]; + mp_size bits = (mp_size)(raw + 0.5); + + return (mp_size)((bits + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT) + 1; +} + +STATIC int s_ch2val(char c, int r) +{ + int out; + + if (isdigit((unsigned char) c)) + out = c - '0'; + else if (r > 10 && isalpha((unsigned char) c)) + out = toupper(c) - 'A' + 10; + else + return -1; + + return (out >= r) ? -1 : out; +} + +STATIC char s_val2ch(int v, int caps) +{ + assert(v >= 0); + + if (v < 10) + return v + '0'; + else { + char out = (v - 10) + 'a'; + + if (caps) + return toupper(out); + else + return out; + } +} + +STATIC void s_2comp(unsigned char *buf, int len) +{ + int i; + unsigned short s = 1; + + for (i = len - 1; i >= 0; --i) { + unsigned char c = ~buf[i]; + + s = c + s; + c = s & UCHAR_MAX; + s >>= CHAR_BIT; + + buf[i] = c; + } + + /* last carry out is ignored */ +} + +STATIC mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad) +{ + mp_size uz; + mp_digit *dz; + int pos = 0, limit = *limpos; + + uz = MP_USED(z); dz = MP_DIGITS(z); + while (uz > 0 && pos < limit) { + mp_digit d = *dz++; + int i; + + for (i = sizeof(mp_digit); i > 0 && pos < limit; --i) { + buf[pos++] = (unsigned char)d; + d >>= CHAR_BIT; + + /* Don't write leading zeroes */ + if (d == 0 && uz == 1) + i = 0; /* exit loop without signaling truncation */ + } + + /* Detect truncation (loop exited with pos >= limit) */ + if (i > 0) break; + + --uz; + } + + if (pad != 0 && (buf[pos - 1] >> (CHAR_BIT - 1))) { + if (pos < limit) + buf[pos++] = 0; + else + uz = 1; + } + + /* Digits are in reverse order, fix that */ + REV(unsigned char, buf, pos); + + /* Return the number of bytes actually written */ + *limpos = pos; + + return (uz == 0) ? MP_OK : MP_TRUNC; +} + +#if DEBUG +void s_print(char *tag, mp_int z) +{ + int i; + + fprintf(stderr, "%s: %c ", tag, + (MP_SIGN(z) == MP_NEG) ? '-' : '+'); + + for (i = MP_USED(z) - 1; i >= 0; --i) + fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), z->digits[i]); + + fputc('\n', stderr); + +} + +void s_print_buf(char *tag, mp_digit *buf, mp_size num) +{ + int i; + + fprintf(stderr, "%s: ", tag); + + for (i = num - 1; i >= 0; --i) + fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), buf[i]); + + fputc('\n', stderr); +} +#endif + +/* Here there be dragons */ Index: contrib/isl/imath/imdrover.h =================================================================== --- /dev/null +++ contrib/isl/imath/imdrover.h @@ -0,0 +1,106 @@ +/* + Name: imdrover.h + Purpose: Keeper of the hordes of testing code. + Author: M. J. Fromberger + + Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#ifndef IMDROVER_H_ +#define IMDROVER_H_ + +#include + +typedef struct { + int line; + char *code; + int num_inputs; + char **input; + int num_outputs; + char **output; +} testspec_t; + +typedef int (*test_f)(testspec_t *, FILE *); + +/* Call this once at the outset to set up test registers */ +void init_testing(void); +void reset_registers(void); + +/* Integer tests, and general */ +int test_init(testspec_t* t, FILE* ofp); +int test_set(testspec_t* t, FILE* ofp); +int test_neg(testspec_t* t, FILE* ofp); +int test_abs(testspec_t* t, FILE* ofp); +int test_add(testspec_t* t, FILE* ofp); +int test_sub(testspec_t* t, FILE* ofp); +int test_mul(testspec_t* t, FILE* ofp); +int test_mulp2(testspec_t* t, FILE* ofp); +int test_mulv(testspec_t* t, FILE* ofp); +int test_sqr(testspec_t* t, FILE* ofp); +int test_div(testspec_t* t, FILE* ofp); +int test_divp2(testspec_t* t, FILE* ofp); +int test_divv(testspec_t* t, FILE* ofp); +int test_expt(testspec_t* t, FILE* ofp); +int test_exptv(testspec_t* t, FILE* ofp); +int test_exptf(testspec_t* t, FILE* ofp); +int test_mod(testspec_t* t, FILE* ofp); +int test_gcd(testspec_t* t, FILE* ofp); +int test_egcd(testspec_t* t, FILE* ofp); +int test_lcm(testspec_t* t, FILE* ofp); +int test_sqrt(testspec_t* t, FILE* ofp); +int test_root(testspec_t* t, FILE* ofp); +int test_invmod(testspec_t* t, FILE* ofp); +int test_exptmod(testspec_t* t, FILE* ofp); +int test_exptmod_ev(testspec_t* t, FILE* ofp); +int test_exptmod_bv(testspec_t* t, FILE* ofp); +int test_comp(testspec_t* t, FILE* ofp); +int test_ucomp(testspec_t* t, FILE* ofp); +int test_zcomp(testspec_t* t, FILE* ofp); +int test_vcomp(testspec_t* t, FILE* ofp); +int test_uvcomp(testspec_t* t, FILE* ofp); +int test_tostr(testspec_t* t, FILE* ofp); +int test_tobin(testspec_t* t, FILE* ofp); +int test_to_int(testspec_t* t, FILE* ofp); +int test_to_uint(testspec_t* t, FILE* ofp); +int test_read_binary(testspec_t* t, FILE* ofp); +int test_to_uns(testspec_t* t, FILE* ofp); +int test_read_uns(testspec_t* t, FILE* ofp); +int test_meta(testspec_t* t, FILE* ofp); + +/* Rational tests */ +int test_qneg(testspec_t* t, FILE* ofp); +int test_qrecip(testspec_t* t, FILE* ofp); +int test_qabs(testspec_t* t, FILE* ofp); +int test_qadd(testspec_t* t, FILE* ofp); +int test_qsub(testspec_t* t, FILE* ofp); +int test_qmul(testspec_t* t, FILE* ofp); +int test_qdiv(testspec_t* t, FILE* ofp); +int test_qdiv(testspec_t* t, FILE* ofp); +int test_qaddz(testspec_t* t, FILE* ofp); +int test_qsubz(testspec_t* t, FILE* ofp); +int test_qmulz(testspec_t* t, FILE* ofp); +int test_qdivz(testspec_t* t, FILE* ofp); +int test_qexpt(testspec_t* t, FILE* ofp); +int test_qtostr(testspec_t* t, FILE* ofp); +int test_qtodec(testspec_t* t, FILE* ofp); +int test_qrdec(testspec_t* t, FILE* ofp); + +#endif /* IMDROVER_H_ */ Index: contrib/isl/imath/imdrover.c =================================================================== --- /dev/null +++ contrib/isl/imath/imdrover.c @@ -0,0 +1,1532 @@ +/* + Name: imdrover.c + Purpose: Keeper of the hordes of testing code. + Author: M. J. Fromberger + + Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include +#include + +#include "imdrover.h" +#include "imath.h" +#include "imrat.h" + +/* Globals visible from outside this file */ +mp_result imath_errno; +char *imath_errmsg; + +/* Set imath_errno and return failure from a test. */ +#define FAIL(E) return (imath_errno = (E), 0) + +/* Check that an expression X yields the expected mp_result value V. */ +#define VCHECK(X, V) \ +do { \ + mp_result res_; \ + if ((res_ = (X)) != (V)) { \ + FAIL(res_); \ + } \ +} while(0) +#define CHECK(X) VCHECK(X, MP_OK) +#define ECHECK(X) VCHECK(X, expect) +#define ACHECK(X) \ +do { \ + if (!(X)) { \ + FAIL(MP_BADARG); \ + } \ +} while(0) + +#define OUTPUT_LIMIT 2048 +#define NUM_REGS 16 +#define OTHER_ERROR -1024 + +static char g_output[OUTPUT_LIMIT]; +static mpz_t g_zreg[NUM_REGS]; +static mpq_t g_qreg[NUM_REGS]; +static unsigned char g_bin1[OUTPUT_LIMIT]; +static unsigned char g_bin2[OUTPUT_LIMIT]; + +extern void trim_line(char *line); /* borrowed from imtest.c */ + +/* Read in a string with radix tags */ +static mp_result read_int_value(mp_int z, char *str); +static mp_result read_rat_value(mp_rat q, char *str); + +/* Read in a string with radix tags, as a long (not an mp_int) */ +static int read_long(long *z, char *str); + +/* Parse the input and output values and fill in pointers to the + registers containing them. Returns true if all is well, false + in case of error. Caller allocates in/out to correct sizes. */ +static int parse_int_values(testspec_t* t, mp_int *in, mp_int *out, + mp_result *rval); +static int parse_rat_values(testspec_t* t, mp_rat *in, mp_rat *out, + mp_result *rval); + +/* Parse a result code name and return the corresponding result + code */ +static int parse_result_code(char *str, mp_result *code); + +/* Read in a dot-delimited binary sequence to the given buffer, and + return the number of bytes read. Returns < 0 in case of a syntax + error. Records no more than limit bytes. */ +static int parse_binary(char *str, unsigned char *buf, int limit); + +/* Clean up registers (called from atexit()) */ +static void done_testing(void); + +/*------------------------------------------------------------------------*/ +/* Utility subroutines for writing tests (explained above) */ + +static mp_result read_int_value(mp_int z, char *str) +{ + int radix = 10; + + if(*str == '#') { + ++str; + switch(*str) { + case 'x': case 'X': + radix = 16; + break; + case 'd': case 'D': + radix = 10; + break; + case 'o': case 'O': + radix = 8; + break; + case 'b': case 'B': + radix = 2; + break; + default: + return MP_RANGE; + } + ++str; + } + + return mp_int_read_string(z, radix, str); +} + +static mp_result read_rat_value(mp_rat q, char *str) +{ + int radix = 10; + + if(*str == '#') { + ++str; + switch(*str) { + case 'x': case 'X': + radix = 16; + break; + case 'd': case 'D': + radix = 10; + break; + case 'o': case 'O': + radix = 8; + break; + case 'b': case 'B': + radix = 2; + break; + default: + return MP_RANGE; + } + ++str; + } + + if(*str == '@') + return mp_rat_read_decimal(q, radix, str + 1); + else + return mp_rat_read_string(q, radix, str); +} + +static int read_long(long *z, char *str) +{ + char *end; + int radix = 10; + + if (*str == '#') { + ++str; + switch (*str) { + case 'x': case 'X': + radix = 16; + break; + case 'd': case 'D': + radix = 10; + break; + case 'o': case 'O': + radix = 8; + break; + case 'b': case 'B': + radix = 2; + break; + default: + return 0; + } + ++str; + } + + *z = strtol(str, &end, radix); + return (end != str && *end == '\0'); +} + +static int parse_int_values(testspec_t* t, mp_int* in, mp_int* out, + mp_result* rval) +{ + int i, pos = 0; + char *str; + + if (rval != NULL) + *rval = MP_OK; /* default */ + + if (in != NULL) { + for (i = 0; i < t->num_inputs; ++i) { + str = t->input[i]; + + trim_line(str); + + if (*str == '=') { + int k = abs(atoi(str + 1)) - 1; + + if (k < 0 || k >= i) { + fprintf(stderr, "Line %d: Invalid input back-reference [%s]\n", + t->line, str); + return 0; + } + + in[i] = in[k]; + } + else { + mp_int reg = g_zreg + pos++; /* grab next free register */ + + if (read_int_value(reg, str) != MP_OK) { + fprintf(stderr, "Line %d: Invalid input value [%s]\n", + t->line, str); + return 0; + } + + in[i] = reg; + } + } + } + + for (i = 0; i < t->num_outputs; ++i) { + mp_int reg = g_zreg + pos++; + + str = t->output[i]; + + trim_line(str); + + if (strcmp(str, "?") == 0) + mp_int_zero(reg); + else if (*str == '$') { + mp_result code; + + if (!parse_result_code(str, &code)) { + fprintf(stderr, "Line %d: Invalid result code [%s]\n", + t->line, str); + return 0; + } + else if(rval == NULL) { + fprintf(stderr, "Line %d: Result code not permitted here [%s]\n", + t->line, str); + return 0; + } + else + *rval = code; + + /* Provide a dummy value for the corresponding output */ + mp_int_zero(reg); + } + else if (out != NULL && read_int_value(reg, str) != MP_OK) { + fprintf(stderr, "Line %d: Invalid output value [%s]\n", + t->line, str); + return 0; + } + + if (out != NULL) + out[i] = reg; + } + + return 1; +} + +static int parse_rat_values(testspec_t* t, mp_rat *in, mp_rat *out, + mp_result *rval) +{ + int i, pos = 0; + char *str; + + if (rval != NULL) + *rval = MP_OK; /* default */ + + if (in != NULL) { + for (i = 0; i < t->num_inputs; ++i) { + str = t->input[i]; + + trim_line(str); + + if (*str == '=') { + int k = abs(atoi(str + 1)) - 1; + + if (k < 0 || k >= i) { + fprintf(stderr, "Line %d: Invalid input back-reference [%s]\n", + t->line, str); + return 0; + } + + in[i] = in[k]; + } + else { + mp_rat reg = g_qreg + pos++; /* grab next free register */ + + if (read_rat_value(reg, str) != MP_OK) { + fprintf(stderr, "Line %d: Invalid input value [%s]\n", + t->line, str); + return 0; + } + + in[i] = reg; + } + } + } + + for (i = 0; i < t->num_outputs; ++i) { + mp_rat reg = g_qreg + pos++; + + str = t->output[i]; + + trim_line(str); + + if (strcmp(str, "?") == 0) + mp_rat_zero(reg); + else if (*str == '$') { + mp_result code; + + if (!parse_result_code(str, &code)) { + fprintf(stderr, "Line %d: Invalid result code [%s]\n", + t->line, str); + return 0; + } + else if (rval == NULL) { + fprintf(stderr, "Line %d: Result code not permitted here [%s]\n", + t->line, str); + return 0; + } + else + *rval = code; + + /* Provide a dummy value for the corresponding output */ + mp_rat_zero(reg); + } + else if (out != NULL && read_rat_value(reg, str) != MP_OK) { + fprintf(stderr, "Line %d: Invalid output value [%s]\n", + t->line, str); + return 0; + } + + if (out != NULL) + out[i] = reg; + } + + return 1; +} + +static int parse_result_code(char *str, mp_result *code) +{ + if (str[0] == '$') { + if (str[1] == '#') { + long v; + + if (!read_long(&v, str + 2)) + return 0; + + *code = (mp_result) v; + } + else if (strcmp(str + 1, "MP_OK") == 0 || + strcmp(str + 1, "MP_FALSE") == 0) + *code = MP_OK; + else if (strcmp(str + 1, "MP_TRUE") == 0) + *code = MP_TRUE; + else if (strcmp(str + 1, "MP_MEMORY") == 0) + *code = MP_MEMORY; + else if (strcmp(str + 1, "MP_RANGE") == 0) + *code = MP_RANGE; + else if (strcmp(str + 1, "MP_UNDEF") == 0) + *code = MP_UNDEF; + else if (strcmp(str + 1, "MP_TRUNC") == 0) + *code = MP_TRUNC; + else if (strcmp(str + 1, "MP_ROUND_UP") == 0) + *code = MP_ROUND_UP; + else if (strcmp(str + 1, "MP_ROUND_DOWN") == 0) + *code = MP_ROUND_DOWN; + else if (strcmp(str + 1, "MP_ROUND_HALF_UP") == 0) + *code = MP_ROUND_HALF_UP; + else if (strcmp(str + 1, "MP_ROUND_HALF_DOWN") == 0) + *code = MP_ROUND_HALF_DOWN; + else + return 0; + } + + return 1; +} + +static int parse_binary(char *str, unsigned char *buf, int limit) +{ + int pos = 0; + char *tok; + + trim_line(str); + + for (tok = strtok(str, "."); + tok != NULL && pos < limit; + tok = strtok(NULL, ".")) { + long v; + + if (!read_long(&v, tok) || v > UCHAR_MAX || v < 0) + return -1; + + buf[pos++] = (unsigned char)v; + } + + return pos; +} + +static void done_testing(void) +{ + int i; + + for (i = 0; i < NUM_REGS; ++i) { + mp_int_clear(g_zreg + i); + mp_rat_clear(g_qreg + i); + } +} + +/*------------------------------------------------------------------------*/ +/* Global functions visible to callers outside this file */ + +void init_testing(void) +{ + static int is_done = 0; + int i; + + if (is_done) + return; + + for (i = 0; i < NUM_REGS; ++i) { + assert(mp_int_init(g_zreg + i) == MP_OK); + assert(mp_rat_init(g_qreg + i) == MP_OK); + } + + imath_errmsg = g_output; + + assert(atexit(done_testing) == 0); + is_done = 1; +} + +void reset_registers(void) +{ + int i; + + for (i = 0; i < NUM_REGS; ++i) { + mp_int_zero(g_zreg + i); + mp_rat_zero(g_qreg + i); + } +} + +int test_init(testspec_t* t, FILE* ofp) +{ + mp_int in[2], out[1]; + mp_small v; + mp_usmall uv; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + + if (strcmp(t->code, "initu") == 0) { + CHECK(mp_int_to_uint(in[1], &uv)); + ECHECK(mp_int_init_uvalue(in[0], uv)); + } + else { /* initv */ + CHECK(mp_int_to_int(in[1], &v)); + ECHECK(mp_int_init_value(in[0], v)); + } + + + if (expect == MP_OK && mp_int_compare(in[0], out[0]) != 0) { + mp_int_to_string(in[0], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + + return 1; +} + +int test_set(testspec_t* t, FILE* ofp) +{ + mp_int in[2], out[1]; + mp_small v; + mp_usmall uv; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + + if (strcmp(t->code, "setu") == 0) { + CHECK(mp_int_to_uint(in[1], &uv)); + ECHECK(mp_int_set_uvalue(in[0], uv)); + } + else { /* setv */ + CHECK(mp_int_to_int(in[1], &v)); + ECHECK(mp_int_set_value(in[0], v)); + } + + if (expect == MP_OK && mp_int_compare(in[0], out[0]) != 0) { + mp_int_to_string(in[0], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + + return 1; +} + +int test_neg(testspec_t* t, FILE* ofp) +{ + mp_int in[2], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_neg(in[0], in[1])); + + if (expect == MP_OK && mp_int_compare(in[1], out[0]) != 0) { + mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + + return 1; +} + +int test_abs(testspec_t* t, FILE* ofp) +{ + mp_int in[2], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_abs(in[0], in[1])); + + if (expect == MP_OK && mp_int_compare(in[1], out[0]) != 0) { + mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + + return 1; +} + +int test_add(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_small v; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + + if (strcmp(t->code, "addv") == 0) { + CHECK(mp_int_to_int(in[1], &v)); + ECHECK(mp_int_add_value(in[0], v, in[2])); + } + else { + ECHECK(mp_int_add(in[0], in[1], in[2])); + } + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + + return 1; +} + +int test_sub(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_small v; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + + if (strcmp(t->code, "subv") == 0) { + CHECK(mp_int_to_int(in[1], &v)); + ECHECK(mp_int_sub_value(in[0], v, in[2])); + } + else { + ECHECK(mp_int_sub(in[0], in[1], in[2])); + } + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_mul(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_mul(in[0], in[1], in[2])); + + if(expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_mulp2(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + mp_small p2; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[1], &p2)); + ECHECK(mp_int_mul_pow2(in[0], p2, in[2])); + + if(expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_mulv(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + mp_small v; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[1], &v)); + ECHECK(mp_int_mul_value(in[0], v, in[2])); + + if(expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_sqr(testspec_t* t, FILE* ofp) +{ + mp_int in[2], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_sqr(in[0], in[1])); + + if(expect == MP_OK && mp_int_compare(in[1], out[0]) != 0) { + mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_div(testspec_t* t, FILE* ofp) +{ + mp_int in[4], out[2]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_div(in[0], in[1], in[2], in[3])); + + if (expect == MP_OK && + ((mp_int_compare(in[2], out[0]) != 0) || + (mp_int_compare(in[3], out[1]) != 0))) { + int len; + char *str; + + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + str = g_output + (len = strlen(g_output)); + *str++ = ','; + mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1)); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_divp2(testspec_t* t, FILE* ofp) +{ + mp_int in[4], out[2]; + mp_result expect; + mp_small p2; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[1], &p2)); + ECHECK(mp_int_div_pow2(in[0], p2, in[2], in[3])); + + if (expect == MP_OK && + ((mp_int_compare(in[2], out[0]) != 0) || + (mp_int_compare(in[3], out[1]) != 0))) { + int len; + char *str; + + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + str = g_output + (len = strlen(g_output)); + *str++ = ','; + mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1)); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_divv(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[2]; + mp_result expect; + mp_small v, rem, orem; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[1], &v)); + CHECK(mp_int_to_int(out[1], &orem)); + ECHECK(mp_int_div_value(in[0], v, in[2], &rem)); + + if (expect == MP_OK && + ((mp_int_compare(in[2], out[0]) != 0) || (rem != orem))) { + char *str; + + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + str = g_output + strlen(g_output); + *str++ = ','; + sprintf(str, "%ld", rem); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_expt(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + mp_small pow; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[1], &pow)); + ECHECK(mp_int_expt(in[0], pow, in[2])); + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_exptv(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + mp_small a, b; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[0], &a)); + CHECK(mp_int_to_int(in[1], &b)); + ECHECK(mp_int_expt_value(a, b, in[2])); + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_exptf(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_expt_full(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_mod(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_mod(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_gcd(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_gcd(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_egcd(testspec_t* t, FILE* ofp) +{ + mp_int in[5], out[3], t1 = g_zreg + 8, t2 = g_zreg + 9; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_egcd(in[0], in[1], in[2], in[3], in[4])); + + /* If we got an error we expected, return success immediately */ + if(expect != MP_OK) + return 1; + + if ((mp_int_compare(in[2], out[0]) != 0) || + (mp_int_compare(in[3], out[1]) != 0) || + (mp_int_compare(in[4], out[2]) != 0)) { + int len, len2; + char *str; + + /* Failure might occur because the tester computed x and y in a different + way than we did. Verify that the results are correct before reporting + an error. */ + mp_int_mul(in[3], in[0], t1); + mp_int_mul(in[4], in[1], t2); + mp_int_add(t1, t2, t2); + if (mp_int_compare(t2, in[2]) == 0) + return 1; + + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + str = g_output + (len = strlen(g_output)); + *str++ = ','; + mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1)); + str = str + (len2 = strlen(str)); + *str++ = ','; + mp_int_to_string(in[4], 10, str, OUTPUT_LIMIT - (len + len2 + 2)); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_lcm(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_lcm(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_sqrt(testspec_t* t, FILE* ofp) +{ + mp_int in[2], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_sqrt(in[0], in[1])); + + if (expect == MP_OK && mp_int_compare(in[1], out[0]) != 0) { + mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_root(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_small v; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[1], &v)); + ECHECK(mp_int_root(in[0], v, in[2])); + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_invmod(testspec_t* t, FILE* ofp) +{ + mp_int in[3], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_invmod(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) { + mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_exptmod(testspec_t* t, FILE* ofp) +{ + mp_int in[4], out[1]; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_exptmod(in[0], in[1], in[2], in[3])); + + if (expect == MP_OK && mp_int_compare(in[3], out[0]) != 0) { + mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_exptmod_ev(testspec_t* t, FILE* ofp) +{ + mp_int in[4], out[1]; + mp_result expect; + mp_small v; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[1], &v)); + ECHECK(mp_int_exptmod_evalue(in[0], v, in[2], in[3])); + + if (expect == MP_OK && mp_int_compare(in[3], out[0]) != 0) { + mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_exptmod_bv(testspec_t* t, FILE* ofp) +{ + mp_int in[4], out[1]; + mp_result expect; + mp_small v; + + ACHECK(parse_int_values(t, in, out, &expect)); + CHECK(mp_int_to_int(in[0], &v)); + ECHECK(mp_int_exptmod_bvalue(v, in[1], in[2], in[3])); + + if (expect == MP_OK && mp_int_compare(in[3], out[0]) != 0) { + mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_comp(testspec_t* t, FILE* ofp) +{ + mp_int in[2]; + mp_result res, expect; + + ACHECK(parse_int_values(t, in, NULL, &expect)); + + if ((res = mp_int_compare(in[0], in[1])) != expect) { + sprintf(g_output, "Incorrect comparison result (want %d, got %d)", + expect, res); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_ucomp(testspec_t* t, FILE* ofp) +{ + mp_int in[2]; + mp_result res, expect; + + ACHECK(parse_int_values(t, in, NULL, &expect)); + + if ((res = mp_int_compare_unsigned(in[0], in[1])) != expect) { + sprintf(g_output, "Incorrect comparison result (want %d, got %d)", + expect, res); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_zcomp(testspec_t* t, FILE* ofp) +{ + mp_int in[1]; + mp_result res, expect; + + ACHECK(parse_int_values(t, in, NULL, &expect)); + + if ((res = mp_int_compare_zero(in[0])) != expect) { + sprintf(g_output, "Incorrect comparison result (want %d, got %d)", + expect, res); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_vcomp(testspec_t* t, FILE* ofp) +{ + mp_int in[2]; + mp_result res, expect; + mp_small v; + + ACHECK(parse_int_values(t, in, NULL, &expect)); + + v = atoi(t->input[1]); + if ((res = mp_int_compare_value(in[0], v)) != expect) { + sprintf(g_output, "Incorrect comparison result (want %d, got %d)", + expect, res); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_uvcomp(testspec_t* t, FILE* ofp) +{ + mp_int in[2]; + mp_result res, expect; + mp_usmall v; + + ACHECK(parse_int_values(t, in, NULL, &expect)); + + v = strtoul(t->input[1], NULL, 0); + if ((res = mp_int_compare_uvalue(in[0], v)) != expect) { + sprintf(g_output, "Incorrect comparison result (want %d, got %d)", + expect, res); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_tostr(testspec_t* t, FILE* ofp) +{ + mp_int in[2]; + mp_small radix; + mp_result len; + + ACHECK(parse_int_values(t, in, NULL, NULL)); + ACHECK(mp_int_to_int(in[1], &radix) == MP_OK); + + if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) + FAIL(MP_RANGE); + + trim_line(t->output[0]); + len = mp_int_string_len(in[0], radix); + + CHECK(mp_int_to_string(in[0], radix, g_output, len)); + + if(strcmp(t->output[0], g_output) != 0) + FAIL(OTHER_ERROR); + + return 1; +} + +int test_tobin(testspec_t* t, FILE* ofp) +{ + mp_int in[1]; + int test_len, out_len; + + ACHECK(parse_int_values(t, in, NULL, NULL)); + + trim_line(t->output[0]); + if((out_len = parse_binary(t->output[0], g_bin1, sizeof(g_bin1))) < 0) + FAIL(MP_BADARG); + + if((test_len = mp_int_binary_len(in[0])) != out_len) { + sprintf(g_output, "Output lengths do not match (want %d, got %d)", + test_len, out_len); + FAIL(OTHER_ERROR); + } + + CHECK(mp_int_to_binary(in[0], g_bin2, sizeof(g_bin2))); + + if (memcmp(g_bin1, g_bin2, test_len) != 0) { + int pos = 0, i; + + for(i = 0; i < test_len - 1; ++i) + pos += sprintf(g_output + pos, "%d.", g_bin2[i]); + + sprintf(g_output + pos, "%d", g_bin2[i]); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_to_int(testspec_t* t, FILE* ofp) +{ + mp_int in[1], out[1]; + mp_small v; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_to_int(in[0], &v)); + + if (expect == MP_OK && mp_int_compare_value(out[0], v) != 0) { + sprintf(g_output, "Incorrect value (got %ld)", v); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_to_uint(testspec_t* t, FILE* ofp) +{ + mp_int in[1], out[1]; + mp_usmall v; + mp_result expect; + + ACHECK(parse_int_values(t, in, out, &expect)); + ECHECK(mp_int_to_uint(in[0], &v)); + + if (expect == MP_OK && mp_int_compare_uvalue(out[0], v) != 0) { + sprintf(g_output, "Incorrect value (got %lu)", v); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_read_binary(testspec_t* t, FILE* ofp) +{ + mp_int out[1], in = g_zreg + 1; + int in_len; + mp_result expect; + + ACHECK(parse_int_values(t, NULL, out, &expect)); + + trim_line(t->input[0]); + if((in_len = parse_binary(t->input[0], g_bin1, sizeof(g_bin1))) < 0) + FAIL(MP_BADARG); + + ECHECK(mp_int_read_binary(in, g_bin1, in_len)); + + if (expect == MP_OK && mp_int_compare(in, out[0]) != 0) { + mp_int_to_string(in, 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_to_uns(testspec_t* t, FILE* ofp) +{ + mp_int in[1]; + int test_len, out_len; + + ACHECK(parse_int_values(t, in, NULL, NULL)); + + trim_line(t->output[0]); + if((out_len = parse_binary(t->output[0], g_bin1, sizeof(g_bin1))) < 0) + FAIL(MP_BADARG); + + if((test_len = mp_int_unsigned_len(in[0])) != out_len) { + sprintf(g_output, "Output lengths do not match (want %d, got %d)", + test_len, out_len); + FAIL(OTHER_ERROR); + } + + CHECK(mp_int_to_unsigned(in[0], g_bin2, sizeof(g_bin2))); + + if (memcmp(g_bin1, g_bin2, test_len) != 0) { + int pos = 0, i; + + for(i = 0; i < test_len - 1; ++i) + pos += sprintf(g_output + pos, "%d.", g_bin2[i]); + + sprintf(g_output + pos, "%d", g_bin2[i]); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_read_uns(testspec_t* t, FILE* ofp) +{ + mp_int out[1], in = g_zreg + 1; + int in_len; + mp_result expect; + + ACHECK(parse_int_values(t, NULL, out, &expect)); + + trim_line(t->input[0]); + if((in_len = parse_binary(t->input[0], g_bin1, sizeof(g_bin1))) < 0) + FAIL(MP_BADARG); + + ECHECK(mp_int_read_unsigned(in, g_bin1, in_len)); + + if (expect == MP_OK && mp_int_compare(in, out[0]) != 0) { + mp_int_to_string(in, 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_meta(testspec_t* t, FILE* ofp) +{ + mp_int *in = NULL, *out = NULL; + int i, j; + mp_result expect; + + if (t->num_inputs > 0) + in = calloc(t->num_inputs, sizeof(mp_int)); + if (t->num_outputs > 0) + out = calloc(t->num_outputs, sizeof(mp_int)); + + ACHECK(parse_int_values(t, in, out, &expect)); + + fprintf(ofp, "Test '%s' defined at line %d\n", + t->code, t->line); + fprintf(ofp, "Expected result: %d\n", expect); + fprintf(ofp, "Input values: %d\n", t->num_inputs); + for (i = 0; i < t->num_inputs; ++i) { + mp_int_to_string(in[i], 10, g_output, OUTPUT_LIMIT); + + fprintf(ofp, " %2d.) %s", i + 1, g_output); + + for (j = i - 1; j >= 0; --j) + if (in[j] == in[i]) { + fprintf(ofp, " (=> %d)", j + 1); + break; + } + + fputc('\n', ofp); + } + fprintf(ofp, "Output values: %d\n", t->num_outputs); + for (i = 0; i < t->num_outputs; ++i) { + mp_int_to_string(out[i], 10, g_output, OUTPUT_LIMIT); + + fprintf(ofp, " %2d.) %s\n", i + 1, g_output); + } + return 1; +} + +int test_qneg(testspec_t* t, FILE* ofp) +{ + mp_rat in[2], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + ECHECK(mp_rat_neg(in[0], in[1])); + + if (expect == MP_OK && mp_rat_compare(in[1], out[0]) != 0) { + mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qrecip(testspec_t* t, FILE* ofp) +{ + mp_rat in[2], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + ECHECK(mp_rat_recip(in[0], in[1])); + + if (expect == MP_OK && mp_rat_compare(in[1], out[0]) != 0) { + mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qabs(testspec_t* t, FILE* ofp) +{ + mp_rat in[2], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + ECHECK(mp_rat_abs(in[0], in[1])); + + if (expect == MP_OK && mp_rat_compare(in[1], out[0]) != 0) { + mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qadd(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + ECHECK(mp_rat_add(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qsub(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + ECHECK(mp_rat_sub(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qmul(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + ECHECK(mp_rat_mul(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qdiv(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + ECHECK(mp_rat_div(in[0], in[1], in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qaddz(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + + if (!mp_rat_is_integer(in[1])) { + fprintf(stderr, "Line %d: Second argument must be an integer (test_qaddz)\n", + t->line); + FAIL(MP_BADARG); + } + + ECHECK(mp_rat_add_int(in[0], MP_NUMER_P(in[1]), in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qsubz(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + + if (!mp_rat_is_integer(in[1])) { + fprintf(stderr, "Line %d: Second argument must be an integer (test_qsubz)\n", + t->line); + FAIL(MP_BADARG); + } + + ECHECK(mp_rat_sub_int(in[0], MP_NUMER_P(in[1]), in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qmulz(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + + if (!mp_rat_is_integer(in[1])) { + fprintf(stderr, "Line %d: Second argument must be an integer (test_qmulz)\n", + t->line); + FAIL(MP_BADARG); + } + + ECHECK(mp_rat_mul_int(in[0], MP_NUMER_P(in[1]), in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qdivz(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + + ACHECK(parse_rat_values(t, in, out, &expect)); + + if (!mp_rat_is_integer(in[1])) { + fprintf(stderr, "Line %d: Second argument must be an integer (test_qdivz)\n", + t->line); + FAIL(MP_BADARG); + } + + ECHECK(mp_rat_div_int(in[0], MP_NUMER_P(in[1]), in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qexpt(testspec_t* t, FILE* ofp) +{ + mp_rat in[3], out[1]; + mp_result expect; + mp_small power; + + ACHECK(parse_rat_values(t, in, out, &expect)); + + if (!mp_rat_is_integer(in[1])) { + fprintf(stderr, "Line %d: Second argument must be an integer (test_qexpt)\n", + t->line); + FAIL(MP_BADARG); + } + + CHECK(mp_int_to_int(MP_NUMER_P(in[1]), &power)); + ECHECK(mp_rat_expt(in[0], power, in[2])); + + if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) { + mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +int test_qtostr(testspec_t* t, FILE* ofp) +{ + mp_rat in[2]; + long radix; + mp_result len; + + ACHECK(parse_rat_values(t, in, NULL, NULL)); + trim_line(t->input[1]); + ACHECK(read_long(&radix, t->input[1])); + + if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) { + fprintf(stderr, "Line %d: Radix %ld out of range\n", + t->line, radix); + FAIL(MP_RANGE); + } + + trim_line(t->output[0]); + len = mp_rat_string_len(in[0], radix); + + CHECK(mp_rat_to_string(in[0], radix, g_output, len)); + + if (strcmp(t->output[0], g_output) != 0) + FAIL(OTHER_ERROR); + + return 1; +} + +int test_qtodec(testspec_t* t, FILE* ofp) +{ + mp_rat in[4]; + long radix, prec, m; + mp_round_mode rmode; + mp_result res, expect = MP_OK, len; + + ACHECK(parse_rat_values(t, in, NULL, NULL)); + + if (t->output[0][0] == '$' && !parse_result_code(t->output[0], &expect)) { + fprintf(stderr, "Line %d: Invalid result code [%s]\n", + t->line, t->output[0]); + FAIL(OTHER_ERROR); + } + + trim_line(t->input[1]); + trim_line(t->input[2]); + trim_line(t->input[3]); + ACHECK(read_long(&radix, t->input[1])); + ACHECK(read_long(&prec, t->input[2])); + ACHECK(read_long(&m, t->input[3])); + rmode = (mp_round_mode) m; + + if (prec < 0) { + fprintf(stderr, "Line %d: Precision %ld out of range\n", + t->line, prec); + FAIL(MP_RANGE); + } + + trim_line(t->output[0]); + len = mp_rat_decimal_len(in[0], radix, prec); + ECHECK((res = mp_rat_to_decimal(in[0], radix, prec, rmode, g_output, len))); + + if (res == MP_OK && strcmp(t->output[0], g_output) != 0) + FAIL(OTHER_ERROR); + + return 1; +} + +int test_qrdec(testspec_t* t, FILE* ofp) +{ + mp_rat out[1], reg = g_qreg + 1; + long radix; + mp_result expect; + + ACHECK(parse_rat_values(t, NULL, out, &expect)); + trim_line(t->input[1]); + ACHECK(read_long(&radix, t->input[1])); + + ECHECK(mp_rat_read_decimal(reg, radix, t->input[0])); + if (expect == MP_OK && + mp_rat_compare(reg, out[0]) != 0) { + mp_rat_to_string(reg, 10, g_output, OUTPUT_LIMIT); + FAIL(OTHER_ERROR); + } + return 1; +} + +/* Here there be dragons */ Index: contrib/isl/imath/imrat.h =================================================================== --- /dev/null +++ contrib/isl/imath/imrat.h @@ -0,0 +1,124 @@ +/* + Name: imrat.h + Purpose: Arbitrary precision rational arithmetic routines. + Author: M. J. Fromberger + + Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#ifndef IMRAT_H_ +#define IMRAT_H_ + +#include "imath.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mpq { + mpz_t num; /* Numerator */ + mpz_t den; /* Denominator, <> 0 */ +} mpq_t, *mp_rat; + +#define MP_NUMER_P(Q) (&((Q)->num)) /* Pointer to numerator */ +#define MP_DENOM_P(Q) (&((Q)->den)) /* Pointer to denominator */ + +/* Rounding constants */ +typedef enum { + MP_ROUND_DOWN, + MP_ROUND_HALF_UP, + MP_ROUND_UP, + MP_ROUND_HALF_DOWN +} mp_round_mode; + +mp_result mp_rat_init(mp_rat r); +mp_rat mp_rat_alloc(void); +mp_result mp_rat_reduce(mp_rat r); +mp_result mp_rat_init_size(mp_rat r, mp_size n_prec, mp_size d_prec); +mp_result mp_rat_init_copy(mp_rat r, mp_rat old); +mp_result mp_rat_set_value(mp_rat r, mp_small numer, mp_small denom); +mp_result mp_rat_set_uvalue(mp_rat r, mp_usmall numer, mp_usmall denom); +void mp_rat_clear(mp_rat r); +void mp_rat_free(mp_rat r); +mp_result mp_rat_numer(mp_rat r, mp_int z); /* z = num(r) */ +mp_int mp_rat_numer_ref(mp_rat r); /* &num(r) */ +mp_result mp_rat_denom(mp_rat r, mp_int z); /* z = den(r) */ +mp_int mp_rat_denom_ref(mp_rat r); /* &den(r) */ +mp_sign mp_rat_sign(mp_rat r); + +mp_result mp_rat_copy(mp_rat a, mp_rat c); /* c = a */ +void mp_rat_zero(mp_rat r); /* r = 0 */ +mp_result mp_rat_abs(mp_rat a, mp_rat c); /* c = |a| */ +mp_result mp_rat_neg(mp_rat a, mp_rat c); /* c = -a */ +mp_result mp_rat_recip(mp_rat a, mp_rat c); /* c = 1 / a */ +mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c); /* c = a + b */ +mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c); /* c = a - b */ +mp_result mp_rat_mul(mp_rat a, mp_rat b, mp_rat c); /* c = a * b */ +mp_result mp_rat_div(mp_rat a, mp_rat b, mp_rat c); /* c = a / b */ + +mp_result mp_rat_add_int(mp_rat a, mp_int b, mp_rat c); /* c = a + b */ +mp_result mp_rat_sub_int(mp_rat a, mp_int b, mp_rat c); /* c = a - b */ +mp_result mp_rat_mul_int(mp_rat a, mp_int b, mp_rat c); /* c = a * b */ +mp_result mp_rat_div_int(mp_rat a, mp_int b, mp_rat c); /* c = a / b */ +mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c); /* c = a ^ b */ + +int mp_rat_compare(mp_rat a, mp_rat b); /* a <=> b */ +int mp_rat_compare_unsigned(mp_rat a, mp_rat b); /* |a| <=> |b| */ +int mp_rat_compare_zero(mp_rat r); /* r <=> 0 */ +int mp_rat_compare_value(mp_rat r, mp_small n, mp_small d); /* r <=> n/d */ +int mp_rat_is_integer(mp_rat r); + +/* Convert to integers, if representable (returns MP_RANGE if not). */ +mp_result mp_rat_to_ints(mp_rat r, mp_small *num, mp_small *den); + +/* Convert to nul-terminated string with the specified radix, writing + at most limit characters including the nul terminator. */ +mp_result mp_rat_to_string(mp_rat r, mp_size radix, char *str, int limit); + +/* Convert to decimal format in the specified radix and precision, + writing at most limit characters including a nul terminator. */ +mp_result mp_rat_to_decimal(mp_rat r, mp_size radix, mp_size prec, + mp_round_mode round, char *str, int limit); + +/* Return the number of characters required to represent r in the given + radix. May over-estimate. */ +mp_result mp_rat_string_len(mp_rat r, mp_size radix); + +/* Return the number of characters required to represent r in decimal + format with the given radix and precision. May over-estimate. */ +mp_result mp_rat_decimal_len(mp_rat r, mp_size radix, mp_size prec); + +/* Read zero-terminated string into r */ +mp_result mp_rat_read_string(mp_rat r, mp_size radix, const char *str); +mp_result mp_rat_read_cstring(mp_rat r, mp_size radix, const char *str, + char **end); +mp_result mp_rat_read_ustring(mp_rat r, mp_size radix, const char *str, + char **end); + +/* Read zero-terminated string in decimal format into r */ +mp_result mp_rat_read_decimal(mp_rat r, mp_size radix, const char *str); +mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, const char *str, + char **end); + +#ifdef __cplusplus +} +#endif +#endif /* IMRAT_H_ */ Index: contrib/isl/imath/imrat.c =================================================================== --- /dev/null +++ contrib/isl/imath/imrat.c @@ -0,0 +1,958 @@ +/* + Name: imrat.c + Purpose: Arbitrary precision rational arithmetic routines. + Author: M. J. Fromberger + + Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include "imrat.h" +#include +#include +#include +#include + +#define TEMP(K) (temp + (K)) +#define SETUP(E, C) \ +do{if((res = (E)) != MP_OK) goto CLEANUP; ++(C);}while(0) + +/* Argument checking: + Use CHECK() where a return value is required; NRCHECK() elsewhere */ +#define CHECK(TEST) assert(TEST) +#define NRCHECK(TEST) assert(TEST) + +/* Reduce the given rational, in place, to lowest terms and canonical form. + Zero is represented as 0/1, one as 1/1. Signs are adjusted so that the sign + of the numerator is definitive. */ +static mp_result s_rat_reduce(mp_rat r); + +/* Common code for addition and subtraction operations on rationals. */ +static mp_result s_rat_combine(mp_rat a, mp_rat b, mp_rat c, + mp_result (*comb_f)(mp_int, mp_int, mp_int)); + +mp_result mp_rat_init(mp_rat r) +{ + mp_result res; + + if ((res = mp_int_init(MP_NUMER_P(r))) != MP_OK) + return res; + if ((res = mp_int_init(MP_DENOM_P(r))) != MP_OK) { + mp_int_clear(MP_NUMER_P(r)); + return res; + } + + return mp_int_set_value(MP_DENOM_P(r), 1); +} + +mp_rat mp_rat_alloc(void) +{ + mp_rat out = malloc(sizeof(*out)); + + if (out != NULL) { + if (mp_rat_init(out) != MP_OK) { + free(out); + return NULL; + } + } + + return out; +} + +mp_result mp_rat_reduce(mp_rat r) { + return s_rat_reduce(r); +} + +mp_result mp_rat_init_size(mp_rat r, mp_size n_prec, mp_size d_prec) +{ + mp_result res; + + if ((res = mp_int_init_size(MP_NUMER_P(r), n_prec)) != MP_OK) + return res; + if ((res = mp_int_init_size(MP_DENOM_P(r), d_prec)) != MP_OK) { + mp_int_clear(MP_NUMER_P(r)); + return res; + } + + return mp_int_set_value(MP_DENOM_P(r), 1); +} + +mp_result mp_rat_init_copy(mp_rat r, mp_rat old) +{ + mp_result res; + + if ((res = mp_int_init_copy(MP_NUMER_P(r), MP_NUMER_P(old))) != MP_OK) + return res; + if ((res = mp_int_init_copy(MP_DENOM_P(r), MP_DENOM_P(old))) != MP_OK) + mp_int_clear(MP_NUMER_P(r)); + + return res; +} + +mp_result mp_rat_set_value(mp_rat r, mp_small numer, mp_small denom) +{ + mp_result res; + + if (denom == 0) + return MP_UNDEF; + + if ((res = mp_int_set_value(MP_NUMER_P(r), numer)) != MP_OK) + return res; + if ((res = mp_int_set_value(MP_DENOM_P(r), denom)) != MP_OK) + return res; + + return s_rat_reduce(r); +} + +mp_result mp_rat_set_uvalue(mp_rat r, mp_usmall numer, mp_usmall denom) +{ + mp_result res; + + if (denom == 0) + return MP_UNDEF; + + if ((res = mp_int_set_uvalue(MP_NUMER_P(r), numer)) != MP_OK) + return res; + if ((res = mp_int_set_uvalue(MP_DENOM_P(r), denom)) != MP_OK) + return res; + + return s_rat_reduce(r); +} + +void mp_rat_clear(mp_rat r) +{ + mp_int_clear(MP_NUMER_P(r)); + mp_int_clear(MP_DENOM_P(r)); + +} + +void mp_rat_free(mp_rat r) +{ + NRCHECK(r != NULL); + + if (r->num.digits != NULL) + mp_rat_clear(r); + + free(r); +} + +mp_result mp_rat_numer(mp_rat r, mp_int z) +{ + return mp_int_copy(MP_NUMER_P(r), z); +} + +mp_int mp_rat_numer_ref(mp_rat r) +{ + return MP_NUMER_P(r); +} + + +mp_result mp_rat_denom(mp_rat r, mp_int z) +{ + return mp_int_copy(MP_DENOM_P(r), z); +} + +mp_int mp_rat_denom_ref(mp_rat r) +{ + return MP_DENOM_P(r); +} + +mp_sign mp_rat_sign(mp_rat r) +{ + return MP_SIGN(MP_NUMER_P(r)); +} + +mp_result mp_rat_copy(mp_rat a, mp_rat c) +{ + mp_result res; + + if ((res = mp_int_copy(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK) + return res; + + res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c)); + return res; +} + +void mp_rat_zero(mp_rat r) +{ + mp_int_zero(MP_NUMER_P(r)); + mp_int_set_value(MP_DENOM_P(r), 1); + +} + +mp_result mp_rat_abs(mp_rat a, mp_rat c) +{ + mp_result res; + + if ((res = mp_int_abs(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK) + return res; + + res = mp_int_abs(MP_DENOM_P(a), MP_DENOM_P(c)); + return res; +} + +mp_result mp_rat_neg(mp_rat a, mp_rat c) +{ + mp_result res; + + if ((res = mp_int_neg(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK) + return res; + + res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c)); + return res; +} + +mp_result mp_rat_recip(mp_rat a, mp_rat c) +{ + mp_result res; + + if (mp_rat_compare_zero(a) == 0) + return MP_UNDEF; + + if ((res = mp_rat_copy(a, c)) != MP_OK) + return res; + + mp_int_swap(MP_NUMER_P(c), MP_DENOM_P(c)); + + /* Restore the signs of the swapped elements */ + { + mp_sign tmp = MP_SIGN(MP_NUMER_P(c)); + + MP_SIGN(MP_NUMER_P(c)) = MP_SIGN(MP_DENOM_P(c)); + MP_SIGN(MP_DENOM_P(c)) = tmp; + } + + return MP_OK; +} + +mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c) +{ + return s_rat_combine(a, b, c, mp_int_add); + +} + +mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c) +{ + return s_rat_combine(a, b, c, mp_int_sub); + +} + +mp_result mp_rat_mul(mp_rat a, mp_rat b, mp_rat c) +{ + mp_result res; + + if ((res = mp_int_mul(MP_NUMER_P(a), MP_NUMER_P(b), MP_NUMER_P(c))) != MP_OK) + return res; + + if (mp_int_compare_zero(MP_NUMER_P(c)) != 0) { + if ((res = mp_int_mul(MP_DENOM_P(a), MP_DENOM_P(b), MP_DENOM_P(c))) != MP_OK) + return res; + } + + return s_rat_reduce(c); +} + +mp_result mp_rat_div(mp_rat a, mp_rat b, mp_rat c) +{ + mp_result res = MP_OK; + + if (mp_rat_compare_zero(b) == 0) + return MP_UNDEF; + + if (c == a || c == b) { + mpz_t tmp; + + if ((res = mp_int_init(&tmp)) != MP_OK) return res; + if ((res = mp_int_mul(MP_NUMER_P(a), MP_DENOM_P(b), &tmp)) != MP_OK) + goto CLEANUP; + if ((res = mp_int_mul(MP_DENOM_P(a), MP_NUMER_P(b), MP_DENOM_P(c))) != MP_OK) + goto CLEANUP; + res = mp_int_copy(&tmp, MP_NUMER_P(c)); + + CLEANUP: + mp_int_clear(&tmp); + } + else { + if ((res = mp_int_mul(MP_NUMER_P(a), MP_DENOM_P(b), MP_NUMER_P(c))) != MP_OK) + return res; + if ((res = mp_int_mul(MP_DENOM_P(a), MP_NUMER_P(b), MP_DENOM_P(c))) != MP_OK) + return res; + } + + if (res != MP_OK) + return res; + else + return s_rat_reduce(c); +} + +mp_result mp_rat_add_int(mp_rat a, mp_int b, mp_rat c) +{ + mpz_t tmp; + mp_result res; + + if ((res = mp_int_init_copy(&tmp, b)) != MP_OK) + return res; + + if ((res = mp_int_mul(&tmp, MP_DENOM_P(a), &tmp)) != MP_OK) + goto CLEANUP; + + if ((res = mp_rat_copy(a, c)) != MP_OK) + goto CLEANUP; + + if ((res = mp_int_add(MP_NUMER_P(c), &tmp, MP_NUMER_P(c))) != MP_OK) + goto CLEANUP; + + res = s_rat_reduce(c); + + CLEANUP: + mp_int_clear(&tmp); + return res; +} + +mp_result mp_rat_sub_int(mp_rat a, mp_int b, mp_rat c) +{ + mpz_t tmp; + mp_result res; + + if ((res = mp_int_init_copy(&tmp, b)) != MP_OK) + return res; + + if ((res = mp_int_mul(&tmp, MP_DENOM_P(a), &tmp)) != MP_OK) + goto CLEANUP; + + if ((res = mp_rat_copy(a, c)) != MP_OK) + goto CLEANUP; + + if ((res = mp_int_sub(MP_NUMER_P(c), &tmp, MP_NUMER_P(c))) != MP_OK) + goto CLEANUP; + + res = s_rat_reduce(c); + + CLEANUP: + mp_int_clear(&tmp); + return res; +} + +mp_result mp_rat_mul_int(mp_rat a, mp_int b, mp_rat c) +{ + mp_result res; + + if ((res = mp_rat_copy(a, c)) != MP_OK) + return res; + + if ((res = mp_int_mul(MP_NUMER_P(c), b, MP_NUMER_P(c))) != MP_OK) + return res; + + return s_rat_reduce(c); +} + +mp_result mp_rat_div_int(mp_rat a, mp_int b, mp_rat c) +{ + mp_result res; + + if (mp_int_compare_zero(b) == 0) + return MP_UNDEF; + + if ((res = mp_rat_copy(a, c)) != MP_OK) + return res; + + if ((res = mp_int_mul(MP_DENOM_P(c), b, MP_DENOM_P(c))) != MP_OK) + return res; + + return s_rat_reduce(c); +} + +mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c) +{ + mp_result res; + + /* Special cases for easy powers. */ + if (b == 0) + return mp_rat_set_value(c, 1, 1); + else if(b == 1) + return mp_rat_copy(a, c); + + /* Since rationals are always stored in lowest terms, it is not necessary to + reduce again when raising to an integer power. */ + if ((res = mp_int_expt(MP_NUMER_P(a), b, MP_NUMER_P(c))) != MP_OK) + return res; + + return mp_int_expt(MP_DENOM_P(a), b, MP_DENOM_P(c)); +} + +int mp_rat_compare(mp_rat a, mp_rat b) +{ + /* Quick check for opposite signs. Works because the sign of the numerator + is always definitive. */ + if (MP_SIGN(MP_NUMER_P(a)) != MP_SIGN(MP_NUMER_P(b))) { + if (MP_SIGN(MP_NUMER_P(a)) == MP_ZPOS) + return 1; + else + return -1; + } + else { + /* Compare absolute magnitudes; if both are positive, the answer stands, + otherwise it needs to be reflected about zero. */ + int cmp = mp_rat_compare_unsigned(a, b); + + if (MP_SIGN(MP_NUMER_P(a)) == MP_ZPOS) + return cmp; + else + return -cmp; + } +} + +int mp_rat_compare_unsigned(mp_rat a, mp_rat b) +{ + /* If the denominators are equal, we can quickly compare numerators without + multiplying. Otherwise, we actually have to do some work. */ + if (mp_int_compare_unsigned(MP_DENOM_P(a), MP_DENOM_P(b)) == 0) + return mp_int_compare_unsigned(MP_NUMER_P(a), MP_NUMER_P(b)); + + else { + mpz_t temp[2]; + mp_result res; + int cmp = INT_MAX, last = 0; + + /* t0 = num(a) * den(b), t1 = num(b) * den(a) */ + SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(a)), last); + SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(b)), last); + + if ((res = mp_int_mul(TEMP(0), MP_DENOM_P(b), TEMP(0))) != MP_OK || + (res = mp_int_mul(TEMP(1), MP_DENOM_P(a), TEMP(1))) != MP_OK) + goto CLEANUP; + + cmp = mp_int_compare_unsigned(TEMP(0), TEMP(1)); + + CLEANUP: + while (--last >= 0) + mp_int_clear(TEMP(last)); + + return cmp; + } +} + +int mp_rat_compare_zero(mp_rat r) +{ + return mp_int_compare_zero(MP_NUMER_P(r)); +} + +int mp_rat_compare_value(mp_rat r, mp_small n, mp_small d) +{ + mpq_t tmp; + mp_result res; + int out = INT_MAX; + + if ((res = mp_rat_init(&tmp)) != MP_OK) + return out; + if ((res = mp_rat_set_value(&tmp, n, d)) != MP_OK) + goto CLEANUP; + + out = mp_rat_compare(r, &tmp); + + CLEANUP: + mp_rat_clear(&tmp); + return out; +} + +int mp_rat_is_integer(mp_rat r) +{ + return (mp_int_compare_value(MP_DENOM_P(r), 1) == 0); +} + +mp_result mp_rat_to_ints(mp_rat r, mp_small *num, mp_small *den) +{ + mp_result res; + + if ((res = mp_int_to_int(MP_NUMER_P(r), num)) != MP_OK) + return res; + + res = mp_int_to_int(MP_DENOM_P(r), den); + return res; +} + +mp_result mp_rat_to_string(mp_rat r, mp_size radix, char *str, int limit) +{ + char *start; + int len; + mp_result res; + + /* Write the numerator. The sign of the rational number is written by the + underlying integer implementation. */ + if ((res = mp_int_to_string(MP_NUMER_P(r), radix, str, limit)) != MP_OK) + return res; + + /* If the value is zero, don't bother writing any denominator */ + if (mp_int_compare_zero(MP_NUMER_P(r)) == 0) + return MP_OK; + + /* Locate the end of the numerator, and make sure we are not going to exceed + the limit by writing a slash. */ + len = strlen(str); + start = str + len; + limit -= len; + if(limit == 0) + return MP_TRUNC; + + *start++ = '/'; + limit -= 1; + + res = mp_int_to_string(MP_DENOM_P(r), radix, start, limit); + return res; +} + +mp_result mp_rat_to_decimal(mp_rat r, mp_size radix, mp_size prec, + mp_round_mode round, char *str, int limit) +{ + mpz_t temp[3]; + mp_result res; + char *start = str; + int len, lead_0, left = limit, last = 0; + + SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(r)), last); + SETUP(mp_int_init(TEMP(last)), last); + SETUP(mp_int_init(TEMP(last)), last); + + /* Get the unsigned integer part by dividing denominator into the absolute + value of the numerator. */ + mp_int_abs(TEMP(0), TEMP(0)); + if ((res = mp_int_div(TEMP(0), MP_DENOM_P(r), TEMP(0), TEMP(1))) != MP_OK) + goto CLEANUP; + + /* Now: T0 = integer portion, unsigned; + T1 = remainder, from which fractional part is computed. */ + + /* Count up leading zeroes after the radix point. */ + for (lead_0 = 0; lead_0 < prec && mp_int_compare(TEMP(1), MP_DENOM_P(r)) < 0; + ++lead_0) { + if ((res = mp_int_mul_value(TEMP(1), radix, TEMP(1))) != MP_OK) + goto CLEANUP; + } + + /* Multiply remainder by a power of the radix sufficient to get the right + number of significant figures. */ + if (prec > lead_0) { + if ((res = mp_int_expt_value(radix, prec - lead_0, TEMP(2))) != MP_OK) + goto CLEANUP; + if ((res = mp_int_mul(TEMP(1), TEMP(2), TEMP(1))) != MP_OK) + goto CLEANUP; + } + if ((res = mp_int_div(TEMP(1), MP_DENOM_P(r), TEMP(1), TEMP(2))) != MP_OK) + goto CLEANUP; + + /* Now: T1 = significant digits of fractional part; + T2 = leftovers, to use for rounding. + + At this point, what we do depends on the rounding mode. The default is + MP_ROUND_DOWN, for which everything is as it should be already. + */ + switch (round) { + int cmp; + + case MP_ROUND_UP: + if (mp_int_compare_zero(TEMP(2)) != 0) { + if (prec == 0) + res = mp_int_add_value(TEMP(0), 1, TEMP(0)); + else + res = mp_int_add_value(TEMP(1), 1, TEMP(1)); + } + break; + + case MP_ROUND_HALF_UP: + case MP_ROUND_HALF_DOWN: + if ((res = mp_int_mul_pow2(TEMP(2), 1, TEMP(2))) != MP_OK) + goto CLEANUP; + + cmp = mp_int_compare(TEMP(2), MP_DENOM_P(r)); + + if (round == MP_ROUND_HALF_UP) + cmp += 1; + + if (cmp > 0) { + if (prec == 0) + res = mp_int_add_value(TEMP(0), 1, TEMP(0)); + else + res = mp_int_add_value(TEMP(1), 1, TEMP(1)); + } + break; + + case MP_ROUND_DOWN: + break; /* No action required */ + + default: + return MP_BADARG; /* Invalid rounding specifier */ + } + + /* The sign of the output should be the sign of the numerator, but if all the + displayed digits will be zero due to the precision, a negative shouldn't + be shown. */ + if (MP_SIGN(MP_NUMER_P(r)) == MP_NEG && + (mp_int_compare_zero(TEMP(0)) != 0 || + mp_int_compare_zero(TEMP(1)) != 0)) { + *start++ = '-'; + left -= 1; + } + + if ((res = mp_int_to_string(TEMP(0), radix, start, left)) != MP_OK) + goto CLEANUP; + + len = strlen(start); + start += len; + left -= len; + + if (prec == 0) + goto CLEANUP; + + *start++ = '.'; + left -= 1; + + if (left < prec + 1) { + res = MP_TRUNC; + goto CLEANUP; + } + + memset(start, '0', lead_0 - 1); + left -= lead_0; + start += lead_0 - 1; + + res = mp_int_to_string(TEMP(1), radix, start, left); + + CLEANUP: + while (--last >= 0) + mp_int_clear(TEMP(last)); + + return res; +} + +mp_result mp_rat_string_len(mp_rat r, mp_size radix) +{ + mp_result n_len, d_len = 0; + + n_len = mp_int_string_len(MP_NUMER_P(r), radix); + + if (mp_int_compare_zero(MP_NUMER_P(r)) != 0) + d_len = mp_int_string_len(MP_DENOM_P(r), radix); + + /* Though simplistic, this formula is correct. Space for the sign flag is + included in n_len, and the space for the NUL that is counted in n_len + counts for the separator here. The space for the NUL counted in d_len + counts for the final terminator here. */ + + return n_len + d_len; + +} + +mp_result mp_rat_decimal_len(mp_rat r, mp_size radix, mp_size prec) +{ + int z_len, f_len; + + z_len = mp_int_string_len(MP_NUMER_P(r), radix); + + if (prec == 0) + f_len = 1; /* terminator only */ + else + f_len = 1 + prec + 1; /* decimal point, digits, terminator */ + + return z_len + f_len; +} + +mp_result mp_rat_read_string(mp_rat r, mp_size radix, const char *str) +{ + return mp_rat_read_cstring(r, radix, str, NULL); +} + +mp_result mp_rat_read_cstring(mp_rat r, mp_size radix, const char *str, + char **end) +{ + mp_result res; + char *endp; + + if ((res = mp_int_read_cstring(MP_NUMER_P(r), radix, str, &endp)) != MP_OK && + (res != MP_TRUNC)) + return res; + + /* Skip whitespace between numerator and (possible) separator */ + while (isspace((unsigned char) *endp)) + ++endp; + + /* If there is no separator, we will stop reading at this point. */ + if (*endp != '/') { + mp_int_set_value(MP_DENOM_P(r), 1); + if (end != NULL) + *end = endp; + return res; + } + + ++endp; /* skip separator */ + if ((res = mp_int_read_cstring(MP_DENOM_P(r), radix, endp, end)) != MP_OK) + return res; + + /* Make sure the value is well-defined */ + if (mp_int_compare_zero(MP_DENOM_P(r)) == 0) + return MP_UNDEF; + + /* Reduce to lowest terms */ + return s_rat_reduce(r); +} + +/* Read a string and figure out what format it's in. The radix may be supplied + as zero to use "default" behaviour. + + This function will accept either a/b notation or decimal notation. + */ +mp_result mp_rat_read_ustring(mp_rat r, mp_size radix, const char *str, + char **end) +{ + char *endp; + mp_result res; + + if (radix == 0) + radix = 10; /* default to decimal input */ + + if ((res = mp_rat_read_cstring(r, radix, str, &endp)) != MP_OK) { + if (res == MP_TRUNC) { + if (*endp == '.') + res = mp_rat_read_cdecimal(r, radix, str, &endp); + } + else + return res; + } + + if (end != NULL) + *end = endp; + + return res; +} + +mp_result mp_rat_read_decimal(mp_rat r, mp_size radix, const char *str) +{ + return mp_rat_read_cdecimal(r, radix, str, NULL); +} + +mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, const char *str, + char **end) +{ + mp_result res; + mp_sign osign; + char *endp; + + while (isspace((unsigned char) *str)) + ++str; + + switch (*str) { + case '-': + osign = MP_NEG; + break; + default: + osign = MP_ZPOS; + } + + if ((res = mp_int_read_cstring(MP_NUMER_P(r), radix, str, &endp)) != MP_OK && + (res != MP_TRUNC)) + return res; + + /* This needs to be here. */ + (void) mp_int_set_value(MP_DENOM_P(r), 1); + + if (*endp != '.') { + if (end != NULL) + *end = endp; + return res; + } + + /* If the character following the decimal point is whitespace or a sign flag, + we will consider this a truncated value. This special case is because + mp_int_read_string() will consider whitespace or sign flags to be valid + starting characters for a value, and we do not want them following the + decimal point. + + Once we have done this check, it is safe to read in the value of the + fractional piece as a regular old integer. + */ + ++endp; + if (*endp == '\0') { + if (end != NULL) + *end = endp; + return MP_OK; + } + else if(isspace((unsigned char) *endp) || *endp == '-' || *endp == '+') { + return MP_TRUNC; + } + else { + mpz_t frac; + mp_result save_res; + char *save = endp; + int num_lz = 0; + + /* Make a temporary to hold the part after the decimal point. */ + if ((res = mp_int_init(&frac)) != MP_OK) + return res; + + if ((res = mp_int_read_cstring(&frac, radix, endp, &endp)) != MP_OK && + (res != MP_TRUNC)) + goto CLEANUP; + + /* Save this response for later. */ + save_res = res; + + if (mp_int_compare_zero(&frac) == 0) + goto FINISHED; + + /* Discard trailing zeroes (somewhat inefficiently) */ + while (mp_int_divisible_value(&frac, radix)) + if ((res = mp_int_div_value(&frac, radix, &frac, NULL)) != MP_OK) + goto CLEANUP; + + /* Count leading zeros after the decimal point */ + while (save[num_lz] == '0') + ++num_lz; + + /* Find the least power of the radix that is at least as large as the + significant value of the fractional part, ignoring leading zeroes. */ + (void) mp_int_set_value(MP_DENOM_P(r), radix); + + while (mp_int_compare(MP_DENOM_P(r), &frac) < 0) { + if ((res = mp_int_mul_value(MP_DENOM_P(r), radix, MP_DENOM_P(r))) != MP_OK) + goto CLEANUP; + } + + /* Also shift by enough to account for leading zeroes */ + while (num_lz > 0) { + if ((res = mp_int_mul_value(MP_DENOM_P(r), radix, MP_DENOM_P(r))) != MP_OK) + goto CLEANUP; + + --num_lz; + } + + /* Having found this power, shift the numerator leftward that many, digits, + and add the nonzero significant digits of the fractional part to get the + result. */ + if ((res = mp_int_mul(MP_NUMER_P(r), MP_DENOM_P(r), MP_NUMER_P(r))) != MP_OK) + goto CLEANUP; + + { /* This addition needs to be unsigned. */ + MP_SIGN(MP_NUMER_P(r)) = MP_ZPOS; + if ((res = mp_int_add(MP_NUMER_P(r), &frac, MP_NUMER_P(r))) != MP_OK) + goto CLEANUP; + + MP_SIGN(MP_NUMER_P(r)) = osign; + } + if ((res = s_rat_reduce(r)) != MP_OK) + goto CLEANUP; + + /* At this point, what we return depends on whether reading the fractional + part was truncated or not. That information is saved from when we + called mp_int_read_string() above. */ + FINISHED: + res = save_res; + if (end != NULL) + *end = endp; + + CLEANUP: + mp_int_clear(&frac); + + return res; + } +} + +/* Private functions for internal use. Make unchecked assumptions about format + and validity of inputs. */ + +static mp_result s_rat_reduce(mp_rat r) +{ + mpz_t gcd; + mp_result res = MP_OK; + + if (mp_int_compare_zero(MP_NUMER_P(r)) == 0) { + mp_int_set_value(MP_DENOM_P(r), 1); + return MP_OK; + } + + /* If the greatest common divisor of the numerator and denominator is greater + than 1, divide it out. */ + if ((res = mp_int_init(&gcd)) != MP_OK) + return res; + + if ((res = mp_int_gcd(MP_NUMER_P(r), MP_DENOM_P(r), &gcd)) != MP_OK) + goto CLEANUP; + + if (mp_int_compare_value(&gcd, 1) != 0) { + if ((res = mp_int_div(MP_NUMER_P(r), &gcd, MP_NUMER_P(r), NULL)) != MP_OK) + goto CLEANUP; + if ((res = mp_int_div(MP_DENOM_P(r), &gcd, MP_DENOM_P(r), NULL)) != MP_OK) + goto CLEANUP; + } + + /* Fix up the signs of numerator and denominator */ + if (MP_SIGN(MP_NUMER_P(r)) == MP_SIGN(MP_DENOM_P(r))) + MP_SIGN(MP_NUMER_P(r)) = MP_SIGN(MP_DENOM_P(r)) = MP_ZPOS; + else { + MP_SIGN(MP_NUMER_P(r)) = MP_NEG; + MP_SIGN(MP_DENOM_P(r)) = MP_ZPOS; + } + + CLEANUP: + mp_int_clear(&gcd); + + return res; +} + +static mp_result s_rat_combine(mp_rat a, mp_rat b, mp_rat c, + mp_result (*comb_f)(mp_int, mp_int, mp_int)) +{ + mp_result res; + + /* Shortcut when denominators are already common */ + if (mp_int_compare(MP_DENOM_P(a), MP_DENOM_P(b)) == 0) { + if ((res = (comb_f)(MP_NUMER_P(a), MP_NUMER_P(b), MP_NUMER_P(c))) != MP_OK) + return res; + if ((res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c))) != MP_OK) + return res; + + return s_rat_reduce(c); + } + else { + mpz_t temp[2]; + int last = 0; + + SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(a)), last); + SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(b)), last); + + if ((res = mp_int_mul(TEMP(0), MP_DENOM_P(b), TEMP(0))) != MP_OK) + goto CLEANUP; + if ((res = mp_int_mul(TEMP(1), MP_DENOM_P(a), TEMP(1))) != MP_OK) + goto CLEANUP; + if ((res = (comb_f)(TEMP(0), TEMP(1), MP_NUMER_P(c))) != MP_OK) + goto CLEANUP; + + res = mp_int_mul(MP_DENOM_P(a), MP_DENOM_P(b), MP_DENOM_P(c)); + + CLEANUP: + while (--last >= 0) + mp_int_clear(TEMP(last)); + + if (res == MP_OK) + return s_rat_reduce(c); + else + return res; + } +} + +/* Here there be dragons */ Index: contrib/isl/imath/imtest.c =================================================================== --- /dev/null +++ contrib/isl/imath/imtest.c @@ -0,0 +1,430 @@ +/* + Name: imtest.c + Purpose: Test driver for imath library. + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + Reads tests from input files or standard input, and runs them. Tests have + the form: + + code:inputs:outputs + + The 'code' is a string identifying the test to be performed. The inputs and + outputs are comma-separated sequences of values. The format of each input + is: + + 1005 number in decimal notation (signs ok) + #x-C0E number in hexadecimal notation + #b1011 number in binary notation + #o37750 number in octal notation + =k use register k for this input + + For rational tests, the following syntax is also legal: + @5.33 use decimal notation (for rationals only) + may be combined with radix notation, e.g. #x@A0.5C + + Each output is a string representing the value to which the corresponding + result is compared in order to pass the test. By default, tests are expected + to succeed (i.e., return MP_OK). To specify an alternate return value, use + the notation $RESULT, where RESULT is the name of an error (e.g., MP_MEMORY, + MP_UNDEF, etc.) or a numeric result denoted $#number (e.g., $#-5). + + Results are written to standard output in the following formats: + + linenumberresult + linenumberresultmessage + + The number is the number of the test in the input (starting from 1). The + result is a textual description of the result code returned by the operation + being tested. + + Note: There is currently a fixed limit on the length of lines by this test + ---- driver. You can increase it if you wish, but the code doesn't check; + lines over the length are truncated (split). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imath.h" +#include "imdrover.h" + +#ifdef LINE_MAX +#undef LINE_MAX +#endif + +#define LINE_MAX 4096 + +typedef struct { + char *code; + int num_inputs; + int num_outputs; + test_f call; +} test_t; + +test_t g_tests[] = { /* What it does... */ + { "initu", 2, 1, test_init}, /* r0 = uv(r1) */ + { "initv", 2, 1, test_init}, /* r0 = v(r1) */ + { "setu", 2, 1, test_set}, /* r0 = uv(r1) */ + { "setv", 2, 1, test_set}, /* r0 = v(r1) */ + { "neg", 2, 1, test_neg }, /* r1 = -r0 */ + { "abs", 2, 1, test_abs }, /* r1 = |r0| */ + { "add", 3, 1, test_add }, /* r3 = r1 + r2 */ + { "addv", 3, 1, test_add }, /* r3 = r1 + v(r2) */ + { "sub", 3, 1, test_sub }, /* r3 = r1 - r2 */ + { "subv", 3, 1, test_sub }, /* r3 = r1 - v(r2) */ + { "mul", 3, 1, test_mul }, /* r3 = r1 * r2 */ + { "mulp2", 3, 1, test_mulp2 }, /* r3 = r1 * 2^v(r2) */ + { "mulv", 3, 1, test_mulv }, /* r3 = r1 * v(r2) */ + { "sqr", 2, 1, test_sqr }, /* r2 = r1 * r1 */ + { "div", 4, 2, test_div }, /* r2 = r1 / r2, r3 = r1 % r2 */ + { "divp2", 4, 2, test_divp2 }, /* r2 = r1 / 2^v(r2),r3 = r1 % 2^v(r2)*/ + { "divv", 3, 2, test_divv }, /* r2 = r1 / v(r2), r3 = r1 % v(r2) */ + { "expt", 3, 1, test_expt }, /* r3 = r1 ^ v(r2) */ + { "exptv", 3, 1, test_exptv }, /* r3 = v(r1) ^ v(r2) */ + { "exptf", 3, 1, test_exptf }, /* r3 = r1 ^ r2 */ + { "mod", 3, 1, test_mod }, /* r3 = r1 % r2 */ + { "gcd", 3, 1, test_gcd }, /* r3 = gcd(r1, r2) */ + { "egcd", 5, 3, test_egcd }, /* r3 = gcd(r1, r2) = r1*r4 + r2*r5 */ + { "lcm", 3, 1, test_lcm }, /* r3 = lcm(r1, r2) */ + { "sqrt", 2, 1, test_sqrt }, /* r2 = sqrt(r1) */ + { "root", 3, 1, test_root }, /* r3 = r1^(1/v(r2)) */ + { "invmod", 3, 1, test_invmod }, /* r3 = r1^-1 mod r2 */ + { "emod", 4, 1, test_exptmod }, /* r4 = r1^r2 mod r3 */ + { "emodev", 4, 1, test_exptmod_ev }, /* r4 = r1^v(r2) mod r3 */ + { "emodbv", 4, 1, test_exptmod_bv }, /* r4 = v(r1)^r2 mod r3 */ + { "cmp", 2, 1, test_comp }, /* rtn = compare(r1, r2) */ + { "cmpu", 2, 1, test_ucomp }, /* rtn = compare(|r1|, |r2|) */ + { "cmpz", 1, 1, test_zcomp }, /* rtn = compare(r1, 0) */ + { "cmpv", 2, 1, test_vcomp }, /* rtn = compare(r1, v(r2)) */ + { "cmpuv", 2, 1, test_uvcomp }, /* rtn = compare(r1, v(r2)) */ + { "tostr", 2, 1, test_tostr }, /* r1: value, r2: radix, o1: result */ + { "tobin", 1, 1, test_tobin }, /* r1: value, o1: result binary */ + { "readbin", 1, 1, test_read_binary },/* r1: 2's comp, o1: result value */ + { "to-uns", 1, 1, test_to_uns }, /* r1: value, o1: result binary */ + { "readuns", 1, 1, test_read_uns }, /* r1: unsigned, o1: result value */ + { "to-int", 1, 1, test_to_int }, /* r1: value, o1: result */ + { "to-uint", 1, 1, test_to_uint }, /* r1: value, o1: result */ + { "meta", -1, -1, test_meta }, + { "qneg", 2, 1, test_qneg }, /* r2 = -r1 */ + { "qrecip", 2, 1, test_qrecip }, /* r2 = 1 / r1 */ + { "qabs", 2, 1, test_qabs }, /* r2 = |r1| */ + { "qadd", 3, 1, test_qadd }, /* r3 = r1 + r2 */ + { "qsub", 3, 1, test_qsub }, /* r3 = r1 - r2 */ + { "qmul", 3, 1, test_qmul }, /* r3 = r1 * r2 */ + { "qdiv", 3, 1, test_qdiv }, /* r3 = r1 / r2 */ + { "qaddz", 3, 1, test_qaddz }, /* r3 = r1 + r2 */ + { "qsubz", 3, 1, test_qsubz }, /* r3 = r1 - r2 */ + { "qmulz", 3, 1, test_qmulz }, /* r3 = r1 * r2 */ + { "qdivz", 3, 1, test_qdivz }, /* r3 = r1 / r2 */ + { "qexpt", 3, 1, test_qexpt }, /* r3 = r1 ^ v(r2) */ + { "qtostr", 2, 1, test_qtostr }, /* r1: value, r2: radix; o1: result */ + { "qtodec", 4, 1, test_qtodec }, /* r1: val, r2: rdx, r3: prec, + r4: rounding mode; o1: res */ + { "qrdec", 2, 1, test_qrdec }, /* r1: dec, r2: rdx; o1: result value */ + { NULL, 0, 0, NULL } /* end of list marker */ +}; + +char g_line[LINE_MAX]; + +extern mp_result imath_errno; +extern char *imath_errmsg; + +const char *g_imath_strerr[] = { + "MP_OK", "MP_TRUE", "MP_MEMORY", "MP_RANGE", + "MP_UNDEF", "MP_TRUNC", "MP_BADARG" +}; + +int process_file(FILE *ifp, FILE *ofp); +int read_line(FILE *ifp, char *line, int limit); +void trim_line(char *line); +int is_blank(char *line); +int parse_line(char *line, testspec_t *t); +int count_fields(char *line, int delim); +void parse_fields(char *line, int delim, char **start); +int run_test(int test_num, testspec_t *t, FILE *ofp); +void free_test(testspec_t *t); +int find_test(char *code, test_t *info); +char *error_string(mp_result res); + +int main(int argc, char *argv[]) +{ + int exit_status = 0; + + init_testing(); + + if (argc == 1) { + process_file(stdin, stdout); + } + else { + FILE *ifp; + int i; + + for (i = 1; i < argc; ++i) { + if (strcmp(argv[i], "-") == 0) { + ifp = stdin; + printf("# [stdin]\n"); + } + else if ((ifp = fopen(argv[i], "r")) == NULL) { + fprintf(stderr, "Cannot open '%s': %s\n", + argv[i], strerror(errno)); + return 1; + } + else { + printf("# %s\n", argv[i]); + } + + if (process_file(ifp, stdout) != 0) + exit_status = 1; + + fclose(ifp); + } + } + return exit_status; +} + +int process_file(FILE *ifp, FILE *ofp) +{ + int res, line_num, test_num = 0, num_failed = 0, num_bogus = 0; + clock_t start, finish; + testspec_t t; + + start = clock(); + while ((line_num = read_line(ifp, g_line, LINE_MAX)) != 0) { + if (parse_line(g_line, &t)) { + t.line = line_num; + if ((res = run_test(++test_num, &t, ofp)) < 0) + ++num_bogus; + else if (!res) + ++num_failed; + + free_test(&t); + } + else { + fprintf(stderr, "Line %d: Incorrect input syntax.\n", line_num); + } + } + finish = clock(); + + fprintf(ofp, "# %d tests: %d passed, %d failed, %d errors. (%.2f seconds)\n", + test_num, (test_num - num_failed - num_bogus), num_failed, num_bogus, + ((double)(finish - start) / CLOCKS_PER_SEC)); + + return num_failed; +} + +int read_line(FILE *ifp, char *line, int limit) +{ + static FILE *current_fp = NULL; + static int current_line = 0; + + if (ifp != current_fp) { + current_fp = ifp; + current_line = 0; + } + + do { + if (fgets(line, limit, ifp) == NULL) + return 0; + + ++current_line; + } while (is_blank(line)); + + trim_line(line); + return current_line; +} + +void trim_line(char *line) +{ + int len; + char *fnw = line; + + /* Remove leading whitespace */ + while (isspace((unsigned char) *fnw)) + ++fnw; + + len = strlen(fnw); + memmove(line, fnw, len); + + /* Remove trailing whitespace (including linefeeds) */ + fnw = line + len - 1; + while (fnw >= line && isspace((unsigned char) *fnw)) + *fnw-- = '\0'; +} + +int is_blank(char *line) +{ + while (*line && *line != '#' && isspace((unsigned char) *line)) + ++line; + + return *line == '\0' || *line == '#'; +} + +int parse_line(char *line, testspec_t *t) +{ + char *code_brk, *in_brk; + int num_fields; + + if ((code_brk = strchr(line, ':')) == NULL) + return 0; + if ((in_brk = strchr(code_brk + 1, ':')) == NULL) + return 0; + + *code_brk = '\0'; + t->code = line; + *in_brk = '\0'; + + num_fields = count_fields(code_brk + 1, ','); + t->num_inputs = num_fields; + + num_fields = count_fields(in_brk + 1, ','); + t->num_outputs = num_fields; + + if (t->num_inputs > 0) { + t->input = calloc(t->num_inputs, sizeof(char *)); + parse_fields(code_brk + 1, ',', t->input); + } + if (t->num_outputs > 0) { + t->output = calloc(t->num_outputs, sizeof(char *)); + parse_fields(in_brk + 1, ',', t->output); + } + return 1; +} + +int count_fields(char *line, int delim) +{ + int count = 1; + + if (*line == '\0') + return 0; + + while (*line) { + if (*line == (char)delim && *(line+1) != '\0') + ++count; + ++line; + } + return count; +} + +void parse_fields(char *line, int delim, char **start) +{ + int pos = 0; + + start[pos++] = line; + while ((line = strchr(line, delim)) != NULL) { + *line++ = '\0'; + start[pos++] = line; + } +} + +int run_test(int test_num, testspec_t *t, FILE *ofp) +{ + test_t info; + + /* Look up and reality check test parameters */ + if (find_test(t->code, &info) < 0) { + fprintf(stderr, "Line %d: Test code '%s' is unknown.\n", + t->line, t->code); + return -1; + } + else { + int errs = 0; + + if (info.num_inputs >= 0 && t->num_inputs != info.num_inputs) { + fprintf(stderr, + "Line %d: Wrong number of inputs to %s (want %d, have %d)\n", + t->line, t->code, info.num_inputs, t->num_inputs); + ++errs; + } + if (info.num_outputs >= 0 && t->num_outputs != info.num_outputs) { + fprintf(stderr, + "Line %d: Wrong number of outputs to %s (want %d, have %d)\n", + t->line, t->code, info.num_outputs, t->num_outputs); + ++errs; + } + if (errs) { + fprintf(stderr, "Line %d: %d error(s), skipping this test.\n", + t->line, errs); + return -1; + } + } + + /* If return value is true, just print a generic OK message; + otherwise, it is assumed that imath_errno has been set to + a value indicating the problem. */ + if ((info.call)(t, ofp)) { + fprintf(ofp, "%d\t%d\tOK\n", t->line, test_num); + return 1; + } + else if(imath_errno >= MP_BADARG) { + fprintf(ofp, "%d\t%d\t%s\n", + t->line, test_num, error_string(imath_errno)); + } + else { + fprintf(ofp, "%d\t%d\tFAILED\t%s\n", + t->line, test_num, imath_errmsg); + } + return 0; +} + +int find_test(char *code, test_t *info) +{ + int i = 0; + + while (g_tests[i].code != NULL) { + if (strcmp(g_tests[i].code, code) == 0) { + *info = g_tests[i]; + return i; + } + ++i; + } + return -1; +} + +void free_test(testspec_t *t) +{ + assert(t != NULL); + + if (t->input != NULL) { + free(t->input); + t->input = NULL; + } + if (t->output != NULL) { + free(t->output); + t->output = NULL; + } +} + +char *error_string(mp_result res) +{ + int v = abs(res); + + return (char *)g_imath_strerr[v]; +} + +/* Here there be dragons */ Index: contrib/isl/imath/imtimer.c =================================================================== --- /dev/null +++ contrib/isl/imath/imtimer.c @@ -0,0 +1,231 @@ +/* + Name: imtimer.c + Purpose: Timing tests for the imath library. + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +#include "imath.h" + +extern mp_size multiply_threshold; /* global in imath.c */ +extern mp_size default_precision; /* global in imath.c */ + +double clocks_to_seconds(clock_t start, clock_t end); +double get_multiply_time(int nt, int prec); +double get_exptmod_time(int nt, int prec); +mp_int alloc_values(int nt, int prec); +void randomize_values(mp_int values, int nt, int prec); +void release_values(mp_int values, int nt); +void mp_int_random(mp_int z, int prec); + +const int g_mul_factor = 1000; + +int main(int argc, char *argv[]) +{ + int do_mul = 0, do_exp = 0, do_header = 1; + int num_tests, precision = default_precision, opt; + unsigned int seed = (unsigned int) time(NULL); + + while ((opt = getopt(argc, argv, "ehmnp:s:t:")) != EOF) { + switch (opt) { + case 'e': + do_exp = 1; + break; + case 'm': + do_mul = 1; + break; + case 'n': + do_header = 0; + break; + case 'p': + precision = atoi(optarg); + break; + case 's': + seed = atoi(optarg); + break; + case 't': + multiply_threshold = (mp_size) atoi(optarg); + break; + default: + fprintf(stderr, "Usage: imtimer [options] \n\n" + "Options understood:\n" + " -e -- test modular exponentiation speed.\n" + " -h -- display this help message.\n" + " -m -- test multiplication speed.\n" + " -n -- no header line.\n" + " -p -- use values with digits.\n" + " -s -- set random seed to .\n" + " -t -- set recursion threshold to digits.\n\n"); + return (opt != 'h'); + } + } + + if (optind >= argc) { + fprintf(stderr, "Usage: imtimer [options] \n" + "[use \"imtimer -h\" for help with options]\n\n"); + return 1; + } + else + num_tests = atoi(argv[optind]); + + srand(seed); + + if (num_tests <= 0) { + fprintf(stderr, "You must request at least one test.\n"); + return 1; + } + if (precision <= 0) { + fprintf(stderr, "Precision must be positive.\n"); + return 1; + } + + if (do_header) + printf("NUM\tPREC\tBITS\tREC\tRESULT\n"); + printf("%d\t%d\t%d\t%u", num_tests, precision, + (int) (precision * MP_DIGIT_BIT), + multiply_threshold); + + if (do_mul) { + double m_time = get_multiply_time(num_tests, precision); + + printf("\tMUL %.3f %.3f", m_time, m_time / num_tests); + } + + if (do_exp) { + double e_time = get_exptmod_time(num_tests, precision); + + printf("\tEXP %.3f %.3f", e_time, e_time / num_tests); + } + fputc('\n', stdout); + fflush(stdout); + + return 0; +} + +double clocks_to_seconds(clock_t start, clock_t end) +{ + return (double)(end - start) / CLOCKS_PER_SEC; +} + +mp_int alloc_values(int nt, int prec) +{ + mp_int out = malloc(nt * sizeof(mpz_t)); + int i; + + if (out == NULL) + return NULL; + + for (i = 0; i < nt; ++i) { + if (mp_int_init_size(out + i, prec) != MP_OK) { + while (--i >= 0) + mp_int_clear(out + i); + return NULL; + } + } + + return out; +} + +void randomize_values(mp_int values, int nt, int prec) +{ + int i; + + for (i = 0; i < nt; ++i) + mp_int_random(values + i, prec); +} + +void release_values(mp_int values, int nt) +{ + int i; + + for (i = 0; i < nt; ++i) + mp_int_clear(values + i); + + free(values); +} + +double get_multiply_time(int nt, int prec) +{ + clock_t start, end; + mp_int values; + int i; + + if ((values = alloc_values(3, prec)) == NULL) + return 0.0; + randomize_values(values, 2, prec); + + start = clock(); + for (i = 0; i < nt; ++i) + mp_int_mul(values, values + 1, values + 2); + end = clock(); + + release_values(values, 3); + + return clocks_to_seconds(start, end); +} + +double get_exptmod_time(int nt, int prec) +{ + clock_t start, end; + mp_int values; + int i; + + if ((values = alloc_values(4, prec)) == NULL) + return 0.0; + randomize_values(values, 3, prec); + + start = clock(); + for (i = 0; i < nt; ++i) + mp_int_exptmod(values, values + 1, values + 2, values + 3); + end = clock(); + + release_values(values, 4); + + return clocks_to_seconds(start, end); +} + +void mp_int_random(mp_int z, int prec) +{ + int i; + + if (prec > MP_ALLOC(z)) + prec = MP_ALLOC(z); + + for (i = 0; i < prec; ++i) { + mp_digit d = 0; + int j; + + for (j = 0; j < sizeof(d); ++j) + d = (d << CHAR_BIT) | (rand() & UCHAR_MAX); + + z->digits[i] = d; + } + MP_USED(z) = prec; +} Index: contrib/isl/imath/iprime.h =================================================================== --- /dev/null +++ contrib/isl/imath/iprime.h @@ -0,0 +1,48 @@ +/* + Name: iprime.h + Purpose: Pseudoprimality testing routines + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#ifndef IPRIME_H_ +#define IPRIME_H_ + +#include "imath.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Test whether z is likely to be prime + MP_YES means it is probably prime + MP_NO means it is definitely composite + */ +mp_result mp_int_is_prime(mp_int z); + +/* Find the first apparent prime in ascending order from z */ +mp_result mp_int_find_prime(mp_int z); + +#ifdef __cplusplus +} +#endif +#endif /* IPRIME_H_ */ Index: contrib/isl/imath/iprime.c =================================================================== --- /dev/null +++ contrib/isl/imath/iprime.c @@ -0,0 +1,108 @@ +/* + Name: iprime.c + Purpose: Pseudoprimality testing routines + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include "iprime.h" +#include + +static int s_ptab_size = 168; +static int s_ptab[] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, + 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, + 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, + 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, + 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, + 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, + 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 +}; + +/* Test whether z is likely to be prime: + MP_TRUE means it is probably prime + MP_FALSE means it is definitely composite + */ +mp_result mp_int_is_prime(mp_int z) +{ + int i; + mp_small rem; + mp_result res; + + /* First check for divisibility by small primes; this eliminates a large + number of composite candidates quickly + */ + for(i = 0; i < s_ptab_size; ++i) { + if((res = mp_int_div_value(z, s_ptab[i], NULL, &rem)) != MP_OK) + return res; + + if(rem == 0) + return MP_FALSE; + } + + /* Now try Fermat's test for several prime witnesses (since we now know from + the above that z is not a multiple of any of them) + */ + { + mpz_t tmp; + + if((res = mp_int_init(&tmp)) != MP_OK) return res; + + for(i = 0; i < 10 && i < s_ptab_size; ++i) { + if((res = mp_int_exptmod_bvalue(s_ptab[i], z, z, &tmp)) != MP_OK) + return res; + + if(mp_int_compare_value(&tmp, s_ptab[i]) != 0) { + mp_int_clear(&tmp); + return MP_FALSE; + } + } + + mp_int_clear(&tmp); + } + + return MP_TRUE; +} + +/* Find the first apparent prime in ascending order from z */ +mp_result mp_int_find_prime(mp_int z) +{ + mp_result res; + + if(mp_int_is_even(z) && ((res = mp_int_add_value(z, 1, z)) != MP_OK)) + return res; + + while((res = mp_int_is_prime(z)) == MP_FALSE) { + if((res = mp_int_add_value(z, 2, z)) != MP_OK) + break; + + } + + return res; +} + +/* Here there be dragons */ Index: contrib/isl/imath/pi.c =================================================================== --- /dev/null +++ contrib/isl/imath/pi.c @@ -0,0 +1,173 @@ +/* + Name: pi.c + Purpose: Computes digits of the physical constant pi. + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Notes: + Uses Machin's formula, which should be suitable for a few thousand digits. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include +#include + +#include "imath.h" + +int g_radix = 10; /* use this radix for output */ + +mp_result arctan(mp_small radix, mp_small mul, mp_small x, + mp_small prec, mp_int sum); + +char g_buf[4096]; + +int main(int argc, char *argv[]) +{ + mp_result res; + mpz_t sum1, sum2; + int ndigits, out = 0; + clock_t start, end; + + if(argc < 2) { + fprintf(stderr, "Usage: %s []\n", argv[0]); + return 1; + } + + if((ndigits = abs(atoi(argv[1]))) == 0) { + fprintf(stderr, "%s: you must request at least 1 digit\n", argv[0]); + return 1; + } else if(ndigits > MP_DIGIT_MAX) { + fprintf(stderr, "%s: you may request at most %u digits\n", + argv[0], (unsigned int)MP_DIGIT_MAX); + return 1; + } + + if(argc > 2) { + int radix = atoi(argv[2]); + + if(radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) { + fprintf(stderr, "%s: you may only specify a radix between %d and %d\n", + argv[0], MP_MIN_RADIX, MP_MAX_RADIX); + return 1; + } + g_radix = radix; + } + + mp_int_init(&sum1); mp_int_init(&sum2); + start = clock(); + + /* sum1 = 16 * arctan(1/5) */ + if((res = arctan(g_radix, 16, 5, ndigits, &sum1)) != MP_OK) { + fprintf(stderr, "%s: error computing arctan: %d\n", argv[0], res); + out = 1; goto CLEANUP; + } + + /* sum2 = 4 * arctan(1/239) */ + if((res = arctan(g_radix, 4, 239, ndigits, &sum2)) != MP_OK) { + fprintf(stderr, "%s: error computing arctan: %d\n", argv[0], res); + out = 1; goto CLEANUP; + } + + /* pi = sum1 - sum2 */ + if((res = mp_int_sub(&sum1, &sum2, &sum1)) != MP_OK) { + fprintf(stderr, "%s: error computing pi: %d\n", argv[0], res); + out = 1; goto CLEANUP; + } + end = clock(); + + mp_int_to_string(&sum1, g_radix, g_buf, sizeof(g_buf)); + printf("%c.%s\n", g_buf[0], g_buf + 1); + + fprintf(stderr, "Computation took %.2f sec.\n", + (double)(end - start) / CLOCKS_PER_SEC); + + CLEANUP: + mp_int_clear(&sum1); + mp_int_clear(&sum2); + + return out; +} + +/* + Compute mul * atan(1/x) to prec digits of precision, and store the + result in sum. + + Computes atan(1/x) using the formula: + + 1 1 1 1 + atan(1/x) = --- - ---- + ---- - ---- + ... + x 3x^3 5x^5 7x^7 + + */ +mp_result arctan(mp_small radix, mp_small mul, mp_small x, + mp_small prec, mp_int sum) +{ + mpz_t t, v; + mp_result res; + mp_small rem, sign = 1, coeff = 1; + + mp_int_init(&t); + mp_int_init(&v); + ++prec; + + /* Compute mul * radix^prec * x + The initial multiplication by x saves a special case in the loop for + the first term of the series. + */ + if((res = mp_int_expt_value(radix, prec, &t)) != MP_OK || + (res = mp_int_mul_value(&t, mul, &t)) != MP_OK || + (res = mp_int_mul_value(&t, x, &t)) != MP_OK) + goto CLEANUP; + + x *= x; /* assumes x <= sqrt(MP_SMALL_MAX) */ + mp_int_zero(sum); + + do { + if((res = mp_int_div_value(&t, x, &t, &rem)) != MP_OK) + goto CLEANUP; + + if((res = mp_int_div_value(&t, coeff, &v, &rem)) != MP_OK) + goto CLEANUP; + + /* Add or subtract the result depending on the current sign (1 = add) */ + if(sign > 0) + res = mp_int_add(sum, &v, sum); + else + res = mp_int_sub(sum, &v, sum); + + if(res != MP_OK) goto CLEANUP; + sign = -sign; + coeff += 2; + + } while(mp_int_compare_zero(&t) != 0); + + res = mp_int_div_value(sum, radix, sum, NULL); + + CLEANUP: + mp_int_clear(&v); + mp_int_clear(&t); + + return res; +} + +/* Here there be dragons */ Index: contrib/isl/imath/rsamath.h =================================================================== --- /dev/null +++ contrib/isl/imath/rsamath.h @@ -0,0 +1,94 @@ +/* + Name: rsamath.h + Purpose: Implements part of PKCS#1, v. 2.1, June 14, 2002 (RSA Labs) + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#ifndef RSAMATH_H_ +#define RSAMATH_H_ + +#include "imath.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function to fill a buffer with nonzero random bytes */ +typedef void (*random_f)(unsigned char *, int); + +/* Convert integer to octet string, per PKCS#1 v.2.1 */ +mp_result rsa_i2osp(mp_int z, unsigned char *out, int len); + +/* Convert octet string to integer, per PKCS#1 v.2.1 */ +mp_result rsa_os2ip(mp_int z, unsigned char *in, int len); + +/* The following operations assume that you have converted your keys + and message data into mp_int values somehow. */ + +/* Primitive RSA encryption operation */ +mp_result rsa_rsaep(mp_int msg, mp_int exp, mp_int mod, mp_int cipher); + +/* Primitive RSA decryption operation */ +mp_result rsa_rsadp(mp_int cipher, mp_int exp, mp_int mod, mp_int msg); + +/* Primitive RSA signing operation */ +mp_result rsa_rsasp(mp_int msg, mp_int exp, mp_int mod, mp_int signature); + +/* Primitive RSA verification operation */ +mp_result rsa_rsavp(mp_int signature, mp_int exp, mp_int mod, mp_int msg); + +/* Compute the maximum length in bytes a message can have using PKCS#1 + v.1.5 encoding with the given modulus */ +int rsa_max_message_len(mp_int mod); + +/* Encode a raw message per PKCS#1 v.1.5 + buf - the buffer containing the message + msg_len - the length in bytes of the message + buf_len - the size in bytes of the buffer + tag - the message tag (nonzero byte) + filler - function to generate pseudorandom nonzero padding + + On input, the message is in the first msg_len bytes of the buffer; + on output, the contents of the buffer are replaced by the padded + message. If there is not enough room, MP_RANGE is returned. + */ +mp_result rsa_pkcs1v15_encode(unsigned char *buf, int msg_len, + int buf_len, int tag, random_f filler); + +/* Decode a PKCS#1 v.1.5 message back to its raw form + buf - the buffer containing the encoded message + buf_len - the length in bytes of the buffer + tag - the expected message tag (nonzero byte) + msg_len - on output, receives the length of the message content + + On output, the message is packed into the first msg_len bytes of + the buffer, and the rest of the buffer is zeroed. If the buffer is + not of the correct form, MP_UNDEF is returned and msg_len is undefined. + */ +mp_result rsa_pkcs1v15_decode(unsigned char *buf, int buf_len, + int tag, int *msg_len); + +#ifdef __cplusplus +} +#endif +#endif /* end RSAMATH_H_ */ Index: contrib/isl/imath/rsamath.c =================================================================== --- /dev/null +++ contrib/isl/imath/rsamath.c @@ -0,0 +1,163 @@ +/* + Name: rsamath.c + Purpose: Implements part of PKCS#1, v. 2.1, June 14, 2002 (RSA Labs) + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include "rsamath.h" + +#include +#include + +static mp_result s_rsa_transform(mp_int msg, mp_int exp, + mp_int mod, mp_int out); + +/* Convert integer to octet string, per PKCS#1 v.2.1 */ +mp_result rsa_i2osp(mp_int z, unsigned char *out, int len) +{ + int excess_len = mp_int_binary_len(z); + + if(excess_len < len) + return MP_RANGE; + + memset(out, 0, len); + + excess_len -= len; + mp_int_to_binary(z, out + excess_len, len); + + return MP_OK; +} + +/* Convert octet string to integer, per PKCS#1 v.2.1 */ +mp_result rsa_os2ip(mp_int z, unsigned char *in, int len) +{ + return mp_int_read_binary(z, in, len); +} + +/* Primitive RSA encryption operation */ +mp_result rsa_rsaep(mp_int msg, mp_int exp, mp_int mod, mp_int cipher) +{ + return s_rsa_transform(msg, exp, mod, cipher); +} + +/* Primitive RSA decryption operation */ +mp_result rsa_rsadp(mp_int cipher, mp_int exp, mp_int mod, mp_int msg) +{ + return s_rsa_transform(cipher, exp, mod, msg); +} + +/* Primitive RSA signing operation */ +mp_result rsa_rsasp(mp_int msg, mp_int exp, mp_int mod, mp_int signature) +{ + return s_rsa_transform(msg, exp, mod, signature); +} + +/* Primitive RSA verification operation */ +mp_result rsa_rsavp(mp_int signature, mp_int exp, mp_int mod, mp_int msg) +{ + return s_rsa_transform(signature, exp, mod, msg); +} + +/* Compute the maximum length in bytes a message can have using PKCS#1 + v.1.5 encoding with the given modulus */ +int rsa_max_message_len(mp_int mod) +{ + int num_bits = mp_int_count_bits(mod); + int num_bytes = num_bits / CHAR_BIT; + + if(num_bytes < 11) + return 0; /* at least eleven bytes are required for padding */ + else + return num_bytes - 11; +} + +mp_result rsa_pkcs1v15_encode(unsigned char *buf, int msg_len, + int buf_len, int tag, random_f filler) +{ + int pad_len, msg_start; + + /* Make sure there is enough space for the encoded output */ + if(msg_len > (buf_len - 11)) + return MP_RANGE; + + msg_start = buf_len - msg_len; + pad_len = msg_start - 3; + + /* Move message to top of buffer -- these might overlap, so we rely + on the semantics of memmove() here */ + memmove(buf + msg_start, buf, msg_len); + + /* Set initial bytes as required by the specification */ + buf[0] = 0x00; + buf[1] = (unsigned char)tag; + + /* Fill with random padding. We'll just assume the filler function + does the right thing and only writes the requested number of + nonzero bytes */ + (filler)(buf + 2, pad_len); + + /* Write separator between pad and message body */ + buf[msg_start - 1] = 0x00; + + return MP_OK; +} + +mp_result rsa_pkcs1v15_decode(unsigned char *buf, int buf_len, + int tag, int *msg_len) +{ + int pad_len = 0, data_len, data_start, i; + + /* Make sure the buffer is syntactically valid */ + if(buf_len < 11 || buf[0] != 0x00 || buf[1] != (unsigned char)tag) + return MP_UNDEF; + + /* Figure out how many bytes of random padding there are */ + i = 2; + while(buf[i++] != '\0') + ++pad_len; + + data_start = i; + data_len = buf_len - data_start; + + /* Shift the message to the front of the buffer */ + memmove(buf, buf + data_start, data_len); + + /* Zero out the rest of the buffer */ + memset(buf + data_len, 0, pad_len + 3); + + *msg_len = data_len; + + return MP_OK; +} + +static mp_result s_rsa_transform(mp_int msg, mp_int exp, + mp_int mod, mp_int out) +{ + if(mp_int_compare_zero(msg) < 0 || + mp_int_compare(msg, mod) >= 0) + return MP_RANGE; + + return mp_int_exptmod(msg, exp, mod, out); +} + +/* Here there be dragons */ Index: contrib/isl/imath/rtest.c =================================================================== --- /dev/null +++ contrib/isl/imath/rtest.c @@ -0,0 +1,124 @@ +/* + Name: rtest.c + Purpose: Test routines for RSA implementation. + Author: M. J. Fromberger + + Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "rsamath.h" + +void random_fill(unsigned char *buf, int len); +void print_buf(unsigned char *buf, int len, int brk, FILE *ofp); + +int main(int argc, char *argv[]) +{ + int buf_len, msg_len, i; + unsigned char *buf; + mp_result res; + + if(argc < 3) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + srand((unsigned int)time(NULL)); + + if((buf_len = atoi(argv[1])) <= 0) { + fprintf(stderr, "Buffer length must be positive, not %d\n", buf_len); + return 2; + } + if((msg_len = atoi(argv[2])) <= 0) { + fprintf(stderr, "Message length must be positive, not %d\n", msg_len); + return 2; + } + if(msg_len > buf_len) + msg_len = buf_len; + + buf = calloc(buf_len, sizeof(*buf)); + for(i = 0; i < msg_len; ++i) + buf[i] = i + 1; + + printf("Buffer size: %d bytes\n" + "Message len: %d bytes\n\n", buf_len, msg_len); + + printf("Message:\n"); + print_buf(buf, msg_len, 16, stdout); + fputc('\n', stdout); + + if((res = rsa_pkcs1v15_encode(buf, msg_len, buf_len, 2, random_fill)) != MP_OK) { + printf("Error from encoding function: %d\n", res); + free(buf); + return 1; + } + printf("Encoded message:\n"); + print_buf(buf, buf_len, 16, stdout); + fputc('\n', stdout); + + msg_len = -1; /* make decoder fill this in */ + if((res = rsa_pkcs1v15_decode(buf, buf_len, 2, &msg_len)) != MP_OK) { + printf("Error from decoding function: %d\n", res); + free(buf); + return 1; + } + printf("Decoded message (%d bytes):\n", msg_len); + print_buf(buf, msg_len, 16, stdout); + fputc('\n', stdout); + + free(buf); + return 0; +} + +void random_fill(unsigned char *buf, int len) +{ + int i; + + for(i = 0; i < len; ++i) { + unsigned char c = 0; + + while(c == 0) + c = (unsigned char)rand(); + + buf[i] = c; + } +} + +void print_buf(unsigned char *buf, int len, int brk, FILE *ofp) +{ + int i; + + for(i = 0; i < len; ++i) { + fprintf(ofp, "%02X", buf[i]); + + if((i + 1) % brk == 0) + fputc('\n', ofp); + else + fputc(' ', ofp); + } + if(i % brk) + fputc('\n', ofp); +} Index: contrib/isl/imath/tests/add.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/add.t @@ -0,0 +1,848 @@ +# Addition tests + +add:0,0,0:0 +add:0,0,=1:0 +add:1,=1,=1:2 +add:1,-1,0:0 +add:-1,1,0:0 +add:-1,1,=1:0 + +add:103427990038,909510006269847,0:909613434259885 +add:128593002,-9007199254740992,0:-9007199126147990 +add:-65537,70000,0:4463 +add:-1000000,-6543210,0:-7543210 +add:#x29C932F25E6CEF8046FA,#x-29C932F25E6CEF8046FA,0:0 +add:2,#x7FFFFFFFF,0:#x800000001 +add:95031018,=1,=1:190062036 +add:#x-176E7F8018D6BA4B550AB36AAAFDC78A9,#x186DAD2485A41B18AAF5EF17922D7E5F1F,=1:#x16F6C52C8416AF73F5A543E0E77DA1E676 +add:-628443782411312,-301652218193016,=2:-930096000604328 +add:13731535,499104,0:14230639 +add:46496,0,0:46496 +add:85658949,0,0:85658949 +add:3,86618070,0:86618073 +add:-364,0,0:-364 +add:916376,71094297,0:72010673 +add:-76,-48988,0:-49064 +add:7,98029,293800191852111:98036 +add:213,0,0:213 +add:116992,19352187,=1:19469179 +add:-54334706,-2638935,0:-56973641 +add:4210,4441,0:8651 +add:2470,-1654142,0:-1651672 +add:-32608,76896,0:44288 +add:598200,65918574,0:66516774 +add:-524863149,95573,0:-524767576 +add:4,6856995,0:6856999 +add:86710327,16209386,0:102919713 +add:31,-24,0:7 +add:5895523,9915789381,0:9921684904 +add:41557511,310172,0:41867683 +add:-6714,923,0:-5791 +add:466232157,987,0:466233144 +add:5919,-63,0:5856 +add:929994,66871,0:996865 +add:23,391,0:414 +add:751,-25255,0:-24504 +add:-282292,-1608,0:-283900 +add:0,-4119448990,0:-4119448990 +add:69248,-64165,0:5083 +add:816106,580,0:816686 +add:15171,219806,0:234977 +add:945180,-585066,0:360114 +add:27052,6664636892,0:6664663944 +add:-481622,-578,0:-482200 +add:926,-81,0:845 +add:-4084,62941238721,=1:62941234637 +add:888598,6601,0:895199 +add:-61,143796,0:143735 +add:408006264,51,0:408006315 +add:-582073,-6752,0:-588825 +add:88194084,595557600,0:683751684 +add:4963532385,72932,0:4963605317 +add:37370180,708428344,0:745798524 +add:638718578,-94054,0:638624524 +add:12603892606,194259,0:12604086865 +add:9812049,8843056,0:18655105 +add:-156093,-3718156523,0:-3718312616 +add:12264,949557843298,0:949557855562 +add:338742,9139,0:347881 +add:48848,-6268099,0:-6219251 +add:3653,981782890584,0:981782894237 +add:608763646,38233135026,0:38841898672 +add:-17063,-4811,0:-21874 +add:63244008,-380818980,0:-317574972 +add:624559862947,21088,0:624559884035 +add:-268795562,74755169,0:-194040393 +add:368827930,56987680,0:425815610 +add:142,-838643130506,0:-838643130364 +add:848909,137303147,0:138152056 +add:6682221270,4495632518460,0:4502314739730 +add:163999538727,754668,0:164000293395 +add:570098317,1230642588,0:1800740905 +add:814302609847,295465,0:814302905312 +add:61148411120,462527703,0:61610938823 +add:979075368979,64243429,0:979139612408 +add:8280601099859,431312,0:8280601531171 +add:29662,3920844058249,0:3920844087911 +add:381765363,6285,0:381771648 +add:6038301700102,167589011428,0:6205890711530 +add:-6720,50309,0:43589 +add:92070025383,8403955,0:92078429338 +add:9057100,9331,0:9066431 +add:46997620390,2556790331006,0:2603787951396 +add:9853238961850,760016661497,0:10613255623347 +add:642786326083,4994197649,0:647780523732 +add:60934395,192791945290,0:192852879685 +add:1304866806,9628566351206,0:9629871218012 +add:-537871392295,1691988267,0:-536179404028 +add:73595697641,63790,0:73595761431 +add:87798124384590,168308169,0:87798292692759 +add:77155772837617,993653875,0:77156766491492 +add:691109994727,83820903066409,0:84512013061136 +add:2012749349577,1194,0:2012749350771 +add:3909606,1258809350,0:1262718956 +add:5961027295,-191014,0:5960836281 +add:-9155782013,84622,0:-9155697391 +add:-7211667,-624806193439,0:-624813405106 +add:1754076,931310,0:2685386 +add:53288031910288,1866366148,0:53289898276436 +add:767503182,-78473238204,0:-77705735022 +add:-89763935864,-14028568280297,0:-14118332216161 +add:454616605,67243118209653,0:67243572826258 +add:674985,745910,0:1420895 +add:9182866281585,-7492901984,0:9175373379601 +add:8427973625,2948084578162,0:2956512551787 +add:89366530,96670928089,0:96760294619 +add:62255464298256,1694823,0:62255465993079 +add:5268676160308,-93499502334390,0:-88230826174082 +add:7165346,-12994330060,0:-12987164714 +add:73330752719,904668539586,0:977999292305 +add:8007349,88617667386,0:88625674735 +add:951867792,807329,0:952675121 +add:645715109491016,58609052382,0:645773718543398 +add:2037750169321,85113205892,0:2122863375213 +add:6585250,76715488825566,0:76715495410816 +add:4585299,4140224,0:8725523 +add:20194080,7047624,0:27241704 +add:786913195,5197776759303,0:5198563672498 +add:751261814658086,65539188,0:751261880197274 +add:-6325172443258,2171993016413249,0:2165667843969991 +add:3947284565,-78726628505,0:-74779343940 +add:-71699817835206,40239308204,0:-71659578527002 +add:53023714,-82553833053558,0:-82553780029844 +add:2808131187169,890250230608190,0:893058361795359 +add:4783795579,-953360022706,0:-948576227127 +add:22326520,59606609543578,0:59606631870098 +add:37110988189,2635629530529,0:2672740518718 +add:5415787,65557975919,0:65563391706 +add:687495904,-3296642739961554,0:-3296642052465650 +add:72930835789,43382168425705304,0:43382241356541093 +add:-995003864534,61722341747,0:-933281522787 +add:74285863538462,4701124896071184,0:4775410759609646 +add:-7259432400758987,917110091938734,0:-6342322308820253 +add:83640964028613,28436773,0:83640992465386 +add:12798300129,42764089830,0:55562389959 +add:907689161228474,9984041726746,0:917673202955220 +add:88648450941,-92224182312398621,0:-92224093663947680 +add:3423736794,992566059450,0:995989796244 +add:26095203,84516699542499712,0:84516699568594915 +add:-664955461457,34154013,0:-664921307444 +add:17408598155,57614703283466656,0:57614720692064811 +add:734135582143613,8386599520,0:734143968743133 +add:75433328059753089,3411724102,0:75433331471477191 +add:-5780056339,370823068636155,0:370817288579816 +add:747133022687630,743183409891560,0:1490316432579190 +add:1351023965,562216806411,0:563567830376 +add:8923051674,5453380084794,0:5462303136468 +add:244571930,-51111880145,0:-50867308215 +add:-41136584383913485,2817501078,0:-41136581566412407 +add:-8079768063523410,441741295522855156,0:433661527459331746 +add:599579537585,1505732756139,0:2105312293724 +add:6728375739,634744472,0:7363120211 +add:163686368,10797029513119,0:10797193199487 +add:38258778569482,81136715091,0:38339915284573 +add:89311393409893347,6487334114,0:89311399897227461 +add:4413952309911,-335091846,0:4413617218065 +add:-8490298221703,906197882389719833,0:906189392091498130 +add:547446627581960679,4111395072,0:547446631693355751 +add:-147199257725737,358585065185151457,0:358437865927425720 +add:733104781218,1305401890,0:734410183108 +add:66789232493812823,152353542633642764,0:219142775127455587 +add:91447917877257,890149399042107596,0:890240846959984853 +add:67840659340,45844535119015296,0:45844602959674636 +add:31351681435877221,-442068622969770457,0:-410716941533893236 +add:8505522087730720965,162001047045127445,0:8667523134775848410 +add:90408836865703,91766097115,0:90500602962818 +add:8278725919,-6565975065136635,0:-6565966786410716 +add:778195404262806210,9985183887639111776,0:10763379291901917986 +add:6696810212664216,312304914759219,0:7009115127423435 +add:3557735824865,584593215289536,0:588150951114401 +add:-49412044681,29956396329782239,0:29956346917737558 +add:11923449620,7765655187,0:19689104807 +add:1724176067,-67142223866,0:-65418047799 +add:525722978624,57023088377443306,0:57023614100421930 +add:726936921764427,3077076587081089,0:3804013508845516 +add:1790333591126,-91682335574328992,0:-91680545240737866 +add:-1112879092907469823,1867817571215,0:-1112877225089898608 +add:-8476115918476,3323398534004,0:-5152717384472 +add:83059391773,-65273298074046515729,0:-65273297990987123956 +add:2211388311050688,-245146603838894173,0:-242935215527843485 +add:585851683392336,3975804417513631370,0:3976390269197023706 +add:139186663640090,15082756961,0:139201746397051 +add:-48189710801086,-33546258184494787728,0:-33546306374205588814 +add:-100779556817445,-1522038785339961,0:-1622818342157406 +add:4885512159295669,480294778789866559,0:485180290949162228 +add:-557882003905193311,20195805293900,0:-557861808099899411 +add:154553862612072,9109218823125727072,0:9109373376988339144 +add:1483847515783086714,78233016786768531473,0:79716864302551618187 +add:632462956668123,-2951738540674650223,0:-2951106077717982100 +add:-60943119399848141,74036520715371,0:-60869082879132770 +add:-7905328383508507808,-207334403231,0:-7905328590842911039 +add:-376183968178,-862976187364,0:-1239160155542 +add:918327139068056021,-685922087142,0:918326453145968879 +add:-9846497109055054870,6775447579440637,0:-9839721661475614233 +add:-84073521083215,71309976692297262369,0:71309892618776179154 +add:-373011272994268095955,4157479098221637,0:-373007115515169874318 +add:49271774069573022576,378613526495506818344,0:427885300565079840920 +add:-5376376953931357562,7508833770175817,0:-5368868120161181745 +add:-23778714258598355551,-7185005392000393507,0:-30963719650598749058 +add:801031622749,53000130414840,0:53801162037589 +add:-970929952514676169,64017648311761173049,0:63046718359246496880 +add:444961381148474,-368409783275279249,0:-367964821894130775 +add:39999239040508219266,38054215870372108,0:40037293256378591374 +add:-712118755181107,21931036897383483,0:21218918142202376 +add:-646755675748528169,609844920243318603442,0:609198164567570075273 +add:171013028884891673,11967223547227113703,0:12138236576112005376 +add:90483783429450285931,8758299165450368514304,0:8848782948879818800235 +add:54722600417344222188,6655544009320,0:54722607072888231508 +add:7059355949487975,15428043300387,0:7074783992788362 +add:63718799432141668051,-1777818839779748621,0:61940980592361919430 +add:-811965656585153,-92999475442666083,0:-93811441099251236 +add:-480943344691207768,38637964026264,0:-480904706727181504 +add:87346474969320,11671605416687563,0:11758951891656883 +add:-144193490776783,320317203586930,0:176123712810147 +add:637224429856480,90100814693140,0:727325244549620 +add:1117448757980,20116238466569324081,0:20116239584018082061 +add:2134662653354031124,57535080216036041491,0:59669742869390072615 +add:-699305697439351543,-1322846377107844464831,0:-1323545682805283816374 +add:-287368527913803,559967333864139,0:272598805950336 +add:-4524131005300321178256,648090525452193270713,0:-3876040479848127907543 +add:983197813618615290581,-555223968315003163,0:982642589650300287418 +add:47595018158554,554354123612822084175,0:554354171207840242729 +add:76492304934567739056067,-17570682458452839171696,0:58921622476114899884371 +add:605579840932458751,5118917191828845481095,0:5119522771669777939846 +add:-77276783972774282464,97578221184517253974,0:20301437211742971510 +add:-55779468870779406,3628329199924803907,0:3572549731054024501 +add:-6810396240935929656,45581601665257956989667,0:45574791269017021060011 +add:-643395735022469,95994342321649,0:-547401392700820 +add:59033016804296,90010200392865311,0:90069233409669607 +add:412262412571713009,44652839425446643811,0:45065101838018356820 +add:-996242836885840433689,9932141967639296363784,0:8935899130753455930095 +add:-187591416585869366840,4868774783363997420,0:-182722641802505369420 +add:786124638558627932,120825949339625517416,0:121612073978184145348 +add:683056931297141410,13435555169749,0:683070366852311159 +add:78591895387046935416982,-3863271218201597391326,0:74728624168845338025656 +add:-581639737241844,59732569151616229,0:59150929414374385 +add:63839107438860260,-57936899988162199911626,0:-57936836149054761051366 +add:90241348579070434,4025779803051070287,0:4116021151630140721 +add:-29146551546957649,500543832007704775744,0:500514685456157818095 +add:40152296103662954,30632073318077007293876,0:30632113470373110956830 +add:46052697297460594549965,-2523434189144367108,0:46050173863271450182857 +add:-908472766655304200,503910242160770655137,0:503001769394115350937 +add:35664754770405781576262,-52328200879455304,0:35664702442204902120958 +add:536193847189289,2055159240163985839,0:2055695434011175128 +add:5692763430774180,559128387745059,0:6251891818519239 +add:962044518204007,36941484559411981897006,0:36941485521456500101013 +add:1778825689878630,1752252372363744,0:3531078062242374 +add:94533959067668939155652,7370593466294273268440,0:101904552533963212424092 +add:-79278320169999633,98078807455225677,0:18800487285226044 +add:97932568071091044410,45504699679270344940,0:143437267750361389350 +add:81602336599709335,277692040888807344679270,0:277692122491143944388605 +add:-8416111605414512356,-71387336643361802215,0:-79803448248776314571 +add:-4364114737364980,5713751339100810207300,0:5713746974986072842320 +add:-2248544818568852,-95216575446860643106235,0:-95216577695405461675087 +add:-86464737497345750915,-9340577567832336397746,0:-9427042305329682148661 +add:7285517444194103327524171,-178398693192528240,0:7285517265795410134995931 +add:745600294808335954574,3590181147179066146,0:749190475955515020720 +add:9465688117779501171539,38370364609588339408116,0:47836052727367840579655 +add:780056864215481439157498,-7015580969512485,0:780056857199900469645013 +add:978681982436757227400,2684547366513014,0:978684666984123740414 +add:-1128116293278100017914825,5548079193241448,0:-1128116287730020824673377 +add:69069382482494805,-40368676133739445253204,0:-40368607064356962758399 +add:1068908356897083556495,92975661850341635306516,0:94044570207238718863011 +add:2045728645356266,6732676856163053,0:8778405501519319 +add:986371258787059591145109,24417303396801332,0:986371283204362987946441 +add:5107392493993300358729,-8580635176929229687,0:5098811858816371129042 +add:1173219044247994941,150432915362745448142,0:151606134406993443083 +add:289209848265652909988,896527174701053128584035,0:896816384549318781494023 +add:7576209306830869,321093885120988771790,0:321101461330295602659 +add:-1998078850553780901,-491302474398583183312,0:-493300553249136964213 +add:48578611214917968888328,-9724795578642180430323005,0:-9676216967427262461434677 +add:-89125038112802690868952,106876489286063867,0:-89124931236313404805085 +add:71163583246605175,94315599279060581,0:165479182525665756 +add:-37978975375912768223,-83894091589588085332,0:-121873066965500853555 +add:26160354602260154641,82502519980721475,0:26242857122240876116 +add:6721445506562724498613,3849322132330485045442724,0:3856043577837047769941337 +add:-49599516930241019167,940046744572738518062,0:890447227642497498895 +add:309633233963607626456,431010776584765161668698,0:431320409818728769295154 +add:5437528458768789581061,98535318335138080471,0:5536063777103927661532 +add:441952255932531337132635419,-457951493790545402320,0:441951797981037546587233099 +add:4234090565000592983852,141452209542036221,0:4234232017210135020073 +add:444877202793878855,-818932236535168281886543304,0:-818932236090291079092664449 +add:8735279390159786014911,74528121661502104489,0:8809807511821288119400 +add:329585339951820135507,3209925326812978905481,0:3539510666764799040988 +add:7513147727765550283468497,18340872039691020224,0:7513166068637589974488721 +add:22672336765411635852057,112360311181155228061,0:22784697076592791080118 +add:94840923157956010314,-890963292023167606621709508,0:-890963197182244448665699194 +add:-42743124461511984041,-154189486799725890635958009,0:-154189529542850352147942050 +add:4642096435824001337488,1075739791472186776,0:4643172175615473524264 +add:9072122446151456250370,459465421414955099,0:9072581911572871205469 +add:1208103563782991690,37264807069479596362,0:38472910633262588052 +add:-35229676312313275613641079,7831519567525205386506558,0:-27398156744788070227134521 +add:-14914636592325904561,238892654922757390,0:-14675743937403147171 +add:70036479094753932788537196,3638698354298942306,0:70036482733452287087479502 +add:2026475183691718009207221,-51818547306091257831,0:2026423365144411917949390 +add:934591237413188471704,9583576351426447252706,0:10518167588839635724410 +add:19623165243467693921345120,713164237953453844732059938,0:732787403196921538653405058 +add:-330423131007863591790334,483122548819491409819,0:-329940008459044100380515 +add:186655649790428913672547335,45905196004697591848,0:186655695695624918370139183 +add:61575494850989411781745,510771432997312770825568,0:572346927848302182607313 +add:701715172953878317016084611,82176271434782371131,0:701715255130149751798455742 +add:37317170353550823267505484,-281915644115285990142,0:37316888437906707981515342 +add:782147829078599149413,406441493949770755536,0:1188589323028369904949 +add:8750933869512603353560747,4845145469101036864410189,0:13596079338613640217970936 +add:82771556090809260029854,417868176867358634531479,0:500639732958167894561333 +add:-60327848305676142893255531,45186448696277654715,0:-60327803119227446615600816 +add:559238168466621140605667,3086402973187970627177143386,0:3086962211356437248317749053 +add:1487217856230533992619184307,88533139618452902103,0:1487217944763673611072086410 +add:74032714774552791328773,-743497205088178750354447330,0:-743423172373404197563118557 +add:87529301918640055328531949,833538436278390237794218,0:88362840354918445566326167 +add:1134893809082711064119381650,835345147684508177653,0:1134894644427858748627559303 +add:-31083560926993891097159,-6452398931722666743775,0:-37535959858716557840934 +add:-494187214625328255573121,-433316980223823483512168,0:-927504194849151739085289 +add:390091842128606730764553615,7074602388637593045951,0:390098916730995368357599566 +add:14996900382322823366993947,155575881895992530106696,0:15152476264218815897100643 +add:256981179582607852185710064,960124902340809507842,0:256982139707510192995217906 +add:606337739205468757142681,34431354430278402333959617,0:35037692169483871091102298 +add:820809632172159862547216787,-4720961905066758420386939975,0:-3900152272894598557839723188 +add:33254605052680847119352168342,-42458830987973889052675953,0:33212146221692873230299492389 +add:1921909649929948589227,650119220435441127155469,0:652041130085371075744696 +add:36032029451816652021799919065,991948874284797761534223740,0:37023978326101449783334142805 +add:17509423061776720551599,561537726801446789470435708,0:561555236224508566190987307 +add:432435308982641288577,2579972583113864486802769,0:2580405018422847128091346 +add:5533541961594197125465685605,-5341574108952093824178502732,0:191967852642103301287182873 +add:29253784634468015940995,66868085704232379455942,0:96121870338700395396937 +add:5840836104812160960058403235,7254794739433874655672505,0:5848090899551594834714075740 +add:-986437670276537865472,-7254530387088660530975,0:-8240968057365198396447 +add:5936378029743262858909,5646361873410369432412,0:11582739903153632291321 +add:9309474173188449211471238,71622847426463521178458,0:9381097020614912732649696 +add:7395866525419579894252,6054211177368524226173,0:13450077702788104120425 +add:418754431137708178806,4581969489771092325887396,0:4582388244202230034066202 +add:427267592272679033207846,-1335344313633491261520271375,0:-1334917046041218582487063529 +add:633189097535167096544295,8453789539859471176551,0:641642887075026567720846 +add:5272319792173353341707102,391850306244460524900101084,0:397122626036633878241808186 +add:65825860390007189905183231257,931471994606023293002971,0:65826791862001795928476234228 +add:-176921811706712109725453309153,51104838980538411694813294,0:-176870706867731571313758495859 +add:76672856213061308993625,-29636580685314230414049903200,0:-29636504012458017352740909575 +add:674452402018255228121289278,67008875737626760336005690,0:741461277755881988457294968 +add:8541968162357356479415070453,-80758853802904365328480678550,0:-72216885640547008849065608097 +add:63670327126030699390525,647239453527002086941714828140,0:647239517197329212972414218665 +add:23827968287407694016891491732,5687322786770428586659139842628,0:5711150755057836280676031334360 +add:-56934084938034523477449,6919565043762938954102,0:-50014519894271584523347 +add:-812505002549423792769451177170,-468614098924848220068202,0:-812505471163522717617671245372 +add:67104776285167776356142,210831864020377644772737617440,0:210831931125153929940513973582 +add:5824940449668378359986211,-64180395015735031445899448907,0:-64174570075285363067539462696 +add:983409682982426617028179979,163969833630884765202234246,0:1147379516613311382230414225 +add:6210538420073191557435,-31054053390220409528967600423,0:-31054047179681989455776042988 +add:469516153781193420842788,1496796321887102771420,0:471012950103080523614208 +add:33979356884336447134582,91638986223658016683623403,0:91672965580542353130757985 +add:-32260848074913901984307362359,-2672012528351544629126598,0:-32263520087442253528936488957 +add:-8417639463674910047939048993449,80120124562574727803706174,0:-8417559343550347473211245287275 +add:775695772679005684017516,-3020790629041979619689982869,0:-3020014933269300614005965353 +add:975852258680635035690012,83046701463562128390834533268,0:83047677315820809025870223280 +add:8781861863169257626949530,28108177849164848399916019884,0:28116959711028017657542969414 +add:-283546689653578050474370627,2807772419117477871716212,0:-280738917234460572602654415 +add:9064465458779158311916969647780,9139819686732442186357751866469,0:18204285145511600498274721514249 +add:8840784216244154251572494530,60209012240418199299108682988151,0:60217853024634443453360255482681 +add:93815677427271630939740,22565184436411206947191022,0:22659000113838478578130762 +add:82452768800915418769333034684,31578884402602201747665,0:82452800379799821371534782349 +add:-861901423955324264599608669156,707341771563323556783706679,0:-861194082183760941042824962477 +add:-27282637700205513755848881,-503533726284787080825911,0:-27786171426490300836674792 +add:9289214479556466478450749,-7084113575511224733535260,0:2205100904045241744915489 +add:7017123255359412684282683,9046068160232439106672624,0:16063191415591851790955307 +add:251153423310728722653267854537,13062952884507685376788080,0:251166486263613230338644642617 +add:764970108101691141391204483,75231888234738846744202931914419,0:75232653204846948435344323118902 +add:70105736718198876906468336722477,2901679421786748849622789,0:70105739619878298693217186345266 +add:-277236273480908454984267,95439324803072858679031,0:-181796948677835596305236 +add:502022119894313002150611379003,-9553217783049460795811638,0:502012566676529952689815567365 +add:11235044224795237679279440,1598484681458068370777229,0:12833528906253306050056669 +add:6006446640030673298734990897916,3932713488343416708785849,0:6006450572744161642151699683765 +add:341984581388111664359529291419,253672139310821088560318393948503,0:254014123892209200224677923239922 +add:-16498480187763102357325186,16757917811449471275953805,0:259437623686368918628619 +add:4840293579085321724261731660,3299269918638542438501050537,0:8139563497723864162762782197 +add:862473464150144977188625432548718,390725508757117448688936595600,0:862864189658902094637314369144318 +add:-29573457775060793626221640796,-955486742447211372069984831882188,0:-955516315904986432863611053522984 +add:2764463542396067736191963723,33349178218458257881168366225076,0:33351942682000653948904558188799 +add:-564129660605536405453000618753,-996106182924479683180384656113614,0:-996670312585085219585837656732367 +add:8033177512692093044315018,-5381259101993480763476852450,0:-5373225924480788670432537432 +add:5694253375903848576996695765,3533498246256483823188758976,0:9227751622160332400185454741 +add:8049869890130722459017898,804302573811695296944485509,0:812352443701826019403503407 +add:-10782856862032822029370450127864,42183304229376991057468028,0:-10782814678728592652379392659836 +add:17953427150766889866624145,2672739534749259247084452652,0:2690692961900026136951076797 +add:382968112253902278556556412715286,507081979144423606544809226,0:382968619335881422980162957524512 +add:10675472848868311098607354530,921641093617028576338449657948,0:932316566465896887437057012478 +add:45793464872625930068611014771,895098402397211759149489341,0:46688563275023141827760504112 +add:-64085785899561813992220240078,-9948203496533963923520873499122871,0:-9948267582319863485334865719362949 +add:-36229685382343277189388317,3225709738074187586965400,0:-33003975644269089602422917 +add:62746144069561486173188762523567,41388696507099517847341965,0:62746185458257993272706609865532 +add:-607094025616255955599781697,-394867562893771866413821906158382,0:-394868169987797482669777505940079 +add:311268724839167391882108484,-82153236672690725073700221869998,0:-82152925403965885906308339761514 +add:-6835603694552724869687187061,-6023776712184941872282636664,0:-12859380406737666741969823725 +add:590358394226908898299218590543900,97734796237031665405902113169504,0:688093190463940563705120703713404 +add:776333186005384178281483204964,7251231826873456228321061,0:776340437237211051737711526025 +add:56669798612022472565446600865,-6052380717302970032083528141,0:50617417894719502533363072724 +add:6865898859037955833953890,178638282809455642352286,0:7044537141847411476306176 +add:5105205245055741189404951,893962641798284490158079805140673,0:893962646903489735213820994545624 +add:51316165533150178772523358024,-628375072698255873957923760051222,0:-628323756532722723779151236693198 +add:-87785238468437978540491414,89732479371379507893122052,0:1947240902941529352630638 +add:950318073610388416087529318775,402634948952512865122682232525,0:1352953022562901281210211551300 +add:-74572627412706083960240275,431357597384151709770753161,0:356784969971445625810512886 +add:9853321136670770651473838461495259,-83924966088311113186923377729455334,0:-74071644951640342535449539267960075 +add:650506501105456725689474061,287241011028313593932616830,0:937747512133770319622090891 +add:8132932977319394188366230514,-254188694333249311199490675,0:7878744282986144877166739839 +add:53320519909486593081198293,-74572156817884131125537363,0:-21251636908397538044339070 +add:-71547639554175546005091389360,-8140195760146170485331061575,0:-79687835314321716490422450935 +add:1327483718371853548235029647793617,54274563336128441076471770,0:1327483772646416884363470724265387 +add:1314001032447052278696101270,5415781672112089561501909844,0:6729782704559141840198011114 +add:47224974651866655046632261766,-76788661932424775106847892,0:47148185989934230271525413874 +add:792552859971310302936618155974,-487118690055436369708858828,0:792065741281254866566909297146 +add:8685351871091309367281665125018193,579376603481579380106078170606,0:8685931247694790946661771203188799 +add:-163023266227426934448401141075814,771214414019011070620622448527010,0:608191147791584136172221307451196 +add:681117685696813411930600559345469,53231124210443068505485918467568,0:734348809907256480436086477813037 +add:24728715686927944276955201,239070293086557045345907117925272,0:239070317815272732273851394880473 +add:764946100412930809834253766,-826649833775850040190545960601,0:-825884887675437109380711706835 +add:7808371142489773310260037786027,3411749587758291799422914115,0:7811782892077531602059460700142 +add:9487499431366548971411896854,617160736935684035360665548277255,0:617170224435115401909636960174109 +add:898285778199998316256066724,-446698135458890722737448919720207023,0:-446698134560604944537450603464140299 +add:679188320572774450433052775314,917321221948698358395231976875443,0:918000410269271132845665029650757 +add:-606026214573430597349972660492,-76705531041680588416688199753404,0:-77311557256254019014038172413896 +add:-2436189233935198704211905220849,37199591944878505577734886802440,0:34763402710943306873522981581591 +add:183575501000337709289570527203677231,136287320714071665681020786679234742,0:319862821714409374970591313882911973 +add:8590013432900716370831629971791,968114425708634187961093620824,0:9558127858609350558792723592615 +add:347137295949542839762519290637421643,102270809320390302037608013,0:347137296051813649082909592675029656 +add:8440473671167620611051468072483271,2296992478227176302012302522046,0:8442770663645847787353480375005317 +add:-5001669553432654706696400609,118900597514025159662837118047,0:113898927960592504956140717438 +add:-62002790901737049130724871593864,49447394219956225227401512811,0:-61953343507517092905497470081053 +add:86330941115371276117147730300459977,2177791532412716777679721138299658,0:88508732647783992894827451438759635 +add:946875123242781630779255037,47946896786026059202158912141346,0:47947843661149301983789691396383 +add:15336011900228959543893716525418719,388047623512726643322227444888,0:15336399947852472270537038752863607 +add:670173436182016731100418370242962831,4761361980899572407426780990276,0:670178197543997630672825797023953107 +add:16361593374554723036317118422757,959754436168611589130929042794416,0:976116029543166312167246161217173 +add:7037129211989227284511625030,-64039638650631553463764702068273727,0:-64039631613502341474537417556648697 +add:1669039732670522007255294145067558610,5040361069110054882215284201346,0:1669044773031591117310176360351759956 +add:1513189097366228884843540957233,759609367644509304958151974044245430,0:759610880833606671187036817585202663 +add:4895978309720518255173456993,-4110535948244791094217531557,0:785442361475727160955925436 +add:384532700809738729029745679298,-8056698430799793973614359358,0:376476002378938935056131319940 +add:-6388105307234743748019853948088503,4997968805095951937740134154116761,0:-1390136502138791810279719793971742 +add:975018502065461978578000363066,2247367452090296660167940131,0:977265869517552275238168303197 +add:78856706773590014370827059719,6542936662766324535583066287213231,0:6543015519473098125597437114272950 +add:6499328245520359687815445935758,158783937355037461719106652621,0:6658112182875397149534552588379 +add:-929274641312553715971084005591328,65105653662781997005394335939613534,0:64176379021469443289423251934022206 +add:456683941925696893937943252471,2047844563635520107891754533956927,0:2048301247577445804785692477209398 +add:2464091244058374057204697838093,548233532044481143606226540715,0:3012324776102855200810924378808 +add:-5782058275134622637686813910631,65732482103665178041908743240,0:-5716325793030957459644905167391 +add:9077295754335257518831628411071383,10924567149120537328883108077429125,0:20001862903455794847714736488500508 +add:4487883990386478000336258527165792,45494719991936774851608031864,0:4487929485106469937111110135197656 +add:-278061320607811538265660406605,6501055843301716146308769533884534700,0:6501055565240395538497231268224128095 +add:-98496078021467197122901029244,4781298078177162558520974148272,0:4682802000155695361398073119028 +add:-880487306232247995563348595589965390,1786978622507362310090719007228,0:-880485519253625488201038504870958162 +add:3564320220013161114076355137453361,3174192776315040318048578353150392,0:6738512996328201432124933490603753 +add:-17938701536608326039598376013574,6544909780634291186211124961480,0:-11393791755974034853387251052094 +add:477266862227893391363944723416214,75215386788899217183549861936487009,0:75692653651127110574913806659903223 +add:882168805504704249200404316267,397370099670749831094907204966440642,0:397370981839555335799156405370756909 +add:-5168732252762846279707583890106130,68924007866194419843572553425738646075,0:68918839133941656997292845841848539945 +add:13976907500017232058982276795936,62903564794422037566078537019953323966,0:62903578771329537583310596002230119902 +add:-723679233282687539426040870751505916,9944693303602413488927619210482961855,0:9221014070319725949501578339731455939 +add:19723375859398094253269538838784,4448602254481220443835883935,0:19727824461652575473713374722719 +add:435487568164299717641211729895291,30263286963580437915152248885,0:435517831451263298079126882144176 +add:821847194805020065585371899303,-56701356407219809621351993974800366087,0:-56701355585372614816331928389428466784 +add:906521314887358356519304370098899949,575586805546053112223797224287895841,0:1482108120433411468743101594386795790 +add:19861035347913984137892042959473300,9203641819631417294115804880148466,0:29064677167545401432007847839621766 +add:35489920465547911895345631311031287850,61963387682089469403889443775403001937,0:97453308147637381299235075086434289787 +add:711218176456565648939214863247002012,72467446712664186983159145098756557673,0:73178664889120752632098359962003559685 +add:453411180015845016525527797241902720,656188106785767735033442856252,0:453411836203951802293262830684758972 +add:3497788563739847797768025384670848,517400530521523434205853846962853,0:4015189094261371231973879231633701 +add:4155970281036560633085895732986331436,58654056236489765208332410680287635851,0:62810026517526325841418306413273967287 +add:-43796787638734252111746756631324509,15458635191255506747952752911563140015,0:15414838403616772495841006154931815506 +add:886478982594616386399515638094,791374254805498814484495931823029294,0:791375141284481409100882331338667388 +add:5420205765532053736853148082964602405,80894300860364935354122327418793,0:5420286659832914101788502205292021198 +add:6409540010109365565390431678312058,3761260998235788651953577451547946396,0:3767670538245898017518967883226258454 +add:379235320792985651222455993704383,39768702701817374238094976575577292677,0:39769081937138167223746199031570997060 +add:9741457286836201279089678473713551193,-9789501315839617552822514677465645799,0:-48044029003416273732836203752094606 +add:679351661380711616762980509555487422,5244958563307694732934184938012411110,0:5924310224688406349697165447567898532 +add:230190844936986997441295775275022034,-185909046836091915997263172330,0:230190659027940161349379778011849704 +add:3156689741537889100921303548469,547814421078639373357367180225132810,0:547817577768380911246468101528681279 +add:-62219007651568146709531118440682893089,-9434399409814593713428350812443801646786,0:-9496618417466161860137881930884484539875 +add:184174790691390536467483515964213892835,2941013349035333556270582770860221254,0:187115804040425870023754098735074114089 +add:51019963839123593098882577978755,1116589028775897480619143898066573,0:1167608992615021073718026476045328 +add:3161373461260957201319457188462572095,295012249650450244682353395660589081695,0:298173623111711201883672852849051653790 +add:255897713184471452642500281024049492424,5260363568754655790521228400406175726257,0:5516261281939127243163728681430225218681 +add:606315001345297293855907552090677,58643218561030036941054387859353998671,0:58643824876031382238348243766906089348 +add:7728401578087472448175772296881,2479932497409122334635317410130037,0:2487660898987209807083493182426918 +add:83912594421874997853645370567167,2586838887610120476863229517446,0:86499433309485118330508600084613 +add:31162728147482517541527422834730838,49272727945051817211201248857958834546,0:49303890673199299728742776280793565384 +add:7732493494017159067700264618259826225579,9076083109776747375814790855266491489,0:7741569577126935815076079409115092717068 +add:379595189057102692932728847043,78412390558490705293355381777932556,0:78412770153679762396048314506779599 +add:-80073436239675271494315527682263,50945580964846901715535623599314335,0:50865507528607226444041308071632072 +add:7287524755764369986358866728286492322771,-3434322398801915039360350216639455,0:7287521321441971184443827367936275683316 +add:5350901001113421691951885827606408,-52813130876478631706333437707256,0:5298087870236943060245552389899152 +add:-93922484436479929644974748134570042227,-18558847074134835688687179622179299456381,0:-18652769558571315618332154370313869498608 +add:6348261214416753548599493164564265,70959376021447769657800151242308058385,0:70965724282662186411348750735472622650 +add:82136982657867459725041723297845260,-4942386549903864832898696177047927,0:77194596107963594892143027120797333 +add:-637766414636467351411944290845261564150,3139008925795329253435316311633609560,0:-634627405710672022158508974533627954590 +add:7876071803789707417919831488411894460,-787451981013463104190187704083407112807,0:-779575909209673396772267872594995218347 +add:-6975874728401593555157382880902999590154,-5386051406453469842388696470942392,0:-6975880114453000008627225269599470532546 +add:263948302163372204339026784768887,-709208282236872695042395059556627390964,0:-709208018288570531670190720529842622077 +add:966883950465093993601498906417362169986,52803750507502030833811587668282000984096,0:53770634457967124827413086574699363154082 +add:758872502722448271767968272715108,924042905049846617145386931355586,0:1682915407772294888913355204070694 +add:8817515445646069320245128327534016,33540272364420722162627441428305029,0:42357787810066791482872569755839045 +add:7452847844446973070588448979886483,13672013320832031648561092777470,0:7466519857767805102237010072663953 +add:504207812168642571415434369106684,3112968037276454309667407723426693283,0:3113472245088622952238823157795799967 +add:79464727253769579340699162892454647,-3445737782055492967953863370896564268,0:-3366273054801723388613164208004109621 +add:27111645259145369800704958812916,67484517522542733254003181309322379,0:67511629167801878623803886268135295 +add:7962416479715287030323333279385706598,88254203468610078692514314020591,0:7962504733918755640402025793699727189 +add:39693287540792352830897524921810,-21314277451673979084086774678038501015,0:-21314237758386438291733943780513579205 +add:198918483468716913242822977257934441,-7728701263590045875855983145711563105524,0:-7728502345106577158942740322734305171083 +add:23489078790493512251447591514734933644032,5044415728397642226681534366309793929319,0:28533494518891154478129125881044727573351 +add:754857260375845266559134913354911,-107973684581827631710281010202379896,0:-107218827321451786443721875289024985 +add:-315532494063826496737110988346555619786454,501129324903842341869098009302271432013604,0:185596830840015845131987020955715812227150 +add:92594285071838024355958905365280662316,2187702621551700872791380132896499,0:92596472774459576056831696745413558815 +add:724288898592047956308741845059503937300137,57590734518283929259390943990555930310,0:724346489326566240238001236003494493230447 +add:2739606628137004623864591349778009,110573647075582659906006861365833637275224,0:110573649815189288043011485230424987053233 +add:-14276517096318036496680563063254770722,947355542566791575863860389736548529916,0:933079025470473539367179826673293759194 +add:2231429252956485218579039663297923538099,-513782743328474567896135012801752,0:2231428739173741890104471767162910736347 +add:-849056192493090160065711552591498902148,570178803220182344540821571410117099230685,0:569329747027689254380755859857525600328537 +add:71805397382388312493912292806954799278,80784372590768053283785033890385062,0:71886181754979080547196077840845184340 +add:88350358965992565491787153066170941,21234283677146108616947794414929963,0:109584642643138674108734947481100904 +add:715269430237566589970907864930513314,8865443182554480537011356202533506,0:724134873420121070507919221133046820 +add:1477643303333104073865392660271903836,-367890944067864281459059958232249,0:1477275412389036209583933600313671587 +add:52217735662219170731154120388630563,-294933344350299941699482081737942598484292,0:-294933292132564279480311350583822209853729 +add:61380058552546011441493813017768437169,2900762818425899718317517551345155090272,0:2962142876978445729759011364362923527441 +add:-277784196782412339397810200390714846163997,57298552978631155824394514405745061,0:-277784139483859360766654375996200440418936 +add:-240135707306520087768252873800163694648274,96353334913929088034747034183526033,0:-240135610953185173839164839053129511122241 +add:5682589714457375725889091714569040,1460653301509827608879103745623307421551826,0:1460653307192417323336479471512399136120866 +add:19638363083802509640291691621245056147864,4211029423275507408378664959653089,0:19638367294831932915799099999910015800953 +add:83194800067935752402123668615503029739,2541880714569630662018719665186119518080,0:2625075514637566414420843333801622547819 +add:5939482394780085376784755590138737708464,514468562230819790647711281175956014526779,0:520408044625599876024496036766094752235243 +add:90204831870247776142696176553164845,448604014584373050945946043173569,0:90653435884832149193642122596338414 +add:-28255771387063942974030915755487615886801,211023308891994717221529619029320336933917,0:182767537504930774247498703273832721047116 +add:757105867421757109115447689795304050728,9406978659060898637265625690923719984,0:766512846080818007752713315486227770712 +add:71046269267930793233803101419359460555523,1066119341117097582611928205374175134353,0:72112388609047890816415029624733635689876 +add:860460409596026218232712913311397528,-386403674339732916173292388406974737,0:474056735256293302059420524904422791 +add:51587104345453069942306514960268280925,7174136164833181606646937608176553464,0:58761240510286251548953452568444834389 +add:646810491958543131766676874643214951350,499259004231242695310290078066810898630,0:1146069496189785827076966952710025849980 +add:855002490358777508650454091557987435,509862775866892935549218038452333306616836,0:509863630869383294326726688906424864604271 +add:106603467132772647500729395434502230590051,-16368407452060510330634069459161959,0:106603450764365195440219064800432771428092 +add:516036973938460113725699447078888101,19774284176043121487876685246833573074044,0:19774800213017059947990410946280651962145 +add:952655868300967849134836490408672046390,26424621652588918937927182288854430428873,0:27377277520889886787062018779263102475263 +add:612516318964652612641515207511494523,9669431975435363339548442466828737776,0:10281948294400015952189957674340232299 +add:312358445059554864178031833622326259,3063646351543973236788253379318869856029,0:3063958709989032791652431411152492182288 +add:21961875002920796735366447872318305568,12735184963536281218871061660462862352679,0:12757146838539202015606428108335180658247 +add:-76958222715483937218117123118097824686,-94131755294315965491758099750033439180279,0:-94208713517031449428976216873151537004965 +add:9941064428919490001398667535954444,6153135198163214971541929596372799080,0:6163076262592134461543328263908753524 +add:3831883399874967153073325466609079148,532933850230226797587412822078065345376,0:536765733630101764740486147544674424524 +add:-50281475345524432188122843117426347,-9803783578868553758867748377042263121,0:-9854065054214078191055871220159689468 +add:834761861391838835749698262829275672420,462418116078562931546840078329636278799243,0:463252877939954770382589776592465554471663 +add:225390444541945757230864160941425071753376,-53966286270122861338860835026614792455718558,0:-53740895825580915581629970865673367383965182 +add:58072467659883242067246942042391055912061,6014910057066062653667358884004188529013385,0:6072982524725945895734605826046579584925446 +add:7983230467245365113789955920296234304,82831178283927503584223331110953816965231,0:82839161514394748949337121066874113199535 +add:-45132067499699119195319118239527377040857087,55414967908829898692681772863326254754,0:-45132012084731210365420425557754513714602333 +add:223736085581687840223151741351715016762,-234872704339511023869747996243506715388251819,0:-234872480603425442181907773091765363673235057 +add:28507472864431142856885789471402326707231,612001776806865658512116926003228872602978,0:640509249671296801369002715474631199310209 +add:181745193154135636884034106408465870431,1377247390938535372211751085008319196,0:183122440545074172256245857493474189627 +add:-4269390869184529398543606143750267674905,7096165581548063546128304224326254363,0:-4262294703602981334997477839525941420542 +add:679756117856607689911810374667015768583465863,6873132770775601366558132717863835975030609,0:686629250627383291278368507384879604558496472 +add:68811928716841819374127395790718594105543,-39375978475154900824641971995674964440336,0:29435950241686918549485423795043629665207 +add:-544206255007274743273093190267769706102594,-2633960527489961764864800511887586286863,0:-546840215534764705037957990779657292389457 +add:2104363621112481255876148263045164671673,3455315958528890329983695074392024415,0:2107818937071010146206131958119556696088 +add:34329184450930780849723051315762611673355499,-7104639609931302899460488253298995450,0:34329177346291170918420151855274358374360049 +add:43634150371577068764686894937264376668,-11959554165007875996906989926905112,0:43622190817412060888689987947337471556 +add:5024013516582802239298322665096973189555767,2088517329172254514727438561881167273,0:5024015605100131411552837392535535070723040 +add:566562417680186012953839263884602744810,7199277629017396422779479852344452527,0:573761695309203409376618743736947197337 +add:638955594778655267039016164163448484433233,14647767846572475359605733710956434972995,0:653603362625227742398621897874404919406228 +add:892892418549132886737629998256603006,-42420003645924668249063343987514804160205,0:-42419110753506119116176606357516547557199 +add:-345020858381297450936373802134725158851,-859477477801413864204931138561051434211277354,0:-859477822822272245502382074934853568936436205 +add:91737862563680387690935307847429742390,-6404695075658291424340413128158568521902,0:-6312957213094611036649477820311138779512 +add:-5423452022691148500208482455973347475028667,920708388791651749460962831411085083383900,0:-4502743633899496750747519624562262391644767 +add:8150633265487263016893827297406214487098531421,693305116681597826454527918912884500199574,0:8151326570603944614720281825325127371598730995 +add:-533542099871802731282960535234702413039265823,723089355050948526591740235214878409611,0:-533541376782447680334433943494467198160856212 +add:-87660042403521352943774533787359048954462,23205508268059470425857002842150306009,0:-87636836895253293473348676784516898648453 +add:611377119302093745013583546645763276869536489,-24306437719460476886753515868367600814,0:611377094995656025553106659892247408501935675 +add:4077104707730979108276738109711194036126856,11060272475917992334991062931569856434791792,0:15137377183648971443267801041281050470918648 +add:-7573466809324629854537923630574679416,47863519134315568229699768981973881143764,0:47855945667506243599845231058343306464348 +add:-799102320184378863119971307727324658691,-223055933928835873102241901074720286440913,0:-223855036249020251965361872382447611099604 +add:-892554445176156160154245376649692459,46912675277606111189784511368222685137077,0:46911782723160935033624357122846035444618 +add:3026665879602974291587291059690414946715394131,369940715997138180165001378043470020585,0:3026666249543690288725471224691792990185414716 +add:884243222337379604041632732738665534,784805891181951699244456801706510227963,0:785690134404289078848498434439248893497 +add:6161631921601317978027999219270688283511,7540058790546974071130804326383997513568,0:13701690712148292049158803545654685797079 +add:6921119983791225541212197181924239508872679243,1418358920528247154891120491105704894,0:6921119985209584461740444336815359999978384137 +add:354562064037463731505174515681520375545196955,298046963066931310381553348264288949421865,0:354860111000530662815556069029784664494618820 +add:9118288949631130571307463256861936097477907856,811804191882243735414480051639019704082019,0:9119100753823012815042877736913575117181989875 +add:12323504604096011377318065801800362182031140,8419570117283520873564639019491515440808,0:12331924174213294898191630440819853697471948 +add:40282114774095347321311816032119808177051,9392020059227568760693643864091980296962225,0:9432302174001664108014955680124100105139276 +add:293824315258364662435205611375731221153259453,69936479932599496690415175383522476194836,0:293894251738297261931896026551114743629454289 +add:744437789281951089483978067750841678986225684,6215758092668446071515969246800386681388042824,0:6960195881950397160999947314551228360374268508 +add:7555232352218578953388426959061233639843,-338121179318504388356512546357851050384,0:7217111172900074565031914412703382589459 +add:800786123647331529935991527240766809126924910,8084356801391362127584834876216208164918895003,0:8885142925038693657520826403456974974045819913 +add:10929663989202222972072257796740362711,2014764235099935818353734632287788031375,0:2025693899089138041325806890084528394086 +add:-2304110026472565466976559294239050373788594441,95118068539305153789040528913479244781984827244,0:92813958512832588322063969619240194408196232803 +add:92970515686777203278075298872457538269139530036,804034060487391950939245065492783268785530482,0:93774549747264595229014543937950321537925060518 +add:306074026230996345745669348355571285049,3351194990528556941059979503062943080591380,0:3351501064554787937405725172411298651876429 +add:-1801109034823531811485037478828625593344102,-6788371291545724511455362562828939498570517171,0:-6790172400580548043266847600307768124163861273 +add:9906924561298959226824383647599274129900,46505636651150809672589883942989253631123,0:56412561212449768899414267590588527761023 +add:-532368057068285718080209540340159606385179953,78439393969883180556469736987530860427701949507,0:77907025912814894838389527447190700821316769554 +add:1457791796516706098588078441562863530737,528666216820331549882926030036885918841998977,0:528667674612128066589024618115327481705529714 +add:47587357391699836981813632674062733663847158658,54288315220694727806529289306655335607545661164,0:101875672612394564788342921980718069271392819822 +add:2441679111284579236791979326321319109424,612350380810923282381362835527975935997871963997,0:612350383252602393665942072319955262319191073421 +add:-2297182432664233691613076128334534556985403,311366264931073208179039511983011701314592621,0:309069082498408974487426435854677166757607218 +add:812480504283331455325441717008120800963079831,821134520243619144054746507506987541221,0:812481325417851698944585771754628307950621052 +add:292567021381222422856988422202010933008593,322995618653906543956044582847376714984579,0:615562640035128966813033005049387647993172 +add:331282545048545544767134884053522581147,5766236410336035826171861644077140841513734,0:5766567692881084371716628778961194364094881 +add:40252183714117806066401858275236076131151,-72745188677928192885457824316277110692234611263,0:-72745148425744478767651757914418835456158480112 +add:46457019922262916743996775404831914092936856027,6315416110239465669051340102484371408912908926,0:52772436032502382413048115507316285501849764953 +add:5466283595093360991616260159696927423349371,9668800763746329080816551076148727500025,0:5475952395857107320697076710773076150849396 +add:19669588483473218340912326281765015036658,6428951178389068517174516071634753843412004200,0:6428970847977551990392856983961035608427040858 +add:-81431110841967281357837413471759747002352,59367885431507523151090269106192098957070,0:-22063225410459758206747144365567648045282 +add:793131141187380089412901409250143061286,49410607246090035402603177567556059311746,0:50203738387277415492016078976806202373032 +add:494932333118909260725671042445153518250291,4075181671023511749962590099189964240222,0:499007514789932772475633632544343482490513 +add:-547362235549081743238187402052314301548,927175407052843450557369599383180954617147573544,0:927175406505481215008287856144993552564833271996 +add:-272998916785610528588015856567128410368677679830,602403911895041304594532488687738325572579146,0:-272396512873715487283421324078440672043105100684 +add:8177918913965812142072794805257040419006,838843558448368858294329869233866828152454,0:847021477362334670436402664039123868571460 +add:798568364983632999724049529535252351299484436,1636919605401113337112219636142485235118757683,0:2435487970384746336836269165677737586418242119 +add:4076227872389818674764507178478356204607924906,4858120806733600624675339938519375739087835150531,0:4862197034605990443350104445697854095292443075437 +add:-58122662125434671011329360835993435253491,73132097808279681951175475035160758741946537,0:73073975146154247280164145674324765306693046 +add:733775087409818416274588823315348054416,97371071518767684325114545482209171317320411,0:97371805293855094143530820071032486665374827 +add:-113771533173503933275852574248237858610647533103,-12104130628645378506655176004172910468799298190,0:-125875663802149311782507750252410769079446831293 +add:19142539887689220939206017561014662533486,24783822476272570995796547534197064407548413574,0:24783841618812458685017486740214625422210947060 +add:439837175373522535394537896444136762539607278172,788273119543040327881133870675846687731,0:439837176161795654937578224325270633215453965903 +add:-3980465773532478253498557952430511370686544744,-22356254466454106659993425179664976374433,0:-3980488129786944707605217945855691035662919177 +add:9650385443349312084379714880369460479489737296,6396197664786865714161963852384918829120808565316,0:6405848050230215026246343567265288289600298302612 +add:894227798078569418728694383878564021992203400,1182303697127187181785402622190820894529084,0:895410101775696605910479786500754842886732484 +add:-4968456861598503731688245766554869039074227065751,926904708071249932339986591447176660865869610,0:-4967529956890432481755905779963421862413361196141 +add:5744863136870997246649436419851337184337852,528486352801627277403411298307704227595528990,0:534231215938498274650060734727555564779866842 +add:5651588707112308839251664128448753689228260350068,984180076053671456754725942868445032681314220925,0:6635768783165980296006390071317198721909574570993 +add:5999152998115672648494375904218236573991007462,-15627181548166981556755315951112371297310,0:5999137370934124481512819148902285461619710152 +add:-37220135577661031799960043003324908060140177399,9970705541292214994356839103435039397499,0:-37220125606955490507745048646485804625100779900 +add:81418507001304873846314147833079242440551,32906438533170379081041165307454763260134,0:114324945534475252927355313140534005700685 +add:-93195022996360129134236780916054647692069,5347394971811231651758505656470675163708448894939,0:5347394878616208655398376522233894247653801202870 +add:605079543296413508307097975102518892738230991,-102491396779053720487374578863736177412235,0:604977051899634454586610600523655156560818756 +add:-110305166634594825509078326414660546828041104,253473010673771926873011949379610506924336779901,0:253362705507137332047502871053195846377508738797 +add:21931199654933572392043984306892711921146445570,2907527660451297402481924885414001739485555606360,0:2929458860106230974873968869720894451406702051930 +add:-81846516530505341747573039394704262141139282278,119414978059342373259474020371815492807938,0:-81846397115527282405199779920683890325646474340 +add:-7594376981942593652353502069500431608125593919,51500020414584784205697427672128650432402168,0:-7542876961528008868147804641828302957693191751 +add:136465982599750396225253353955535355661156027759,5386715282857389783661176620617283963576556199,0:141852697882607786008914530576152639624732583958 +add:960930288983993235515929578403745857227039650174,201668060600182361443839360602375118505473666,0:961131957044593417877373417764348232345545123840 +add:927399705750647791187277745876572384967669031,-673794088022646279670235088913126760332168167,0:253605617728001511517042656963445624635500864 +add:7745147274519362522020786496011332545870526042,19019754982701808405498074108182013455237249,0:7764167029502064330426284570119514559325763291 +add:-842589681484827364133898448093132213715096,66373404917619583079354798332238441802307622071,0:66372562327938098251990664433790348670093906975 +add:9158459055331725756564214096327568283821833271587,-7389288408299737295395199016916294076133587,0:9158451666043317456826918701128551367527757138000 +add:4944028992893254151938145908432799220246101,-436673227225833465221751159174587350069599,0:4507355765667420686716394749258211870176502 +add:85957500826134796993374704843873074932736702843,-4737398263551254522274364145346551611616824,0:85952763427871245738852430479727728381125086019 +add:26693268270411692795540232504436733736819493,4761693453843664104004802004918903884493929,0:31454961724255356899545034509355637621313422 +add:597280400846352101193980095689737150106994666,774020411370064574149407278425457714972829559066577,0:774021008650465420501508472405553404709979666061243 +add:626155559446956944212578906031124683128572,190636244537054762721029791162041488568193458261,0:190636870692614209677974003740947519692876586833 +add:-51338951497767599237983853763132687032134115219,68079208415865834874846470899944876794467826,0:-51270872289351733403109007292232742155339647393 +add:9281945169594691475182670852780411412286110132,4120131010237928269938977002467007362193300912745,0:4129412955407522961414159673319787773605587022877 +add:144444680217834068698978156521073014198828507368215,23691353332382600912666065659579140865069030,0:144444703909187401081579069187138673777969372437245 +add:878907846660280522460467125993162483781740948299,5727027980609935208356763794713340938325393172,0:884634874640890457668823889787875824720066341471 +add:3863121890985058037468197591726440896929526748,3838808795310625556439132045393084001945658165756,0:3842671917201610614476600242984810442842587692504 +add:-43851511659924905732938464166653593999167629,374198438005814389346971540424050513685984,0:-43477313221919091343591492626229543485481645 +add:22107098238291185428187231696045952139458647,-1094439233801215665665730295403509442215518,0:21012659004489969762521501400642442697243129 +add:-94370080435346767326735355398641314752346677702547,900650711826114107815166281187719185619458093712865,0:806280631390767340488430925789077870867111416010318 +add:70130581982287853776073835767285560754385359048506,-532362174374052657999220752357898449008895,0:70130581449925679402021177768064808396486910039611 +add:368905471254498539128761742427996559644271835585,271908988467870372234177722038239359722817938904087,0:272277893939124870773306483780667356282462210739672 +add:1665461612154764119629895499464633250637874,19134987808509688322855052440395621824879039321919,0:19134989473971300477619172070291121289512289959793 +add:-70082361212896736227109455495902573787866185574,63015365869689393850987592591316804653013263,0:-70019345847027046833258467903311256983213172311 +add:-25078358419757381745462531594488486741766002505050,6161145995589782600946047354747671861460817403,0:-25072197273761791962861585547133739069904541687647 +add:666708317711411288619476006374466033771205130,781945629304382958374150588014142227194285896984780,0:781946296012700669785439207490148601660319668189910 +add:-792815175132398652587456324873505574700585654,21786271555833620127501336636667271735069671301676,0:21785478740658487728848749180342398229494970716022 +add:8661916666639431619374961032583120863479342934873714,6870583561131081729711383493275798626139956,0:8661916673510015180506042762294504356755141561013670 +add:681924022906622856896996499665629155099035690,-1004571345497457234878302490699035957625595966418,0:-1003889421474550612021405494199370328470496930728 +add:60230268321104247199768325351860140731648751905,-4983405216089518546950014876276513305697847179,0:55246863105014728652818310475583627425950904726 +add:2918902473029364921844125458709973674625996417335,-2210652159145259648205005443331558229225741752,0:2916691820870219662195920453266642116396770675583 +add:6803277105307410414680931382137753681870063418,-776208865523397828037840355299954380619094803,0:6027068239784012586643091026837799301250968615 +add:-25003719704019868385876356333662873293268630766666,9372027355506508855692368294638946856664530455245,0:-15631692348513359530183988039023926436604100311421 +add:8627504130949202764401824904787234047442744,-5835544012798417318076520693682832657982999792109,0:-5835535385294286368873756291857927870748952349365 +add:8260090424580577318194392652868871801866634,36338984070638282375666743416237170513165272265,0:36347244161062862952984937808890039384967138899 +add:-2567885127747973574087086225772899311267410108214,5508239791588330680899787231378688448833646,0:-2567879619508181985756405325985667932578961274568 +add:48666808545649708354733246480044529199921866,13005891966314816519574625124428351433895270842,0:13054558774860466227929358370908395963095192708 +add:8389420702531793876639200928278611121728614873,72321325080169680993090249289587185602319073066286,0:72329714500872212786966888490515464213440801681159 +add:65036752240714453689171239051023570841745399448,28805290908818160518681925899689595311583946916,0:93842043149532614207853164950713166153329346364 +add:8528322759745304970664183606826265148753341767,5634304035479369557540127200029887348029829,0:8533957063780784340221723734026295036101371596 +add:6995036754431505162769439569653358554669540097656670,2722846684750068252266709009646270633127873447,0:6995039477278189912837691836362368200940173225530117 +add:4614880368095698349182582007399802736977295545255,11355964798518264828005986699392784240730268,0:4614891724060496867447410013386502129761536275523 +add:9765319509166162487395146409291488887181479800078357,56035915231430273323816838439018348917266581235751,0:9821355424397592760718963247730507236098746381314108 +add:-1138347106436233679061275009102135358639634924718224,46159563323218296802052742149061303164800629266863,0:-1092187543113015382259222266953074055474834295451361 +add:745228794745562968451209928390566434920348152,53527148122790166734511060330707072382963660028206,0:53527893351584912297479511540635462949398580376358 +add:-588301306658858069453782008551175393534786100,8712212161075124266879455562405482117241102217433446,0:8712211572773817608021386108623473566065708682647346 +add:46121030188079872648021130753538085801476800798517,-39019521584656792767403515534426019969693675753732245,0:-38973400554468712894755494403672481883892198952933728 +add:29619919729277459435885608963790118777332486981,-52524378650492377071821593603303584552489704670,0:-22904458921214917635935984639513465775157217689 +add:98181101791503545628614157059694144214397756,1723001921171301726556866325501042586856901467,0:1821183022962805272185480482560736731071299223 +add:5153029430313427472772415517579200893432348228326467,-1040085720098897906942859081192037450000456492060,0:5151989344593328574865472658498008855982347771834407 +add:55004581470141018296263456318558804429110712,19377908184204050840224411596809648305527908013156,0:19377963188785520981242707860265966864332337123868 +add:1072136046766180220620214293788952197166650,-213267489440701336454712703551017176911643371,0:-212195353393935156234092489257228224714476721 +add:85287699588051450238950600525312209592474610983306876,517154134935551400902310308900510987679476894019343,0:85804853722987001639852910834212720580154087877326219 +add:3350463350046534274745259894989563302676256855267,99327287030974528755979749538531148523479743562098,0:102677750381021063030725009433520711826156000417365 +add:36843614050676239637380078007323912504843199635073,28079537606053733508869174435690016524431336472901360,0:28116381220104409748506554513697340436936179672536433 +add:626594076527207859168744152946567653623622813350,289789726716786201909677270796703151236725201042779,0:290416320793313409768846014949649718890348823856129 +add:93605170968295281833171644687712829154123033934,2543628559470582895074562108146894775567883682,0:96148799527765864728246206795859723929690917616 +add:2052998161971266479740877443236081325994829866117101,3539290099275844711415812545767592527236681167098,0:2056537452070542324452293255781848918522066547284199 +add:5417604415616705991065803076609145766510431919,1353196489306588682358657032784715674378273388275,0:1358614093722205388349722835861324820144783820194 +add:272499404407187599426080423265627888541662659954,1327146833710771382036670351680559306817615656153,0:1599646238117958981462750774946187195359278316107 +add:-699651119896474314900584685497791738111506192,-69672515802110594977623027100779022212514726206040720,0:-69672516501761714874097342001363707710306464317546912 +add:712509548377940176185869895492904750887086413,56176731066398404861602715769426642572627041935026808,0:56176731778907953239542891955296538065531792822113221 +add:7143592025239088040306437550950750880457741265799,79269337742179821463637514051770454228086789838,0:7222861362981267861770075065002521334685828055637 +add:85784228041270748531044763418005303861773086316768,479955707155465525495908770086376625866496445325,0:86264183748426214056540672188091680487639582762093 +add:8633607053652219081012560844815432350350653816,-27730558580923841131198160035073520602640809937568,0:-27721924973870188912117147474228705170290459283752 +add:86298209842676209783265202243860839968224984059,-14653841574444115669146420066088654283351629895,0:71644368268232094114118782177772185684873354164 +add:625971576355871986206876583141040580270991368399,1591656865887426266688630862274904247349299714291874,0:1592282837463782138674837738858045287929570705660273 +add:8094263949925391895110456153285525932274467906035,8828498248880817055759174086148047904385900536902829,0:8836592512830742447654284542301333430318175004808864 +add:82237003877466505256157158841093493965062954411803144,91547031285735648783322726839616156920221022695429,0:82328550908752240904940481567933110121983175434498573 +add:9037532307369285758380237914390337810953906576116947965,-2080798311402701935902060326222031250344403292352,0:9037530226570974355678302012330011588922656231713655613 +add:50808222368724781507631572923387538639418605384327,2105468684081970883293309501603862482752205466,0:50810327837408863478514866232889142501901357589793 +add:614695843041957442246110545422122115064228337420826,4173998806904671505997631134479640680904576896439869,0:4788694649946628948243741679901762795968805233860695 +add:1064820342923287213463623720132244635622458829981525933,-1475875068811641600756631104502187851477440325297,0:1064818867048218401822022963501140133434607352541200636 +add:10157417423684726201410937603631975742627908169404,7838021453657103572002203182188244231243955079181707,0:7848178871080788298203614119791876206986582987351111 +add:37159508474657925925316976495629749227380940275864026,1962232433094621175896408173610784235423834821218,0:37161470707091020546492872903803360011616364110685244 +add:90799712490109616993113540668118622608569993361558,6473804353031813836768680654473327017068712061,0:90806186294462648806950309348773095935587062073619 +add:8558267182043409385092694859321311049409595764196,-43855190592575763264725873745536703978426263630380326,0:-43846632325393719855340781050677382667376854034616130 +add:8862769280704424674067234121859535881853068385985015416,3128430671333004136364095742988724990646419068,0:8862769283832855345400238258223631624841793376631434484 +add:378208270494674096813484033949342736267924012919568644,1144519071359286777414333143799173474364390418550794089,0:1522727341853960874227817177748516210632314431470362733 +add:-6579674113733012078327119937146015198044119737,-3734798125808966311088975985514063521776488722551148716,0:-3734798132388640424821988063841183458922503920595268453 +add:2960711245597899800032622343542149905437203154361936820,499809669955373495757639913113238315793000498691,0:2960711745407569755406118101182063018675518947362435511 +add:25821180677407112730506355642526955953730655437874901,220829252352340433327709631917215008695896671223582832,0:246650433029747546058215987559741964649627326661457733 +add:4105370173243521757766753923407753132483088841573916094,-5859495212721416724385219267491089611350684535452912,0:4099510678030800341042368704140262042871738157038463182 +add:5163869845851925892481681950908088101067549260179722231,4902983733534376916005427640372005698206345908473,0:5163874748835659426858597956335728473073247466525630704 +add:8939484182366010380381840561998154807909027117547207,-5791890006411319753232065830229236658118816108248,0:8933692292359599060628608496167925571250908301438959 +add:701510238238697450550654709447628676278557462178180,78660480845787107751570298546903383688737254959620217,0:79361991084025805202120953256351012365015812421798397 +add:341765117982065537129466755082499645994576852735,692520757209429295113115688021272259739538890867946,0:692862522327411360650245154776354759385533467720681 +add:-4895783578731845919967474094433303503864596778179935462,-8364042240998784278401769408809806799945229261776648,0:-4904147620972844704245875863842113310664542007441712110 +add:14238409419953914857984647802372979092302755219238310,6371574430505907367749465495358382099864633219840163,0:20609983850459822225734113297731361192167388439078473 +add:819145829642159547700859583648855896951539123580831,361506805586624128214007976586393021628930076090363940,0:362325951416266287761708836170041877525881615213944771 +add:1877636417667934516336941709697932194927216313530003266,3110415340804941864303432168123355167418335131760417702,0:4988051758472876380640373877821287362345551445290420968 +add:7672066575928913691752679142441515012172611183558245718,371851147532253430639711983046051123330781047618685,0:7672438427076445945183318854424561063295941964605864403 +add:95512312207249366298896076611182343964081859466,-97124870343231010626703079092608549509450053912,0:-1612558135981644327807002481426205545368194446 +add:-5806422968663023549900750663638875296207673594658363702,90516128085557874002777142664275230359248090059,0:-5806422878146895464342876660861732631932443235410273643 +add:-1527157822675106197481254438080912892158041984128532354,725563661143607175528703551625121106037288811283,0:-1527157097111445053874078909377361267036935946839721071 +add:-42827691392859896582177202183556705231114395686423,45128827735882217281406911116739020388874185279388551,0:45086000044489357384824733914555463683643070883702128 +add:46043838505488963276375641613705710661972295575962167,28467164488355628577488094369127349235531802379663224,0:74511002993844591853863735982833059897504097955625391 +add:-38951950148008162832054098288607961881664530927148,8335283480464728668637429037127284541356281150509317,0:8296331530316720505805374938838676579474616619582169 +add:622249316814675692027128671081941223678839381254582193,7261720220517111354905851547139726385938166469124332501,0:7883969537331787046932980218221667609617005850378914694 +add:3674907036214085782411042221746956364413334313796,1921363713435768167432104932165249283578036436190717,0:1925038620471982253214515974386996239942449770504513 +add:7188482591275581867180190647387989483887113319876542897,6602680320762178166851882906088739930967430231717025380,0:13791162912037760034032073553476729414854543551593568277 +add:-1122742189773381273084251248143689561591037547534016,-968674210476153943757292285354448302755574664218668317,0:-969796952665927325030376536602591992317165701766202333 +add:-5630591882567573704954413450307476327113066874903314334,39824636924677667925199181345729096573735144801160,0:-5630552057930649027286488251126130598016493139758513174 +add:209583289465308712087487686838240265261210109472315151239,81969909236232824125903325576417695025146872644272065,0:209665259374544944911613590163816682956235256344959423304 +add:647747950632636576869808198783011688046450148232434870552,916898592764747488235431320315097102338752371550,0:647747951549535169634555687018443008361547250571187242102 +add:28135712883527960051641471442637534495815689268599701727,-38552244671238077902324238695360695260926661808213,0:28135674331283288813563569118398839135120428341937893514 +add:-831441344128176770720666876352870008663528096084544984455,-2692062828036480019863362944971350891750264323444185775,0:-834133406956213250740530239297841359555278360407989170230 +add:794701017798083397494303069423796491577530373372626,-72102207786198755767165144812992747956259847426428,0:722598810011884641727137924610803743621270525946198 +add:197485890851875072994741135376825653896503519991,138163469337810386780302197638192920802358090884502167,0:138163666823701238655375192379328297628011987388022158 +add:937892167666694076995649413871805692261114284540745180898,484506468570589158974739913192421910069689875922723630197,0:1422398636237283235970389327064227602330804160463468811095 +add:49513458769560636111865879434482526113781325925566233,9100294802196263191040735829862469546124284819589,0:49522559064362832375056920170312388583327450210385822 +add:6804265638701156312303584072108871897818849901582,-11345730118278439960458447085533973659139348981794,0:-4541464479577283648154863013425101761320499080212 +add:51279593637893634015629961349071462173442991832147136305,-630963561638139460898375258178326027272464749013574827807,0:-579683968000245826882745296829254565099021757181427691502 +add:-171297863190088468833128267336456231676696349106086723,25562345013839243089120015450478579141692354834498920234,0:25391047150649154620286887183142122910015658485392833511 +add:236820721337287547681130447452461282950000944868027,7910172708500900617141147757503793584328456508673025,0:8146993429838188164822278204956254867278457453541052 +add:6265195034976332988146228918664074473854894060855990323,7606251428765818252926521082377358210182682774550344917,0:13871446463742151241072750001041432684037576835406335240 +add:89597374568972918585799186543628138088356766678901,1813314149334378741507569909010462456324603409087645773,0:1813403746708947714426155708197006084462691765854324674 +add:195306949022209072289234099720202676610869290157465206,-994716438467019815849178678443452892613653602203942,0:194312232583742052473384921041759223718255636555261264 +add:-939205563958045162651332219711896963000039406190357,563202907700832072617064560363622275558376679989258989,0:562263702136874027454413228143910378595376640583068632 +add:80098286952047593891272622966959373457660113936107,5904947277434951020763542155046693897001992702425164,0:5985045564386998614654814778013653270459652816361271 +add:19798014000926405624727315383918920042183182364693,6487262615903993794908286483828887670955698777423148134,0:6487282413917994721313911211144271589875740960605512827 +add:84945814099981001691936754290990954291541653727223572796,-456805979472350610125202046336073888213752286874218,0:84945357294001529341326629088944618217653439974936698578 +add:2512089645159345096564730857111312670343564829071686,2455481799353124733391499423535890463012321535291607772379,0:2455484311442769892736595988266747574324991878856436844065 +add:73301381174453517580526931086388280775135813526768,4626165037419596821133153230043681255350276120564978,0:4699466418594050338713680161130069536125411934091746 +add:792820818959899903274588755045896284554931997668781703281,2595874074799206526967637468037895862567437806098280407872,0:3388694893759106430242226223083792147122369803767062111153 +add:31597081840709827246680247566853001879220752914725613176,2390964620594830956235541402980808255816375199839045,0:31599472805330422077636483108255982687476569289925452221 +add:31597081840709827246680247566853001879220752914725613176,=1,=1:63194163681419654493360495133706003758441505829451226352 +add:2037822438092847430389261539441146424774943894590,39916000644658200588230707520252700806573106896546,0:41953823082751048018619969059693847231348050791136 + +# Small integer addition tests + +addv:51776377,-46479,0:51729898 +addv:7494538123,-48092,0:7494490031 +addv:5,20101,=2:20106 +addv:626,15974,0:16600 +addv:927,14290,=1:15217 +addv:71398252,45970,=1:71444222 +addv:93063,60606,=1:153669 +addv:-4895,63134,0:58239 +addv:8033997,6091,0:8040088 +addv:92778437607,15749,=2:92778453356 +addv:807578710629,-16317,=1:807578694312 +addv:6722,34150,0:40872 +addv:484482964826,45791,0:484483010617 +addv:63333,19921,0:83254 +addv:757593394565,58611,0:757593453176 +addv:5848315192249,20055,=2:5848315212304 +addv:21778,35258,0:57036 +addv:639687980,-1547,0:639686433 +addv:-8993430803,-39481,0:-8993470284 +addv:-825483,40649,=2:-784834 +addv:375685401,51109,=1:375736510 +addv:134791583451863,4578,=2:134791583456441 +addv:53129115309,51316,0:53129166625 +addv:471178234304,3338,0:471178237642 +addv:-7636956216875810,23137,=1:-7636956216852673 +addv:-2312413443812,31719,=2:-2312413412093 +addv:5200691919,55510,0:5200747429 +addv:5715872742,43764,=1:5715916506 +addv:5568388095431485,6290,0:5568388095437775 +addv:76084126643,54578,0:76084181221 +addv:96531391779281,46438,0:96531391825719 +addv:-828922693,15465,=2:-828907228 +addv:769843302686441996,27790,0:769843302686469786 +addv:1414000736454,15931,0:1414000752385 +addv:606227414766,517,0:606227415283 +addv:717100323961,499,=2:717100324460 +addv:-85406334226225355,-50533,=1:-85406334226275888 +addv:-3753831486,-36277,0:-3753867763 +addv:-58465715745893828,12779,=1:-58465715745881049 +addv:2855399155447860,5468,0:2855399155453328 +addv:4552049505281749,-33297,0:4552049505248452 +addv:87837072754930,40967,=2:87837072795897 +addv:-42693214607695890,-30492,0:-42693214607726382 +addv:70742576302309,-20599,0:70742576281710 +addv:118600972756003,10194,0:118600972766197 +addv:-882812251166,55167,0:-882812195999 +addv:-416381834108529,5090,0:-416381834103439 +addv:2956620172683281,-15742,0:2956620172667539 +addv:2711117679184010399584,9500,=2:2711117679184010409084 +addv:1356315685039,40425,=1:1356315725464 +addv:100388100074891247,28468,0:100388100074919715 +addv:735453579551845,-55120,=2:735453579496725 +addv:9573520208716968,57962,=1:9573520208774930 +addv:22464333496911435917,45263,=2:22464333496911481180 +addv:2318330134061664645524,35817,=1:2318330134061664681341 +addv:40085116522469,35577,0:40085116558046 +addv:-9824195637526213,46625,=2:-9824195637479588 +addv:1387219546869173,16428,0:1387219546885601 +addv:519326948996459554946,16498,0:519326948996459571444 +addv:901089575144273153684,48818,0:901089575144273202502 +addv:-7267047498859484256669593,10213,=1:-7267047498859484256659380 +addv:2746871124496359442,58189,0:2746871124496417631 +addv:-1505797511965887167260747,10886,0:-1505797511965887167249861 +addv:816815491488878842,49097,=1:816815491488927939 +addv:16917424131349552780253,38836,=2:16917424131349552819089 +addv:957454833834708924361,39916,=1:957454833834708964277 +addv:202026277214860503572,-38223,=2:202026277214860465349 +addv:968746861113481671,1030,0:968746861113482701 +addv:895889431267844251,44333,=2:895889431267888584 +addv:-3357720693387242036833,6150,0:-3357720693387242030683 +addv:659201417242721199959654444,44813,0:659201417242721199959699257 +addv:-400853063392189225718219,-1010,0:-400853063392189225719229 +addv:7218879194561993107952676021,-44154,0:7218879194561993107952631867 +addv:4721568551140507782,28030,=1:4721568551140535812 +addv:17034283717006469465522672,-11569,=1:17034283717006469465511103 +addv:41795594273804830816397,-7668,=1:41795594273804830808729 Index: contrib/isl/imath/tests/bigmul.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/bigmul.t @@ -0,0 +1,10 @@ +mul:1973284924569393016522181930166284437824113120930085705223363410232863255766399553325346410701486329074823374249547700471683909277697787590783678904983357211584574690370289495346677331618312561665754485123402827162476353576735207718451299565526093115255556962215997764515429748902159033904867393928929335369918394864191487555087825530530292436823694624357846430402766705368186347858763649288740551240105434820489955559033038872623623075504620415436212337263593361227009430895404467373404212231777284568356947010238293550872942631550054733886261493387307990754063500729850132294968984927109971586336754260617576297578,5023215555039217191451486096670046812323372237867852342682903508090873804207633443539517026163606065770027196694503291009850587117226026773591715017125540836707619882023150680605967194554434367524090941938814045780235333982097410791452776449214446635671357519707417878752761895933104747199582531838714305022614904134506738511247696618513698871318914624938137416674596881724436242382943205716649496664131501091102879563857843031208992280893614063087964394912022421136928015233318011144243860597237613050611024432789921991289922378761307428111094457098264457145099945444765267932710530788173695233378407323077034767182,0:9912235527621363370177765461045903296757346464251250997934314384765381968455767811674327750035883028560327843635490083086230089733649800500491928845965808260177110097000550870708488183060088779215210481900113545281854124601490142211180660492441361405426298053896802091578235012988730731854809702026093664780523793649405978324745399501432045298507869343282835244908856693641856464415460033802080004246708824900236489959461486545994943320360059459917374730418136788819890973086342429995201653932338829740545718352667527142958499428354077966431655595175455785104618218647409782931121099857213491801531717606789462812743975739913830932552436532349361163108142395102143904119547756730321871557900417573185916761969667939077354954258105548072267528998411702020631497735552158986372677452750936969993423245268272976429454770189221077520557005286622417163333812030510164503314440581497599501417407932697447376958591635071781976491704916693799964449632893911830806101578411062044010045678256608720149155356874608716245388282176400921764516344436742619757576145128777884235797616593795005421758664915151768829194432974835591116318659671888399376705850603804666493415116788205809451378581533592708248188469927900316495904963905315042780485196 +mul:9281860481025428743103260720025399298938288092709373682664752121448026422364244176957076161560781963714610840062462308785533773682081509516924811454802263149810015499242805866671806182669824281823377004291671016071522932056033291108610609315306035746008726247945073883264784349702632503413711514594728450092072160898603477481125780254532680608704164997261749601100642928524030186658056860132922920804055208139127600955714414432667835794981195051773905850760614924210968557995928682559530646363463541164514351639956960443946215999260668876064044712007044169839741253208493501852117173644320085073436239558982298112600,6461820852819773895887891707090409545105222339300767589991593922286229155430279300935431963821489860557211392101557073166691740801924350342690481832500741574765066771636009594821433888176432105527291712269105001105197791973525400419521802156326222007905452621388581343089554119326311972031808789454501569850634390353513026195347029048776084662261279361336878277930892526127759184987426337401986666833244149616653136274450771865938000177859526607860886891713725823803723429415374914088095471203681073462945634413721478459297998380784046348477788577160851236668812562054262272695670208399244540961973019014052558168787,0:59977719609253892722042877572104051408101805397813781927843789294722416373486626629774528405272256981042258018309437739185326109543499153652843618549437079862481903741355077622392955980952291940377584494183016978345215858006577896133494138343531131577292900447484484933940153864330993312663423548963573589721592630804430303529313438416057807260878676382165577508312265364581705446497795257921765099792473625934500220786302375753400097833125635066325976636969158668550422583295871444269629329520664064347927080680043172866686997969891857469015379192927001271209231629114491574459392387236668293395718184725588195195152678956030072754849704861168107422055308610203187476081482745232498851974127247916788413967230550779676328898994935061206241398061433819969649590309647846577368325165533615473712118854791617654923496518553311816034223039109644818155748055376095608924486676004240127363839126636148993476097467363646856228375774851238347182483585640237087473022416289005469183518515797794634470718006577945646586807657786278665230204669208538087683902595460600395463199673225484879511079106227162215467672070600187376901683430397215820702335580004490264383605166178465290892905016286750248542616725432536301930399671042547182331416200 +mul:7912472862067339862128371179317677419131938894010486952786566311807271094923069332388514681475314477095129839383791878789616020411634591014351511065638534352498100902940229903010080076033147913858702310386781454704764453620638192722142673704997301635080657906841977228453431784636268795567399742877979696735712353260720882016758802630449316568009735495464820484500112849579042319792054180751808291492597692968145199206126879627571212323371773988020895279516215647740755736659817523229210171324629444663573614970129038286402265282862415058866062409919400686067571225883598025018993264993072866008153094783713777842233,3201725902397772208341447704654332382791919074661304465094673003562268414312780910138677841790209187781035267718271550359273576299056459823432739891496517659999050131295751440278895964609377686119310540452547253245263824257293859748569384694164098523184164132157046027096354720108308754361750383079701345225130461743071738716695085603994849362372761995341700678666090085339160622218852314697895484240550249851988347340743956951710723755778934782102893613303732727155104650554024190836124710855983325513102342105122420688920843770754330984726835478343584190293399561063733594503384748007915045169469662902517503038695,0:25333569314500437108599815772429501373680322608913314601365306943723819341950927345977940371140685035806629270878047237205018842387430734765189552850021696237198239642293495906804381299300903869208226135003940108018078759100293636602524498314852735550782128370170231188998120042175944314926905277276072583015211137886295474308983469549440318811455833426554950412383746982707726227053848985460478532792206103062118340221448441569085773835002535297094293453339349660395100207046263749435022808551287672469069089094272260153240006042417355640412016581090184175248699060812193046639667626562834648506089700951846853126579987123062116039551606757622165057350453806797625779923041984890801656780414838861143950031146465833755299675796593415374155208079244535350498995407594399059593691111928041690837178741233242536763431952235684501117687869354466659838302659999947981358427161420945738762676783164008518789595931971474305683979958242844858007484186182190899873321326797561319701242638077070008212803881009955276396752500690925651017578103332620257046368245654905509937113127728190752471098993165924776064643774593124028657833142320855925010595166301204722218705230663769696225288154861096367993176213914077427256483682770659737804205935 +mul:5808324187702080655474460793682039951322360995931125673869791371944228644211378816153373947301972618673468024419809216698234959175295640166063762988660558965367914554186920892629719688885314609703455963977845612750271884481278417471936841270780965441117412446282412169100969024758168373693942106624503929819630667668476732052476696223555182229399707506392013582768244824407047675765649910095793401597173883674841030712174173054018546762918277235618291532242003800812379951389007164665130775067356573065178773886633889021628231165391459939591112464657659598153999220909590051109791624395690563647765208381376662473375,918729402656599354295427509394488660812811650986545042142269515180033877242550175086096078333116750486296504860969753318764397360672070743283292590583724934273152632680100030114145522324231651230586226973102509131367913652288365962855153489305948459500758622220373494821215068462533405866936756424017653969429333910353069394383604797810245598567635036667927595346004843560767022814009296322200770357321286444971587792559784113298566437496673370692769029520191499051311630305921790132367949451008467412252240244679740653218546677567374795191493091691181895973054804640859501444377706515253377176192389740639658485554,0:5336278211403410225943519042620965615785619555317282219346015490965402490268953491398003239066178293858189178402401757111178985594855165207776985174779911791823768749096812598455271447538265382632879247518155595749750602819268050354139537957357918637213694511920007326845297089513356097333014041709972148731714014484445915988844776055070353805573753587598803658209910219837061261823670768974929077810129897859279877221144040999522002504993617242444634441005711709824155554871737671327646822053264060565735107228683619949429470582056504636832239947839478335167862425087205811476396561330661528512869808146764271405115946216597932921295579405822441084739925916695069723138186232413577801041059512270479551378420195541014794476699958865807286746222858840284109951768425928740087238483028034722002174473841150445679886458245212446868769523239331330174814615221560520986189551103233794829342754962915857263215385954151542007327435281109291419192156862517657537231189038431999019986573647246318902197844837896116701072282756311874936853442457550589683870364331449005930361210722151521672814074171107488735222046242474639960036313988979683887454104915755099621937143196324447593623621066203333451482527676410948714122996747858076347124750 +mul:4289351015617211853860547293440287163118502026849525600172204430479364457520139869848831815115110666309028281362257922027167887676604882712946357785774765671053291569361256480674248716110951095880149104811531028000846825692159030869973707804728263847551536308296065212083263317121194233870838444421131817712327319493025493358961844276996294363551631856740972199816713986701316425469067461982409331003038962007405485449957519072614334803913032240759760944833349605582847295426216585712797815837902507714668306750095431507743637803032894122691956397938532173109072764661515711293817060848120252743975673113125247753747,1129243400327281633151431371474891473455867467281646580615131416918186134500058210362967474476291935913056166817170589720180888384893984130837655605609160519483475686999411456978438146043336536562159220682249690564087391733538120293725815373571240283145745271266418667658265953408844001550460545760069911655331444115026283289502832470850559638590225665815329814544221402813003890575490644213046498706732967784948480361985741430703857522843819419578526133778265155095749489410876608829677795172822626775506026922427707604322446404480105940239935673644113523059324254840712255877427181434254002649024354681415060823887,0:4843721326072859217924739456975877871730592847101085181527790647663373107593901947296442009364096344634703274313593786101304850876247763256161098298112279311640124203085232376040570318789033357875445637660657625729801200284217407957188046703959398051857408830260318911921120701333722007653177281821055544288036482973644506286720667660669123827281708456990562589037743832216048193876408309523302257690396843316573270798223002206543082163754435230120328349462372851186274316082236306199355982964083210551564485517422220956818077182845893000928069354900697467244100517711217647512106740360746188198070167537230256896186561769720724666496535533088417070244576470000350911551644970207092820479716847918547327933258080841778598694603733794328556831506027782599545271976125608421461150637806657972513810116161800305056210665818016285706544698227685536076722128657311114222869723283459946629814469251976435853584113074214728600366960017102944781196949905674572781584251454518622141686465871411947838733201476173396601005947322753083122168399723089970121912770142886331646964005500389958994113759402037759299455183775918663007587029195358902062641122546567477401625532541758569470800211805386875050358317201026695356110634225798225911354589 +mul:2922598094751746153870691566295068444832682377449634443644452036808313025110180304221606287367480270511738542685007831198718549192848393891804644713550364054117828837916381145944541939810080376799967571912016414096689178814643326642017130538718508791191026602318951021214103395742936719511134851054150494365154144550755804519428501885962875546302716557826154750576355553275917160667544245815793363700075966760245307752621192750454214313695198971665682789483848832034351563529541544408090967307450920552147497375102711833800774226189505763460050841396334194550570633737523051548126923180438589141499584449356454157781,301263854476835865302831775981280157037775814731880717517906672139362327909576030289130356551031249856290116188787587208441664042085339381130045070287550419156538713298378724228993892995370333046698005135756870427773491796745257234813488146992861769360888649780752254778964967516001628591841720032608844779416229017746534677888032360001957340989928039014267141513178879025837777147645983010327629059951078283105727024828148762758710195230027569199491918547602586967248624457368763471524299806755969674122616318652168130325681600833992180785147209796398791957157839966041221298841443636110696808763448994316318819400,0:880473167111567810988117967961880121548976598870490103359907404451794288634314088754703982882682833177383915593219929916760062726336137217195565128836228831115945317704393055974317368390656797236936312760587634287099001130993733243945419647905839367532106871136628959505856124206216765869030390930116922779023015952215753780775710838592094598640777970191507874750041226456888332070206936111152887141719425417531881441970211071893599749277222881299254752348929477247066394923935790203657132250180904188191913717059363295447971852930353504673614060561262045695029116400460109271428627838849952738530831538881267424864968780605625590534156059660049417419319454100204293309555760730912655165939915172711384623654862226288504196439643394977024748646967678483943835665120965656012280087576516616128951989019537622931843487928203695095825088113381854602767942831065334578782746652133152957849781352666171117141170614812817658757480681486453133627351917446563065914034736341623821165223200244445057536369218334564861784940394704850907451562300721495943024972967062949640936264682263417359654728928172240308459032455914059483410980465823622773353548898797178794257922243219031264284831902460218578846768551900722035824054391273507243751400 +mul:5926829196540658675475456498963270367274167353270350161220559308972890667000611959077400634022036756298496888045889139127967069561321992685909920175362591913993270611799645183177425442645246583405296832015660977965704980797187259222752640840230405885131399744453603991696537021254629232292058451234918953535616811141856188592686058223965739982132693674564657697584188823828175787137971950097846827086108380914550087286625763777114003492300442812034505494306586173660076762683909293356952194336742697639190379957186138293602890079658463645699601808928093978909018729566309848085271814423786075811123687515222571521141,9951748549035347469939830875084342841213955171500540569908439680913759851880792256750294922770245208009299837781200411491572872855217655269162163547244594548791001649285963901760838066367556260426444830819384430864282488995682230931798936940632516431790824149442647895647799515499501451313199296478183164266650410143061944307590041145587301786773822623122005086984557462948454440882483631228680923933447857195870319437437969503685592935555841532972330863543676262890554252868386868097538156042902583850929860163229668324731088466679335541839144081462858536522998396202372335534127835253275227166439208550011362833647,0:58982313857053834210030369008701535470547846378883471574850906519661590920623239557155133816718872389461593523638664405853333986848705490618952594452832827902837873064739619027951652972791249957555491448326595877448003385631909355204580249078753687938446662770501781443141702574212326646295344874829910024290326910430502035229144841509314463725728935072109280568176044293667824135683356181998327810932214680277918878645875609893787816791489540198200526206052593279579085310784507516815859424425808996966049588369054806335526262661190188588991128921011359320086022801222253658894714772351423922462488376381753960122147656387949595523415175858244128147046721635779584519776716527922563179399569323397526878913784277530861145139796781253014531853594223956266367885067511225156573281630685001517329742811780233540173221050224903621919442416853554192768813644401915841492966828144740472647777117385889467734627421827100398019644421335032837486242511571228006782734808577532905812345873829690513970221918856437531183865939487578348802015996867422278241109287621714275599191991940919835845537011096714711601047529737712802340247704082674118292833054347839678093716883543951111177062577074608322061562989806239684134854317815924284926631227 +mul:4777034176054735892839001319154604024448982911062996662961434499047973311450046365095175854088514975567276445923641765710483565552588310101703859907398033663982963466700114736836981086820103724619793226902430054022230749484829232751622018429096822596030038641334221042974404610831943227778280482931541043539126216389807230921518942393713547539642721143788088068568685638257090375125430847183020265156489658843788411995875911054271475454361570597270062164847413843213234002767652983163982217031030775985346429845722052312845786262475405890214193945400669516695016006129145191835497619324112510419184839333823563038032,9827138548939292009245650065800975788958754975503505329013026058397999436949984425213239460163893334243646132127297454621612856901543246299673374601632283715496329281241648395821925002725694160249373602782352654357507333003611095526709537503510444389839900076419267762739355812530600135102575311854184301816642079363387499882043347624028484658998836131051290010878235398822043835106058212641700259728565297115088713153106682478432953135863939627050490807699853245333608896404452729513744632901892423136011428170599697693508420836045009263224191727733246096441225270861482533930349836055052069956275296881553010823844,0:46944576701107943679938938351717570276643024426351383376012128990331836851800394169999825926287789789923977857842224952030837018641751724128416777942347287817243085205947279140888810687502712653904720940250076045512070807034595001066901214351395013853583253749775182943641508176342644616344704991826014772126193902151538695286620417331840280282729602713896669409104608963314021947099534454163546746786314376632556034151803662894104512257731557376023921031478485341917927131527641804456632089758164963179174829067502841242835472135512255663254933420936078744362206666240251798031087309505320414834036730091215957763177449453464018931816818279479765564154397725457327968428958452351403338069002258937875534583660748382069795371892066725535235829019294948550962261648137489651867767182000050986894967544702207404744805388059998480229757580719768298728934644409403172897264279729988289280804868097625427040524002128803008253639601815039926425566665683322030827022419320049680101981176755790419161472786615666424889499802013777946532365772475376346129529789899467556777542539903184853306724757517591411008018192458452871055585402125971467717860280265556030939477806408511006676155314529119943122617934755061739058181638708393543824435008 +mul:4718526549709911993506825300392344853225467500177328568314994788126810717786579407393677363360732454086076553654622431077040278132967064493298016988387203796834942642515095105038480589941892582203464757978762451494680419073901829593050682173084623555079499639864808992561773015425098686639107710126506218374693057900167675112099207386871851914556838486427512658440072954892382195328941863291925131611709258615015617716874132201457077873908213746723440854928237000349411712082236090494727142820721728009499408048129273013743078395120046662079326001366135078211783789585155007423087104738440174209004586903786989164923,6864909625695099184857987413146793144809795231762816099678934112289429933759119594825554881121839952705699464175423549805747165577308703501708566885788095967212817910018877393281757866693495857986692383902136266802917073126657350936148259550527207353925931727830829709553153285795187708071469565512676957784213778578364574484904487858142015156737351049851111701482889769961092136069932966937675469744753107902213424358119650624652509775218017409565394932197216635621683624922457211807452760603826715508259815323885112220648677904268244358078258267292267766114067884100779411269652418038495358844980710175781452273298,0:32392258330201459760562074159505402666827022332133743824383722373771586724279936834893209475335792360740207288712753288966019272688772189727359830430112385377963211525866654614652734441343015702880600337106757047952016128925022121801109717569522414321736297039964518897435783148195384835215896781072440523968496981818936751998711792513353592722753606646586300140596112682346518934342989922440494425543851079417451668961455337221634115522324089759170630437711987215149300155598498709258144994089401776318144221493654769821130765906090094965112873750275198731396444109844761570671491936925731286931889673265998052517878340520697512644133898593713774598643978958986749813165344980644092219544151830910222269638171801555630525215918638130181021806972858430511411445741538921977552404857036735214137961033740561691592280961494473639844034425651660408422689100017005963792872277451240550916940855637560252384459024952693573633908574846415082397672705378909528200133322572418467010953663042748965810118650644957942518667994045551271839593077571232233290052571470146092765056400446256851048896070598829313006513443533069418336284379590405097307714842901615964467210622771049744023258299567880689880017261076464212353340481079608972991126054 +mul:9351359077717175899950414794158087603156751215661949004587120106073267545901109456791730860642333677736460489711278989024326442512123908471776539363116436679164824939981569343722408520504708037728468632659374071452933990971885163627008124264246742383054580586823189866118106292666120868893909093218961607925558747851310421259521224120112349616696032997520626166708182604366198593113508419711212092952552738381785471705126020208187067765049493707603435017168771840449365758256918178174456397001413868398658687746818925263901770782577181315131090723377262366519979729982933337084774328653741904208050516673656644156545,1216016766515133990299168668478735765845001733139931228142324729567294927452246949091528311290839436344864081129175577116760112996696086551953114162706042576570065867528105907714734959487715485323991160014202401109849117829323361272785163230303985302397208164280805555950490245017175800587222856847357832531423637659868015190810500399483016069191576487343684935319583093232012062136782881389216056886912824752493825582458023165949476390088955696767644291944525456085901327930362230500131946293930906615027984889540977885375442171280684232489081312736136944281636434187988121106769493755643246344604960317372762640669,0:11371409428207585816935645514971157399477456508122422645057323321908767523269456583816541352834881341044768023230578135410646986307902229480486969521756932041792070183404871499743753639195221172390950269396259738917572970086985537003463801797780611812023947668962735701914400160076584463668883897061046609698150079230869671219723047659413380098398681168541189318039580846097222930562274632561522358056585578630564543897574680699501191088545558042869487637213954033470545221407447339126024545625169695761828292387153041130103874335098480537357654083162452706238752455266859966099385082784949007603605080575226559633436587076629170515896969351447588541709062809148081408725380230173050904929264600376981651953193133627520880237674546041286603479563072447211757006563163317121555286268728294863795655638987849849029666001617848646789972884742730075162580289223257765499073795704140984717050187282907922384088916411395714743783224419377067797857302004785665907904680432071096387636727273241941645361614333739368488852077835547570517599052273376169343996742621847611518237883451876811880344515555813725251939567959622992970218067169395450107931883100562142495317614789690641680450835968600224117925675820963997683401725608775582419528605 Index: contrib/isl/imath/tests/bigsqr.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/bigsqr.t @@ -0,0 +1,11 @@ +sqr:1973284924569393016522181930166284437824113120930085705223363410232863255766399553325346410701486329074823374249547700471683909277697787590783678904983357211584574690370289495346677331618312561665754485123402827162476353576735207718451299565526093115255556962215997764515429748902159033904867393928929335369918394864191487555087825530530292436823694624357846430402766705368186347858763649288740551240105434820489955559033038872623623075504620415436212337263593361227009430895404467373404212231777284568356947010238293550872942631550054733886261493387307990754063500729850132294968984927109971586336754260617576297578,0:3893853393532835086992417436028929533017113693729112812565021883956380915141255996799612067028873878620962721020287843580667785031474733116478946359424550361012589585752973317305997480128700704790709288646018647234120006459544716434681174565732418911811134893433511190240729608798717705538511464455525691334268473593164287128437946659209216966182223959978048461766767048994203857805328335121781687530460374272192439643337616561191454804340602152636521570315735724808211136112178623597726761562233624418966697972730157242837023392799098096001348791292540282769112707428306351952761016511009581482140339266124773156503871585331333229748575546970788710593878329700066394630525667688977999379996797554988699433650675888676455423881055671268822403174758764173450801472107412934932928242628018889547481661696413558606207836289835238941646919528531917854164993719517257318458050248512708310597280868179529982466268126947562915613777011430797948425936457263384797803263966764408262497707996175287022739124394402973694264968889229848339525935294695324028820522528376607382070267797540723336423743427176925087940756280955052040945732043168661526388800230588103529678940221446182218158117656968368051493245055497411735966238847890150408666084 +sqr:5023215555039217191451486096670046812323372237867852342682903508090873804207633443539517026163606065770027196694503291009850587117226026773591715017125540836707619882023150680605967194554434367524090941938814045780235333982097410791452776449214446635671357519707417878752761895933104747199582531838714305022614904134506738511247696618513698871318914624938137416674596881724436242382943205716649496664131501091102879563857843031208992280893614063087964394912022421136928015233318011144243860597237613050611024432789921991289922378761307428111094457098264457145099945444765267932710530788173695233378407323077034767182,0:25232694512387950837246573965423768214659605305747920385364235438142069506752963638176638070663137697548178189512977583934503415751046457217304699834312165759735798834063392638459720554883875322668860726378103278773377069820923135889568597012480529331635521511826460253219709548240571066232289334814339006865253319737519393614525866345823654520523063598485936725991745466055344350193829007241842078415817997984841814058315445235956513287712770234190490867970313521815239706704426480962959318704528841466812066587818519893723352288704763970670959149274002543782704910304301127024275547153165875047466897500391977033070459139260182367193259631752968757844481234924736806232657312752696107333138306380229367277562995612116036553257307316583486420415930866764617533873750528784187657897741011800821517930103416987940072347360626799917296234474844881851193687709571104637725109465383256753161526510645230553484635324115139968700121652080718290604667285871496065225935146563937996599437542585972890644223726730952165788539505477436754054328420237106613886502086271044799562764032162609215838263998005175988570392248195621627510973258180359384380604104188938302848583871731189060087097132563112796351181762659883855872472102926784944221124 +sqr:9281860481025428743103260720025399298938288092709373682664752121448026422364244176957076161560781963714610840062462308785533773682081509516924811454802263149810015499242805866671806182669824281823377004291671016071522932056033291108610609315306035746008726247945073883264784349702632503413711514594728450092072160898603477481125780254532680608704164997261749601100642928524030186658056860132922920804055208139127600955714414432667835794981195051773905850760614924210968557995928682559530646363463541164514351639956960443946215999260668876064044712007044169839741253208493501852117173644320085073436239558982298112600,0:86152933989221603452383960579862529767754507451814327308106099502021338841158564739970946221037114450601947058545585968015185524235118008637093904307143275940199882886916868864207222193239426427361340073440244139751159451898557777069779343414467483495630400743470728307452356966341313677960852068933154671924573760734273611606091152908307935158991039816559413312322566981208062121327548308369676448001395998891570657014429725703319770781094147168569110700521525439009556347021461844081202006912863907929538746074819161945225863226888248444085706919956519264360573870762587910641782352656676156415732700656963630951402092115464901859063766186151616572411364019115388448066844528476234630236343390094769930168862863247247299575418570145375916876386437237082903988846801896214556691481561360799069054218343648585202335896476703207744614538742683914717622691916676976341150631784446520414431143406963418046854017770653263907209702756518001381533976295371716790304760562189392378368525802079624573216454183740278425217025651543107627286662679019527820835682239802308666416070981938963841923859050577866586430415553449794707717857305424419844800957514744493025148562704471289382692563184970909544450306975779736393494626043617522278760000 +sqr:6461820852819773895887891707090409545105222339300767589991593922286229155430279300935431963821489860557211392101557073166691740801924350342690481832500741574765066771636009594821433888176432105527291712269105001105197791973525400419521802156326222007905452621388581343089554119326311972031808789454501569850634390353513026195347029048776084662261279361336878277930892526127759184987426337401986666833244149616653136274450771865938000177859526607860886891713725823803723429415374914088095471203681073462945634413721478459297998380784046348477788577160851236668812562054262272695670208399244540961973019014052558168787,0:41755128733936470013419340614768581207469280475771932448759452471724306748308207056387185341042180822565865975190354615808904657250278538353955888696480598934323757476309374738685684994497716128880324468585630205909258071948935579506193339045950864572735480453777206082914955771593313309955856894724849311870450595834339482685071806743252667708340467642167114083116000124778596927193502323818049586734603742810042021276752915040017354940400178030129663940983913088794072426640243829816327008274324005485264616967551641307060646091607001504654635788964056297229985621142475464282158634817498369712218561902410195152713461864918871424016455091203930645713444133980971449546681537220327549312525941229246794507705534347619463146219624170792658352361826542837966194021639735363473953690177390313887375288592504393102090201580067126091162084412913867210871907813153659746483106875412725262090893163145926694590206586186591043900660223003982254816402106419038767972908977390372043067587105414843306130785601573472584510045946592593734424590918536936724371910844356800883765758566604517939781506812650805380392096724391320635856788305664509062325460162834870676905242982755100465091215613432199297726350243940958759758306993142242781051369 +sqr:6461820852819773895887891707090409545105222339300767589991593922286229155430279300935431963821489860557211392101557073166691740801924350342690481832500741574765066771636009594821433888176432105527291712269105001105197791973525400419521802156326222007905452621388581343089554119326311972031808789454501569850634390353513026195347029048776084662261279361336878277930892526127759184987426337401986666833244149616653136274450771865938000177859526607860886891713725823803723429415374914088095471203681073462945634413721478459297998380784046348477788577160851236668812562054262272695670208399244540961973019014052558168787,=1:41755128733936470013419340614768581207469280475771932448759452471724306748308207056387185341042180822565865975190354615808904657250278538353955888696480598934323757476309374738685684994497716128880324468585630205909258071948935579506193339045950864572735480453777206082914955771593313309955856894724849311870450595834339482685071806743252667708340467642167114083116000124778596927193502323818049586734603742810042021276752915040017354940400178030129663940983913088794072426640243829816327008274324005485264616967551641307060646091607001504654635788964056297229985621142475464282158634817498369712218561902410195152713461864918871424016455091203930645713444133980971449546681537220327549312525941229246794507705534347619463146219624170792658352361826542837966194021639735363473953690177390313887375288592504393102090201580067126091162084412913867210871907813153659746483106875412725262090893163145926694590206586186591043900660223003982254816402106419038767972908977390372043067587105414843306130785601573472584510045946592593734424590918536936724371910844356800883765758566604517939781506812650805380392096724391320635856788305664509062325460162834870676905242982755100465091215613432199297726350243940958759758306993142242781051369 +sqr:7912472862067339862128371179317677419131938894010486952786566311807271094923069332388514681475314477095129839383791878789616020411634591014351511065638534352498100902940229903010080076033147913858702310386781454704764453620638192722142673704997301635080657906841977228453431784636268795567399742877979696735712353260720882016758802630449316568009735495464820484500112849579042319792054180751808291492597692968145199206126879627571212323371773988020895279516215647740755736659817523229210171324629444663573614970129038286402265282862415058866062409919400686067571225883598025018993264993072866008153094783713777842233,0:62607226792952120707247651690259584550519870655409677855259967323970315280127523038352871914217595657318525178928588450738646984186124330548937584545791047411539195482412684246501620725878474982273096945918283314804856302186143180922532479221483774049169665661942575676028716750572824612078547029156326889126648510908500466713726943581967682677688720020286471235758599038656604686024251557579582894251121291196845804656311881653516178849444455844734491852772836158003590931403972989130702566686718563356156866003782202713979799591740568927365378424851203143470432976436058675581145034980081878073994378951069636407956044433595527157452771941753992894632221806355150244262738932228009536850616640523085668143546230350996800173647076957602749446577970514855423674477236535999309116324096409059875960147686741898480716484475884168020125576823399861877763053135612337099607591166573133277345115055382830446955279324436937777170960368837490516357978919384758079145639420844517829747508647571589827612402546568196379111371730312522985608775973653102317116479931771770023631636770509419737783921899453982796775527984382371135662826874391308916487368098573786023125281233044093938346589157068552970819362523463113448971217548940797438426289 +sqr:3201725902397772208341447704654332382791919074661304465094673003562268414312780910138677841790209187781035267718271550359273576299056459823432739891496517659999050131295751440278895964609377686119310540452547253245263824257293859748569384694164098523184164132157046027096354720108308754361750383079701345225130461743071738716695085603994849362372761995341700678666090085339160622218852314697895484240550249851988347340743956951710723755778934782102893613303732727155104650554024190836124710855983325513102342105122420688920843770754330984726835478343584190293399561063733594503384748007915045169469662902517503038695,0:10251048754084828769243329882069275971914890627613738671716877356696804611372225772535909788437192398839842991123901962510118430249474946611045135201967809016816348471137614785988048128241390515692315971455106778002837246102797924605981990933580811595517905674487926190125149743783912791172620685090710721294031418339826218705767020474113475213303982913823024270407367538077398654621734474924951831977997748681939864774457132880966130787121010568095721257658186826775993645732246207566570744542977468845272538470202747808100801988318054298959125301114504026010747921910115853973562914401985468980995690517283225637392666056494069338918735138921764426048557221613239082343742804403199476104847288722226052090168714977201702134281100828032952230896037194398681770354240611642273082773400855766704556982242260945911858324534827894030863019362601675206293366185548957348669774225514518006218467888321089699097391620575727815238097871345555390807646501726425056233120235063071527081727369212097120985047406879578675516214002560189818550388605034487273578377097275389460683099839403381468382578885231830676913607497216090992928203120279557550890527892898136710592601635774254477237306606095549841913591690732525191072433380838558667303025 +sqr:5808324187702080655474460793682039951322360995931125673869791371944228644211378816153373947301972618673468024419809216698234959175295640166063762988660558965367914554186920892629719688885314609703455963977845612750271884481278417471936841270780965441117412446282412169100969024758168373693942106624503929819630667668476732052476696223555182229399707506392013582768244824407047675765649910095793401597173883674841030712174173054018546762918277235618291532242003800812379951389007164665130775067356573065178773886633889021628231165391459939591112464657659598153999220909590051109791624395690563647765208381376662473375,0:33736629869445035074327166424244667388357269999486865605478076413334103798774353682775639542213830809145772052196100574522690756062172293340346900291485418359566994652736736860394553990711528438046447648607265759258849563437038985527522027887469536324986597076326498910837071795251458205904524980493828205498641172851466789655356761510862552511481361948668830231946389600859901152088906546349833795040838140061368522170448758952855372046595253341556353216263984297060270145341296413999867239761086030849655515473988519859922461900886021497209068404156115345891990869710785087691035884591154201820846643004027670616846756481869815422806896037776208720169056623748294226301861321525789456138753657995854650377786223245822168795756177015382020556433922740315469664231971951907243785787603463207205574424710054218646675174351835854569823483723752860910674029346480228748308601384452239082508478253308005445835634293503650832325029963894202698752252776230543203916010757514406789343217818289245459834266233887027255260435438561649500763399981546227245264080216426993032919933996719529973685635989795024502963596132673681479045820438921344384798517847291471865516742005312681288127831399544453631661789669782852521261353330598972583890625 +sqr:918729402656599354295427509394488660812811650986545042142269515180033877242550175086096078333116750486296504860969753318764397360672070743283292590583724934273152632680100030114145522324231651230586226973102509131367913652288365962855153489305948459500758622220373494821215068462533405866936756424017653969429333910353069394383604797810245598567635036667927595346004843560767022814009296322200770357321286444971587792559784113298566437496673370692769029520191499051311630305921790132367949451008467412252240244679740653218546677567374795191493091691181895973054804640859501444377706515253377176192389740639658485554,0:844063715305751868681971206141868238620448349106067649090713042117549119633369793955554348233719755746126280893464820812016005338079930881262278122705660442998154342355231619912542048747564579820455957515967658062579765882068075603317542476485725126614065677508294074683170609567910430859163617312267835677287917010092241479784627554606309976396139987941907937127453128868471672503456384949412832353492125047104125088327869349587314979541859707555223546684520169107982699720021602759206250992533576051949917523223132790224645209557953390063396322748548091847415504398952105342081716845349560247052750420294095678053428216713216713011181812689683492914196236985079977491424396246564512152250347194515570324811898058414788694226000558523630907238488791193859962605342734660937039255359759104296817461843423523782150363606482926217674814654230899763084537946295374731646288495775906239750491832422646745846855470956372588268290873333606787465192588104280578046176481855676139021153292248933293930046473039414083316216665998616344058420309846209053553460359073991880276416769133021195916404214034472772439130482850276889991434513090312643865962017932695340904893119106854707377145235453780149075870382271613690866218610061236826686916 +sqr:4289351015617211853860547293440287163118502026849525600172204430479364457520139869848831815115110666309028281362257922027167887676604882712946357785774765671053291569361256480674248716110951095880149104811531028000846825692159030869973707804728263847551536308296065212083263317121194233870838444421131817712327319493025493358961844276996294363551631856740972199816713986701316425469067461982409331003038962007405485449957519072614334803913032240759760944833349605582847295426216585712797815837902507714668306750095431507743637803032894122691956397938532173109072764661515711293817060848120252743975673113125247753747,0:18398532135176406809034490875693170758925004882141511261808766893882448134661308449674877552336295208917642945790156108898313095424805879501417605739586230929916416741917205011890576364165214842655074817157593175638265096642262911624804249958062053834777196200988231246651694562541632157282179693998749538692029970111424591747477697863942461566583625378474559289840644351696058468544250603519147443482666917127248552520455914618534358459972013595330956153533329148549282058238538359006965923000938192868814224682091707519285881336562876756579025080274645910079084625282553972963075141236187211115990844325515052297351541590023546664412131806032342665984009007162435318353241414465270052529631433227305387943571878454069329525592969380744392762518290885050324171445597112387157817625779490377052814617138025027758796703313537279036322299993462750908493008657797831919621067953926089315029584404727826473302371816974351550286725462756040416199337645083147388751639897989371703481110044912875697392570337540041944755640545845535510530045287632724843324253307769460477224412912973549722946229475760911133865605380194780577819320270517078651641752393246783502013220800728332790909778902389930435716496708472843056646872808640669152540009 +sqr:1129243400327281633151431371474891473455867467281646580615131416918186134500058210362967474476291935913056166817170589720180888384893984130837655605609160519483475686999411456978438146043336536562159220682249690564087391733538120293725815373571240283145745271266418667658265953408844001550460545760069911655331444115026283289502832470850559638590225665815329814544221402813003890575490644213046498706732967784948480361985741430703857522843819419578526133778265155095749489410876608829677795172822626775506026922427707604322446404480105940239935673644113523059324254840712255877427181434254002649024354681415060823887,0:1275190657182721248462063420980207026343022717532622175860219061730792418936740434742094796665906100480439897110257178409857469307077098501942134999624668547631597875340226548233364555044904897637802662331582604911532131450166620402887103231322314236615939231233057651679712668806821697694902550747299740911409056026074325413724541784521105637039150272466375734348928193048571410349655195899575836960732640894105648518962149080274129413128568380000791288924018568364735478182966987827049189244120982249845311602108211176904677903690707944807032554116276797233387539070384134761545289596978472118656073247977568361787904215232007927547273675655812990627547232348919520589298481108958425401154144890217117213559902391607690446197638363620347853484948687625457207482930736345600737267824848389507129569922536325291727973935250559919378188248920389764990722709984543141728260567769676565198058565461309218448131493714100586880045778660348267815919731674340804133476623427737669995140408727297933180816128182764727848278876101607499408120957922795369902531715310169128136970642349303253384538063850831674689811408417573400679901877915536329660371027882694070998224914758044726450736635586342639879086413949670062421005617619755229788769 Index: contrib/isl/imath/tests/compare.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/compare.t @@ -0,0 +1,31 @@ +# Test ordinary signed comparisons +cmp:0,0:$#0 +cmp:0,1:$#-1 +cmp:1,0:$#1 +cmp:-1,1:$#-1 +cmp:1,-1:$#1 +cmp:123456789012345678901234567890,123456789012345678901234567891:$#-1 + +# Test unsigned comparisons +cmpu:0,0:$#0 +cmpu:0,1:$#-1 +cmpu:1,0:$#1 +cmpu:-1,1:$#0 +cmpu:1,-1:$#0 +cmpu:-25,15:$#1 +cmpu:#x-ffffffffffffffff,#xfffffffffffffffe:$#1 + +# Test zero comparisons +cmpz:0:$#0 +cmpz:-25:$#-1 +cmpz:105:$#1 + +# Test small-value comparisons +cmpv:0,0:$#0 +cmpv:0,1:$#-1 +cmpv:1,0:$#1 +cmpv:-1,1:$#-1 +cmpv:1,-1:$#1 +cmpv:499,108:$#1 +cmpv:499,499:$#0 +cmpv:499,-1024:$#1 Index: contrib/isl/imath/tests/conv.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/conv.t @@ -0,0 +1,228 @@ +# Output conversion tests + +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,2:1111011101001010001010000111011010100001010000110010011010011000100100100011101100000111011001111101101000011001110111001111001111010111000101111001010111101110 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,3:22012212212000122111011022212212002120111111102001120012102211211202200102022110202002000211111221202 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,4:33131022022013122201100302122120210203230013121331220121313033033113011321113232 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,5:404041130042310320100141302000203430214122130002340212132414134210033 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,6:44515230120451152500101352430105520150025145320010504454125502 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,7:644641136612541136016610100564613624243140151310023515322 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,8:173512120732412062323044435407317550316717172705712756 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,9:265785018434285762514442046172754680368422060744852 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,10:1411774500397290569709059837552310354075408897518 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,11:184064268501499311A17746095910428222A241708032A +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,12:47706011B225950B02BB45602AA039893118A85950892 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,13:1A188C826B982353CB58422563AC602B783101671A86 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,14:105957B358B89B018958908A9114BC3DDC410B77982 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,15:CB7B3387E23452178846C55DD9D70C7CA9AEA78E8 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,16:F74A2876A1432698923B0767DA19DCF3D71795EE +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,17:17BF7C3673B76D7G7A5GA836277296F806E7453A +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,18:2EBG8HH3HFA6185D6H0596AH96G24C966DD3HG2 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,19:6G3HGBFEG8I3F25EAF61B904EIA40CFDH2124F +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,20:10AHC3D29EBHDF3HD97905CG0JA8061855C3FI +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,21:3BA5A55J5K699B2D09C38A4B237CH51IHA132 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,22:EDEA90DJ0B5CB3FGG1C8587FEB99D3C143CA +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,23:31M26JI1BBD56K3I028MML4EEDMAJK60LGLE +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,24:GGG5M3142FKKG82EJ28111D70EMHC241E4E +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,25:4446F4D5H10982023N297BF0DKBBHLLJB0I +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,26:12E9DEEOBMKAKEP0IM284MIP7FO1O521M46 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,27:85NN0HD48NN2FDDB1F5BMMKIB8CK20MDPK +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,28:2D882A7A0O0JPCJ4APDRIB77IABAKDGJP2 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,29:MFMCI0R7S27AAA3O3L2S8K44HKA7O02CN +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,30:7IGQS73FFSHC50NNH44B6PTTNLC3M6H78 +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,31:2KLUB3U9850CSN6ANIDNIF1LB29MJ43LH +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,32:UT52GTL18CJ9H4HR0TJTK6ESUFBHF5FE +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,33:BTVL87QQBMUGF8PFWU4W3VU7U922QTMW +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,34:4OG10HW0MSWJBIDEE2PDH24GA7RIHIAA +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,35:1W8W9AX2DRUX48GXOLMK0PE42H0FEUWN +tostr:#xF74A2876A1432698923B0767DA19DCF3D71795EE,36:SVWI84VBH069WR15W1U2VTK06USY8Z2 + +# Conversion to binary + +tobin:0:0 +tobin:-1:255 +tobin:1:1 +tobin:97:97 +tobin:8492:33.44 +tobin:-69393016:251.221.37.136 +tobin:-218193:252.171.175 +tobin:662844:10.29.60 +tobin:8241131209300:7.126.201.178.194.84 +tobin:705223363410:0.164.50.150.139.82 +tobin:-28632557663:249.85.93.215.161 +tobin:-553325346410701486:248.82.49.135.113.248.93.82 +tobin:-907482337424:255.44.181.214.111.112 +tobin:4770047168390927:16.242.85.39.8.167.15 +tobin:977875907836789049:13.146.28.245.9.6.65.57 +tobin:3572115845746903:12.176.210.8.21.16.215 +tobin:28949534667733:26.84.86.186.243.213 +tobin:-183125616657544851234:246.18.159.29.228.28.174.208.222 +tobin:827162476353576735:11.122.171.227.198.150.95.31 +tobin:77184512995655260:1.18.54.231.215.68.126.92 +tobin:115255556962215997764:6.63.125.254.104.50.175.49.68 +tobin:54297489021590339048:2.241.135.110.149.175.144.125.232 +tobin:393928929335369918394864191:1.69.217.178.12.173.1.47.149.43.18.63 +tobin:-75550878255305302924368236946:255.11.225.199.59.30.217.134.166.120.200.174.110 +tobin:35784643040276670536818634:29.153.177.98.228.47.31.93.65.31.202 +tobin:-5876364928874055124010543482048:181.212.112.219.201.219.43.162.130.153.141.251.64 +tobin:555590330388726236230755046204154:27.100.137.45.209.201.206.212.69.137.217.165.34.250 +tobin:2123372635933612270094308954044:26.204.252.173.123.198.84.97.94.88.53.79.188 +tobin:373404212231777284568356947010238:18.105.6.21.0.246.144.164.13.115.91.8.162.190 +tobin:355087294263155005473388626149338730:68.99.39.192.10.100.204.157.215.128.79.45.43.110.106 +tobin:9075406350072985013229496898492710997:6.211.220.20.76.13.2.68.169.142.198.197.165.106.64.85 +tobin:8633675426061757629757850232155550:1.169.172.77.223.131.135.137.86.71.95.134.109.237.158 +tobin:-217191451486096670046812323372237867852:255.92.154.114.175.151.49.93.18.105.200.58.156.24.75.180.180 +tobin:26829035080908738042076334435395170:5.42.198.7.200.110.201.64.35.201.25.125.64.230.98 +tobin:16360606577002719669450329100985058711:12.78.240.46.160.248.51.247.149.232.48.220.205.240.69.151 +tobin:26026773591715017125540836707619882:5.3.56.17.26.95.176.214.116.53.154.110.71.84.42 +tobin:-315068060596719455443436752409094193:195.81.241.253.255.182.14.126.183.113.140.138.49.151.207 +tobin:1404578023533398209741079145277644921444663:16.31.175.15.121.161.137.196.26.125.240.115.59.220.1.85.25.55 +tobin:713575197074178787527618959331047471995825:8.49.2.79.246.51.45.90.242.199.86.95.47.64.104.90.91.177 +tobin:83871430502261490413450673851124769661:63.25.12.201.105.63.89.102.174.73.208.109.149.109.99.125 +tobin:1369887131891462493813741667459688172443624:15.185.188.136.198.40.60.46.152.22.161.146.105.88.210.253.87.232 +tobin:829432057166494966641315010911028795638578:9.133.123.83.146.186.254.230.112.155.225.249.127.219.248.43.131.50 +tobin:312089922808936140630879643949120224211369:3.149.38.92.196.150.155.232.60.223.247.126.50.176.14.127.177.169 +tobin:152333180111442438605972376130506110244327899219:26.174.219.37.168.212.28.162.39.139.47.209.114.56.212.157.2.33.192.83 +tobin:-2899223787613074281110944570982644571450999:222.183.242.113.50.20.39.238.192.239.78.170.102.70.102.231.209.137 +tobin:444765267932710530788173695233378407323077034767:77.231.246.225.189.253.236.180.85.80.95.147.220.91.211.171.195.205.195.15 +tobin:2928186048102542874310326072002539929893828809270937:7.211.139.211.153.76.242.8.164.101.41.243.188.255.255.239.194.98.21.205.38.153 +tobin:-826647521214480264223642441769570761615607819637146:253.202.98.131.34.175.212.21.119.210.126.69.61.176.197.180.182.201.116.60.110.102 +tobin:8400624623087855337736820815095169248114548022:1.120.178.112.248.52.41.234.187.122.100.10.161.143.20.186.83.68.157.54 +tobin:-14981001549924280586667180618266982428182337700429:245.191.228.168.55.2.155.157.248.12.207.194.168.98.220.91.66.110.69.189.179 +tobin:710160715229320560332911086106093153060357460087262479:7.106.23.173.245.150.209.228.252.222.62.180.93.143.150.200.182.76.119.140.239.205.15 +tobin:73883264784349702632503413711514594728450092072160898:0.197.120.251.47.105.95.210.233.70.183.8.43.3.136.2.36.106.51.96.215.206.130 + +# Conversion from binary + +readbin:0:0 +readbin:255:-1 +readbin:1:1 +readbin:97:97 +readbin:33.44:8492 +readbin:251.221.37.136:-69393016 +readbin:252.171.175:-218193 +readbin:10.29.60:662844 +readbin:7.126.201.178.194.84:8241131209300 +readbin:0.164.50.150.139.82:705223363410 +readbin:249.85.93.215.161:-28632557663 +readbin:248.82.49.135.113.248.93.82:-553325346410701486 +readbin:255.44.181.214.111.112:-907482337424 +readbin:16.242.85.39.8.167.15:4770047168390927 +readbin:13.146.28.245.9.6.65.57:977875907836789049 +readbin:12.176.210.8.21.16.215:3572115845746903 +readbin:26.84.86.186.243.213:28949534667733 +readbin:246.18.159.29.228.28.174.208.222:-183125616657544851234 +readbin:11.122.171.227.198.150.95.31:827162476353576735 +readbin:1.18.54.231.215.68.126.92:77184512995655260 +readbin:6.63.125.254.104.50.175.49.68:115255556962215997764 +readbin:2.241.135.110.149.175.144.125.232:54297489021590339048 +readbin:1.69.217.178.12.173.1.47.149.43.18.63:393928929335369918394864191 +readbin:255.11.225.199.59.30.217.134.166.120.200.174.110:-75550878255305302924368236946 +readbin:29.153.177.98.228.47.31.93.65.31.202:35784643040276670536818634 +readbin:181.212.112.219.201.219.43.162.130.153.141.251.64:-5876364928874055124010543482048 +readbin:27.100.137.45.209.201.206.212.69.137.217.165.34.250:555590330388726236230755046204154 +readbin:26.204.252.173.123.198.84.97.94.88.53.79.188:2123372635933612270094308954044 +readbin:18.105.6.21.0.246.144.164.13.115.91.8.162.190:373404212231777284568356947010238 +readbin:68.99.39.192.10.100.204.157.215.128.79.45.43.110.106:355087294263155005473388626149338730 +readbin:6.211.220.20.76.13.2.68.169.142.198.197.165.106.64.85:9075406350072985013229496898492710997 +readbin:1.169.172.77.223.131.135.137.86.71.95.134.109.237.158:8633675426061757629757850232155550 +readbin:255.92.154.114.175.151.49.93.18.105.200.58.156.24.75.180.180:-217191451486096670046812323372237867852 +readbin:5.42.198.7.200.110.201.64.35.201.25.125.64.230.98:26829035080908738042076334435395170 +readbin:12.78.240.46.160.248.51.247.149.232.48.220.205.240.69.151:16360606577002719669450329100985058711 +readbin:5.3.56.17.26.95.176.214.116.53.154.110.71.84.42:26026773591715017125540836707619882 +readbin:195.81.241.253.255.182.14.126.183.113.140.138.49.151.207:-315068060596719455443436752409094193 +readbin:16.31.175.15.121.161.137.196.26.125.240.115.59.220.1.85.25.55:1404578023533398209741079145277644921444663 +readbin:8.49.2.79.246.51.45.90.242.199.86.95.47.64.104.90.91.177:713575197074178787527618959331047471995825 +readbin:63.25.12.201.105.63.89.102.174.73.208.109.149.109.99.125:83871430502261490413450673851124769661 +readbin:15.185.188.136.198.40.60.46.152.22.161.146.105.88.210.253.87.232:1369887131891462493813741667459688172443624 +readbin:9.133.123.83.146.186.254.230.112.155.225.249.127.219.248.43.131.50:829432057166494966641315010911028795638578 +readbin:3.149.38.92.196.150.155.232.60.223.247.126.50.176.14.127.177.169:312089922808936140630879643949120224211369 +readbin:26.174.219.37.168.212.28.162.39.139.47.209.114.56.212.157.2.33.192.83:152333180111442438605972376130506110244327899219 +readbin:222.183.242.113.50.20.39.238.192.239.78.170.102.70.102.231.209.137:-2899223787613074281110944570982644571450999 +readbin:77.231.246.225.189.253.236.180.85.80.95.147.220.91.211.171.195.205.195.15:444765267932710530788173695233378407323077034767 +readbin:7.211.139.211.153.76.242.8.164.101.41.243.188.255.255.239.194.98.21.205.38.153:2928186048102542874310326072002539929893828809270937 +readbin:253.202.98.131.34.175.212.21.119.210.126.69.61.176.197.180.182.201.116.60.110.102:-826647521214480264223642441769570761615607819637146 +readbin:1.120.178.112.248.52.41.234.187.122.100.10.161.143.20.186.83.68.157.54:8400624623087855337736820815095169248114548022 +readbin:245.191.228.168.55.2.155.157.248.12.207.194.168.98.220.91.66.110.69.189.179:-14981001549924280586667180618266982428182337700429 +readbin:7.106.23.173.245.150.209.228.252.222.62.180.93.143.150.200.182.76.119.140.239.205.15:710160715229320560332911086106093153060357460087262479 +readbin:0.197.120.251.47.105.95.210.233.70.183.8.43.3.136.2.36.106.51.96.215.206.130:73883264784349702632503413711514594728450092072160898 +# +# -- From Tom Wu, triggered a bug in s_qmul(): +# +readbin:22.200.146.12.243.10.174.111.79.92.242.37.59.156.205.75.163.223.107.103.20.203.19.168.35.69.241.146.93.87.91.210:10305260085868809781027103920001537650251216529133196585936939957967423757266 + +# Conversion to unsigned + +to-uns:19:19 +to-uns:732849:11.46.177 +to-uns:2456939301:146.113.235.37 +to-uns:65221819301662:59.81.163.94.255.30 +to-uns:-844378241131209300:11.183.213.137.94.177.226.84 +to-uns:8570522336341023286325:1.208.155.227.240.84.37.160.100.53 +to-uns:57663995533253464107014863:47.178.211.118.41.71.211.74.100.90.207 +to-uns:290748233742495477004716839092:3.171.117.77.85.127.49.10.213.243.253.144.180 +to-uns:7769778759078367890498335721158457:1.127.20.101.49.86.0.169.68.4.237.33.216.119.57 +to-uns:46903702894953466773316183125616657544:35.73.83.24.98.4.211.124.18.69.32.88.95.142.132.136 +to-uns:-851234028271624763535767352077184512995655:9.197.141.78.121.20.132.41.143.246.59.33.126.2.92.102.177.71 +to-uns:-2609311525555696221599776451542974890215903390:117.1.109.101.2.62.220.206.134.57.198.156.134.252.135.230.114.144.158 +to-uns:48673939289293353699183948641914875550878255305302:33.77.214.236.147.20.12.74.7.55.12.207.229.43.143.81.121.102.216.82.86 +to-uns:924368236946243578464304027667053681863478587636492887:9.166.158.105.220.232.187.149.229.98.114.203.143.151.179.13.117.242.141.170.94.170.87 +to-uns:4055124010543482048995555903303887262362307550462041543621:165.97.120.89.181.168.202.95.163.0.0.6.89.126.141.209.204.168.88.165.194.166.83.197 +to-uns:23372635933612270094308954044673734042122317772845683569470102:14.139.121.201.25.49.14.230.89.139.204.223.141.232.201.189.74.36.63.100.115.152.44.110.42.150 +to-uns:382935508729426315500547338862614933873079907540635007298501322949:3.162.221.90.36.235.220.148.206.72.220.121.230.47.59.194.10.29.105.64.171.5.133.101.247.195.168.197 +to-uns:6898492710997158633675426061757629757850232155550392171914514860966700:255.225.26.217.121.147.85.123.62.227.155.115.151.17.14.226.20.151.216.70.129.251.123.127.200.253.229.131.44 +to-uns:46812323372237867852342682903508090873804207633443539517026163606065770027:26.126.173.147.234.225.62.206.132.172.56.142.212.124.86.139.56.123.128.83.59.140.190.156.37.116.71.8.107.238.43 +to-uns:196694503291009850587117226026773591715017125540836707619882023150680605967194:1.178.221.36.198.34.91.147.187.41.80.248.32.21.173.116.21.184.114.128.226.148.105.231.211.137.139.144.142.36.59.195.90 +to-uns:-5544343675240909419388140457802353339820974107914527764492144466356713575197074178:187.9.226.242.27.68.215.247.155.152.75.195.109.94.123.200.36.80.1.19.58.240.99.181.158.175.120.210.195.130.202.54.99.2 +to-uns:78752761895933104747199582531838714305022614904134506738511247696618513698871318914624:40.137.215.13.233.153.110.152.75.205.157.188.162.180.175.192.136.147.0.49.169.41.111.20.20.6.222.4.94.232.86.88.35.227.166.64 +to-uns:938137416674596881724436242382943205716649496664131501091102879563857843031208992280893614:7.94.95.163.78.130.176.52.11.67.110.168.191.141.240.164.45.130.231.131.248.48.191.162.48.249.20.181.82.141.159.150.82.213.105.159.88.174 +to-uns:-630879643949120224211369280152333180111442438605972376130506110244327899219912899223787613074:19.91.70.129.236.212.139.74.185.0.218.23.135.137.133.202.56.181.112.58.173.172.130.179.124.221.173.55.223.123.126.130.88.154.176.35.3.43.146 +to-uns:28111094457098264457145099945444765267932710530788173695233378407323077034767182928186048102542874:13.41.35.240.41.168.225.145.107.18.87.253.43.231.202.150.209.215.163.157.127.252.45.194.199.62.14.60.97.225.213.204.55.37.185.133.79.239.24.46.26 + +# Conversion from unsigned + +readuns:19:19 +readuns:11.46.177:732849 +readuns:146.113.235.37:2456939301 +readuns:59.81.163.94.255.30:65221819301662 +readuns:11.183.213.137.94.177.226.84:844378241131209300 +readuns:1.208.155.227.240.84.37.160.100.53:8570522336341023286325 +readuns:47.178.211.118.41.71.211.74.100.90.207:57663995533253464107014863 +readuns:3.171.117.77.85.127.49.10.213.243.253.144.180:290748233742495477004716839092 +readuns:1.127.20.101.49.86.0.169.68.4.237.33.216.119.57:7769778759078367890498335721158457 +readuns:35.73.83.24.98.4.211.124.18.69.32.88.95.142.132.136:46903702894953466773316183125616657544 +readuns:9.197.141.78.121.20.132.41.143.246.59.33.126.2.92.102.177.71:851234028271624763535767352077184512995655 +readuns:117.1.109.101.2.62.220.206.134.57.198.156.134.252.135.230.114.144.158:2609311525555696221599776451542974890215903390 +readuns:33.77.214.236.147.20.12.74.7.55.12.207.229.43.143.81.121.102.216.82.86:48673939289293353699183948641914875550878255305302 +readuns:9.166.158.105.220.232.187.149.229.98.114.203.143.151.179.13.117.242.141.170.94.170.87:924368236946243578464304027667053681863478587636492887 +readuns:165.97.120.89.181.168.202.95.163.0.0.6.89.126.141.209.204.168.88.165.194.166.83.197:4055124010543482048995555903303887262362307550462041543621 +readuns:14.139.121.201.25.49.14.230.89.139.204.223.141.232.201.189.74.36.63.100.115.152.44.110.42.150:23372635933612270094308954044673734042122317772845683569470102 +readuns:3.162.221.90.36.235.220.148.206.72.220.121.230.47.59.194.10.29.105.64.171.5.133.101.247.195.168.197:382935508729426315500547338862614933873079907540635007298501322949 +readuns:255.225.26.217.121.147.85.123.62.227.155.115.151.17.14.226.20.151.216.70.129.251.123.127.200.253.229.131.44:6898492710997158633675426061757629757850232155550392171914514860966700 +readuns:26.126.173.147.234.225.62.206.132.172.56.142.212.124.86.139.56.123.128.83.59.140.190.156.37.116.71.8.107.238.43:46812323372237867852342682903508090873804207633443539517026163606065770027 +readuns:1.178.221.36.198.34.91.147.187.41.80.248.32.21.173.116.21.184.114.128.226.148.105.231.211.137.139.144.142.36.59.195.90:196694503291009850587117226026773591715017125540836707619882023150680605967194 +readuns:187.9.226.242.27.68.215.247.155.152.75.195.109.94.123.200.36.80.1.19.58.240.99.181.158.175.120.210.195.130.202.54.99.2:5544343675240909419388140457802353339820974107914527764492144466356713575197074178 +readuns:40.137.215.13.233.153.110.152.75.205.157.188.162.180.175.192.136.147.0.49.169.41.111.20.20.6.222.4.94.232.86.88.35.227.166.64:78752761895933104747199582531838714305022614904134506738511247696618513698871318914624 +readuns:7.94.95.163.78.130.176.52.11.67.110.168.191.141.240.164.45.130.231.131.248.48.191.162.48.249.20.181.82.141.159.150.82.213.105.159.88.174:938137416674596881724436242382943205716649496664131501091102879563857843031208992280893614 +readuns:19.91.70.129.236.212.139.74.185.0.218.23.135.137.133.202.56.181.112.58.173.172.130.179.124.221.173.55.223.123.126.130.88.154.176.35.3.43.146:630879643949120224211369280152333180111442438605972376130506110244327899219912899223787613074 +readuns:13.41.35.240.41.168.225.145.107.18.87.253.43.231.202.150.209.215.163.157.127.252.45.194.199.62.14.60.97.225.213.204.55.37.185.133.79.239.24.46.26:28111094457098264457145099945444765267932710530788173695233378407323077034767182928186048102542874 + +# Conversion to small signed integers +to-int:0:0 +to-int:399392010000012093849283940182938492839481928349823984:$MP_RANGE +to-int:-29381082039841029384018230948203801985928309481203984:$MP_RANGE +to-int:-25:-25 +to-int:101:101 +to-int:-1235:-1235 + +# Conversion to small signed integers +to-uint:0:0 +to-uint:1:1 +to-uint:10:10 +to-uint:-15:$MP_RANGE +to-uint:101:101 +to-uint:100000000000000000000000000000000000000000000000000:$MP_RANGE + +# Tests to trigger off-by-one bug in computing number of digits needed for string +tostr:99999999999999999999999999999,10:99999999999999999999999999999 +tostr:9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999,10:9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +tostr:832136388736902947561088644572239329432528812529007215254079045034263648726187965907662527121488680217097287175564480588901672671661161,10:832136388736902947561088644572239329432528812529007215254079045034263648726187965907662527121488680217097287175564480588901672671661161 Index: contrib/isl/imath/tests/div.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/div.t @@ -0,0 +1,963 @@ +# Division tests + +# Tests for error conditions + +div:102233,0,=1,1:$MP_UNDEF,? +div:0,=1,583922,-12345:$MP_UNDEF,? + +# General division tests, verified using GNU bc + +div:0,847887705,0,0:0,0 +div:80000000000000000000,25,0,0:3200000000000000000,0 +div:65000,25,0,0:2600,0 +div:800000000000000,25,0,0:32000000000000,0 +div:-4,58,0,0:0,-4 +div:36869,818935,0,0:0,36869 +div:364,921,0,0:0,364 +div:5169,898,0,0:5,679 +div:#x100000000,#xE424,=1,0:#x11F42,#xD2B8 +div:-6144,15855207,0,0:0,-6144 +div:680441,-8247,0,0:-82,4187 +div:-31218529,577983165,0,0:0,-31218529 +div:3,6280,0,0:0,3 +div:-2,39790,0,0:0,-2 +div:-310,611711,0,0:0,-310 +div:46573596,6038351,0,0:7,4305139 +div:4525534,39110,0,0:115,27884 +div:5938,7789378,0,0:0,5938 +div:19732849245693930165221819301662844,18446744073709551616,=1,=2:1069719901075515,6029073732495380604 +div:9,456578633,=2,=1:0,9 +div:538090499,1858,0,0:289607,693 +div:572,3804550,0,0:0,572 +div:288850,21164,0,0:13,13718 +div:-5190106,34726,0,0:-149,-15932 +div:7795,72811,0,0:0,7795 +div:781579692,-5,0,0:-156315938,2 +div:781579692,-5,=1,=2:-156315938,2 +div:781579692,-5,=2,=1:-156315938,2 +div:453020143,-3473628,0,0:-130,1448503 +div:8,853320290,0,0:0,8 +div:852316479,2925,0,0:291390,729 +div:8,5,0,0:1,3 +div:859848,9,0,0:95538,6 +div:70,48,0,0:1,22 +div:253385147,659538174,0,0:0,253385147 +div:-455686878,87344,0,0:-5217,-13230 +div:28271,635389,0,0:0,28271 +div:-86,2692,0,0:0,-86 +div:8591158476,73,0,0:117687102,30 +div:9082,275389,0,0:0,9082 +div:-582874,74264,0,0:-7,-63026 +div:237,4104,0,0:0,237 +div:7076150589,92653,0,0:76372,55673 +div:28665011462,-1272,0,0:-22535386,470 +div:-8056787359,8082209,0,0:-996,-6907195 +div:53192266,900107,0,0:59,85953 +div:91513,740,0,0:123,493 +div:-98721211,8015090320,0,0:0,-98721211 +div:11450,-36952886107,0,0:0,11450 +div:13925193,949882,0,0:14,626845 +div:683469315,-73092992,0,0:-9,25632387 +div:1164719,42872,0,0:27,7175 +div:-83594243092,3591081825,0,0:-23,-999361117 +div:87138285,266592788,0,0:0,87138285 +div:936091,704216,0,0:1,231875 +div:142238814011,709885571028,0,0:0,142238814011 +div:580,-60286,0,0:0,580 +div:5794931,-5726480,0,0:-1,68451 +div:88764678929,-2091175751,0,0:-42,935297387 +div:950181713208,-13449,0,0:-70650733,5091 +div:97846262,387939152,0,0:0,97846262 +div:32321004,4640815041,0,0:0,32321004 +div:9059,24970299,0,0:0,9059 +div:-223020,974872432,0,0:0,-223020 +div:628713585932,70889408675,0,0:8,61598316532 +div:5404031582279,-4343762403,0,0:-1244,391152947 +div:-27687,92528708054,0,0:0,-27687 +div:71252,-444744751915,0,0:0,71252 +div:2821624059,830276221,0,0:3,330795396 +div:77957,604211270,0,0:0,77957 +div:4336867764,377604023491,0,0:0,4336867764 +div:-1183882,537011618,0,0:0,-1183882 +div:7224227137658,26159,0,0:276166028,11206 +div:40420610021,29600662602,0,0:1,10819947419 +div:-53857,7190456320,0,0:0,-53857 +div:9365,85703,0,0:0,9365 +div:84454441,7874100414786,0,0:0,84454441 +div:-692,-92802,0,0:0,-692 +div:-31682292914,2103996,0,0:-15058,-321146 +div:675174791229,617791,0,0:1092885,274194 +div:151503,-7352433026033,0,0:0,151503 +div:-5675649814790,-45077421077,0,0:125,-40972180165 +div:-259966,4211178684,0,0:0,-259966 +div:99243,8777962733,0,0:0,99243 +div:-603163384555,4331787866,0,0:-139,-1044871181 +div:602983,3355548,0,0:0,602983 +div:-6945091776175,64113609219877,0,0:0,-6945091776175 +div:637048330,39484763123,0,0:0,637048330 +div:-268774166,54251789102520,0,0:0,-268774166 +div:96621785,-44159202070842,0,0:0,96621785 +div:259095,798144185517,0,0:0,259095 +div:673478104612,6115944997,0,0:110,724154942 +div:64865142,-7529340145,0,0:0,64865142 +div:62901084202908,923068964,0,0:68143,395789056 +div:857311552,30222,0,0:28367,4078 +div:6646483,1292987,0,0:5,181548 +div:855267457921,77070194891856,0,0:0,855267457921 +div:930905,-429874001253,0,0:0,930905 +div:-82732,973702689,0,0:0,-82732 +div:7498877,33402368,0,0:0,7498877 +div:2891132,3009602159727,0,0:0,2891132 +div:-16580361,45469862,0,0:0,-16580361 +div:28811879,1156690,0,0:24,1051319 +div:681237481,42215447,0,0:16,5790329 +div:952119,65641,0,0:14,33145 +div:669100,32909317724335,0,0:0,669100 +div:406354444955,4811582310504,0,0:0,406354444955 +div:-87218901,5441737753,0,0:0,-87218901 +div:262693,279060,0,0:0,262693 +div:950539838,98609240829243,0,0:0,950539838 +div:8061719120,-28536222,0,0:-282,14504516 +div:-3551675,11288323481405,0,0:0,-3551675 +div:3133528691,1315285,0,0:2382,519821 +div:1588170591121,9023526203,0,0:176,29979393 +div:1709754910,343280090631449,0,0:0,1709754910 +div:7694474,6311674489334,0,0:0,7694474 +div:285071476,771758808364462,0,0:0,285071476 +div:4473571504184,5027949393624517,0,0:0,4473571504184 +div:-314089112111113,-8919383,0,0:35214219,-5804236 +div:919605168565,-857045700084,0,0:-1,62559468481 +div:-2803909388714,46792205688194,0,0:0,-2803909388714 +div:-864476,-809506582,0,0:0,-864476 +div:157477674603,932718332239208,0,0:0,157477674603 +div:-86938062350,44113358240184,0,0:0,-86938062350 +div:7332602805,35651734,0,0:205,23997335 +div:40677613,7075290162,0,0:0,40677613 +div:6636106412767060,-388484912,0,0:-17082018,153254644 +div:9453362014,-644867786149524,0,0:0,9453362014 +div:123163311944389,-16324640549,0,0:-7544,10223642733 +div:55603403145688,-51970044763,0,0:-1069,47425294041 +div:-54436610546,-9254821627256041,0,0:0,-54436610546 +div:34541223746384523,408005019,0,0:84658820,283766943 +div:23462284247353823,2661546,0,0:8815284142,350291 +div:417392442148,-30391736401961,0,0:0,417392442148 +div:-718458863,-73668989433156990,0,0:0,-718458863 +div:-1215789,25426915315,0,0:0,-1215789 +div:8299846204145462,9023932210324,0,0:919,6852502857706 +div:-82615892630,85109462984880568,0,0:0,-82615892630 +div:828237348372,822759132224411,0,0:0,828237348372 +div:35003657,287087229590,0,0:0,35003657 +div:741329413510689,600380266222,0,0:1234,460164992741 +div:-454795890210,66807881739,0,0:-6,-53948599776 +div:442416942,-79456387864,0,0:0,442416942 +div:7067406608460,507872176187,0,0:13,465068318029 +div:57674203676661022,3315186364,0,0:17396971,2642557578 +div:-6677233842,881012314,0,0:-7,-510147644 +div:828372724537918527,2204184463,0,0:375818239,1222097870 +div:-97445457356928,3845827480,0,0:-25337,-3726496168 +div:644919922824665106,692147849,0,0:931766130,174110736 +div:-54599915326211,-274657876971100,0,0:0,-54599915326211 +div:3507375128,373578606,0,0:9,145167674 +div:19124901,485472050038835999,0,0:0,19124901 +div:687842561,49925524361,0,0:0,687842561 +div:193224391137090311,84335903540,0,0:2291128,41131297191 +div:388138056,66626944,0,0:5,55003336 +div:-656523898932,84101085851135799,0,0:0,-656523898932 +div:86004003567986,713613577148692,0,0:0,86004003567986 +div:7992270343,87209595913499289,0,0:0,7992270343 +div:-890969253231921,739402045213270955,0,0:0,-890969253231921 +div:6345032414365,821532347711110478,0,0:0,6345032414365 +div:-2988926571013999683,766437559276027,0,0:-3899,-586527396770410 +div:-15464671727416040,-618822744180643,0,0:24,-612925867080608 +div:21542413221581,-12802725163,0,0:-1682,8229497415 +div:210193665939,3964410139763307,0,0:0,210193665939 +div:-79273337971,91480286016,0,0:0,-79273337971 +div:6859567649816379680,-89417752889,0,0:-76713710,85837971490 +div:4244108501419250,1773608945178,0,0:2392,1635904553474 +div:-7873175456557395,-541450782136,0,0:14540,-481084299955 +div:2898452653,8240117642629,0,0:0,2898452653 +div:-8585567176400751363,39056741283,0,0:-219822926,-27546697305 +div:4923064817310182,488568656518880796,0,0:0,4923064817310182 +div:3946741285053501,-8922249541453011,0,0:0,3946741285053501 +div:438914382542168,98348892578,0,0:4462,81623859132 +div:257824992496,-9594074905801512,0,0:0,257824992496 +div:6213773111135227489,251684062660,0,0:24688782,155248147369 +div:-851789213354610296,395154960128827139,0,0:-2,-61479293096956018 +div:234318209260,31123149038286353070,0,0:0,234318209260 +div:243854015291982,52511298700,0,0:4643,44055427882 +div:7259566528156,6524807428024562671,0,0:0,7259566528156 +div:-887488809078966765,845297673812,0,0:-1049912,-637771662221 +div:65325904373281379,40360887138954,0,0:1618,21988982453807 +div:85548880813,9240276773237567918,0,0:0,85548880813 +div:7737568342993115224,69017119565996596,0,0:112,7650951601496472 +div:-2862875578129,87167074447,0,0:-32,-73529195825 +div:48121669474016423,812759701293155,0,0:59,168847097720278 +div:-82120995972822350,9793327794599,0,0:-8385,-3942415109735 +div:96669753363716639,3137138094734,0,0:30814,1980112583163 +div:44554701178616,52377515472783262637,0,0:0,44554701178616 +div:12903174971697,577437337389558244582,0,0:0,12903174971697 +div:38970472084822,-12255774904287,0,0:-3,2203147371961 +div:-371784186042,36063372236212364134,0,0:0,-371784186042 +div:-5423240799687893943,69598779690234855,0,0:-77,-64134763539810108 +div:78261697698230901561,532057670838,0,0:147092508,494031019857 +div:-867163311151035436254,1681644368464785,0,0:-515663,-1531175379008799 +div:425847772644293,726262561530005,0,0:0,425847772644293 +div:623414319659742,26868506006719423291,0,0:0,623414319659742 +div:3999344581644,6784937040418183244,0,0:0,3999344581644 +div:-418166904889870721653,99856664384501754791,0,0:-4,-18740247351863702489 +div:4737717701335,43868455388327,0,0:0,4737717701335 +div:-170318802370599286974,88681362021061351331,0,0:-1,-81637440349537935643 +div:-401236499756120675284,617234855370415616,0,0:-650,-33843765350524884 +div:8507669577483416,1708320712715767,0,0:4,1674386726620348 +div:-779872398090729,9483722067689467,0,0:0,-779872398090729 +div:-6974404749995800334378,88119801211272782297,0,0:-79,-12940454305250532915 +div:1644424212644083246063,6570040442718779,0,0:250291,2220195557331374 +div:380529423855576,-66584160392695795292,0,0:0,380529423855576 +div:-59486508603350002,3049574533592654270009,0,0:0,-59486508603350002 +div:4670852164286,194818165100985439247,0,0:0,4670852164286 +div:-9242375894510748,427966685403010,0,0:-21,-255075501047538 +div:-2547406540907066001,9156772267145703887,0,0:0,-2547406540907066001 +div:41045576141401448,295376215711793,0,0:138,283658373174014 +div:-8596645367243,618616563342036461,0,0:0,-8596645367243 +div:-8190662465572761,4614103375660380354519,0,0:0,-8190662465572761 +div:13625026664287920203,962611652006092322040,0,0:0,13625026664287920203 +div:-140239543538185,-36750209483049,0,0:3,-29988915089038 +div:19272745315539563545972,4913276356215789258,0,0:3922,2875446461238076096 +div:81488845695775561589,6137038314233733147,0,0:13,1707347610737030678 +div:59682455708892,188993136701455,0,0:0,59682455708892 +div:-45017621011770980,5037281596391885620833,0,0:0,-45017621011770980 +div:12784502496583369914436,66775897063651761451,0,0:191,30306157425883477295 +div:69627779066297453,44437721988866612,0,0:1,25190057077430841 +div:-9837326629633299,980665943940704469610,0,0:0,-9837326629633299 +div:1548374752880296357809,-3696277363166782287,0,0:-418,3330815076581361843 +div:-708439719674935281,5147784263606738,0,0:-137,-3193275560812175 +div:-7570135590104019,22684260196955,0,0:-333,-16276944518004 +div:7197857209654848797343,5395261067987895097519,0,0:1,1802596141666953699824 +div:42034917537094135582,97988383165721711085970,0,0:0,42034917537094135582 +div:231126155949672582,9057297455411228,0,0:25,4693719564391882 +div:-911497664257321106698,-18662736693873,0,0:48840514,-11481903135976 +div:64066981598227998719,731669238473176,0,0:87562,559739039761807 +div:35960724694947949779,-747063649911230162,0,0:-48,101669499208902003 +div:624879014956928,17179603356281093930126,0,0:0,624879014956928 +div:-3559399723529186749748,153806520430475822650,0,0:-23,-21849753628242828798 +div:-375790972015605,113007880734109473,0,0:0,-375790972015605 +div:-8787548671098011,8921111513701891873,0,0:0,-8787548671098011 +div:-4332240904268358207600,202327025748990,0,0:-21412072,-61385130400320 +div:9234628706335936400446,65579862120113054437,0,0:140,53448009520108779266 +div:-598537435499087,-2334884709153191798659,0,0:0,-598537435499087 +div:-8778093680300813378318,-5335331111760467,0,0:1645276,-1450067999274426 +div:834964892558660,4731312923556947,0,0:0,834964892558660 +div:697663848949724,16714097460480423,0,0:0,697663848949724 +div:660124536913505493,-400393621100679,0,0:-1648,275849339586501 +div:67401867410433679076,433247521397462506,0,0:155,248501593826990646 +div:-3192841130293725192,94067632460761922343048,0,0:0,-3192841130293725192 +div:-888171986451016091961,61046771373537922044313,0,0:0,-888171986451016091961 +div:5413476093760118894,436643671457387927452325,0,0:0,5413476093760118894 +div:3390818445571570,71193890227980923543296,0,0:0,3390818445571570 +div:3709278299197858947885,622346666342073,0,0:5960148,60492485241081 +div:61046636418932697473,752452096310648123,0,0:81,98016617770199510 +div:-9490582336573659,6796700304740895609,0,0:0,-9490582336573659 +div:-6770091537873296360125723,894260210116688124412,0,0:-7570,-541747289967258326883 +div:8265260740385351513048054,-37568692482712647407307,0,0:-220,148394188569083440514 +div:29941612974211919398,17117150207877877221595,0,0:0,29941612974211919398 +div:904565427385797381401147,732377327803549406181,0,0:1235,79427548413864767612 +div:828695336330867,665449887430200916,0,0:0,828695336330867 +div:583964043448404224,-159103379771833684164472,0,0:0,583964043448404224 +div:68659884135230073,3794043309187845772,0,0:0,68659884135230073 +div:-19577883397074285891599,89166539289139219809001,0,0:0,-19577883397074285891599 +div:47123114739550322,81879863505548403487,0,0:0,47123114739550322 +div:2081796666654613977139,-5323946267713561205491896,0,0:0,2081796666654613977139 +div:5580573071674875331019254,48049594740533118,0,0:116141938,18394751853316570 +div:-827318924045362735,6765606250148903029558502,0,0:0,-827318924045362735 +div:74355428058748494058359,-21632036475261687692382908,0,0:0,74355428058748494058359 +div:-704818230891696889912403,4179012972972804984179,0,0:-168,-2744051432265652570331 +div:54203012886802530,8642657915176877761716,0,0:0,54203012886802530 +div:99602518405709989487439,181452400672924186,0,0:548918,29533129791156691 +div:669551881716343753,65924540094419185740265,0,0:0,669551881716343753 +div:17773767489747228176421376,99265471480253104908,0,0:179052,86290264949236434160 +div:68861552761996536283999,3032962718342296259044166,0,0:0,68861552761996536283999 +div:-13017342749140884149199232,79805947528944429,0,0:-163112439,-988735239546901 +div:-846660807407559032521972,77200873303583960046,0,0:-10966,-76030760457326657536 +div:20732670221446843791112897,158830667623944099,0,0:130533168,938387893737265 +div:87479614966913872614027,-20093149492209048359,0,0:-4353,14135227327885107300 +div:815811689877913117,-96853054749489063852925232,0,0:0,815811689877913117 +div:88424170141166441101228,41882896205789554161109080,0,0:0,88424170141166441101228 +div:8907792217571919630,1822019507410919085762,0,0:0,8907792217571919630 +div:508794162072510930223084886,-69410487054586064946,0,0:-7330220,21655243065234616766 +div:7560829661415328254781,71577097034806313439,0,0:105,45234472760665343686 +div:7451615053542910305,1115867448037197150640,0,0:0,7451615053542910305 +div:1420226199720665341735779,832064548724686659546,0,0:1706,724079596349900550303 +div:-389977371089920999571936723,8114703647013040404,0,0:-48058116,-1916145250323817859 +div:675206408971175566604,36474013799024907341535694,0,0:0,675206408971175566604 +div:-502561109202609111272,-414660684126386698299,0,0:1,-87900425076222412973 +div:-7443609476960080458698600,-92469297206353960522,0,0:80498,-15990442999344598644 +div:24688964911945445107348,-799787361463460092976944,0,0:0,24688964911945445107348 +div:74622389634816941348941747,361423050927986753697692,0,0:206,169241143651670087217195 +div:57087631963106216588129,60933956374125435992007156,0,0:0,57087631963106216588129 +div:24667793118599351096874664,944711324818117322023856,0,0:26,105298673328300724254408 +div:564352217106369256763287,81622332712601232269,0,0:6914,15408731444336855421 +div:-419643083493336850638945386,-90994516601676379,0,0:4611740346,-16619082369458252 +div:3968897352690734435372,22251724057784007850845,0,0:0,3968897352690734435372 +div:657621764031152559636,1284248378184585349838990,0,0:0,657621764031152559636 +div:478747162724364955902006,88051418458918816631123,0,0:5,38490070429770872746391 +div:6665622554429783258955137608,694490725232295413492445192,0,0:9,415206027339124537523130880 +div:739043574063917325584775,6568858167203582304319770218,0,0:0,739043574063917325584775 +div:488239617545415130712260,-175755600464230772602,0,0:-2777,166315056246275196506 +div:-45020591983716715,29238208588753924571931348,0,0:0,-45020591983716715 +div:7127560906474483695,2443668648642679038,0,0:2,2240223609189125619 +div:56992002738244984812189281,5608720362174497796029,0,0:10161,1795138189912706738612 +div:6460467352419769344150698,317411399503484718457,0,0:20353,193138325344869395377 +div:-932907356818921691594434039,-97184909630029367110035347,0,0:9,-58243170148657387604115916 +div:3995705323622443163782,89030590085262709211588,0,0:0,3995705323622443163782 +div:767569373426935379750,1549154787571680632324257,0,0:0,767569373426935379750 +div:931318846320283067427330537,-86130685020277950106,0,0:-10812857,65883975492678017695 +div:31826303162303263286188,5737442550621928753,0,0:5547,709334003424493297 +div:57706427262137233402480,76482797550886260948017,0,0:0,57706427262137233402480 +div:72853807229779038632,3169975417424853790892514721,0,0:0,72853807229779038632 +div:656860988961860702860500038,2051614607117987332942,0,0:320167,1695044716052434458724 +div:419136122263611128595,629629147994291589835819893,0,0:0,419136122263611128595 +div:21718233877577237636870231772,28954985957426921952977486934,0,0:0,21718233877577237636870231772 +div:8137115583255366542038482,-53056312894008476008,0,0:-153367,28043639968602119546 +div:350144503855608500819,279913875130875757713464,0,0:0,350144503855608500819 +div:67536193348303696626965587175,157462565791912473045994827,0,0:428,142215189365158163279801219 +div:-6653909716122388287977917,-456461036794945909189066,0,0:14,-263455200993145559330993 +div:37893238038459578489871345783,58476986428077111625242,0,0:648002,33879092754002491279299 +div:9750862793806595478546835,831707298467569713898,0,0:11723,758133871275722520581 +div:82929154752623245294293,793446150807998771837734747,0,0:0,82929154752623245294293 +div:966515993017183338978310,77669990894453129707640,0,0:12,34476102283745782486630 +div:158090994204861340057333,31910675611432229121455470549,0,0:0,158090994204861340057333 +div:1330572162878429717062,21084117694617750279966598211,0,0:0,1330572162878429717062 +div:832245616705658749585054836,-6079221966362676227357795958,0,0:0,832245616705658749585054836 +div:-566340281799124821634,146366719895661144175,0,0:-3,-127240122112141389109 +div:4970340520764553911461,91205816337394717102255090410,0,0:0,4970340520764553911461 +div:3278473198323030526681,2105717666245284028185,0,0:1,1172755532077746498496 +div:2122422503626206527321754,17148805521927416661130,0,0:123,13119424429134278002764 +div:1912021218223919631352475809,38185948805565948914414505595,0,0:0,1912021218223919631352475809 +div:941796603263493070268724375,444845019508763781185108406,0,0:2,52106564245965507898507563 +div:104754716329414707284533930,43667472164404259911976738073,0,0:0,104754716329414707284533930 +div:89122706354696915439758538,31455209252293039108428126,0,0:2,26212287850110837222902286 +div:118480448597792962897533,67244410472175197017373,0,0:1,51236038125617765880160 +div:352695831583961620878034763371,8582622957634803011445036406,0,0:41,808290320934697408788270725 +div:-624005759812006640839,8172000984425101361637221854,0,0:0,-624005759812006640839 +div:7384400794640347039203,-628293484000022806320912136,0,0:0,7384400794640347039203 +div:-2828685708623719356215,7634212328177549702763918762,0,0:0,-2828685708623719356215 +div:-86550506492571342719558,666034531900739098444599,0,0:0,-86550506492571342719558 +div:642452648202950019476496886617,604805196719437392366385471,0,0:1062,149529286907508783395516415 +div:4662456248509569207839,-33567555776748285848111,0,0:0,4662456248509569207839 +div:62996041896426933131446657891,763936004120034809021339118482,0,0:0,62996041896426933131446657891 +div:8345367673768217736530,3642617362546668617513754,0,0:0,8345367673768217736530 +div:-84451394313979740929245775,1334835508641575600458674242637,0,0:0,-84451394313979740929245775 +div:1176029794050678765470272286249,40628825039402391375029153,0,0:28945,28453285176547120053452664 +div:7707482263998465479379,-2829972969411199798203141,0,0:0,7707482263998465479379 +div:-11136894339272544791100807454,67013816338042624404219,0,0:-166188,-2229685917126612460282 +div:-428729652188276782322695284232,-774565897177367154457859446208,0,0:0,-428729652188276782322695284232 +div:626676530287556077206017712837,908674926870287524187734,0,0:689659,688897120453562229270131 +div:2773148741407028218531427,557528937606955521382821134,0,0:0,2773148741407028218531427 +div:75539539184325529932345561314,-502273785664131486016696176,0,0:-150,198471334705807029841134914 +div:3606180022705211288777456393,122973836595862158705454565,0,0:29,39938761425208686319274008 +div:-30856676793350414230630,38692347037119733077452,0,0:0,-30856676793350414230630 +div:28070532442085800846842,6911568634505880039237117,0,0:0,28070532442085800846842 +div:94746783288740489316741633573,86780043180255118744681,0,0:1091803,71804408409905942683730 +div:-24888475865091602999453808074899,-2607720766137261712927817388,0,0:9544,-388873077577211270718923827 +div:53207047214418054977598334400421,4391350648985919720756952364,0,0:12116,1442751304651640907099558197 +div:944627096784739396211350732172,47554680361438235326247368315,0,0:19,41088169917412925012650734187 +div:90507814687564826997063490,263428140883010973433496,0,0:343,151962364692063109374362 +div:40830360719924046206003172846797,289018741615486979391301844046,0,0:141,78718152140382111829612836311 +div:46815309089103159131589670878273,844714076577304483690089137,0,0:55421,410251112367341001240816596 +div:766097719529863726042659,864954870692483641146857,0,0:0,766097719529863726042659 +div:36588837904828449995291554992448,5981291437419281216117821938,0,0:6117,1278182134706796298838197702 +div:744905055097349284759083504,-402232162933870784393172,0,0:-1851,373321506754462847322132 +div:-496174511680228005426626189898,6850190505814392535531175627173,0,0:0,-496174511680228005426626189898 +div:117807976873474930026716,72472466715338440688738889,0,0:0,117807976873474930026716 +div:29688886500382323149926912509,171231756792519788711530194,0,0:173,65792575276399702832188947 +div:95600026518374000257859,99155834015695214013381,0,0:0,95600026518374000257859 +div:947283711638216525748681460035,375183675933541675266484,0,0:2524853,81906386026327073533183 +div:41432664026918887246001356,89293848269510580767075145704,0,0:0,41432664026918887246001356 +div:347133325715091646723859014383300,8007256671477794251698509596618,0,0:43,2821288841546493900823101728726 +div:-72131155022320848089529987358,607237864853852225127081848,0,0:-118,-477086969566285524534329294 +div:52607679919645038811433035271755,-86393659667162016384842618430,0,0:-608,80334842010532849448723266315 +div:507690908006392398957998748,2764904388542893841465155862,0,0:0,507690908006392398957998748 +div:65723044947927998584588839362573,-414671665541745655865677654655,0,0:-158,204921792332184957811769927083 +div:58581181220230933312243002393,727812383468376773626369395972,0,0:0,58581181220230933312243002393 +div:55621061599265643370130457,75058109335016054327498821167125,0,0:0,55621061599265643370130457 +div:8042490680681402413656869107,985374040566072816763255884821,0,0:0,8042490680681402413656869107 +div:205865392688566277909245217913157,188746850681839171579701059,0,0:1090695,146384137702663123171367152 +div:645469876768555458540596006480343,-1176209889279660120170867010701,0,0:-548,906857443301712686960884616195 +div:-372748268475137934411499506,-6952751051457138928077564508,0,0:0,-372748268475137934411499506 +div:-53726448220098738825476944862,666316374954612779881255280093902,0,0:0,-53726448220098738825476944862 +div:3999043104096914451698824,53972081370928852391234278,0,0:0,3999043104096914451698824 +div:6875840365821778484266515548732,-48235349383818088293481585385242,0,0:0,6875840365821778484266515548732 +div:464946247859367335487708854577230,-91038566114714256247221434416,0,0:-5107,12290711521628833148989014718 +div:774638812953340934130134234932,1781076313255841252742417918164985,0,0:0,774638812953340934130134234932 +div:181439807984506382551684665,983773852096178563301436779,0,0:0,181439807984506382551684665 +div:-16817917749776745039099453680,29825644384864912855101360,0,0:-563,-26079961097799101677388000 +div:22133214432524045001245001353,-198976752808774771294935518769806,0,0:0,22133214432524045001245001353 +div:2921499120428770523924215,57361572214425723589097781,0,0:0,2921499120428770523924215 +div:123171649003149782751271079,-73094968897222766037958236983376,0,0:0,123171649003149782751271079 +div:769172117059026460908975826,97495810773186124439901474,0,0:7,86701441646723589829665508 +div:94112063717361782849247888341,9764365600045726199272325886020217,0,0:0,94112063717361782849247888341 +div:9469809875854665598033283678676801,13423826176729482294685830678,0,0:705447,11970959382501694048484373735 +div:-842464855184253146889699,56551832462429857048225522,0,0:0,-842464855184253146889699 +div:598571783530686410412162091727492,943878487966896512387279950152,0,0:634,152822159674021558626603331124 +div:6953911548504792867117243682880,-1243290077624733705142673151816,0,0:-5,737461160381124341403877923800 +div:-9281561117131091717433858956,24045037010263371696747810870864,0,0:0,-9281561117131091717433858956 +div:143976137737540251569359185478383,265536580911922810877928898030231,0,0:0,143976137737540251569359185478383 +div:40928612217108238156488248958516,652899471410195581619563697,0,0:62687,303052817307731502659484677 +div:-70884981920443005098389267,994979502748896336180903347917699,0,0:0,-70884981920443005098389267 +div:6634749014277303650696175833,495438828683857357740137178054,0,0:0,6634749014277303650696175833 +div:7422909929360831470432375670687378,44420776675922024505687379448537,0,0:167,4640224481853377982583302781699 +div:46314400055365971953154263039,8152799875814716360460312147,0,0:5,5550400676292390150852702304 +div:6591812486274558813658703427,17421702938564211067047963695822,0,0:0,6591812486274558813658703427 +div:124008796997131146663153333663944,123778079237035114605937158,0,0:1001863,119198477435638705314738590 +div:7901064786124799043739659032,5571379890858077238984496202525017,0,0:0,7901064786124799043739659032 +div:-6965802504602789618852220893,639736224353884761032877844589149,0,0:0,-6965802504602789618852220893 +div:971873099542038287548098257,33891065268003504765508649367,0,0:0,971873099542038287548098257 +div:675025802085588841328307981424510,5883130258364185867146732282508,0,0:114,4348952632071652473580501218598 +div:3002202702401536393223671580,32010263936497485071510555,0,0:93,25248156307270281573189965 +div:34972912833617921349910233,474530829196480379440614753566093,0,0:0,34972912833617921349910233 +div:276535788922741466724367182792751,-9977731202427442856055105791931326,0,0:0,276535788922741466724367182792751 +div:14688056569711843047315045,33632661368158430395335244297,0,0:0,14688056569711843047315045 +div:-879571497507836359459742179631,46691865250496831422027355865479980,0,0:0,-879571497507836359459742179631 +div:494117042357580878818138056,29316968901414007402594292795459,0,0:0,494117042357580878818138056 +div:1256269358576514580546391822558882,-5715622931835594771199373401675,0,0:-219,4547936504519325653729047592057 +div:-7954432693582559842284447426278,-1415175992700551307691498753891217,0,0:0,-7954432693582559842284447426278 +div:9290637525511632506517536450,31193173758140935479273605091020135,0,0:0,9290637525511632506517536450 +div:741965597318745797468077425593,5090853342489379493387893,0,0:145744,4267770973672583752348201 +div:28726807242801656618422278445,-66260445037131724567939080371803922,0,0:0,28726807242801656618422278445 +div:600680612706025211965401567803,601606994582634974447563159467,0,0:0,600680612706025211965401567803 +div:-66914527546382741959361703369956,7595234786937152212557447828,0,0:-8810,-509073466430966730588005276 +div:-477200248767482289180868434831103210,299754033389841609330851428,0,0:-1591972736,-104820787767789757788436202 +div:1602055237860095405473195539557021,-482613481963019529862911261825616,0,0:-3,154214791971036815884461754080173 +div:5847782734638264086149188726633444,856996324395574391409855532415801398,0,0:0,5847782734638264086149188726633444 +div:79271780305017072764462340,334727107872141024597713303,0,0:0,79271780305017072764462340 +div:-8309528822503909832876248028239283,-280321240085800591419535364757,0,0:29642,-246623880608702018380746112289 +div:-7036110366628173318660022670592,28316814714059617609323292157,0,0:-248,-13540317541388151547846215656 +div:948009776246268508005837034128,9919518492899054009114568949283,0,0:0,948009776246268508005837034128 +div:18836117763174709382287464458,-95991422838941512823432481785039,0,0:0,18836117763174709382287464458 +div:46329535017445104282274302989008943,2426057049787109955278434918171122342,0,0:0,46329535017445104282274302989008943 +div:297935043427322209379153089088,5013180436585374804022483003677803281,0,0:0,297935043427322209379153089088 +div:-118750521055580916050992218218817,60015490720625049417386142837,0,0:-1978,-39880410184568303402427687231 +div:575684179239053603789472576628353,7053037456193336012438564397416,0,0:81,4388145287393386781948860437657 +div:-22678246623112702170004970988490199,56088891589189424871010131732,0,0:-404326,-49442422098769608928465817567 +div:6471427876906983381994784223,7282306840714785835314255152341703,0,0:0,6471427876906983381994784223 +div:603142728037804458149682405206,-650651299197030110194378722974,0,0:0,603142728037804458149682405206 +div:95931851622486456387293188404091,30758076059621180125667261744973187,0,0:0,95931851622486456387293188404091 +div:-726881908942360166762114252209703,363140012331598428300964292698,0,0:-2001,-238744266831711731884702521005 +div:615441001400268210176031416893518,64796591895996509835103891278541,0,0:9,32271674336299621660096395386649 +div:-84863286321984569539608600726350943,95803928515186040910470967405915312,0,0:0,-84863286321984569539608600726350943 +div:127629355200690947978534550183,797344806129236668518995114759425,0,0:0,127629355200690947978534550183 +div:2288916268196725535426416610805794415,4632856553925567389796050303893057,0,0:494,285130557495244867167760682624257 +div:976908939861250135603632878187851391,-6608040757199335387091406901838035,0,0:-147,5526948552947833701196063617660246 +div:-12183790198926859582276525192366339,3503085624005426351029343283863,0,0:-3478,-58398635986733396469251090825 +div:162265381015355009933791722345838,7623537904684559645894301151112382716,0,0:0,162265381015355009933791722345838 +div:-593766143424589564713907089125639,224331769330731597387481028255128,0,0:-2,-145102604763126369938945032615383 +div:604869729619335696245226863211466041,93942209533557682128293773108407,0,0:6438,69784642291338703271551939541775 +div:742895297953619211242501957373791,531142018450802021651202332570,0,0:1398,358756159397984974121096440931 +div:27653047597891730507139754824,5480890077990244820355276983606,0,0:0,27653047597891730507139754824 +div:3784487646863079978435416373977,694796147453752363831293132728,0,0:5,310506909594318159278950710337 +div:2973223272105672225946453215625903,19361627619874023404230915287,0,0:153562,13011542577443945945402323609 +div:245900231135215525853387549499,-7177692471091872136903418261273,0,0:0,245900231135215525853387549499 +div:9997981965333038339861175645427,-4045879607573312864719096965459966764,0,0:0,9997981965333038339861175645427 +div:6806842983457720589405220668623962,-927052066456609430942182858322,0,0:-7342,426711533294147427714122823838 +div:-122270014267619817663497887649323141,-2162707234463692663424997827917303191,0,0:0,-122270014267619817663497887649323141 +div:-73410057200050892585310982601,-2781563564880350086545084449330,0,0:0,-73410057200050892585310982601 +div:41074074074626336295845220577523,73580647879659031572628791338989878719,0,0:0,41074074074626336295845220577523 +div:38518920335521852358928552909455,934752467373574138232063654381123270465,0,0:0,38518920335521852358928552909455 +div:4300545050696782443239516173845124,-9078020631753897849258060104921396,0,0:0,4300545050696782443239516173845124 +div:9125102035522831694438174632387280948,14030892071253083076166776508287771,0,0:650,5022189208327694929769902000229798 +div:10049229592281672286226252965830,-947015519470033748849687371329705317719,0,0:0,10049229592281672286226252965830 +div:74199952025194030063111669270731296,53730729670173947678290654632594,0,0:1380,51545080353982267070565877751576 +div:62962644403023975314385553509953336,18661881999119919255366397124335,0,0:3373,16116419992487666034696009571381 +div:-48885268599530160005042589357517742267,1224963343286960109782754733806,0,0:-39907535,-1103588784380283462421739114057 +div:8260532189465861184106347872307,8068023378797368816499164870542708410,0,0:0,8260532189465861184106347872307 +div:-873293644410280888333970242222255556855,-53468033733881855748079429886216144,0,0:16333,-249434788538400588913890687276903 +div:8118527378780784121252739484687134,7449409022714146507892440406735208908,0,0:0,8118527378780784121252739484687134 +div:28529491283005611559168619648453262781,-883723803503785940933815830371,0,0:-32283266,663961158020941954801575391095 +div:899559711064017522862617539102500,-566535897303370911043077254061825,0,0:-1,333023813760646611819540285040675 +div:15574337293150371571515035679594790928,-55555266615224096139156320494291715,0,0:-280,18862640887624652551265941193110728 +div:4585681465427957919096525629579,66250889555016187900342661335447207,0,0:0,4585681465427957919096525629579 +div:740366425347027728645955294884621471,-8981847007405192941035608249485839462,0,0:0,740366425347027728645955294884621471 +div:995741708152482543471981480782324347091,21342276145547465497291491758534,0,0:46655834,15123660154109622191683793959735 +div:-3250628989112846425058431588079956,188350448043333903099558871335715,0,0:-17,-48671372376170072365930775372801 +div:876756580410958121101100042110445,700377806984105935223010779109492,0,0:1,176378773426852185878089263000953 +div:273777021637125264614902200521817247,5596822025834012700584044296044,0,0:48916,2875421428699353133089736528943 +div:-464090250274653177412801749314226,331074623300822560323451165878,0,0:-1401,-254703030200770399646665919148 +div:396075925225537300206063956732379,43995671606762821537409289353046922,0,0:0,396075925225537300206063956732379 +div:-18658324380438997683615076571716,5092778408442460759386491384527084996615,0,0:0,-18658324380438997683615076571716 +div:-3965312367885757866883408465644,62732726984931603243998191276757746,0,0:0,-3965312367885757866883408465644 +div:18384490431288410418670437084794892,251064583418108672333112094297258,0,0:73,56775841766477338353254201095058 +div:5162911931645462592809376061314438,276766756569293637905979057590818,0,0:18,181110313398177110501753024679714 +div:8135417534757202149267580550442399,57219388491890904146726624261571751057,0,0:0,8135417534757202149267580550442399 +div:182770016919229728734188047616685,-40885421527209929308823628618058876,0,0:0,182770016919229728734188047616685 +div:92048299381294008029880374643382,11111217138310865417953673269446,0,0:8,3158562274807084686250988487814 +div:5200981870655088437520091813182496782,8050665661143383427978138223450564832,0,0:0,5200981870655088437520091813182496782 +div:756533369514441505798425699358577956,213131801093410029221386684045445047,0,0:3,117137966234211418134265647222242815 +div:799371912191908595027684426426504203412,17112684578666430604042990191541053858717,0,0:0,799371912191908595027684426426504203412 +div:1298725911189943981172370165599649,65794189885654690328812265324475773,0,0:0,1298725911189943981172370165599649 +div:860525228612860972598185202071685976152,151574827288199259902280707159394761797,0,0:5,102651092171864673086781666274712167167 +div:3584182117338772880305442381515310406513,415718227605762773246300051378162,0,0:8621662,71682816997193200587950163461269 +div:3468267249506034567392210570575412440358,2065367734321219422680254672539,0,0:1679249264,1757779312273888004381735679062 +div:50367071916831078065713924791723412318,65724451969804512659247548060987947789728,0,0:0,50367071916831078065713924791723412318 +div:79874071719000306927937931805669,6145217682421427626924604560525904590,0,0:0,79874071719000306927937931805669 +div:423797068560673311763985503147656006,69667145306964427593061472412068457736722,0,0:0,423797068560673311763985503147656006 +div:41523275633578269444354516606248777741194,-694978110274856348249211949536413124775,0,0:-59,519567127361744897651011583600403379469 +div:-87407113783597425860610212435025646,22427444695442827429769682014306,0,0:-3897,-7361805456727366797761625275164 +div:-5398995964042513456203407110806239,759328487523337723297727841375739581,0,0:0,-5398995964042513456203407110806239 +div:-486450683665060870587027665253017864,98034404319738594732566595585128,0,0:-4962,-3969430517963524032217959612728 +div:82802462159510025179539722591174489656,-7995658647747583535810574975199511344136,0,0:0,82802462159510025179539722591174489656 +div:-9247518837150320354892251517725,95037788396291796059988855373871527896146,0,0:0,-9247518837150320354892251517725 +div:-5710350451928497877474611321475359,884522303455599132933755693677751985,0,0:0,-5710350451928497877474611321475359 +div:-6247471877283545360155543727272765071,675373004151999159209581260366203727893602,0,0:0,-6247471877283545360155543727272765071 +div:549120950829660962410197911937811,48123906347804179379843793292937012521427,0,0:0,549120950829660962410197911937811 +div:-106448127960021997407899520808890,9065012874636494312839056387435045253097,0,0:0,-106448127960021997407899520808890 +div:69560159021211857117768649206402791,351520915367913488351778070201730208854,0,0:0,69560159021211857117768649206402791 +div:603624320694634013723571987622589,2701844331050375027455889272518786,0,0:0,603624320694634013723571987622589 +div:67014256406500009956329723823638317486,-1091809123530714597985512683792998,0,0:-61379,104213308278646576940805107893244 +div:235637292979855521853832255322576,-189051691838200548750099363324518519845,0,0:0,235637292979855521853832255322576 +div:46621760725175766077357844382212912326,382903788461287808084560177696868561667,0,0:0,46621760725175766077357844382212912326 +div:17972807610345735075506894651990254671255,55415225623081699101048670679962759717300,0,0:0,17972807610345735075506894651990254671255 +div:-99369177703763557258065488925907194288158,6888487468349330333818924437618675770942,0,0:-14,-2930353146872932584600546799245733494970 +div:6974086110297401606708008289033796059,298190885369602196463446343967843,0,0:23387,295874158515038017388642657851818 +div:22082353893401399289701395360491738,34004577923140732261317680713467602,0,0:0,22082353893401399289701395360491738 +div:3021321469279908093607775280467343863,54418828629265035058612376701138652,0,0:55,28285894670331165384094561904718003 +div:-773023736068095185985747288307356,62254616741081128985277622196480901,0,0:0,-773023736068095185985747288307356 +div:-2914004549648558380597177821180027971982,41945684266123534509905568470747536706,0,0:-69,-19752335286034499413693596698447939268 +div:7760354325840316590533609759835164008896,868363194633558774643668133661139838,0,0:8936,660818594835380317791317439218416528 +div:62481824056284557813538132809580514163491,3063406952822650811300655756477238,0,0:20396187,2989413594030548244777844306671985 +div:999032777586519798809642100185769791083086,53063722362186015952243063915405514648,0,0:18827,2076673643676476761935850430166805190 +div:1470131951969797494200280446936328952439,-985834190529311083948780402821210768,0,0:-1491,253173890594668032648866329903697351 +div:695257822575467619322639555633582443264,6467796678447835413755920250534956,0,0:107495,2018625717551520946908302327348044 +div:34431866058056304430649293119014790521,-66121478435132244087535870280208408759829,0,0:0,34431866058056304430649293119014790521 +div:458534877296422067611914397253412590469,229983379105475980155252782290948271559418,0,0:0,458534877296422067611914397253412590469 +div:2185065840509747880280098827050369,-23363950333069346956170201374188305,0,0:0,2185065840509747880280098827050369 +div:660127414048214811857806676633782977984,64123543109305824067686258949394280427,0,0:10,18891982955156571180944087139840173714 +div:748036409612739266280596599738236249637,-89094948094100676872295250639398845430367,0,0:0,748036409612739266280596599738236249637 +div:9049727473118706892393777842066328396165263,3856651773197697798307166289847038513869,0,0:2346,2022413196907857565165726085176042628589 +div:980189895420499303642948634803744800389758,-3190314421704305860902855244770982859,0,0:-307239,882810490075245016292255552797773457 +div:6108171433112534565184964245024814724366,4260996317082295106607737650284809362606641,0,0:0,6108171433112534565184964245024814724366 +div:358196359808272615858599795581371458918250,9543484816419438536292482064209522533404722,0,0:0,358196359808272615858599795581371458918250 +div:44482449128693269579458765976093879533678,400743721350983175894244132476709300635,0,0:110,400639780085120231091911403655856463828 +div:832339795151923812236511477767777941,2368224477252854985783540371974941967671687,0,0:0,832339795151923812236511477767777941 +div:-27251313242004640465020477977011074115415,2399123426123186914483922523780597130907,0,0:-11,-860955554649584405697330215424505675438 +div:434369443368140265771072488323999183210887,7582603002573727151808563609276596120660,0,0:57,2161072221437818117984362595233204333267 +div:-797664602996630747189073160786968930897788,8488149668482536480367533655921312940145901,0,0:0,-797664602996630747189073160786968930897788 +div:59063238214543857057620510112580247310883,28114133320457432516252314750546246,0,0:2100837,26711994025902474545948986923502981 +div:1573691164802147334879722389254185849497882,-7127075045154454822615337483298105005772756,0,0:0,1573691164802147334879722389254185849497882 +div:-40379721983479963451044525213342063379,5752617301360961501951105993116579979599761,0,0:0,-40379721983479963451044525213342063379 +div:-66553094204238345681366812314746973,179491260943660304940853680122139916257,0,0:0,-66553094204238345681366812314746973 +div:41557707370513928375878448109901883,632935174723424546856310964927309397,0,0:0,41557707370513928375878448109901883 +div:87216666974663503011714591959065214272591,-362212517956666997849487067083877113331,0,0:-240,285662665063423527837695858934707073151 +div:600930802118279524585230000011936249444105,276956438642688260499397309603052638,0,0:2169766,138070288388354494697143759139301397 +div:-9062026573948610573181435477111972535105632,26459705612915075584081819752039455108,0,0:-342484,-756815003826842757521154491791897360 +div:17653370013085499100472199530821555711,-7698383733180213420749857647904028433762549,0,0:0,17653370013085499100472199530821555711 +div:30662369693082036358310810281385879664,22236287546685236318100930067052020060194,0,0:0,30662369693082036358310810281385879664 +div:-512521060439171480106970932632563580,89514481912211104455621084880967327358452,0,0:0,-512521060439171480106970932632563580 +div:21086477798868875028201033077501739509,-32949987996179141109692270028847703801843,0,0:0,21086477798868875028201033077501739509 +div:-708751005350456170908462092345570661,20771494122418135637231294901492781698,0,0:0,-708751005350456170908462092345570661 +div:4761140473028193547540165802031057658,6168913684826084448506253549769822795,0,0:0,4761140473028193547540165802031057658 +div:1006721746946704053236444265263223831,-68339952093888456017995310177868766706,0,0:0,1006721746946704053236444265263223831 +div:49477930040212907700651237822802690917,932149775404881165633388914278605445476133039,0,0:0,49477930040212907700651237822802690917 +div:191141779546296204030941021563218099367,3656389331006196783212925046242222356116162,0,0:0,191141779546296204030941021563218099367 +div:52321773961113824095699208419101883834511175,3945419458824649179733387424219698232106948,0,0:13,1031320996393384759165171904245806817120851 +div:1778145454400348709637901904657092758,878609889134331105537302232981688580,0,0:2,20925676131686498563297438693715598 +div:74713594237827753439495191401245889889,5392802592936410381907322733518534312,0,0:13,4607160529654418474699995865504943833 +div:270095098083877602963826744218949767,47636389981971696673999931157764182609,0,0:0,270095098083877602963826744218949767 +div:7520391039221099182471773929113536857,381897415343050691905932641495648269699614,0,0:0,7520391039221099182471773929113536857 +div:63508808128380210731820150543656327585,-616515868713883945771114329692765309888882,0,0:0,63508808128380210731820150543656327585 +div:500726636417051241894505979036450257584284510,-2188106361907716060317149708820198851710,0,0:-228840,376558089498651529439670035952358968110 +div:9644202180018661897773323824784604735459,889341707658332087101739860527895964627301119,0,0:0,9644202180018661897773323824784604735459 +div:2169616399713342398130612752657502922,-320164160717395068313105728380324945,0,0:-6,248631435408971988251978382375553252 +div:-5377162725601993828110678056377142779006,55796345170536010537794307342731868052,0,0:-96,-20713589230536816482424551474883446014 +div:2037294950563567811082451474155649111,2834014022081568485840663386191616163,0,0:0,2037294950563567811082451474155649111 +div:614981246208238240735840654289003858288,59358494220000869333484696079415051563764262,0,0:0,614981246208238240735840654289003858288 +div:-869974954402953214631782702522562619117445900,461625972083775526198257072077692914743043,0,0:-1884,-271622997120123274266378728189167741552888 +div:502948632448506662993366487259075217376090892,42616114515034714091468739214068502864104,0,0:11801,35865056582001999943895793852815076799588 +div:6366779403200391484287273535628255514,82250958048563873223556347205141650947263970,0,0:0,6366779403200391484287273535628255514 +div:23811157225570913409830665082241103895611,7476929574668972035850358498197955282806,0,0:3,1380368501563997302279589587647238047193 +div:4433024520272083942063140827835336668419,-6814734610056822899976511626133696026724,0,0:0,4433024520272083942063140827835336668419 +div:968786326198881698061088417967223975939,599601873015338765622213846860944593816,0,0:1,369184453183542932438874571106279382123 +div:9195492262506042027630313206086692630450795,64887542474450141869346719067771980637953781,0,0:0,9195492262506042027630313206086692630450795 +div:167036152523476713010727258508768159942500,515803210529897970656947678674520384659564747,0,0:0,167036152523476713010727258508768159942500 +div:8138478748257408221805876607659300558448,49661986735515173743313027014090079675,0,0:163,43574910368434901645853204362617571423 +div:59222143484521909529262811142486420090033691,-51030363360606792052118776207857821648905144,0,0:-1,8191780123915117477144034934628598441128547 +div:-467669865565641334900015053005237790,-4166801708575196388168955453453946582052,0,0:0,-467669865565641334900015053005237790 +div:77373277085707339767125359451768440817535,1763315960012269607653138271304663086,0,0:43879,736076328961652913305245191129266941 +div:55495442705704588053146646518531149753186,-5663458625155167579301715514248517944795126414,0,0:0,55495442705704588053146646518531149753186 +div:488849922299811997818757217594597733202150566,939685030270889494431285974083671162411745,0,0:520,213706558949460714488511071088728748043166 +div:2400821515253609347478984845179365395392,174683346240076973534036449659865563554754338,0,0:0,2400821515253609347478984845179365395392 +div:94256886099064494671287831080381327786727083,933612219301830695726258097049775646275143622,0,0:0,94256886099064494671287831080381327786727083 +div:423105830682881413387057917631404228266134,257145583503215058907245918993287651344,0,0:1645,101345820092641484638380887446041805254 +div:9725239973027586290174961618324279259233,128059695274170533356219539907244279505,0,0:75,120762827464796288458496125280958296358 +div:8575857564646639781619620979013176021242222,-79327770769273229627122866232866675878,0,0:-108106,49577863588019549876402042891158775154 +div:8813097514151610923608219242438159700407184937,7989256671292882171963354392382046005647066,0,0:1103,947405715561887932639347640762956178471139 +div:-4220854853661426119955083509997540633581226963,-3143361547579787840091976435701544993088232,0,0:1342,-2463656809350838551651133286067252856819619 +div:18064088683968825697348480535147810355871,5304724916018022284963666250494765425823768215,0,0:0,18064088683968825697348480535147810355871 +div:668152482128694155192224637784736382693510,-95257956151627868536527340956566505149833532,0,0:0,668152482128694155192224637784736382693510 +div:61701221596016091555562189539716738900156785,-204037550501076287029400288051994390707,0,0:-302401,62286940121281584513032505583155969278 +div:9028974806172994844965393599047382592,34693980268705780311458320694963675758359651,0,0:0,9028974806172994844965393599047382592 +div:89063698366423052530435721631252853122745595691,-559482379459044468566903354300289497747749008,0,0:-159,106000032434982028298088297506822980853503419 +div:-1824554464595257659941777994663246309941052,73623748997742382675661945460325724770677,0,0:-24,-57584488649440475725891303615428915444804 +div:-55142421317035129657275321126826228423017036239,28826110399433506733627712523209314338730651,0,0:-1912,-26898233318264782579134782450019407364031527 +div:756782070286814928506227576085403683630,4000214993529718974257266487592194977145045820,0,0:0,756782070286814928506227576085403683630 +div:13159677289487357602217280155496420963004939,767301253318942647744497962442472942956,0,0:17150,460795067491193399140099608009991309539 +div:-88187589231094865339990742097539889292776818,510825751942051438265912944524438114392912,0,0:-172,-325559897062017958253715639336533617195954 +div:489109845016577010833075435898092017791090,110123269200994712057868031610104395461351967,0,0:0,489109845016577010833075435898092017791090 +div:19217131883780524110230989478044970954979,970929416394097229812264700944439582834558,0,0:0,19217131883780524110230989478044970954979 +div:24527357215769113990068349908153315315362058,-266862918096402442472122404915934028297493384268,0,0:0,24527357215769113990068349908153315315362058 +div:187180335008792237327827003721933462481,-854140420436008308741513900838309996093,0,0:0,187180335008792237327827003721933462481 +div:545261221970766906869881791377703238778715469,-8788464536650499527970204831752102396425142510,0,0:0,545261221970766906869881791377703238778715469 +div:-8978883239491077969334655758351790550761758569,404693816228247849601154967878424829635,0,0:-22186855,-219438296026172022653503521227250310644 +div:1672482949489286830657071584694755544154,-16569314415512041409298987093228138867183570,0,0:0,1672482949489286830657071584694755544154 +div:774730270533571544207396913338620375028137352997,48786260906229317422119214339872570992323,0,0:15880091,7792907516676258376772939019266087811604 +div:8223377606023157629124739253629162465167167,520715840696524916222797841353549481506911,0,0:15,412639995575283885782771633325920242563502 +div:19134961218524422663618095601519767611971718057,3320597299770542518684500859989485655905,0,0:5762505,2675610172546986065973326056572390876032 +div:9685331182266568794457591582614487872504040,213566802520062116223869626405725301078500,0,0:45,74825068863773564383458394356849323971540 +div:59252244414367138020160608470582658601544,-3576888946047794041513522160303428731243100275,0,0:0,59252244414367138020160608470582658601544 +div:9042130790289921021769539257940643994441439005,7080061253408914683252703075136834100504476,0,0:1277,892569686736971255837430990906848097223153 +div:37181356995874904748900986598480003983051,519027821181254318600589595065858229824972513884,0,0:0,37181356995874904748900986598480003983051 +div:4809573571268875241068163376639283894303,397857290741686940249008741474516933138008,0,0:0,4809573571268875241068163376639283894303 +div:57672160438267186781489366189915687528444846039,4311847164079124929339394059428992929411,0,0:13375279,1613350112775719684954110326408545415370 +div:8624907898892313136658244150578480770110291,18756723497726238453263886656453055357901904440,0,0:0,8624907898892313136658244150578480770110291 +div:4229153408642008158454182552166239580124743197222,723306877996286799790273745169628337170848,0,0:5846969,515510937124971245462645522951165247237510 +div:6302453408140626668691370469108993823368172,-26870693985061276927685322296318387971972897857,0,0:0,6302453408140626668691370469108993823368172 +div:-26183394096110224783461710144582526395666,8931365187310300822957876202988418128476294,0,0:0,-26183394096110224783461710144582526395666 +div:1337734304086488205388200603174151745237404,-37555196523265867970637056819130422860022,0,0:-35,23302425772182826415903614504586945136634 +div:1394934047175944473993592421680155397883435756719,3316595803755393152259408400413331925963184238,0,0:420,1963809598679350044640893506555988978898376759 +div:-3923445604156694953553293681269071976204126084324,-2385865039714571024603149142302411580843310590047,0,0:1,-1537580564442123928950144538966660395360815494277 +div:-4666574422365035446555661286742673507442477825880,6511395679936223490637275038009230986077915234,0,0:-716,-4415115530699427259372359528064121410690518336 +div:25682320341721789029990750876038989350503,2075225204575110735785546638041462321365144552208,0,0:0,25682320341721789029990750876038989350503 +div:507066551593936721924672174902109570507318,-90150385867099161583728850458645628165485311877,0,0:0,507066551593936721924672174902109570507318 +div:56460765920562193755877284769059649453013,106293089508542656937426290853822589311742,0,0:0,56460765920562193755877284769059649453013 +div:113389347059878790962060029189435317366606631,9123943931303946176502291145148092536746735300,0,0:0,113389347059878790962060029189435317366606631 +div:90965037743938985628689890077906379958065298745,355159479956085299356917050991168761100055,0,0:256124,171099666594416198867309844272190074811925 +div:-165340776845080586286334926027619556728505,4315813260375908780045944338058657645416510920831,0,0:0,-165340776845080586286334926027619556728505 +div:9675893678882076470951813438529414802324809,-49138410559062258960736821789190923818163376047,0,0:0,9675893678882076470951813438529414802324809 +div:52196020861900342939093799976830869614855,898691237498364401852494744239741816001653191,0,0:0,52196020861900342939093799976830869614855 +div:546701462352913231490095779602087905799659,27796772128829838971566803617855813694963277,0,0:0,546701462352913231490095779602087905799659 +div:-239361790908041495849499565651036682869595828,59582341264073879085346989042621623014587677976339,0,0:0,-239361790908041495849499565651036682869595828 +div:26247208631803295885744522675941429011719441867,94578293352355651122868883826971735945985150768,0,0:0,26247208631803295885744522675941429011719441867 +div:7151462784689393204933488144237700308252236907106,4869138896069717850331723402637093025616552,0,0:1468732,2675587124367180075367635717394552387255042 +div:444179011665054388522294113788022095382753092,87809235040601661387269133961569114730886240155,0,0:0,444179011665054388522294113788022095382753092 +div:9396002262631352355829080408353148431716175837629,627009066609807681311137500374921292105192019668,0,0:14,617875330094044817473155403104250342243487562277 +div:-67404859652885739843969210485993809184078129851,46946911826310720654816125341841364822782750,0,0:-1435,-36041182129855704308070620451450663384883601 +div:-857317750867775465958757317203227431120067,92423921722813825213538574566017075976934245071208,0,0:0,-857317750867775465958757317203227431120067 +div:-604814342197174902063835288834217421426135297,30987537976824612265560882867080135947080229,0,0:-19,-16051120637507269018178514359694838431610946 +div:537582514919678675297229509855601144545558,97995250751872994415105767317261578435382881110966,0,0:0,537582514919678675297229509855601144545558 +div:39007116647886661941726367331622958240358112679,-5144176915242189162509107363545822402755422,0,0:-7582,3967276520383711582315301218532782666503075 +div:720186514683083735071865829645724624020144283905,921875961665713476662472782679559347600188961,0,0:781,201388622161509798474586372988773544396705364 +div:4925300524276512099528492538263141469746686350,-21746080565844400504762758043901034656358047765835,0,0:0,4925300524276512099528492538263141469746686350 +div:5966000116741864064364725002160835848207074879,452383546194102189149587219685512801821102583315,0,0:0,5966000116741864064364725002160835848207074879 +div:1730022951574373079411594826626220707013971004,867119495065650306148038934759853852208599,0,0:1995,119558918400718646257151780312271857815999 +div:565379733109542105910214574424401953032077613,51059839129853759630343322732850868439955821491756,0,0:0,565379733109542105910214574424401953032077613 +div:380859104711500390575977473068323845888716252660,6180121353081961565969801679654221330060450855,0,0:61,3871702173500735051819570609416344755028750505 +div:68068921222429620875809588817152460375197553199,70847310210650369483877621724938884574632970327227,0,0:0,68068921222429620875809588817152460375197553199 +div:-722057802895969286253197273768040930277501,24306448094583832291685007488076569960645346636,0,0:0,-722057802895969286253197273768040930277501 +div:317592535736773933828600449815426639893020969423190,-93086204599568503148872348535005098881410913,0,0:-3411810,92021920119100246282360210893478434402340660 +div:611020260549327414799176188444349897969388695,3705943065234383781833374645394121853197511,0,0:164,3245597850888474578502746599713914044996891 +div:311597138605996430909903314778924265380533841573,900097580338833508210694004713940730225636589400,0,0:0,311597138605996430909903314778924265380533841573 +div:1471368037568797633184945517471946826925463570,-51986614090044718428104256857291140310189522,0,0:-28,15742843047545517198026325467794898240156954 +div:764577682558529028045406367446280331248422324968,3284529318538080158133345096780067681846690345,0,0:232,2566880657694431358470304993304629059990164928 +div:25345733340779680384223438130261035483720695,-4963832661075587414370207844502105067515360717435242,0,0:0,25345733340779680384223438130261035483720695 +div:9728219568997241790958216942026281594007662902,4830901363966824643813184028118279269292788953297,0,0:0,9728219568997241790958216942026281594007662902 +div:378990675295147250343254009937685278864098648256945,1608729233755427518873468676407616643664376791798088,0,0:0,378990675295147250343254009937685278864098648256945 +div:898267137520595727470006439782753575720539020,-10549538784345819645739254144254774260670381268575,0,0:0,898267137520595727470006439782753575720539020 +div:5995515572054268086933479746008640056780766451925,8030600055411670042494710011412948461403231,0,0:746583,6090884857231597651661557926755620958042252 +div:-29108480583332747319862771298993930146421704,1070825121844450385018502033657868394429345713,0,0:0,-29108480583332747319862771298993930146421704 +div:1309351864286127912492763722652139231241412,67215284518814518103811333196815587050385227,0,0:0,1309351864286127912492763722652139231241412 +div:5057770892603033060848565127774886456638357230325,4560833131311412489432012223910819044848375100332,0,0:1,496937761291620571416552903864067411789982129993 +div:633417011776645191559278275893992860044140785076,9267459276776555758115340080177517575774981964493,0,0:0,633417011776645191559278275893992860044140785076 +div:81198441395376013971576012512699341529160887275,7447901692377824339480278247455048336927582640790763,0,0:0,81198441395376013971576012512699341529160887275 +div:9051874321306026560005193316581192573940541867187,37537551211896722531771511300407567291038941024813,0,0:0,9051874321306026560005193316581192573940541867187 +div:2608213478636475749024179986585033501198860091868353,4860413071332838243659712432305837800300477,0,0:536623830,915784885941031884462459089442842973301443 +div:407598478820396357158686484143933270533665010845,4355992703916618082567359020934982484449368723357,0,0:0,407598478820396357158686484143933270533665010845 +div:630711778218873882494940824096903507347713330,57238514966674350042018295073350807282445218805,0,0:0,630711778218873882494940824096903507347713330 +div:93688378632955946315197302995234838965963790793683,3160654096505987021546437056562511465114160,0,0:29642085,1248727276013620984317459066303575325370083 +div:-2525656519498119353338247264242041272975381031,327276040767955818809485641052992513513655213981074,0,0:0,-2525656519498119353338247264242041272975381031 +div:66016468795885111884527337073458991710229978420,16320322768232010844919027662356786278707098868275,0,0:0,66016468795885111884527337073458991710229978420 +div:-2302712368656752027279644835027749767667073228557819,9316845119063833412338569173366972112730895383,0,0:-247155,-7513254530280253105770984235775145068780172454 +div:48838864669737321321234466529333448212306449830,-32564162155964258347156982593283846680395226572752488,0,0:0,48838864669737321321234466529333448212306449830 +div:-220645217365027594041560662624047120760954694026473,478332284603296206017913627846840038736821534931564,0,0:0,-220645217365027594041560662624047120760954694026473 +div:-72981125020238190928338132724424652132640002,39188164680782185128568299727848835374297549277320,0,0:0,-72981125020238190928338132724424652132640002 +div:848294406307295588337784985646050321749073734744419,1894284566269937543645699304914191326539279181,0,0:447817,1574693990967354998860017291904472233349746542 +div:88331621619959932308180786862825270799091494710705534,2178577739962310780960655130496700895938054790,0,0:40545544,2006897502197066182000445542767995672948349774 +div:-6856699040860275517650307648299585141626669701068,271009865938172922862180983261519271114664396,0,0:-25300,-149432624500569237128771783147582425660482268 +div:-88407824671930579360204282767163259115148101495,999762964506455261651611324045254876016161327250,0,0:0,-88407824671930579360204282767163259115148101495 +div:77210128389009986005731678815189051918123188603393,1004893588971319006745864695885807127204177369,0,0:76834,134373987661441419910771498947106517424633647 +div:297784613656392099571586950531714472282249229,38243230119670761105711715396092668555574825,0,0:7,30082002818696771831604942759065792393225454 +div:-35509945917648756037422888630539391852716391754248754,597284352710239029652457972715277271026334934549395,0,0:-59,-270169107744653287927868240338032862162630615834449 +div:801533871821359460893588251165565622439064765617,822025202425769092976017224921611946029366105,0,0:975,59299456234595241971456866993975060432813242 +div:-522010146755299559121351482887404344773949966,-3932667350437494585764045269025085811459344224177389,0,0:0,-522010146755299559121351482887404344773949966 +div:-58459624214325180544444869117416512994249719120541094,42099937836886376971951088854357470492133289729419,0,0:-1388,-24910496726889307376757787568343951168712976107522 +div:-253345562577317672511220652744246967807793182895907110,5749989880936090964050051849193062955356828797,0,0:-44060175,-2175044340819256659509727005208754118655047635 +div:929733472033240998779303334258721213318162598707,767612759141593942240674520830211174476840069251,0,0:1,162120712891647056538628813428510038841322529456 +div:964194291196691142924085838110342670268423649945,95195593030727305502485226537387747371662899678,0,0:10,12238360889418087899233572736465196551794653165 +div:-930824010798502796427972044794470458904018793646,59612624490118074742886336029812178788101136417100079,0,0:0,-930824010798502796427972044794470458904018793646 +div:4496931676886813794791418684601244183539575641824,17411178665119193136820706152905856572839870547600463,0,0:0,4496931676886813794791418684601244183539575641824 +div:-538173513290298732583524004704645684413620731176123,5191614740631357425621901873779740989648663178,0,0:-103662,-346046970959128706412664890173944661008818287 +div:645223072897535515198700423081805044495125969741938129,-4527829932821589910817760274407207149545929368,0,0:-142501613,4080777311682643434931455406859698817217867545 +div:99627943961043088669512673603139357672824609930416,466295743266513578268755141190344363951636566,0,0:213658,128046206330563766987646692761559645844511988 +div:8378463829762121913631626419465685262621092341,277603732177643189147101934156154702276101226001738,0,0:0,8378463829762121913631626419465685262621092341 +div:9842615010830513092601043514307725085136324358384,982829207195358411241726125114558021029115376,0,0:10014,563329976193962426398097410541062550762983120 +div:62320220612711436764404545275083408051364828569716359,29238061288213780350752248589890807799224738132935,0,0:2131,13912007527870836951503530026096631216911608431874 +div:-95796294809205390217092020218600576789023181059,165301144024373968274096547718999489219277029418,0,0:0,-95796294809205390217092020218600576789023181059 +div:87456781258209959765037687145068876793116934415493249,12068929953842578406244505715637579551016022265904027,0,0:7,2974271581311910921326147135605819936004778554165060 +div:4650729780737505464243409512735245030691695372618246,84864736041440063700547247893177477447164617313268,0,0:54,68034034499742024413858126503661248544806037701774 +div:-625358026462075054949936252035182773523079306781808,-7037095653882435960759081957329932874958248091338799,0,0:0,-625358026462075054949936252035182773523079306781808 +div:2568284414900282086629402504199999865573825319657504,5768783213527705673129403864116463929738223137152322675,0,0:0,2568284414900282086629402504199999865573825319657504 +div:21872791887330497853718749618057463060198347580531402,1324557936763556387760743907736237330887941028,0,0:16513276,1099563344481062563504290440813742452313443674 +div:-33663209218662096950671228753577152738857975888365,64455980252274430283628664249222461742909356825,0,0:-522,-17187526974844342617066015483027709059291625715 +div:897547639705131822906931936065160910250510030878007,5363864878695927157573012052790958211464944313132948910,0,0:0,897547639705131822906931936065160910250510030878007 +div:5009490811735999584822449253729050585733274306709319,2406843316925106774841027948556192949607544362335487460,0,0:0,5009490811735999584822449253729050585733274306709319 +div:26946852936100376197741904167965017845209833397099,308919640253848342394664627646584079095578466190402123,0,0:0,26946852936100376197741904167965017845209833397099 +div:1985893148050510215060586789904119885262534441,5866449806057188251900630030898916114586086296,0,0:0,1985893148050510215060586789904119885262534441 +div:5562239080137747796995442181907475991350284893459206265,156398892363409903713342341853412785128113829406,0,0:35564440,56612798080976501265602288199428588294379283625 +div:65178480098314895239449345070432724637440125039775,1290757832744933770056846180890168907973673153410496,0,0:0,65178480098314895239449345070432724637440125039775 +div:23657300680705528280619872949865464121904006372229057,54009346128207976631438579725539802296822123315,0,0:438022,18870935613940563883381325068840245386273546127 +div:2465896601579984309597565211236176792392608862458577021,-40289404326330144787151484318600863409012051557183,0,0:-61204,23899191274128044745765000529548307435258952748689 +div:4530895653520455283627656673385442171856783842314,-93233120674213574021733372853213159559027357138117667,0,0:0,4530895653520455283627656673385442171856783842314 +div:916112574807335146788888377531188026131378675176,967597859681274796485056494940030314717751207208858625,0,0:0,916112574807335146788888377531188026131378675176 +div:2836353387405193828295144729357504288167954496834813,-47750867938530360881039623534374164321838133495716184,0,0:0,2836353387405193828295144729357504288167954496834813 +div:888544290269727108571429100899398323213047387976643,232593764199419096127199419642853734112674182121501231,0,0:0,888544290269727108571429100899398323213047387976643 +div:-95528231285086139734583293340171808952248738222733284,793897402237626526946706417222476481392026422526754,0,0:-120,-260543016570956500978523273474631185205567519522804 +div:5037223546635984893254983907596574271648794864585,-135600768236385462209166458097331958573087149090026,0,0:0,5037223546635984893254983907596574271648794864585 +div:3597926907607703532951852295319420299540575082900605212,32397904521210638837288370977004776603517163371689911,0,0:111,1759505753322622012843116871890096550169948643025091 +div:2949870570599287735739111770944723963347077343574168440,13426005226039726224409657686289401061489856647303547,0,0:219,9575426096587692593396737647345130880798737814691647 +div:-6292945917085019054270321590350396947352956870846986425,341295410748594067077010194722238510564411359595737,0,0:-18438,-141133702441645504407620061763289566340222620787619 +div:576504230473861553261538972452278105135349421005,-435859823015036299275541119431403593387201588094,0,0:-1,140644407458825253985997853020874511748147832911 +div:513271751605046021061398181450246519536581003892,1804974737576433978846636236205909460681769870983,0,0:0,513271751605046021061398181450246519536581003892 +div:518565283589729505911763776861051767197425505162856,80256044584676536034995400588268683853363345693,0,0:6461,30979528134406589658493660247800820844928640383 +div:-8803453406819218000000306371196263081095678566028295082,-55765725990796735310893334087719738405325766157271534,0,0:157,-48234426264130556190052919424264151459533279336664244 +div:30910800403711655057148039026242334689849626271558314256,83948578597192063348545167380196449977141674761638849,0,0:368,17723479944975744883417430330041098261489959275217824 +div:49242996359867738984900367600384020935433157154372,2708783714074411929119022487862398012033030877105302717,0,0:0,49242996359867738984900367600384020935433157154372 +div:21379071756862143968426604961644165060562036140310,461158186026323145332549423710888480451753865883923090,0,0:0,21379071756862143968426604961644165060562036140310 +div:890497438806243182741322174370053431770114463163083,-553230364990398459699806691827737650133760743598577997,0,0:0,890497438806243182741322174370053431770114463163083 +div:3023647463972332206442886065358904974207929712372177354,954649340832479585995977185409104558411042237463566294,0,0:3,159699441474893448454954509131591298974802999981478472 +div:35489760963836552056324219511199170577078030263500,9911937794382297889765816250290479042378434631444578,0,0:0,35489760963836552056324219511199170577078030263500 +div:4135741741874158916022517640987066604514941788107532,-28163724964933933312984726177284380068495757852680949,0,0:0,4135741741874158916022517640987066604514941788107532 +div:545414705998769838413644038929944315836407586765492978003,40142701966897036750492630938275806447937324811027279,0,0:13586,35957076506697121451155002529209434731091882876365509 +div:75058649832069709510468311408895020488684235853480,-2888974200822060946807576793636547307530522265641548,0,0:0,75058649832069709510468311408895020488684235853480 +div:-66933551184377520017610837511897921700694960480368326,653887787579904832254964727311893728850303235046236,0,0:-102,-236996851227227127604435326084761357964030505652254 +div:2435629492619014604053848939625684854601784871657,-291893351983540450002470218001632642526157243983032264,0,0:0,2435629492619014604053848939625684854601784871657 +div:4353873124828196561972948174190449777941113312128,54820424043864696600903577780832618011158946935730643,0,0:0,4353873124828196561972948174190449777941113312128 +div:6563332558449452126564485551259042246419252988238165,698324403420861093632423144820174865039557171760521,0,0:9,278412927661702283872677247877468461063238442393476 +div:6651389855462289995786489027518276832180673970627,-491461095877924735369902036753617462691001210108931850366,0,0:0,6651389855462289995786489027518276832180673970627 +div:6927903135341590486179736781500384096788524701827,218829613953562480451106314783086433106706968172108955440,0,0:0,6927903135341590486179736781500384096788524701827 +div:545264621820945020606844611617845056531423301824882054149,875522645453735240583714479359375422140055663654,0,0:622787571,103319057246612448860090001299718413253014409715 +div:86684332448285178538540680259953842278268190530391877,1004758465343373611009533596159290181785288025548175925,0,0:0,86684332448285178538540680259953842278268190530391877 +div:-92317828450423143272179560065430627651793040689272,22070418041935886277960894290327131047538612473095276,0,0:0,-92317828450423143272179560065430627651793040689272 +div:7971256552090299009697202541746345670252715480656564528,201282600297357182844197939592816412476029915756077647398,0,0:0,7971256552090299009697202541746345670252715480656564528 +div:51609533271954429925110080029550304256694456133044809,485763884901242868745815971537580121006369686192,0,0:106244,35084506782578079607949511641880493715193261961 +div:55881591305337924534730793672599558668292512146650104410,2222509574710359486675225376172946110121737537397794673,0,0:25,318851937578937367850159268275905915249073711705237585 +div:19368449809775464181696546358821387683250538685332,24510908730652135218597094611704093063219507437128,0,0:0,19368449809775464181696546358821387683250538685332 +div:-2935049511482530629217049856269086660794528627329678715946,37471582465832914952060760873346941905859586735847868746,0,0:-78,-12266079147563262956310508148025192137480861933544953758 +div:36100788373557792247173517969159682950517798879230,5080501101336645920307905996377195554239168429725057140,0,0:0,36100788373557792247173517969159682950517798879230 +div:-619343993545565489581918826619755522056336720755028240,5722220737779420639556807213632172372985391133964,0,0:-108234,-5154212747676080127354659490977438635896761568664 +div:2214624479709129652867518274099800744215833156381,596426619358648105117142458022253139919252174606588,0,0:0,2214624479709129652867518274099800744215833156381 +div:5033621023669077052146401601213685801870950098584920712831,6799225107652133581418467714714131055036511563510,0,0:740322749,902228583435466263288772550060049562516909423841 +div:5358032037701639498140968139141468348228418868104,8558469544431829473340967206378658910509072615323310050,0,0:0,5358032037701639498140968139141468348228418868104 +div:9748963428125495559040360700047156483695054417931835757,89907138812423274211888428791450791283996367956807224600,0,0:0,9748963428125495559040360700047156483695054417931835757 +div:-37234857139625248358511007131249688678503673691725663734,-9768451005959695483831603140151504358763270636290461,0,0:3811,-7290355912848869628767564132305567256849296822716863 +div:14140350728384927368127641043017594043341305190489552,678387465698256214286200006608789600890351284725416,0,0:20,572601414419803082403640910841802025534279495981232 +div:16226406385251314022733101915283965938409231292486,-3756447461810096116929418499028120801376280771059460,0,0:0,16226406385251314022733101915283965938409231292486 +div:6545974979782747370293360546030862327851785067995680,-8744885285916351107220120754451051904389636789416979493,0,0:0,6545974979782747370293360546030862327851785067995680 +div:1152408063163445395815670313984522609667667839270597239381,95249480242199210996494814595420706184321580039151,0,0:12098838,32128876378241260984354491943697962902472875632843 +div:1690204685535914155988172971158586449220783297513957809,9929613337808118536737016690304412293482744573038,0,0:170218,5762400891834901871464168349997448737481780575525 + +# Division by powers of 2 + +divp2:6650822,18,0,0:25,97222 +divp2:-22,3,0,0:-2,-6 +divp2:626665862,11,0,0:305989,390 +divp2:382,7,0,0:2,126 +divp2:-8554783,11,0,0:-4177,-287 +divp2:80613086,5,0,0:2519158,30 +divp2:2476669303,30,0,0:2,329185655 +divp2:234993203,12,0,0:57371,1587 +divp2:78175,1,0,0:39087,1 +divp2:1092697,3,0,0:136587,1 +divp2:-51601200,8,0,0:-201567,-48 +divp2:-133,8,0,0:0,-133 +divp2:67494772097,28,0,0:251,117472641 +divp2:81070756,20,0,0:77,330404 +divp2:597,10,0,0:0,597 +divp2:-6061,14,0,0:0,-6061 +divp2:914736,17,0,0:6,128304 +divp2:5146181168,8,0,0:20102270,48 +divp2:908169,16,0,0:13,56201 +divp2:99131,5,0,0:3097,27 +divp2:828749,17,0,0:6,42317 +divp2:57934632020,24,0,0:3453,2905172 +divp2:374659,20,0,0:0,374659 +divp2:881062175551,18,0,0:3360985,123711 +divp2:8978255,9,0,0:17535,335 +divp2:-306454,22,0,0:0,-306454 +divp2:455535314,22,0,0:108,2550482 +divp2:-7013481097,8,0,0:-27396410,-137 +divp2:1902116776574,7,0,0:14860287316,126 +divp2:57980384,6,0,0:905943,32 +divp2:-6429952,10,0,0:-6279,-256 +divp2:-121080553817,25,0,0:-3608,-16163161 +divp2:9486785,18,0,0:36,49601 +divp2:-264976349260,22,0,0:-63175,-1194060 +divp2:-9957437441589,16,0,0:-151938437,-34357 +divp2:42280023,10,0,0:41289,87 +divp2:9445756856,10,0,0:9224371,952 +divp2:542833427595245,43,0,0:61,6271753240557 +divp2:-1989040985179,37,0,0:-14,-64895636571 +divp2:-842046065662,21,0,0:-401518,-1788926 +divp2:-36486783654,37,0,0:0,-36486783654 +divp2:12161238,12,0,0:2969,214 +divp2:522437544246,12,0,0:127548228,2358 +divp2:5771713949080,24,0,0:344020,16100760 +divp2:-192975675937641,21,0,0:-92017972,-1921897 +divp2:51399227509,40,0,0:0,51399227509 +divp2:76781489061746141,15,0,0:2343185090995,21981 +divp2:624421287579358777,15,0,0:19055825426616,5689 +divp2:585792449987,17,0,0:4469241,93635 +divp2:64111034807,16,0,0:978256,49591 +divp2:-4872049514614819145,60,0,0:-4,-260363496187431241 +divp2:-513726738058624,27,0,0:-3827562,-62639488 +divp2:-5129414645415250,35,0,0:-149285,-21103148370 +divp2:9777073958585027,20,0,0:9324144323,950979 +divp2:4917705257,31,0,0:2,622737961 +divp2:9309157350108809,25,0,0:277434508,16969353 +divp2:549889891480003,40,0,0:500,134077592003 +divp2:43259632605223,33,0,0:5036,721999911 +divp2:80760535636025,12,0,0:19716927645,2105 +divp2:95148114869248768947,22,0,0:22685078351318,2276275 +divp2:72784357307196492,23,0,0:8676571525,9292 +divp2:8695487295473310914,48,0,0:30892,162314927725762 +divp2:-999894977194,21,0,0:-476787,-166570 +divp2:422873004052896,16,0,0:6452529969,4512 +divp2:5850059500167,33,0,0:681,314043015 +divp2:279461298693250805,55,0,0:7,27259719560503029 +divp2:-2391765116812271696,39,0,0:-4350595,-221690208336 +divp2:93848076004932,44,0,0:5,5887145782852 +divp2:54463987988137594412,48,0,0:193494,268844485922348 +divp2:9735669349328114,31,0,0:4533524,691512562 +divp2:-96573804848256945392306,69,0,0:-163,-355587759787924163250 +divp2:693910684713664114,18,0,0:2647059191565,48754 +divp2:56085146568929935461,53,0,0:6226,6324008912519269 +divp2:7090107398039299,30,0,0:6603177,81864451 +divp2:767239571830013898753,66,0,0:10,29369808881631834113 +divp2:-74636360117262549362461,43,0,0:-8485171760,-6890174916381 +divp2:5461169750136459,50,0,0:4,957570122765963 +divp2:976702847245116276,37,0,0:7106448,71221928820 +divp2:3617864287401198,48,0,0:12,240164566873326 +divp2:-1309978694518086461,40,0,0:-1191418,-749976460093 +divp2:-2386749120888691269,33,0,0:-277854167,-244046405 +divp2:7266512965529689,33,0,0:845933,3826315353 +divp2:-6961513563355648932180971,48,0,0:-24732264461,-193888863384555 +divp2:5143351773441402886258,50,0,0:4568214,56404232132722 +divp2:900799510679250396,62,0,0:0,900799510679250396 +divp2:30978095034050773575947556,48,0,0:110056301970,184099523155236 +divp2:398942302365209775391228,57,0,0:2768218,44660240185115132 +divp2:914903526125867075664,27,0,0:6816562459810,77563984 +divp2:2551094792632393428431439,87,0,0:0,2551094792632393428431439 +divp2:6909886286515846175008,60,0,0:5993,427709407012247840 +divp2:461670131377821667,44,0,0:26242,15985200256995 +divp2:7884527998899506514865191,44,0,0:448183527561,3748608715815 +divp2:-17784618887403951072,44,0,0:-1010938,-9512034128864 +divp2:-2928855265612995457576576,88,0,0:0,-2928855265612995457576576 +divp2:8468445340017772238,58,0,0:29,109764431618131662 +divp2:97699128177500917404004263,94,0,0:0,97699128177500917404004263 +divp2:-901210903909447624384117,51,0,0:-400218038,-507572120280693 +divp2:-9099254471589743272646814275,80,0,0:-7526,-878753170044103808133699 +divp2:88420842262358445100031098,32,0,0:20587081616362194,3379223674 +divp2:5920604485769478876616913,30,0,0:5513992612966782,320526545 + +# Division by small integers + +divv:-5721818303,-31144,0:183721,-11479 +divv:100359289911028,16,0:6272455619439,4 +divv:-80498620,-41490,0:1940,-8020 +divv:37386622,55859,0:669,16951 +divv:501578,15096,0:33,3410 +divv:6823,11067,0:0,6823 +divv:-56695604,31395,0:-1805,-27629 +divv:396,1627,0:0,396 +divv:82237128,16423,0:5007,7167 +divv:274600467,39390,0:6971,12777 +divv:258805,22852,0:11,7433 +divv:5139922232,23459,0:219102,8414 +divv:8755497783395,46470,0:188411830,43295 +divv:56370361453114,52292,0:1077992072,24090 +divv:81119249096,17631,0:4600944,5432 +divv:3925148017708459,17729,0:221397034108,7727 +divv:-289130964,59901,0:-4826,-48738 +divv:-2394107507926474,13709,0:-174637647379,-7763 +divv:-50229865870,26540,0:-1892609,-23010 +divv:3694598237147,64566,0:57222040,2507 +divv:-158417511658676756,-64615,0:2451714178730,-37806 +divv:4290308067505999,15193,0:282387156421,1746 +divv:560784439224,18032,0:31099403,4328 +divv:9207709447044,43308,0:212609897,27768 +divv:42833310641849859264,57815,0:740868470844069,10029 +divv:-95089845960500,-61243,0:1552664728,-23596 +divv:80687877739837,-30796,0:-2620076559,28873 +divv:87851714436662969875,61349,0:1431999126907740,28615 +divv:-5469457537,11848,0:-461635,-6057 +divv:-87902672172139257996,27307,0:-3219052703414481,-25329 +divv:-694576880064214,41179,0:-16867259527,-1881 +divv:47595892116434828,47204,0:1008302095509,27992 +divv:-505437926464614447947,63863,0:-7914409383596361,-45404 +divv:-747214784268033231559289,38881,0:-19217992959749832348,-36701 +divv:40648086806090824914,-26501,0:-1533832187694457,19957 +divv:23860923193973296,51883,0:459898679605,27081 +divv:-54927711987466879,-11937,0:4601467034218,-6613 +divv:4311756940677447464744993405,57924,0:74438176587898754656877,50057 +divv:6015889311543917179186719299,-50635,0:-118808913035329656940588,45919 +divv:3915173119649887691276,20797,0:188256629304702009,10103 +divv:209840208083311316090,36847,0:5694906181868573,6759 +divv:80000000000000000000,25,0:3200000000000000000,0 +divv:65000,25,0:2600,0 +divv:800000000000000,25,0:32000000000000,0 + +# More regular division tests, all with remainder zero + +div:2546905999569583642767,14957376976449,0,0:170277583,0 +div:8820890915810513585008,1290654714992,0,0:6834431249,0 +div:32722399167479650872,485171756,0,0:67444979562,0 +div:281565136283209685892638788,662476076955569,0,0:425019326852,0 +div:378946105625441540737303,730177609549,0,0:518977986547,0 +div:4582336996784637790714331883462,524659399010705751,0,0:8733927201962,0 +div:30908196512568974558050436710,558351619821782,0,0:55356150882905,0 +div:22323179841972640636983704753,52956211127329649,0,0:421540351297,0 +div:52861155259463695471936251160,9468000366853,0,0:5583138277489720,0 +div:63260535208765360919938678377,42122224781389,0,0:1501832715082893,0 +div:28984143265639802151626094051438,400082299653446,0,0:72445452574997853,0 +div:3317964166851176108015612343691026488,4043377664512227983,0,0:820592198441457736,0 +div:66344183633702866132053676311141052606577,91178778320288608847,0,0:727627468320008374591,0 +div:5695550794829300030546270882518324992076491,700880200540761512031,0,0:8126282908883599504661,0 +div:39037424763225371397599506194643545880,7823304879274443640,0,0:4989889230399751117,0 +div:436302766535175847931361924986715811355695802824125,539874776595118725233603625,0,0:808155493551392334022517,0 +div:346745970223883677972239586841121624456285168,91526846077189641641348,0,0:3788461911289433710716,0 +div:52724986995800116311347732059133990047851510404883234,568154076534742483223872266,0,0:92800508125151146767566749,0 +div:2377848542111935708145523356022435793438514852230023651,78161062689778162572883876143153,0,0:30422418276855244470867,0 +div:232771550187355002750375300477927538332648185231317422242,385169380058229884085331084789,0,0:604335552717520311627548378,0 + +# Bug fix regression tests +div:#xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,#xFFFFFFFFFFFFFFFFFFFFFFFC7,=1,=2:#x100000000000000000000000390000000000000000000000CB1000000000000000000002D369,#xA11260 + +div:#xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,#xFFFFFFFFFFFFFFFFFFFFFFFC7,0,0:#x100000000000000000000000390000000000000000000000CB1000000000000000000002D369,#xA11260 + +div:#xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,65532,=1,=2:#x100040010004001000400100040010004001000400100040010004001000400100040010004001000400100040010004000fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80fe03f80,#xfe01 + +div:#x0144E8D32EFB430AB38966D6CF217276A50D882C9BB1956E47F0C11F809819482F6671C7CDD70EBFD40A67E96E8728B1FB26092168F13A2689FEB0B86D689F12949DDF22AF0A030FDF2A27BB4CE09998ADFDD014B507C487D2BB6C71122AF93F13E99F22A7C5F2E728A50C7761551C4E9322502DB31D03BDED78A9301C50D57AEA88C1FEE4EAC7F0B38002C0F86D434B7D8311D4C410A0CECD6B81D40E8289F31045CC6F6C4EC203BF2A6BCF549759C92875BE633E20801C130874CAAEB8FD7276BE101898F12FE7648FB2C76C09D3643386B7F99B26FFA462DF54DBF401C8B73B5101B0A45D83774DC307ABB9F52A54E152E6FE5EBA1F5C91E0CFC2B84791413448023D6BAA4BB3B765DAC3C7D679832378C6737EAAFDB1395DDA29887653C17A4F16330550D9F71C99BD7D81777943CA1437F0C6C9AE89472A5CDC304DA0952AB154FF9F0B73A68FB5B7E661389AF3E407B4456A9FB5EC7FD7F78D0FA97C09DF4BEE8048687BFFA8B6231D9893ACCB75904A16BEB45C9B58DD4C63C9902D0C5015D2325EF7294EFD442CF7C6F837A8D6661DA492459429F9D7CE1251CA3375CFDD74A1C8EF5FFB8370245295E3C09B47D697EA3B5924F7181B1F9810FE479D2B17E63F1886053C32E53B4D6990DFE036BB50CCE32E76EB5BE5F2E0B40EFAB32D19968C0275277A4FFBABD2C5A24C982218DA3B32703381399A653A3CB9FA3009695581F18A7023727D6BE13E5D9829E9788BBC94DCFC493307101A0D7A8A212AA5FFAA45CAC31212202C23DC6ABB39D6192FEFF6FC3C084547036E2DBD6AE3DBB16D0101E10E899B32C70CEF1056DDFAD104E165F7D147C8143C6E6D08C0315D01D41D5FCDF528A8E2AF9B68526949742C691DD8EA545D9F450B54F447E52ACF59172A9BA2284703A6A525BA28664EAADA9CC9A1AA7875CE0273AA591F2AA8C20925EAA62037D109CA0EEA3824C1ABC869978B5B62F853980C,527,0,0:#x9DD4AE7AE3F3E047AB2F86F36EF8F04867BA224C9A45AC9596780B6AAC0290D95539B3274501D2411CDB86482673F35C5E41A4638DF46A28CD54634DEBE64A1E6ACE84760F8CE729DB28303CA956C1AA8026E69908252D172FCFA340B05236EDFBEE17A29F4EA5B964178B1D4EBF8AB92495B4130001D154C0AF742703CE32F707A796896EA61A92758FAAF9E4705B13ADF05F952998701DD5FC07CCC198FE167A50D95812D3CD5B67AC5AFFCD2A28654365B6C44FE8BC83A8C8856E9ED769A317D54C8E4D53FDC310DAF9677CC203032B951E697C5B26903614D1D448C2A7B3E357C60508FE4886ED8E2B9614F7E72AE7AA0410DE8A9EA328B6885D67423030B6A7388DAE88D78B1F8119A3A00C649F13525064648CB92FC88CF3A1038F2EDDA916ED8D06BA84AB4840D869A372C51EA44BC04179C5F7E08164001776D50CB6038FC968F29E30D97BBBF19C865DBAF7C1AD8D133F7EBFA2A80F5394F77DD530B88F0F323B7FC1A7EF8CEDD48FA12CE9EDAE6F1DF95FFDBD62452B214E4B51467A53A5D3C73E5408632E9E4097AA56DFA5B40BEF9DAB8E518867FD3D972BF155EA5C9A5EB17CD58074A742D5AF3DFCBC664CB5CA3FB4B0613485DFF8B5D03507D1513E399332A257DF90E7E9719BDF125430F7339462926404D531677F42E3E937A9CC83613A86394FFDF89A4BECDBA1CEDD9F6D82C4FB406A16F10E70AFF07927FECA0D60E176BEA8C4312E535AEB11B7665E858517F109BA90CEF68464219955024423D88981BC0DAF6E33B1A9283D412F16D06335EF9D86142025C37B54F0CAC5B5AE55097D9F6DACF547ECBBED87ED107543819C8DBD0099B65EBDD07D04DC74A3E2C2496D9E4E0E61D6615A7E08D3FE996DBE187750C4C1FB9B18B928B6550DAEAFAB8D7E4E8662AEBE7F77299D516BBCC8F2242B9FD28EA7460282819525F63E7E5C66E4D0C73181CE8577D3342D76CABD26D8CFB6,98 + +div:#xC085B984D2F30F92A00B8814DCF9A909C8672B081225AA88A7293D276E46B240B96E345B76A5E2D4E5CE7F4C208616DD38CA2029C37FAA8EF2561C688DA55150788FF7F34E484596590DDE971387608FB88D92A8868F4A2F165D0222A272C5AC300AFEBB152B25D3FAB5999458B1AC27FAE5E2ED6D50E7F8FDE7E22178E4C954,#xD607ECBE4F4608C16A0FBDF0F4DC57278E937A73D2226CE8388C6B9B9DF9C58464CF3E05F29FC58B59CD34CBA4F47810D92B7B4FCAAD1860C76E091D0B1491B9,=1,=2:#xE64618B3D9A1E9B5DC38D204743994492C406B98FFFFFF95EF529A267E06AF4364F984172C9569DC33FCA47F08195C2937CD1CAAE1F954A2A78AA08AF59EC954,#x5BAA50658645474B56E43FF89470E38A4D69E90D43F0E1D5DBCAFDE8853AEDBAC364F06CE50511DEA15DE5D944D9ABBEA76EF56D1E1E2732AC396304B28CB7A0 +div:#xFFFFFFFF400000002,#x7FFFFFFFE,0,0:#x1FFFFFFFF,0 + +# Spin in s_udiv(), rep. by Andres Navarro. +div:45035996273705000,45035996273704960,0,0:1,40 + +# ISL test failures +div:-110768999339257979395151936604514986,384307167128540502,0,0:-288230376151711743,0 +div:-1141798147252782335678234520236874583761538254,990352029122461210705605426,0,0:-1152921500311879679,0 +div:-11417981504429295188771564013355757832033533955,2475880072806153026764013565,0,0:-4611686014132420607,0 +div:-19746054620424668475119147467564405598366894325375493578959094720,137015778031883893401769208133025156060969696320,0,0:-144115188075855871,0 +div:81791893044,81791893043,0,0:1,1 +div:66461399479760783996783510248698675,57646074961906893,0,0:1152921504606846975,0 +div:4951760153682756594365890554,8589934586,0,0:576460752303423489,0 +div:9903520270472025075672416238,25769803758,0,0:384307166770626561,0 +div:11141460315522012760862883825,48318382095,0,0:230584300062375935,0 Index: contrib/isl/imath/tests/egcd.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/egcd.t @@ -0,0 +1,752 @@ +# Extended greatest common divisor tests, including +# constants satisfying Bezout's identity + +egcd:7,328492456,0,0,0:1,-140782481,3 +egcd:930165221,819,0,=1,0:1,-85,96537294 +egcd:166,0,0,0,=1:166,1,0 +egcd:44,37824113,0,0,0:1,12894584,-15 +egcd:0,93,0,0,0:93,0,1 +egcd:70522336,34102,0,0,0:2,-2785,5759331 +egcd:863,25,0,0,0:1,2,-69 +egcd:66399,5533253,0,0,0:1,1229584,-14755 +egcd:4107,14863,0,0,0:1,-1643,454 +egcd:7,482337424,0,0,0:1,206716039,-3 +egcd:477004716,83909,0,0,0:1,26067,-148185319 +egcd:76,9778759,0,0,0:1,2187354,-17 +egcd:0,8367890,0,0,0:8367890,0,1 +egcd:8335,721158457,0,0,0:1,-159892121,1848 +egcd:90370,2894953,0,0,0:1,591452,-18463 +egcd:67733,1618312,0,0,0:1,-106035,4438 +egcd:166575,4485123,0,0,0:3,-397448,14761 +egcd:28271,6,0,0,0:1,-1,4712 +egcd:763,53576,0,0,0:1,-18397,262 +egcd:52077184,5129,0,0,0:1,1375,-13961031 +egcd:6552609311,525555,0,0,0:1,173606,-2164516163 +egcd:6221599,7764515429,0,0,0:1,2913991310,-2334941 +egcd:89021590,33904,0,0,0:2,-5437,14275908 +egcd:739392892,9335369,0,0,=2:1,817116,-64718359 +egcd:8394864191,48,0,0,0:1,-1,174893004 +egcd:55087825,530530,0,0,0:65,-1805,187423 +egcd:243,6823694624,0,0,0:1,2218402779,-79 +egcd:7846,430402,0,0,0:2,-77457,1412 +egcd:67053681,8634785,0,0,0:1,-3793089,29455346 +egcd:6364928874,55124010,=1,=2,0:6,4571384,-527837761 +egcd:3482048,995555,0,0,0:1,328872,-1150261 +egcd:33038872623,62,0,0,0:1,-13,6927505550 +egcd:75504,62,0,0,0:2,5,-6089 +egcd:15,436212,0,0,0:3,29081,-1 +egcd:72635,93361,0,=1,=2:1,-22347,17386 +egcd:7009,4308,0,0,0:1,697,-1134 +egcd:40446737340,4212231,0,0,0:3,100060,-960797387 +egcd:728456835,694701023,0,0,0:1,99101538,-103916923 +egcd:9355087294,2631,0,0,0:1,790,-2809015189 +egcd:54733,8862614,0,0,0:1,-1246171,7696 +egcd:38730799075,40635,0,0,0:5,-514,489913393 +egcd:72,98,0,0,0:2,15,-11 +egcd:1322949,68,0,0,0:1,-15,291827 +egcd:49271099715,8633675426,0,0,0:1,-3947828585,22529669726 +egcd:175,762975785,0,0,0:5,-34878893,8 +egcd:321,55550,0,0,0:1,26131,-151 +egcd:217191,451486096670,0,0,0:1,198071748991,-95284 +egcd:681,2323372,0,0,0:1,917749,-269 +egcd:78678,523426,0,0,0:2,98880,-14863 +egcd:90350809087,38042,0,0,0:1,7341,-17435079373 +egcd:633,4435395170,0,0,0:1,406402717,-58 +egcd:16360,606577002,0,0,0:2,-128322922,3461 +egcd:9669450329,1009,0,0,0:1,293,-2807878044 +egcd:5871172260,26773591,0,0,0:1,6401741,-1403835749 +egcd:5017125540,8367,0,0,0:3,71,-42573911 +egcd:619,8820231506,0,0,0:1,270734085,-19 +egcd:60596719455,443,0,0,0:1,-151,20654863742 +egcd:6752409,94193,0,0,0:1,3303,-236782 +egcd:14045780235,33398209741,0,0,0:1,-7792585660,3277209961 +egcd:9145,27764492144,0,0,0:1,-4065243847,1339 +egcd:63567135,7519707417,0,0,0:3,-485762107,4106344 +egcd:875276189593,31047471995,0,0,0:1,-4089317138,115284166233 +egcd:531838714305,22614,0,0,0:3,-2211,51998558297 +egcd:4134506738511,2476,0,0,0:1,-377,629527076098 +egcd:6185136988713,1891462493,0,0,0:1,-495247968,1619475161045 +egcd:374166745968,81724,0,0,0:4,9131,-41805547421 +egcd:62423829,4320571,0,0,0:1,-1655596,23920135 +egcd:4949666413,1501091102,0,0,0:1,494932087,-1631978715 +egcd:956385784303,12089922808,0,0,0:1,1485803831,-117536040949 +egcd:6140630879643,9491202,0,0,0:3,631459,-408542209367 +egcd:211369,28015233,0,0,0:1,-7466081,56330 +egcd:8011144,24386,0,0,0:2,4799,-1576539 +egcd:9723,761305061,0,0,0:1,146419877,-1870 +egcd:24432,7899,0,0,0:3,892,-2759 +egcd:9912899,223787,0,0,0:1,82520,-3655317 +egcd:30742811109,445709,0,0,0:1,100330,-6920269141 +egcd:6445714509994,5444765,0,0,0:1,1710399,-2024833698457 +egcd:7932710,53078817369,0,0,0:1,-4132035559,617539 +egcd:3337840732,3077034,0,0,0:2,723227,-784527093 +egcd:718292818604,81025428743,0,0,0:1,34254894424,-303670650665 +egcd:326072,253,0,0,0:1,-45,57997 +egcd:29893828809270,93736826647521,0,0,0:3,-7295461626941,2326612589313 +egcd:4480264,223642,0,0,0:2,-23286,466493 +egcd:176957076,161560781,0,0,0:1,-31655390,34672061 +egcd:37146108400624,62308785533,0,0,0:1,28939329218,-17252518260107 +egcd:368208150951,692481145480,0,0,0:1,61559555031,-32732631176 +egcd:6314981,15499,0,0,0:1,-3877,1579662 +egcd:2805866,671806182,0,0,0:2,45436714,-189771 +egcd:98242818233,77004291671,0,0,0:1,37912166082,-48368707255 +egcd:607152,2932056,0,0,0:24,13034,-2699 +egcd:329110,861060931,0,0,0:1,423790795,-161979 +egcd:6035746008,726247945,0,0,0:1,-51545008,428383417 +egcd:388326,4784349702632,0,0,0:2,-1147292297345,93121 +egcd:34137115145,947284,0,0,0:1,456621,-16455174641 +egcd:9207216089,860347,0,0,0:1,-394196,4218585935 +egcd:8112578025453,2680608704,0,0,0:1,-855589147,2589349837748 +egcd:4997261,749601100642,0,0,0:1,-67513226341,450081 +egcd:852403018665805,68601329,0,0,0:1,-30001234,372779110814299 +egcd:92080405,52081391,0,0,0:1,-12636003,22340576 +egcd:60095571,4414432667835,0,0,0:3,-74437007062,1013343 +egcd:4981195051773,905850760614924,0,0,0:3,-146240346450057,804163027486 +egcd:9685579,9592868,0,0,0:1,1793043,-1810372 +egcd:59530646,36346354116,0,0,0:2,-4115037905,6739902 +egcd:1435163995,69604439462,0,0,0:1,7586354849,-156421967 +egcd:99926066,887606404471,0,0,0:1,169670756253,-19101407 +egcd:70441698,3974125,0,0,0:1,58887,-1043777 +egcd:849350185,211717364,0,0,0:1,-59186631,237440024 +egcd:20085073436,2395589822,0,0,0:2,-341128500,2860085191 +egcd:1126006461820852,819773895887891,0,0,0:61,-706362472938,970229368007 +egcd:70904095451052,2233930,0,0,0:2,400136,-12700165688899 +egcd:6758999,15939222862291,0,0,0:1,4123564111309,-1748590 +egcd:430279300935,431963821489,0,0,0:1,98776246963,-98391051236 +egcd:55721139210155,7073166691740,0,0,0:5,-369561824033,2911341799388 +egcd:192435034269048,1832500,0,0,0:4,7198,-755878513871 +egcd:15747650667716,36009594821,0,0,0:1,7200472117,-3148897400951 +egcd:38881764321,552729171,0,0,0:3,63876322,-4493383429 +egcd:691050011,51977919,0,0,0:1,22745801,-302406990 +egcd:52540041952180,2156326222,0,0,0:2,-170294052,4149305677871 +egcd:7905452,6213885,0,0,0:1,2027303,-2579183 +egcd:3430895541193263,119720318,0,0,0:1,-12421015,355956329656547 +egcd:78945450,1569850634390353,0,0,0:1,-213574967886499,10740367 +egcd:3026195347029,48776084,0,0,0:1,709073,-43992736549 +egcd:22612793613368,78277930892526,0,0,0:2,14856095743435,-4291603305253 +egcd:775918498,7426337401,0,0,0:1,-3568692411,372864079 +egcd:66668332441496166,5313627445077186,0,0,0:6,-18855448933863,236573103938824 +egcd:3800017785952,66078608868917137,0,0,0:1,-5030282046793581,289279111249 +egcd:8238037234,2941537491408,0,0,0:2,282888965705,-792255696 +egcd:9547120368107346,29456344,0,0,0:2,-2851235,924116168074373 +egcd:721478459,29799838078,0,0,0:1,-4113566985,99592822 +egcd:463484777885,77160851,0,0,0:1,-38346752,230338774171 +egcd:6668812562,5426227269,0,0,0:1,-1878258319,2308372291 +egcd:7020839924454,9619730190140,0,0,0:2,1676947567713,-1223899236455 +egcd:5581687877912,4728620673,0,0,0:1,-1477827499,1744435091593 +egcd:86212837117,93176774191319388,0,0,0:1,-16333778951401391,15113008971 +egcd:10486952786566311,8072710949230,0,0,0:1,162596692991,-211223200405940 +egcd:332388514681475,314477095129839383,0,0,0:7,-4152534349932681,4389046916654 +egcd:1878789616020411,634591014351511065,0,0,0:3,-55735306584035142,165011657725421 +egcd:853435249810090,294022990301,0,0,0:1,-71973674612,208911796010781 +egcd:800760331,479138587,0,0,0:59,2283452,-3816219 +egcd:310386781,45470476445,0,0,0:1,9204755541,-62832736 +egcd:206381927221,426737049973016,0,0,0:1,-51635348161827,24972293048 +egcd:80657906841,97722845343178,0,0,0:1,-44940641023991,37092841744 +egcd:3626879556739,974287797969673,0,0,0:1,-416739368163900,1551352175437 +egcd:12353260720882,167588026304493,0,0,0:1,-4766112882926,351320057681 +egcd:5680097354,954648204845001,0,0,0:1,-206590628821018,1229201373 +egcd:8495790423,19792054180,0,0,0:1,8077970807,-3467489852 +egcd:1808291492597692,96814519920612,0,0,0:4,-3825789187820,71457690917437 +egcd:796275712123233,71773988020895279,0,0,0:1,16421100444870785,-182179140537376 +egcd:62156477407557,3665981752,0,0,0:1,1292733717,-21918214413059 +egcd:2921017132462,944466357361,0,0,0:1,-167559490864,518222951729 +egcd:70129038286402,2652828624150588660,0,0,0:2,61204814273941601,-1617984186560 +egcd:4099194006860675,712258835980,0,0,0:5,-46544273205,267871728840131 +egcd:18993264993,72866008153094,0,0,0:1,-10126377677909,2639543177 +egcd:37137778422333201,725902397772208341,0,0,0:3,36710995342741392,-1878165459827929 +egcd:77046543323827,91919074661304,0,0,0:11,-3080180234575,2581806232959 +egcd:50946730035622,6841431278091013,0,0,0:1,790206978840254,-5884508662999 +egcd:778417902091877810,3526771827155035,0,0,0:5,-62143495200058,13716115340897371 +egcd:7357629905645982343,273989149651,0,0,0:1,-10489681694,281687051588686593 +egcd:59999050131295751,4402788959646093,0,0,0:1,2181599081375342,-29729763077344837 +egcd:68611931054045254,72532452638242572,0,0,0:2,5482399071936641,-5186064629726171 +egcd:8597485693846941640,9852318416413,0,0,0:1,4640854869916,-4049776069443081003 +egcd:570460270963,54720108308,0,0,0:1,16083505887,-167671472335 +egcd:43617503830797013,452251304617430,0,0,0:1,76760132288467,-7403152472886549 +egcd:73871669508560399,48493623727,0,0,0:1,15908333574,-24233601655059575 +egcd:99534170067866609,8533916062,0,0,0:1,-3636610149,42415108188475141 +egcd:1885231469789,5484240550249,0,0,0:1,1215645072521,-417883264932 +egcd:1988347340743956951,7107237557789347,0,0,0:11,216195821117034,-60483750895153609 +egcd:1028936133037327271,5510465055402,0,0,0:1,1073852868395,-200514113917520622 +egcd:908361247108559,833255131023,0,0,0:1,70168847825,-76493572911138 +egcd:105122420688920,8437707543309,0,0,0:1,1099150493096,-13693928112891 +egcd:7268354783435841902,933995610637335,0,0,0:1,177721439316803,-1383028419904388383 +egcd:50338474800791504516,946966290251750,0,0,0:2,-82754441959453,4399029230620270937 +egcd:38695580832418,77020806554,0,0,0:2,7049841355,-3541870284322 +egcd:460793682039951322,360995931125673,0,0,0:1,-12872500500857,16431118446002835 +egcd:9791371944228644211,37881615337394730,0,0,0:3,-994456930616087,257040192279396732 +egcd:726186734680,24419809216698234959,0,0,0:1,-2766640019167190414,82273258719 +egcd:529564016606,376298866055896536,0,0,0:2,28277719651140475,-39795131343 +egcd:145541869208926297,19688885314609703455,0,0,0:1,-4361261236227472297,32238803887896062 +egcd:39778456127502718844,81278417471936841,0,0,0:1,-7120109086823404,3484651347093815497 +egcd:7809654411174,1244628241216910096,0,0,0:2,-284584948977462005,1785681883582 +egcd:247581683736939421066,245039298196,0,0,0:2,-51357390229,51890244702955249521 +egcd:667668476732052,476696223555,0,0,0:3,60657763034,-84958248556823 +egcd:2229399707506,39201358276824482440,0,0,0:2,-5131877014016252583,291852262700 +egcd:4767576564991009579,340159717388,0,0,0:1,-29682941117,416027199034854288 +egcd:748410307121741,730540185467629182,0,0,0:1,-213318504992896387,218536599371724 +egcd:2356182915322420038,81237995138900716,0,0,0:2,5252342047370707,-152336090720664004 +egcd:6513077506735657,306517877388663388,0,0,0:1,85680643466766665,-1820594206381108 +egcd:216282311653914599395,911124646576,0,0,0:1,429112007291,-101862393081040854019 +egcd:59815399922090959,5110979162439569056,0,0,0:1,-1114788966780819601,13046726616842810 +egcd:477652083813766,624733750918729402,0,0,0:2,-154413302241487321,118059630163644 +egcd:659935429542750939,44886608128116509,0,0,0:1,15839652572247565,-232878989079292726 +egcd:54504214226951518003,387724255017508609,0,0,0:1,31301361124239357,-4400178916414896230 +egcd:783331167504862965,48609697533,0,0,0:3,-629742688,10148120643700831 +egcd:7643973606720,70743283292590583724,0,0,0:12,1182943528930131602,-127819754647 +egcd:4273152632680100030114,1455223242316512,0,0,0:2,12098554144849,-35526486240961014982 +egcd:5862269731025091,3136791365228,0,0,0:1,-386529556073,722375272334573 +egcd:659628551534893059484,5950075862222037,0,0,0:1,2470161881316403,-273843450328876151623 +egcd:9482121506846253,34058669367564240,0,0,0:3,-1589045402569649,442399009322730 +egcd:65396942933391,3530693943836047978,0,0,0:1,1333698073169157271,-24703295773820 +egcd:24559856763503,6667927595346,0,0,0:1,-250002320323,920829011695 +egcd:4843560767022,8140092963222,0,0,0:6,-479036307613,285038693786 +egcd:7703573212864,4497158779255,0,0,0:1,1735016188064,-2972059668409 +egcd:8411329856643749667337,6927690295201914990,0,0,0:1,57955419569688883,-70367197465289023043 +egcd:311630305921790132,36794945100846,0,0,0:2,5335676048581,-45189858410215015 +egcd:12252240244679740653,21854667756737479,0,0,0:1,7408241549029968,-4153234277439483257 +egcd:914930916911818959,73054804640859,0,0,0:3,3000864169057,-37582516567124740 +egcd:144437770651525337,7176192389740,0,0,0:1,-2917598661927,58723543558714060 +egcd:9658485554428935101,5617211853860547,0,0,0:1,449096244749153,-772196190086168116 +egcd:344028716311850,2026849525600172204430,0,0,0:10,4273604619400616489,-725383257448 +egcd:936445752013986984,883181511511066630902,0,0,0:6,37504920718991502298,-39766823953131263 +egcd:8136225792202716788767,6604882712946357,0,0,0:1,-763274997603269,940240423932206378732 +egcd:577476567105329156936,1256480674248716110951,0,0,0:1,165865135596220858037,-76231358802105687681 +egcd:58801491048115,31028000846825692159030,0,0,0:5,2620151256531588957285,-4965476229559 +egcd:9973707804728263847551,53630829606521208326,0,0,0:1,16368451878013344235,-3044035631088017117934 +egcd:17121194233870838,44442113181771232,0,0,0:2,-5375949729958541,2071068923785980 +egcd:194930254933589618442,76996294363551631,0,0,0:1,-38281520562566769,96916697409778838629 +egcd:6740972199816713986701,3164254690674619824,0,0,0:3,304736351600199807,-649195300386062944621 +egcd:33100303896200,74054854499575190726143,0,0,0:1,-30231828546967434629772,13512722683807 +egcd:80391303224075976,94483334960558284,0,0,0:4,9695304929308312,-8249266378534037 +egcd:954262165857127978158,3790250771466830,0,0,0:22,53714840833849,-13523654091347297164 +egcd:50095431507743637803,32894122691956397938,0,0,0:1,11834908275426407707,-18023731548159747940 +egcd:2173109072764661515,71129381706084812,0,0,0:11,-844279059631827,25793988931499293 +egcd:52743975673113,1252477537471129,0,0,0:1,198187508901071,-8346015665318 +egcd:3400327281633151,431371474891473455,0,0,0:1,205422443946739001,-1619262239320730 +egcd:74672816465806151314169,181861345000582103629,0,0,0:1,27254332141007722192,-11190710933415108645643 +egcd:474476291935913056166,8171705897201808883848,0,0,0:2,-1170007477720025417249,67934506766326698557 +egcd:984130837655605609160519,483475686999411456,0,0,0:1,30260545442548343,-61596346486657707977136 +egcd:843814604333653656215922,682249690564087391733,0,0,0:3,38030549017256981789,-47036639393790777318635 +egcd:81202937258153735712,402831457452712664,0,0,0:8,13421756749885189,-2705563458591282665 +egcd:6676582659534088,44001550460545760069911,0,0,0:7,1211181274540019933457,-183778794394919 +egcd:533144411502628328950,28324708505596385902,0,0,0:2,-1398171989606979473,26317219908236327476 +egcd:66581532981454422,14028130038905754906,0,0,0:6,517088823759485624,-2454252026321337 +egcd:2130464987067329677,8494848036198574143,0,0,0:17,-7062764335631653,1771305627228686 +egcd:38575228438194,1957852613377826515509,0,0,0:3,129868619328885840117,-2558778747355 +egcd:49489410876608829677,7951728226267755060269,0,0,0:1,3860693946871021816365,-24027917399688934216 +egcd:42770760432244640,44801059402399356,0,0,0:4,5296495695549791,-5056468564505481 +egcd:6441135230593242548407,122558774271814342,0,0,0:1,36997056041193015,-1944398045028139827512 +egcd:264902435468141506,823887292259809475,0,0,0:1,120342636882041621,-38693469240520931 +egcd:4615387069156629,5068444832682377449634,0,0,0:1,-2198712149475939054985,2002173834082799 +egcd:36444520368083130251,10180304221606287367,0,0,0:1,3547776565155412457,-12700702501188462318 +egcd:2705117385426850078,311987185491928483938918,0,0,0:2,48604570190513342423426,-421430988026778607 +egcd:6447135503640541,17828837916381145944,0,0,0:1,-5783155035268931939,2091262724234125 +egcd:193981008037679996757,19120164140966891788,0,0,0:1,-1586493554887429351,16095553194700936591 +egcd:64332664201713053,87185087911910266023,0,0,0:1,19609332567597552767,-14469453865385550 +egcd:95102121410339574,293671951113485105415049,0,0,0:1,106953417739910482828300,-34635575105438351 +egcd:65154144550755804519,4285018859628755463,0,0,0:3,-609852871996317628,9272874514298907745 +egcd:7165578261547505,763555532759171606,0,0,0:1,-174953906015578927,1641852952316256 +egcd:5442458157933637000759,66760245307752621192750,0,0,0:1,29074397305494111881389,-2370215838375818515507 +egcd:42143136951989716656,827894838488320343515,0,0,0:1,370905938581526544116,-18880586083238491373 +egcd:5295415444080909673074,5092055214749737510,0,0,0:2,-79624725963726612,82804680196255688279 +egcd:118338007742261895,5763460050841396334194,0,0,0:1,39330742550539324473,-807556862613311 +egcd:57063373752305154812,692318043858914149958,0,0,0:2,-70368857818416495450,5800057458900243919 +egcd:49356454157781030126,38544768358653028317,0,0,0:3,-1638594177535601368,2098214669607345263 +egcd:98128015703777581473188,71751790667213936232,0,0,0:4,1131009376775245397,-1546772628993544572326 +egcd:95760302891303565510312,49856290116188787587208441,0,0,0:3,-3088248308134997399905293,5931680690668486327459 +egcd:40420853393811300450702,87550419156538713298378,0,0,0:2,-17578959514036280337967,8115969657005769255362 +egcd:422899389299537033304669,8005135756870427773,0,0,0:1,1826207874406781724,-96475839795446732840135 +egcd:179674525723481348814,69928617693608886497807522,0,0,0:2,-17176881265197584758274313,44134262860096480672 +egcd:7789649675160016285918,417200326088447794162,0,0,0:2,-94835249783231044512,1770692222592009406889 +egcd:177465346778880323,60001957340989928039014267,0,0,0:1,24984084908903832591086708,-73894410929202849 +egcd:151317887902583777,714764598301032762905,0,0,0:1,183810322507486902798,-38913216802619989 +egcd:51078283105727024828148762,75871019523002756919949191,0,0,0:3,11485911105291504406000748,-7732604924142639690250403 +egcd:4760258696724862445736876,3471524299806755969674,0,0,0:2,856359023818037629295,-1174265290574387452901557 +egcd:261631865216813032,5681600833992180785,0,0,0:1,709538151924588968,-32673500929505135 +egcd:720979639879195715,783996604122129884144,0,0,0:1,376019130933410843211,-345795040670644006 +egcd:36110696808763448994,31631881940059268291965,0,0,0:1,-2383142920549669168891,2720576398805277667 +egcd:658675475456498963270,36727416735327035,0,0,0:5,3298655738340100,-59158629436863579657 +egcd:61220559308972890,667000611959077400,0,0,0:10,-26640911325438571,2445232377004423 +egcd:40220367562984968880458,89139127967069561321,0,0,0:1,26548285035112330181,-11978822394062224915657 +egcd:268590992017536259191399327,61179964518317742544264524,0,0,0:3,600487671783052773266369,-2636248332740054832357965 +egcd:834052968320156609779657,4980797187259222752640,0,0,0:7,-284790928354963265969,47689297559175644596626 +egcd:2304058851313997444536039,9169653702125462923229,0,0,0:1,-130649054522071275152,32828187439358617259301 +egcd:58451234918953535616,811141856188592686,0,0,0:2,-99923944925714621,7200562927828430183 +egcd:822396573998213269,36745646576975841888238,0,0,0:1,6092800501072128894693,-136361684305643132 +egcd:17578713797195009784,68270861083809145500872866,0,0,0:2,10088182822145144907111889,-2597554443418689739 +egcd:76377711400349230044,28120345054943065861736,0,0,0:4,-2062007766043178352451,5600622387542163743 +egcd:76762683909293356952194,336742697639190379,0,0,0:1,-75512400432970134,17213541871304020806343 +egcd:718613829360289007965846364,56996018089280939789090,0,0,0:2,-2524732262127936558957,31832180208715887766629415 +egcd:7295663098480852718,14423786075811123687515222,0,0,0:2,-3469836111463770997012649,1755070072665297072 +egcd:15211419951748549035347,4699398308750843428412139,0,0,0:1,6946404824215205904662,-22484725489054469667 +egcd:17150054056990843968091,37598518807922567502949,0,0,0:1,-7518057558796082945642,3429259918338934660227 +egcd:77024520800929983778,12004114915728728552,0,0,0:2,-2120493047554731255,13606164385813996546 +egcd:6552691621635472445,9454879100164928596390176,0,0,0:1,227870736946333719833045,-157925516866534574 +egcd:380663675562604264,44830819384430864282488995,0,0,0:1,-16273991432157066610391981,138184344602692003 +egcd:2230931798936940632516431,790824149442647895647799515,0,0,0:1,331133100467518126491471001,-934133541615045780146562 +egcd:95014513131992964781831,6426665041014306194430759004,0,0,0:1,239158098260009820460949479,-3535813695397102752012 +egcd:45587301786773822623,12200508698455746294,0,0,0:1,-4813378778407164821,17985229666126454386 +egcd:544408824836312286809239334,47857195870319437437969,0,0,0:1,-3285821056099126073737,37378495485205612484001511 +egcd:368559293555584153297233,863543676262890554,0,0,0:1,182689982444744817,-77971841749691835919840 +egcd:286838686809753815604,290258385092986016322966,0,0,0:42,-3439904517337276235112,3399377055680475215 +egcd:247310884666793355418391440,8146285853652299839620,0,0,0:20,77671205038431135851,-2357999065620583642815591 +egcd:723355341278352532752,2716643920855001136283,0,0,0:1,-647343221413917008844,172366784345707798483 +egcd:4747770341760547358928,3900131915460402444898291,0,0,0:1,-48191502504962163320631,58665242939847808459 +egcd:62996662961434499047,9733114500463650951,0,0,0:1,-2609387863316684519,16889016126666164094 +egcd:85408851497556727644592364,176571048356555258831010,0,0,0:2,10373200197110227040698,-5017601262696030666591307 +egcd:3859907398033663982,96346670011473683698108682,0,0,0:2,23114207598170766553332033,-926017483502444222 +egcd:372461979322690243,540222307494848292,0,0,0:1,-216390837474738389,149192949855933584 +egcd:7516220184290968225960,300386413342210429744,0,0,0:8,-15749172306804321015,394073238736743444182 +egcd:6108319432277782804,82931541043539126216389,0,0,0:1,14516925059734418621210,-1069243551048233051 +egcd:7230921518942393713547539642,72114378808806856868,0,0,0:2,-16718190793824596963,1676335948054892581924595036 +egcd:3825709037512543084718302,2651564896588437884119958,0,0,0:2,-590856988072406763814624,852495415840807251070275 +egcd:911054271475454361570597270,621648474138432132340027,0,0,0:1,177507600588673885690903,-260145507410443226451439067 +egcd:65298316398221703103077598,534642984572205231284578626,0,0,0:2,27704620476219826795345676,-3383688041836699547596371 +egcd:7540589021419394540066,951669501600612914519183,0,0,0:1,331190832641661629577944,-2624202995275280476641 +egcd:9761932411251041918483933,382356303803298271385489,0,0,0:1,-174786897144790383992576,4462481353982094260231281 +egcd:29200924565006580097578,89587549755035053290130260583,0,0,0:1,-12724495224425705121391303686,4147529720281901737723 +egcd:99943694998442521323946016389,333424364613212729745462161,0,0,0:1,-5705329051108614724676136,1710167963313731051974706105 +egcd:5690154324629967337460,1632283715496329281241648395,0,0,0:5,56290934452012514099439970,-196230655901744389641 +egcd:1925002725694160249373602782,3526543575073330036110,0,0,0:2,-3919880867811415654,2139710227393535147948013 +egcd:52670953750351044438983990007,6419267762739355812530600,0,0,0:1,-203989820551702316343657,1673763862318789910544563426 +egcd:510257531185418430181,66420793633874998820433,0,0,0:1,11533829131275308680081,-88605131851925052020 +egcd:624028484658998836131051,290010878235398822043835106,0,0,0:1,-122928139167747537660445423,264509596583252200647779 +egcd:82126417002597285652,9711508871315310668247843,0,0,0:1,1977141009391962114230902,-16719905131309273821 +egcd:5313586393962705049080,76998532453336088964044527295,0,0,0:5,7351068169285296934826456278,-507289354236443273333 +egcd:7446329018924231360114,281705996976935084208360,0,0,0:2,61771771846187437852753,-1632812017439206420394 +egcd:92632241917277332460964,41225270861482533930349836,0,0,0:36,-232831718389563965069268,523167552648600475583 +egcd:505206995627529688155,30108238444718526549709911,0,0,0:3,2815345833969785332425863,-47240638572857371542 +egcd:350682530039234485322546750017,732856831499478812681071778657,0,0,0:1,114634298969783930190784719020,-54854160136223590904319282827 +egcd:73936773633607324540860765536,5462243107704027813296706,0,0,0:2,434277168489579388852756,-5878363900642009138649028319 +egcd:9329801698838720379683494,2642515095105038480589941,0,0,0:7,174846258141415342001899,-617321323637898767831439 +egcd:25822034647579787624514946804,190739018295930506821730846235,0,0,0:1,17294294853830144704620058819,-2341282265740751416856382785 +egcd:7949963986480899256177301,54250986866391077101265062,0,0,0:1,-4923803556165288789334505,721536385032484788574613 +egcd:3746930579001676751120,99207386871851914556838486427,0,0,0:1,-48583865685594090026984533471,1834947756648482241123 +egcd:26584400729548923821953289,4186329192513161170925,0,0,0:1,1656738211241031433334,-10520766639746090510993433 +egcd:15015617716874132201457077873,908213746723440854928237000,0,0,0:1,408879360871055069439454937,-6760056426484746584749467457 +egcd:941171208223609049472714,2820721728009499408048129,0,0,0:1,-561073227079218020506735,187209522225614099075479 +egcd:30137430783951200466620,7932600136613507821178378958,0,0,0:2,874263946876564747820132932,-3321492162990162597361 +egcd:55007423087104738440174209,45869037869891649236,0,0,0:1,6370717719612306117,-7639941477849380770592557 +egcd:49096256950991848579874131467,931448097952317628160996789,0,0,0:1,-326595408525690731353759748,17214713445914733493338694553 +egcd:1122894299337591195948255,54881121839952705699464175,0,0,0:15,1530959605417535453487243,-31324174065771247623514 +egcd:35498057471655773087035017,85668857880959672128179,0,0,0:9,413483537492374633285,-171332532504207423622284 +egcd:1887739328175786669349,5857986692383902136266,0,0,0:1,-1152123029924601355085,371272259343532579901 +egcd:291707312665735093614825955052,7207353925931727830829,0,0,0:1,-3501220426060812684211,141706874954742490398970247737 +egcd:95531532857951877080714695655,1267695778421377857836,0,0,0:1,437662312686039158539,-32981534147821284545085645329 +egcd:74484904487858142015156737,351049851111701482889769961,0,0,0:1,17139443017007319377607732,-3636605376854762326364603 +egcd:2136069932966937675469,7447531079022134243581196506246,0,0,0:1,545901561496939760038844699835,-156573218627833145909 +egcd:509775218017409565394932197,216635621683624922457211,0,0,0:1,42814883976773638426025,-100749667317060906989689284 +egcd:745276060382671550825981532388,5112220648677904268244,0,0,0:4,-58944865145259393149,8593173083522474449221607614 +egcd:8078258267292267766114067,884100779411269652418038495,0,0,0:1,278129835236887309130321543,-2541344486065477531385724 +egcd:8844980710175781452273298,935135907771717589995041479,0,0,0:1,-48834539676535952819435698,461901374804996053728595 +egcd:58087603156751215661949004,58712010607326754590110,0,0,0:2,1191143911590048935583,-1178475990232715912474903 +egcd:5679173086064233367773646048971,12789890243264425121239084,0,0,0:1,105424447625040632402467,-46812261417225737221083455184 +egcd:77653936311643667916482493998,15693437224085205047080,0,0,0:2,2640971088036021388319,-13067997644040407190632050442 +egcd:7284686326593740714529339,90971885163627008124264246742,0,0,0:1,7198130762602806275082298459,-576399232016044918973300 +egcd:30545805868231898661181062,9266612086889390909321896160792,0,0,0:2,-538109282848491556444597462033,1773785449920680245879519 +egcd:5874785131042125952122412011,2349616696032997520626166708,0,0,0:1,561505530055217292587132395,-1403941478853022044849375718 +egcd:260436619859311350841971,1212092952552738381785471705126,0,0,0:1,249307384938854393628000175415,-53567486307626529321214 +egcd:2081870677650494937076,343501716877184044936575,0,0,0:13,-8002592767368064135037,48501542813302049871 +egcd:5691817817445639700141386839865,8687746818925263901770782,0,0,0:1,800431353877405067350643,-524406331883086413378341354467 +egcd:7181315131090723377262366519,979729982933337084774328653741,0,0,0:1,234315848781865941936193642222,-1717509905406328622700624837 +egcd:42080505166736566441565451216016,76651513399029916866847,0,0,0:1,-10862717669575888116265,5963465387040535737057564145103 +egcd:3576584500173313993122814232472,956729492745224694909152831129,0,0,0:1,112997896952360433126909373108,-422425074022064413751985822775 +egcd:39436344864081129175577,1167601129966960865519531141627,0,0,0:1,171787444425430917487358673786,-5802211669555479977323 +egcd:4257657006586752810590,77147349594877154853239911600,0,0,0:10,563538244311585376718458939,-31100907120886287790 +egcd:202401109849117829323361,272785163230303985302397208,0,0,0:1,23898973633160449229831945,-17732558216601391500943 +egcd:428080555595049024501717,58005872228568473578325314236,0,0,0:3,-27025471292559437633908505,199446682235027309708 +egcd:65986801519081050039948301,606919157648734368493531958309,0,0,0:1,177217106981913490775680119487,-19267788661516250973518154 +egcd:32012062136782881389216056,8869128247524938255824580,0,0,0:4,65752954911363551966964,-237327459876009040631431 +egcd:1659494763900889556967676,44291944525456085901327930,0,0,0:2,-1939570066390918372994278,72670242950040945291001 +egcd:223050013194629393090661502,798488954097788537544217128068,0,0,0:2,-161550947050238364712712345521,45127663552810491926056008 +egcd:3248908131273613694428163643,41879881211067694937556432,0,0,0:27,152368979327239401229505,-11820301337418926358261534 +egcd:3446049603173727626406694518,128204824207783873176312600555,0,0,0:3,1056928424865089617706172356,-28409444040782355854331071 +egcd:700031253558626136214208233370,52123353846012574000878521623,0,0,0:1,18394042136597105147975391256,-247037142178779880729238222953 +egcd:435876668588605457895900237986,271303986771473105323219943001,0,0,0:1,75954147113817500975823522812,-122027844129493972049386903631 +egcd:21894869356689284742223217,560101383667765190092124546814,0,0,0:1,-267658820677239482560763028061,10463025233963471610122617 +egcd:93550360054222226284955381499753,862954759319855471087513825,0,0,0:1,46956904727976525514024192,-5090458447435021286477243513311 +egcd:163036556076233835371222,325253846064704092481611715780,0,0,0:2,54681731490561412578180374911,-27409733321748193593258 +egcd:298760510595869651060219530,2623576823283807936237615,0,0,0:5,-2274816856798681184620,259045376379949119206227 +egcd:296230762513979639442717636233354,744175580561578635268252771,0,0,0:1,-32683945300355203946061855,13010357086674471069800614815901 +egcd:98928114229803289645575952596,348257401408420844843182275974,0,0,0:2,64013299296094164502149959938,-18184006885079414479620311729 +egcd:25494984833088459284053502,55538387170360999263101791354861,0,0,0:1,-13961772810342240040396540580435,6409173981787208904855911 +egcd:9359069710378270733841468708,7964135606537379331278169,0,0,0:1,-85301538328543188593444,100242271485686143586274937 +egcd:195970387106442905335558970212,98516089210647543971591302645,0,0,0:1,41045531049286373118094757998,-81648679653930215927296149435 +egcd:56089374569303066947729808,3639958663360642892752262467447,0,0,0:1,-1082612960697886770974458433228,16682355345789150259831175 +egcd:77185220697583421203504780317,38956103306675053558083657208,0,0,0:1,-15968896903521518756033811651,31639787534500855950959809021 +egcd:7188758981017613732187784596,8631409677648057462898487410251534,0,0,0:6,699438759027432535326542480920388,-582534817418185462274574963 +egcd:13002008635939628191889025,2592210142742456161455160840997695,0,0,0:5,75548903633041076033203125863138,-378938220044671750740451 +egcd:5392206357529202370293290582,948791676960011700258391458218182,0,0,0:2,187120500260806390833148058965610,-1063449833754065004912067599 +egcd:56544377896569143411201431214146,76585331663390150529866457483782,0,0,0:2,9058983102991352121685655626679,-6688416081888426016772130405426 +egcd:1031141749989374985000595839,2009599508279438972802543089088229,0,0,0:1,-126919473322514828506873048560747,65123407569678662184010846 +egcd:298829367007901182284218491,86088936999033370088419809276,0,0,0:1,-15810428616337484255943286769,54880691297149907598944205 +egcd:89096238096139543100186984,6280657804119840743206710613975,0,0,0:1,-2167845076635776547503368565936,30752645204900197093113959 +egcd:72302302888163686505438102,216294628465581933787047635,0,0,0:1,-41789803774641178599701942,13969367023054995629391271 +egcd:7344423585894563618479886291,64742746516225911812839171195,0,0,0:1,3780593925465397372719483346,-428870949858745274825015983 +egcd:476166266511928480941810303162,18227725793516746361381041226,0,0,0:2,4455414192209412199765379430,-116389612489299070719517452233 +egcd:2947038272293705986916176,304655516887206203888885395,0,0,0:1,-109032350828407811155001224,1054707671446621662700315 +egcd:5336534152617403337493975,121693724313422319665633935007584,0,0,0:1,-20927747392063258189216772528249,917727182113838425381039 +egcd:7843688392207875316169462536803513,961373577118119555001824067724,0,0,0:1,15264598965786873678488692173,-124541344352904002665189888529827 +egcd:57707445075805800484005722,3193791338236737476237368616160,0,0,0:2,-726032458195877241439267854299,13118414375725016916077568 +egcd:3888164897150599425315896428,205183819721771722595087705,0,0,0:1,89162997566753336326543942,-1689609042924883873671187935 +egcd:602417296292970251426446187098,518146488443536951749769338863282,0,0,0:2,-94681801709378439277053173041833,110080751806786360731992754598 +egcd:15607864856380204759343924600056208,85052708198112429563844521,0,0,0:1,36709574212910552715797330,-6736505931307702456822986279949959 +egcd:82966223347346884138560378408,387550826708631961461927727625,0,0,0:1,40689557976537119419523190072,-8710751525565014944116387463 +egcd:457941790845177233752849712592384,906379077457778070185230350,0,0,0:6,-38742338721240980168476766,19574299999617999644302509928229 +egcd:17520719333212917099310752269335,777312604525614950110016270,0,0,0:5,-37751502797693573191966387,850923400797104861105824821195 +egcd:7306687969771772551064816345560,93860833710620402880693367063925434,0,0,0:2,-22267197686818972849668228015866402,1733411680109554581599314098733 +egcd:9217304562871982912081196416939115,45870849307880337525730087,0,0,0:1,11332401339029049951636388,-2277136703300246618193509803178237 +egcd:2134005353764205569149428712160814,18399584757091279388913554789316258,0,0,0:2,3505886019286566312711773541099241,-406616759759275454593644975464334 +egcd:328060478808294918960133208057727,5348905699347524558908735435,0,0,0:1,-1625801360474358080252404807,99714072885871998294880707908974 +egcd:152187719989614115335894105182,345706102040316044204222170,0,0,0:2,76351546968434028595864981,-33611694390777105417832332162 +egcd:90466176767209784417980607,47937980732897762962198916204,0,0,0:1,18691494153161079961152768391,-35273659596235640430430634 +egcd:22191701690446556393936729275,39127301370409752749065478506260,0,0,0:5,-1218868518522681739916085065245,691301613338140203683659113 +egcd:2775905315510344742322701111035,7936207786535867419090958193322,0,0,0:1,1862857017468570252301586587547,-651585094029390131031434362252 +egcd:514225903257242358267890795752,12195287538749560345215842,0,0,0:2,2593213573051136744157827,-109345317829044919259315081931 +egcd:5110340321650167437688203484,5898223610382806099689579027273,0,0,0:1,-1018061900744385391688765044676,882069437338979035072954345 +egcd:44404545087402155313016176366973,25830952532663780058171102811682180,0,0,0:1,8891719587254083391047997850029457,-15285257592320164601304464794387 +egcd:63300097463298300923000480926,16725067069928349236075120182800720,0,0,0:2,-857298523517998961630904929133553,3244655454410895040363088764 +egcd:93746022629651569339267076554163,59574007540242509707977428342,0,0,0:1,11788481187505597040178059987,-18550426096928359281490940224140 +egcd:836458939105765496287004470978244,993138957276858432408154782964382,0,0,0:2,-230968215392250987185055187226932,194530107794670768100558065725255 +egcd:80307477121258242272132678185446,332941739408686566344932888055688,0,0,0:6,-19596167789673034226948559353263,4726709241167753753045385329608 +egcd:3788453611470993575354311943,818010566804135634923861221704098,0,0,0:1,-137813490037976101809867354792809,638255830952858499594495856 +egcd:259587623659498181771581731880751744,58285944586801516286178106,0,0,0:2,12918436162055871131672937,-57534731031267918251576351240716171 +egcd:958710310132392913096861246,493657249388271089046091328590299905,0,0,0:1,135918487767490572772558916150543076,-263961393703363123681764919 +egcd:4551280541337185611914329527123,908864538052498723441933539502998,0,0,0:1,7268920160967968521955585604127,-36400248331876396282408916690 +egcd:13070475233480910888148121360,4413285328570554568205135584756141,0,0,0:1,-1717230732757565870913316011799224,5085785325815291001604078501 +egcd:14182858242524025309933936657556,3681095590818104384942178227869,0,0,0:1,1066740967448959129497195096699,-4110036142652596636215627796247 +egcd:30711728727831843417803691928823465,812520406510931643757197797324,0,0,0:1,194250898522863680149137450729,-7342315162507265729295009482678716 +egcd:569581482051982147368669338544,92228924551131117274576467984481,0,0,0:1,-15253790413013464064435116976927,94203381343103503173116637169 +egcd:48368135803685842814525775885,40003260510798989461787462217258154,0,0,0:1,-10067998535127146280640641119302781,12173265733848893973291833209 +egcd:4930018459600661874298066807914,2880020912442370329450214542118524,0,0,0:6,99607976318992660230378108507283,-170508887575977201168637981194 +egcd:711972151064706829096321326250,7007757329792910915127427981,0,0,0:1,-2295746860897920906029564326,233242641537338029349184727921 +egcd:4867220801462747830964320558865,559593908596537627162047055199,0,0,0:1,-136024405963053072514365585053,1183109408518107154940668015954 +egcd:1945367852716329243161308578831818,27652505202701349899029917766402433,0,0,0:1,-4394234229043878775227521709624144,309136620491535022574591706581921 +egcd:2412119651934489718572203112,71072673842732776958058175719000,0,0,0:216,39866022094797375420918506243,-1353004046985744635384612 +egcd:6670138054949154699848469764210,11854940081839078859576304802,0,0,0:2,-798743094019718928779709705,449409838495131194424053526626 +egcd:5079267998502677211817352966622046,725385967799535801573193170671426,0,0,0:2,-8733269027224634938993697761408,61151739710183405161934626994145 +egcd:4480886776816194313314948946313097,7994809135117481733885678298185027,0,0,0:3,1325601507700856805107662436885592,-742965862823827740623264222516423 +egcd:1874083707489243811559858061454,9579456370990495994658664409458725694,0,0,0:14,297611345884849035866817528293453049,-58223405680490774590261172728 +egcd:8686331588156731815552370068,3661502563583219068024887206,0,0,0:2,434080449473510327885732734,-1029786721321607796844318985 +egcd:9453863620833568356276223534918,23089387412280380517663003882151,0,0,0:1,-733315877883858422418297112256,300253453100215815170432043159 +egcd:55969320483418908248140871212,85079326328092084335875608943,0,0,0:1,6383961327473919368001838883,-4199680379617232871527304365 +egcd:920794688460040921882938496,500020334426725550170801887474283487,0,0,0:1,-164831869162100766351156834325468988,303540274591861720062941727 +egcd:2844850591475245305055592454156239745,217485336689197516110267978741866,0,0,0:1,-16965642610700236477617589115003,221921712748763436022152765469317446 +egcd:2250199404990420542899432858,805700188980281851693883900245317954,0,0,0:2,-125668559037065384081466548929550437,350973377738811240057657762 +egcd:2676253116351366843635779601279052,36480162826421640007834066520660170608,0,0,0:12,587251884638716966437757250151967981,-43081898889148741230200589919875 +egcd:434143745379431441298635777347861647,3321086261271951935256233282,0,0,0:1,217185906813395152991805457,-28391283938371176479724338141821279 +egcd:328831327716598552708493006826883,5998904017653902496457354820710614,0,0,0:1,-1691762719070528355733005679612283,92734369387521661720402695326635 +egcd:82257549943062294615386699467607,981668433037552750731455606581623,0,0,0:1,459255931703398524802713311124392,-38482716228173528870552258975841 +egcd:74258380804562546584265075951,77261232078825514789206570986101,0,0,0:1,-17606092948365433867565372298025,16921810841773443299096443176 +egcd:16604612215694436405195267479037791,12088809689403272378161906752667109,0,0,0:1,3335737012027898468082114279119872,-4581809207139284046012442723179539 +egcd:117187641044570371899825799649735,8178592535769464440682270853557106,0,0,0:1,2457083678190030290584253972331461,-35206527142278737093501147598489 +egcd:68116770003229052128759620238,45736612498624533810503009289382345575,0,0,0:1,3731521474495048658135396258227407127,-5557455529701362669272570263 +egcd:2342779644629940837325383152346,35028149264501773716827009029,0,0,0:1,9345366038727486594063066374,-625043965692319665157982363807 +egcd:41835886127596634688804793376,2957403801973782095124355461083505178,0,0,0:2,-140338661769489730626292727126091297,1985252155681011990306970133 +egcd:25097271744035338424812948162775851793,6632509587157028992269773636929691,0,0,0:1,-1033804362959546806519618544340632,3911893181067603431716224112635814747 +egcd:96520534936943177089214535009509,153964299411236835495293391645461,0,0,0:1,-46118336610084143333960687917,28911679766215052420281648314 +egcd:351485939694896123221486285958,258506570841696812103157651165770,0,0,0:2,-46453451455854421472351814714311,63161779539565138403359187422 +egcd:28007417021035441195271408027331994,676148020718828368622335803516,0,0,0:2,7786979935141692020919165551,-322552440730491285420662042795887 +egcd:4413362764336697663014052800322,65693610499398083043787280412,0,0,0:2,-6078361211144309430831885779,408350413891448394748721866070 +egcd:197461225716508808586959311780588571,454511236742266442066996230684,0,0,0:1,-219776105748141429162113653733,95481158035346356765866516205288166 +egcd:744324786002890919135978033721,2141150730373780972923060548366089391,0,0,0:1,-874346039933062214689297981457141765,303947508147659392320612047426 +egcd:372181197908829408250471651219,78669259391484278000787446068847,0,0,0:1,-39097687514411049901323408115062,184969634735797925888333342957 +egcd:684001754049621391333368494606676207530,811149742697476858677211191126653,0,0,0:1,-10915635617581306251815187309810,9204606148505852521943359730207435417 +egcd:364115078887792552377812666799607025862,8827301542572999906405869168316,0,0,0:6,353056586514687016404428485663,-14563139848644964464623772510953465875 +egcd:938042970041490895536761429291587,259757840576661229754224229243143,0,0,0:1,98100150147783338002545568916477,-354261322783767043672286176280986 +egcd:820267097131794751974736885266425315,82778860358839053567709120364638296644,0,0,0:1,-6400683257976970254293978091743005009,63425249549479075033990058036517669 +egcd:5457600674875173931733854800284,215111250666665397843928050541,0,0,0:1,15698966476127453640130012992,-398299437009563514118180872347 +egcd:6974124210886759868095546470042140,692694405426414064223497416146001,0,0,0:1,29811566834519349840902140899878,-300146166038548580439590878684919 +egcd:578127999598677928196850592197,7973510834560431357694126562765421,0,0,0:3,1163976746730659318155746392537117,-84395388948370397153290973126 +egcd:14723115671662580034450839772216631448,337895382484927435971195174146558,0,0,0:2,-83832862484269350178843664235104,3652849359365062786475539074792751743 +egcd:5703374596739162783083891159661674696,33366082296877919793073058464756227504,0,0,0:8,-1420826709123263094052675997824009987,242866599892681179183222633947553490 +egcd:3887856931052935625932193493988,2024878462802165949196024488137162136,0,0,0:4,-38889854468224057532149506069268181,74670254545888366761385533837 +egcd:116797886673620424155638344455575785,81954763999357052682292188450710,0,0,0:5,3939912856352315655141769553963,-5614969439772751205749020485962445 +egcd:39829595917373567921976064035194822733,3324835861238165638267965325306,0,0,0:1,-506495325242796237927113416249,6067518813078093176620314277655697103 +egcd:172216102857743621234283534482806021,145818479011898244797230396928023167980,0,0,0:1,-39678809736017016135656043364181182859,46861893122703407143312718238723498 +egcd:7727386332979968071664568403819269717,8575912217193880571454308157117336041576,0,0,0:1,-2268426632858813001110639846963498854811,2043981854778897974533067749584386763 +egcd:1257841454013765362088088015288120393334,5205555031313951556768022638995305531,0,0,0:1,-2069900289624638164056699910111515249,500159228805191194406298831997643647957 +egcd:329035719059507603931777828933787916,63174092441176600783246575745147736,0,0,0:4,-245032949249890737539102034446971,1276228744002642318798325126059915 +egcd:87426773521557211600093712732512,508336012580310863309243338497305585,0,0,0:1,-205653577638095609940604488277326932,35369575066695095584232158908561 +egcd:362736691322477088361764242120205,3310232079384692960069748150503077194,0,0,0:3,-298020242142018021148617862617948095,32657189583460645957996941439487 +egcd:119651446745096900798041375200448579,34904565501135027467488578221618555201,0,0,0:1,3540823847551645875601198046573235235,-12137801744454264167914107388308264 +egcd:33213056682266640333567121628934,394975398517140989884982468602916178,0,0,0:126,618949137634363451274564985445508,-52046767643929692458960957957 +egcd:73953631593374110277606522091274192654,472933146030124955694766250141468288,0,0,0:2,-25101980308935881143484630826554441,3925253748048624389535318040775271182 +egcd:8710580473357199589908718434142,809420061697430276091837694297806840287,0,0,0:1,139259190736440579781799630396860501656,-1498638895878772876966684998673 +egcd:77046997340564369387791662570845,4689854151349789784672220940122,0,0,0:1,-1962814468060010425072973823553,32245983823849957256883772384363 +egcd:9502904350676529706040238562436114,120812359166607505889223477518,0,0,0:2,-23295919059968979396801881056,1832419233554513311030927129706327 +egcd:31192932152325411540357484553215718,868422046212786848257208790061091,0,0,0:1,-230532004021048809280348128406617,8280500468324364563224586249922077 +egcd:4323608585320872985487445640831972992,4084657409651854768355784706431953538,0,0,0:6,54695934287773592257749571957761641,-57895629266230261159874845651528957 +egcd:3107887987298186821475596783022,17295539125083136515530515139788847,0,0,0:1,-4548338553569994765732871853161292,817304777293980388775383524775 +egcd:6492834786527134721523710453730006412699,17967549886740060364182315507603,0,0,0:7,470846050128324576077742494869,-170147050245744662628832662693122120208 +egcd:799805327081992551235962453510248660453,527300566054543088930412034236453,0,0,0:1,-237075289836488158904993771580490,359593924105739027278040604269201695607 +egcd:833510079586844189468222881538313142775,163464471091603074311918213259985533,0,0,0:1,-61563360576469717421897023746373636,313913361301437981499182950778660790497 +egcd:49929157404053899498216569279542495014,52392311954248457857910547305304892,0,0,0:2,-12646518967361681435848485552856301,12051959773910155320611318460802797748 +egcd:8019914013817036621081087587164121,46265590541944209649621467308503531211227,0,0,0:1,13683404292013421097959669212670785871407,-2371951261245719997345654872544098 +egcd:6793690558655838315726513011194313858016,36465391197483395356496390604936557,0,0,0:1,17578619745456361142487500175464301,-3274987572521910182985712771749335932795 +egcd:321787145894134330720247393571488832,18281500192882799634120662107983334952501,0,0,0:1,-6095953088727896985909292224676751826817,107299692324481991773965193337745245 +egcd:6047548862579556374720382350020069977,568658196833000836860083279186765,0,0,0:1,-60242414519379328797326699138997,640664194123467451661791719429686438 +egcd:2870680665840606619961146285976303711365,201189029370140692788327587076886544,0,0,0:1,-17987198256416229496582948278184755,256651679413089218267919705828623910104 +egcd:39798370242867453845816667887487587,35013670694520682198689629893928314,0,0,0:1,2054010924317556869064391839728301,-2334696295115298268400128614101999 +egcd:73858651956033138177599059035112771,52098398670389170171335995363841,0,0,0:1,17240380939183249647785945691706,-24441275123112177186980477847169325 +egcd:7644571930682061497288549926132,785802125855010277645849882091997,0,0,0:1,271947942761049618119207873759383,-2645609551610500508344199027815 +egcd:41557893857172527363631252083795195,1371686406573225335634810457756964207,0,0,0:1,-655209336639216756304666696201636448,19850834662935335118652391694675823 +egcd:973653542609832491247256728338117715,2002969097578635540682944029408420962675,0,0,0:5,175219282530720533493371867912236604557,-85174991154795587826633985259908870 +egcd:831391603082990206528467891742567543,91348680460502373319036115086068410,0,0,0:1,7961031378909225546181572782336037,-72455722479397588386999277916029549 +egcd:176911664463691309750764037723638110826689,460013441967893539463255590714202,0,0,0:11,361642599535882299511849044819,-139080271113761217419393593167310893140 +egcd:6348236474737074437089035380543803,95699625549966825347938548412205080931792,0,0,0:1,-24203197508040948460999995184599094127421,1605519565440601434387009540507317 +egcd:36378047425993403908760151690761395656927,8324175954260445983822589970605585871744,0,0,0:1,-37338373251079967191012744395502594657,163174964152701799172289301950393962035 +egcd:5858122486508222854576912675764622,153452046194711393162502085210831888,0,0,0:2,-1917578181935824357411526205393145,73204679545178717228315912714034 +egcd:112814326530446724164485340282110380257,1110948014051557856317025720135946251,0,0,0:1,-463407619011972388363881014261728099,47058024125949149529869264751419106444 +egcd:6762936490294534151595858255833949,728054939347597344951631101746688290337,0,0,0:3,-3202433078336335166791354061436519790,29747551115599101396300822706649 +egcd:605526563136558093297316930606967635244,9300793514406874242288831761716510,0,0,0:2,1345751153121394580612078693754308,-87614897516475468831438470665488535865 +egcd:4991270541520370370359273753865001,20395641239574465006088950312639388,0,0,0:1,-6874587192924230257223537357557787,1682365567137806304784656152958051 +egcd:500946862886657134755071848342560490955748,3247882743399223852727598527588480210044,0,0,0:4,-23547587498989715538211417876627327203,3631932251908272984390735044167733370292 +egcd:35871368552972366494601834117723560353107,1239860437073895516621923584113449874234,0,0,0:11,51469208630308277351083609242535070737,-1489095785865112466538607676302494302572 +egcd:81015511060223907703360673011829949,18579927224926372016967617691018603546752,0,0,0:1,5992620067510956522835707392099844262933,-26130090364822596580080018527487583 +egcd:686805747950297226208831836097754506778,415846263888979485125026003401455197236311,0,0,0:1,110107419398192448360459918988248994607406,-181851840695728638721354366896502478797 +egcd:1552581181786867650628866738064485666,85001787017719566705908468802934139661004,0,0,0:2,-14586161026251782336851603095136839467709,266420270895607062006639549884867549 +egcd:2851667439961142964793942899685249435,5962772303345585675470039928831166,0,0,0:1,-2115221698102148418532942878583229,1011594697552485521822302637286789576 +egcd:976351980138172140382095386377096085376164,333761105209340508973257305004288242553584,0,0,0:4,-11680691421845751055896280275529788227959,34169548281993462971582117489794480071420 +egcd:20256356281064282905418422186773378,36340325278599621781402169518780276,0,0,0:2,-7025630039156045892929526907737769,3916136250324079267011293834961209 +egcd:394033413204458189167729459825446183,8154588797405589591500377773574341,0,0,0:9,165356907535808812271372935734782,-7990120445312753421042830670631317 +egcd:665386750398767451333668812103953203673693,8552358001531037761606275007435960,0,0,0:1,955024064062749227842006843214437,-74302357130697440661858910661622274980954 +egcd:5687975873047240253725753499538688,999307950133750868872575786467795722,0,0,0:2,-124602922769525950861094557747847926,709229240425208460210072090208845 +egcd:874386700310057076622355171620744115078787,6285850330763062054705785971806513126150457,0,0,0:1,-1288975686576661743329027505076878260385105,179301627951558198068988999319064038000148 +egcd:1355399916760756632497111838694490983,18711706480754058334085390313570835572010,0,0,0:1,2437253796054429273026706937620795028837,-176544752649619721719844994195203277 +egcd:36233162261680351064206988631037080,28152769682211333909464292684458349851046,0,0,0:6,-441278995396378059385736368512158452537,567934651664879095404422678700021 +egcd:4627432565929377000942281079613356,26956649857247707823755540417743526,0,0,0:2,4330342191483523965289985331335031,-743355223464507160483903148381059 +egcd:6854846008427410556215762033804468577678,7155117253417530565506970580853273,0,0,0:1,-2452250746495250667905605947764875,2349339730700732618876715217888241493587 +egcd:2209645186813254112014092471353574880075,64182917222911163587618920972678745056,0,0,0:3,-4461195093044247750680745185136778743,153586946360569502568644586700147510013 +egcd:3025313331138953295279745199525101,8653524593948850180321261885145757158940,0,0,0:1,904226340311477989339899624174300049361,-316121826662884025029029485732009 +egcd:8175371412709228305420266641849867,82198171379976862350953285654395132,0,0,0:1,-2003681145318731802560456037905993,199284695518342758166966519484151 +egcd:84689792444868552924138110130100582,948880824334996164969139354006847,0,0,0:1,335813075011390237303675237523472,-29972088057443111534563303078311649 +egcd:8798524220512740895216632300585304,949715540408757144575796561647960443,0,0,0:1,-365201672634729056326900567364188532,3383366519058383956113494719486803 +egcd:217649222873019166379207709389541260,16404476006672084886049791516665079733587,0,0,0:1,4012192602792553158779189839801583942744,-53232459339725558831435308832318597 +egcd:594697321798546733359335415436661243,385951688100825419173743409926063859804,0,0,0:1,116343479007815023999562971626758550519,-179268953881601291313670792169485229 +egcd:56227820964445229423667006497516016715601,81892476688838156595578659146703309694103027,0,0,0:1,25913798344112231705938155558240294564843998,-17792555222598091584460603000915882858511 +egcd:836582345984336327468570096848318493595052,901634981123482446675039618318674827,0,0,0:1,429320451122865276676843207141615999,-398345137110681379270140802352205993417561 +egcd:70540891202696028214987115150030744,9583233767357631859259680519209578191440,0,0,0:8,-65514112814860871412811677812543980163,482240548076342233536804327541737 +egcd:9903948980685538036955142798518546054188477,73908402033109722105152729700594715538850,0,0,0:1,-31422618411370648401934291718142285762887,4210725722988152216237083404707290444549206 +egcd:540759354899060646610120700119399427327,91829281306603966715331478896265100858175,0,0,0:1,-9770047081196394787775469051083116371787,57533330129430781482128884413734461642 +egcd:87721157714374242858698347997325066587969,3284901878940400480442656721233156988,0,0,0:11,-123316683391743383266271066589127117,3293091432036939336610864709449064364218 +egcd:4743734019370435439736155675086368671242,373647739342207812233533011552089267317,0,0,0:1,-108245641206455177441179302126281646589,1374258363087126030891243596578927294967 +egcd:84363520867921952836929767189559325742,422634774589111146040596691819371580962015,0,0,0:1,3529869940822424493948866300794579980218,-704608977581504060641229871924854517 +egcd:8145193020311860837319395234399151215,532483509543719726427588068482044258548,0,0,0:1,230786770856496735053640355467784076499,-3530255419123562891236643633077796683 +egcd:2377647587095841620160668696819055129523472,773096322510799886986749609397216837,0,0,0:1,263630662321274282849039145784297888,-810792639805759699888475288147822340650355 +egcd:75184748541587873957500013097478130,838111431578529041793523211422510010621443,0,0,0:1,170760592066107917165103873007351219014134,-15318478774501769393625664676412633 +egcd:579262716093774075220251800110978515474,6043876047565477568423604334043743356163,0,0,0:1,1258844697728783566949425789115960891115,-120651349069335995640079130709736259543 +egcd:66383499181676556938103877122737166934035,530832541812442581934024695453113464955694,0,0,0:3,58293023611847179837332973337639810769253,-7289859947210577726709498679713475897458 +egcd:7920960396383675142682578572154754762141,798535291859442961798164423259513237,0,0,0:1,151926171612145541807953823850652973,-1507010649099546070150810894614252028216 +egcd:175236050519274673434166760526111360606823,281877686251107928756886484438054967,0,0,0:1,30236916062321703712671871858025268,-18797506894262892734920915273989626884589 +egcd:4355982041361439306851196662378203909,230636237869932319651414274905344806569567,0,0,0:1,-64199936549664682976687684995834852683768,1212531791403025059927999150787108039 +egcd:72466256004741341461529939955428815241048,404507868131062510694999082807036449755,0,0,0:1,21713717675376618978762676626454759457,-3889941204725080048332941044415757290037 +egcd:7876383615744606969586418493837128431527179,897248260026492001519641792023993581200574,0,0,0:1,328885352293723988890704291802089818369491,-2887079658631153099411074216761336194523512 +egcd:823746082909669336405179113773513767930385343,37536559251756687921153410535826723241292939,0,0,0:7,-2029208842362729101726422682288492660756476,44531328087129752982635593229262336345380225 +egcd:658695079684573590715110773468603499162,3354130807798642409123305655417010832860771,0,0,0:3,318657279290364283792244027119488336746923,-62578949361845124027649122556776393513 +egcd:4349656478540188481997316018037862985088490,688164220169053746563537722321624153,0,0,0:1,56153129479244282567341033533205593,-354925199932218939235077939287991582863873 +egcd:7196129991932253742247456920599960563583,1551953095381685219390198409960379051033,0,0,0:1,651009094600825687351894649336633273547,-3018613181428336616312033224198849913300 +egcd:33718565587845077554141406672209629947944,694018815107815973458210855280455125239178134,0,0,0:22,-11818955283142246659701315974948629193544001,574218177114593127458433250572665313149 +egcd:48034338404178048948731566945929396028527,245664579509095487326837561653834012231174,0,0,0:3,24571615785870174014749679914459909098657,-4804442342296368964974395821258650295714 +egcd:485688355671330103332655405066123104761671,70636792660478486808211498921213574664883214,0,0,0:1,19547946123779409908059764963032815931101605,-134408846325241118506649731947663309341911 +egcd:6405149591444338689334448812244664862636234,9522703507242637580231918951297251454383627,0,0,0:1,4648320274874893850302119473915399249290504,-3126547695921952271338054472863305659139405 +egcd:64888595504329753453829805980940122981,73955307031239460966127905414203750404095,0,0,0:1,9965146616771182675098528346228259968446,-8743447818881541791120354159157072395 +egcd:624397623292152787575544548499552047680257187,960228998573111999015226085451185104,0,0,0:1,419057942589135698988432238815099419,-272496231381448951268571570751366533430073263 +egcd:60540572208222349219969550724682829020471030,4146162156445517660494465536041682341,0,0,0:1,-1307551616090572205211276468970533788,19092336489263721226601454355991849598797301 +egcd:415933355431563557683948328005258732307,5191044700097573019754760781524192087,0,0,0:1,1272462334566092003025721823752845041,-101956264885641864639215199859367306478 +egcd:9944542537317183395984185860699341460076,7450240798258772130917228765744091077415,0,0,0:1,-2889467954547926066102243756339464559009,3856846746608830907837548122674598401739 +egcd:4675993042036765219044958471374401510644291,6536407542677511110744163901635941172672,0,0,0:1,-785059225257024547643372954589113914325,561613003920024127328079524546062364650733 +egcd:500068345406386239937220975858990964037635,31309949109544510956180803197239985764729,0,0,0:3,-1337847095354555157020998431688305125259,21367488686743026560783774598424528170692 +egcd:806337865275549066573685960631804017167976,42306413004831134281119351290563344128,0,0,0:184,109822054528620172938148368508740339,-2093150298482413200450472447557203137060 +egcd:75157219623632887126944407240803003838398,4795768824229131006026406965734558941262273,0,0,0:1,375827824436403534958920350232021578113439,-5889811493651217920413308759091284230977 +egcd:277262123821617241116745186212290538176548,4446513976462629109342017933070790727,0,0,0:1,734493945181565476977850175671555945,-45799327799969845689934000551863252036517 +egcd:98171317282291412247388001560687711655155,51444743731067016851540276812580755320,0,0,0:5,5036290558758038355810670649180532431,-9610686000386638919489216467402354664865 +egcd:11014904274052317243271908163944833907947641,71515011684041336572702882283905967103935856,0,0,0:1,22425609806502481498757965832664201241272121,-3454043276916581370784741983560371109627385 +egcd:87146147055128061249851083940353618024451530,227751615279709532340759791204097256262332638,0,0,0:2,-48331440979237806245330122927282663110593182,18493387446627430920818738708903565546903449 +egcd:402410699751971626070151333628642606391822950,9235049484375572036983799138607635445972248515,0,0,0:5,153549074522224851922845419478631135245172365,-6690791492703523748388769353438975615410083 +egcd:949267985651789297050574941117571101295556,5494464173916711420285490445361551565873818839,0,0,0:1,2312316926578234231731272711847855389498723615,-399494538794444801285919505216009539379901 +egcd:2652808479750993333843650846776418156707877,915987161711340965720691406464012679987924553,0,0,0:1,213033065472660034588639329773318587419735771,-616969261334816443264024565709812558076022 +egcd:1163472262648389280712221532386409222890356,857318074714986117766247044705267090767144356,0,0,0:4,-58043325122501989349933223216924978819779359,78770996207404485098817007910493906597668 +egcd:10406098257685455333151512936763024878968848,132372816094796368125357785730208051589,0,0,0:1,-32359440420839902616239305059134083709,2543841904381874254942688300338927982667997 +egcd:9959025918172523065346020240503154713303537545,33255835687967680839900430396715330645,0,0,0:5,-2158235906216683429459031976527278345,646320469261857919214099624368160581238329214 +egcd:20019690353839180990330900629296501436697659484,19010146624748888880368271406285795722061,0,0,0:1,1935509632476532363016337521607327705259,-2038295878718141770102878985700637985667333055 +egcd:5207112395329419329605828389549218469303865220,385309659461901750334677757380851297191,0,0,0:1,165915572078042391660107459840258089603,-2242199256442908119061230570559516064159668349 +egcd:601993736892612416519724463932736313173624,96686409886473200154411387090103804018,0,0,0:2,-10124237854286044843764528144646895899,63036033567153639591480721728193636660221 +egcd:9451492454940277922879179145156727251630812630,890293318906622270914566376145745936579427,0,0,0:1,-43405247621678402209625928105193852993915,460796865133092194091416698827502410647445713 +egcd:421136320827745191070632842619729525606371205,5096571308608922651479373999535629936434586,0,0,0:1,2075009266732940120807179123930369827773227,-171460716501561691306683845372085898878504919 +egcd:6991302085135094450298373606130554478351,38899616762470308043236153517332129921230176375,0,0,0:1,14126040436007201764984293331381102890858042526,-2538827478892831192526315111045693967367 +egcd:27088648614991201551819724048844336626611308269,66943487424321378156955754932465286944711,0,0,0:1,3124674948499217771505415118094328323367,-1264398150927660424730004830166744953548129302 +egcd:26633206192249265107832407597998778309,28885683872079634891270314620229364998599495,0,0,0:1,9892272799081534529886664444698656529168119,-9120882937536253989479027571007889246 +egcd:1293392085583226795107306787473899947221,227416266407034301082063615024346171491,0,0,0:1,-29907285136077480460193096683361056071,170092696126889751795759289938962958812 +egcd:79278263825216401490025404779637155001507461,6902468820227813108248070623732536421506899016,0,0,0:1,-828360674462642860581800632473551541382892027,9514131509009287407522188041794942836491653 +egcd:1369065262257696288586379151913703456926925,3921318368201662164740427949862301432814147,0,0,0:1,-410960600654239702792755872263158438997325,143480286394165720161890484611766660313358 +egcd:306811423659369908685018354614281524950,502749149014618067791749640767411770493,0,0,0:1,141326450781475203732924651029513241656,-86246927816738114071710451592343402043 +egcd:9719811370227578672711620046487180969505460,433430579275086048076182917145558458171286,0,0,0:2,-21526798977219262508638934913326592901682,482744954943713828666591712770941953706527 +egcd:5788020148019388092466048940831790038394,75552141815311856081164996922322733981520384,0,0,0:2,-10518739104218372390717930642371017316511851,805836504487242701754398309597647648769 +egcd:856377298658655395314577199206116518702414869,7440017597742186912190292505781910769381749,0,0,0:1,3131903658221817580778138665646284726818753,-360495275616161421170385112657167062910608644 +egcd:1689647907310953553519794122563381184305246481,7013833160958039894149455543255572091142877259,0,0,0:1,3398821499458899262672354561225223368687478979,-818783609774341856728010232260343119764124822 +egcd:7909384989092513144957228763780800053405820795,21477020481637847440258297023176370214097826,0,0,0:1,8859749519842138091084779610567087626046933,-3262797552354666439266711401038798592605600059 +egcd:30979357654518132817819836417705740257922764,260940405630631925922236059628149432070542923194,0,0,0:2,-31298236747286947106814487094222102681769572678,3715788161694199667767789519431128923820201 +egcd:984850871549275259750343917908080800989821,977566457784993078336038170702548828397820,0,0,0:1,-129037873131119636035172993956125957494919,129999409046825903670134925875065572390725 +egcd:259004643342990580972799103658759292285,825595283492252050104233175225637957516,0,0,0:1,-375346335685149725207452317778364301475,117753148241117547777519554141059751586 +egcd:794001855955218991102614066001175910817213141182,174022684013084507387799105725951096751,0,0,0:3,-10938806147098475396784404050656099019,49909771430013704026181882273607321813941786211 +egcd:9811672997383161859807242291870208222778,13360741920658508650761847028208454943504591143,0,0,0:1,-1533646877846983951433473286385655919684529373,1126257938986564477278948068254744237365 +egcd:814664124635912365609614464622452998365491267078,6619294472928701717769024660487632849749,0,0,0:1,-20513340331737189016390223384951047090,2524662184626944204865785704990399314361764729 +egcd:65349983887385540524173152888970462548991658424,660961177147869398908783897959724877565,0,0,0:1,136074117943219163120699904988199259974,-13453802919940888187441439968788876247928595515 +egcd:9480849241792212657354357845320329169823,109501469778488317937641164193300571933305,0,0,0:1,3804987659970807633940154130872070360587,-329443197831394171414676889854922460020 +egcd:27503221926847760895555182327237470261,628279771111583514714898881996093117588062576805,0,0,0:1,-220013546416993125291275595704774951395099395899,9631189276257473190741590492577938648 +egcd:9168322681946840027266828729455827850468,17545637116438090457732596682574619803340605948,0,0,0:36,-5813964096141413249612569112312284994308162,3038037236318899283433014963271953349 +egcd:2822315921382556721951896564280262300560,9667399667971791940314575307296845555254630,0,0,0:10,5947088441699739947657932361375488982750,-1736202388578886042166718097228730473 +egcd:5505800972045902016093732268279937842194207316,51771316999189365770795878029705923949174,0,0,0:6,-3811017207863891625916436251841504892445,405295894788019795906550250885730982995283199 +egcd:315267941927920486224102737047056204820506827,53799684850237810468689873350190525649040,0,0,0:1,-5914499459775939664589775100476101941437,34659163476663297256696619263386415724342510 +egcd:9236131800332788704514704731129950333068432256,263545285729806754190856317347550775965605470790,0,0,0:82,-536397367813719623726930035810410515130829203,18798426891833334693523979076019903671419395 +egcd:4691968437686244138977558753087888903984652912321,529627716152176622105651175417186500904294321336,0,0,0:3,-62906908078037944919327151653884810577788339093,557291882983286077007886029051098501072983943821 +egcd:26280657162235005084493562155644126686642367,1370831800919999167427179169348201053666488416,0,0,0:1,-668950545558535940883160448398038518399005825,12824665968877633003981478280580109910324086 +egcd:6045536043693122656233686475730851232212520209,9098289067800470455174047447178904376043370047963,0,0,0:1,-4206871815253583433092955625418062663341089554958,2795338222470951124088702397531861215608753021 +egcd:975864626523714146502659630640337751487212439,6940988044327081299708879840237906908066266,0,0,0:1,182253857832309393566019050168841800978819,-25623886940908208028290520855889573665491690 +egcd:7654068749692096886133022573587354873176,8748850507770691102882209873577170582376569780827,0,0,0:1,1964615562778113529408565381234249139996181774218,-1718774663124332015670834305172702577021 +egcd:850756247079996358624434449149782878253590,77804648630198634241116586202790778174949752,0,0,0:2,15630184779111518797262593460062779851865543,-170908519965767105980455355954051171663309 +egcd:82272488067830066441292242534154314172131040679,688350307921755313885460920932900835434083205040,0,0,0:1,122655586374168160071266274502558269222291956119,-14659948793933732247908546146130285866296684120 +egcd:50275540077712584568735998044458763684689,12487524215373463010691321732158466401371527,0,0,0:1,-4310272707559638258553658315624231083512470,17353422865679261179696672421592621956753 +egcd:392457454844037291990581880634611045578102532,2006776942135757695410535631587193797511467,0,0,0:1,199439819133605873020173563252516107678750,-39003659135343525760309650090094101928308197 +egcd:122656263585184646029569124623378862644114041656,280853932414286875647350581672340197593777,0,0,0:1,109974473329532838224195381954535972984910,-48028731064556951924576138949303550622577592767 +egcd:122723560516597269398769177665063637962901,765616664403695605489624269692889608096979049375,0,0,0:1,-258226752172223790724516164492921485841472381649,41392132539192550495968547772584597424794 +egcd:6372235942926383038761681930859971388824310569,450457134311977647755977405844641979355735844426,0,0,0:1,31158770674255982909157224955056954353717569041,-440776764988213077644482491833524983838080428 +egcd:55710124200643562666353596472476352006557402,129521722711569048118860224844308955120907039667,0,0,0:1,55524240351481153050668122616773552997196032054,-23882189499716295999156216742362854145492121 +egcd:52638437489786006097404197485813719704184482762165,38484575113442816269970218082013142493165049225433,0,0,0:1,8178630279958745518165064668394460744601578134160,-11186568059401556693065851931124978194437124969703 +egcd:8865739212422336318534105978323392918519865739,156466530229954316319347454260872006246776,0,0,0:1,-22332727854888622695494970502136839031101,1265421689689503887387017047199762890477050140 +egcd:265397516257014571242786403736445985853962,32533852784248587969347758598232018992116038855339,0,0,0:1,-12908032440841768357183540035974013542745984846425,105298311032592235052498055248608994180209 +egcd:3535080036435391574837524982968689282803781,74249567587110445850983262206024731586008,0,0,0:3,276939285966568545124733076132658099351,-13185296196863522858383215997152316071266 +egcd:47346135611124365598287053304187866567992166810,576740218461234987857552610598030250941997676415,0,0,0:65,-2126430640686396085034515662972949280965477373,174564336349217453788449880226773993486353933 +egcd:820830106986357361740709716178206505926491986956,3217456208051702777250937472105195691807814504596,0,0,0:36,-11508975978649369323663700445407671174097770014,2936143764821793638026885620541736768610769895 +egcd:61739911443386844943500901189571167227813737,3848550281723202830510194085486377628651546,0,0,0:1,282984239815910264880297243679049891924891,-4539741104353078811173218272678740948066221 +egcd:4935130472338939834485774824152368863725458605,1035806531451219174441688602906921731365011,0,0,0:1,-351908970967360751930093135356643002982497,1676680570528195395018821587922991870638322426 +egcd:3266540541396232463580738683146696014840917,4935087952292184155374454402916005109216111873405,0,0,0:1,924328175593731869854608058802170988017990845743,-611813910576679910370160267913438850314786 +egcd:14026215249956339676506155791652279539578905172124,30781337324124641929530137787213325258646,0,0,0:2,444505386198527884956851751358641210372,-202548971831029013803042093087467123341818781381 +egcd:4294047460058049577385615940946646673529873,7888285331485320409101196690477192599721030309,0,0,0:7,-535244381384157584881763833984960586681612928,291364305398447665235093604580474039882939 +egcd:3323417013847245232113101349532994925521490334138,5122451664153873677965641025886074343796981341587,0,0,0:1,1425515532127150707596577092883695524648753420721,-924866232731438695305713017060351754850266688931 +egcd:80935426461988829507228088844586242462996089069583,653780401944410326556349775523493660318880484692,0,0,0:1,-2131004721544266945571387397182966694100115521,263809951197286132655279411613822876325373015332 +egcd:226598141134799568921266709711899059121200358247,76992399049617831317308817003284176072753,0,0,0:3,-11448437027496398690279470751607992954914,33694164376637528064598542583627016152058686337 +egcd:664319721933063857023655129340934847648590823,658199665265274466519942300240556524715643,0,0,0:1,124352795083709078633408434668474547721672,-125509049322160532052275511129607044720504885 +egcd:8884738003622398686160547451276690420223171,4299975907886085056063300778367761002052776699,0,0,0:1,-1116654257404751368771631661850560365381800860,2307264210358821074298460923747673330704239 +egcd:59719426635130468128765525893511605775762068605,15511948776571237043257049623825428922813014745,0,0,0:5,97984350967559952500670074951721914832581821,-377229795126457555963914383461705837385561060 +egcd:363283435899720839207247713911327116143466,2646681445153091542108809095748079207088831696,0,0,0:2,-645295047870741251832001677370106736568796843,88573183821900377839952804802844006175665 +egcd:52931164096003232205392055066962781951605227742808,947807568550870804286088054962593413637490,0,0,0:2,194186113496156753567887057914625616943499,-10844497743719497124422772319106386069172727940731 +egcd:795766141035085366569782895765897502125872618,5246887073403305711124413150544060139255883684657,0,0,0:1,127592149200051856506732829832319739908307643715,-19351190672651565653969035751475639783463117 +egcd:82250667724186953595968128381514526686421673,289549134724791932338507372783255493005385,0,0,0:1,86151709811972420581533505911642683307877,-24472653542377849432010330789204946130679372 +egcd:61639425939671741256997475006356513882668519581250,3578514828596765772820255901738596048541569387462,0,0,0:2,20996407912033026016667547576264242700583756497,-361660239647628207370955868455456400780266234704 +egcd:27684537637183448026151946909258691476828389542,9528939357362238270010422927669825442411130925,0,0,0:1,-1491403989803236735430244778811958637923713822,4332993247150086860055318193545031767864356713 +egcd:5435307729184909003359952075698243178049039204593,81652326357120772943208044441275143659212363293,0,0,0:1,-18786061737353190995893206957396074979160669634,1250521952251468167669960168322598898079025280191 +egcd:10924773406337855054647765543952064725613723120618,14527409504138198936169926863040904530587755,0,0,0:3,1943780369495648845597031433407372402007186,-1461744441249394454828419839546381797839691182739 +egcd:52213006390422220435171878651888270946818062,871645758909254953745968603137179283818003972840,0,0,0:2,-29741256420958113534899191845042319813299285189,1781549896496816094656316432366924841439533 +egcd:4688712561272866795875010705784298446804017837,70990811276700678878005205180077865101611393303,0,0,0:1,-25861123710957590275105742577281286038202175280,1708043244069738879850646003632659154370684087 +egcd:601876680344350654318757321802040059504236,57573030176060116021084277750039823155966100,0,0,0:4,833675530078099686733366641090550664373764,-8715363061372584744643797829391972554063 +egcd:857505478933565140863302872774416730451047627,974314057900536449023558662039365613006496,0,0,0:1,29431249747985173674309139068596168851555,-25902795619249680104451374326446194507504004 +egcd:45485812933729425157241764872535935492149300,423866118406290068921435664923874810909565066,0,0,0:2,-92026904416450995131867199112617558634435512,9875567726185991444222573035098359638524797 +egcd:8708905393403458838119906185182390415193154723813,2649214839375624500171797402777266233996857,0,0,0:1,-878693520989369471627635491452708391853508,2888576128426243950131007882950541927952108467965 +egcd:669875536982562277168757149616294771674281736129,97516567980777338564845413606958767175755421280,0,0,0:1,46381889226420155390297645103754990574679184769,-318613478664861551321523526265950713581534609390 +egcd:552142172787258525043120366564284640581592165713,863962961122054854184533799151634607728550493,0,0,0:1,-120985334199661742489066675182491559538012882,77319408708953488066818827922573705864500213519 +egcd:8912171393647579492805585431506224333605369238663,52587987699344024446727521307243310639764632765,0,0,0:1,-24208869892720635889960417808933792198197524458,4102716364884452109263231978180096274383271959027 +egcd:275693664465005824088249757937188874572769224053886,3466602115356222955936873595606282941132234317,0,0,0:3,-221006434365087927325688159903180401056179309,17576310096434242315782225656574466646053079410381 +egcd:5028642354464479207857147979297496218105888083856,6176113771729541577635381980538182053262643750137555,0,0,0:1,-710631712528650391026653778416986011431221346318294,578602153413129397137286808053013793718378471803 +egcd:8465402742576453065707574311196744344728516738,61661356518501223354721904644532208588697512,0,0,0:2,14937393734471008272165421983397469074399301,-2050734220366918264382181168692457172485461053 +egcd:33090073711191135330109687427439016660084475,445642221929395862212411325653215048318205553,0,0,0:1,-165351447151677755593906743574229677911339226,12277767467392269710361072198887310106213167 +egcd:38084383375564641238722495396072746414069859975328,95831351502059780199491060292730447215506096476577,0,0,0:1,44701417714871641774374755091058724540366425072078,-17764811859591030607619685717710642838720797546079 +egcd:39669808567342798362844877241009314051976791967,99119958834519191165493856402857838929818011836481,0,0,0:1,21195389536433434447160930459850047078305039520162,-8482822786723704528943403211431983212657912413 +egcd:656394443821895273811037542396860681243032484395,734418747296348194673752402369075033727947320580668,0,0,0:1,-198348208669444102178880145335745201028303476849097,177275787950594932355555641521970313763246167487 +egcd:4151672272018474022265799254859348963458925,8657522863384451966497522640761563355339408510876,0,0,0:1,-2593012562485881796973545247397827317361955393143,1243466350195667180206121886940940782727901 +egcd:616193338763982804182193956310277879275176598293949,1991282968221128113819350795131871998526550,0,0,0:1,672187344044686564879107554044311287720999,-208005276202308979536534651654988391029147577601071 +egcd:8687537844058264818625968633794987777114571540965,4588008014762873083430262838940515379172783903,0,0,0:1,-273131667435174631012578706118035112399381704,517183424618854791062408052693760196421481021687 +egcd:94299417704457808128488838366264331063646462702181,378910566091211661215935743383333262065042992,0,0,0:1,128249482146971828065759668548405619393919421,-31917430047190763670990418627993655771034878683475 +egcd:436084754250362560867427019991801320098048671740882,654347024914243888183493882710929942025818488523755,0,0,0:1,-124697661855776361333795036367240691582603011762292,83103838109598963945718792347908533185519371904059 +egcd:576845066105037981878716311963244757143336175108810,47169550600388313323767894641195570046736010,0,0,0:10,1719524489809815702007774620101569793957264,-21028379651032953624905166044366014052373893560783 +egcd:455450311793013669133010532968680473621765301849,196887903745437577462662843393301335218213938749,0,0,0:1,-62895287849643879856045665234849365671155433961,145492322872554565259262962480158041518555693610 +egcd:3900215337216547857536549769208785869150917,703107675983691037178395903530670398382868009,0,0,0:1,-291772656941803838282558784634427859227791877,1618494905481932988460302827539233588975690 +egcd:4235417950821263716456215603171042810879865369448,30099855971642941146023855759175128865528083067679923,0,0,0:1,5433558916670879875362806366021878036014090738651158,-764568209037069458320253834476596864323900548821 +egcd:220042544397196218820917335251808518190371752175199,933535692277684232594974193302788809761883748,0,0,0:1,-449365625423429659602361441217910654207591337,105919416258801934451915453319879733490159050690718 +egcd:5686178248384112550645420272297349915998890583392866,6394565636060087046686488902334128218389439375166652,0,0,0:2,-386878534783330326592254369705226038342074430538853,344020287608948398285006281037355413110304951350725 +egcd:794165469687755539056069459111608933432404895,782304420953549695337102011535232984737054552,0,0,0:1,15995811988912600943335882434276695389371735,-16238335360201271890738766944404884526025987 +egcd:9449310146893908465306850102371521287231298790519,13201049101057800842831327281338645274946911094123582,0,0,0:1,2999793730046215341383581586839770857893954084651465,-2147252170256912651603598387202626192386287752937 +egcd:107247303626237439573377913856037555329228637,248037365489312307060126693885968609330300538729254,0,0,0:1,3295187394963377883360979486845920526196477093867,-1424785182489835167324341201022464061856757 +egcd:77133522083392356030810996444450842713578606,362446320582641682962892932453319089993578656338136,0,0,0:6,-12252467688569006394870089744676118644607994086307,2607492291584185635921553686052009701918118 +egcd:3746529922356093187817513741403069494944937614875518,21163192571109744382435762015727356715830696078192,0,0,0:2,3360441477707708557262863370472736448288910259287,-594900533379131316626599736433550281233005427135467 +egcd:1480332370019794273587942168003226621597722167298822,76107169267609678850598825056993761581288230,0,0,0:2,14857689610118706993669180053071538933427241,-288991419405294102329201336816763365353292004875870 +egcd:87998368974239358270522399707979936427930543218697,29464787743750967717125516987996695441482348481,0,0,0:1,-10786185369002819879240292144429281969862945959,32213594347963902773511656741076864997101194881504 +egcd:6380501221201357438439263574761686303469688367209765,2101187057561466700690279154331921103508225955903802,0,0,0:1,145825347333296093990690878414508843106434447353569,-442815789957334350484616630550368772984065306700842 +egcd:175895697545417190557526178538864907787776215968336227,5776330255785661509841982629017072861313591718920,0,0,0:1,-1178091011635241644387254463790507228219378563237,35874185008035358988026900184682989666782145774075290 +egcd:93915008302504565970294462868559347357873734156532,843248938319701518093307338244595352966717434,0,0,0:2,151276724006692666989516063064725067523333305,-16848114649719091351395265497230824419920506759837 +egcd:5976711283802179473855536437769569634799149864037,172795022672485802101638449934309020644291613,0,0,0:1,-82366904453391796214074238888113409850549992,2848943214015556962691631373397667435722686056285 +egcd:2205248615867285476540661866508420170225141139,983067017505522956565352285112444457364117116888337095,0,0,0:1,218267429603838059510873324752454714497132891681911749,-489624754418200054062883904405297170239063538 +egcd:197117471835494353404914690778881470433860149135581,14191428012947823659636428685835151126952873593,0,0,0:1,4459525876016258192519437797582725274696114004,-61942354600486601745601801863681456852754652027611 +egcd:83820729536850105215720647153262328929793073678,98655882859633233870604900342857378466000427081,0,0,0:1,-47880418250666765255679449182794532875903726259,40680509585126232668822359561687380513654344563 +egcd:85021523085826077943750195658443246760234911045931,47005020817553666242267156046836837169033298,0,0,0:1,-22669310085724864052132047557226288756475911,41003689335106972184099227663484803158330242761279 +egcd:5946017255219161818471671405255932514415767039839,6345872556760394171049368149822641242688180053,0,0,0:13,187171763444601755684128559806849993896322673,-175378015422918739007590870520259264416567583578 +egcd:71419612666385070427345623221576087904278400094,54972479988506664671028428434907112336472819338750,0,0,0:2,2179890297903206135328344242764978585525743095133,-2832088360648962656287313107815515563957911534 +egcd:5562790597381394993959486043063470014111501298412109,626590695183962064663009600613096722773908377293252,0,0,0:1,-303862519026371604863957069193342886543269595527523,2697651875025465536959295692693138029979462283932754 +egcd:90975070092326503556334167670828683463142797887371,295231087609240283637008177080140457131796372960954,0,0,0:1,-47867129509253228973744519011198722760573329294115,14750192798078785017913570665381167139156130951029 +egcd:42687927598884676578701708409630846818779523811494,523099282468377097295263711037946167371766507649747737,0,0,0:1,26078560817221509087425598130571631203765655378478163,-2128161428162465937231181781214658658975752224633 +egcd:149816245892721291534122835342563111201446590523,42288103374933513898890089821708822543153841946467,0,0,0:1,-5793317563557773262285017616969069220347034903402,20524285067631197541636488904710796574034942341 +egcd:12209271420687937418818672144031853294587657600243,62252474450489282538022150950275214557489689,0,0,0:1,-29660844749864463057583581069915997873519776,5817235496494160175697352420052606379606904518921 +egcd:379128079964034811949790348241734661654811843827149599,87839782929720118794817037174959224009493462534,0,0,0:1,-18238653567217319969185225852935419777019511901,78720432558454288371409573793995440050250015166426550 +egcd:114215100939505653408300174032176291289669380562,23741400935738901134986324457933329645223539201365657,0,0,0:1,-1827217335953581276681577241157959216199445411446483,8790374798405201192178937348284544880847527471 +egcd:1926579880365706875550579926206866629082953879469101769,3149513448830666223576844897044248210956111085,0,0,0:1,-25053848460898792135835176590575779166100741,15325618116798233452500443229076217786312231314349798 +egcd:34061999712899400597535018329561333406378163617467742,171772975832275747480880934476689264812053050103356,0,0,0:2,-30353734173948016840673304098829017018627498398083,6019042749355297425828459633966808378067330339305673 +egcd:69099794678760243778781800244520189661090743680330,84272230826240573484054504866235051739757277304495597,0,0,0:1,28460232196411257321137881889341868158873397195672407,-23336230475929248726663652223642021667308541046297 +egcd:3730778374119404797425236403038460041746582520101,7496868998594071853311205794112072400183459199,0,0,0:1,-3417158685287301201140604914926004319611879342,1700531478727317431970501601480361491459818880857 +egcd:694479210821228795777963254574810624923840260622974,85973514938807029266086479669558486228659003996037,0,0,0:1,-4363087914001491864265409481816897855579273618450,35244270906174989824540564289343982280916293290873 +egcd:976689567441345731919313645335687701163688099904322773,265009793970603358383229061050229738244347533205920,0,0,0:1,-96111738809058080341677874192436389369700333445283,354218352450277244615910581013823408191179307271342353 +egcd:11306238535217366491646986230523588259738750710860,9711793888012260176296349031139366341426284472,0,0,0:12,-88605262509097782289291274601914001329437685,103152130796347815361130641167067199415554197871 +egcd:51967669483767224464737921823977975662824880006456,1280946574522273740836915199783500350492882920,0,0,0:8,10268330208562887554239646266539240997802113,-416583486807630194700790333441124375693097218206 +egcd:2608000098327642864267195515218438837191124764,76463054831351286123635518055043629109951547944085,0,0,0:1,-2838713528640047131970640855543361319685828626166,96822775105523699697177482202209085573424645 +egcd:4468842728483750749309421622173029139461617867432562,104288232549062003896035112908374600291926031581641,0,0,0:1,-40897526108506312057324550666951171967489049680830,1752495058126446443607941125177833715948426475092021 +egcd:9515999226131724451239821556730726791154394377871161,7017412308925966316941922876372144830810785912251994145,0,0,0:1,711542578372858898917028457620268762515142703628762671,-964891091911944776459586890186052584752080420639414 +egcd:213839504515148236538273214896810704701481567163944,7404902411186480168131101360415567235929305381970861083,0,0,0:1,3380833338481241432824569741692207456495975720502139882,-97632039668337051697511687169125113631113481270429 +egcd:4704143575442564619226639933367529686541295734236339,6208190661916178838888950379033665108451167558784,0,0,0:1,1036231609662380598181323571412442265592690061947,-785185657902980530502486174709506058502162341225648 +egcd:7800918125130733756931790281898023131423182325003,49727855698492641147972884260023067177838769605345,0,0,0:1,19886322404414182208422530205281052324435144823897,-3119611145659963799957590789424626986012404758802 +egcd:16259480181384339216392327597672842436080220095778,4211887904631546369945283484243515208523965162735,0,0,0:1,60867090942630605523831629233862298664493090172,-234969990011354799892126958820227867474219476729 +egcd:250262833515008658954045947163909193707871367256381,9360574256964093238653836590939739950376635341916,0,0,0:1,-4577416570401947847275576528151972968266287934083,122381085779547263818532525602930002569551981217314 +egcd:49350305588299753800512832973348076363359882929159394640,82697581133815540138675428448684737574082443779556532,0,0,0:4,-7094756990744589041872300640946840405432374076597223,4233841193026162290519658157361356032844712511769908257 +egcd:6929763065061301565614851166591733819231208368855577,7015852829866459363250622386383961076838110347968449,0,0,0:21,-140151926963831515623623343137474264566890746373088,138432157931912474126854600439744488201286606016053 +egcd:798771392168930640410188390828161875038624287357,26910611328285765453242714553447940950358339441064142,0,0,0:9,-589064228600178541791155571644660170053125967736035,17484837048696468032579268233817988200645136912 +egcd:25397454048672817537966781867771032309891340572691,23256250389273255570062468054746082424429806429,0,0,0:1,6728497363996047750398121428930431990223003005,-7347990314789774434378123575091130429836158761726 +egcd:123423695423831974268547456942149055439119884772839,46840700163848752557976957753546114906692522490120,0,0,0:67,338082829316269748785166702372267870226049440293,-890837071341720045931329882131992024423327017348 +egcd:255083834192307897983466926757917955799611163337033,19691274316552711716703825178816583758491484527599,0,0,0:1,8267652047084102914471657271320768345286498962274,-107100452212241711960185536892796650356109725315359 +egcd:12995280360832692505430343465201277534610726091988596,59465235355121959404752559527335404508679919016,0,0,0:4,-7141155689480540101632551150483184164353752087,1560597880945943136073564871687625551494286751865366 +egcd:22991573949171758827108078165749233594263284484912054137,283817289083807864939015806533699958979417645701638,0,0,0:3,-14276343780208855857892287243849657918266920759821,1156503237720469287676414796512164794747302414005802460 +egcd:73499010438519566918821582344590421556887663107370504520,3896393550660794088432191407076243899495579652351675,0,0,0:5,-256046171286391936281227275615268399494905890920906,4829886912457785280143525162619404419581682774707946415 +egcd:9583870140187439825440257165562832875040106160360,144350435363505176257999415244713117818105415897,0,0,0:1,-47530478459628272998131044625702170795099568341,3155694903939446205334553339280276087238902971313 +egcd:2461253900541942202429868097665121039076482321402912,4470103014382515051213146843793545738275750665419,0,0,0:7,-245912852093874846806381542597934573753889813353,135400451502357810057163583858882200066572301755797 +egcd:7046608505460840717651450079359511868310129053953828335,58898419892762238699911322923913407676555176583579748895,0,0,0:5,29358649717475420636966955061254137346962695123318402,-3512469624561697691831838742681262193506315801921927 +egcd:506826573770755010074059089662551590730419138892682,2122797248606187597520041255704732461621253654865,0,0,0:1,383346693931445995397683618340486631342217567423,-91525599809021126197144665711931909038630799314789 +egcd:651539360489382353856038642218105742846167090450124082,62040904220472849789353991154770087142114255535343,0,0,0:3,-2355997477848366312104173979342645132007028304972,24742145675004203493726030544699958619654829318107349 +egcd:21241404865403392359971818730574585605571301440311980,633711839015175748736538000969606849077009552352665518,0,0,0:2,-29634494220450461639960895856430281807980194035925990,993319441051141196492952842918573155102238513897539 +egcd:705059512890402826453839323123808449258609192987,54700053492589412596920621965162616297504870254670606577,0,0,0:1,17209927692044096764621482310232491609809545108074829881,-221828361412398689301748597143984873381349400098 +egcd:415394044144508415296949741318653110880449387898,712027399337932687761182029057846295919208016685209861,0,0,0:1,311602633323208816932778876458826680113268935109136666,-181787776906565417455080707523448468254230808647 +egcd:83651009241467439062630103095611805553814512321696,446490369450787055845922775483794833260870810890813375784,0,0,0:72,-1344835414515943831032725871506341368981976803617565435,251958042961384654578843735842923162844346873473 +egcd:6070283815502486157201490923461524628539767903594155636,3804770539341434134928308971505690245714256366681925,0,0,0:1,891543412196165172397968883307773535161244063478816,-1422404187036464521764325842283917202125611790642909427 +egcd:96178348424332762060134475763000420774833630208152855,2806142261547257037797431000328431629728168038259049468,0,0,0:1,-225250250276381610381864841594193349660878357372833721,7720277532117966753867311498921456722048818963874392 +egcd:865765710958745231463327672884696335768725685962,880656889492281564646438436388571726030066590436314543548,0,0,0:2,62379218473169386716154064883279697033462165217514103793,-61324437558888497176774502622595381331609802518 +egcd:3070091985634497235831095568321669340142231224753241,3872660861602828375769437905423007683683302354983,0,0,0:9,-130408390759835341307955887188778334976643191426,103382601688896077821738216002703636813104276203725 +egcd:9504468312001233029402718544926917268255994088587,210179277000215612334709921044939204096404089694219,0,0,0:1,-54268679178541938321110274347377533333619467634554,2454071347795548035690892610366452456534032251421 +egcd:9812086714469743421916608502147765364717936946446424,233160386400300595605996182320148818062281081024933671783,0,0,0:1,14451818554970487550218007381375932641589632889155020753,-608175767043463911892366241689545509336116825541137 +egcd:4360347517898600722460235991841444558919923303109907,283395924916312034671252929842416261359155988664543,0,0,0:1,-105355408855707603292421311080809208231429401696971,1621004944361269525623546575360221751817290611287086 +egcd:907128595118057734919250855358256235977656150196435477,4751580206547799719609283650403815057095853254068516282,0,0,0:1,-889356095279141478429404461825805439836321286132426239,169787799048096169202610086149258055777141370865005422 +egcd:3973997826695458235929341947630757918334953729985,919677988629130382841929983511305489218360268786013503512,0,0,0:1,384594482287927020029873640499023823049367287552218834897,-1661861712108041873322099084387127370672735847462 +egcd:324009569902112154788016906941706831494599024684,58395597253468362692345409336860870479092825229925,0,0,0:1,-24289711240864138406494464493033446495436364142986,134772127734877303605549194460068805419486762181 +egcd:9872056470535077418025544166904013532879288870389,987664828323257512963011567924222937884833452375999089884,0,0,0:1,-258549889378418898215810868491864809363285916014306422747,2584296853749008257728523207193933514360103172426 +egcd:6138432786866037932815463907301440109085864021227742475,9643623319216552530346508247173742908756209280545686430,0,0,0:5,405384190611356540803926039847087441116531679787752407,-258038241909272527261791760130585315013837095770089124 +egcd:9769529614309261031704728459798815700297631096679,3517848632227013216032933216030143937697714956834420809911,0,0,0:1,824442973956188793176135575810678140011131714049438939237,-2289586872950597937723114927397934685180169653102 +egcd:147669070524401967353624660276651246996312407855626175,618549790847610101709816507641892193136137457678390333,0,0,0:1,-236805668183208014750730197115976279202350305381572622,56533642776931164630044536099572395597955604255694447 +egcd:80869456296117844580165320271841144299624178440949,1514427424327350480216517445312029963129987647776900447567,0,0,0:1,42937034698172799579489980026944211003937200326398387877,-2292810203533548889500989218354940644696579422616 +egcd:780887627633271006167866160971476360466719486004445,6754024108447725515883403276228352886002003364798583358,0,0,0:1,-1452325437600127814516627181590300017598700651740748185,167915149147974595643816598065833917458080039787797 +egcd:7199869643335698558244236956584912995424331052926,1527691037819148269409741859243943945701460882281456,0,0,0:2,57636477641770614383597878932375099638471007783959,-271635504463112985014746084869260309486608865147 +egcd:455180951765525170462545338088508018606122351276980553,556221150703226579334767784298557173503136268977244374088,0,0,0:9,-26099094677797268547154896038734560717230667555583420223,21358070869183507434245801704745654317447493932633856 +egcd:93476519277392442254618836667858506817969980392044,987802175681385610339163711595695835800228648753133,0,0,0:1,453471836205864432156593588057832292869365167568759,-42912406838557667802187349192829335384746711750815 +egcd:9180181445786644280041614496157713989549610132944896,7069909765059709568140852896063908165359626347795742,65537,-59832818838,667:2,210652202891822695654795784473414654009859303252815,-273529013631655892016199829860413659231566937548689 +egcd:273907002017625351000357839595395794496103882311,58944774459707213986630692862708398194596783791903184158,0,0,0:1,-12003726808325219248723901188186062373690817244591520681,55779411376906145094866211582214461320097963024 +egcd:22771998405981875169000582212334819990253681885689,60821984515441323586153842147099185189621658456861319,0,0,0:1,-23264721625000571047177124342948563692619090190183688,8710406409472299618111529542234963792113787292207 +egcd:3842241889401713108515872147470991560356182059740378113,6515515734620532620891823824801930655919134250326,0,0,0:3,153369059865421665432317909089784699996324017593,-90442729379334735477828876314356700692421064332545681 +egcd:2864468548588229088711156824748351772387325226285,715849610154437365072792769096891349579259900786933,0,0,0:1,268550748090675670123276782608442742660458501428618,-1074604443019284165403977646554099860591230618013 +egcd:3810898561978236785388520202269462480808294248695893,1062108199707865331145512609955734128758543891943,0,0,0:1,339617394241108857543260840698815161575640725383,-1218564586632720303123702323672631316897985132530526 Index: contrib/isl/imath/tests/emod.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/emod.t @@ -0,0 +1,756 @@ +# Modular exponentiation tests + +emod:26,73,10858,0:4748 +emod:-79268,611,80,0:48 +emod:46600826,0,8487413,0:1 +emod:1465748,364434193,5,0:3 +emod:873883,48223971,348,0:127 +emod:-52,183,125544,0:49784 +emod:-846,394,969114928,0:877192256 +emod:7054382,917,9,0:5 +emod:3768,797,42,0:18 +emod:357352724,2093262,84225,0:72601 +emod:109912993,364,8323,0:5279 +emod:-3224,270672,198893010,0:47016406 +emod:55,95723840,523703559,0:372050017 +emod:791480518,904571,581451304,0:444873224 +emod:7278,922,2398,0:2040 +emod:-5,925972,33496,0:15809 +emod:0,649246,262,0:0 +emod:52004,997,2,0:0 +emod:-4115715,8,234398,0:3299 +emod:-13612,2576,57,0:7 +emod:9843599271,9688373,8509,0:5780 +emod:3415850521,762,3050240,0:760241 +emod:38873,18109,6791035,0:4721568 +emod:504242,66851907,859955181,0:352955933 +emod:67731070,2628566175,7885095,0:6298660 +emod:575051,8,72796410,0:35016721 +emod:3,0,6595628337,0:1 +emod:80479332,13,9,0:0 +emod:35578433693,9608165878,32791508266,0:32575013339 +emod:9998073,96042198253,2871019117,0:94477702 +emod:8502,88462049796,288668,0:234260 +emod:966350153,6125446381,940,0:33 +emod:51249,46773,83983261446,0:2570243355 +emod:2571204,205,4404831987,0:2226688593 +emod:19,439650,888059767,0:247638574 +emod:9485028101,55407,3066739,0:2994746 +emod:868043,56705619,183207,0:162593 +emod:7072012,750002,2399910888,0:1322891440 +emod:55779049,27843295,96,0:25 +emod:57835434,31279309,90443,0:13168 +emod:-6511,7486344275,346901687,0:325667244 +emod:635099,3669199,81611251,0:59252827 +emod:8010935551,34,9927,0:1405 +emod:24885132,4526383,58404,0:15444 +emod:613003,6878758,49607641,0:43381288 +emod:132639004426,81043,587317316867,0:532884551555 +emod:4439384,43262747,10119,0:7922 +emod:689907710540,460484866,82087637,0:30398950 +emod:84094,867130,62309,0:9025 +emod:-33557432,60878,580294942,0:194480658 +emod:3869257,4125450573,456883055,0:129529247 +emod:9878539157,15920872437,4738245,0:2745542 +emod:8582013178,46758,28059,0:26806 +emod:48259672,37258629489,7377276929,0:1692584431 +emod:920350,289730727,1122526,0:471310 +emod:13029603,4503668042,8665149,0:1456593 +emod:6938077836,651113,5180493,0:2235984 +emod:-352466,9169937470,70675259176,0:18255076720 +emod:612474,308813590252,510155,0:383521 +emod:180356946205,710633896291,575721,0:242878 +emod:83046,3518,9768613,0:8644737 +emod:8670878985584,7549509958953,968064799634,0:673069231488 +emod:-37831593555,141781,3434657,0:2539127 +emod:94250019226,452692809515,99738576,0:82526128 +emod:-1746555354919,310727,6925934085655,0:2276231760446 +emod:777851791,126226427233,84192406004,0:11526643943 +emod:3511,42864,89474,0:53201 +emod:611596753206,17005495050,3708625387380,0:2318918831736 +emod:482182433948,97822330605,90338471939,0:27830209373 +emod:8971927,5117957930887,1928567236065,0:1437815380378 +emod:67445777442,3930771,4541604,0:773076 +emod:-52133,16783,3337,0:541 +emod:22,7787554274,823549,0:503210 +emod:46816685133,272923,22855404855,0:4704305202 +emod:181225207536,22085689725,67955765111,0:5581219593 +emod:207971493064,41707850,9115746425,0:6454330776 +emod:42840650,206759347,852090956,0:15995168 +emod:27703329637330,20686092,8407250,0:6767250 +emod:-4953,669615,741766623319,0:660186892888 +emod:11957529241,380932179443,973373783,0:970856001 +emod:78726001052485,62593863,24053,0:22766 +emod:340516095,798875,2556443616,0:348235359 +emod:954899979887,472716,979176,0:21817 +emod:1669727071,1008664017563,37837,0:17717 +emod:592681,30974401363809,65653048867352,0:2039369146553 +emod:-47884,525888510,60238953788774,0:8466915489354 +emod:5643430747,31164,8629966388917,0:7441630635230 +emod:-9134817647675,7013427758650,14493293680,0:10069704265 +emod:16875464,4824632,157384425878173,0:110131510850102 +emod:-1891400577,334033142140099,1461471589,0:500051598 +emod:337804687158388,2747595,7100373337,0:3797937129 +emod:597469670,80669751974,564129148100,0:462736594600 +emod:-373150,494511905,69961532,0:44955656 +emod:541002,396515,663670,0:448308 +emod:7443329,192200716115,819064750,0:75062949 +emod:352331718576096,937115695,121165545639266,0:64461611886972 +emod:94655436207250,2442730,199021327246786,0:98351560387664 +emod:450100,441162616,8233398,0:5554612 +emod:-562161185511147,564556372236072,6280258,0:3623203 +emod:-87181577138119,6636401624,33493475420,0:22078084821 +emod:63757825,675193212577,791180,0:551825 +emod:75719430,7834623506500,81861106,0:11697720 +emod:7636428268,342917,424075566,0:382499056 +emod:2847036414481441,3486471,96180960030,0:59848561291 +emod:7605693821889,6857556039961694,9340113967299,0:2791642232520 +emod:8460275679756,1249967640481565,3530286614,0:1855000398 +emod:-21034390,9455714874055,499517062,0:436407454 +emod:-67878984199,6771837956,26518969637,0:25569641018 +emod:24845854,38512788750888,97880493,0:44709115 +emod:913222119920236,89756684,24503538,0:2358514 +emod:282825837874763,49707087,4419250635,0:2888992652 +emod:63007338,778023537730086,51807416,0:42047040 +emod:86515727,37854772745819,932061443536802,0:913958455659941 +emod:16752138958,84132272429,883645897,0:66146743 +emod:76020717,31715587905196,205759754,0:84248649 +emod:408229656454238,503345091356,5122409740,0:1428721156 +emod:335638746639,5761369582225304,4092173299,0:3495108299 +emod:4118216,163393347759,33772615,0:18314396 +emod:6140126413594,8416471601616,48576280861410361,0:26480949886245014 +emod:-654797902884,3118772351656763,49622473264915,0:8452790798791 +emod:724850698,6033802538378749,5080656658,0:3131590110 +emod:-67747240120320,5206803331886510,16513427532371,0:9305404239198 +emod:571096000432,140739165,2954342334466067,0:1353110426217941 +emod:-99625731171,97620037702645811,44537854660922914,0:235109017589213 +emod:33191179298252,90227008,7699370104843722,0:3200733061202818 +emod:63893120170170773,976336027,635053357,0:242474238 +emod:42622029452,37698167195197,75773078526,0:28876796648 +emod:83620114446490,8610382003,464773010095268,0:378308871158308 +emod:9574472571,9560271542,228122075654,0:119978765197 +emod:56753833744514594,333744771296,46684214084,0:22141695456 +emod:-72021302,2716854503311092,329338426,0:308255178 +emod:-12837777900800,17117883244,11645469,0:4924588 +emod:517104019809,96545405933271150,48276368795,0:10960026506 +emod:749819481,17040593450696047,13586015736,0:2311264233 +emod:-3050009718172511,728537309,5801457671812805,0:5155502323398924 +emod:583365344369904345,274298196969,206968876678,0:178154366245 +emod:38505842262,85917484751521,136556283742,0:107808326812 +emod:15796803,666915498303283,9286239329074,0:2947240710171 +emod:1386598857453,2520081676103,9050689134,0:1960415451 +emod:837113484763,3657616517904,83176471315,0:52463786271 +emod:4678899921,2786079987037,15314196040,0:13824191401 +emod:326751076,992797863718,911067433083695337,0:303879844417619866 +emod:756697895735,14491908578947766,2765309614060,0:864557526445 +emod:11248294,4566321352111312,1353192745166,0:172343816040 +emod:7099878002228869,59309793877,927000340655945159,0:5356010609771131 +emod:-52873339014,197683370410545570,9868414456,0:6992876320 +emod:413327450631,3360204571,9303944255,0:1706685666 +emod:-50582368810,137417275741,67023586922155120,0:46974101556682880 +emod:557831168094776659,36136648411374,6960687433,0:6184527385 +emod:7693794217685,34977654183341149,7387705549462024391,0:5937660734860285181 +emod:1230160392609995,985408024602754529,44727668402979310,0:16636048945342015 +emod:20103166039699,5221451032884,543018728744286356,0:478895368134894537 +emod:87410236728907840,255693035925652,37882890299906,0:34530311513908 +emod:-302501648157631,240206529977,230243222283595,0:46069838353259 +emod:71032979947810,4416429704,2419723038477582,0:15218189462248 +emod:355188737187056,6605255426444793,75874689681,0:60034193666 +emod:6806384607660,60639456674,98209051459683,0:1432252996158 +emod:65303175086889,48887808654898,73427910350,0:4396384481 +emod:7752516269162058,62869883943828471,54774176016,0:2099905536 +emod:4326860229332706,2310571812316625763,54001071080,0:33511865496 +emod:6209542490007593568,8412972472856318,788629588235,0:362055759304 +emod:49913992353929542,2486110799,4585324963758433261,0:995513978680870140 +emod:349243489434121,6540085499657705,1389913007264228051,0:177284383643046305 +emod:375679038462457,2350871880932563,6382236922719413,0:6083733543560031 +emod:-30721033347396,77626742323874,523758275336801,0:84240020331255 +emod:5192099267362805,550370357942059,3061410194809,0:1707076237630 +emod:3546331202177649495,63420031374822,91402241031313,0:53901671764582 +emod:-79044395581,9116190241482576941,239200013057,0:188422584849 +emod:286354276465,8227634038665534,8044901060955,0:5958399217675 +emod:826012386295,49355018525,20566214354390,0:4083971754695 +emod:557522956445489849,32695219802913423753,6644227791725857,0:4886117301253388 +emod:-970081051547602,98172198401841564685,928763975802,0:22343542292 +emod:321415667027595,92728916953004350117,4993968573660723,0:2876297201989143 +emod:-8699136317926938091,34913749137460,747114775995,0:558798686791 +emod:-750347276056433413,65602570699247,72710009984856228277,0:105504442183260111 +emod:796490992759,979812498143888903,84011139142607244,0:27172815871253503 +emod:11599197279102044,36330854506634,5869662463842692,0:4784840887360516 +emod:-34727277565261165051,53891223619,2799195351079917048,0:2607666110843551325 +emod:36836705996677,91726402457474120970,787136088375328120,0:479138071357571209 +emod:786215427840767085,6538388351143408779,402285004679,0:145021397316 +emod:970294384045960,339246418487,392505811982975275,0:228766017656314150 +emod:346820606266075,751258033318226,999763369665239019738,0:843347570419357235431 +emod:5301442588198654136,6353479688437885432,36561155260520,0:30332565944536 +emod:-983848133889575,94515815574826812,64461274919837567,0:37200063729864517 +emod:1440437495907,707949003595768210252,773151956245425964025,0:534921841457783741126 +emod:9193524500595,90938893533,22068045096454773348,0:2946366481749712299 +emod:380288714663108486927,73556495897685,78844051786179,0:11766474674606 +emod:-26813489896157,716398856020,4739728890232268011,0:1219466999743008960 +emod:70217805755997,315269791230838613,7083375858304586,0:3059227926161215 +emod:-504603375916094,8554599200483,203113429839514225,0:156384813943715991 +emod:165732904527293745,925640726772320963,700604179708906,0:676451920881317 +emod:8166221848180,76217001334707,46983566031377519480,0:36926290142288602000 +emod:-709635175190425441750,1295562689422083413,78349035380937817045,0:39271509694798926445 +emod:-2183184852451752183835,379414486190148900,724528035479902191477,0:637578758017403897095 +emod:4238159883750584463888,7386606561456,5728437931813448,0:4306066978435024 +emod:1805409007202,743465586820332156,626695586336006980,0:577226884938331876 +emod:941901705860483,972657766381340158572,16833834708698,0:382737644745 +emod:36719313097210,86800505504547056103,565303478138221,0:473055435424504 +emod:-2666022326987011,3591998328200,40859674965133754,0:23789375408884171 +emod:7645153844358510457,209771482022016006,905933746892551078,0:296096846282298881 +emod:7851918408989360228,84734870178640245420,17989167921034697586,0:903417754686768694 +emod:46165799974266,2935049136348,8423621229264979968786,0:6706766736891832422390 +emod:546378248247723,8703795888148,20029030818332,0:13614240516425 +emod:811349021801350852565,48747346545449,8830100158031,0:5382741806069 +emod:885481101754677356504,7096462381701,455223655560834,0:43346926638854 +emod:-80474402802255,3514824850066,78159132039306813,0:54916880583163335 +emod:7131297407676,3315297183633054184085,934198951388076635723,0:651097991912957628236 +emod:12957689764990,546447634520927,3127766567382808,0:233348459584880 +emod:52914542138895536,376010137099253465,490953375293336830,0:36400103844339446 +emod:45685344805562074769093,61394436169997,80543985329602650474818,0:71110063880403297977149 +emod:-3761985423518632726760,956482080293262442007,25753912455108628113,0:8836130744460244129 +emod:80642483462801,144058405752215292120,106396321855736640702,0:8066898094483615543 +emod:529953061572415,79301418791778407635,92480175275263158380,0:39970833689504413995 +emod:74684906365344856040383,442523186603390862631,9182842638237756,0:8987946408749887 +emod:-71808994356961094403637,86526866467357,8474332396093731,0:2594467781892122 +emod:407234425686004311062,856447201531274,99637771372094,0:11888452937044 +emod:93295648386572486115412,25979074094596934000,83211005582689,0:77383113960508 +emod:9427365949717166,750902522043226813,9221846367078539073,0:7648128015969044021 +emod:92605054801073,5909052810075662,88928490696637500993,0:37110323432146043137 +emod:-82692010434673,814335630290109048818,53615009335053,0:46299654891349 +emod:45016205353589874668,95117600743459,2986728093611093895058,0:319442824024520549342 +emod:-47452361244427905002,7926505809295224807,3915672967969228,0:229192748539424 +emod:-2641799394644983,25158485319487,548355600533885000,0:46465320728116873 +emod:767992806236118220,58099104472634917573004,48648467500194542,0:23718576556107152 +emod:-85155145157549109,521405736695668,339367664853783,0:2173663047474 +emod:3109969578772647428011,22269815033051372764,91121430284940146293642,0:52586393883507723599717 +emod:504356843590479398148,4419882553863792022,9212984461142295,0:1998044953256529 +emod:-10529450854970073999,5289053916959379831,999122926156817831483980,0:128976265175682275841921 +emod:25251527460055267035,26387387620759906501,323214288066858358673,0:254793115154305799288 +emod:6257997874497129340,9035751438224410218,1608008778482293,0:444618779310887 +emod:-9314563912100585682096,5935830113611844768083,947452458146468426,0:907834316089122654 +emod:3164647012237657886390,72243936723121379261,8112420611117792966,0:6801353756302558894 +emod:908809580547671,11401194426509342,3883128241166899713060,0:688491805461764918101 +emod:829435256639678,469855084024947,237050421425357196,0:185926450835794340 +emod:-193452572186083034,763665077760046967,629827785597782,0:574275231643438 +emod:7638580239647112236,383888251385090059747,356384740003525821086,0:304972626268345366750 +emod:-72910784081163807426,4623502102569648619,293471055432367196531956,0:13722886778137743252076 +emod:156391592094203189804337,180577077123580,281066969751444,0:219820379090949 +emod:93982143896834595,99254856446162105637797,82935001019817754026,0:28907883734889605835 +emod:82453615072254173,9862903307325418383,569773975023302632076,0:311001760399812937577 +emod:3599043000903587396023,1768639534098606,38013039729215754,0:1079943278228851 +emod:863869462578254620,414856952917501776,32810489269754337315502,0:30667070092013729127996 +emod:-67081501875735917569336,2248358004479895344546,812436139390882,0:530577288676906 +emod:-932875447143221697244421,22884241204983991,156603178117421124,0:5900450340225199 +emod:-4456681099810903468721166,99859000729568447523,4675399066130721,0:113161030847184 +emod:-843621806462466979,168009327704701836752481,10448286951664808938217,0:2076672088394686331297 +emod:4833390360325487794744,8202438083226798875527459,271225323310380890,0:109131151997473424 +emod:657374545071472745,615300564202736701004,50439174668838374,0:15625484688443795 +emod:334093752354839787827005,401544420239962514,99419641355758954494574,0:38382862135390739723851 +emod:156986963896657756211092,9173759581769093378967163,8482190150813633225,0:846371056378442363 +emod:1965032331757601512,642865979115343140209,9373512589399604415598947,0:7634824208068996776380749 +emod:-884974536295232799227800,81559669471762219,77787068435634953,0:63000181811454420 +emod:2100689836805842766786405,3628560134433649198454,34727948234158164340523,0:13219112123623843462414 +emod:204578349882954931508,882862780583656098107,571211084473029381559,0:187547454428552727366 +emod:35013594249255180219043301,910526477139765124,281006281284018940,0:134109664959487161 +emod:-467870778338402348427,54493035145105123686,5912947085723132571998682,0:1228965263004421246389831 +emod:94103148636604290205719396,6986083069335320780020283,858637669487264716206825,0:855205440944993038852461 +emod:9132908171171712697673,41809905452128490,174186492804184908063,0:154317930053007308485 +emod:7763434019228270224295,2502174946472481,71917943549435776979260745,0:6076366391198365677016715 +emod:-624036880788622535703082,608930212992798754,7235811042721337412628,0:1325308214356957324816 +emod:41112778559515327410738,82601330734126683,389247780403397923,0:182819510299862932 +emod:-647553347892336647456803,634286301340932198340,4512267124852163233,0:4111852157418352314 +emod:79428691080290217,198093832523396251835,150772939563126693976322,0:36470696123667183989883 +emod:6751000393418867022,67240075486544827,663245235329581121676,0:362034082749896584032 +emod:57296278532026543994019,519712307129820052877,663606606885427005,0:297293712817608939 +emod:531634944201680433,69864774974090600,96423733207237312620797,0:20862933415144438574915 +emod:4605715778913218047806,7769596422373325424743519,563574411491581221,0:123599395766971416 +emod:910034907691723750329932,17528561702379847624714,7515500539229911873279,0:6808962399448284143279 +emod:61052317026574460778685340,77880774451137672778485,69232824274358824169,0:51811780816940817487 +emod:7504746423220767824904370,1945066924906518322,80909556817814270662793,0:22566971663084142719867 +emod:929639344035642594793369698,3240062063297979069920119,850413690404585997068724106,0:175349368401050551985442488 +emod:-55736601709440224634358,811055227679722468934466,1713909333328494414590,0:1152624446078802914104 +emod:-1356054913265870994230220,28314681428333792392,42265180710762324353,0:34292912442229873713 +emod:795295333902960419,8481745029583236616,343155151194196011568598680,0:313527770347784158498537041 +emod:2432870569967522452,48595187151195492,378387522780739724,0:233064959084707632 +emod:6831853307491550923094341,4409540435311149052023,91972635448121089016,0:52155803105308856869 +emod:99769909628484709088680438,668486550259622211760148794,99625276554619484105,0:10139590869737725659 +emod:5889039212181347754641685,676061753141375585943062606,776941837814809562309,0:443449450881823633972 +emod:479351744822383002190971448,468173515469111051509,167960102357712774,0:66373795292168212 +emod:373219776743647759815237747,78249029163204510445,237186840834301611953,0:93966418449839408977 +emod:548375816882114508561323746,896053512213126651537,4677386569405408164,0:4478771625586068820 +emod:543601581214625935,1432960291544699189690679,924713807666487815493709763,0:862081075000207249513732210 +emod:1726232497710046755875742,5018298664228901655980708,7598365887065911342569,0:4962214251289027951290 +emod:9940521109172176165804017,4735918364128985502,350872142370229985,0:77630482962237299 +emod:935844817555228747927989470,350944095522512127242,825141475757917666304,0:534643899908921707520 +emod:2636017152603937585811,88011950079842198071310,5957119762224240516059563,0:2064861372547160647113440 +emod:459469197042596126,604919581582116554623882,89801712022876493637,0:68195913281093479378 +emod:4677369076208454967820890632,13495127487606866501768,951687217731413972141,0:425940812723542345395 +emod:1566835275008318146,21867518155515654397956,7894931071725936607844864896,0:5253224487355519414221016704 +emod:3095066120724771665597351,7840426399106867615329405,705258460541720096620295,0:414423194663820488096331 +emod:91875762895950687211242590,6694585759057681706987,7365408657949985936,0:4938741305415608976 +emod:443023899338514715234998,24793081831491994199,24949681672266832443634,0:22293819994495988487874 +emod:8441986070029128775,997522126456942441153610,11266967419294676193463,0:4453548841469958625938 +emod:295284416391225922343593,3617280519422675857505683400,14967809405365615010815,0:7477177024743894714751 +emod:2748651151308839006,37444237944901366482969738,351048919067619839,0:320910471543612655 +emod:-856968271079561907778735,54979731653719035309,13976862935818813774447156,0:9945835571304601097054109 +emod:-3585077692884519189,1798930632211469960587972,70639908743442539388,0:23667983555955792981 +emod:6524605456430450605,56279387249888817212050,3814442499042852567,0:1145383276626865816 +emod:85234961390603945529096,75018358449394308437641627,12556653126866666115633914,0:5730557471924420585444024 +emod:2456775653742592876022454990,3560359960250729589724528,66846897799509249930222618344,0:17148877353421047482932486912 +emod:60282271857634247950,2052963624811178191751039152,906040428126999262088429727,0:32620681800129303136189897 +emod:54070246300857636559309,22183829543621704345694286,197786250025515478569975,0:12804855038900748642766 +emod:9617136486380916397202,4126846760685727322075123,78146300710034615866,0:51417588230377161780 +emod:62448246499005815495980,271071921688103354259,84492924742872826420211992495,0:66230579346601533104993148070 +emod:291386580832558654322705,764558287307875268927802656,447484733675418860019,0:11605899890452215403 +emod:32205011691602629984379183426,29358614276116380282,907702927282762504936328,0:643210659902127157683712 +emod:432494591994967547828093,358695607350358964677676,38957308299840969040967042,0:16197996155411494418456541 +emod:62528660927816817311355639978,47252461860428008289625225,6282175389133291127280,0:3555910613503639333728 +emod:-7614434286778285473167,474945456781970658327,621222471994372349220,0:549700448153054416597 +emod:311184079845536545337250910,9227029559805107004632726,52006471030183808566923631,0:25043301259244786049173911 +emod:3230868170439410850659865082,898186274112724548080138325,97707512380767417641,0:86932054306036765096 +emod:834011756636699109536519415,655009820336167759334332874,6890219519286864975018117944,0:2569215046679239758839951841 +emod:92892177448912750218,741399635351000593290121,624016777142908239971157,0:25136877523502693125494 +emod:836992515247957659739610,2583612763764193545264,1174519855635794829842116895,0:750264993625612676826364480 +emod:320791582460540931132160011,677439026930118779930468052,7415527559007185772557,0:6931004685726629652067 +emod:101060981222042386397,835069990698118657833498051093,304411313271626308269946786609,0:285961239724909691347928816210 +emod:-9581797085167617798550,69848378277411149359046,669942888182689235848827883504,0:254947621159139967003748108640 +emod:-94964174425453007033,714714872860590256160828941,146992630364320648886162567,0:112947428019587305836657677 +emod:490519145948557684335954,9081227005048911779923546,22555674763700463167272317713,0:5273066867735076907883920377 +emod:1222395170293635119614342,198182065457378753800,396502033389928296562225041686,0:76278932978086825000656068226 +emod:51847702997938374834482757925,65476864639254697225873266265,9982159563202907510238115896,0:520589670319457135074666741 +emod:444956279289663791215,101406862272274292233509,2521187648951207508813886007,0:1270796539216569834626269783 +emod:241755197289597987901,2982588579376062144566419683,46590075624035346402027176400,0:2234222576652608430033640501 +emod:30298268536110439415,5662223601814697342044103898,1675333306953772484178502284,0:956756379448476070508796445 +emod:9243876208586685329510289,358317687877159897071845946358,23373687043380292463158517976,0:18143528811380542759393916529 +emod:23933345236350049832324943731,1463874466227132752562758546,30285509683054247993598313,0:22909785183159204540182817 +emod:8232014647356048136737851,23114731717567737971387,5589633642881113626832,0:4835838093570844807475 +emod:1572721001930467120310,32884392623150618360081,127189088301879894538319,0:56473705512662665317934 +emod:-6309990340663959494270231,54301230262284516360861,714321021064688153899314430099,0:84913950012890099224323844767 +emod:724404836134898298450826978,79473347677565218701802220,85097228863562935294353,0:23425975598985124017685 +emod:1248615504830621338524,4939277515828927242493219,856480994935389549295086483,0:208559579900786673941630403 +emod:71694075133584459673485423,491471707800513684058387625,57613309973036459402620201485,0:9334604736522066347584171098 +emod:487205142874162363228855132,32170196309678727121574378501,2365947677964956706238797837018,0:1460443051085803997813915083462 +emod:10498793931533837751986544,83121914354650984352606,84780501352556446964608987,0:2663500197542495228867200 +emod:858271416618515546128946278,461548172771122263789060099,290346398222664413963288252,0:199454897909502042282033164 +emod:194961196331029028416806,3010397360933184988474874531100,8894255215761028137154900,0:4725434487338660122833576 +emod:406136918536976813980235355,373377808309891123266509790,8051548562083247464877013,0:6712616553296291113074471 +emod:-2530001401510124123338044,9596531290218038290076321444660,94617861891432411698686664,0:82720940727488645909580144 +emod:962341019433102549599309756,87959647015007020857271,4814935972310202770646,0:1937702586166074196292 +emod:-9481051936536536822112378933,19198535394666739186712937,381277436963458897720268488253,0:221821071935200208681658632115 +emod:188158462154750488255090,5147960444849946425093800,557834326930177732304779,0:535548855861651576845189 +emod:320937896085553144086178,691095750038113040331093041,26671339372282533818130976644,0:16304271928904332907031077440 +emod:6459406930432717296751,26393034277242496542604,95792580547993865659473661096,0:16263747513649826536284379625 +emod:-3955284617135866036386266,88955985063356610183176901,47993723273921407452861564818084,0:36345079468314192494573668280420 +emod:4469223387855120286647143627227,112486512731974346137499409882,674951744546236842962508833599,0:263941892665547640864795291242 +emod:5842180236545542508010186,3813995676143309308292843196544,419290459505201296652777,0:194534437035210733745993 +emod:52508914199335388219666638736,609717218258403246894120563,365684533154366812172288342,0:306118597360054606711715756 +emod:5797432698581273588431858,441479045571067025706603688,282607387577967901654384422862,0:110229077503714060775972506150 +emod:65328925252943246789191171238484,96713927150618911532802278,22277460692198085977483518,0:7608494060818884444883860 +emod:-3505111910190253821104955721,8184864474744270904051127420,194419774575051270128492444,0:162992788664326488651926473 +emod:-604067818162739797934946139,9043516039569227564714121728292,7767059317109793197108173473745,0:6948009587818483763849064344026 +emod:7754422959972636616784266184,659289209085822436564762,8509024996912387887787842,0:2665536004048450967780290 +emod:36416867151518840487645460967878,844372541160118666333682064,952635585495157217378104,0:851359968458957942741896 +emod:6507853401807441673041800837243,34718667350062293363755353,5468669123427020938108147,0:4716020318197938412234249 +emod:51211857820907905381543,77515986228844405658622,52805031690609904659313514144,0:46181146040418002449595796465 +emod:-3481005717923100913496633,72515117151236778732398780112,164464215085523994586779407667,0:110489875791376642480427623726 +emod:9727520131157808840831645280,924001182352699721614717943074,93954856739560714418171822477006,0:53602981268650203244797808464888 +emod:6268799672425688143953868,65752004602477767685988190527369,919519002172663755283332370,0:743721248544699996778206728 +emod:217255430663108140697379866,5639408060368994877725872115390,827864622867155990409562324662297,0:346888052171315931113255266057390 +emod:9584126703131986575758741162,32590496648447908561813496450,160498103515332847853363,0:53968810450556766053341 +emod:-76826728747216724677957902631,961349485758023144791477276257,137367232300949721808331182,0:4959768054309457695928319 +emod:62055398452252367690310080057082,129229535556008217119353115725686,9981426678099891826285608,0:805998125116661384829888 +emod:202510417400115156940889305598,15341206726182593212766128,996183974088677690094216724625421,0:817289450583828545947664474415931 +emod:-25516453293605744322947001163,5071219340735886356369047,602175104818483716891162778987,0:411839702152622861532714876139 +emod:993183387816460492640272,1614311327330565172683092096222,497972804217752566422039,0:494226915046684056423589 +emod:-139458968709342780820670342293,84079268451086347933669527964491,7982294793121272710766231686742,0:4200752285053689019247323342313 +emod:-642079420338207037888590791886,5097585020105759079603894,1749318042304737154855400042,0:202512538887870570156602468 +emod:526399148116041173415852373,940696687718156710488520497,50662078590094962860547244145,0:45895605101830456875539711113 +emod:8906813754152277992921404,80888477226023092123029527,13570789641532548676576422141690,0:11991254102988651371230177697914 +emod:93310258111859031487846046,779504595719824871139074,2316452607286039459212508186835,0:1841260888091242285457152387296 +emod:90444057415261195182482901256,534224787389163242275249003871,5364056042511354002232797243,0:2973840956442065396692091111 +emod:3159667409620907467186412,992919840843965860035887,83366646442680814563981888244,0:48427633954764114194397665660 +emod:99320619586506347666588920440,4405632885227428882941735745,19542923441973303902244764,0:2496404967738009049373508 +emod:80097846201870647655651438569,7478823295278459690728990,760398924078893349243418019,0:626123454565827223374998274 +emod:-617776158199232099295079230176249,968254047400958548769181004211204,44388668787389960907543,0:12309724362933796108087 +emod:1941484805465095241888868932546,28318560596248215297413369,78732478295542770828847418,0:11323556200622810322816682 +emod:6902476729554822701916716,82251167994228841481066017,35882713885308531026666821,0:34780023777540678364801405 +emod:5062468746465213498385560089,8136268100978763412711554289,68866609367366454712369109,0:44871781917238275621305468 +emod:88628634209852159542629660518,9900653566206690096097393485358,5146762817312746650783957833123075,0:1130545067675413155892767251194249 +emod:4183039741492584407492357481,978182783653208012914682683,64655693200972774031969126,0:5025716145757911119761805 +emod:5009607688574515313104324,2147563655528822623340385945,6236086785233460500733859,0:1405104917101339899753318 +emod:936982273588401762969515216739112,973707182278032902057390292,1894889840757299574823297466,0:1186002927649083815020840328 +emod:-979316518105993608150102623315,2370209457844401593122209941555,54428721194110089109350854,0:26913462600141970364018171 +emod:-5655018125941779786582905,17920278334613052052585561795,924138192567854018477877769509401,0:61476589026820682320306888608974 +emod:84489372498470137649774035034,7109018035481124695636450,5797230889810299281193349634019,0:5612051483938131301074837863677 +emod:107426142087823893785249225,5226421952107015855967156538,834564679898397955796242150,0:374409797926018190303172625 +emod:157094343256569268019396107347412,3363666015878047053403499712,3077292378832241991737688300,0:2345199073898407378386288256 +emod:4599347793505224871406391916492561,10349753756389543100648649,65816642199331170025417801554157,0:24079921356378393197992579532100 +emod:847167595799527189060120024265075,9107386461422683351260870279493410,92958250555849386269043855,0:35153939443890825069457375 +emod:-1191675132738936968619514,74950542877141809186776499,30939415755921402575464055877087805,0:17053440194220346967773901128643571 +emod:-6782161375037252568833831731,21588926184031614794842404042439,87384900356318490043390649044683,0:78411924985423842001255202388041 +emod:725370238412744340662463645,801132128288180827454102757582711,620855082501145881156782549,0:359871609759550116946514648 +emod:-874379189856445894179721337013,990125527305844856332150787749081,8231539277268138641840413167,0:2289484932966836920485418470 +emod:-83008902474732975330921978226,82794210686607729439615194829247,147791999288202013476656713406,0:146693025926271847405525671222 +emod:993041496775769783771922013177,652198618560534787722679399482,14725280081827750297488969316270418,0:12116281278492392720710544362298223 +emod:46622323497579971935863115,394817683428792448650089831981,275712081411878292477481334593,0:158697271488808580622506705623 +emod:-3898794108935715830804259645307545,8539310275091037665015112113,410028214486245399572630623,0:154269296324614984783868211 +emod:79671715478701846571943769152118,50747562547703106180109929449357,4023635598183808950664694822818865,0:1391680419606609518497878438964728 +emod:559336542916921480977013076660,3500214095929566980492663465,336757157474053361967887529292827,0:205213355551911588287255669283398 +emod:67082036968759143737139839,523004801838061152155611054,471652207874138548702202353,0:106442966546624668524597821 +emod:-3256665451209505423898886159916,59781980277755911367047005074,91129573344353344374535568122224243,0:32050945513189163759638087657164892 +emod:421990276114311172439204299235,35826815490436606511044043492,15446384327646373190492730438585,0:9198468415514629536422965781785 +emod:44343136069714981893949445602918,74625812833376942712384866,8553344812866281257132806310141,0:5783836105657448834498697176854 +emod:-3350599651069474402466963632288428,111533243609492247217520718860965,19776907108357809938962249484450996,0:8355570250148181808922442971171888 +emod:1174811337592368749244214511251994,42091803705746744966101838336617,845309015023334575607631339,0:328886787862996931441907071 +emod:-29148586556051713564217625193,68513553022673456091977636318,517234274741375130441484814600195366,0:261242636773611113876824326123905043 +emod:6504167945767766564692832116,79109138160593227576416337070705,859309929776480635814520707,0:653461697201929229418946370 +emod:93782137244393346713836734,79816233695566241785503895940612,47212904918142268923262812947,0:35930841356748083688108060545 +emod:-481374015950451874599738760,971500384056236606682756504,449203445432063323041956755151715073,0:326479696526020517109710611255112326 +emod:33975864000889551938267169,96711853837688512196605358270819,1078256621965966374431724388,0:90992844234742791085579521 +emod:108501037609635132976961872036788203,6219795372158712553653962311654,8716372274939376496374246159612450,0:46493029021502557862865275214619 +emod:-2231157093133343418986538244814994,83376994288776233556841533573723558,947070007417842767887988323,0:569695285035798211404990578 +emod:4320183260196502618997084267,41119367893002798881298799670088,928548312561033253354469301,0:685331663284665282972257551 +emod:989219761371718106548064391401720215,746254976033978038152730412247975,899234555824809502131806801683692,0:353153945728216728164717147859487 +emod:70249906941776493080760539479,449610892140392817236359849962857788,4178349342228788164226432276235,0:1335233721704565001505221772011 +emod:545502797337663151341732385037258,90145671428166124528612984500230,65353209667979259637734612828610332,0:56057131907461848190987965655332892 +emod:70201665323655856669206321215,82151238444466709049154516320141984,720986595714891193688614781,0:434647021965056085408831563 +emod:421198830106569057199561575692,1004609557346343726386068926525410,633868114840728850333551602744,0:604704399006232077090793233120 +emod:4615256370681079013157800020325,8400414787259268709004735030130,44141279558739534891246414484563077,0:18767312155202497589136865119303869 +emod:51901922040540262359036981493,66541229620660433942048401110186352,604842069438884017503376380377487,0:560241581983999804968823332813883 +emod:865876649476766227336308707540,54523494380158570191694786271952,30189625477183041262303690798037,0:5517799863814849137124453024505 +emod:540104790337412628896589738918163962,25517420734892235958218943479822962,516223444101948157559494280688,0:285444604149225295822139831184 +emod:-120865564927993207924741653485624,913588382476805140812832387555144,5292849031978636063718154558956,0:379625045854381376013487318700 +emod:70630316045710645831137056416098,472369686133234789698150515963,59384539168300629700324758824,0:15022806530946436030583838784 +emod:3922428518882665203875466914597759,68182625456652248599363364893901806,6502711284299228524855233028593,0:2808475877330758629142848372619 +emod:-767906197466320392395972570845,5881247518778543233940000315537304,287419172400279725552523866012,0:208494064792679452780358308329 +emod:-183473058607238695125794649,5195900726421669056563048427,4401632354842192930996857262,0:4089525058119677938261594431 +emod:165422203258159204617067246120,96059662222900813086080021260,42765970916596985181285425013,0:3450069033793034400281980621 +emod:-6202976578952904184671995477658,2047878587371155342936292231391653173,638007817147957433105556793060,0:264771935095789602347821114292 +emod:5715510499720116696692085743763,585913772675513473362454296932,1051092429534137447273592584087,0:682705608964805508054206642997 +emod:8554351601263637934780353184462472,2234206121089089275957949179,718140465388982120919431110935367,0:184669837268894201543573681894661 +emod:80692144241982166867606755367641125,2849616930185309069767665166,23879511236239108118965785436012,0:20523073803895280124615325144457 +emod:99791107145824395590258329666,325370594025067544378522706736314,96399847267939282102767305772251127,0:2325174100015879854256600082049436 +emod:4159932940100685089115794076141116759,23990995412460118678564628973765928,80832081463108433977538716243727639946,0:67527463845329678499612133471786203313 +emod:788157166896159069390966287243419,1486322813809144772467638907874658537,891915835907995407210370317163200,0:102062258185041646930644428900539 +emod:39482400163217130341378273663281863,5988616246240813543901974803730,5233286401955663097666421133559,0:1266706417570788723251682663891 +emod:37283395352033119876301598293239416669,13544410706066077917137340119619527,90922298984492607133074207595203967287,0:29635409004691233225521023456097882412 +emod:997092394433838709995127446401,945171627926561384468473783312841500,810366180441978415788967038942786,0:208268256396490525163362174178287 +emod:8028402014609956835909160326346782,26557618265296731376128156126,460114218338498016675422156130523617,0:57220159633664593786040042202487645 +emod:82562576995621135938138768719119421725,80752496992618170687901372956534626,1448566551160810322268830690053691854,0:646521647376500058682612093836622553 +emod:85548648520427764614796522518452921164,89651898605887779463577396538675594569,65124148378449835470532787649213,0:40497439208050142443242215136607 +emod:16837336872939465286295768414551331,569935780141651744430445423490,8783437523930110362354247602517607,0:2046943362901310534745130604075491 +emod:-4440812678686390091523604851953175,389451017692789149570538026068781,1428843786528259273557255613906046765,0:1080150304658630116675444179316296480 +emod:967128946679209456313061694178754547,71927999075234140765964350500643464922,5912388198893179472569863818550882,0:519919011257421171091112245394593 +emod:50956630538253741318888787410839027467,7254477767965547955941480470459567,615206000459040658792942579937518,0:553679691619602644270040205425927 +emod:3275455955848771032620932860648810050,31488699805619979770222331680514,80458424575688534547636632889962148887,0:6244384826050692991633033848953781669 +emod:-21389208725934970402070480138,83394267330366428453791161248271,435867681437150310057862989648368134,0:48165848424304409414740281589776608 +emod:85613012922122238849286197885966265,6264623415046666744379998032348811600,4673861359129062110917409479097,0:922666804172116833801730611634 +emod:280083488936332437588802230890313578923,244124978249612335794064534642,2375736859306949519167609169171687,0:551623669267415869843380453511910 +emod:781188309374419725364720820335533,135014953285485878049171718509399492969,344084387156056462159513838518,0:106507543249649319840719909431 +emod:98561799065473561371563615410812461706,9134726040214334897451541211570930222,77036158481210325032314040316433349581,0:10604005574133189996015761603720044688 +emod:5834647121579885467217130407763503632,200264652092134485478998460165283,49796811768811795244403981652327326,0:12616757208278628842077030859699158 +emod:7156274802094801607862890235975,298547310278869882278519047422,3385164957713213782961023671150442537,0:2365150345459624684113261880718766685 +emod:79536547656264208689393334480936544,8321385671827825288762542280445,785140248493770428377830327387,0:667723641201713821468357364660 +emod:2401918006460405664310271707131,7938856973411329632754746333467451353,50252536011125420227927790886850,0:2560962372344356633910159134191 +emod:-640484386299773856766873434498216561663,521312377097674590222482921347754,2076627816299488817471309926917653,0:1044102083342050524913059924893882 +emod:45733835810902836305620972021854492,637659651938075050952475958589,780295381235534049283047240996085162,0:356302494046578600997282893502520224 +emod:-705304982613296623295125876847640,664590498867602222651797274067257719868,7499703984527131597058855628260006298,0:4482230223758031512649996652730841066 +emod:9684252440964253807141800312433763,190043365382656690493696042245955707225,3095261211042298242370348907837021107,0:2250643148518714515189768690498752024 +emod:-89032437425480643935967748757354416,621983182028088553431259572347916435410,38079815655996180160875323024441762,0:32643143118487494012451637529005930 +emod:6548447424813914775693159183257,65121910212312442407559411924073,985538984256472333797587014404581436986,0:740155433087747455737389029181370989287 +emod:4289065821289287300568064096399722,9121623380688074176040884046612007916,961296580001696582058791225882,0:45381992080327999853100134788 +emod:-72973996651785334626703541251510,851343162677051554053312177517930014,11415255076241129984914658151314087,0:11296475116822862530646104043954143 +emod:6215781314311141827082903466280283111,82690774957918159004435315373320417,27716342728984668538238211473421,0:2433474471136329719554510283452 +emod:39290925538924182292886302889784,3013982337030112395184480691476,2874832168405952076336884530324927723027,0:2409837907629149262138096279585792264660 +emod:9277827192686619891057091530556789562,96429757152650874683611007657644,4535029359155968493194223758827,0:3867452547234619026743402511805 +emod:5694258184281411312360339289572762440841,7178050879307469422753687401052115032679,9753293426594405370122100566371326332981,0:1459323522232121155703484803621777382578 +emod:2631708872518347779478401470159636,69245107191231315124801771805922519,5376563717710166640876235141463100221,0:1586930529708153725166340638954835393 +emod:-532822740296211412518831858845632,40668524195320929579193193936667373,505606545836126920558776593155866029,0:421534471253420106860659063178492972 +emod:-18119290713835899269532794976004002911,37879676757802798170292588489563693,51891136935808235992985547250049168,0:14815387892201994526759362316856817 +emod:944625015888233591695043379987489,7693259777885983120642487312415887,3163174379156957158184811373016,0:868511369288625949950763838225 +emod:-8261719628034460466290601450600373559914,269611237440354291239517315110858,799350125207208117394870062241902513223,0:399235834451270298186875260990350588241 +emod:79473780570881594097438192951192117314,7169647683642226403729056378024586066648,22954171389461145428057650940743,0:2168846776879932971592555333531 +emod:95869904428201135413560110749448802753,158340104707707507507946829328121,90984891161322604272382067470532492205,0:5924564037970417636455059119103926748 +emod:-22521492621302175192658392780275102359,7693302694515406325578226762983037994984,782722878640118008162156430550954718,0:119815974456412544146474518425004437 +emod:9963842744602755276656167034564168,48412659540989981271789655274768,43293723041754769021056672485976,0:38945698446931926733887929540536 +emod:1320877778921077387166182925462256771230,57630920609252345178704453175970,3193372771615772702336566528721798637962,0:788819527153114047491271244519182772544 +emod:668849032341201560206891871233861747403,888433768055712910244091518751770,267361236110795236214710559012632439586,0:155637798445501597369455066609821901151 +emod:6512075833061087798080551616254563514,32092556887038243782172094249883515187,7726674502992997466882017926352963171,0:3997773747495074686605793565307898133 +emod:175331741086869721483946575985451578,498971069791965179508784120214414266,36153226259659293800129850353069792,0:11517636272100517299763240352733600 +emod:-677346278108428877376669412246870,9122326662016035239584815083992070495176,8466447950617025601185822550216037750,0:7996073485764019141592014511479503500 +emod:3004006376153998272508651886671867319,89420637491378914617711759949193596,94841662569213792123219861089357581,0:91022466232802632841224039771245469 +emod:141963083020862928745284661527006268743,1094074097142911406442396572480839364679,14372416626149499532166554918559602886813,0:10501331757552726404117414997172439332093 +emod:3537251641169958447429792087940591841,85312557100182485395003016294806105,4933954336062823716515388316534139210277,0:1264190504163163061419402586060377117556 +emod:7613372643252414055043698859413975454452,8104856536803203203690055640315246210,22350828251203871238906729812254148392345,0:13852329926953072565535594189985589893489 +emod:5496200720802281470038810856743043086,13398984382633586073486065955736662183,79312825247526611330966937485082122,0:66661235819185738734811419475614276 +emod:63918543446915084085082601250202595579,8493763746998771444323258554325712411,4937677683346782838292257801829180799,0:3333170338194997537460486316124046513 +emod:36261747289234573444167038136694149416,2349120291543932920428306772143,686686391823818082220818261012540,0:264297913952895694560131373515156 +emod:91704684660004985825508358858995087038874,2015370309491008506921827067333129594,9135792372038219712944984119888962386,0:4529804613575839287527481063380800506 +emod:30278645824646334826846693204541658068926,12818636001054407099890316510058892,7851583114283368731828210428552882985,0:5669753244104840595149054032720029076 +emod:2796270570869456261650857714163957,11563304674625187778126296571762555,6215093511413186796467390016946078,0:4670137082336559942534996304341551 +emod:768218963811498104890466470855528,87947819439418684675632728454831941,1973550877645428060151378123682620,0:441798238493938931699648323746568 +emod:-2428535063509936208105830667774640,3035965301290018588642321798578636,188189970059256072630697270059421551204,0:187579612082668219226020920724838998284 +emod:-68851281721881705328338599426899449637,61411216780529093075213667248360855790,762904049248955019330945036218634,0:462150975555814307044400024262763 +emod:50381922933536391983048133911745304,1327567537265931585748836565776184592881,802215654672213785119298527941754940929,0:390003904015432758428242187678591715653 +emod:529101440911633844520662940603032143,43786012747535262261511038179577399,511020742387225982022507255362265561978107,0:43144871536679970770284455068495104451271 +emod:-83888631215376392729015255508425419556,2987291005239618438509136686862070733775,961384311110037617113682300965438706,0:29648441889315953286284555584666926 +emod:-821196282249805910413962910577363,899754172277729178591041212333965173866,28634570307010794416106940080087125523,0:13173340434987909802210494442005883282 +emod:381631360270395672709101001383167564,5158459604313031569589122775835258400018,179977223820697561825527184706001338,0:90425662788930319644902518702187078 +emod:86931293242801082346374758755111010579020,2626551520446310376390615092828594222,938653251144169045231475456784193560847491,0:365195163429401966471156565576650759315955 +emod:571783539909088029876839939054322959996,3089568378114138198880587155086119890,2744081752554506253029969486161407282,0:1264543407557838374228627104087788028 +emod:-90886625513314511815555188570608546,51200053536142533814421471973168803,3158468647093861876601465341868309,0:2925547080612167963149993945191255 +emod:678603997120076532741658796530004849,43414916815768520427422498534418015,8716484032032480216675313011200057709,0:76319340105732892359044842900479950 +emod:612730541295585524235353860578447295001,22424302005854819986022320120713071951,173790728285176883772120949725911541084,0:137975127594893849412331247896142478137 +emod:13948884468878712500594129935211199120603,9383236477661484239823311361156037555,7150124390877159720608122766898971171111,0:5539575869437504207805443963399777689601 +emod:54492739252211246006137151994700249,67190668798711463919179422578016332737406,5016308665959551730292366483247498,0:4961979712444768037254544658761431 +emod:29680512164999518310606641453082247,1353001032424138907392467987475747589038,459082082784205465090366530024559,0:450480541453779074511769512964428 +emod:15403192267035685992492637058662708278079,691714738501419527821402660938221344683,7782687609483337882572886515961628752,0:7725198743465314962321221679530076511 +emod:126478593002688908873146865473634929634525,6358340236015836865079291052256775,642178072362342080585886203440168430935,0:218622928181521828894284595162507920145 +emod:13913359834837755549848482705915052266,903509443568563265008997239488312244,38405152518791040164077250979465916520,0:28518709836314856470772911348321435016 +emod:83931848804764686468764875474979982242,37231771700852953560669364821981996529,8064976106252567560098554617279771,0:3942705697569048252011335611766898 +emod:87898783621436420303252969787195069,967379407272322490869598290122854378588,601280977875708034746188580088928109,0:411325933760221674646671409872577059 +emod:-574877736091741275350898383808389927915699,594958545957868400560169903622579655897,4423949440914171636206327704817250586403446,0:3323591297752691954350870547829008827201931 +emod:124800993363976911520180513839889298395611,3963571144428060960568682938453332161723183,674078271234292330095446224557694423193,0:422135852569833954257620597634971621477 +emod:90777341202629209516486441959509025385211,33892788023206849882232725042383975802458,965834508749187083956638172933001579344,0:656580209956545000201526160758647431417 +emod:428177661658876831707141329481947688426,65730335739816729185618200604751902,5583905204611961380972834719217342953,0:1199936539591520430103110063283203324 +emod:7784166932835047133921651620293244411254,45683020890860577526532414749737728,8865546781759541156004910823031924045350,0:8781672808470559198269957754771904762286 +emod:-50974859063823766693159687850998551,4260289458698540774171384011548170301484,3075280497472455596559827351977048841679,0:640353521741095591912508608109444685750 +emod:-44302701915422822099105814706266768585326,352328336928075991743029118271328701469969,197750610229907539580754650086642390905,0:93246465784416858941838796225126642669 +emod:766771922418857228732717683752395675,53187483912419491901307730154421458430,92096091103428097138850170920718803085695,0:57565491053888594101424663327538976145125 +emod:52721172881006130419437464601359973583,52365059560631450286814267296264202147,498576604623229902884884195640797562,0:181571367769928285755960377087597847 +emod:-130061614640638992198273716595411981919,2346118145486800692560690336691790893,1645004080847919147880779643424152795003,0:465587055828660570780657181568452731225 +emod:307876682184042075642894436987556451604446,414568064245406529394828107789210339588896,477711345483924032017056685517738462284,0:109389690976160199299716512672430415312 +emod:5371610880889161920476163626282917268,671190145264797106864756436651734380622028,857741777438607646271321549114765205923350,0:287287981571642915909267131628181821120776 +emod:5204868302533203940801436297790593533332860,83487861479973096451480151041003379,71382668037578608278694683426146288,0:30832566835341111033409687661632112 +emod:556625156486454810659526673624620788538,4626440741141159394644754018141116454244,72891055350325059886351235380188925751695331,0:57282604851594939929936357788070706169855035 +emod:-89511300923170376817021029243002896666477,903721376056645176029730798837754904819,2013905533937026971053538084460982634236907,0:570791309010977172526727690555890004463372 +emod:69694851714973479181534773177163535244,386316471197222025887461600408882433030749,490469070636694229175921907889063586231473,0:427487689181588318519876546414273004996449 +emod:-588196597032453101052930493773379817093105,42480403111373035847406143062717911612705,4544690508644322943234886196205261164011,0:2047663912083358415178872122408088880103 +emod:18601385516319880347082113262021644716,353623982591699522702650394835799306077,882857015216699962449940196076317077670033,0:167450675786501647351135027234844843065181 +emod:8987750839863791535937648238891007778,4992783303820924306757780883007042021257,44078061546357456041964194188918599,0:7906772385757741707231672436897321 +emod:3066043816339025712845503823677606013,902933129598925384688189274201201551,9952994249589962222132861005360182224154,0:1174534817927019518079679504541484744197 +emod:-8621225450444798677120486482628514696,99155842760569961250514993113606863884,25114933437945893268599527258089494552599091,0:2901441178432592927100180880754049113544590 +emod:90281107710916849341198657251024115664365,754667850911713614499014770880887141334,30898295870918445141561498179371522917819,0:13951738483311575701788614225768771977539 +emod:-377295017128784286263228943698366029281236,815351785301111612401048321797886149066,29710296428625255526774084470011099286,0:16786657050746173886424618254498209594 +emod:90209342286956964721158878154317059477,1184109459781060213060226071584865744,30538892118817816797303238023509341587403,0:28384974665672321900008538327342162253338 +emod:-76207593117960738992003792949566245548142,85201520873038006008429375802296986890284067,9310049288843035339384905918862674083743,0:702354734188303284325632288622165913045 +emod:3050032614782701178357664755062786032,6801863531876714949028658176036217984466954,43950118108330216557290417378894698723105,0:39620291264605476263313200424175332570554 +emod:677773161150320527783770738001557704372,737402634272859936882908890962095194591840,6047292927355913043161167285175711434800,0:1483012736746464157045759924622953000576 +emod:42088022811917334978597559931011799497514,588319468481766273347382652716318465,741545598763153697103785060193676712330111,0:531456297231876059205154397650433936193557 +emod:687777305090023482357070950201516321450289,6133564983213467693779486826114552977,7627976248578721073068053781703769523841594,0:5843136042246311804421931194539413550947857 +emod:91512065672092684699107288546273626439473487,77707078677517557779288077287329555442145,77507839007463389547163721496077953290665164,0:38085531137788908878444542689408043701328043 +emod:212359500386820079595762158387084577,717033680869242497989232895502553209306,57994712116702439737072157729729872704610052,0:50129132851246790997550498079907544729976657 +emod:-825584369512058731518137754499088478179447156,1557907027924626933995813818185230430454,687117774891041750881385770197632894,0:469172376510748056891468208407987466 +emod:-637734412004053009388081157566315826855075,36476067391256503367264361488762844508,8901726487790531465993910110654847381,0:4608357665978022682117013835997146678 +emod:-54456151981942190750703318217840449704343130,99982993771652282608320462546135364960046,75503441196796803933415452275033785162139990,0:1100695159195786352512500747472823910559430 +emod:56697516355737268216190660504482018822,88504062521017516515948614320857837302,31042097144177216624878213666191323514,0:27351339735066170958422624002651576306 +emod:-98852251157147894938842540415683732209931823,1103039394658513749769074015498619281,7550633351197275605040420550766377478,0:5707985330709738472127894458871700507 +emod:852323466440811463681452434704718127867279,34051201027780798621123886995870064920,795262345784174548938737711612423959,0:548570523642232944065382365273044931 +emod:889194223622807557021642095643419375,97697994551840383739114494141322582209674192,70985658980570759747746606912921132003556472,0:54920500907444323447367511646922423261389401 +emod:-59429009735672945055727939898766153531198,3806951738924291817324705452300312658284621,90645462413613180896154498632105428944,0:8969737683089946972629350404791649984 +emod:-788749280314228561044345431332920373159,44015816904317649966556444126647542275202,81067964499763345132379481470512547700720528,0:421573413445326284503993935343886089184977 +emod:9008250476728385872623793527898989079,2093760923583615910781525258418818015395,84876061848991122343034995751598547888,0:60481132777467814904735222040023224935 +emod:7323424567945169155005613073259826377279633,5345346096429285612041846952680414187,7435331969248825511490730370379710920,0:5701245548135054050237139667347533017 +emod:51404894860307832493700969749859131586957518,9938875974899784631458092317153698579925696852,919124325203452723338865802119093445414631,0:581269944116304841135442821130730046480816 +emod:6976423617979510411465515007491044851,811899783025865657772563202580630898795428571,6842295935464600709869948911248187992875653,0:1463570911818405692736959800443272136874063 +emod:9244740154784184489624653851590988118413336333,74724797442153844622872240019401506034596,415430272200957807957520540642458327434814547,0:227245764253849571682827833616120828123015976 +emod:926378595873538467696967488061013453069,13726821339710674251825283897470743239,984332184269068978074654811562030364,0:366045593329883963651763814907781689 +emod:-2813562000424875340357193353899248540030,886165849336487766393906742230529958590960,2271217318347813010825877828107460187565073890,0:736934018978417266185885759728676558811563740 +emod:272054208241621617590554322826124010321,247618769151239284337079695008609818283496686,649481706449462881752315195565911763474,0:256814202110410998800134363843790671923 +emod:528587416597254711558479148286684876795995,56025560898493899721803630575638541012744107,9092163742836866873755879991932002700857700053,0:588768500717688902898041234316335534968163070 +emod:-36376510103909754880425141038180683008,697554526126494541279186939566773312469,7678019691033242250502480954454444789783096,0:5565390320666040024632809464519631265578088 +emod:27353070533528810361133250533207881585,454632738024798173419305392484295653512789,8645616700024063945147977100235060594126432,0:4587159063853018443969072957434344637693713 +emod:4564708845856171353601915371168338496301854853,7977961275571093400571875056194861455149,813927549830561854195243397042782008374,0:175995834338047549986610112197044992575 +emod:78175395789694647002168837493633590621186642,8578229500974640597201805617750253952058296,20420572460880064835714904978798146323419,0:13267874012653989247914000024945154331041 +emod:140750235074048885495514519935667682244,2119009829407208281675487240867001784,80904987806406684614200209335872193933373288,0:20538605766997209360435961966799813436662320 +emod:9887824160642886854268459508821295133,164654330601600177496087425862536885517,74733613066493027861988707350740433987311667,0:5362288908065092864439824122867646582501022 +emod:55287594962561555095068246083044803040880723,936954069289825306215654233135813117759441,745114678852371902761659303193044148784138736,0:290151193402965126922268234821385444873479187 +emod:49271627767039808526745187094137141719732,30065281370305611177302331797431914619013097,484472846194900484542233448660288882119501,0:458376187678161540698348417833456289330989 +emod:-33619977831470526307371048811162970364476,3021585613307372422202371415945287499364,41518376269473392058127463402457118308536,0:24307170522911035642636754257602979386776 +emod:-25382128605388905979122243374547045342,828302867171033162078210088228770176829233725,8266339347894794362758578546936481856264205,0:4167869286530376166812379465397611080036603 +emod:7806062802262727519367165518120421617547186762,51990474722372679127714742060768843445794,274591070028574724870239318997476790646356,0:180286762288683513660209941777027215969804 +emod:-14318350583742657677501199469782146645295,961806524953716379402040320560202880271077808,3687275580612869739753747169826129862213334399,0:2737868566562935158202389734126986146079719735 +emod:5760787392296885353944866764267524928758610,46155936499409386931117510358618192060334282485,9185503223984382023640943204999579979071680929,0:7506254742023345352482567480829597623259247559 +emod:758462979498659646336246209035644159621552,136635434728102133698904796510225702345660178,9498019876743551759329514429520428372065505605,0:5565366837043674646400082916150410306576873804 +emod:182033670937033200311127104143473575388632458,465202911160104863025573660937504913136,394894056005762580037702893386135121788,0:316367714111986031710088217259606247428 +emod:2632031473801519112928562274312812079466,2498635333283012493093325455044250943493,799862304047991036206572453520324334513,0:260071365955878514310663254591271630685 +emod:1021726135630824830413448736592392545545812,4431216689055888716659906849751643616246362757,595012854621587453243625735815790460446478875,0:506405473722516168522817128617260580471663667 +emod:-74647441813141773592808970599111638815902798,9458739990542641030328044128925695503721278,67632705274078858494220871541834514286,0:43860643833521638278988180954457097574 +emod:74347467735199697397903862391515976816,27228101096114329060763685814389121867,2329466465821059768201256128129347846,0:527826993612543999076744976068461088 +emod:70535640036795289071039498872891011642193,175763117977529697478928626604560680829675857,705090454888208372647565597170374314517,0:179091754275860670608755581507296361572 +emod:243670574841881773841146078165542230152996248,27224356467518163226383802462318164385847,52881980947180661815959615676455311403364453,0:6543936847510216013770565818083740841303302 +emod:-3063522500685962875075820880911603917,3092546229913230570432064938454622435247872,445936607970411171632403906819964092617858,0:244095099022673834362318413541677305006965 +emod:39258083183616152671542900110410755401440,89093980612505699952982513757457937212093,962271109020614661437340991578568879083263254,0:305927769953786743646130969214578455895721012 +emod:-898028156876410713010493580194881547802568137,51663960553269149619746641641026382469722494,88192102753654247658195333315719037577000020,0:85184597556224178158455641450790019451878649 +emod:420238670197853908213239792155799109438,56874184795237971698065659542105288066970508072,7039994314494472877016149904621158951181,0:4195556681277481820163873546402003983965 +emod:988537214014327037772289213676835383723493,513562354885152593212937649884550491754906560818,93157394660505505194821589054314827610053,0:12739336675286048975363676477920500556548 +emod:842740677032405514674303211263314042915529378,8831402402931313770942586028473722467913,682852291371107996249203176454681279672468752353,0:650699316446407153033148645266760437516984688808 +emod:825599814726370563248636889273016715133942454,475680601046386573129475547513603110412899,416247625434559948206627127417433632778118351,0:339574109914067304840079566026200464971617828 +emod:567648490639035833763803769141627245584615838614,50724317254941774744692403469242853096809,41148923802029037929684987081095814446741364,0:20502707948232123804215524099617477740021816 +emod:115087026829239549004467892483132444989997188,4535425742394168264586248943679679529149663,433955044135381795877250546954925503743568344878,0:251660326553696762196196778824084224173978677678 +emod:12036785909772650615373227006202901241216144834,7640930319417728873563211760140268194907,413484971952354004891213262066509431492,0:386239521261870781782143346233879040668 +emod:320557378119349288211730243419102961495,84587343773197883044120518369669143774565,450141050577587452674598657343574939265610,0:231814299231780092365918681959558354516555 +emod:4760513985682144284402040197893582245744274,700922306891278320888270773879393663215011878,508613578824050038059978191899173905936352067,0:226155180059930658457926847583608180369805551 +emod:-1986722625420716592016545661236480979772,6587808211180976790034063002169935351319078136,248018664573312581284613240553608321163,0:47757498985820966232985385469724481611 +emod:878958607745362254467126051915110114983,76503615843648834046772312529145734419,599816542297740804095006213529020435923894574,0:250411227594713677669720417184781499038401385 +emod:842403714056568268363014451655139215576923530245,882962407685597232301145770370705099374,82560775215139790378071910956865546821689,0:16330945270987575660257305978980256916947 +emod:34552684591792222791353473595987201905919750508,212190283105668244835487282221966055090390808214,911560266007572327824644939132754269623196,0:375847062861355613267496115505135609589744 +emod:-255595855064966654171339977100486303810714342893,6536377115945497812146512349336490454281691,2358447779128139560919507162522654854246713,0:464809906345666089854305504087451343505919 +emod:18482506274556543305894610082680844279454,209945312016600815281820143389332478519181,699102020350956658786203685996030350661513312761,0:72242030557111920456295390210910475158413094888 +emod:6415210528618065990871168801815200139332991888,597649022838328236100124856044642774484278,7231830016713662975924622826283198323690910,0:4006117305107713700741948795422083910788724 +emod:6064555073982428831750221623690023330296876,92735364529176955551691773164814148521984,57696657922579845113546414118019201058924665,0:6870916878745310102921277390541323644461026 +emod:9386717595978609521086313430321645886736486585691,1936977561716961194789196774828364291100085,308710514484691606827023276042134027471318,0:55355445075743293412821307947169157597655 +emod:853095304936028332312865139673151355180032547,402516533127912932547366145735034332969264851347,3612211333648128600921169717824883676314264487,0:1447874577344295276390988945761876053311260753 +emod:61856527307782794639480931649487570761759,981353953577921813238706114977389364158181496476,2875727585132422327960555829952850177070241,0:501562823449987389919037987877783485624875 +emod:-3267284769511763375166288313542521834448737,75871983689910147433442901613935364192726737,598080070299105299737322321312252319973858,0:412778730998143883082550011380441775883929 +emod:405422539092856845025942882047354831627260512213,1337913948299733086787799108945523111815394227,36305189460456946509918912104812255759867575,0:30995366858217213552892783895317137044496967 +emod:6960366366888598610646870748629752920549287367,39434037540809306957325491962655662351828,3736135718526702463297936582263494485512861834479,0:2992479585704247653816936018623391133511705239998 +emod:-1826866256845184317995843519306378742885,6087838149038632125552666538607155530202455862,3505196452565303635830882879536478893015661284510,0:2876258092163187750168292253816666759927848105405 +emod:-30453880527433344036376413763327782174850922,958106051241874716971554801010144468715392785302,83704796154657119123303823148452214065244,0:12172291368658411466771610032308050809112 +emod:-356428887897712690551027940776016664193551,974311528436818547612106283639362895440535373,4175822946282741428795690626208558273399181,0:2217100635742324748464089855768646097870944 +emod:15887850640158985382379829997884660521441664,3279446731722646638040158087688724381294988413421,52724586555424276758984551014477985909146482,0:35842723031112195508473058690940883109069966 +emod:-2754358773916450393380020466377500694537892748,6693196828758606502929005505195902945008422,81987501340134124186844933306300364101202601696,0:64957670918930713389913976423032686263311873504 +emod:64795655511571826535953650784879339331120906280,201781316213631005455227216755502850172048,9183404199411504412156373561368468657063847925055,0:2917132830074900548165772586526792013580435602635 +emod:322376591049977138697730895670752146989338805,223962315373891826478293010620538065565321,134425497979583765111585462044979782868043951339,0:12680763077525899140335801175036995248897549410 +emod:7378293498837163030108494500023638035245941999,2701192105797571727239301264973963904903943488,61103840672560006595434005526860223512609429784,0:10575104110432808219323836371535482428895151433 +emod:6586150511971850295907641345124913235499024397884,25513878140895710942385809529884547574325,402623421320542043817163858150135923312140690478,0:212703145455744928999402867801599663279882403300 +emod:1148513813380533679268801317870273567836422766,78264425883354201492861909224929965803589851,888529022913756404039252857597221260693723470,0:344612069767725463911981963977120251304004566 +emod:156897858936863936558762112272942619182648359,5998398850499440904999529048665563755755197719,4114314816923307068086587017590920904175696,0:2365605906155718722370615329402928970075415 +emod:87182346175010426980309825602413855400180387897,6881708075476719061473118229291803541629550,874317437435696504884100729090652126764764928199,0:358356267780280626874735799972579854632076151004 +emod:911804580943517196035138307824767637716096,51910018818079388343993224114362468044260,755719409656106996416099738309867560127420,0:619648429452324074929397811402394241260156 +emod:7907371058268574577015600989784286442091497358826,51384490845283761025532093399709612887400222268,714932241344452067231089183566607442645499,0:39652714695362677793061396306809603985720 +emod:74152151887141438565558836677120157654525413725,3865673216281651353443515507748331062737635617119,39515541452736626357498604574956947118936,0:3348164210948022420110568984992044206893 +emod:1921212600092818926909753666688437613889202174324,15126673218216417698630762186472446617543479982,1513247907205025148358918017400696573029502,0:47771732582221332296766778100437627607854 +emod:62177741738385906366557378447871109683100,42062431220303473355860970126711938425550656184,773958434020341693602047125826174529582651,0:442082897911401536767776238214849664334966 +emod:-1806808081053455087879198258615146551580359661,44724668030512207581826980240922859464701,5189597819742605059176771398730210738088315756312,0:4809675330086812178815566854450153052638869156587 +emod:139380296373533535850169111091445251133031553,5568131554680055330705039219787143467175996,518185013729942602529965143602253217637466,0:193773139480058911982453569250459620737303 +emod:974121940443001500503304094214484700334099,728467767024352630604669587731875660396330,44674919076720204028296797718736637414521026104,0:21438174710368725104589700570479560530599609609 +emod:-527405333948184200720039219764919299319468854,635924082359258060601853893045398322160190689738,947819620520708699044943964793321010513297329179858,0:342816230736644110664562034099738209027304408209052 +emod:4964014414366266067601563988433897971039777,972491441089677662999190229721797813272801,938609136796638825673168709652895939249020,0:757905229497791954404463471617284756626357 +emod:-3836548959134851265232468756686852887039589263025,91958638726161076829164170565310939352504345492,9842518325582477123987885320987474902828056396473,0:1785937883725230279579795187739041151659042418262 +emod:362003077050650651287331998851003608874005730075,7224278456794231058200539570034490392355119609450,686491790315346927921146778571888891553496,0:316447529525677730606205777277031419657281 +emod:511417748058568151891786589987253660165796727,8094482124265898686460762144280960033447161606040,186381274246323455788720228571054777422314708850,0:45279922457870097101374197162961699877223826551 +emod:81264000690609604351458160311340827489802109902,391885387725085278459091170640814114585520,862357107879749607217822835234106152392133001671034,0:589199761114611925556876493283500689288324693424922 +emod:60467632250983508695725501646784109879778908745114,837672302787514343932615418244003255566590288,469196685288767236431865642803573408203650783,0:47351563702942679095591216340308509524717890 +emod:-459476727597478328887650694792354077730065535006,6551100280420641334568069542701824749257357,44015235164158274406848669553614570342982958461378,0:28017796628275197434019563629223716729911088938710 +emod:895843043275999934611988163188471273684218111033342,7246774352032830692528490542295484830970866278,861847510016050471694148161127317335094105768,0:654035466899277641878411664189821364246515408 +emod:286589462111588691084089929906408043383921020101,9692415030522370188366193590872225386635917218031,719298087261564603655693066504254890048009456875,0:427302318670364247525213648717424428327518555601 +emod:676436471530083898997041363054013845405132592805,9826535789561484874848870984693688846169671622,81123191412086856575942178138898627611978864,0:58559446218187016378111352068475314798576601 +emod:82851204887068882391372029299659256702159316,172869110320082328384071354204393838581736,67056444908658930881509973314864718767829541458,0:19106724465380212672652647774912584474721840748 +emod:696109009687864457810113686337232495156421183,3401811110841371494776087049474111559799131700,4299920714282089106120610636935635090268618368,0:2020511812293185382323106458123683937285282817 +emod:642181116705547745922861595409305314439788715713,3191544116958009442265013426506709691563847359096,11503959864174296512003111411775254312499675635074,0:4542807727654055188419122200833174452933393471703 +emod:-43473592792665227303659232677180275856179335420193,367337932661391050359451420336432743104912012849579,40336899717936194492442741600463146885238391884,0:33883445452210304367843379593615127696274144511 +emod:149677082879100259644810248166250018278560400684397,67835958963093533534750484479612188112600772232,2417319759617452658480101694897700221629257,0:413114555403103000658332346965315753541371 +emod:4308690827834618796779071688055990154958119217979550,8139792103252594022614523084666149717083186251,15533037471757153506550580840055923919409189,0:7020715664515618963916470331313209937794066 +emod:4607793512504764431422636985189117330151450,5810855517430042248184284609190428320492582797693,254077145071398684004350471347456740109867649920,0:249414146109210156171911011976187568245339994880 +emod:75015031620454344801239233353680150096201722256401,4993964830386180911249138189300268494685186990942,4241132252523512745096917242615525253291052986,0:433337045531299838053635884507298069666061467 +emod:44960897309673530453555266827045004683193626,9864385579695978005342342313046773936648945269556,64756470723619643596096247881962254980723676611,0:49116998830009971503948732099380336099106902368 +emod:824638657497552691308275418547421010797730757488,7102337564045908912215659769896546075594806,7549559927659163526633926834915307075816410605,0:431856052905253153141408472781012880375756789 +emod:-8258821865451861122164335490949730530149357550,91240131099914556769212391842754945963419588729545,608091538039563385874042418452351103116377287,0:138416095708955483721209050087621590198128350 +emod:6918006637544381236582913953764444433570928,142116742659743263417878030971625713139395825277,42465778998553599048069556979313575711603846192266,0:21075269211617428685041608731276059490981153877082 +emod:22864575309091005999606038194627722799352002613109,896391086004059443203372771274754832310503484093,891750130247908667659048761409012710669636399491,0:291616836488219220269230095553451995714008687531 +emod:-8194888032441259199630599625358473476489205,5233704072524169370158667063506533972281083980647,1489037233721004711195744120696209782731350261503,0:552028516294652365815212711109824092516937002021 +emod:402772636759093114336215386282519687390989479435779,189516067274441373930013687419363508463761721803660,80415811227458788175575610653906545982219330975,0:22728298548876566392049076077182437096372400601 +emod:25478733323871259877912385362343090774624815,7071155968374703054163176660383261326011527019503126,6134327557381540088147721199406548730558126028,0:1024740410140626130936532360899124497564707733 +emod:1373842982649207730088589912059387373550201,5632296300635658701077632379614186637591919259,15391327625104216613547146396703256586018696280834,0:4302181480010047578962481977259846491527280155375 +emod:9495802289929888822634017883238054795580349,5002682765682429592404202303916871057826935,15884650860342620721715065457253891894018967206,0:8941067791071558272472337248264693834973616755 +emod:31600516776786509284343708819765575234628755,228791299265655690472626502236069938161188391,40936664868340332393928739047239776545553829753710,0:30627744149685105327689441848075123499867991131765 +emod:38524550306915104068946046715826855759569613774844658,9194419836976281683587306717261558747169442193954208,7779595009435858929206493144805114063764499766215590,0:7087991661129889057406934247049530530993451959597276 +emod:554411708679558039842538802463328992263904679,6237197282110482695552284318126536429504723341,10950325577001918036371982331444541813617574475194180,0:5787600514717071948035385347363174161644959891539359 +emod:-65036555989091136374058985938454117449763159,34831798653870828072406297626104961773750661,31676515243089740330950585861176809143792092,0:30732949823978690229767791353264924799202285 +emod:519484888832782036702272050651904638826888669,753074873494165067376985336730357180001686201437,26162868641248965913351015420400997201482504702269,0:18484433084399526415475352405874231763303729896278 +emod:486622002393256987329857884862358772922652299948862,5397488133084406712845993173123874999792355443180,52221363514636645344562494690476680459663806696245,0:31424877006247871341476564009060753196816273746886 +emod:2519545249333346583863745851735514920346268018,5762304897220756179596577719327585953058564086,25968687826793482314025869361353695830319122017723364,0:11446923482269709284929175954873487230221266306098484 +emod:25181558468391709065005750569128856213137442801,17395204260174949840937998424068393371443165843074,5405603350542397445284851120217561963941561607,0:4017170326519248316993458817903116669933612061 +emod:407900825111562209157049195681691242826792800,267987715516648071532918817255425280495590423956301,68776425368933157858220727119994638551746175,0:47031090204538290387899250133897480746869275 +emod:-98803819636216862704666508079523455809956165947,98671412267375938209192375718233476934668297,55621612703501672327703967617091220387319483168426,0:32713255624638051486342207442183163021264516435649 +emod:3699193512054702576853653403075240437897079123,8717079191539632537960810302588868157436232036,48522242477672943422659170492335520141870413,0:8651476435014431039453023117472444582400514 +emod:77936539433974741743578486606140093995870301132423,954499217422932957346614451159347140560185480521281,163215414633308466314077081093001860212713379,0:103758294538389867607040992307260424637536023 +emod:-4028502338091434385570286181712320072468742558,96989036369391542800442739082061530586823254263116116,78068537791270178387717266347434743278287908,0:21669953939490893566721670542161427811188984 +emod:918884247467748036366436587703999780118117975546957,5615852005546776682559779744353394064478095142,2401794658690427064436304716694865657554211766,0:960515354911580091015228026871019794883284885 +emod:9780239941823826659833679733394177755526189646937,89322777323067153562491076481435606732771405285,29157211787311713009469704820603173835586448915,0:21784603970310613711389261139944185838629281707 +emod:96098774697583148524351932903096795874200556392,6980912905868697403003059554264649562235986501752363,208924194204367947369626074783038546699206285520,0:79697661577989072841423526677085730430307916048 +emod:-573991994177224613634480756482666353761100288807,7158287307293331130042236674166424104745547165,9922520662865454426464919345018943051389988697,0:5619512846811035521678742038957891764003573958 +emod:59911103774024380942223423632168855379630335,6818486079655068602807082064093124643116770724,8864024398516747656055508658685364700493232356531142,0:2383722465709179243642856098503264547092886596175227 +emod:-62313348406991266015553975744856571685314477634,21991981158838978996770304861386400122523958836,954507703567266334987920599572200024950117776,0:673874525887635950319127294209157951664603712 +emod:9820087452416196217911209095780565350316442900,148320444363560053307036007569156568389928195017362253,3631113047524475643723456921191780561936707959783575,0:1549830330276375593962772767912210881310119448216925 +emod:-25798647424975836057412872830909832741720494281462,9299188364970643235457620086027788049113237501724,522064657371945322423320375992281138757129069042588001,0:314662317723871224913513394778330419886523487691115165 +emod:930783335744991271355677086538660736067905998974646378,776787459928168870257234381028892429138274839820310577,3676898834201974197391604163986622259912692963,0:1454707990857958111219870293206602713503203390 +emod:754324807048657228679765605878761298609690360511998,958586904489606201890927436646020906824192582152,225179126294857543684132265900588355218787359997532,0:184341533271280210707350262029004357506956964249100 +emod:-4277241617014152774634908150956976406225721463619,740666737188827503974760746294458696679071963170918433,84911564006449909724569329147240459921838626102161,0:32837984989291416730559017868100153859989248628941 +emod:7690914272601666512634428163546937580730709939602,14197296902658248167889786104196831416278344312144,81931815436335281188537823089415033249544638767808135,0:3199600947635353412828955610370257711774177287067436 +emod:40693757858681089447717885993659911215985324585652278,39136056473317073147714521234945625238580560862152494,56180103978500893124049541126696155778770577135,0:35530182604079785705672771377947698867955134584 +emod:-61262007457380831475587401250265303407703358053,5605602757602617615751362780250832755031303714,39786650424951253014286369945896326084999234541,0:30624920045735321607213022533773280830319909832 +emod:-8294197985009320613004835515579701550690472035947,27497176409134737028455478387441759659126437088890626,878254584167789416959102500401944397284939932959,0:96787593049516460622263353747535019044011554347 +emod:936948855951886126122485690093336688820905438,952037324756179560869502130218077067074192084922,33269225773280332072695417422958575761899978253499,0:31343729843026164021419525495602740164653732233547 +emod:1825784156631469036083553494921853600892959329084,1792152855908535702866815908479066064573203506328,7584434492468684030603996404862850988077230764966,0:5668645854080378677534840608739670840420553612804 +emod:4771542980687362499528587321796090255401127670935,49673918430106064176014347389103358990211599558,566808710453386184370243734899518529679284370157755,0:122614051205229170899163057352055351000892027836640 +emod:1823975371238131949336117473697450176001493124551422412,105862300137903514746181350899950234467623927399,872150475093096064129104506408316916638215646399,0:41655575950454700889468004661814966001328043635 +emod:-7403599133408228298723066626194976743023770563,8091134022905952963104699681073539225469153697858,5425355350845048150843160638835947264066541393,0:2741144821308534612335116015287775234294403710 +emod:890646208254935784836741265729061048252488750371261965,3014682556575993233966766524815533447095651265,546627202244553599303777629347742865125211029412308759,0:129189292373035871943643466963326800150883513587943803 +emod:-478301676028477872037215528133488673909770705969021,4776644958028138697511933491453433971900379293,9804006501217419003156374248597140990532373604359741200,0:4256526039075877642788870040517474793472829088151023139 +emod:-2685385133378038265400322588836701680595103090,6682051156600485359090971175835317671334686963274670,272381294217617274132435187599076952898337370816,0:160448248258559406045792992578310861095674214848 +emod:5610352369978196066557531911583288845257728872885,29105174820600183606830671874489670474983812495,10153364462051971143078318734983556641603678006,0:5654495476089063930689151404880397736789807021 +emod:226106902099977963681448571570521911815066120995317231,1707966440323110108128795246285372866871484571190343733,3022313205119289698061840897980713840817653246137,0:1577789001757918961027109729382551177312942381192 +emod:56994398320188483459448108143592444430607410910,776571171150667113541269029583357392475898590899457,2952252481199115860737553986433506978840458215941629739,0:2115048663787786340261444189400738968421587522302410834 +emod:3490308621678382172799094687550532898406999135779394,92096452137945096831873480789275081374251295752,41859985473397465016337344479699193310470254681186836,0:13883201384282345984019723588819996850955384028405568 +emod:78199345624452323665538899878571977010103711120353586,426889339090868016603770192089391858795483010444,614591398724869622540933622810612317245462099,0:522221021562810412369119229465715299116874680 +emod:24494234546606769948911248691757492347200292227140712,737664088655731527937609365429682453415687199299030,41867909567513789892657868211831771169136305959589936,0:29639257666757184257116019424419930205524205997421488 +emod:56340168172071966259164709446976804762407806722929085,9330607041404161548877129661058575432184418559,9073094112420733297526890865499708444478527878927152123,0:154033683820095649526112863414229406070106242714564017 +emod:-98557586380727162991959870302640551435620563142855,352179144624443366108174660913068150097236769961283,82957931261705630469780521065649609232909069967906297,0:4611469772581670990273871321012941407812443591119341 +emod:-327557046252127633720556940076118229316928253056031837,87561673782562800570041955183322599955629735731,999914991747113895498838412296608587151797268932915993,0:394844471425716300825167828282861382716619299699558452 +emod:62239294453310399816462667483598707872602240932142297,4658914995757017485299221864332093690860930515,2486140058721179216992139245736934931657664228105707838,0:1785631544920858868455392242463320012563257587191303743 +emod:98844248773908427486663349850376500066907267527022459,30192206183400841123051111248262548983869820657370418,68953646632746416359816661196045006942249287619,0:46348894487037788897865804485372390262476609587 +emod:157314584387460613339515315779646913728585159983563958,7129487243609251992087268468464230874147780513130629,7635331003686312032946464576006029771208342239,0:4241581628875360523816771058381935521234659115 +emod:-20413864406387948000986404651284225843901612271532247,60570204203293653144874911182227469571265725493933396798,74868812887175685382885501310045723065586089753,0:19048798896908808195904371996264452593501059126 +emod:-9994818638674529038541342163911785506433155975282,2441529131191726286407021656054505236538534218505,868763054397265950319354411340564521520500110285341,0:713646341945805538982296660502179127412919111592110 +emod:89928590797284478729252348706855088798121290869809060,59274533239795541803239071337695221071797917061551,458720998639333601494661224903885165927950415283068,0:238541586391208422370502281952541020478014766570928 +emod:95798368921402497294705740910984389802169456614551866,5780238728300624701546948669191486225967922222,17602545836464476089657116165016615105637757631075883410,0:78935491841772453025866169047063528694493328256027716 +emod:-6285988010245529074539471748460012192454923426879038527,4464035763112866760911458677964807167647554031374417,557426143112327094606990154681823173588434990737834515,0:492308894761273719919857937651384253941194670007301468 +emod:9216609859426876786581364775917107940830826147193,2584656223509851604195298909793029088361431700609487947,97854661860659618908160182622420008085466240143877617,0:85437882709473882823892529660893798801236147303713473 +emod:9369310120459129777778887291797647697234777683432051,29114272244461903760267994837317966967186291374,9778907141259037429006274419046033685045015909549812,0:6158258816758612931552439105354775382106793792840429 +emod:121095461268256661739120249224368430821121813080,24216928007688542369493467184086532629768906571974067315,1289101505296127733900239534120001726302383453437972,0:559264053276767206654909871928116713399654543670428 +emod:182013722639261555865084991953687573500429962535766,5312171499532129540711226268300910853763234503893756460,373925090068292154121977949608424249047611823254,0:314492433924568960493434943112384754084000516952 +emod:93122409584336684208634425627697110814180323391,14785829877381197130422634393843365096818009069934141,71932199753627287791733451362196318752438103297,0:8651254301747600278741940327234016885952587642 +emod:47314169772357749238033685118725095245857710174326752251,7737526111797627477363360414613284237413174897695810,22636439121232576533369780871442014748582558494258753099,0:13481881160769756096301137118624702877253559402875253449 +emod:40437135697420911841447145598134529938086874417869482,34142834203311856114775566332299272975314691621831451157,61483400000688184187598139984127464523117551228,0:24693895005298972635867796289890449288509340480 +emod:602105062592660782251188458378445123063805101057628877,8347043677742730027972079328186098141974290663352,26831519142227837662521069711039879610686983918942079815,0:19346421778661788162968173970766981230660937987122859431 +emod:-631401827295443763663013499197680737231639584989,4430590554183773954781048837898216988481838421600006676,2298393896534361874746279427962482679705626081354993,0:902945851002567106949268418213474969113107638762554 +emod:27786418359632188385534950865019584947593363685667,98296086104810263777729111156693306399745439517905843246,885588959591327389647962772187472088293854582596501585,0:219691806105674835153486211154061118027834335467768059 +emod:544755872510174513208896610649845089424204895203973,87613019793007744065404211674234696040702876770839324,4802706142382015625537025588688720114067633075179938214,0:4385825975408070392248170302791202812902625274088936755 +emod:266945202318091617395513307631280644325314217797596447,327566429748960361523726509719626329764280050772,11519336904029441280173947176416866297494364467208,0:9214541334269337101551342582484701318239260425185 +emod:462274575377872280232466472100106379919338255223,55208106570738920386188352962242729542845793547908872955,394947463398055276743090558014108833519958843326036,0:14090943624401742126636618168767136948067183397671 +emod:498588690178207860433541173652626793819053542771822736281,7320383073654496423015034860141911017275032239632,864143543362782361157239005190574446540608427530,0:405837700105174778010475141584205874050426805841 +emod:9889983273673267055836467894511050393862566401427167421,9249465646754817541871880579390030265752574382697001,25959701663622988366438447815418575609294742760915,0:14146692686195759173905915586727366427907029148496 +emod:8977490701791885156174343111351369788045969359197758,310958534312954656622864682281335777958703646747002872696,174885990030766375557335981487351371779234545791,0:172268700100468974308770735824988553302287984097 +emod:75891699691571906472460353214537778119193566652164258472,75642710398299172975011498854625838470353049691991252,955726338299637204220414390179262210175010011084260057,0:871551220400711242628454200406202564111664531240532043 +emod:817687870329204460156610156013195890028396416937162234,71199838789107588122529185516473983414598608665610,9797217400749418393402581106919553154845468700907872,0:9732835751266971971517518815617086242024182057719936 +emod:656535389260219421975691249279051158130957449883966,9965820125071850776397934471591602941345422709213,7172697024967323900460450488928712811727935935053426,0:952029660753929926293707648671191250800460252928490 +emod:66765940995445083043566397231259337861214788967954,698949221229345492777837382914330269944860925101870058401,370977162689246158196783733149906357225503977003,0:56780810013712823080333031377883978714594923759 +emod:-24860118467430048016063231699711679455683726879672563278,546329058333516554426292196577372643895447816095329334984,102083942512514956911062347152596366057306100868,0:89329427941719016468252169448693561927858667460 +emod:518281434431704435940150792966272899127164218411,19290830216216089485046976601623655817078004660590796816,216069676358948655463888215158143195786697578360538582,0:86506166688482117996142986160440612354876384284094157 +emod:517542901438648396791987658999334820221431246981278,4954735021213009892606598900462212813613793939697004110,5546708620630276172568015746256008412046274679011721163,0:114558840275328029858937724196533085168759209383758948 +emod:97796431105417086121597265848245224080646880891314620699,3566309852926516051758561425477409449674731444065,4237358411463841472327670289343773756088420869185382928335,0:1728379035119996080675313770460691892171354788520339293899 +emod:8797217794906750966627546899905389746578400755524,87461473070045326370501974269638901791524473673607812671,63579576817694957532492907897275166360331019259167287988,0:10068755237067361214693799084814132014570304060924282180 +emod:3559874918456198560844107856956492116344121248206,45190612746644425408414684724540657030439304479324039,684772758312255825130987448842421703263477856778082,0:500105229544177258096786497048655528691069662344352 +emod:244693542815021761876325478432698673186866834942911366704,569049151750280294347914587638406693043104703456596078,40418336644392592645116495825339904699620388961770,0:29946736018608816763137681085572521922498414649586 +emod:9552030352913538449959248911819718532447389423411634,15303289522386175735929093158193781525599040386989921,17905297851878021472325954407339512702437837940804355,0:7227207308763570886905006773221274115571235787935329 +emod:2427953611523095508885901603899411553216124564768970531,84219397598182701873267938504642229898519369455120690652,5124565221346746692094768907421280792680721722663049,0:2356962294194965054880021165404451023189256523983359 +emod:4450272023458109693579519823508011943468990250887770429477,9852180148050086854797451708622242708750405652182828950510,53218591961090046740426308696077544888041718958796756705,0:20722361228858746975332642022116538507546307084688876639 +emod:-3004436507840212393446088399233355090512633931853,49762352101558708510764823100128412949214842904414503,62339832791097134323794421391092834208651832053582621969,0:18644587060060960018044094951299852000053162441627275349 +emod:88466522329785151709268834138668446416231472463853002,84423940822580221018912007091908955924620089965579353300,4272746558814012659752446371362908792507498696285890777,0:2076687497522815194513922920413442770240123518700437310 +emod:-452137704321173773725358540484655780134513962685597,108536825158896375705138771152627679486775845056880757255,7443505375179903958445129175383134980666720252160978,0:2626655033625685458909447520232601675412626580083149 +emod:3646226144731352080332815382512112527325988973642,736730185733372156433101295886081895604485817722725,187559548105706428460460100309284194685793795827962,0:153703862976742792640135721867824635074042235940792 +emod:7128578973288696116455318246508827884395148700024035843,120044617176238734085406385417402387651027645325661,437777976047468143063879147080739099513994845762621846093,0:383512808517870785600076597930828756369001886406596109329 +emod:92651404329219142594991415600374429189694983250618442,1831956594370082650320589803647600704949512437508530740,989079198090857685320779737579388665165981389775724354,0:429473741854566274661236706264645428539362137664132958 +emod:783048980600864030214223520282343154949582263988130988029,5640798680918146067495300825091961866365823288705,712576055151408429943237184396668347415006718010549447,0:132303576760619346367560792334725765196706066347238184 +emod:54419766013288244584593400647946050509291116271357,37442044497849759156397618484039469808263267657304,55409955411797081810766022756739065410388681698701498,0:625989815794948434601895148375843191288774735399931 + +# Regression for overflow bug +emod:#x02,#x6FDD97BC0A760282D5A180D2308BE3B075BB6456F26B1DD0BEB2C1B0F880CF2C8EB724F2AD0567F7899D9A980C7DB93E418ED09AA3E35357F4F2E05963CB636A0C91B1BC7A000ADAC40F332D6ACCF4A3285112EDBAA95BB27904794ACC8D6FF188E2B04888ABFB11665BD1D915DEC8C6575706067AF3F7179BA57D1465D78129,#xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF,0:#xD2C80DADBC0C72DBAC45F380064FDC5FECEEED268C7E86368DFC436908B2D33426C67DFAFAA56FAE89722EAE3644270B0512BE69DE61FDE07585001B5EA4FFDA1B8B98393D657E2EC4073CE4A6953093EF7C3B130CE1BB316C97CAAA88F83C32575D6E1128E107BF66910AAD2B84C44128370DEACFE7EC8A98B2CEA4DB7B09F1 + +# Jacob Refstrup reported this failed in 1.11. +emod:2,#x10001,#xa6aabe38d013970f47a8751ba8b3a2d20b6cfb1be2f63d7c36067957eaca627750d9fc9b03ef2503fe73d8209099752070a15c40d481c71c014731f580fd905db763434f999ee24b0fd4b5f304948181555531e5c058a8574023602191f3679cf350ef9cacfd883b4ab466e2ea10e661f20e06347995b8a751aa9c17c0cc18d495d4140fcc9917cea0506352ed4bd505b626d6803c0769cf88eb7b3a15419e38b81a1ecb6e3695f8e1f3ef7a72afc40a26787f3feeedb1da6715771462e783c04b20804c4228e7bf2d647f2b745f64295006f2b8aec12dc96eaf720fc7d5b220c465664b95ebbb4efd67cb65b73d0556ee10a7d103d25c9da5fe2a757b193b53,0:#xa53fda84e114af74cff65ac6367f2d45a7a0bce93a0b837ffa48d1187fa7f48a87e543aee994bfd1837ce5c72dfa26ae45b1179e486d9f242fe0efd942b0e210edd0b34b870128165035931db003c5158e5104d7f220eb682a6a7878af64e88908a8969e65b827c1d212f911deedd62322df956766b42d284d7fe88f79821bf1c0f70b6fa657faf6eb8ead181539c80c1a13e9efa7890f4e63efcecfa32b4e1211bbdffcd6a945a04ac46f9888f7d7a6d182a0f1abe5aa2b1319d0cdf03074fe20b45a2f58daf4603b63ea35c2ec395c51e3b85b10f91cf85f1909788d6a5603ad7738eaec0a7d393e3b31477710adaf98662113fd349d34103aacb05f42849a Index: contrib/isl/imath/tests/emodv.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/emodv.t @@ -0,0 +1,305 @@ +# Modular exponentiation tests with small exponents + +emodev:19,2,84,0:25 +emodev:19,2,84,=1:25 +emodev:19,2,84,=3:25 +emodev:92,693930,16,0:0 +emodev:92,693930,16,=1:0 +emodev:92,693930,16,=3:0 +emodev:522181,0,166284,0:1 +emodev:522181,0,166284,=1:1 +emodev:522181,0,166284,=3:1 +emodev:437824,312,93008,0:26544 +emodev:437824,312,93008,=1:26544 +emodev:437824,312,93008,=3:26544 +emodev:5705223363,2,3286325576,0:818318913 +emodev:5705223363,2,3286325576,=1:818318913 +emodev:5705223363,2,3286325576,=3:818318913 +emodev:6399553325,6,4107014863,0:3307178134 +emodev:6399553325,6,4107014863,=1:3307178134 +emodev:6399553325,6,4107014863,=3:3307178134 +emodev:29074823374249,77004,71683909277697,0:8940258342532 +emodev:29074823374249,77004,71683909277697,=1:8940258342532 +emodev:29074823374249,77004,71683909277697,=3:8940258342532 +emodev:78759078367890,8335,72115845746903,0:20414099940189 +emodev:78759078367890,8335,72115845746903,=1:20414099940189 +emodev:78759078367890,8335,72115845746903,=3:20414099940189 +emodev:-702894953466773316,312561,665754485123402827,0:84548134549060215 +emodev:-702894953466773316,312561,665754485123402827,=1:84548134549060215 +emodev:-702894953466773316,312561,665754485123402827,=3:84548134549060215 +emodev:162476353576735207,8451,299565526093115255,0:235405725752406313 +emodev:162476353576735207,8451,299565526093115255,=1:235405725752406313 +emodev:162476353576735207,8451,299565526093115255,=3:235405725752406313 +emodev:5569622159977645154297,902159,339048673939289293353,0:314927034088061888405 +emodev:5569622159977645154297,902159,339048673939289293353,=1:314927034088061888405 +emodev:5569622159977645154297,902159,339048673939289293353,=3:314927034088061888405 +emodev:6991839486419148755508,2553,530292436823694624357,0:4272543854207020971 +emodev:6991839486419148755508,2553,530292436823694624357,=1:4272543854207020971 +emodev:6991839486419148755508,2553,530292436823694624357,=3:4272543854207020971 +emodev:84643040276670536818634785,63,64928874055124010543482048,0:22546118193382720472157537 +emodev:84643040276670536818634785,63,64928874055124010543482048,=1:22546118193382720472157537 +emodev:84643040276670536818634785,63,64928874055124010543482048,=3:22546118193382720472157537 +emodev:-99555590330388726236230755,0,62041543621233726359336122,0:1 +emodev:-99555590330388726236230755,0,62041543621233726359336122,=1:1 +emodev:-99555590330388726236230755,0,62041543621233726359336122,=3:1 +emodev:700943089540446737340421223177,8456,835694701023829355087294263155,0:258410405038140346743628562611 +emodev:700943089540446737340421223177,8456,835694701023829355087294263155,=1:258410405038140346743628562611 +emodev:700943089540446737340421223177,8456,835694701023829355087294263155,=3:258410405038140346743628562611 +emodev:5473388626149338730799075406,729,850132294968984927109971586336,0:685051590046393947084559076736 +emodev:5473388626149338730799075406,729,850132294968984927109971586336,=1:685051590046393947084559076736 +emodev:5473388626149338730799075406,729,850132294968984927109971586336,=3:685051590046393947084559076736 +emodev:7542606175762975785023215555039217,0,1451486096670046812323372237867852,0:1 +emodev:7542606175762975785023215555039217,0,1451486096670046812323372237867852,=1:1 +emodev:7542606175762975785023215555039217,0,1451486096670046812323372237867852,=3:1 +emodev:-3426829035080908738042076334435395,0,2616360606577002719669450329100985,0:1 +emodev:-3426829035080908738042076334435395,0,2616360606577002719669450329100985,=1:1 +emodev:-3426829035080908738042076334435395,0,2616360606577002719669450329100985,=3:1 +emodev:5871172260267735917150171255408367076,88202,31506806059671945544343675240909419388,0:9882411358511873694991988201288706348 +emodev:5871172260267735917150171255408367076,88202,31506806059671945544343675240909419388,=1:9882411358511873694991988201288706348 +emodev:5871172260267735917150171255408367076,88202,31506806059671945544343675240909419388,=3:9882411358511873694991988201288706348 +emodev:14045780235333982097410791452776449214,6,63567135751970741787875276189593310474,0:34130827114620482312672610863840969228 +emodev:14045780235333982097410791452776449214,6,63567135751970741787875276189593310474,=1:34130827114620482312672610863840969228 +emodev:14045780235333982097410791452776449214,6,63567135751970741787875276189593310474,=3:34130827114620482312672610863840969228 +emodev:719958253183871430502261490413450673851124,9,661851369887131891462493813741667459688172,0:326930997921634036854135001452458647807696 +emodev:719958253183871430502261490413450673851124,9,661851369887131891462493813741667459688172,=1:326930997921634036854135001452458647807696 +emodev:719958253183871430502261490413450673851124,9,661851369887131891462493813741667459688172,=3:326930997921634036854135001452458647807696 +emodev:443624238294320571664949666413150109110287,6385,784303120899228089361406308796439491202242,0:342407852738883656584329996186795949032601 +emodev:443624238294320571664949666413150109110287,6385,784303120899228089361406308796439491202242,=1:342407852738883656584329996186795949032601 +emodev:443624238294320571664949666413150109110287,6385,784303120899228089361406308796439491202242,=3:342407852738883656584329996186795949032601 +emodev:1136928015233318011144243860597237613050611024,0,2789921991289922378761307428111094457098264457,0:1 +emodev:1136928015233318011144243860597237613050611024,0,2789921991289922378761307428111094457098264457,=1:1 +emodev:1136928015233318011144243860597237613050611024,0,2789921991289922378761307428111094457098264457,=3:1 +emodev:1450999454447652679327105307881736952333784073,77034,7671829281860481025428743103260720025399298938,0:4381187915548158452304254783248892025314678287 +emodev:1450999454447652679327105307881736952333784073,77034,7671829281860481025428743103260720025399298938,=1:4381187915548158452304254783248892025314678287 +emodev:1450999454447652679327105307881736952333784073,77034,7671829281860481025428743103260720025399298938,=3:4381187915548158452304254783248892025314678287 +emodev:-28809270937368266475212144802642236424417695707616,6078,19637146108400624623087855337736820815095169248114,0:6346379403436405925654497852274419173995099516658 +emodev:-28809270937368266475212144802642236424417695707616,6078,19637146108400624623087855337736820815095169248114,=1:6346379403436405925654497852274419173995099516658 +emodev:-28809270937368266475212144802642236424417695707616,6078,19637146108400624623087855337736820815095169248114,=3:6346379403436405925654497852274419173995099516658 +emodev:54802263149810015499242805866671806182669824281823,700,42916710160715229320560332911086106093153060357460,0:13057328573793336952133919465279513927703000293901 +emodev:54802263149810015499242805866671806182669824281823,700,42916710160715229320560332911086106093153060357460,=1:13057328573793336952133919465279513927703000293901 +emodev:54802263149810015499242805866671806182669824281823,700,42916710160715229320560332911086106093153060357460,=3:13057328573793336952133919465279513927703000293901 +emodev:-87262479450738832647843497026325034137115145947284500,0,72160898603477481125780254532680608704164997261749601,0:1 +emodev:-87262479450738832647843497026325034137115145947284500,0,72160898603477481125780254532680608704164997261749601,=1:1 +emodev:-87262479450738832647843497026325034137115145947284500,0,72160898603477481125780254532680608704164997261749601,=3:1 +emodev:100642928524030186658056860132922920804055208139127600,5714,414432667835794981195051773905850760614924210968557995,0:389354308493629553310648689336990724529053681122415475 +emodev:100642928524030186658056860132922920804055208139127600,5714,414432667835794981195051773905850760614924210968557995,=1:389354308493629553310648689336990724529053681122415475 +emodev:100642928524030186658056860132922920804055208139127600,5714,414432667835794981195051773905850760614924210968557995,=3:389354308493629553310648689336990724529053681122415475 +emodev:-9286825595306463634635411645143516399569604439462159992606,8,7606404471200704416983974125320849350185211717364432008507,0:7552810691207713503035685321335559561108880936575121774165 +emodev:-9286825595306463634635411645143516399569604439462159992606,8,7606404471200704416983974125320849350185211717364432008507,=1:7552810691207713503035685321335559561108880936575121774165 +emodev:-9286825595306463634635411645143516399569604439462159992606,8,7606404471200704416983974125320849350185211717364432008507,=3:7552810691207713503035685321335559561108880936575121774165 +emodev:3436239558982298112600646182085281977389588789170709040954,0,522233930076758999159392228622915543027930093543196382148,0:1 +emodev:3436239558982298112600646182085281977389588789170709040954,0,522233930076758999159392228622915543027930093543196382148,=1:1 +emodev:3436239558982298112600646182085281977389588789170709040954,0,522233930076758999159392228622915543027930093543196382148,=3:1 +emodev:98605572113921015570731666917408019243503426904818325007415747,66771,63600959482143388817643210552729171226910500110519779197352540,0:20785847662807375106647030150336411392148138353164443936289703 +emodev:98605572113921015570731666917408019243503426904818325007415747,66771,63600959482143388817643210552729171226910500110519779197352540,=1:20785847662807375106647030150336411392148138353164443936289703 +emodev:98605572113921015570731666917408019243503426904818325007415747,66771,63600959482143388817643210552729171226910500110519779197352540,=3:20785847662807375106647030150336411392148138353164443936289703 +emodev:-4195218021563262220079054526213885813430895541193263119720318,78,94545015698506343903535130261953470290487760846622612793613368,0:90102715451299572179538269962926144393625103247204607297473248 +emodev:-4195218021563262220079054526213885813430895541193263119720318,78,94545015698506343903535130261953470290487760846622612793613368,=1:90102715451299572179538269962926144393625103247204607297473248 +emodev:-4195218021563262220079054526213885813430895541193263119720318,78,94545015698506343903535130261953470290487760846622612793613368,=3:90102715451299572179538269962926144393625103247204607297473248 +emodev:782779308925261277591849874263374019866668332441496166531362744507,86,593800017785952660786088689171372582380372342941537491408809547120,0:331857206426756526945777967606015729867677745543253114395853770569 +emodev:782779308925261277591849874263374019866668332441496166531362744507,86,593800017785952660786088689171372582380372342941537491408809547120,=1:331857206426756526945777967606015729867677745543253114395853770569 +emodev:782779308925261277591849874263374019866668332441496166531362744507,86,593800017785952660786088689171372582380372342941537491408809547120,=3:331857206426756526945777967606015729867677745543253114395853770569 +emodev:-368107346294563441372147845929799838078404634847778857716085123666,1256,205426227269567020839924454096197301901405255816878779124728620673,0:29070586076917968101851296107557342940225724785154296253334920994 +emodev:-368107346294563441372147845929799838078404634847778857716085123666,1256,205426227269567020839924454096197301901405255816878779124728620673,=1:29070586076917968101851296107557342940225724785154296253334920994 +emodev:-368107346294563441372147845929799838078404634847778857716085123666,1256,205426227269567020839924454096197301901405255816878779124728620673,=3:29070586076917968101851296107557342940225724785154296253334920994 +emodev:-3986212837117931767741913193889401048695278656631180727109492306933238,146,8147531447709512983938379187878961602041163459101435151106563853435249,0:458849149288958792038072118798350524070548896798699913432941879587784 +emodev:-3986212837117931767741913193889401048695278656631180727109492306933238,146,8147531447709512983938379187878961602041163459101435151106563853435249,=1:458849149288958792038072118798350524070548896798699913432941879587784 +emodev:-3986212837117931767741913193889401048695278656631180727109492306933238,146,8147531447709512983938379187878961602041163459101435151106563853435249,=3:458849149288958792038072118798350524070548896798699913432941879587784 +emodev:8100902940229903010080076033147913858702310386781454704764453620638192,21,4267370499730163508065790684197722845343178463626879556739974287797969,0:1559194008070478152155445790765388085122959413923185554185144471054870 +emodev:8100902940229903010080076033147913858702310386781454704764453620638192,21,4267370499730163508065790684197722845343178463626879556739974287797969,=1:1559194008070478152155445790765388085122959413923185554185144471054870 +emodev:8100902940229903010080076033147913858702310386781454704764453620638192,21,4267370499730163508065790684197722845343178463626879556739974287797969,=3:1559194008070478152155445790765388085122959413923185554185144471054870 +emodev:-67357123532607208820167588026304493165680097354954648204845001128495790423,7920,54180751808291492597692968145199206126879627571212323371773988020895279516,0:38482445641925799800186404699759520693970772165979000339200404095536700469 +emodev:-67357123532607208820167588026304493165680097354954648204845001128495790423,7920,54180751808291492597692968145199206126879627571212323371773988020895279516,=1:38482445641925799800186404699759520693970772165979000339200404095536700469 +emodev:-67357123532607208820167588026304493165680097354954648204845001128495790423,7920,54180751808291492597692968145199206126879627571212323371773988020895279516,=3:38482445641925799800186404699759520693970772165979000339200404095536700469 +emodev:21564774075573665981752322921017132462944466357361497012903828640226528286,0,15058866062409919400686067571225883598025018993264993072866008153094783713,0:1 +emodev:21564774075573665981752322921017132462944466357361497012903828640226528286,0,15058866062409919400686067571225883598025018993264993072866008153094783713,=1:1 +emodev:21564774075573665981752322921017132462944466357361497012903828640226528286,0,15058866062409919400686067571225883598025018993264993072866008153094783713,=3:1 +emodev:777842233320172590239777220834144770465433238279191907466130446509467300356226,143127,809101386778417902091877810352677182715503592735762990564598234327398914965176,0:717304943713249257110869278409054343635488519531912801196499856064635084080304 +emodev:777842233320172590239777220834144770465433238279191907466130446509467300356226,143127,809101386778417902091877810352677182715503592735762990564598234327398914965176,=1:717304943713249257110869278409054343635488519531912801196499856064635084080304 +emodev:777842233320172590239777220834144770465433238279191907466130446509467300356226,143127,809101386778417902091877810352677182715503592735762990564598234327398914965176,=3:717304943713249257110869278409054343635488519531912801196499856064635084080304 +emodev:599990501312957514402788959646093776861193105404525472532452638242572938597485,384,694164098523184164132157046027096354720108308754361750383079701345225130461743,0:552831886836151341677818629154179022877513599687843019762824346082731337442633 +emodev:599990501312957514402788959646093776861193105404525472532452638242572938597485,384,694164098523184164132157046027096354720108308754361750383079701345225130461743,=1:552831886836151341677818629154179022877513599687843019762824346082731337442633 +emodev:599990501312957514402788959646093776861193105404525472532452638242572938597485,384,694164098523184164132157046027096354720108308754361750383079701345225130461743,=3:552831886836151341677818629154179022877513599687843019762824346082731337442633 +emodev:-717387166950856039948493623727619953417006786660900853391606222188523146978954842,55,249851988347340743956951710723755778934782102893613303732727155104650554024190836,0:94917559281978557652285194564919194471255372629172461015483079456525825293407904 +emodev:-717387166950856039948493623727619953417006786660900853391606222188523146978954842,55,249851988347340743956951710723755778934782102893613303732727155104650554024190836,=1:94917559281978557652285194564919194471255372629172461015483079456525825293407904 +emodev:-717387166950856039948493623727619953417006786660900853391606222188523146978954842,55,249851988347340743956951710723755778934782102893613303732727155104650554024190836,=3:94917559281978557652285194564919194471255372629172461015483079456525825293407904 +emodev:1247108559833255131023421051224206889208437707543309847268354783435841902933995610,733,5945033847480079150451694696629025175030386955808324187702080655474460793682039951,0:552121131858054985509439507160337194912532999251631220245735338315863124161594561 +emodev:1247108559833255131023421051224206889208437707543309847268354783435841902933995610,733,5945033847480079150451694696629025175030386955808324187702080655474460793682039951,=1:552121131858054985509439507160337194912532999251631220245735338315863124161594561 +emodev:1247108559833255131023421051224206889208437707543309847268354783435841902933995610,733,5945033847480079150451694696629025175030386955808324187702080655474460793682039951,=3:552121131858054985509439507160337194912532999251631220245735338315863124161594561 +emodev:-32236099593112567386979137194422864421137881615337394730197261867346802441980921669823,5,91752956401660637629886605589653679145541869208926297196888853146097034559639778456127,0:60518806834095575644319015741820323735595936545413392902275336817607638484905412448628 +emodev:-32236099593112567386979137194422864421137881615337394730197261867346802441980921669823,5,91752956401660637629886605589653679145541869208926297196888853146097034559639778456127,=1:60518806834095575644319015741820323735595936545413392902275336817607638484905412448628 +emodev:-32236099593112567386979137194422864421137881615337394730197261867346802441980921669823,5,91752956401660637629886605589653679145541869208926297196888853146097034559639778456127,=3:60518806834095575644319015741820323735595936545413392902275336817607638484905412448628 +emodev:50271884481278417471936841270780965441117412446282412169100969024758168373693942106624,3929,81963066766847673205247669622355518222939970750639201358276824482440704767576564991009,0:62281703540827707015524754807406004815705275005421409683659540143504669055166031995074 +emodev:50271884481278417471936841270780965441117412446282412169100969024758168373693942106624,3929,81963066766847673205247669622355518222939970750639201358276824482440704767576564991009,=1:62281703540827707015524754807406004815705275005421409683659540143504669055166031995074 +emodev:50271884481278417471936841270780965441117412446282412169100969024758168373693942106624,3929,81963066766847673205247669622355518222939970750639201358276824482440704767576564991009,=3:62281703540827707015524754807406004815705275005421409683659540143504669055166031995074 +emodev:-579340159717388367484103071217417305401854676291827723561829153224200380081237995138900716,651,307750673565730651787738866338890216282311653914599395911124646576595981539992209095900511,0:151509745004628309027577206278564432986410874344501872366280516978352818925422691489195213 +emodev:-579340159717388367484103071217417305401854676291827723561829153224200380081237995138900716,651,307750673565730651787738866338890216282311653914599395911124646576595981539992209095900511,=1:151509745004628309027577206278564432986410874344501872366280516978352818925422691489195213 +emodev:-579340159717388367484103071217417305401854676291827723561829153224200380081237995138900716,651,307750673565730651787738866338890216282311653914599395911124646576595981539992209095900511,=3:151509745004628309027577206278564432986410874344501872366280516978352818925422691489195213 +emodev:-97916243956905636477652083813766624733750918729402656599354295427509394488660812811650986,0,504214226951518003387724255017508609607833311675048629650486096975331876439736067207074328,0:1 +emodev:-97916243956905636477652083813766624733750918729402656599354295427509394488660812811650986,0,504214226951518003387724255017508609607833311675048629650486096975331876439736067207074328,=1:1 +emodev:-97916243956905636477652083813766624733750918729402656599354295427509394488660812811650986,0,504214226951518003387724255017508609607833311675048629650486096975331876439736067207074328,=3:1 +emodev:3292590583724934273152632680100030114145522324231651230586226973102509131367913652288365962855,0,3489305948459500758622220373494821215068462533405866936756424017653969429333910353069394383604,0:1 +emodev:3292590583724934273152632680100030114145522324231651230586226973102509131367913652288365962855,0,3489305948459500758622220373494821215068462533405866936756424017653969429333910353069394383604,=1:1 +emodev:3292590583724934273152632680100030114145522324231651230586226973102509131367913652288365962855,0,3489305948459500758622220373494821215068462533405866936756424017653969429333910353069394383604,=3:1 +emodev:-7978102455985676350366679275953460048435607670228140092963222007703573212864449715877925597841,29856,6437496673370692769029520191499051311630305921790132367949451008467412252240244679740653218546,0:5317938765885037665302910560037583058809520625824168737742040261509540549928785850499941206729 +emodev:-7978102455985676350366679275953460048435607670228140092963222007703573212864449715877925597841,29856,6437496673370692769029520191499051311630305921790132367949451008467412252240244679740653218546,=1:5317938765885037665302910560037583058809520625824168737742040261509540549928785850499941206729 +emodev:-7978102455985676350366679275953460048435607670228140092963222007703573212864449715877925597841,29856,6437496673370692769029520191499051311630305921790132367949451008467412252240244679740653218546,=3:5317938765885037665302910560037583058809520625824168737742040261509540549928785850499941206729 +emodev:67756737479519149309169118189597305480464085950144437770651525337717619238974063965848555442893510,0,61721185386054729344028716311850202684952560017220443047936445752013986984883181511511066630902828,0:1 +emodev:67756737479519149309169118189597305480464085950144437770651525337717619238974063965848555442893510,0,61721185386054729344028716311850202684952560017220443047936445752013986984883181511511066630902828,=1:1 +emodev:67756737479519149309169118189597305480464085950144437770651525337717619238974063965848555442893510,0,61721185386054729344028716311850202684952560017220443047936445752013986984883181511511066630902828,=3:1 +emodev:13622579220271678876766048827129463577857747656710532915693612564806742487161109510958801491048115,28000,84682569215903086997370780472826384755153630829606521208326331712119423387083844442113181771232731,0:61921681237911684957734827136839012206257886339643336895704703733211281700691618371720081605408837 +emodev:13622579220271678876766048827129463577857747656710532915693612564806742487161109510958801491048115,28000,84682569215903086997370780472826384755153630829606521208326331712119423387083844442113181771232731,=1:61921681237911684957734827136839012206257886339643336895704703733211281700691618371720081605408837 +emodev:13622579220271678876766048827129463577857747656710532915693612564806742487161109510958801491048115,28000,84682569215903086997370780472826384755153630829606521208326331712119423387083844442113181771232731,=3:61921681237911684957734827136839012206257886339643336895704703733211281700691618371720081605408837 + +# Modular exponentation with small bases + +emodbv:9,32,84,0:81 +emodbv:9,32,84,=2:81 +emodbv:9,32,84,=3:81 +emodbv:0,45,69,0:0 +emodbv:0,45,69,=2:0 +emodbv:0,45,69,=3:0 +emodbv:-93016,221819,301662,0:211706 +emodbv:-93016,221819,301662,=2:211706 +emodbv:-93016,221819,301662,=3:211706 +emodbv:44378,411312,93008,0:33472 +emodbv:44378,411312,93008,=2:33472 +emodbv:44378,411312,93008,=3:33472 +emodbv:70,2233634102,3286325576,0:2426711328 +emodbv:70,2233634102,3286325576,=2:2426711328 +emodbv:70,2233634102,3286325576,=3:2426711328 +emodbv:39,5533253464,1070148632,0:416533177 +emodbv:39,5533253464,1070148632,=2:416533177 +emodbv:39,5533253464,1070148632,=3:416533177 +emodbv:7482,37424954770047,16839092776977,0:7609954661820 +emodbv:7482,37424954770047,16839092776977,=2:7609954661820 +emodbv:7482,37424954770047,16839092776977,=3:7609954661820 +emodbv:75,7836789049833,57211584574690,0:32805712142475 +emodbv:75,7836789049833,57211584574690,=2:32805712142475 +emodbv:75,7836789049833,57211584574690,=3:32805712142475 +emodbv:702894,534667733161831256,166575448512340282,0:98236745124961586 +emodbv:702894,534667733161831256,166575448512340282,=2:98236745124961586 +emodbv:702894,534667733161831256,166575448512340282,=3:98236745124961586 +emodbv:16247,353576735207718451,299565526093115255,0:280933599223623558 +emodbv:16247,353576735207718451,299565526093115255,=2:280933599223623558 +emodbv:16247,353576735207718451,299565526093115255,=3:280933599223623558 +emodbv:56,6221599776451542974890,2159033904867393928929,0:837205353236184592624 +emodbv:56,6221599776451542974890,2159033904867393928929,=2:837205353236184592624 +emodbv:56,6221599776451542974890,2159033904867393928929,=3:837205353236184592624 +emodbv:35369,1839486419148755508782,5530530292436823694624,0:3355242496236254343057 +emodbv:35369,1839486419148755508782,5530530292436823694624,=2:3355242496236254343057 +emodbv:35369,1839486419148755508782,5530530292436823694624,=3:3355242496236254343057 +emodbv:-5784,43040276670536818634785876,36492887405512401054348204,0:19286493506125729203919284 +emodbv:-5784,43040276670536818634785876,36492887405512401054348204,=2:19286493506125729203919284 +emodbv:-5784,43040276670536818634785876,36492887405512401054348204,=3:19286493506125729203919284 +emodbv:0,95555903303887262362307550,46204154362123372635933612,0:0 +emodbv:0,95555903303887262362307550,46204154362123372635933612,=2:0 +emodbv:0,95555903303887262362307550,46204154362123372635933612,=3:0 +emodbv:70094,89540446737340421223177728456,835694701023829355087294263155,0:418424229988754966300052414286 +emodbv:70094,89540446737340421223177728456,835694701023829355087294263155,=2:418424229988754966300052414286 +emodbv:70094,89540446737340421223177728456,835694701023829355087294263155,=3:418424229988754966300052414286 +emodbv:-5473,886261493387307990754063500729,850132294968984927109971586336,0:19962186036319737098397980927 +emodbv:-5473,886261493387307990754063500729,850132294968984927109971586336,=2:19962186036319737098397980927 +emodbv:-5473,886261493387307990754063500729,850132294968984927109971586336,=3:19962186036319737098397980927 +emodbv:542606,7576297578502321555503921719145148,6096670046812323372237867852342682,0:6019928069694583180163173577702370 +emodbv:542606,7576297578502321555503921719145148,6096670046812323372237867852342682,=2:6019928069694583180163173577702370 +emodbv:542606,7576297578502321555503921719145148,6096670046812323372237867852342682,=3:6019928069694583180163173577702370 +emodbv:35080,873804207633443539517026163606065,7700271966945032910098505871172260,0:5423974510417358397307357591894900 +emodbv:35080,873804207633443539517026163606065,7700271966945032910098505871172260,=2:5423974510417358397307357591894900 +emodbv:35080,873804207633443539517026163606065,7700271966945032910098505871172260,=3:5423974510417358397307357591894900 +emodbv:6,73591715017125540836707619882023150680,60596719455443436752409094193881404578,0:19278231891294150546581628518996450870 +emodbv:6,73591715017125540836707619882023150680,60596719455443436752409094193881404578,=2:19278231891294150546581628518996450870 +emodbv:6,73591715017125540836707619882023150680,60596719455443436752409094193881404578,=3:19278231891294150546581628518996450870 +emodbv:235,33982097410791452776449214446635671357,51970741787875276189593310474719958253,0:12917271140684347997107415362626020816 +emodbv:235,33982097410791452776449214446635671357,51970741787875276189593310474719958253,=2:12917271140684347997107415362626020816 +emodbv:235,33982097410791452776449214446635671357,51970741787875276189593310474719958253,=3:12917271140684347997107415362626020816 +emodbv:83871,305022614904134506738511247696618513698871,318914624938137416674596881724436242382943,0:318195604484243187814770062976379619616506 +emodbv:83871,305022614904134506738511247696618513698871,318914624938137416674596881724436242382943,=2:318195604484243187814770062976379619616506 +emodbv:83871,305022614904134506738511247696618513698871,318914624938137416674596881724436242382943,=3:318195604484243187814770062976379619616506 +emodbv:0,571664949666413150109110287956385784303120,899228089361406308796439491202242113692801,0:0 +emodbv:0,571664949666413150109110287956385784303120,899228089361406308796439491202242113692801,=2:0 +emodbv:0,571664949666413150109110287956385784303120,899228089361406308796439491202242113692801,=3:0 +emodbv:23331,111442438605972376130506110244327899219912899,2237876130742811109445709826445714509994544476,0:1993464329197419695692136638851665690518853959 +emodbv:23331,111442438605972376130506110244327899219912899,2237876130742811109445709826445714509994544476,=2:1993464329197419695692136638851665690518853959 +emodbv:23331,111442438605972376130506110244327899219912899,2237876130742811109445709826445714509994544476,=3:1993464329197419695692136638851665690518853959 +emodbv:-2679,2710530788173695233378407323077034767182928186,481025428743103260720025399298938288092709373,0:154954456135957386487732495151651926343687936 +emodbv:-2679,2710530788173695233378407323077034767182928186,481025428743103260720025399298938288092709373,=2:154954456135957386487732495151651926343687936 +emodbv:-2679,2710530788173695233378407323077034767182928186,481025428743103260720025399298938288092709373,=3:154954456135957386487732495151651926343687936 +emodbv:8,66475212144802642236424417695707616156078196371461,8400624623087855337736820815095169248114548022631,0:5187964347290625676649944455881080044360235674382 +emodbv:8,66475212144802642236424417695707616156078196371461,8400624623087855337736820815095169248114548022631,=2:5187964347290625676649944455881080044360235674382 +emodbv:8,66475212144802642236424417695707616156078196371461,8400624623087855337736820815095169248114548022631,=3:5187964347290625676649944455881080044360235674382 +emodbv:9,10015499242805866671806182669824281823377004291671,1607152293205603329110861060931530603574600872624,0:322976644144573292044502952628119378896898007465 +emodbv:9,10015499242805866671806182669824281823377004291671,1607152293205603329110861060931530603574600872624,=2:322976644144573292044502952628119378896898007465 +emodbv:9,10015499242805866671806182669824281823377004291671,1607152293205603329110861060931530603574600872624,=3:322976644144573292044502952628119378896898007465 +emodbv:-94,73883264784349702632503413711514594728450092072160898,603477481125780254532680608704164997261749601100642928,0:385098763603163293508297247576178742276025427508920032 +emodbv:-94,73883264784349702632503413711514594728450092072160898,603477481125780254532680608704164997261749601100642928,=2:385098763603163293508297247576178742276025427508920032 +emodbv:-94,73883264784349702632503413711514594728450092072160898,603477481125780254532680608704164997261749601100642928,=3:385098763603163293508297247576178742276025427508920032 +emodbv:0,403018665805686013292292080405520813912760095571441443,266783579498119505177390585076061492421096855799592868,0:0 +emodbv:0,403018665805686013292292080405520813912760095571441443,266783579498119505177390585076061492421096855799592868,=2:0 +emodbv:0,403018665805686013292292080405520813912760095571441443,266783579498119505177390585076061492421096855799592868,=3:0 +emodbv:-559530,4636346354116451435163995696044394621599926066887606404471,2007044169839741253208493501852117173644320085073436239558,0:980083462330793649852651395567038357390956681750027115900 +emodbv:-559530,4636346354116451435163995696044394621599926066887606404471,2007044169839741253208493501852117173644320085073436239558,=2:980083462330793649852651395567038357390956681750027115900 +emodbv:-559530,4636346354116451435163995696044394621599926066887606404471,2007044169839741253208493501852117173644320085073436239558,=3:980083462330793649852651395567038357390956681750027115900 +emodbv:-82298,1260064618208528197738958878917070904095451052223393007675,8999159392228622915543027930093543196382148986055721139210,0:8315318460941735744654692360810076563134610768999859190038 +emodbv:-82298,1260064618208528197738958878917070904095451052223393007675,8999159392228622915543027930093543196382148986055721139210,=2:8315318460941735744654692360810076563134610768999859190038 +emodbv:-82298,1260064618208528197738958878917070904095451052223393007675,8999159392228622915543027930093543196382148986055721139210,=3:8315318460941735744654692360810076563134610768999859190038 +emodbv:-5570,31666917408019243503426904818325007415747650667716360095948214,33888176432105527291712269105001105197791973525400419521802156,0:19067105956731919771713581587977175395882533198855245354642060 +emodbv:-5570,31666917408019243503426904818325007415747650667716360095948214,33888176432105527291712269105001105197791973525400419521802156,=2:19067105956731919771713581587977175395882533198855245354642060 +emodbv:-5570,31666917408019243503426904818325007415747650667716360095948214,33888176432105527291712269105001105197791973525400419521802156,=3:19067105956731919771713581587977175395882533198855245354642060 +emodbv:-26,22007905452621388581343089554119326311972031808789454501569850,63439035351302619534702904877608466226127936133687827793089252,0:8473726082518788387163006019447427099005218230673702028073224 +emodbv:-26,22007905452621388581343089554119326311972031808789454501569850,63439035351302619534702904877608466226127936133687827793089252,=2:8473726082518788387163006019447427099005218230673702028073224 +emodbv:-26,22007905452621388581343089554119326311972031808789454501569850,63439035351302619534702904877608466226127936133687827793089252,=3:8473726082518788387163006019447427099005218230673702028073224 +emodbv:1,775918498742633740198666683324414961665313627445077186593800017785,952660786088689171372582380372342941537491408809547120368107346294,0:1 +emodbv:1,775918498742633740198666683324414961665313627445077186593800017785,952660786088689171372582380372342941537491408809547120368107346294,=2:1 +emodbv:1,775918498742633740198666683324414961665313627445077186593800017785,952660786088689171372582380372342941537491408809547120368107346294,=3:1 +emodbv:63441,721478459297998380784046348477788577160851236668812562054262272695,670208399244540961973019014052558168787791247286206733986212837117,0:211218046769494325969669872092652715825286994236558200831519171517 +emodbv:63441,721478459297998380784046348477788577160851236668812562054262272695,670208399244540961973019014052558168787791247286206733986212837117,=2:211218046769494325969669872092652715825286994236558200831519171517 +emodbv:63441,721478459297998380784046348477788577160851236668812562054262272695,670208399244540961973019014052558168787791247286206733986212837117,=3:211218046769494325969669872092652715825286994236558200831519171517 +emodbv:317,7741913193889401048695278656631180727109492306933238851468147531447709,5129839383791878789616020411634591014351511065638534352498100902940229,0:2840857949915095558231699206349834791724216125018136484978445417022859 +emodbv:317,7741913193889401048695278656631180727109492306933238851468147531447709,5129839383791878789616020411634591014351511065638534352498100902940229,=2:2840857949915095558231699206349834791724216125018136484978445417022859 +emodbv:317,7741913193889401048695278656631180727109492306933238851468147531447709,5129839383791878789616020411634591014351511065638534352498100902940229,=3:2840857949915095558231699206349834791724216125018136484978445417022859 +emodbv:0,100800760331479138587023103867814547047644536206381927221426737049973,163508065790684197722845343178463626879556739974287797969673571235326,0:0 +emodbv:0,100800760331479138587023103867814547047644536206381927221426737049973,163508065790684197722845343178463626879556739974287797969673571235326,=2:0 +emodbv:0,100800760331479138587023103867814547047644536206381927221426737049973,163508065790684197722845343178463626879556739974287797969673571235326,=3:0 +emodbv:720882,16758802630449316568009735495464820484500112849579042319792054180751808291,49259769296814519920612687962757121232337177398802089527951621564774075573,0:5513704439164313512320603722396796903350762139161644395131273954203378131 +emodbv:720882,16758802630449316568009735495464820484500112849579042319792054180751808291,49259769296814519920612687962757121232337177398802089527951621564774075573,=2:5513704439164313512320603722396796903350762139161644395131273954203378131 +emodbv:720882,16758802630449316568009735495464820484500112849579042319792054180751808291,49259769296814519920612687962757121232337177398802089527951621564774075573,=3:5513704439164313512320603722396796903350762139161644395131273954203378131 +emodbv:-65981,52322921017132462944466357361497012903828640226528286241505886606240991940,6860675712258835980250189932649930728660081530947837137778422333201725902,0:2906363080300504036446988558153247540678666818543108704882000018688053575 +emodbv:-65981,52322921017132462944466357361497012903828640226528286241505886606240991940,6860675712258835980250189932649930728660081530947837137778422333201725902,=2:2906363080300504036446988558153247540678666818543108704882000018688053575 +emodbv:-65981,52322921017132462944466357361497012903828640226528286241505886606240991940,6860675712258835980250189932649930728660081530947837137778422333201725902,=3:2906363080300504036446988558153247540678666818543108704882000018688053575 +emodbv:97,722083414477046543323827919190746613044650946730035622684143127809101386778417,902091877810352677182715503592735762990564598234327398914965176599990501312957,0:889212904562853779260747052184064517476716523608339827860458031582708193206654 +emodbv:97,722083414477046543323827919190746613044650946730035622684143127809101386778417,902091877810352677182715503592735762990564598234327398914965176599990501312957,=2:889212904562853779260747052184064517476716523608339827860458031582708193206654 +emodbv:97,722083414477046543323827919190746613044650946730035622684143127809101386778417,902091877810352677182715503592735762990564598234327398914965176599990501312957,=3:889212904562853779260747052184064517476716523608339827860458031582708193206654 +emodbv:14402,889596460937768611931054045254725324526382425729385974856938469416409852318416,413215704602709635472010830875436175038307970134522513046174307173871669508560,0:104803682559692025313965046839630608596949538962860573954122948467983495146496 +emodbv:14402,889596460937768611931054045254725324526382425729385974856938469416409852318416,413215704602709635472010830875436175038307970134522513046174307173871669508560,=2:104803682559692025313965046839630608596949538962860573954122948467983495146496 +emodbv:14402,889596460937768611931054045254725324526382425729385974856938469416409852318416,413215704602709635472010830875436175038307970134522513046174307173871669508560,=3:104803682559692025313965046839630608596949538962860573954122948467983495146496 +emodbv:99,8493623727619953417006786660900853391606222188523146978954842405502498519883473407,4395695171072375577893478210289361330373272715510465055402419083612471085598332551,0:424015515432121716805639629631123704621802071965154851362821400859180276022226483 +emodbv:99,8493623727619953417006786660900853391606222188523146978954842405502498519883473407,4395695171072375577893478210289361330373272715510465055402419083612471085598332551,=2:424015515432121716805639629631123704621802071965154851362821400859180276022226483 +emodbv:99,8493623727619953417006786660900853391606222188523146978954842405502498519883473407,4395695171072375577893478210289361330373272715510465055402419083612471085598332551,=3:424015515432121716805639629631123704621802071965154851362821400859180276022226483 +emodbv:10234,1051224206889208437707543309847268354783435841902933995610637335945033847480079150,4516946966290251750303869558083241877020806554744607936820399513223609959311256738,0:849166472390089324447217011402258926811127602345244477949055266800343927988355770 +emodbv:10234,1051224206889208437707543309847268354783435841902933995610637335945033847480079150,4516946966290251750303869558083241877020806554744607936820399513223609959311256738,=2:849166472390089324447217011402258926811127602345244477949055266800343927988355770 +emodbv:10234,1051224206889208437707543309847268354783435841902933995610637335945033847480079150,4516946966290251750303869558083241877020806554744607936820399513223609959311256738,=3:849166472390089324447217011402258926811127602345244477949055266800343927988355770 +emodbv:-97913,19442286442113788161533739473019726186734680244198092166982349591752956401660637629886,60558965367914554186920892629719688885314609703455963977845612750271884481278417471936,0:39492300709350508322185513215823770925957483374622610701455481874758748756164234825489 +emodbv:-97913,19442286442113788161533739473019726186734680244198092166982349591752956401660637629886,60558965367914554186920892629719688885314609703455963977845612750271884481278417471936,=2:39492300709350508322185513215823770925957483374622610701455481874758748756164234825489 +emodbv:-97913,19442286442113788161533739473019726186734680244198092166982349591752956401660637629886,60558965367914554186920892629719688885314609703455963977845612750271884481278417471936,=3:39492300709350508322185513215823770925957483374622610701455481874758748756164234825489 +emodbv:412707,9654411174124462824121691009690247581683736939421066245039298196306676684767320524766,96223555182229399707506392013582768244824407047675765649910095793401597173883674841030,0:45372936066320285565767345060984614982597172133924700246907679760042995966513245912459 +emodbv:412707,9654411174124462824121691009690247581683736939421066245039298196306676684767320524766,96223555182229399707506392013582768244824407047675765649910095793401597173883674841030,=2:45372936066320285565767345060984614982597172133924700246907679760042995966513245912459 +emodbv:412707,9654411174124462824121691009690247581683736939421066245039298196306676684767320524766,96223555182229399707506392013582768244824407047675765649910095793401597173883674841030,=3:45372936066320285565767345060984614982597172133924700246907679760042995966513245912459 +emodbv:12,741730540185467629182772356182915322420038008123799513890071646651307750673565730651787738,866338890216282311653914599395911124646576595981539992209095900511097916243956905636477652,0:597882447446136206020843479948282217243162285637054743586243300633734568794892620330552220 +emodbv:12,741730540185467629182772356182915322420038008123799513890071646651307750673565730651787738,866338890216282311653914599395911124646576595981539992209095900511097916243956905636477652,=2:597882447446136206020843479948282217243162285637054743586243300633734568794892620330552220 +emodbv:12,741730540185467629182772356182915322420038008123799513890071646651307750673565730651787738,866338890216282311653914599395911124646576595981539992209095900511097916243956905636477652,=3:597882447446136206020843479948282217243162285637054743586243300633734568794892620330552220 +emodbv:8,813766624733750918729402656599354295427509394488660812811650986545042142269515180033877242,550175086096078333116750486296504860969753318764397360672070743283292590583724934273152632,0:187419881697087928981580635353669700411908736518656599363509921235901203393697886905365360 +emodbv:8,813766624733750918729402656599354295427509394488660812811650986545042142269515180033877242,550175086096078333116750486296504860969753318764397360672070743283292590583724934273152632,=2:187419881697087928981580635353669700411908736518656599363509921235901203393697886905365360 +emodbv:8,813766624733750918729402656599354295427509394488660812811650986545042142269515180033877242,550175086096078333116750486296504860969753318764397360672070743283292590583724934273152632,=3:187419881697087928981580635353669700411908736518656599363509921235901203393697886905365360 +emodbv:801000,114145522324231651230586226973102509131367913652288365962855153489305948459500758622220373494,8212150684625334058669367564240176539694293339103530693943836047978102455985676350366679275953,0:7455082526360199945904164673384849878483828122749940095337812295059378328144102232203949899838 +emodbv:801000,114145522324231651230586226973102509131367913652288365962855153489305948459500758622220373494,8212150684625334058669367564240176539694293339103530693943836047978102455985676350366679275953,=2:7455082526360199945904164673384849878483828122749940095337812295059378328144102232203949899838 +emodbv:801000,114145522324231651230586226973102509131367913652288365962855153489305948459500758622220373494,8212150684625334058669367564240176539694293339103530693943836047978102455985676350366679275953,=3:7455082526360199945904164673384849878483828122749940095337812295059378328144102232203949899838 +emodbv:6004,4356076702281400929632220077035732128644497158779255978411329856643749667337069276902952019149,9051311630305921790132367949451008467412252240244679740653218546677567374795191493091691181895,0:2157703003465786984862106104496545852077633747681111082485733289488843538802921375640668056154 +emodbv:6004,4356076702281400929632220077035732128644497158779255978411329856643749667337069276902952019149,9051311630305921790132367949451008467412252240244679740653218546677567374795191493091691181895,=2:2157703003465786984862106104496545852077633747681111082485733289488843538802921375640668056154 +emodbv:6004,4356076702281400929632220077035732128644497158779255978411329856643749667337069276902952019149,9051311630305921790132367949451008467412252240244679740653218546677567374795191493091691181895,=3:2157703003465786984862106104496545852077633747681111082485733289488843538802921375640668056154 +emodbv:0,30548046408595014443777065152533771761923897406396584855544289351015617211853860547293440287163118,50202684952560017220443047936445752013986984883181511511066630902828136225792202716788767660488271,0:0 +emodbv:0,30548046408595014443777065152533771761923897406396584855544289351015617211853860547293440287163118,50202684952560017220443047936445752013986984883181511511066630902828136225792202716788767660488271,=2:0 +emodbv:0,30548046408595014443777065152533771761923897406396584855544289351015617211853860547293440287163118,50202684952560017220443047936445752013986984883181511511066630902828136225792202716788767660488271,=3:0 +emodbv:946,57785774765671053291569361256480674248716110951095880149104811531028000846825692159030869973707804,72826384755153630829606521208326331712119423387083844442113181771232731949302549335896184427699629,0:63291678821403600137229027314563244771616884878395099760855279589610716265728494065685311702593475 +emodbv:946,57785774765671053291569361256480674248716110951095880149104811531028000846825692159030869973707804,72826384755153630829606521208326331712119423387083844442113181771232731949302549335896184427699629,=2:63291678821403600137229027314563244771616884878395099760855279589610716265728494065685311702593475 +emodbv:946,57785774765671053291569361256480674248716110951095880149104811531028000846825692159030869973707804,72826384755153630829606521208326331712119423387083844442113181771232731949302549335896184427699629,=3:63291678821403600137229027314563244771616884878395099760855279589610716265728494065685311702593475 Index: contrib/isl/imath/tests/expt.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/expt.t @@ -0,0 +1,154 @@ +# Exponentiation tests + +exptv:25,37,0:5293955920339377119177015629247762262821197509765625 +exptv:0,5,0:0 +exptv:10,5,0:100000 +exptv:1,-1,0:$MP_RANGE + +expt:-1,0,0:1 +expt:-1,1,0:-1 +expt:1,1000,0:1 +expt:10,5,0:100000 +expt:10,5,=1:100000 +expt:16,2,0:256 +expt:16,-2,0:$MP_RANGE +expt:9,114,0:6076396096647706909168138770838836135530328017648434830996201971201776350890241322455818405320466786549738961 +expt:-86,476,0:662617332696362860524067230796827820618815284881665908870595313490845384402730799402221740741547892729430741053639014274968962128613995528237195069353968871860065099842959580048834695510748974202424908905352730826874949676923389706328585129209694843598031316497606363273659659518137129001683914681077900538211178870670637655474948719356656149928857724507047191532188701873201466847680543186709462811132458087950485580962981785390351911145306017418845982546035812744084364382432586452339098567898296989357418159116783507112574874002896769395516552960579886303506398054290885811079444534809660731243125017742263312078176886504861185566719851630353701862941682854137129215263285153620969438652988427729550528379121310832057528645876351114476064584186293636620546183047738657594287749786268444920697293633564476272776432769083439149706832453778408583421346390651383448852253784001810843070684412323782386158601772005993742336 +expt:40,238,0:1951092843947495144613498268620728941092873839165606969286973099765857336762353512575191314414682481974891831950879139309654984799555178316431360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +expt:9,761,0:1508515174935868832740908844641413400230908698282014024654729092918735474326353646362638387096847659573480147230064829611049820323852929496264239478087068540642226919569780605621815548160687919464946810325130045648382743363240874672014902866728521582870078261816669666838432797381766007612134725161586319767428484319859256110793709691241551836459283171491322903212579581783263716842956174378353601721913353516686324030063352338083503343527729254306613462747468830270057853272630516028854927235895950242106874919224742672988595490274178820331573555174825456815488479104792855190670321093410569224479462267429452231735849215995686173314732407799996091669536594590589720060331368687564979078136565140955509332862196370159944529609 +expt:97,144,0:12448864341302864356285624793135454957839907062356377399873019819913674333304037397385881749787740378047787615516124593880867160513889753519548772992938610862712907794913424958325207507075928443769586211194132774382517001523776118917770065797726717096819996931978519564039067219497326081 +expt:25,122,0:353737464016668451855824972300304366432911374927310085530570894138105520257533012294512947342224925759920017160034290220932919252862236536572027034708298742771148681640625 +expt:60,794,0:71136550947732097223049080592911024204723415862845308040389197768507697553695725763485652390828706079386079253286683076446508807986344183438029484620306186446936364042768259107355223169364392353311443322952870623266797106042061359252992933819289381215897875409197357921675407844235432207568030978595888122411284106189806970016530299277993693667005155741905298746901362592844010565441606260646610040560804127639267467909340287601194961411351728753184912061106832973826776921930054951881992593414738674333726484856598478050587647451437933451435999205268943471465348558111458293504367268910731207434743916849298071460249600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +expt:77,531,0:532813311656570249504626338521175986931059533505926279525440059983661596994102351537446926949363360529365260710018282274969608991708422465645470353238950991164094603760337431471373797674342466447685331328334896929530869521639021347860305641901746618212067382436047417802334922329714967747069071224609067366771145964345230898570999327581370275837424654936614015736099665593408214589717971837806254491231718922616012680565189067437536528526576020597271981783296886490561985553063246822960810078500648480156559918530508398231087164252252053517193755387712164533565474034807917780960207694570186046344187446803758345139338159388892261095589551022214765624192005132067602116482379395414788544646979450596452460362555591887638135655580299669062424023518502777571809123694201495640270788238169354113138409879326088017367705387411669267281998186298445497315171994082486321864442017377055208040226703055135151101106282748423896319916554310684705542590586019379478759401961042716809342108506273015769966750567573 +expt:69,147,0:2045579385385676298810517927458702060863220937986515106749791476657551971253912701625142580828008387342063850849956585037595400455275752324351745210872040235629033488870814386789439565218837255775426196335872604764004481418507627655312643367630027383681234193549436923389 +expt:63,5,0:992436543 +expt:43,146,0:30647461956799913663494655425076773992386225973903296590660647835395776515882377986142610962128804096035118305690037018948311119864211319779734143116465886493057052663022568542180068531441910862918530533350093865623799781552091321941805049 +expt:98,726,0:426708164655477000890275450255347996233537359230825603678068055078572185768690530483979279727883872477967005148697167468182222427688835250730805216703200346494527373336005252179998129153425179169405541975856774474069498366622503869407903427510194050762239470842997997171904492470843168606219304544549428357468779947949943413206194819154200161585559598504692063910328095937302046813011102683058231640089632368478947866970023522346778845648102870898031392605132459073175114548205304577635185214718149330416992983890351407166804165953949747506605647268028309196988233767305361741291382876521135508192965016090404300931198517364604358975250384413502392769253607192796721507324069628343907393125548382919869819440252750811077561632309583741878536279703230000857054139878422446147127180603427708828429704600917447413869817618302245994562895269981736545881770397064210337561050137140587310204526285808818450640283721161279575346308077129128490827488909459752308152575975333376251163648250120013220501057296109952540925755870893739088626118741752210805146783700608707536622996922837160677398003341203351388553480766110431344123182677789104679858022371096216510424982048676315996005859351101823572640031789389690671319495099716878889860298319419347560159622529618640118175355266744662407331598655239886273495406443560838728384648401252398353045183922227138034113900212648350987135932227570141916304732230558988327877007227972193394243239402490072781553664 +expt:27,994,0:5964603431471868470779586030579897508944005422481111504996101053704042888070620658634603446892718184220478121160877417420632344218074218536055055853341137441998294000251200835878902350186488825026483460943513306200517889603246366106853840145090440733291280737628836962672475155047075274192277218811417069065936482209339531226972570820904792756362193437359255260272908936652780579152117702725740119749377918245976402017781340294169531390247883611378505356757467342298706583634922064709088257785640184257059718176205448907751675016209636121926542527171904829380257098579043693273941177601321704542520456253669795714215535002523967268853493688846286706973999035367452588515476784419866076998252005842676395279638218578241484332229406009518807659452519350666942646794806449473475747553767493845162021519112769640526941059309326051192732830213515976229333540580413722595827300619108280969740698513378110488385074544619780641948295405495780237236276684111403379203230366783709039063472719411695740144082704697603632985497552873504333474571968038639730745252032873211100978857900893481330626200727251839567315077961576806464237728134101031182507236896333266479325934856175889116335417594516961071359041380154522292684361535083826965209299951003822498563135386891475232447007531309326110170827274814394069801400172716308094800028763449103928013302738446528312264064411790429063607977721347425016445446736220565463902437544468120409 +expt:-34,885,0:-228476523750723373644687014002375633344738959573253313295673378381427602021772078020242635916606956729056926140060033073714690114938322706601446752472086204645016603045913330963730961808178207763215017501900858842569395980296056740108703232651676106742955978639790402346938757058023705396206982274162272726053788981662544438635344871901487308331092875364378228725341155111018434010367438360637105101040524061771063338296772106596332044158968115550006262659165852163296710243618168537491315057352543683129215465809356035846400682903175992116512861339446629911475952731908088842546841550719832093476305343487020461708563559436380209360381168143472508064742652734842472679645707885058211800145889276047957973692059807305288049119319173129319106681652756562743739107763982095644384826187365922752532925851190935179707337534386963062100373634441547376770817028643050332728353004280762321859734138238987031675696783935311587870039192834643563874032592612926869623391797208269743645539702607895028584122500698098111011232061951530722490246531280555160067707338914792416989446928511604549465504192826378832978906732786898284995067855250035120805001076275382922780012160428673191761070264969953411775690292328243025746069928396010308859738310517827535649006402912255952898688436528776249218886864180489977578374114695105630836780908831245277680459913198577305780224 +expt:68,110,0:3766867964664544159080663337184475494042561418541340945804586832720994284771961635397385875362345125057120310938269750846083952813873238584240580179827028286414766076572917365783013027168357407600410624 +expt:53,658,0:3745606907993421946887439162000086810348803803092371857142904229709206909828318821048723175183121197130197244352493778939138463422250852343527134762386848777080851567505679505075345465770806895721134211771274772293259989505354294489544040145546102855689216456038976289617392680444976953405298744483530421163275053596226349987392709474693470945596072586963883209895508334043197301264236788171635960039858646321742025220295519025375907766179640091678782720809671950054095805941850551155084902979965473850917202849828979441725255702684409539964150439149357477472547510742865588406211296859461563407639715931477329008440374383580709783691664845736383663038801784370088793404842551953417842873348778874221805705399715354432210347494670220197359227112393213208248173978860627750353040703341367562548515958900446957626661507861996868491462583136836486757565972785201597859791653509981302034055855843211266876872054969345931382022744508783063231741810980521737612696916450990320941990166412615155878082383699204415978877720954451681587069814429903479542778158301091332107305065103043241495237616334706497558758024048371354995778381078122856889 +expt:92,804,0:7680919010486502611899642593747149466649196229266501367711103750663463292831658713415279184569662244175409947032999989257086334914196151008717155913095724421214123565414211404671154819304177054262624540117568190722055697928671476680220542928701368559838336428067111425536616146489821648041701273110577053706361418086034761443472306518865080966679098105467798346917600554685542898553062250741733411314786612840508881986382144004386089851397484105951275595996231115064888236880983094071936561219536816852038032287045459246026554363716223803369919418940349582736218979681160219265039593199424543894793508283019529562836802500641291446928979006411204413367433175378170319515975143760263714327381242315380104084348844582613710587726111048178373881327576604839032050152609478011520362808140313650631437624206065559757026169586967629556330683105990075123728304036555187713491828534603673570621146978011206391066697511863181519910465645525817216154078233941728180083417123747740080789188156807592630560128265705528875621630095351201299879483799930273817796360416169388658060657506361895914025279478414056917576529844826749149254978523394656765480215719926358133890602585178838119464948003289948380599052143243657411917203711988600003537438673472852245599607482384889722702462622774797489957621592414208918554109594415643546111991744898184380453126034201383595790269274373055123173862494511611609472258838476906869425218506801608515950342031211116660445405063954103192171748610888916224658384554763772392708457944737818761788668778004849546835031715922094579082757147279920864952420663296 +expt:-93,17,0:-2912125755884410842622249251854493 +expt:83,344,0:1455002626766365151331492634356788248715003383435775455996374149087127274539469938480434554541764208550166395886013614290542493336553727055035200479566375122407588223498846894540017410056428775935861377005037728217969587830322338737768781971954310027112710091083345708154562101156949905590633490616529984721229205694585229393810736667126990248301840585766896715156041016184889232474489806021208434163212143568783993412750969879402550558174816868622343662524065027291485375058885945026037942093663550462847296831559200222610314374017319326883901944196944190346470731947264070070668533749087738060363624871768516622722491132752341069559484881101460722290741607521 +expt:37,509,0:1639372139330474505096339736526839874531950388106785764526499216811362225270703761672667866735996696543474964780972938761569608985235961843219297731833082892285640739207743839560976358344004254125552207884861967683494079795135492763316903001285669079285642352434013330494551450924529881670919372226435491663678910321572802241052671829048684593319302540499062531002552822413972447877352398056117420144161447269350831919710819792646829325266226815447766753199630288869617053962763718694151712581758666586038482541785095213523640877958314344476036711277346617174429612617143676944589174538616885971879400465341144053670575443367839317972672752212894927196448994763102499581012815364079440761668903982747115134081448923972310533501089520501466675410274312105259815806872362946932755486301682363073385077 +expt:34,19,0:125342809160496617801464152064 +expt:-76,29,0:-3496183156153757826996482351208459912924449087659442176 +expt:37,959,0:8043653985532953716889715133535087168670385482210859421739682450017285673683111089377825581114293665656145651712345850663980083336468179806875814073857765425892155354598266669506804046627707739916500884106198506997527648083295900530561613402364276614913200001026056509772329191449641564220726849838723452604518199139241770839665976645631344667870833619675231878104275459443798340311110952188496587631537611487174398583536053876742575306117395796907118640363142612543112228300527887243345970257920772909373983605623295787525934506659963651305156708304203030998266284694349384314377300558457176325498546062335314396443971466680283426513605059525173724321570541512640520991258079091372220776160186495883992700218975056631545666177364476484572440897669270951851900895176798423899545287983761049721641455850562227655219058197710285516766496107629355803471562655222885223162182968326669241365735898955624385521019652649599364538263697078170698660931177959033737136065046900419098588879986481831152277650601951389732469419718135458317284510180252252347215282909809244252103764833246379696609330932880474725472382498914394849425766909318546858182860618752740997875122661035517690985707005948901199463714885386589945448510035753998020104333298915321476036121567051616071951554677670098530225928071546828420949645455483886944027286648764164718652180618519663834711653112733332792953298854502679756506895010313106988391740237915628327936616978344717429852330779137901687317622168225757826112789753604087557655040173 +expt:53,855,0:18024719238727749739525445919483313820179132397627088793412502725451984940695378279438673546750025166612239273512610516827961724525198882762072448802914929186534874689268838685049338395668464648214285629458942854743809087942072596640624011936285554457003232121031929203367446328606007087882829501707445687372318602594007967315081778231244881573239906171935915143655956161425143440493226007667195047540127725460951375078510152848109086910835297918453026272054497519156136102101888168736867868647822194907272146486388416624265152334316284765111597489635974901154683366709520639989936829700879404498384693571443613183789387222654028458579806593806268491518181218800476712301946966270100813204092285152986557168694900881657470791233632087214162768980287038944834419004548322680351210051534951796722585140993240046500305409149666028347813321755225701104959869144974670164886058856826565923628643498059733335090448195444279918303399796642120257846094099858071377352515014517392246807264485477604806428498201472579832708245125875380579584993781814239835479412029038694921470435633141289405105409413524512605572562361133641297988371189750573248231052889827586537697292556993264681319509450424190822893352470802584486267244129501288234774550146263799764737409541494978039756256344516245332054030367728222980738023243510101784709043134443224472285495023599866477956084806532775907376656412097028192665531115092097120219791652662455717002643200873090340640713123160526016567186689389757 +expt:32,656,0:2389933285405466860396692079116393607592094511377675771193917107985577957215786660857642782380647855358562124487585166367387947413551391813528167636162447060549990168729176552922878656050672076285621550614985470720664776531442576135048333979096784310286244860102378967371399286213595759636919115966603400112237639950891727815590236647193809310063401704857160813929322419325892381145791656471799426867797910499315367811275543479800432663111156312795121794429616492767525864645383481760770859827287365500386734880646418760089786239708463669779102319740012320361344177543946675529942817886591133769700783852263121450795052384716461322528105766425932143907687036561966697338295352111191252732978138183228296826658380107463086196091321472046087589204515401546744232072241940768351560772822305604027448970361890755796703363650465900018004257276623522292065343862084678326596045941765842024484410215769394555885885158749838834979597158322722201614329459219680380702370857126529706245613395378176 +expt:44,825,0:705436783209414656391711687641131832457317079567241536806961190125032329799945689381531828701711922651328924171833912445806993257740496413957550233738157646707468341476136656655190568061765250287343123150183203457096310554778580693127605900054156781937329687900011079033154328368560570397733837126414151383627725550551123061599523989519231809246838020349444255196435779598286912941849683826803885007041497453499648698536652839190738405213015416967571009307605140974000980854307563054593796685305388455731431361267420888839574695702395994221207745406708122106371051596919061007969322392348313397932391816147444777599673900815310461704623664643196151052250877625946280731633882993330125061545681460076713485728798412351901806167839675417726868727194522011871552299094826966964668768915141255798918499796543486231511141788910147145213662462426979493734390203264331227425018827335966699727291310495771236126927600243376852048316429905244128279916690719962985233688697060839371456481476421673214751905689846742695604260150120965796700034367974580976289127610455139192549104607458487162099297483432995551188890538592998367871918611578833922235492029074979130410421219592032895629208451572864516745372515998761341772487485436904736855847415242732131193954436562666516079556232801577061434743967882168334814393918596862293538397642429151346165775119942485356314624 +expt:59,114,0:7535799365523929401466950149815776414046724006436301251256273386014282698913901410854119082161738764751825402834444249521979494417181418024031729730875375541703751272328798861158409927866104969176716761 +expt:33,638,0:648475603635833183196469398829966467819872179533313634773199294300845287950459501715005525988291242251589147926178661960824082441163194476232580397116885117509943674289579029366937003306245475847226805096473463034937358215125841547863811379526289909390311989707533329900551425869234787887523054960552278032611552781528108935648755207909825160440738427953647870234694868460377213725626413535570112216908805974133165357493773798997957325074032229891071788781461177535131032268348271529076288914099185644193139733366057736098900551638267073002144185264974730918597301702988431169584478969558388865801487275460346465072354829295831509446111012459075308582088675497358398567086973619837648636885329011064845212317340840818123718736632174769798597171923150676024529241760831961841633158660369965791581395332178142007133509696793640532076763117981014872625633261577688978190292542653541593712317454035995088612040333001542622676149361438454964780663603604979033175966419868609 +expt:69,872,0:29950710056653639866040347513592954608907832187759095021784612336213340883909743941015111690452867673342534673834960600259673961740938823369536279442812481113707789275256589878997231276618632636210489615929064857400027555434720369902556432133478971302553689173725290340815598949062749239632058821352962601488612707115779689919582783658366139458929359238601369623679788087432179938746909197524719589777317181141198765254386641701187353660512871784711559256412459533781485842843404652110331152933616653843115472865088192382607300085255939568539834001519100403938776165952337332146706473461537817329969120309309517770547565346056282486046731066492332789904059680738904349305243649494763250736765491708310216396673397796961838301667209428954933817477191941146364618594356436871426698169064040813675818513426197050972194802492745959927175153699196273914186935407179377493000883694252000018528388345695513167889176432751477073481242404466807236118127264128971920247017078705326478921858295937254808875182604664522156032745827731392987081529736044441817762936554493023891039839715605648021019219907116643520667553628457465780133403776577685023637262452859732368262675698820414066865949360110605575303893868842664652278685058236518116527393248213186175036314144344761002775344535262642684517202791126837476442938864508396830200526809879345482138492481769343790209140327431667550761817827241581355415614928705123841250085260545474358015032657030444618098608485724932887367556645547344897117535819883458173888231937264034262930323293309593162187140783379967834211500900425793093911669240962055595069032779064523361 +expt:-35,560,0:4765460083484463473472807029671198741039814209947733085375343877805519722128264213906493004712395811794836067456926301347831701213543102558807372013840371317686389493491044956157976970854534780866809198779109650495115701056756779233669845873333611352227016172179141127201204621485258250872410797565587431587955801098712622722961241140244408879022252575756465947941316439513115927707432620645580331357844859947529159485059102032289565818525572625258477572647406049297215450764812141735725360033399668564250475303073470958824427283582477027047896762000913374878650247253682919902323190143426951007619514663885034098702528525398380830769050070744862297092823136092265705202572748338959960458521661389246148014773201598614888333659845567286582320269709906762495527111679682357140289756441194587185256840255908734955659782455404151202404960940839373506605625152587890625 +expt:-83,209,0:-122270392573975557137544098494603104038431911133401401060669780228862020091902727664948350712829411551252088259762269665003646460255858818493536471916081519810436077327712541465284264947694222413222906768064481479603637285266239005383584918898692141414316852928726367305370720092433674542731019975979821342341530442634729485864001750080837642935553282153040722532849483710322964546566862518809499408403 +expt:-22,544,0:18964367700820944190420983771842117471035813402172302356001324232625456871631696158159426747244273988396896874782255417862295115980915085588836421854267161890941876064963407590082206716515749082957670650572915503706055302390446576711188138153431530926911613355471966093726010812009574536833618487020923293412479710272640024885745749390406182848296906282562712038022234856787439331540733410267670953621778020862196051822262364620284766229990123269618359711309083829625146905646383609813594662427186141810814135462546643373090731265237443450146344536874441550683786161973931814080708597655835455648574641882644636540462283387226460671638812957375987034299333511378035037854459892174703913394380151030879671916383365880966083883565056 +expt:55,53,0:173469266931818817701197572759460512158186359368276122994156906997886835597455501556396484375 +expt:56,7,0:1727094849536 +expt:69,511,0:4486269579432801228328894978520612039865782962773314299890064827550076871686539386493998487559513347930912978842976457609693197201213966463505628022312395013622414842679517721662844319556038654381323108565877674965192437982575193911756281655521858715295957459295213878788866632588753200138937292160832095681182024559479348223221677348390842846953123958441380139228198612700886931654375724810762399664286697632157511028362743434949776821972216621014709224808699213105247588616225388811148034573781049594047599184470666181439258133413347363982316136095491031694475463436444214376593921337732387516213520549630132463991049105936530704212604782416902497080757979392934118897752584527916561354795284032980721598161111294569421622420394749960961723356836189382523894823797755998521714994563261231632958790842100581461483738927484818446238271808447886746812572795337464271466846423907255769829987902959874517226021350215314613561013455027818736269 +expt:65,627,0:497364306835738758369203816929587563621484908670308464881508611000120397210171552818133505588600972283722504217038299267610870712281857521011539651202476710112665851438274405311118329759864306530206464076881590237702559066115100823897031634086082484171733231579340629242599537765843919362377197750957150409164905009889637997973633002262727089466214411540563439873655647562353181575977350122226034217971081813504998125791931120734615674206813835553948971108562651944903797187278504359842148559086576885512335220747304460608200450624832543393270309192761368009850923893828230888362356748911750574377927901251690822238297994571714786631993517145675163841742009468644933432283278288658898061814717433241276039971839163707090134740016885115455078319929919984436448696758395047545344494824758451226738937682595385197871210901912587652241955896134593132930558535330562369949669112499207879073779991774258219495999580367039563626586056205306276658856886524280676036800529831507826841752629258128889348309920708180393144270583624503924679141781718886992556665276474942605349507318130943424722182510632471387490571856915266835130751132965087890625 +expt:46,193,0:817074232257484121156770823318605146696751569369000241039998457282648867989095210690478016388511247325018574872571127938218392125122241277384005423186652367061816702091193768108652663491211481548491110769652180143820817287796926886145903321477727282551759124806922035803851540296187694499862514735119610739703337122267136 +expt:35,224,0:7434331703617558866735418205564382401519158226603733006962337038114968755942018524978551854012503800960010205708607955416310926336526408147412201804428417291385136369283229527393145734163012864208910675715691737778124973593953966099385511183284037573029373908498077607797410012638709522747893758502294434854784643817993128322996199131011962890625 +expt:48,871,0:2296771307785108997996275281694403742355413375274328510033245315525621390174696501258885481415349678804771928342175537874324074456135373852706084607201324469163233145482596686038350670427036741247616932972355015054433455747986815070761138607427191348086868570458350738831195704010357098624395027409387096510181101959230801667175083036850637754119339482591099632372672743060138882768223599588213396264220864703488219466055760560916641000944392297133620617588807928555012293449584277763904964488395570608415840137573373251523555726603443441113068235906294848808710212674698053441585803096252716528906610961258208381697805496015211611434136696039563551082904259850787494200559601774616526509976357060921883050658747159151714704641435607899726584101580154243983256304378508592421407973560468995638307786371450739384529436653347101351955239349662908173828605297840447911481941092339861863239287090444745959885402693797565521445366949111927811171516747397914656348938374407730394789915004848099910670723354943700564628811075303193718039885360453078287438644715151039299030827041903587917146772156422724773803085293734569147130667846393861058073699252566570823424630289221233864648893789083533315907406376875479011330114253420148543906354793351474113233267966052291368733321678620499879469220151506192717633536571962409876554555026897490062209992621985629094620892105629420732687045223957170224155835158216412193474005114831859911410553422254858147750406913717620915044352 +expt:-36,518,0:146115200201244140508535808225340127069092033074086594939641038813380464643092784368499957960397457415719662913975450241240449832879511228597374618467828990096974163693493678321796688824401816250266725231269351174696889365960762080267621636961848851793903147492257687807404324628050042266187673582798121678172191086987308854792095986157320245166750739737004704454814011348168427466038007182398317491734265151076778063010496132619211679988260689473089297585811096036931998406782027461402044049893679481715416361137493463388085294521529831982907701884889345802533151813498254699533482401990075682782757616061340632427940899702653394635849940302575034960855494543054252959646383879992036574182030574286127878688271055584323109202843000534198573252028967226364808637164514811988498672481692393863899485418029056 +expt:67,225,0:735920003111339161159356395080570801473725293860740494275221824045023812579963935301031775447575688346607267267532812956137018229766093126468162396242424350409934923304882749620115802577608721780903966951407943056069309235411902308234969497397301699503940488310770219419812977280307849553181552764429270926502167344901946040611637758836796263098836023546748650013560091709744036462304218800125741698559917914307 +expt:64,327,0:417687513717921146683814441049501323149276759827878850220310682498444752633939174795763205590085370174509431176916209651043434482148970466887815330179965962230671681555803952508317812856112304403464539027712767146228053984109968456131599036017965241520523692299911631594821772907828969071619810063458617810626197420731690747206373943510385502671614727661759398749224149762165354813028102550602008280537871902180618847076481978941607093146933705617051198474299205992992784680935699867987139285893610877812099445086372781691711812234396546078333906858033970549278924593901475494268981324283904 +expt:-25,467,0:-68862700495331938784380419966649877120052824256986622780279879321123463371356437053662605722822371713113741286131261775228105217869324551668789632411755509078456849695493437707718952335537901163716308200277822404533843040793058284766310091608343833157319217838813156052838258955825903648017660766106461430902101129851205246720686051369993734795826264711765354552138512394382816264477130422900505062094863105482712026465196187406241972801187592058303442054845271865009183194933559721460674706658198949275466978787964466683095692914947643154576581856285051087744587327756364233631868758575460879749512993364615070536471908013709253282286226749420166015625 +expt:39,139,0:143873356853696095816280231561762895966095121358512894018038780434656905244853021253466390417066964861759354168210279589225963338479315659197113508775296585740367513592599261280433915157811377734958643545758755017210195959 +expt:-95,925,0:-247933317851371692765238123220353261074803765143732218785336375547364098379952983086176914411708967965243034975624089734549054262155405601872988521853631418092306768960388547432760579266561975163002729996245381862957127425938796307154036020276283894081669921750185924525104091927547088831951444593347428073211061542081598903847868922087058124406471582647813289892107277092495163694211929855009513467354559044835615466736137087947544617589164470286717500588970895846757222008275492885619438633488692498481179512599142893182301567662753282826824205385088400850355763371781678525389031580015072637605912123616365008472820886799996936155624310901771575510951295719809269053623900174867256402312047226014214451002303098027112553312370656182542716538763092449820889312056658510682841044062831350452293919927832336800994362138064805630261807651118108456301725299789286301137388212766815512960048788081683942442538085959986120065061285006871234949930940185524537103913351720159010805686696397758933127125408357428549627886466305653330611608087733791050176139563443301008883800301224683395958487326723987984535755499835378139919056198037756593511533680696923763042182818051706007416822608172896694323975433662457082439992053758519686924061393975580909143061424199971052081917912118305230171515641167651175575831760969677740062001963108837109680812905974982663520916997121589375625626487587266051342244289361033565546995111061042957242305246986582855170773641851842228652472157775674690273006693174629830847980593151580935023679044298283432329850647778394157726704922914014083180482909180414233817825446242940819724654162541194190922934651789175392031213637280829578333494425326947316977013855379710169610940508930766848830071334425047278453644935556250177705704902919191612346964146136409193037371777312838361240210360847413539886474609375 +expt:10,790,0:10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +expt:38,727,0:318181364845266673293939034580700586615440320951037592693430676258808017944424452887520229213529156147652152548660229015222939861579338359559018300102639754560937092707601655387811647657615783015052071118531074778468055452194170663662420447464862055872460088793374322229582464089946075887299294193817540314008779527867126627186841075133467621258418817935949751545729428873936316847772054961100333271621441963886222050417381885840563709089357402135650374520106690685058742735682668165890186931960150146694452795036044289394868653254020018082650676484218338479013477191914691177584198123357631992799912818573072108670426678744162041820440354139322736565922639316890634686494961802003379496237970297257659344819835969921578132529764554764775387964765201989940411202080226725613765864563543622841931061034686660258178316702259830705725064960086720549582591661146532434470239211074978214823780252294240896745420707470768467541239033990368271634631401684194520335589793556924858688944215388612471082194103983918698849904549069496888168308090987990818992745725204687937832492824270761610420142018658784694019990897837283216723902382526473775384524270600192 +expt:34,140,0:25529857218193114702174428995046692565363901687129767356632099628880917562050351316339403612051006254976853376622453913126272976393819424111873308895894292132165245320628698829331239739743398255119320169479694974976 +expt:16,677,0:154606681340974124033724916902627302485363041461934511562903250082108656614988464109648607664350683544053521938530767427600678633466981349875552123311129851630541427823062009528531348391461351902236714300408426870798081310080290256564473876678342716043349504953916566734770683646870083782168391645037091096887725074202784437995895234871118748161377827084898726055250090503083390633622079852383302615813886977424887371916745952542456924382093237294285328320534432277883419048461987671479977721049775052451336009020607051890596444709721396693315217517965349881355454288834865724272352477664124571092063711425076519590380710563089443910597712561034332057450154631167542515719607903185440744035174760067913386635899419010434568177660006643202632247398908883971060098166563478386618325197936106985114484308324182451552256 +expt:6,706,0:2370187868170736180128996880721994304027981016428826558124299374475962263011616081209558299337721916323935274576896010123644085589608182399969109349184244152181717235854411892769936008301419019510706362282451476374286734568331276868548412899353395251910059734878220922682256862053827867397853562809960786231614060068494140882400067369125402792475819991480014501511652656632709028304308993356905586688240373617002392227009641266162761580915216325822191118000345304381153590367158129348967240326861414168892378280984649126875465847201669629322152902656 +expt:76,281,0:3225666254982005051650393297063271441718814825117776170427014225270006782094402082487845256842905212014111773807699305585198980793893448295836068068070917535721168698915088215578832824619604662314479653278742492907609252295864963415964828492105414048009356278895083198343094504871689181249621303435108028838697311751040340640118912946160635394223543123655902100316582935791118589542551193090214863975492460201159924354445816812213366018820916069793903958454530414527672845513966606441240056930757447014687133057326317955318808576 +expt:18,645,0:447471924335366323510556443313429700068812234629235460450763927673222040496888107200760252341703827945191621326306131795482065495578664462850472512309208303012474749490243865165651244373346115911654861626284849310331418035860337441989794201851669712221122090746182713388579296175033571904584078117965994933295275297103840168214754293386003180820988449264532865805743450873842642690490009197041409759427844949926369573051943199612022394939265067082007558614061463253995880975471188662315261624151062500359331883381108257415114898922045511558749525591359567772810243728526346583785738997208574199792837718461074881349077212584333624940968146337548498271397497840948183881043905337007166709139932188874261432029055567751709278200083034120925981318112036767874722249963589907141208823123050935466250723940859117568 +expt:38,388,0:9037233162685752053376455537502721342270736042628911593411187820255850239811996204786955561847703657226822474981226433833893660651795689900570630384290367549695011356487125952090574619505343150852674019087633094038448212974827153618462678721327783567647950749746305048046039645769130932898726170627803026748555303885698486663393441172336532741462629794066215797431699115607727238433090103791079601594737166721617874568124700807143370244859773481280231903946961271883712351477922567791456197385467880154554338880438639750996366163411447302912395804684732748389562157940271392193893922966877712008059498487345053696 +expt:-53,961,0:-10693273783600734316315714480041535221366626391070652169481102268537307894640601690397477696258749742562195832242552646613189180449413635841376794326217929699139495316029126112610199345461230984883346783455894745072918234142756324123553503913216798272404688802123185365091119718074925049882233927864436065352441795323304595442144701951516685757397182021033950771925191451161942776319733212924587917285871042600950991564279236504812265880751815730359811693631083452415593025707823313397391467358190650783232378570454741033068772420053491342610776102390217648020227762293217888965761840533847099886723514168515183975698570560700046391474030860444256074699445298615381649814262336045393110771426131519842556272342779016381298742869204722523464017593559562643622326956756787868098747774454389349057962560351445716834035262214568687712133450404931561726575840016754345335968416895437533133106784692856314926056588599354521991402833078563695458116405668054338438928149786528236240697114627604940900558577671850669754855161031297481210200709336712927075772035987106414260818355636404688451829315745413124591033509314578360848228738843568098733649384111596453174139763494748428119399833236094765497395040014927396796803419365269517770431524291886017302139482314655716680780294886334131069691255122316199720460643469796601064562003254702066340683252320430491769624200733429385588367602550126577348991899954540173131577135256775953664267528916851026738118382069532086600634832714152507186748303140799773366399952508384413524462895427617680029976682845372011808593897598687010617459593771185880907170544507963089979836763018697440064683745136860496786467398309247801653 +expt:24,659,0:3624167720890114802953487528882213552899975941370552554329513099376544209818189786714454437032689083823830559210703982255340689476005362403899468531020537380006871571749241446843383626812449117417305212547159344386130625689077819341774113065166198322275559097572679481175645104461252543777972030011842688825307404880548921803031127032140294965934932124130451113999567382233597289101129667669422461740167339579466317525327207235602937780467185586995750085737222095672175124755623264554299753026627050426905461119988938722765511047677254959618655219659560371687805940337041876822078905563120206071769003516902911102160952293062550519277843309757303919027154659813054662466523344826296354696819676501832559230684594091362492325587744451955871184496572010101281716464201362384124303957980156819470050845018195253142021574427135662512522551131249157276857182203346963051964089533177481641786738454705685271070900224 +expt:24,87,0:1197782680101993558280692226488373902822663746844330952273499589865047835820100735571943168026820232018026475094146023424 +expt:74,900,0:203492195695385637811035038604720591140552513788947796070956567581984736792471731249691172218148855021082026970704996363773142346074349135425135963357684169839046304274718335440539737845426708166907155882416103467979779965950248991451379072444893391480544023125591578249908365143894932986279251195201771680227260763948792352936603246330319755571622810515846412833416610215943371396912549385505415900612631771649294092252136231153758926269683448101315780244106657481380278801404098349704834462242414233848548074782034341541814977421309404166439064217724352480695426781157497383082801267848091972668055615592471820028314038214611664559270461638562962083716708158789715725864674555451425781736717842336751000970187435030966278734709392131234668572146766791316051896061637266899364682542146271901296285157019816702372549096549022107433241920866238031206698288958221202218632016024210082467069376475499042527317812114570642803224866302666554372000471823903015245471090472707641476693056302565407925873424770841334676265472397398045286273466791200069893478024154625862765074269711308789130828925453589264234500803624442724824603006351547935458354176575577193029177679995128433886548139638707554538291806471117578045308611020975110487218424109419478440720096710842152057246110025136351560085959690150206324456752232548848972311293881638155478974286423259965771742724362278920613669975929606425566174524456931028511307439225074591462541836290927880691511343917965103496059384368500739378244369199231681115377111475866919320958869237569684233879998976599199774623618592008415441793489599256106350578620210330523214745293501592975212532951752926208891738168918126903740755841015125828096229376 +expt:69,543,0:312648443078484768295888815598845711939768666257291433888513312757955049368020160698630214239551072326750999792081447984468792281784366584961486617285817648690364818430979007147880947832896589374742603762111790546410744285504068124412810547392012131346756698151463417807121112731347729403260984454420384883458358195998166979494748478670615869985947232052762056592943794463276191202025608190774698452993168999008156807611820727458156566335247124610066310858249753566038784341494062081025248869417660801751147084173434635188719725442490006572202113716375420781068822739057141812677299815087162596322545640703492929693633783845458495004922557983277693860984056624336776034398970301860440468265923692038302131802660874130160823777321529100807734183365271603815201483619478837176405601832237316540578306276376458696902711394652750821782153970726977230649237363702489026445302222042642632912600454038910186382368705894343877258931593200635310200405119407405120535210771274792854910251876704104130656951309 +expt:54,530,0:1474662736655096656312338279909177255103797074286295793375027509375168436887287143309336449315957822362332074972461382683286797326877474651509739917544753283401205851132747553963526978426226509486446008694568119578399112394135310582133814792181430889458385225614364665191714345684166126923640114344412210292872490366419258147481273591304234282967518734863233094427554073982927115901949385739053040841288630681194000841739865889168738376527086934295573433603264828521334566838823869117642465232442629165125207009991732054135918621566022150672289445131265256648929940581735965044254187533327954696081027388229809762269205140612326771928146305517366531304549928582772855377825128227036208742669924062385323267632632943920240050640881476505929970785291909572050487719596150442436573679196485824822432870194747280187996123290839971281376461049282852724465409463771310117744414420026630389950888196241467693900151918455422976 +expt:-84,689,0:-673640355906192963680854382395597279844991495307708500762664884953750280820203051032786298142078133894280971340126666823703549559943495473379620456496637792111780395798111098844210312668985085973564668031838744003567469055747069065192031462953751775303646522049111090958707099958568715666445558819096127800586726116121938372786122995565072105666246516054767846555535819145164971484723840655291769178603047752590255749910890559652661832177657587633043896917516743806552357328358607488168344891668330944104480564369749820890670196494165679972464070728580289276173364888339312490946125601330630747303595303211714451602985604824640650790788957226193419801364185053958966373216314087383429341884277698769522842899547363770116372724893917923171530322741674875748776826251410886127808937300207685295104886265377799994629948453289346468117865398420831689205702265516443957514776123773586799797709730156072453168535652382546461520516180270928971757408912398951511864855349540254511900269624608773339111608340753334445558782955747228498729808997160178550956563569619227991188807243565793371441378712685201693989991158958417406905444641725997669829449050156320054612300296488530139587379779862430775560465112395949278438701569138898951204188270163608488455419654051297485964746817157884159015683507047747566104920764542724284450774974464 +expt:75,389,0:2505136873002946052821571944823592082408787982442343539331511593683631375266061611945471197761357031711510886915023731134485877973866520759948988373363766768657863172035979520149693975667330757807327190596028499425293356360109900636077772084412582887566894237468021689121483843531949402500679864184300241610176967959666214567894484564567187709777650474627724716339736193918464027876178424957702442801379144695328707996397566477572403174056763614383402310541133628718945533392880172251145025200868578667966567102968410404698307362393252463909620132842830908725719886487634875664806284931154944418880613973079280757557147546572939584559289443428088245026515302516929139885052576138027479661467278315711837421986274421215057373046875 +expt:-90,493,0:-2764121656403808255688998318308448927779841418065114299643004937365951143205621653706679499387531179825563949289390297858821486365687544518614573344000251044963118567564039833580386521905044421727153991835591278223063849704280112286033144210330626593002183744292468432067084387118208158609151278745306808847873085867331739532972963860539108442723664744816240576949951467742831617638950862455974397049424866492109130205243025439534284350885748646940037382914614547509931290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +expt:-78,713,0:-115731536307359192637735081399829109511702293973922696694208047458262444229652160307279087329855878256079999392518677233048314972657057388874094275182501289421919041337127404591027574520060185351444059593154392195135354268588962536879418312873113711549229994647861923000955099677819115616815194464713534830563588649882898053840400195424586032548275013843268241516993330630236304363211493713517911756737817101493890807716278347242379720375897560983549657660651681988416735332099874519575576530792228244128002461198707035814595388684169319814963566786245098551322585402939881500335265639906067916278437416968431351004007211662828198106584287898060279705437441896284017744946256629249246220165360343009335114244569954394057846850014421787925696186369699659423147781488451057285691394827566399868414895988087540099866995327706689353227627368171888882696031349643682455531264058160696858927471245322701673243300242916477186602464825933213315337095950543131154067825494224012789649177821755061866161853106394589673669448275431723352429590524472448401745233005597262909298660312513585040969384431420061687766818410927875672704386212307596396632002473179981323601609734932089290982557135462892951962999979904301332318424478936510361126749344194878185769161091829612201395286090063520676684836034985334594621505414563276756705579096792040160061812562668290048 +expt:36,763,0:287612717441501252938235364995076989912258567835194305503864222905817654453491398558770456798842563403876433023498607174234086604662738885378449834211542708982978196216184813939600530734616215970579451031345428619291554254395119224829150049864061092082799955573360133603219521595326864695021799168684562013852249376992623873343118112855686115088808687279222093858336092955998950873167464052797680801992263797310300356797391216282203047175649924968146172953919714557432086976362430640363345164555500849478372610459794623063760436116166308460356269543727122939698305973093062079308977070843850732062284240023079465164860441817815804509328285118427837803457119764359138865084351583806289107350041743083265057334370946088906064154344591975302967899967697344349561592938790173718507304039781398805086538649982989194487018155662504702768958902129616878720294795677270817445558061795402174726521022090102401668102031654702766531351739548933899772524672856784086512436602122477055532078885288888908773574437636605795708667526674002708829716332805686493462673251888541522849276838867497234297868970484972490798084656418668432596022103085029156910177825279909646274306163059443534849729765631328256 +expt:47,567,0:1200840839795357756556171793866035488669397069402218058853429523017606108853866073051675237735344222717110142579489091060363324010183030955999583202587790744873920391925268687014453103791428866488369403851229457767518484585400595793732678736929295286963479405802380386638374173162627363885156520588965951827128250889143941188182953700926722256155063001822289750113998809814892368365148536721743814094413016337848688568918084494871619775117616358924448269763664022118923055017911137842861355188743612895261789827872451309409128169082116168520009588315723475618309774431818335253416491565575448829636518484518313005184981691618323760943375615590224232297887531959092930319995333870473790498756459817363196667267350757707139114347799391414825307971212091044223074718730556986735254848581373154216006935257074685468225843364862663458199989272421190309964881842705492582909183953774649449964290445535763582719721041629607601034000766219103889698770634063 +expt:93,245,0:189811445138907350552800803028132318270856486385053418037712749975151905680839772940450886299589953341083999271531699036629608182153885935579378849451189841246877163907007586748371382526385877632296297367806278260073619502837087612560855634258114918915142457424551221666268613973872509210548656938814203992202491112249204302074777529915290725274509877730873272245110513173712234923547513758360328049613739612358250332564697958770448525150872819149530642122991079434707200113667499693 +expt:-32,412,0:132370456868089885903728134916792123229979044535154622595605894871140987448802881098535736981597853547268988767936094287847913714280410812805481072174892167662104073696464879991808809985596015029436652086821140759661740927560170521238888834410398394247502421409940705455667510851752205552056534626811618859097761109564081530555125656725768476650930897040696615149886691980619883285333853446759459196371669470109465000830819767736722846319827541624437545423803544499106306804575519579034243488673510700931803310410369834741948404811173882422130791081531135326386594346734508460627224488365883999000804776390900106160766976 +expt:-73,370,0:268817937446766145442198106557555707299852322454026359428476916174845729180692785461163460485079723744959939462749245845895687904735816865076794263717604966012182689168095690958838217033687276040045060280067207626046312195168080651837761881395764886113963753760834412127698107460752445557996802419849779908408253837884316512634805178240609167419868913614668320759158141050801534936091723675844304423297869129029497377604564133226027972677630729381553858132072499006005550335236095584481554598465568525006973584347149020417329885051185116957434174133558557099710477806848859002101511273766789849989896446599654420469118962896980442098745167512954118478569833907613848252608011717544208148049 +expt:-65,904,0:7476088006612927635813859446573471148405722216005428337873036043231186079958168234655128261355783807158721704379260915957758217822077621867500440560206384169070769533159985551483020985475710683700979236907363112033644990047101957273046170714199216404483780160537007038623527166449258864160198748783512961234393617386826793415081976514354630915756963837537486398859606568067746395464131895813501401617041983662268869523438391204770495826612433408765458410620435663877807032464442529968477115921940103577390216858052825708753864587656082968468616911026081653819514030331916018123044661418565642911025530870993821616297682244798142168034872991984538769820084587324504721191662886576517902618307361704402178724708336420139149948284282543262975792304028749420427332919952946188081580583790225269482964488371646996041495410496609499748805494361565442458937572152995474884127357284721870748060112844298373068726360209939266659158366899951921314063488385052535648321076683428148126105842193642286024992930678285755041759862538217409572268726649499499606980773383704800598813078039204400082630771801675842668399057762298657807788837860460553823914353025003459058307226171183437694740812857306950156717503856430459650244670803765893833707297125156273455126961026717976027495374263765611273780285988547067568437963799276682277771865186868699849332832741068240987335316519864763484922262355869276408357104152723004824262877136699430206518871186162960291243767646620145129860636993132567141351134152092406933156142883106133693959341914156343195330930009161411582963602590356021133287170265873006021777183311414517741244623039165162481367588043212890625 +expt:-77,614,0:2019785527067220859016075096184821912149421106403027443543560963240192036701879476616954690218222713063782827876839369054281035769658427703648498436632136421739556912595801858063198011831673005695866824564211542399160220651543556138188133469744318628351948574415103501052771273393981204066697612765091526265490864745203168780093996025480290335505689022134191478915929217289966800333369370418943444639005411560553516922153999320601289370932595922673608497374963224036658222600028845023713848177941244589411074334426669985928674891448116003285619161392614412835348838786861689490408617856711975955518135283909499974832312293000442708315178452215588031532966458821114754177230599064225634988092966765366270357352136983827262519338412138264927508379009517645365508020391394723293691499336705517066728129446273985998316873616836259122863394701325807912500191267168031985999081769304410020219207253073778474082824985837553109700468359743907719360064109613799688571311209634969765328990761517943042264537196838333401400347380897531424713195839839974898196239469825106641941501788961002992626402375484540632168133513967413294827065585616353005356965040287767941447609 +expt:-51,351,0:-227578803811760559923803665892351520428370789673508990418850061972740388632750522239984381328651663024374140778482561178630115570070474657027787117315641203458108979183298782364210915367865734034950589483411688132192087107896659215307961790261180554632888410345697285434656919490027197985190413884000757019718417174783272092501346827675850086279238576158406359659768393692045443493046761068561458216727137559396464882832268384099230639577378336557744586454311460874543212467858982205362934063365853125812601286856625659044169653638370861329579070059094709483721882329882116015560878826102047594205051 +expt:50,702,0:47527289157378995587876810145877577731621780159337975811043651439146356231936805088930037426315546580065265737582454716869456561094715587588615614596313199454696177025793364822808942384619882008554402956376005194359554004974096403788137885595666449606725010563408965535017560520176300458833774557317910487124563377753556232426423122662213885097303501569798166547963265331566412324291699762962584993997746712370064075751466905079402279342701902764578049398469516972909332253038883209228515625000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +expt:99,984,0:50702746367732423332636756046707088578844764784173362783707521133315788404642161576107293454340562078957046303833670333713130937649400178138638781061468425602312597594693701873663307101648324074767020103581094560099128401539216160840172463185716103882966689828690031541684807314202742848158232180498584873013282070399063315854921210409313246152527668347143019550364225837781560926140640093081116049657971469048051468284711694257785789178809823941465962040360930016157617452358728751181336693124773903638007273836503394835409596627165112284850875254019710400215921524572141759487839278218635745589782578579334381032101526933997551326789078325869307607100354120311604173747476470292725643886125380388270758769897729363768023262199885056661555947313285025375746755494964841587184402442187978403892800295699470235365305791026570731207454053082865363542424265608839239142648022105330036603608639151764223209401458833898013848306012540918241308571343492002358749458954575469142998610765627649222413431262464681890620336354859534385697259957037363331495002282308313059575072371143057132684161422385180562511230179934391119387461580548233050228505428143177483520819923735804035411728110201914987438877780430590906308303881797836439366427239746559919144471214829376603306425594428226006996275012485608462520827573208905537492316802360406651053484551978898843772619804303428095512709190321751942504748924572861274319455120692685486947434437367729541467272766686966807916370179754298758691241170194777607607571459715789461966313236323523592837374223651504636299665197397806178032081657083412157743291936555271637270327920149177481942718892398679774780630393442679911779866113264527251757137767743475728830777662545861851530110286521972777533327238249737517010066472027602218338978796182855291347346819511885654909739106341730048204503382676292182395762019301010339302187086865618764387685077382309395957419707422191992883094903391508671890404797538764337688679015997252261601 +expt:52,827,0:1363845534203275602945715020440112734101654002035408092138994948157965218152597293322552516013541102339042395990176596143927924801584852182694494402174469146476365708253904854631754423456184213955558063795789571339488371939150388709770832326123293382199321743931181340567197060909930816221066728909932740981323058976498861029285889367417218324674394634948477294304297443288075797373908416729496901734018773669789061707665790116223052131538693972561939226658646132503581784089567145866185449011839827233650866407425601793037832263017989277208429957875080013654195540329347914131526642439138839114974367753637477200190329282310264113595396994805361388494628682431321748217640801660295524027806208203770728640462587823579475986549878451221998889514922178015943053639821129315654194174336476091685209054536280060360926059507789375655383925910919328884755937580198622348199281035939633612639571160057396942003035048191323428551521466383128724883857629281100336791723016090894181692768913507036769585784474370724499814943464300066137630528362913596888302207349032278219095928598441501164781762405564581223661028609149292490970074970826464288906555662494076317777084113019235504450774633168894206571329889041276981381226535278534026720907837639336650956477462141594816136215684669130211088491324847506030723793623545095412834551391863147335556256713198925300756827943629425257037444345305406856996887201268436359318843454128128 +expt:60,323,0:22021853740468578834412999517383915986003725826542069182383222392560149753844176723050212105982537239537599021478108969602682255828632115769764860327553473474873742876444567203370333512921531141121798618506475910567199986084415121901524096659710646681600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +expt:93,407,0:1487853124884939684161385095260700523967859232818286064937128697770803227477244897265636431308165638318966698855220495473642835305695739102629480041222137050463066756784476730673688602838369260908469031821258574541365094727586343393304192201159344658073883254741254481946525006070001016365758933994228518537153685742527173077615516552516989509505043555164058392121782339357054879545731381596514378851078834808332428961106140341211035824086439359162868820393089217972263771995780773037041591155928597930802603797367287480285258739006095757736651824883846891644962424204439039748118255361764570889647940764521065367186406409883179355871269579713473352431638000331921603972636225043550734332376892148456648021902107583989118652297791718607641268173465287735838369363888845836639239193661056146350176700757 +expt:40,532,0:1976584504954205257348587370301926826655826657852950374579114824486624409843704559491800622084346918898311307268718866322166100951033139422529427733796274510952318596450843372699872145918879065832419606235085401060175854330319264634942415582511323792390723208128503608909506002101860376290882104576621154915114333409116160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +expt:87,730,0:706406052439804276576366923069975401164592339719248046363175133041504186269361366113522873942837171766575825692907350413361305763457682609785452731784223726861092814681363318067351830762134706310235218630451383037256434744365437287493102400695653964561812007768770271884322063288345456326150855163077971604365104144672964323628928074590169741911380893259497388141831058301465764795085547886037717455631758754798786277409911481103533394944945594049303351200226257695107186231608269522603794233543597973234060805867176925733535004507818576356738265678541985876988343565444956563176444492195721906970792397883768414377487670435384357764529998377542821466271982699148147379912153120661855805478752385210208666518800046101644963551222667137255772127065300202085523460000468880606604031569380116746352741827362128287425183441335754455687265829010585467574413596756689179258204408286889278803328179345980814287315190200086811052836534046524248233679177100752570989171333960664035727831280319345425290977756020974412906899038592201787348761825228061083631544347976763613084792365803249527341553106644812202911851620419765048510696413924148728211652659875437527114828561845302300246793974650997138116778423178153360481516286629888500954470861598210243812921260066728648008448752894712658707214973199057680079905435919626256730123127286301269269533605024856318874090809110868170349185734499760880296308653980901200084758996049 +expt:93,605,0:855428814634958918544599433108540171368754753688076725315883503766618616635962892836439002252201637178631493204536270801813620260674345152674646475870593626683064317677060559261922597424647952067084352720270230897768699019551822862416702016439561791131256840774075776817158756158362876954703668271367349100772697424595673989246853166711784033450960087641035381498697333940896283341471626085405973825001412103159308752988378154950172135332537721061626398804507352072137874822359784882151232478545958168287870325307214815056872605634979408681579673200606265939799910966127483516061505432535339722111470845347125788524278717471958918210481766553564146010755715128950367184222764324448405602954498081027273677629683607327120669429941319549473748000856525799606103272316670237148246821455126298282076072799525481524482941289874128889144124068775066511048362399672727230153446359840323405054769633940438256055614689237151453949465506127337023888311827938050913222460384888518805017976698191594508859162464655030117614187828782625057625442536831551817101524758129922535918617854470433795037085700145033888156152683557013427888199380333661049871576750433106831383797201751809880804414028368093423693 +expt:19,963,0:27524390933462438193837863038173257600749953407807781713047411800439226575830665293723529758944853530204290511646210815182136606877662463470431698540803603366243306719651411385140530410420060215533879433895666800137273296375613114999995493626942192121350040312694984901577002074624731875041793317359566297539168950875820565444735886011981922691483574660663239016046035782355557105396128292283603712352714496861384151418904174890595393015389865531243654829040983885834314285234495791323218841795533872159352451945484907904644311539896414067347389400151749600657579278895960573693934814752676278273915895909394982922563318173736071016647179057619243763230042827139542125644226762956903187476598431665900029305113678469725913961143048032016348386870923089862955467576132232067430573022824628886621106941902269773912408414386384958744554226394315986912008000652067452553259073901900219599312892013220890882796369063146728028726932516237716682483149607295171755157994925014520354281344751176954994548850375523372990992872608235206800552848373884097904303114896951128191894747953292238976905990208894450092732832100441840572843532041330491790737292506221131878514424077507009732780885474368274416396249038243621795514514228806975329626059 +expt:56,854,0:89655113212012673099023948416704807879861978221153827237199661778584008468165651080543902613878620062782298351513276228294432072744284649261971266393894256607375431816304583821803793716587924442301007552505586044505538442132617485337199937369235592237428954101205944468928491652642992561924170992990684875183153689532992782682092920117235762980760669791412674782564117374541646440937370311927125956106266172810510670685525518812212950138056170979608664706763694733342515990968354863012666224960142013969526617072730522216789165659791684923653320596610175398020948129729808736281334106447129989405194534944350195768931899586302086738465979769199582498488866115372356961255007890457956873669299696404273010639537644911751286565659364626323246621985820562215324013173040199503927765343915648047310527662125096994825235508795834438673893661434170547036065620501605840890610501329654028608371726543612867845130909422255505338304701800505808679604352191497405251720910198472034708192083380402820761289291643085960629808979419703266679006005273854103326911946960981639672499634075872556388250454617093178267203875157005188789441834290824824375362710217394654516436622832004430364564578406063107709727937712128720552024767984099273684466490280196940322959059058007593299284990312017697525386129849377270562464418952129091640339393380715993311611910305891157877528570148396220151382371598274439328443130602108218216942517868406522662920683285329640812262460209537817661379779669996166934404739153002496 +expt:45,612,0:5835236069718882114506897382533566247377415373160348322335381401959804325982764654985369043691019754782274324932902412422919504450121982411071559141523227598048101908706172870018726600366871511993242258104983964714191482096777425460159405868198347157194247010711764769855120922789922675107180581288360243567263537448253664324716669975682189100014404252781455216273744498335122639653589122310702857513362909180771831512471469920303997788269181344157274446834696917540185278250066349263511743262735271477684129972106758329375646539895223543706592566504943908712300110805454844873245197309482926904374664094429569566237475738252689670337625545730148780598867696059299091915732424441403497739984466234589413447120981326541342694519489432552938181829843044368724644161584697373078490608422316687980922524068552209758486036117805534388377565978109780133632127524991766800756255658237049157308049222993126272044553147845347401604176748405215264533091894230978452810922757566292930209161937682438292540609836578369140625 +expt:54,451,0:20397910418377356550287300571804200557786099666116822595739338489264108594693629585863016865675849836447133820178583817056787257865484263341787975124682123033432566176550892031542044673807061607597691619952835660477594361209973279361945781375083740594965736649506183676117824430817491153516247325248281553959922896499435214529883689562648236636643053318925258184450463587681659723559391253678624035379856699358467799364301117153745186153084620238270375863919362076592257374084773424126742009360452069312697567282746968871243121905805216854913928572510658635514695126678391222696789673476384418005261871513244182859164066090813969042874136599996354815022967528679816614580768946293305191453668744093542408847163544646677483277319352956875504219155308754191860667890267580442087522304 +expt:56,73,0:41469229998734605907229666533990439080884762393847798172038084645287681671512979662987869210144861737361911662097025032274313216 +expt:22,325,0:19380780692127535243822988975518862106688283415440409657318777291773460112826177488864304471507503296260257393000381968404530628735640782306320769328605753305997492221828698343046454208648959261843736522465022722130523152030591371634509064404845763380835114201823755461164985487277973692677490997892134149211679493862203005748191879355934593251640178434694460018581599355100053236481539133268074642752831875821126444829199442221499154432 +expt:1,259,0:1 +expt:70,28,0:4599865365447399609768010000000000000000000000000000 +expt:2,431,0:5545339388241629719156828368286167406872874150751633150340959161229242615611251246079948812208279156194782421922807143657948315648 +expt:-79,826,0:27540854187929799985257468247523155680538433703286824739517469481759833990910653892340315597031695813840072524465738129420981768137177778398386187136483179521533720543407277753119393284152155957481914060287817028607256937594519868156459054669091954974712188347267089425432969106634444194388017265965949995692097701957114472823086198047050856806061672798574128287158999679211211045866881231653749742181206820843018712814234776885483960209113108635431190289016087501917845943054954808695879153901235902843669634627518243307894193841992956050535767242625612932115880911409609569876836530027970817956419533492446863797815044925775952042741550534011707510148845849950514957657983203500516405099685290711977967093948805920524360187028296830546987867500833588472504414005192236672391462985520150287811665577020744455460650359790618613062093825277825004505744707271241064882064070718065648023094280188167073044844547232500114457694590999166919669094693398432022411757793919755408026466841256100301169395413642500129881284167587546361348378140644375492018741141892055856217500455547981975199608522237536059854818106117812566998653773404384267708945402650064006573487698794343692465354553659902815430390133210939131290292916108564064726731071156431583014478295860724491974850345289250462234755107356158270289808695989364604670354446702945425544248554707467316099882094498480778646008506840517719579244276824018750506251514906770636895869751648864985470369467283659845225076014465077719158624528591794989379957868089133908677744283634297198521265648631548657239277970447594973921 +expt:66,694,0:580084506530496199901715842061550478736929285435953296906334763408916457294745083700943659750072194007911117976928910771034469652824787161140202192812060086123933696794422026495786736350391860998721709184616206282429321340426294474560554065373638494945279261660818135550623361880986266761169809383156965092394530526878349935560951819098684650456236731366518214247980897154666883115720824687584260186753579248039306484564334815454921665784875496640601208054064934367623514543431818401964065471753818112528393669877004534296514842252720036344695851083439754895878703603097422007514258951525128317284811160997854687940441212627578246621158606819889227734453833088076792053010410429208939580294030978672807007323066516188519488729062055117608304054056122408278794377322396923294276347941530691555115638860207628093697674034586478685823166311562429468232346680345400111368599877502918619287029806863424209567337550321781645413583273156313569257554412238414216208778666350590080290958187713067860125458768396034295744470317801851373266428602679222973688293459392062447571375823266655946023131694535754930689276382991650046678195497949989578167243234281923601875893680839438188017891503234218524380143598199558737455868031691457764742432465500138998414409914742091022336 +expt:61,929,0:372749204262219234661028605059600082005472058401807779391175774103147347020721809274006944812742694550566021615220848169519541529572954087195954262275827015340392843546317426147733284748546026914169745283094850736754214694252834868482075113112267516722630530017429413488354970058983032863915079743805868398514511489371415564743824566521175475718773953538278821907613967819226017166214104739437588073569813368813398149488565589556629477697737427900926249987010320503591278599110557450366143792209234346301744107084844660292442687200498652998894095601669905889013178322152368594429857818699973029703219264103421059688221938804094297461171047462303386552014767355489371231645242214605709573806038882091320000969833466616172674723281820861230659720784846394592186695882554183766611030058785231355760030032991550909225744604523622367813062613525325165760288801654110165225918836315855062845073372541514571337989620384391488490776891951817514249041749473163422333900356474699047977817400879900507930748372050203706672988848432054792535888114117248293709532406518972437029506673903536575555598954258917589173484915883729820461151786963746755203344621234694493460419788239808892616004989648342937608880857613762630401759659568336317724218590545423848713453198029293212741308983125342860690464093569963158486256404302217070545170719057156149028351035109222842931378174195730467004520244530634927115724793217592798273975809563142500814120034065476390178392762733701597980347726390211680084858484316148662425498700389466706121929317730214556147564067838219041971460802562516019394610534531801572433089111247198407104918760032599577878951582322678994706142652947962481341 +expt:-9,601,0:-3160444535448242529092641683723644059539145692308657340859411006936058865374641314408196086827043799075550619379423798587542309132164609200204439951579781831500807632453119338125875367204968679095724562036128784121814572255501838157522005562307704591221323902634201333248104060896549891818729439534161465226719835137730531986768862453929457126667118122860406909711654476082395260883189301675745656233295957116371351513365076222859294597957033255348289403621311527049289776180957730267554140209309181978595028474886982653235278904914878205932888067162450567679909275108376009 +expt:97,61,0:15598246895092955513443352386309396583401527586016822407020611754291026801166140429261857563228075418881342331811243126497 +expt:74,605,0:767698049587939197359683749977648383836859839557642912409031546875066993197361480792391911022007587571205286132111673072469130312439363390154975794877785145691154425588220181582417662944285388056619181981589072518943031753597130867006603410867195350232262952739727149609075085699454676389509914456400111058880374719374067186562888441743787354629796015365677880935538353010170412164805965916706642591317263073481887535024205339087233459024635435688359086659169461648708865487255695675398023180920346709788305388156864497546177737256623458491643341041204795577475348427124793503135829398978121525554056766257030843704524575334061514903999726663601269068024921811397693529872001218499944501992703297464998852615587466138862714871448007704439720092007333440282216859169819279737835066578327985762318343795059984146296977874262661155133530578457531318820157803398989111207312212355231067323772033741977708388313965862076950112842132301934452667454484343330105847945439333136829953705856876014817393705072041603637057816525800795342430049224928087060220666508991256383019365798391401213524865142728401193068597503580931118244325830426624 +expt:36,975,0:248278005620103284639045703633892910971579590446576896390366023318446808572139362706941322105353809474568993267209279242065096446488620910399483811208530728287594195549653360186846362277601130595472769480324082311203270696569975943570941969562919822812104500652408711500447873544596047411274288014555337548896670749271601634625491645631804888387660782682890889223510249234197182987228667338352972908620961079256927945363991111693736862822062801054752644720735597690210678508403694665212607341057194061256992464781310624503950172678945568406904426022068101752528300052652001276542298094132591990104962487076763890948081836407437498998808161080386782802526119075692789537066681886677023071338001090161651248031406605922396939134353858229048521453819325323124966146924584063700897925385709942659537790517149987487173581392712392934799338496185296838242169097046867947616557569663967960878013987948526741195844085783626887255741456401906399763700966299733165267865215995696668857089937482337710909782176011909086961041572658525585707034935545895295838426884822305638121505564930966674346565073344787297923158159728519118453365025481613806608095528043429679151758551183290377061790258979194328969739145711528285504071957396890777097691503292292512140424378576323419960320470786958549180355944550997252189926822915544222112451356508263343401791620402670748174883090503543874879537424232633444841283544725100377811657760945870884387665856213462789220780358446036998302940381411899721937124651210804520592109143837152301285376 +expt:-7,998,0:2557666612174935343076642515066804502377520561389767696864275525553001216974247274131608960292888178840788079990848858707874061009535980056363078332058256731224798188707371509890293039384338196239143157226455217716275665577013531086263168378395631166498491605806001681974869749146726373202776324945125013953453368299778708945971227290643969595629713562243419908025456961888745599561183240940509205834167387996660455423008573664383326301867960985504323358173474091543641085509125145760080557840801210219094336590559580686735948781675614855516621028604833789337737476275129016558156702593389621170307048966068339005329960325088885775363738622269191020959920658840427262709698255458449248536217491851761664583813025566114309314584253990687002952980625513485971873761776789106023932689391842584592322920065018940027985924506720083084514443495522449 +expt:98,601,0:533177103720501595374014423272499180364132378499160666153205148287497431057729394569971402806644432590292381465328310811262311129879335218558809778840423111439831395996547946125056037438926572002773115800873538665211948124422673756566945099641176492241232608229762984189514655606698161295525325616990201393228718812438865636613600881016384894116920222938495899464735527691752379448855611912417527389079639150256802359259202228730317836086556170590276966277499401959437472907925192927018522051374174184596825818778972688910983212905978633684186938477351015355179910878863238407299688657725777618404474888655212468833055969341513248604687220063488622962824592611061373538419157946717588609988450009564429746027878532253109391471912738954897803162861544906424860818226748531212662795741229276596890126256794061814383421311422736715585563600029962135442113826772475696417325421015883937926780471519318690864459664035455228247945210545963671338082833659176679989196527849975925731239343901932556903446683281672284250829662800543414520052002458669739331249230862598278859245402390741706350229540923193423152041354794777470610379380463931916503753572520250120327494841108274055472875847368852693579726848 +expt:71,113,0:155665870729530205341310326859872459537926086918288608509540470629351860391099882586273156224776434943964531186950530766165453973920218517388369336029496210775525110769905804823288221938617835119278838123463111 +expt:88,907,0:442367935572376572508225245682376008933489111316498137860990507028355805276660122793212942345797461553842453310264287269547264461627567883151291662994492100078344571908312323703967322111609104550792111450058081718989072815115851882388563478737616122984915164909745468851730941089128173523430879823706000843384957667316760881888264090864169349212921302774263449334569646606880597808832359653989122198423765672987068986676530059825422164710070729150784542517772146017930986715605834667445246856197609230392607836274592038028103289662613608042193082727017234381117193204646042933195569061774171215561867979977536504587733669688385439306083861005747682093252438793416405292269393894857797371282733609831597024792462532979252620533612898923536406352613040278291119133710169841942272610880326076250824796315291769779313197811055736478745579585246354714882550479199964522615379791935029462701848490881087210486616588742015690198161694007740631075914977342479383653037979280440452432330650580558326686619170505019301413395716564578646343919112222038215172712390311828679340129762907111087076354552831143978497060075661718540626266557415357423140554743330726141178661837462646531942496692764465824964428334360066828688839099062489813585188443877907045253387120110743470809899546315304940652259267302446808962933370950281961149706759813262075876658787778751634455269684666084979732880496655480607530401657107712607869822390372442674816531402008096066231847402127938718306972865332558595609085653122439480481119259426244455543280347111130355917037063730253045491171053471360412763262481476838567930318043324002372902635753161108413432524658790895161967566922959535333684336970564087502342071263031219942567744837673438233646370315543730522460987677141774838398907195160788992 +expt:54,693,0:3538959212637179650332389010097218547839980601093690465533384462821473107518120134643329245982087864317937908704373458854914106407415643779615995841169386600913075521454433838879465455760020550207139247760073103240863782684441878651997401564323185374793175538443983412787862620393247499479636694089753362683716397696397917283398425558068217711985447159317136026122405227956991309955957305130230342078570923159947618234652978345575496908772641954759715818896470873163820343504250486061693462131428151141184256959845856167488510754499527069147459850959898142673913068231658647704696101725713008481473114205759711924188717911743864320055181356930972595979239402793810079643314094026495828298793070503069066311897901487935228391178144871449270977053884209274680793281139427835365536821473478187015781075924946317138803162094976414459954194354095344108788615082753544608345483223312927636999008063997529650656957732197940704471295178444341702958910607189754168223147765846213872939337214235441488423377963042762703792152968410669091074122567701986969963794378828129171913930842249996279788381704931705888803023880349755565650291290845634952973640558107667121388591534953156403175205437026399021173691121664 +expt:38,856,0:197132715335944702010464928289068787258126989327281133977642459352310471635694659935863663034893224402661971507965073109281478523865599215163431556175379522026942698195490717331056237820749570952967717007649366271894056379198300178606041623775325949617283624435203477373703809019861048596220111560408850308709136073536236931756950635354870794668286264213752040997939539541387051080544346518658745783173789667395614130438466933466487546913034843807849350170476768221968845260192149232038583063007145032622472464523166365735920186939572956871374170348147525734840393491062416576459571924060826547986510253181877148984750114103946480014297867097001766341891006238734128868718256859876341374385005847514034681950344623145375661088734911525281809871480522601658340102129823934063220140098540350561496324424874246538855230619339148284533370024488661745011726445642690111494919560707585228174864187763259132194822208827893654702830695772629276887925981051128487055423282643887884462938381948997470435721291697587128910687319970929427859109724267542710439086909913634572523183081655946843912895400563035037344361397713522987937999965880651790361428060580389888264631102954948376159211750103503891634869806965067088907401334445114937251493551662240660610686055435327064505561719003363736562191988450674773018772056555774194438968053446880417310543649670866927616 +expt:-31,708,0:765736298588882623745464551248533589516728262330945024485987989003966799697519427922524828295538506333120906420497833190822172854823291505196845183135662558430608661582624850664725007618784585092336587620980112185589698249795027371672676312069829503342898152005067487306044707288099529713186820460094321862725166577558202701116811479992992160597205251212891371390724533853382322337514186669568739285186663884891566968084627353685451588298678227268272695471519080722554889447126207382826609688589782622034263523702002067627492259917412663020367888185843581319175113423749435759149520782360313210168155362235445104891714946334675780994250948917428592423464724255498014927635397210595806788729762917250871841151153544592712985783889618176401395175667540813239941136361290336680403138159551455700446304015319933056996010034922500542872536431111997459504310947292431025900542295004555040557979582695891302414344669597914053356301361988698100342875761385692372383787936620811489997313151757515795773510401149056466969197955066877735357001712514205212720669933441 +expt:83,555,0:1225578881193055029211627122654046612502838285027451787523333889078091117395677304740312290856548894569025972732093305262022262904766698517843710251028889032008071021523615947494541437140578410083242439006303675242241181694132064945370271165796403044400021233214176036607316649425463754916274528213700425307672925070793107159063558868221691827352040472536655806967633986881743762489226940035732391901428677713410085277373744973773271636779960125482940121021337248817093605269643954914154264236561300490516647836816796937996874660377751119032325126115584325317487570936637230731531209445181074951179372481656744462723784646444882817173348451279220016187868806676293898865251048319248697918535078227324297131747582957851638254483032160979834998953230605023477565269493853309225765083693484738566931845020418708591682116652295291303636819498565470825532192376545824497931844947390200802139827837145992356261755130151073475298317589343849166306928091630048941968076783492543886466245827183954554006162583165658402103419444975524038123795891288877937208254234082383456107 +expt:-14,196,0:437617814535571368432038511337652545614427696923129424177713451048312616488063444444116568548619798360728579274072579602558189605289698688298076102960815381950768025379270967729373733335391251544937988597855682119418496679936 +expt:-98,54,0:335898517749742807149149239304847110365424413007280865740297764742923286290279482895371271867934265713885184 +expt:36,114,0:2621109035105672045109358354048170185329363187071886946329003212335230440027818091139599929524823562064749950789402494298276879873503833622348138409040138018400021944463278473216 +expt:19,880,0:2009874029398980029295434722831970797532919043227819887587032786743144365367526664823247908827194455630622170606057232748931122179234484742203908570131852774251405487769265120505741541610105732725739348564765526542332365086458667418301828317751506967076229654788429336978672638225832010298145579102409262752736707461051491772477782570352887264641512286428683926389567737024065515860584891869348632484190723337772808946418211067908239231699266990927693314506689204660382252789414936010605752823023740942793443449899582312545405585967436891389485301908118540573354341705957891466220807814875490535322936464464190634279487514642962273091394501124072606449141530155166291432938436888069305529351823734620388268783707293175582244589408920429277320778044335476174137843245578718617250608413970893780067437205632161590787983801169075275248391505534693130703217363266217430925635281802546131654287314896587348755945486748557565093898213697334397719214794326654886046758572050840080888194502573280655340846994980936684326929231978782129907525294831982650961681342044316149573667246042886388298925914414391461565675869861333636998206401 +expt:22,721,0:77046492558224796788761802514088072131880275970877661304506183244811291459780757474421304659351160305442644292605839122224017614753423013459535933948248049249528771300446785986946709805896287030039183115458755228202024899421282006247675157856987007861882304710551488072995285854106976686201919909140206483194373001181110350256617582296405321373555584594309012456901291312584219573768786649572212517073683836945456976006726338250005200687545264869064958787610169087462340120923702046458000168595260841096750492141312671829384006125954306548840981666835043447963679445859020819819138834089832266078096711197961096290254275206028869494312694951676428802173538454063412657550689313921331316469141026674958943351278665317595537923216695203682252676572051050680540810268656944394976378717156317037697429183535766592224765986513447985454463834647332790672247864336230364221176419961961474234981387758066111628913552702951065406243272417272225028996432449465191839224742019072 +expt:17,917,0:2097301675874874262337384393256157290550457272641070742685181359655298484419530330975119591493945747194067982196745980906719459748758882521093062942106370414411307130989688371347312396400965251294933801479523245300205124498392914857119952454973605402952283548281059993829706858741240642855866024547671426840363544681591758614171705795900874121429015664043430807387470485214251545286572177964862773770430978379005467765291145746924901839002665096400397942453076588723612807208413217092949289492019664961222972978192822676475920744552252701836678236202368876327668639558452692524803118939191010230124869369557526977853787148876084719302299232475362067256488446210852407409309331633276993895009372306807316745243435453345840085033563601310824164178695180595270040323771052788593322649328459197776655430007609049049177562253219889705605903722950620003852016584473859694998609725264429690598113186546955167630012283368654064816468752154783362082778625443452372549847742049125737902403986921080094805248820329567053386368469178503759368276006576774606472539223477845778733320367553885443289921963031175184555111324035235498303342308177 +expt:90,974,0:27052299935047786065293705383293371594928459960636493591858679901229530489397827439967797113560000179030752129693483986009759069814344789464328028124389302229982080849292903566689398199538736384291803478523321463426163427287122485942132332484438824633259632500429907489423839508356778347605611863182944177635491198031896503926679224776089106017711039660784400591006292140993879293923209120615399556982103777565419076004780936708141570335102044570334141660285505239366482840745962298126113781491303989125579971415048181359429126117863548989486391973761921728851807165407598678812115381168882267007400683443822154895256736017606370596941988046175011944197627446203315020223655176866443121247527516304873917419276577740100216553128143639001206191984430353639022361358939550577829476281299576074140336299277402936582067383619719327798911232272710866516643940342077662311510080648261530453984792175767586937809041407061474275004126136100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +expt:88,533,0:25660449281262222538494450001863125622542059254495725488128163750941665069643744134848017926826911153501794213458141136118798686952318128330169211354566747333325537986995462503989216458427236156137402612135248417253059095443287160848570588029400648482452870347054911987033926310964969317423952372643231383031833176623179144615827641601677528585812306167020803446102194410693881507224213793037477717521197480665170498415644315118063624358208859552595534937279894843336541477825309304143549461073381212334783418760579349454160671722140424226639994874257433085267041153503087290920628156801330326875713842007053978145083999034880721014435679044734743002931660496447382048291494534747035171647495659446493320583080918221954598494959009870518773105244525770713362092498386891958081893316423699439660136195380395615149744310401608278793638807731614951269163459033645996046310958400025916261303110642807596573667882890880336479719496725477724544562900521034037056197498694805705196162644018155788990216861162622711326815130754780320976368304128 +expt:12,155,0:187539665641051633765939629010126862030861602821510134598513247329704373202067865855904581679588305105558426392209111518109357753525875656563557488739845521658156679168 +expt:84,732,0:37362626400287469786015728314475507196576346217451577972340560264817777335475340674816958024184760346347561438501466002380065324994816957074697212139052544975947819746208063697307962302948345421020870897563746896137814303577394468618413663330314199040777371901150981465952170446359267027980870158458849108279054769543589192992244998367449195186118755704549074553943383839728968976499539257576575130852721502719453361944489930498227884992093281287795552589618712166509707464487440188402096761270376491306019370966520073730856558528831146413882339665688468833965993044432654395376803788836651945621982999063779396803021750087040026958788856842217636023983209404960799438677955235981923691837336224814448363848125978496886798250942574484985336211014321720899330415880628445289132294841424914787671230730112190724165482715241239871542120185970126756942511944451784053266847219551455015565798473788074284186189118669182080184743138159319501208245476233431491562603292975987521331235533354675181947901194397959442206360514628651055734093466035888302489823943737682169815612826149059209986740615789135359084267106289623915297355833264060175823550703443673841878097340893266267479095018072578698649320448199760433477235766344924312161142440752268668342566161645418763284828712617629493206149751363684796869848593636426521501235005044720096689821574083797399723544574440327020813476324227172574108126760343901889888256 +expt:79,286,0:526439064947238802053645461445020487916872652166019614740851000911432565395604993916756724273343382808249492973087992062325249551325359686735575913143465467581047691930038117373467695602824586884710893085987595912587448288044732217351433963632626007275558435035805433116956578902569644720408764508101410145243233157169608100135310715793917742521403034578354501408583090243486810991762771487300120584737790555454222432759955623420408431532698387943150871884498498636773443364760233971133647087214954160646197476641876831719032258038195184329121 +expt:-48,298,0:1023030868022814299054713017964868399102957735431782102215916358604604051659703035572837203405877079107051634525945219766070256763817295621420805604993635631490817683951846687765019250182667988090399985362595946141453130325277952090882208566546530763707685586001179407168248639583706997713561296809021500677647862937784168307555475376888964203999111072179073538018050362405289547337600007038981171944778216894564706920577451010395411246759676715366409166040432558779691978486479294657424378342139756544 +expt:67,294,0:734500327961443669234315379892319347436893827696021491142391697563378578446291077887806124176875773502748252261770540334529098051241702520337994712391193396474812051324450141046760676076260316236367877489247807236984474045776385255239037010394553624592302745770678862650712113089224670041590960921068572134081690133046715543153096542269435280673848480153667033339024712187305544312593068136273774422287977966196973980766284625470220034542418965941570269327451886686200812785835233820579323336965260949631248809309330127020161010203411929 +expt:-18,16,0:121439531096594251776 +expt:23,783,0:17096043011003615277598794858486068754024940440179973307979725548138117553890262896641152305435426637168346356686100176044925372354921872747501460658856273444772550524367017737008810328712782564379920672077160208017588610872900933505244440864632694623791999654579846020232116933586706946483379032274515986264401321379356564215058936360373677277919864278279794625946762796494116433783821073561146442740575287992208852561076777520575751129272827760948307704793048037510164918774200200085555861489097574107784367443496372000977637695193822915836028040509766497522766784721558336792917997571201278516192223590838889688612546686389608843721034916667041733614883996563547634015007274594387270209090391868747626612843208187603964244920932750585408044205476476229852915573917584786214180312460069710688659542311237951704151388274748457930956937912692497993167574943229551708370492252437047946879513486746068495028744525641440991301695614236365008498571998939850585670845752278477745811135337129266946940607139194863121256913904896962276321551899101278415815402393374517929767 +expt:-66,815,0:-8478274364648612330188917253283022359058819830563672517212108821628253393962000107434004509667343937534845252876105916914550690362654306802088184928424521570461209219177571955862371964722226410637046742655117010513197262769697714640814368023744763233323396664955472317206306714935880218313050258650385673367221675620501577511198414613930001668113399143106311450680541330404416353053190642499775032620035730460907253528440201689228392425128611695226403417406791574278689202884590346418539029059209980814013704118450210566908353305850659319394569789593583277865075164609668529102638203772555818321297822419290710586417444995207152787848623117218947477799582750664329264358615866224038190922228629974680499679526981709174616924365577700177072886843030924028404354842213079523220238443352288912242203925033885655177475234008253977458800922719481452623217104266383098663601342961199447190374025272206739771683319522016840242048283276894211421554923410027867743938181352146258867339132020852657862198937040181786435550099700309055348307396827575249256603692440439981038825878568365720841374284500628316724088850430536784223423104076749618800240805402030937435626889672205773792103911906204527061949920720885833279883726692710574946314456869324980999570723090979946872598945360813531346459611164448392012613641192887272701599318084665769391014924333193179500033230229853166710458920123986965349475008600343653534535593116799600793757728203652141876940711203421375996087235090052747651710976 +expt:54,664,0:20391845050873191652345159631406874537839455686365280217235427133476142582092996043619608390016389292965226896811762634987782972686518739140212360064330493755768007040302669237780668310608681482526562495176314471562104423826827089408141436551453430030964346636473177072344012300123214143559305872414360567214132682148167038413419037687295369781258678081076745492992503736782832174090246186699082419488498244657442094259244802484573507417869446357085909447262706180711907718273125250308231346034020925518798041278971653974463785808172029353263314071093941305571685611808887063740166405396225068221678544525487393228625876836004989079566259935122474245224409591612160442040129636723080187009657142522509070943421819954801779957035427054617629433447229882724015810298068048100626156055542733454456801321357919554628269944544954700528568251750045531145328694687448392559273455873142746224088225238286750883430569184631252959597186815034796504990060130502168310308220045378042228226870235350079089558343443820937472250762918032769865387382756419568756482286011357857171768933280108973733824989544483820081477750150555112569963683757807113376801387242848256 + +exptf:-1,0,0:1 +exptf:-1,1,0:-1 +exptf:1,1000,0:1 +exptf:10,5,0:100000 +exptf:10,5,=1:100000 +exptf:16,2,0:256 +exptf:16,-2,0:$MP_RANGE +exptf:9,114,0:6076396096647706909168138770838836135530328017648434830996201971201776350890241322455818405320466786549738961 +exptf:-86,476,0:662617332696362860524067230796827820618815284881665908870595313490845384402730799402221740741547892729430741053639014274968962128613995528237195069353968871860065099842959580048834695510748974202424908905352730826874949676923389706328585129209694843598031316497606363273659659518137129001683914681077900538211178870670637655474948719356656149928857724507047191532188701873201466847680543186709462811132458087950485580962981785390351911145306017418845982546035812744084364382432586452339098567898296989357418159116783507112574874002896769395516552960579886303506398054290885811079444534809660731243125017742263312078176886504861185566719851630353701862941682854137129215263285153620969438652988427729550528379121310832057528645876351114476064584186293636620546183047738657594287749786268444920697293633564476272776432769083439149706832453778408583421346390651383448852253784001810843070684412323782386158601772005993742336 +exptf:40,238,0:1951092843947495144613498268620728941092873839165606969286973099765857336762353512575191314414682481974891831950879139309654984799555178316431360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +exptf:9,761,0:1508515174935868832740908844641413400230908698282014024654729092918735474326353646362638387096847659573480147230064829611049820323852929496264239478087068540642226919569780605621815548160687919464946810325130045648382743363240874672014902866728521582870078261816669666838432797381766007612134725161586319767428484319859256110793709691241551836459283171491322903212579581783263716842956174378353601721913353516686324030063352338083503343527729254306613462747468830270057853272630516028854927235895950242106874919224742672988595490274178820331573555174825456815488479104792855190670321093410569224479462267429452231735849215995686173314732407799996091669536594590589720060331368687564979078136565140955509332862196370159944529609 +exptf:97,144,0:12448864341302864356285624793135454957839907062356377399873019819913674333304037397385881749787740378047787615516124593880867160513889753519548772992938610862712907794913424958325207507075928443769586211194132774382517001523776118917770065797726717096819996931978519564039067219497326081 +exptf:25,122,0:353737464016668451855824972300304366432911374927310085530570894138105520257533012294512947342224925759920017160034290220932919252862236536572027034708298742771148681640625 +exptf:60,794,0:71136550947732097223049080592911024204723415862845308040389197768507697553695725763485652390828706079386079253286683076446508807986344183438029484620306186446936364042768259107355223169364392353311443322952870623266797106042061359252992933819289381215897875409197357921675407844235432207568030978595888122411284106189806970016530299277993693667005155741905298746901362592844010565441606260646610040560804127639267467909340287601194961411351728753184912061106832973826776921930054951881992593414738674333726484856598478050587647451437933451435999205268943471465348558111458293504367268910731207434743916849298071460249600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +exptf:77,531,0:532813311656570249504626338521175986931059533505926279525440059983661596994102351537446926949363360529365260710018282274969608991708422465645470353238950991164094603760337431471373797674342466447685331328334896929530869521639021347860305641901746618212067382436047417802334922329714967747069071224609067366771145964345230898570999327581370275837424654936614015736099665593408214589717971837806254491231718922616012680565189067437536528526576020597271981783296886490561985553063246822960810078500648480156559918530508398231087164252252053517193755387712164533565474034807917780960207694570186046344187446803758345139338159388892261095589551022214765624192005132067602116482379395414788544646979450596452460362555591887638135655580299669062424023518502777571809123694201495640270788238169354113138409879326088017367705387411669267281998186298445497315171994082486321864442017377055208040226703055135151101106282748423896319916554310684705542590586019379478759401961042716809342108506273015769966750567573 +exptf:-18,16,0:121439531096594251776 +exptf:23,783,0:17096043011003615277598794858486068754024940440179973307979725548138117553890262896641152305435426637168346356686100176044925372354921872747501460658856273444772550524367017737008810328712782564379920672077160208017588610872900933505244440864632694623791999654579846020232116933586706946483379032274515986264401321379356564215058936360373677277919864278279794625946762796494116433783821073561146442740575287992208852561076777520575751129272827760948307704793048037510164918774200200085555861489097574107784367443496372000977637695193822915836028040509766497522766784721558336792917997571201278516192223590838889688612546686389608843721034916667041733614883996563547634015007274594387270209090391868747626612843208187603964244920932750585408044205476476229852915573917584786214180312460069710688659542311237951704151388274748457930956937912692497993167574943229551708370492252437047946879513486746068495028744525641440991301695614236365008498571998939850585670845752278477745811135337129266946940607139194863121256913904896962276321551899101278415815402393374517929767 +exptf:-66,815,0:-8478274364648612330188917253283022359058819830563672517212108821628253393962000107434004509667343937534845252876105916914550690362654306802088184928424521570461209219177571955862371964722226410637046742655117010513197262769697714640814368023744763233323396664955472317206306714935880218313050258650385673367221675620501577511198414613930001668113399143106311450680541330404416353053190642499775032620035730460907253528440201689228392425128611695226403417406791574278689202884590346418539029059209980814013704118450210566908353305850659319394569789593583277865075164609668529102638203772555818321297822419290710586417444995207152787848623117218947477799582750664329264358615866224038190922228629974680499679526981709174616924365577700177072886843030924028404354842213079523220238443352288912242203925033885655177475234008253977458800922719481452623217104266383098663601342961199447190374025272206739771683319522016840242048283276894211421554923410027867743938181352146258867339132020852657862198937040181786435550099700309055348307396827575249256603692440439981038825878568365720841374284500628316724088850430536784223423104076749618800240805402030937435626889672205773792103911906204527061949920720885833279883726692710574946314456869324980999570723090979946872598945360813531346459611164448392012613641192887272701599318084665769391014924333193179500033230229853166710458920123986965349475008600343653534535593116799600793757728203652141876940711203421375996087235090052747651710976 +exptf:54,664,0:20391845050873191652345159631406874537839455686365280217235427133476142582092996043619608390016389292965226896811762634987782972686518739140212360064330493755768007040302669237780668310608681482526562495176314471562104423826827089408141436551453430030964346636473177072344012300123214143559305872414360567214132682148167038413419037687295369781258678081076745492992503736782832174090246186699082419488498244657442094259244802484573507417869446357085909447262706180711907718273125250308231346034020925518798041278971653974463785808172029353263314071093941305571685611808887063740166405396225068221678544525487393228625876836004989079566259935122474245224409591612160442040129636723080187009657142522509070943421819954801779957035427054617629433447229882724015810298068048100626156055542733454456801321357919554628269944544954700528568251750045531145328694687448392559273455873142746224088225238286750883430569184631252959597186815034796504990060130502168310308220045378042228226870235350079089558343443820937472250762918032769865387382756419568756482286011357857171768933280108973733824989544483820081477750150555112569963683757807113376801387242848256 Index: contrib/isl/imath/tests/gcd.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gcd.t @@ -0,0 +1,761 @@ +# Greatest common divisor tests + +gcd:0,0,0:$MP_UNDEF +gcd:0,0,=1:$MP_UNDEF +gcd:0,0,=2:$MP_UNDEF +gcd:0,=1,0:$MP_UNDEF +gcd:0,=1,99999:$MP_UNDEF +gcd:-7,328492456,0:1 +gcd:16522181,930,0:1 +gcd:844378,24,0:2 +gcd:209,3,0:1 +gcd:70522336,34102,0:2 +gcd:32557663,995533,0:1 +gcd:641,701,0:1 +gcd:290748,-233,0:1 +gcd:-95,4770,0:5 +gcd:6839092,7,0:1 +gcd:787590783,-6789049,0:1 +gcd:721,15845,0:1 +gcd:-37028,-949534667,0:1 +gcd:618,-3,0:3 +gcd:16657,-544851,0:1 +gcd:28271,6,0:1 +gcd:-35357673,5207718,0:3 +gcd:99,-565,0:1 +gcd:9311525,-5,0:5 +gcd:6221599,7764515429,0:1 +gcd:21590339,486739392,0:1 +gcd:335,3699183948,0:1 +gcd:14,8755508782,0:2 +gcd:-5302,9,0:1 +gcd:8236,9462435,0:1 +gcd:43040,2766705,0:5 +gcd:863478587,63,0:1 +gcd:8874055124,10,0:2 +gcd:8204,-89955,0:1 +gcd:3303887262,3,0:3 +gcd:75504,-62,0:2 +gcd:436,2123372,0:4 +gcd:3361227,943089540,0:3 +gcd:37340421,223177728,0:3 +gcd:-35694701,238293550,0:1 +gcd:4263,15500547338,0:1 +gcd:1493,38730799,0:1 +gcd:-635007,298501,0:1 +gcd:4968,-98492710997,0:1 +gcd:3367542606,17576297,0:1 +gcd:232155550,3921719,0:1 +gcd:4860966,700,0:2 +gcd:2323372237,867,0:1 +gcd:4268,-29035,0:1 +gcd:8,-73804207633,0:1 +gcd:395170,26163606,0:2 +gcd:-70027196,6945032910,0:2 +gcd:5871172260,26773591,0:1 +gcd:17125540,836,0:4 +gcd:1988202315,-68060596,0:1 +gcd:554434367524,-909419,0:1 +gcd:-40457802353,3398,0:1 +gcd:410791452776,4492144466,0:2 +gcd:135751970,7417878752,0:2 +gcd:9593,31047471995,0:1 +gcd:-18387143,50226,0:1 +gcd:413450673851,-124,0:1 +gcd:-618513698871,-318914624,0:1 +gcd:37416674596,-8817,0:1 +gcd:6242382,-943205,0:1 +gcd:-4949666413,1501091102,0:1 +gcd:-6385784303120,899228089,0:1 +gcd:6308,-79643949,0:1 +gcd:2421,136928,0:1 +gcd:333180111,442438,0:1 +gcd:723761305,611024432789,0:1 +gcd:-91289,-9223787613074,0:1 +gcd:10944,57098,0:2 +gcd:57145099,-94544476,0:1 +gcd:9327105307,88173695233,0:13 +gcd:73230770347,67182928,0:1 +gcd:4810254287,-4310,0:1 +gcd:7200253992,9893,0:1 +gcd:-92709373682,-664752121448,0:2 +gcd:-2236424417,-69570761,0:1 +gcd:781963714,61084006246,0:2 +gcd:78553,-3773682081509,0:1 +gcd:24811454802,-26314981001549,0:1 +gcd:805866671,8061826,0:1 +gcd:4281823377004,2916710,0:2 +gcd:15229,320560332911,0:1 +gcd:6093153060,357460,0:20 +gcd:624794507388,3264784,0:4 +gcd:2632503413711,-514594728450,0:1 +gcd:7216089,86034,0:3 +gcd:112578025,4532680608704,0:1 +gcd:-972617496,-1100642928524,0:4 +gcd:86658,-56860,0:2 +gcd:2292080,40552081391276,0:28 +gcd:57144144326678,3579498119,0:1 +gcd:77390585076,614924,0:4 +gcd:685579,959286825595306,0:1 +gcd:346354116,451435163995,0:1 +gcd:443946215999,260668,0:1 +gcd:640447120070,-441698,0:2 +gcd:1253208493501,-8521171736,0:1 +gcd:8507343,62395589,0:1 +gcd:81126006,461820852819773,0:1 +gcd:87891707090,40954510522233,0:11 +gcd:-767589,-991593,0:3 +gcd:86229155,43027930,0:5 +gcd:-431963821,48986055721,0:1 +gcd:101557073166691,-74080192,0:1 +gcd:-34269048183,250074,0:3 +gcd:7650667716360,-959482143,0:3 +gcd:-176432105527291,712269105001105,0:1 +gcd:91973525400419,-52180215632622,0:1 +gcd:9054526,-21388581343089,0:19 +gcd:19326311972,3180878,0:2 +gcd:501569850634,39035351302,0:2 +gcd:-3470290487760846,622612793613,0:3 +gcd:827793089252612,77591849874263,0:1 +gcd:19866668332,4414961,0:1 +gcd:136274450771,8659380001,0:1 +gcd:952660786088689,171372582380,0:1 +gcd:429415374,9140880954,0:6 +gcd:-368107346,2945634,0:2 +gcd:2147845929,79983807840463,0:1 +gcd:77885771608,-51236668812562,0:2 +gcd:62272695670,208399244,0:2 +gcd:61973019,-1405255816878779,0:1 +gcd:286206733986,212837117931767,0:1 +gcd:-131938894,1048695278656631,0:1 +gcd:27109492,306933238851468,0:4 +gcd:-314477095129839,3837918787896,0:3 +gcd:4116345,9101435151,0:3 +gcd:63853435249810,902940229903,0:1 +gcd:80076033,14791385,0:1 +gcd:-31038678,1454704764,0:6 +gcd:20638192722,-14267370499730,0:2 +gcd:8065790684,-1977228453431,0:7 +gcd:362687955673,99742877979696,0:1 +gcd:1235326072088,201675880263044,0:4 +gcd:568009735,49546482048450,0:5 +gcd:849579042,-3197920541,0:1 +gcd:1808291492597692,96814519920612,0:4 +gcd:6275712123233717,739880208952795162,0:1 +gcd:774075573665981,7523229210171,0:1 +gcd:2944466357361,497012903828640,0:3 +gcd:282862415058866,-6240991940068,0:2 +gcd:571225883598025,189932649930728,0:1 +gcd:815309478,-371377784,0:2 +gcd:320172590239,777220834144,0:1 +gcd:654332382,7919190746613,0:9 +gcd:-5094673003562,268414312780910,0:2 +gcd:-77841790209187781,35267718271550,0:1 +gcd:735762990564598234,-32739891496,0:2 +gcd:-5999905013129575,144027889596460,0:5 +gcd:6861193105404525,-4725324526382425,0:25 +gcd:859748569384694164,98523184164,0:4 +gcd:570460270963,-54720108308,0:1 +gcd:61750383079701,3452251304617,0:1 +gcd:-1738716695,8560399484936237,0:1 +gcd:9953417006786660,90085339160,0:20 +gcd:188523146978,954842405502,0:2 +gcd:198834734074395695,171072375577893,0:1 +gcd:-102893613303732727,155104650554,0:7 +gcd:90836124710855,-98332551310,0:5 +gcd:10512242068892,84377075433,0:1 +gcd:-726835478343584190,29339956106373,0:3 +gcd:5033847480079150451,-69469662902517,0:1 +gcd:3869558083241,-8770208065,0:1 +gcd:46079368203995132,23609959311256,0:4 +gcd:979137194422864421,-1378816153373947,0:1 +gcd:-72618673468,-244198092166982349,0:11 +gcd:529564016606,376298866055896536,0:2 +gcd:554186920892,-629719688885314,0:2 +gcd:3455963977845612750,271884481278417471,0:3 +gcd:-41270780965441117,-4124462824121691009,0:1 +gcd:47581683736,9394210662450,0:2 +gcd:8196306676684,76732052476696223555,0:1 +gcd:2939970750639,-2013582768244,0:1 +gcd:70476757656499,-100957934015971,0:1 +gcd:3674841030712174173,540185467629182772,0:3 +gcd:82915322420038008,123799513890,0:6 +gcd:466513077506,73565730651787738,0:14 +gcd:-38890216282311653,91459939591112,0:1 +gcd:576595981539992,20909590051109791,0:1 +gcd:956905636477652,8381376662473,0:1 +gcd:9187294026565993,54295427509,0:1 +gcd:8866081281165098,6545042142269515,0:1 +gcd:338772425501,-750860960783,0:1 +gcd:6750486296504,8609697533187,0:1 +gcd:736067207074328,329259058372493427315,0:1 +gcd:680100030114145,52232423165123,0:1 +gcd:22697310250913136791,365228836596285515,0:1 +gcd:30594845950075862222,37349482121506846253,0:1 +gcd:866936756424,-1765396942933391,0:1 +gcd:6939438360479781,24559856763503,0:1 +gcd:927595346004843560,7670228140092963222,0:2 +gcd:-357321286444971587,7925597841132985664,0:1 +gcd:6673370692769029,520191499051311630305,0:1 +gcd:9013236794945,1008467412252240244,0:1 +gcd:406532185466775673747,9519149309169118189,0:1 +gcd:548046408595014443,777065152533771,0:1 +gcd:23897406396584,-8555442893510156172118,0:2 +gcd:54729344028716311850,2026849525600172204,0:2 +gcd:-7936445752013,-98698488318151151,0:1 +gcd:6309028281362257922,271678876766048827,0:1 +gcd:6357785774765671053291,56936125648067424,0:33 +gcd:11095109588014,9104811531028000846,0:2 +gcd:-921590308699737078,472826384755153630,0:2 +gcd:652120832633171211942,-3387083844442113181,0:1 +gcd:32731949302549,335896184427699,0:7 +gcd:3635516318567409721998,16713986701316425,0:1 +gcd:6746198240933100303896,2007405485449,0:1 +gcd:-19072614334803913032,-240759760944833349,0:3 +gcd:828472954262165857,127978158379025077,0:1 +gcd:8306750095431507743,6378030328941226919,0:1 +gcd:7938532173109072,7646615157112938170608,0:16 +gcd:25274397567311,3125247753747112,0:1 +gcd:0,-6378030328941226919,0:6378030328941226919 +gcd:-6378030328941226919,0,0:6378030328941226919 +gcd:-6378030328941226919,0,=1:6378030328941226919 +gcd:-6378030328941226919,0,=2:6378030328941226919 +gcd:400327281633151431,37147489147345586,0:1 +gcd:28164658061513141691,818613450005821036296,0:3 +gcd:476291935913056166817,170589720180888384,0:3 +gcd:84130837655605609,16051948347568699941145,0:1 +gcd:438146043336536562159,-2206822496905640873917,0:1 +gcd:8120293725815373571,24028314574527126,0:1 +gcd:-667658265953408,8440015504605457600699,0:1 +gcd:53314441150262832895,283247085055963859,0:1 +gcd:6658153298145442,2140281300389057549,0:1 +gcd:213046498706732967,784948480361985741,0:3 +gcd:-3857522843819,419578526133778265155,0:1 +gcd:-4948941087660882967,-779517282262677550602,0:1 +gcd:4277076043224464,448010594023993,0:1 +gcd:-644113523059324254840,-71225587742718143,0:1 +gcd:264902435468141506,-823887292259809475,0:1 +gcd:1538706915662950684,448326823774496344436,0:4 +gcd:2036808313025110180,30422160628736748027,0:1 +gcd:7385426850078311,9871854919284839,0:1 +gcd:804644713550364054117828,8379163811459445,0:3 +gcd:981008037679996757191201,-641409668917881464,0:1 +gcd:64201713053871850,879119102660231895102,0:2 +gcd:1033957429367195,1113485105415049436,0:1 +gcd:14455075580451942850,-1885962875546302716,0:2 +gcd:2615475057635555327591,71606675442458157933637,0:1 +gcd:596676024530775,2621192750454214313695,0:5 +gcd:71665682789483848832034,351563529541544408090967,0:3 +gcd:5092055214749737510271,-1833800774226189505,0:1 +gcd:600508413963341945,5057063373752305154,0:1 +gcd:-92318043858914149,958444935645415778103,0:1 +gcd:385447683586530283,1775981280157037775814,0:1 +gcd:80717517906672139,362327909576030289130356,0:1 +gcd:31249856290116188,7875872084416640,0:4 +gcd:5339381130045070,-287550419156538713298378,0:2 +gcd:-28993892995370333046,698005135756870427,0:1 +gcd:9179674525723481348,81469928617693608886,0:2 +gcd:7522547789649675160016,285918417200326088447794,0:2 +gcd:-901774653467788803,236000195734098992,0:1 +gcd:142671415131788790,-2583777714764598301032762,0:6 +gcd:951078283105727024828,1487627587101952300275691,0:1 +gcd:19185476025869672486,2445736876347152429980675,0:11 +gcd:6741226163186521681303,2568160083399218078514720,0:1 +gcd:3987919571578399660412212,9884144363611069680876,0:4 +gcd:99431631881940059268,-291965406586754754564989,0:1 +gcd:36727416735327035,-1612205593089728906670,0:5 +gcd:19590774006340220367562,984968880458891391,0:1 +gcd:70695613219926859099201753,62591913993270611799645,0:1 +gcd:77425442645246583405,-296832015660977965,0:35 +gcd:807971872592227526408,40230405885131399744453603,0:1 +gcd:965370212546292322,92058451234918953535616,0:2 +gcd:418561885926860582,239657399821326936,0:2 +gcd:4657697584188823828175,78713797195009784682708,0:1 +gcd:-38091455008728662,5763777114003492300442812,0:2 +gcd:54943065861736600767,6268390929335695219433,0:1 +gcd:-697639190379957186138,2936028900796584636,0:6 +gcd:96018089280939789090187,29566309848085271814423786,0:1 +gcd:-1112368751522257152114,1995174854903534746993983,0:9 +gcd:-84342841213955171500540,5699084396809137598518,0:2 +gcd:225675029492277024520800,92998377812004114915728728,0:8 +gcd:7655269162163547244,594548791001649285,0:1 +gcd:17608380663675562604,264448308193844308642824889,0:1 +gcd:223093179893694063251643,17908241494426478956477995,0:3 +gcd:-9501451313199296478183,164266650410143061944307590,0:1 +gcd:4558730178677382262,3122005086984557462,0:2 +gcd:54440882483631228680923933,4478571958703194374379,0:7 +gcd:36855929355558415329723,308635436762628905,0:1 +gcd:28683868680975381560,42902583850929860163229,0:1 +gcd:24731088466679335541839144,81462858536522998396,0:4 +gcd:-72335534127835253275,-227166439208550011362,0:1 +gcd:474777034176054735892,839001319154604024448982,0:2 +gcd:6299666296143449904,797331145004636509,0:1 +gcd:8540885149755672764459236,41765710483565552588310,0:2 +gcd:385990739803366398,2963466700114736836981086,0:6 +gcd:-37246197932269024,3005402223074948482,0:2 +gcd:-751622018429096822596,3003864133422104297,0:1 +gcd:-6108319432277782804,-82931541043539126216389,0:1 +gcd:30921518942393713547539642,721143788088068568685,0:1 +gcd:570903751254308471830202651,-564896588437884119958,0:1 +gcd:1054271475454361570597270062,16484741384321323400,0:2 +gcd:6529831639822170310307759,85346429845722052312845786,0:1 +gcd:-754058902141939454006,69516695016006129145191,0:1 +gcd:976193241125104191848393,33823563038032982713854,0:1 +gcd:2920092456500658009757,8895875497550350532901302605,0:1 +gcd:9994369499844252132394601638,93334243646132127297454621,0:1 +gcd:569015432462996733746,16322837154963292812416483,0:1 +gcd:192500272569416024937360278,-235265435750733300361,0:1 +gcd:5267095375035104443898399000,-764192677627393558125306,0:2 +gcd:51025753118541843018,-1664207936338749988204,0:2 +gcd:-62402848465899883613105,12900108782353988220438351,0:1 +gcd:-8212641700259728565,297115088713153106682478,0:1 +gcd:-5313586393962705049080,-76998532453336088964044527295,0:5 +gcd:463290189242313601142817059,969769350842083604500926,0:7 +gcd:1917277332460964412252,-708614825339303498360550,0:6 +gcd:99562752968815530108,23844471852654970991199350,0:2 +gcd:3003923448532254675001,7732856831499478812681071,0:1 +gcd:5794073936773633607324540860,-76553654622431077040278132,0:4 +gcd:-644932980169883872037968349,42642515095105038480,0:1 +gcd:41892582203464757978762451494,68041907390182959305068217308,0:2 +gcd:-5550794996398648089925,-61773015425098686639107,0:1 +gcd:26506218374693057900,-167675112099207386871,0:1 +gcd:145568384864275126584,40072954892382195328941863291,0:1 +gcd:3161170925861501561771687,413220145707787390821,0:1 +gcd:723440854928237000349411,-71208223609049472714282072,0:27 +gcd:94994080481292730137,4307839512004666207932600136,0:1 +gcd:7821178378958515500742,3087104738440174209004586,0:2 +gcd:869891649236864909625695,991848579874131467931448097,0:1 +gcd:17628160996789341122894,299337591195948255548811,0:1 +gcd:99527056994641754235498057471,655773087035017085668857,0:3 +gcd:596721281791001887739,-328175786669349585798669238390,0:1 +gcd:266802917073126657350936,148259550527207353925931727,0:1 +gcd:297095531532857951877,8071469565512676957784213778,0:1 +gcd:-64574484904487858142015156737,351049851111701482889769,0:1 +gcd:9213606993296693767546,-974475310790221342435,0:1 +gcd:-6506246525097752180174,-95653949321972166356216836249,0:7 +gcd:7211807452760603826715508,25981532388511222064867790,0:2 +gcd:244358078258267292267766114,6788410077941126965241803849,0:1 +gcd:-84498071017578145227329893,51359077717175899950414794158,0:1 +gcd:315675121566194900458712010,607326754590110945679173086,0:2 +gcd:3336777364604897112789890,24326442512123908471776,0:2 +gcd:-631164366791648249399815693437,224085205047080377284686,0:1 +gcd:-9374071452933990971885163627,-8124264246742383054580586,0:1 +gcd:-8986611810629266612086889,39090932189616079255587,0:1 +gcd:131042125952122412011234961669,-603299752062616670818260436,0:1 +gcd:-5931135084197112120929525527383,817854717051260202081870677650,0:1 +gcd:37076034350171687718404493,6575825691817817445639700141386,0:3 +gcd:6586877468189252639017707825771,813151310907233772623665199797,0:1 +gcd:2933337084774328653741904208050,516673656644156545121601676651,0:1 +gcd:-9902991686684787357658450,173313993122814232472956,0:2 +gcd:9274522469490915283112908394363,44864081129175577116760112,0:1 +gcd:9608655195311416270604257657,65867528105907714734959487,0:1 +gcd:853239911600142024011098491,17829323361272785163230303,0:1 +gcd:23972081642808055559504902,-4501717580058722285684735,0:1 +gcd:5314236376598680151908105,3994830160691915764873,0:1 +gcd:4935319583093232012062136782,881389216056886912824752493825,0:1 +gcd:580231659494763900889556,96767644291944525456085901,0:1 +gcd:303622305001319462939309066150,-27984889540977885375442171280684,0:2 +gcd:8908131273613694428163643,418798812110676949375564324,0:1 +gcd:604960317372762640669451812,820482420778387317631260055,0:1 +gcd:3125355862613621420823337,52123353846012574000878521623,0:1 +gcd:35876668588605457895900,-237986271303986771473105323,0:1 +gcd:-43001262189486935668928474222321,75601013836677651900921245468148,0:1 +gcd:50360054222226284955381499,-7538629547593198554710875138,0:1 +gcd:16303655607623383537122,23252538460647040924816117157,0:1 +gcd:29876051059586965106021953,26235768232838079362376,0:1 +gcd:29623076251397963944271763623335,47441755805615786352682527,0:11 +gcd:9892811422980328964557595259,603482574014084208448431822759,0:3 +gcd:-2549498483308845928405350,2555383871703609992631017913548,0:2 +gcd:-935906971037827073384146870,879641356065373793312781,0:1 +gcd:19597038710644290533555897021,2985160892106475439715913026,0:1 +gcd:-5608937456930306694772980,836399586633606428927522624674,0:26 +gcd:7718522069758342120350478031,7389561033066750535580836572,0:1 +gcd:718875898101761373218778459,686314096776480574628984874102515,0:1 +gcd:1300200863593962819188902,525922101427424561614551608409976,0:2 +gcd:539220635752920237029329058,29487916769600117002583914582181,0:1 +gcd:5654437789656914341120143121414,6765853316633901505298664574837,0:7 +gcd:103114174998937498500059583,920095995082794389728025430890882,0:1 +gcd:29882936700790118228421849,-1860889369990333700884198092,0:3 +gcd:8909623809613954310018698,-462806578041198407432067106139,0:1 +gcd:7230230288816368650543810,22162946284655819337870476,0:2 +gcd:734442358589456361847988629,1647427465162259118128391711,0:1 +gcd:47616626651192848094181030316,2182277257935167463613810412,0:4 +gcd:294703827229370598691617,63046555168872062038888853,0:1 +gcd:-533653415261740333749397,-51216937243134223196656339350075,0:1 +gcd:784368839220787531616946253680351,39613735771181195550018240677,0:1 +gcd:5770744507580580048400572,231937913382367374762373686161,0:1 +gcd:388816489715059942531589642,82051838197217717225950877,0:1 +gcd:60241729629297025142644618709,85181464884435369517497693388632,0:1 +gcd:1560786485638020475934392460005620,8850527081981124295638445,0:5 +gcd:8296622334734688413856037840,-83875508267086319614619277276,0:4 +gcd:-45794179084517723375284971259238,-49063790774577780701852303,0:1 +gcd:1752071933321291709931075226933,57773126045256149501100162,0:1 +gcd:730668796977177255106481634556,938608337106204028806933670639254,0:2 +gcd:921730456287198291208119641693911,5458708493078803375257300,0:1 +gcd:213400535376420556914942871216081,4183995847570912793889135547893162,0:1 +gcd:32806047880829491896013320805772,753489056993475245589087354,0:2 +gcd:15218771998961411533589410518,23457061020403160442042221,0:1 +gcd:9046617676720978441798060,7479379807328977629621989162,0:14 +gcd:2219170169044655639393672927,-5391273013704097527490654785062,0:1 +gcd:277590531551034474232270111103,579362077865358674190909581933,0:11 +gcd:51422590325724235826789079575,2121952875387495603452158,0:1 +gcd:511034032165016743768820348,458982236103828060996895790272,0:4 +gcd:4440454508740215531301617636697,3258309525326637800581711028116821,0:1 +gcd:6330009746329830092300048092,-6167250670699283492360751201828007,0:1 +gcd:-9374602262965156933926707655416,-30595740075402425097079774283,0:1 +gcd:83645893910576549628700447097824,49931389572768584324081547829643,0:1 +gcd:8030747712125824227213267818544,63329417394086865663449328880556,0:4 +gcd:378845361147099357535431194,38180105668041356349238612217040,0:2 +gcd:25958762365949818177158173188075174,40582859445868015162861781,0:1 +gcd:95871031013239291309686124,64936572493882710890460913285902999,0:1 +gcd:455128054133718561191432952712,39088645380524987234419335395029,0:1 +gcd:1307047523348091088814812136,44132853285705545682051355847561,0:1 +gcd:1418285824252402530993393665755,636810955908181043849421782278,0:1 +gcd:3071172872783184341780369192882346,-58125204065109316437571977973,0:1 +gcd:56958148205198214736866933854,4922289245511311172745764679844,0:2 +gcd:4836813580368584281452577588,-5400032605107989894617874622172581,0:1 +gcd:493001845960066187429806680791,4028800209124423703294502145421185,0:1 +gcd:71197215106470682909632132625,70077573297929109151274279,0:1 +gcd:486722080146274783096432055886,505595939085965376271620470551,0:1 +gcd:-194536785271632924316130857883181,8276525052027013498990299177664024,0:1 +gcd:241211965193448971857220311,2710726738427327769580581757190,0:1 +gcd:667013805494915469984846976421,118549400818390788595763048,0:1 +gcd:507926799850267721181735296662204,67253859677995358015731931706714,0:2 +gcd:448088677681619431331494894631309,779948091351174817338856782981850,0:1 +gcd:187408370748924381155985806145,495794563709904959946586644094587256,0:1 +gcd:868633158815673181555237006,836615025635832190680248872,0:2 +gcd:945386362083356835627622353491,8230893874122803805176630038821,0:1 +gcd:5596932048341890824814087121,-2850793263280920843358756089,0:1 +gcd:92079468846004092188293849,65000203344267255501708018874742834,0:1 +gcd:284485059147524530505559245415623974,-52174853366891975161102679787418,0:2 +gcd:225019940499042054289943285,88057001889802818516938839002453179,0:1 +gcd:267625311635136684363577960127905,2364801628264216400078340665206601706,0:1 +gcd:-43414374537943144129863577734786164,-7033210862612719519352562332,0:4 +gcd:32883132771659855270849300682688,359989040176539024964573548207106,0:2 +gcd:8225754994306229461538669946760,79816684330375527507314556065816,0:8 +gcd:7425838080456254658426507595,-1772612320788255147892065709861,0:1 +gcd:1660461221569443640519526747903779,1120888096894032723781619067526671,0:1 +gcd:-11718764104457037189982579964973,581785925357694644406822708535571,0:7 +gcd:6811677000322905212875962023,8457366124986245338105030092893823455,0:1 +gcd:234277964462994083732538315234,60350281492645017737168270090,0:2 +gcd:4183588612759663468880479337,-629574038019737820951243554610835051,0:1 +gcd:2509727174403533842481294816277585179,366325095871570289922697736369296,0:1 +gcd:9652053493694317708921453500950,-91539642994112368354952933916454,0:2 +gcd:35148593969489612322148628595,-82585065708416968121031576511657,0:1 +gcd:2800741702103544119527140802733199,46761480207188283686223358035,0:3 +gcd:441336276433669766301405280032,2656936104993980830437872804,0:4 +gcd:19746122571650880858695931178058857,104545112367422664420669962306,0:1 +gcd:74432478600289091913597803372,1021411507303737809729230605483660893,0:1 +gcd:37218119790882940825047165121,-9786692593914842780007874460688,0:1 +gcd:68400175404962139133336849460667620753,8111497426974768586772111911266,0:13 +gcd:-36411507888779255237781266679960702586,288273015425729999064058691683,0:1 +gcd:-93804297004149089553676142929158,72597578405766612297542242292431,0:1 +gcd:-82026709713179475197473688526642531,5827788603588390535677091203646382966,0:1 +gcd:545760067487517393173385480028,42151112506666653978439280505,0:1 +gcd:-697412421088675986809554647004214,6926944054264140642234974161460,0:2 +gcd:57812799959867792819685059219,779735108345604313576941265627654,0:1 +gcd:1472311567166258003445083977221663144,83378953824849274359711951741465,0:9 +gcd:570337459673916278308389115966167469,6333660822968779197930730584647562275,0:47 +gcd:-388785693105293562593219349398,820248784628021659491960244881371621,0:1 +gcd:11679788667362042415563834445557578,-5819547639993570526822921884507,0:1 +gcd:-3982959591737356792197606403519482273,-333248358612381656382679653253,0:1 +gcd:17221610285774362123428353448280602,11458184790118982447972303969280231679,0:7 +gcd:772738633297996807166456840381926971,785759122171938805714543081571173360415,0:1 +gcd:125784145401376536208808801528812039333,452055550313139515567680226389953055,0:1 +gcd:32903571905950760393177782893378791,6631740924411766007832465757451477,0:1 +gcd:8742677352155721160009371273251,25083360125803108633092433384973055,0:1 +gcd:36273669132247708836176424212020,533102320793846929600697481505030771,0:1 +gcd:11965144674509690079804137520044857,9349045655011350274674885782216185552,0:1 +gcd:3321305668226664033356712162893,-403949753985171409898849824686029161,0:1 +gcd:7395363159337411027760652209127419265,44729331460301249556947662501414682,0:1 +gcd:871058047335719958990871843414,28094200616974302760918376942978068402,0:2 +gcd:7704699734056436938779166257084,546898541513497897846722209401,0:1 +gcd:950290435067652970604023856243611,4001208123591666075058892234775,0:1 +gcd:3119293215232541154035748455321571,808684220462127868482572087900610,0:3 +gcd:432360858532087298548744564083197299,240846574096518547683557847064319535,0:1 +gcd:-310788798729818682147559678302,-2172955391250831365155305151397888,0:2 +gcd:649283478652713472152371045373000641269,9179675498867400603641823155076,0:1 +gcd:79980532708199255123596245351024866045,35273005660545430889304120342364,0:1 +gcd:-83351007958684418946822288153831314277,-51634644710916030743119182132599855,0:43 +gcd:4992915740405389949821656927954249501,4523923119542484578579105473053048,0:21 +gcd:-801991401381703662108108758716412,1462655905419442096496214673085035312112,0:4 +gcd:679369055865583831572651301119431385801,6364653911974833953564963906049365,0:1 +gcd:32178714589413433072024739357148883,2182815001928827996341206621079833349525,0:19 +gcd:604754886257955637472038235002006997,75686581968330008368600832791867,0:11 +gcd:287068066584060661996114628597630371136,52011890293701406927883275870768865,0:1 +gcd:3979837024286745384581666788748758,7350136706945206821986896298939283,0:1 +gcd:7385865195603313817759905903511277,1520983986703891701713359953638,0:1 +gcd:764457193068206149728854992613,27858021258550102776458498820919,0:1 +gcd:-4155789385717252736363125208379519,513716864065732253356348104577569642,0:3 +gcd:97365354260983249124725672833811771,5020029690975786355406829440294084209626,0:1 +gcd:83139160308299020652846789174256754,3913486804605023733190361150860684,0:2 +gcd:-17691166446369130975076403772363811082668,94600134419678935394632555907142,0:2 +gcd:634823647473707443708903538054380,3956996255499668253479385484122050809317,0:1 +gcd:-3637804742599340390876015169076139565692,783241759542604459838225899706055858717,0:1 +gcd:585812248650822285457691267576462,21534520461947113931625020852108318,0:2 +gcd:11281432653044672416448534028211038025,711109480140515578563170257201359462,0:1 +gcd:676293649029453415159585825583394,97280549393475973449516311017466882903,0:1 +gcd:-60552656313655809329731693060696763524,493007935144068742422888317617165,0:1 +gcd:499127054152037037035927375386500,1203956412395744650060889503126393,0:1 +gcd:50094686288665713475507184834256049095574,-832478827433992238527275985275884802100,0:2 +gcd:3587136855297236649460183411772356035310,-712398604370738955166219235841134498742,0:2 +gcd:-8101551106022390770336067301182994,9185799272249263720169676176910186035467,0:1 +gcd:68680574795029722620883183609775450677,-84158462638889794851250260034014551972363,0:1 +gcd:155258118178686765062886673806448566,-6850017870177195667059084688029341396610,0:6 +gcd:285166743996114296479394289968524943,559627723033455856754700399288311,0:1 +gcd:97635198013817214038209538637709608537616,-43337611052093405089732573050042882425535,0:1 +gcd:2025635628106428290541842218677337,8363403252785996217814021695187802,0:1 +gcd:39403341320445818916772945982544618,-3081545887974055895915003777735743,0:1 +gcd:66538675039876745133366881210395320367369,385523580015310377616062750074359,0:1 +gcd:568797587304724025372575349953868,-809993079501337508688725757864677957,0:1 +gcd:87438670031005707662235517162074411507878,762858503307630620547057859718065131261504,0:2 +gcd:-135539991676075663249711183869449098,3187117064807540583340853903135708355720,0:2 +gcd:3623316226168035106420698863103708,281527696822113339094642926844583498510,0:2 +gcd:462743256592937700094228107961335,-6269566498572477078237555404177435,0:5 +gcd:-685484600842741055621576203380446857767,871551172534175305655069705808532,0:1 +gcd:220964518681325411201409247135357488007,-5641829172229111635876189209726787450,0:1 +gcd:302531333113895329527974519952510,186535245939488501803212618851457571589,0:1 +gcd:817537141270922830542026664184986,7821981713799768623509532856543951,0:3 +gcd:8468979244486855292413811013010058,-209488808243349961649691393540068,0:2 +gcd:879852422051274089521663230058530,49497155404087571445757965616479604,0:2 +gcd:21764922287301916637920770938954126,164044760066720848860497915166650797335,0:1 +gcd:59469732179854673335933541543666124,33859516881008254191737434099260638598,0:42 +gcd:5622782096444522942366700649751601671560,1818924766888381565955786591467033096941030,0:10 +gcd:-83658234598433632746857009684831849359505,-29016349811234824466750396183186748,0:1 +gcd:7054089120269602821498711515003074,4095832337673576318592596805192095781914,0:2 +gcd:990394898068553803695514279851854605418847,-7739084020331097221051527297005947155388,0:1 +gcd:54075935489906064661012070011939942732,7918292813066039667153314788962651008581,0:1 +gcd:8772115771437424285869834799732506658796,-932849018789404004804426567212331569,0:1 +gcd:-474373401937043543973615567508636867124,-23736477393422078122335330115520892673,0:1 +gcd:8436352086792195283692976718955932574,-24226347745891111460405966918193715809620,0:2 +gcd:814519302031186083731939523439915121,55324835095437197264275880684820442585,0:13 +gcd:-237764758709584162016066869681905512952347,27730963225107998869867496093972168,0:1 +gcd:7518474854158787395750001309747813,8381114315785290417935232114225100106214,0:1 +gcd:57926271609377407522025180011097851547,-460438760475654775684236043340437433561,0:1 +gcd:6638349918167655693810387712273716693403,55308325418124425819340246954531134649556,0:1 +gcd:-792096039638367514268257857215475476214,17985352918594429617981644232595132,0:2 +gcd:17523605051927467343416676052611136060682,32818776862511079287568864844380549,0:1 +gcd:435598204136143930685119666237820390,902306362378699323196514142749053448065695,0:5 +gcd:7246625600474134146152993995542881524104,84045078681310625106949990828070364497,0:1 +gcd:-787638361574460696958641849383712843152717,-98972482600264920015196417920239935812005,0:1 +gcd:82374608290966933640517911377351376793038534,3375365592517566879211534105358267232412929,0:1 +gcd:-65869507968457359071511077346860349916,233541308077986424091233056554170108328607,0:1 +gcd:434965647854018848199731601803786298508849,6881642201690537465635377223216241,0:1 +gcd:719612999193225374224745692059996056358,-315519530953816852193901984099603790510,0:2 +gcd:3371856558784507755414140667220962994794,-46940188151078159734582108552804551252391781,0:1 +gcd:4803433840417804894873156694592939602852,-72456645795090954873268375616538340122311,0:1 +gcd:48568835567133010333265540506612310476167,-10706367926604784868082114989212135746648832,0:1 +gcd:-640514959144433868933444881224466486263623,495227035072426375802319189512972514543836,0:1 +gcd:-6488859550432975345382980598094012298,1739553070312394609661279054142037504040,0:2 +gcd:62439762329215278757554454849955204768025718,79602289985731119990152260854511851,0:1 +gcd:6054057220822234921996955072468282902047103,-41461621564455176604944655360416823,0:1 +gcd:41593335543156355768394832800525873230,751910447000975730197547607815241920,0:110 +gcd:994454253731718339598418586069934146007,674502407982587721309172287657440910774,0:1 +gcd:467599304203676521904495847137440151064429,1065364075426775111107441639016359411726,0:1 +gcd:-50006834540638623993722097585899096403763,-5313099491095445109561808031972399857647,0:1 +gcd:80633786527554906657368596063180401716797,60423064130048311342811193512905633441,0:1 +gcd:7515721962363288712694440724080300383839,847957688242291310060264069657345589412622,0:1 +gcd:27726212382161724111674518621229053817654,844465139764626291093420179330707907,0:1 +gcd:-9817131728229141224738800156068771165515,5514447437310670168515402768125807553,0:7 +gcd:1101490427405231724327190816394483390794764,-1715150116840413365727028822839059671039358,0:2 +gcd:8714614705512806124985108394035361802445153,2277516152797095323407597912040972562623326,0:1 +gcd:-40241069975197162607015133362864260639182295,92350494843755720369837991386076354459722485,0:5 +gcd:94926798565178929705057494111757110129555,654944641739167114202854904453615515658738188,0:1 +gcd:265280847975099333384365084677641815670787,79159871617113409657206914064640126799879245,0:1 +gcd:116347226264838928071222153238640922289035,68573180747149861177662470447052670907671443,0:3 +gcd:1040609825768545533315151293676302487896884,-81323728160947963681253577857302080515,0:1 +gcd:995902591817252306534602024050315471330353754,5332558356879676808399004303967153306,0:2 +gcd:2001969035383918099033090062929650143669765948,4190101466247488888803682714062857957220,0:4 +gcd:520711239532941932960582838954921846930386522,-3853096594619017503346777573808512971,0:1 +gcd:60199373689261241651972446393273631317362,4966864098864732001544113870901038040,0:2 +gcd:945149245494027792287917914515672725163081263,8902933189066222709145663761457459365794,0:1 +gcd:42113632082774519107063284261972952560637120,550965713086089226514793739995356299364345,0:5 +gcd:699130208513509445029837360613055447835,1388996167624703080432361535173321299212301763,0:1 +gcd:2708864861499120155181972404884433662661130826,-9669434874243213781569557549324652869447,0:1 +gcd:-2663320619224926510783240759799877830,-9288856838720796348912703146202293649985994,0:2 +gcd:129339208558322679510730678747389994722,12274162664070343010820636150243461714,0:2 +gcd:7927826382521640149002540477963715500150746,169024688202278131082480706237325364215068990,0:6 +gcd:136906526225769628858637915191370345692692,539213183682016621647404279498623014328141,0:1 +gcd:30681142365936990868501835461428152495,-5027491490146180677917496407674117704,0:1 +gcd:-971981137022757867271162004648718096950546,4334305792750860480761829171455584581712,0:2 +gcd:578802014801938809246604894083179003839,4755521418153118560811649969223227339815203,0:1 +gcd:-85637729865865539531457719920611651870241486,974400175977421869121902925057819107693817,0:1 +gcd:-168964790731095355351979412256338118430524648,170138331609580398941494555432555720911428772,0:4 +gcd:790938498909251314495722876378080005340582079,5214770204816378474402582970231763702140978,0:3 +gcd:3097935765451813281781983641770574025792276,42609404056306319259222360596281494320705429231,0:1 +gcd:-98485087154927525975034391790808080098982,19775664577849930783360381707025488283978,0:2 +gcd:25900464334299058097279910365875929228,58255952834922520501042331752256379575,0:1 +gcd:79400185595521899110261406600117591081721314118,201740226840130845073877991057259510967,0:1 +gcd:981167299738316185980724229187020822277,8133607419206585086507618470282084549435045911,0:1 +gcd:81466412463591236560961446462245299836549126707,866192944729287017177690246604876328497,0:3 +gcd:6534998388738554052417315288897046254899165842,46609611771478693989087838979597248775,0:1 +gcd:948084924179221265735435784532032916982,31095014697784883179376411641933005719333,0:1 +gcd:2750322192684776089555518232723747026,16282797711115835147148988819960931175880625768,0:2 +gcd:-916832268194684002726682872945582785046,80175456371164380904577325966825746198033406059,0:1 +gcd:282231592138255672195189656428026230056,96673996679717919403145753072968455552546,0:2 +gcd:550580097204590201609373226827993784219420731,60517713169991893657707958780297059239491,0:1 +gcd:31526794192792048622410273704705620482050682,70537996848502378104686898733501905256490,0:2 +gcd:-923613180033278870451470473112995033306843225,62635452857298067541908563173475507759656054707,0:1 +gcd:469196843768624413897755875308788890398465291232,-15296277161521766221056511754171865009042943213,0:1 +gcd:2628065716223500508449356215564412668664236,713708318009199991674271791693482010536664884,0:4 +gcd:604553604369312265623368647573085123221252020,990982890678004704551740474471789043760433700479,0:1 +gcd:97586462652371414650265963064033775148721243,969409880443270812997088798402379069080662,0:1 +gcd:-765406874969209688613302257358735487317,687488505077706911028822098735771705823765697808,0:1 +gcd:85075624707999635862443444914978287825359,778046486301986342411165862027907781749497,0:1 +gcd:8227248806783006644129224253415431417213104067,-96883503079217553138854609209329008354340832050,0:1 +gcd:5027554007771258456873599804445876368468,9124875242153734630106913217321584664013715,0:1 +gcd:39245745484403729199058188063461104557810253,220067769421357576954105356315871937975114,0:1 +gcd:12265626358518464602956912462337886264411404165,-62808539324142868756473505816723401975937,0:1 +gcd:-12272356051659726939876917766506363796290,17656166644036956054896242696928896080969790493,0:1 +gcd:637223594292638303876168193085997138882431056,94504571343119776477559774058446419793557358444,0:4 +gcd:5571012420064356266635359647247635200655740,-21295217227115690481188602248443089551209070396,0:4 +gcd:5263843748978600609740419748581371970418448276216,5384845751134428162699702180820131424931650492254,0:2 +gcd:886573921242233631853410597832339291851986573,91564665302299543163193474542608720062467,0:1 +gcd:26539751625701457124278640373644598585396,2325338527842485879693477585982320189921160388553,0:1 +gcd:353508003643539157483752498296868928280378,10742495675871104458509832622060247315860,0:2 +gcd:-4734613561112436559828705330418786656799216681,5767402184612349878575526105980302509419976764,0:1 +gcd:82083010698635736174070971617820650592649198695,632174562080517027772509374721051956918078145045,0:15 +gcd:6173991144338684494350090118957116722781373,-738485502817232028305101940854863776286515,0:1 +gcd:-493513047233893983448577482415236886372545860,510358065314512191744416886029069217313650,0:90 +gcd:326654054139623246358073868314669601484091,-749350879522921841553744544029160051092161118734,0:1 +gcd:1402621524995633967650615579165227953957890517212,-4307813373241246419295301377872133252586,0:2 +gcd:429404746005804957738561594094664667352987,378882853314853204091011966904771925997210303,0:1 +gcd:332341701384724523211310134953299492552149033413,851224516641538736779656410258860743437969813415,0:1 +gcd:8093542646198882950722808884458624246299608906958,-36537804019444103265563497755234936603188804846,0:2 +gcd:22659814113479956892126670971189905912120035824,-7769923990496178313173088170032841760727,0:1 +gcd:-66431972193306385702365512934093484764859082,36581996652652744665199423002405565247156,0:14 +gcd:-888473800362239868616054745127669042022317,142999759078860850560633007783677610020527766,0:3 +gcd:5971942663513046812876552589351160577576206860,5155119487765712370432570496238254289228130147,0:1 +gcd:36328343589972083920724771391132711614346,626466814451530915421088090957480792070888316,0:22 +gcd:5293116409600323220539205506696278195160522774280,-89478075685508708042860880549625934136374,0:2 +gcd:79576614103508536656978289576589750212587261,852468870734033057111244131505440601392558836846,0:1 +gcd:8225066772418695359596812838151452668642167,32895491347247919323385073727832554930053,0:1 +gcd:6163942593967174125699747500635651388266851958125,35785148285967657728202559017385960485415693874,0:1 +gcd:2768453763718344802615194690925869147682838954,295289393573622382700104229276698254424111309,0:1 +gcd:543530772918490900335995207569824317804903920459,3816523263571207729432080444412751436592123632,0:1 +gcd:1092477340633785505464776554395206472561372312061,-80145274095041381989361699268630409045305877,0:1 +gcd:5221300639042222043517187865188827094681806,28716457589092549537459686031371792838180039728,0:6 +gcd:-468871256127286679587501070578429844680401783,7709908112767006788780052051800778651016113933,0:1 +gcd:60187668034435065431875732180204005950423,6575730301760601160210842777500398231559661,0:1 +gcd:85750547893356514086330287277441673045104762,79743140579005364490235586620393656130064,0:2 +gcd:4548581293372942515724176487253593549214930,4238661184062900689214356649238748109095650,0:10 +gcd:870890539340345883811990618518239041519315472381,-326492148393756245001717974027772662339968,0:1 +gcd:66987553698256227716875714961629477167428173612,90975165679807773385648454136069587671757554212,0:4 +gcd:55214217278725852504312036656428464058159216571,-38639629611220548541845337991516346077285504,0:1 +gcd:891217139364757949280558543150622433360536923866,30525879876993440244467275213072433106397646327,0:1 +gcd:-27569366446500582408824975793718887457276922405388,634666021153562229559368735956062829411322343,0:7 +gcd:502864235446447920785714797929749621810588808385,-661761137717295415776353819805381820532626437501375,0:5 +gcd:846540274257645306570757431119674434472851673,8616613565185012233547219046445322085886975,0:1 +gcd:-3309007371119113533010968742743901666008447,-54456422219293958622124113256532150483182055,0:1 +gcd:3808438337556464123872249539607274641406985997532,8958313515020597801994910602927304472155060964765,0:1 +gcd:3966980856734279836284487724100931405197679196,7991199588345191911654938564028578389298180118364,0:4 +gcd:65639444382189527381103754239686068124303248439,57344187472963481946737524023690750337279473205806,0:1 +gcd:415167227201847402226579925485934896345892,586575228633844519664975226407615633553394085108,0:4 +gcd:61619333876398280418219395631027787927517659829394,919912829682211281138193507951318719985265,0:1 +gcd:-868753784405826481862596863379498777711457154096,545880080147628730834302628389405153791727839,0:1 +gcd:9429941770445780812848883836626433106364646270218,13789105660912116612159357433833332620650429,0:1 +gcd:43608475425036256086742701999180132009804867174088,26543470249142438881834938827109299420258184885237,0:1 +gcd:57684506610503798187871631196324475714333617510881,471695506003883133237678946411955700467360,0:1 +gcd:45545031179301366913301053296868047362176530184,-91968879037454375774626628433933013352182139387,0:1 +gcd:-390021533721654785753654976920878586915091,77031076759836910371783959035306703983828680,0:3 +gcd:423541795082126371645621560317104281087986536944,8300998559716429411460238557591751288655280830676799,0:3 +gcd:-22004254439719621882091733525180851819037175217519,99335356922776842325949741933027888097618837,0:1 +gcd:-568617824838411255064542027229734991599889058339286,663945656360600870466864889023341282183894393751666,0:18 +gcd:79416546968775553905606945911160893343240489,57823044209535496953371020115352329847370545,0:9 +gcd:944931014689390846530685010237152128723129879051,9132010491010578008428313272813386452749469110941235,0:1 +gcd:10724730362623743957337791385603755532922863,72480373654893123070601266938859686093303005387292,0:1 +gcd:7713352208339235603081099644445084271357860,603624463205826416829628929324533190899935786563381,0:3 +gcd:-374652992235609318781751374140306949494493761487551,-8211631925711097443824357620157273567158306960781,0:1 +gcd:148033237001979427358794216800322662159772216729882,-2761071692676096788505988250569937615812882,0:2 +gcd:8799836897423935827052239970797993642793054321869,7294647877437509677171255169879966954414823484,0:1 +gcd:638050122120135743843926357476168630346968836720976,-521011870575614667006902791543319211035082259559038,0:2 +gcd:-17589569754541719055752617853886490778777621596833622,-757763302557856615098419826290170728613135917189,0:1 +gcd:-9391500830250456597029446286855934735787373415653,28432489383197015180933073382445953529667174,0:1 +gcd:597671128380217947385553643776956963479914986403,71727950226724858021016384499343090206442916,0:1 +gcd:220524861586728547654066186650842017022514113,99830670175055229565653522851124444573641171168883370,0:1 +gcd:-19711747183549435340491469077888147043386014913558,-1141914280129478236596364286858351511269528735,0:1 +gcd:-8382072953685010521572064715326232892979307367,8986558828596332338706049003428573784660004270,0:1 +gcd:8502152308582607794375019565844324676023491104593,10470050208175536662422671560468368371690332,0:1 +gcd:594601725521916181847167140525593251441576703983,963458725567603941710493681498226412426881800,0:1 +gcd:7141961266638507042734562322157608790427840009,-4549724799885066646710284284349071123364728193387,0:1 +gcd:-556279059738139499395948604306347001411150129841210,96265906951839620646630096006130967227739083772932,0:2 +gcd:9097507009232650355633416767082868346314279788737,-12952310876092402836370081770801404571317963729609,0:1 +gcd:4268792759888467657870170840963084681877952381149,45230992824683770972952637110379461673717665076497477,0:1 +gcd:-14981624589272129153412283534256311120144659052,-3422881033749335138988900898217088225431538419464,0:4 +gcd:1220927142068793741881867214403185329458765760024,30622524744504892825380221509502752145574896,0:8 +gcd:37912807996403481194979034824173466165481184382714959,-90878397829297201187948170371749592240094934625,0:1 +gcd:11421510093950565340830017403217629128966938056,2237414009357389011349863244579333296452235392013656,0:8 +gcd:192657988036570687555057992620686662908295387946910176,931495134488306662235768448970442482109561110,0:2 +gcd:3406199971289940059753501832956133340637816361746774,21717729758322757474808809344766892648120530501033,0:1 +gcd:6909979467876024377878180024452018966109074368033,842722308262405734840545048662350517397572773044955,0:1 +gcd:373077837411940479742523640303846004174658252010,174968689985940718533112057941120724001834591,0:1 +gcd:69447921082122879577796325457481062492384026062297,4859735149388070292660864796695584862286590039960,0:1 +gcd:97668956744134573191931364533568770116368809990432277,32650097939706033583832290610502297382443475332059,0:67 +gcd:-1130623853521736649164698623052358825973875071086,97117938880122601762963490311393663414262844,0:6 +gcd:5196766948376722446473792182397797566282488000645,612809465745222737408369151997835003504928829,0:1 +gcd:-260800009832764286426719551521843883719112476,-4764630548313512861236355180550436291099515479440,0:4 +gcd:446884272848375074930942162217302913946161786743256,21042882325490620038960351129083746002919260315816,0:8 +gcd:951599922613172445123982155673072679115439437787116,170174123089259663169419228763721448308107859122519941,0:1 +gcd:21383950451514823653827321489681070470148156716394,474049024111864801681311013604155672359293053819708610,0:2 +gcd:-470414357544256461922663993336752968654129573423633,9062081906619161788388889503790336651084511675587,0:1 +gcd:780091812513073375693179028189802313142318232500,3497278556984926411479728842600230671778387696053,0:1 +gcd:-1625948018138433921639232759767284243608022009577,842118879046315463699452834842435152085239651627,0:1 +gcd:25026283351500865895404594716390919370787136725638,193605742569640932386538365909397399503766353419,0:1 +gcd:4935030558829975380051283297334807636335988292915939464,826975811338155401386754284486847375740824437795565,0:1 +gcd:692976306506130156561485116659173381923120836885557,770158528298664593632506223863839610768381103479684,0:7 +gcd:79877139216893064041018839082816187503862428735,7269106113282857654532427145534479409503583394410641,0:1 +gcd:2539745404867281753796678186777103230989134057269,1232562503892732555700624680547460824244298064,0:1 +gcd:-12342369542383197426854745694214905543911988477283,900468407001638487525579769577535461149066925224901,0:1 +gcd:25508383419230789798346692675791795579961116333703,-3196912743165527117167038251788165837584914845275,0:1 +gcd:-1299528036083269250543034346520127753461072609198859,600594652353551219594047525595273354045086799190,0:3 +gcd:2299157394917175882710807816574923359426328448491205413,-72838172890838078649390158065336999589794176457016,0:1 +gcd:-7349901043851956691882158234459042155688766310737050452,38963935506607940884321914070762438994955796523516,0:4 +gcd:958387014018743982544025716556283287504010616036,1443504353635051762579994152447131178181054158,0:2 +gcd:246125390054194220242986809766512103907648232140291,244701030143825150512131468437935457382757506654,0:1 +gcd:-704660850546084071765145007935951186831012905395382833,5588984198927622386999113229239134076765551765835797488,0:1 +gcd:50682657377075501007405908966255159073041913889268,-221227972486061875975200412557047324616212536548,0:4 +gcd:-65153936048938235385603864221810574284616709045012408,2620409042204728497893539911547700871421142555353,0:1 +gcd:2124140486540339235997181873057458560557130144031198,6337118390151757487365380009696068490770095523526655,0:1 +gcd:70505951289040282645383932312380844925860919298,7547000534925894125969206219651626162975048702546706065,0:1 +gcd:-41539404414450841529694974131865311088044938789,-87120273993379326877611820290578462959192080166852098,0:3 +gcd:8365100924146743906263010309561180555381451232169,64464903694507870558459227754837948332608708108908133757,0:3 +gcd:-607028381550248615720149092346152462853976790359415563,-638047705393414341349283089715056902457142563666819,0:1 +gcd:9617834842433276206013447576300042077483363020815285,528061422615472570377974310003284316297281680382590494,0:11 +gcd:86576571095874523146332767288469633576872568596,28806568894922815646464384363885717260300665904363145435,0:1 +gcd:307009198563449723583109556832166934014223122475324,138726608616028283757694379054230076836833023549,0:1 +gcd:950446831200123302940271854492691726825599408858,-72101792770002156123347099210449392040964040896942,0:2 +gcd:981208671446974342191660850214776536471793694644642,42331603864003005956059961823201488180622810810249336717,0:1 +gcd:436034751789860072246023599184144455891992330310990,72833959249163120346712529298424162613591559886645,0:5 +gcd:90712859511805773491925085535825623597765615019643547,-747515802065477997196092836504038150570958532540685162,0:1 +gcd:397399782669545823592934194763075791833495372998,-59196779886291303828419299835113054892183602687860135035,0:1 +gcd:32400956990211215478801690694170683149459902468,-4583955972534683626923454093368608704790928252299,0:1 +gcd:987205647053507741802554416690401353287928887038,99876648283232575129630115679242229378848334523759990898,0:14 +gcd:613843278686603793281546390730144010908586402122774247,-5096436233192165525303465082471737429087562092805456864,0:1 +gcd:-976952961430926103170472845979881570029763109667,935178486322270132160329332160301439376977149568344208099,0:1 +gcd:-14766907052440196735362466027665124699631240785562617,56185497908476101017098165076418921931361374576783903,0:1 +gcd:8086945629611784458016532027184114429962417844094,915144274243273504802165174453120299631299876477769004475,0:1 +gcd:78088762763327100616786616097147636046671948600444,567540241084477255158834032762283528860020033647985833,0:3 +gcd:719986964333569855824423695658491299542433105292,-615276910378191482694097418592439439457014608822814,0:2 +gcd:45518095176552517046254533808850801860612235127698055,35562211507032265793347677842985571735031362689772443740,0:5 +gcd:9347651927739244225461883666785850681796998039204,-49878021756813856103391637115956958358002286487531,0:13 +gcd:-918018144578664428004161449615771398954961013294489,-670699097650597095681408528960639081653596263477957,0:1 +gcd:27390700201762535100035783959539579449610388231,-1589447744597072139866306928627083981945967837919031841,0:1 +gcd:2277199840598187516900058221233481999025368188568,9608219845154413235861538421470991851896216584568613,0:3 +gcd:-384224188940171310851587214747099156035618205974037811,-365155157346205326208918238248019306559191342503,0:1 +gcd:286446854858822908871115682474835177238732522628,-57158496101544373650727927690968913495792599007869,0:1 +gcd:-381089856197823678538852020226946248080829424869589,-3010621081997078653311455126099557341287585438919,0:1 +gcd:116824003493453841699155925492342665434851317689062,-23510392931055495213857939210838689217666922526899551035,0:1 +gcd:580076669302513896163920831671903321718154827187111,57642903862300589084685292813271561699366462736142,0:1 +gcd:5760449410973032312996903274730533429280588604119,54924391723347076414566698417788233810196808558058264,0:9 +gcd:5657781195595763129830083459999757852112323789572340704,692061618840647789470644193517118113508111433346167161307,0:1 +gcd:-411686824144764716061907353842274549877341843077020461,64596348790121485579427789661619008385819947602752810318,0:1 +gcd:632256394728894097701649213009572878755743290206395156077,831219707790000649838963373434914934485492976701321111,0:1 +gcd:1670481530219772906326138470230000469885289884882422,468290338328174403769157221534943442214405575737600,0:2 +gcd:-5940255960924729598832299636442321100271324046668226,57672031765846684220194592702663453624777841860734299817,0:1 +gcd:1070320750308710183653165839089007570013512879851785,1457798154372592051774290334996812066679847800239,0:1 +gcd:4878833860261622243309660185570248437064542060170266009303,2713399212910344466363698742990679778889654409261764714,0:1 +gcd:-153727669883775746511963322850970227020812560900211022,967696702028565741720227898697068313091723784217356354,0:14 +gcd:-540592613733911579302709730020084890208422708295834255759,1487237786400760689794761062671094249214728767786149324317,0:1 +gcd:6147134348286513705872901614503400707429078163757093529,477008107151085089956583728568535862114663515203848020888,0:13 +gcd:7614680849639684551334463800131196276563566036683927,25187069984138015151555984154271413618496480687947851,0:1 +gcd:34751974072174908316243318351151710272413759348773,8306602488518142539700335965542308143538343391985,0:1 Index: contrib/isl/imath/tests/gmp-compat-test/.gitignore =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/.gitignore @@ -0,0 +1,10 @@ +*.o +*.so +*.pyc +#for now... +test.list +gmp_test.c +imath_test.c +wrappers.py +*.tests +_T* Index: contrib/isl/imath/tests/gmp-compat-test/Makefile =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/Makefile @@ -0,0 +1,29 @@ + +LIBS=imath_test.so gmp_test.so +CFLAGS+=-fPIC -I$(IMATH_DIR) +IMATH_DIR=../.. + +runtest: $(LIBS) wrappers.py random.tests + ./runtest $(TESTS) + +gmp_test.c: gmp_custom_test.c genctest.py gmpapi.py + ./genctest.py gmp > $@ + +imath_test.c: imath_custom_test.c genctest.py gmpapi.py + ./genctest.py imath > $@ + +gmp_test.so: gmp_test.o + gcc -shared -lgmp -o $@ $^ + +imath_test.so: imath_test.o + gcc -shared -I$(IMATH_DIR) -L$(IMATH_DIR) -limath -o $@ $^ + +wrappers.py: genpytest.py gmpapi.py + ./genpytest.py > $@ + +random.tests: gendata.py + ./gendata.py > $@ + +clean: + rm -f a.out *.so *.o gmp_test.c imath_test.c wrappers.py *.pyc + rm -rf __pycache__ Index: contrib/isl/imath/tests/gmp-compat-test/README =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/README @@ -0,0 +1,106 @@ +Overview +================================================== +This directory contains a random test generator for the gmp +compatibility layer of imath. The tests cases are randomly generated +and run with both gmp and imath. The results are compared and any +mismatching results are flagged as failures. + +You should not see any failures when running these tests. + +Requirements +================================================== +These tests use the python ffi to run the imath and gmp functions. To +run these tests you will need the following items + + * libimath.so + * python 3 + * gmp library and header files + + +Running +================================================== +All the tests cases will be generated and run automatically by the +makefile. First, make sure you have built libimath.so in the top level +imath directory. + +Use the following command to generate and run the tests + + $ make TESTS=random.tests + +This should generate all the needed wrapper files along with the +randomized unit tests. By default the unit tests are output to the +random.tests file. The tests can be run by hand using the following +command line + + $ ./runtest random.tests + +You can also write your own unit tests and run them by passing the +file name to the runtest script. + + +Testing Methodology +================================================== +The goal of our testing is to ensure that we are compatible with the +gmp api. To test our compatibility layer we generate inputs for each +gmp api that we wrap and then call the gmp version of the api and +compare the results to the imath version. The results should be +identical. Any output mismatch is considered an error. + + +Testcase Generation +-------------------- +The test data generation is inspired by the QuickCheck testing +methodolgy. We want to test both random data and important values such +as 0,1,-1, etc. We generate input data based on the type of the input +parameter. Most apis take either an mpz_t or a signed/unsigned long. + +For each parameter of the given type we generate the following values: + + mpz_t: 0,1,-1, all min/max values, all min/max values +/- 1 + small numbers: 1-4 digits + medium numbers: 5-20 digits + large numbers: 20-100 digits + long : 0,1,-1 short,int,long min/max values + random long values + unsigned long: 0,1,-1, unsigned short, unsigned int, unsigned long min/max values + random unsigned long values + +The generated data for each paramater is combined to produce a series +of inputs to the function. The input data format looks like: + +mpz_add|0,1,2 + +Which represents the call mpz_add(0, 1, 2). Additional test cases can be written by hand. + +Test Structure +-------------------- +The tests are run using the python ffi (the ctypes module). We have a +single description of each api that is used to generate the following: + + * intput data + * c function wrapper to call the libgmp or libimath function + * python wrapper to call both libgmp and libimath wrappers and compare results + +The test_gmp.so and test_imath.so libraries are loaded at runtime by +the python runner scrip and used to run each test input and compare +the results. + +The code generation pattern looks something like this: + +genctest.py ~~generates~~> gmp_test.c <--includes-- gmp_custom_test.c +gmp_test.c ~~generates~~> gmp_tests.so <--links-- libgmp.so +genpytest.py ~~generates~~> wrappers.py <--calls-- gmp_test.so +gmp_test.so --loads--> runtest.py <--includes-- wrappers.py + ^ + | + reads + | +gendata.py ~~generates~~> random.tests + +Adding tests for new APIs +================================================== +New apis can be tested by modifying the gmpapy.py file. This file +contains a list of all apis that will be tested. Adding an api to the +apis list will cause code and input data to be generated for that api. +Rerunning make will generate the test data and code to run the test. + Index: contrib/isl/imath/tests/gmp-compat-test/genctest.py =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/genctest.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python3 +import sys +import gmpapi +from gmpapi import void +from gmpapi import ilong +from gmpapi import iint +from gmpapi import ulong +from gmpapi import mpz_t +from gmpapi import size_t +from gmpapi import charp +from gmpapi import mpq_t + +class APITest: + def __init__(self, gmpapi): + self.api = gmpapi + + def test_prefix(self): + return "test" + + def test_param_name(self, ty, i): + if ty == mpz_t: + pname = "p_zs" + elif ty == ilong: + pname = "p_si" + elif ty == ulong: + pname = "p_ui" + elif ty == iint: + pname = "p_i" + elif ty == charp: + pname = "p_cs" + elif ty == mpq_t: + pname = "p_qs" + else: + raise RuntimeError("Unknown param type: "+str(ty)) + return pname + str(i) + + def test_param_type(self, ty): + if ty == mpz_t or ty == mpq_t: + pty_name = "char *" + else: + pty_name = str(ty) + return pty_name + + def test_var_name(self, ty, i): + if ty == mpz_t: + vname = "v_z" + elif ty == ilong: + vname = "v_si" + elif ty == ulong: + vname = "v_ui" + elif ty == iint: + vname = "v_i" + elif ty == size_t: + vname = "v_st" + elif ty == charp: + vname = "v_cs" + elif ty == mpq_t: + vname = "v_q" + else: + raise RuntimeError("Unknown param type: "+str(ty)) + return vname + str(i) + + def test_var_type(self, ty): + if ty == mpz_t: + return self.mpz_type() + elif ty == mpq_t: + return self.mpq_type() + else: + return str(ty) + + def init_var_from_param(self, ty, var, param): + code = "\t" + if ty == mpz_t or ty == mpq_t: + code += self.api_call_prefix(ty)+"init("+var+");\n\t" + code += self.api_call_prefix(ty)+"set_str("+",".join([var,param,"10"])+")" + if ty == mpq_t: + code += ";\n\t" + code += self.api_call_prefix(ty)+"canonicalize("+var+")" + else: + code += var + "=" + param + return code + + def init_vars_from_params(self): + code = "" + for (i,p) in enumerate(self.api.params): + param = self.test_param_name(p, i) + code += "\t" + code += self.test_var_type(p) + " " + var = self.test_var_name(p, i) + code += var + ";\n" + code += self.init_var_from_param(p, var, param) + ";\n\n" + return code + + def make_api_call(self): + bare_name = self.api.name.replace("mpz_", "", 1).replace("mpq_", "", 1) + call_params = [self.test_var_name(p,i) for (i,p) in enumerate(self.api.params)] + ret = "\t" + ret_ty = self.api.ret_ty + if ret_ty != void: + ret += self.test_var_type(ret_ty)+" "+self.test_var_name(ret_ty, "_ret") + " = " + # call mpq or mpz function + if self.api.name.startswith("mpz_"): + prefix = self.api_call_prefix(mpz_t) + else: + prefix = self.api_call_prefix(mpq_t) + return ret + prefix + bare_name + "(" + ",".join(call_params) + ");\n" + + def normalize_cmp(self, ty): + cmpval = self.test_var_name(ty, "_ret") + code = "" + code += """ + if ({var} > 0) + {var} = 1; + else if ({var} < 0) + {var} = -1;\n\t +""".format(var=cmpval) + return code + + def extract_result(self, ty, pos): + code = "" + if ty == mpz_t or ty == mpq_t: + var = self.test_var_name(ty, pos) + code += self.api_call_prefix(ty) + "get_str(out+offset, 10,"+var+");\n" + code += "\toffset = offset + strlen(out); " + code += "out[offset] = ' '; out[offset+1] = 0; offset += 1;" + else: + assert pos == -1, "expected a return value, not a param value" + if ty == ilong: + var = self.test_var_name(ty, "_ret") + code += 'offset = sprintf(out+offset, " %ld ", '+var+');' + elif ty == ulong: + var = self.test_var_name(ty, "_ret") + code += 'offset = sprintf(out+offset, " %lu ", '+var+');' + elif ty == iint: + var = self.test_var_name(ty, "_ret") + code += 'offset = sprintf(out+offset, " %d ", '+var+');' + elif ty == size_t: + var = self.test_var_name(ty, "_ret") + code += 'offset = sprintf(out+offset, " %zu ", '+var+');' + elif ty == charp: + var = self.test_var_name(ty, "_ret") + code += 'offset = sprintf(out+offset, " %s ", '+var+');' + else: + raise RuntimeError("Unknown param type: "+str(ty)) + return code + + def extract_results(self): + ret_ty = self.api.ret_ty + code = "\tint offset = 0;\n\t" + + # normalize cmp return values + if ret_ty == iint and "cmp" in self.api.name: + code += self.normalize_cmp(ret_ty) + + # call canonicalize for mpq_set_ui + if self.api.name == "mpq_set_ui": + code += self.api_call_prefix(mpq_t) + "canonicalize("+self.test_var_name(mpq_t, 0)+");\n\t" + + # get return value + if ret_ty != void: + code += self.extract_result(ret_ty, -1) + "\n" + + # get out param values + for pos in self.api.out_params: + code += "\t" + code += self.extract_result(self.api.params[pos], pos) + "\n" + + return code + "\n" + + def clear_local_vars(self): + code = "" + for (i,p) in enumerate(self.api.params): + if p == mpz_t or p == mpq_t: + var = self.test_var_name(p, i) + code += "\t"+self.api_call_prefix(p)+"clear("+var+");\n" + return code + + def print_test_code(self, outf): + api = self.api + params = [self.test_param_type(p)+" "+self.test_param_name(p, i) for (i, p) in enumerate(api.params)] + code = "void {}_{}(char *out, {})".format(self.test_prefix(), api.name, ", ".join(params)) + code += "{\n" + code += self.init_vars_from_params() + code += self.make_api_call() + code += self.extract_results() + code += self.clear_local_vars() + code += "}\n" + outf.write(code) + outf.write("\n") + +class GMPTest(APITest): + def __init__(self, gmpapi): + super().__init__(gmpapi) + + def api_call_prefix(self, kind): + if kind == mpz_t: + return "mpz_" + elif kind == mpq_t: + return "mpq_" + else: + raise RuntimeError("Unknown call kind: "+str(kind)) + + def mpz_type(self): + return "mpz_t" + + def mpq_type(self): + return "mpq_t" + +class ImathTest(APITest): + def __init__(self, gmpapi): + super().__init__(gmpapi) + + def api_call_prefix(self, kind): + if kind == mpz_t: + return "impz_" + elif kind == mpq_t: + return "impq_" + else: + raise RuntimeError("Unknown call kind: "+str(kind)) + + def mpz_type(self): + return "impz_t" + + def mpq_type(self): + return "impq_t" + +def print_gmp_header(outf): + code = "" + code += "#include \n" + code += "#include \n" + code += "#include \n" + code += '#include "gmp_custom_test.c"\n' + outf.write(code) + +def print_imath_header(outf): + code = "" + code += "#include \n" + code += "#include \n" + code += "#include \n" + code += "typedef mpz_t impz_t[1];\n" + code += "typedef mpq_t impq_t[1];\n" + code += '#include "imath_custom_test.c"\n' + outf.write(code) + +def print_gmp_tests(outf): + print_gmp_header(outf) + for api in gmpapi.apis: + if not api.custom_test: + GMPTest(api).print_test_code(outf) + +def print_imath_tests(outf): + print_imath_header(outf) + for api in gmpapi.apis: + if not api.custom_test: + ImathTest(api).print_test_code(outf) + +def main(): + test = sys.argv[1] + + if test == "gmp": + print_gmp_tests(sys.stdout) + elif test == "imath": + print_imath_tests(sys.stdout) + +if __name__ == "__main__": + main() Index: contrib/isl/imath/tests/gmp-compat-test/gendata.py =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/gendata.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python3 +import random +import gmpapi + +MAX_SLONG="9223372036854775807" +MIN_SLONG="-9223372036854775808" +MAX_ULONG="18446744073709551615" +MAX_SINT="2147483647" +MIN_SINT="-2147483648" +MAX_UINT="4294967295" +MAX_SSHORT="32767" +MIN_SSHORT="-32768" +MAX_USHORT="65535" + +def plus1(x): return str(int(x)+1) +def minus1(x): return str(int(x)-1) +def apply(fun, lst): + return list(map(str, map(fun, lst))) + +mzero_one = ["-0", "-1"] +zero_one = ["0", "1"] +mm_slong = [MAX_SLONG, MIN_SLONG] +mm_slong1 = [minus1(MAX_SLONG), plus1(MIN_SLONG)] +mm_ulong = [MAX_ULONG] +mm_ulong1 = [minus1(MAX_ULONG)] +mm_sint = [MAX_SINT, MIN_SINT] +mm_sint1 = [minus1(MAX_SINT), plus1(MIN_SINT)] +mm_uint = [MAX_UINT] +mm_uint1 = [minus1(MAX_UINT)] +mm_sshort = [MAX_SSHORT, MIN_SSHORT] +mm_sshort1= [minus1(MAX_SSHORT), plus1(MIN_SSHORT)] +mm_ushort = [MAX_USHORT] +mm_ushort1= [minus1(MAX_USHORT)] +mm_all = mm_slong + mm_ulong + mm_sint + mm_uint + mm_sshort + mm_ushort +zero_one_all = mzero_one + zero_one + + +mpz_std_list = zero_one_all + mm_all + apply(plus1, mm_all) + apply(minus1, mm_all) +si_std_list = zero_one + mm_slong + mm_sint + mm_sshort + mm_slong1 + mm_sint1 + mm_sshort1 +ui_std_list = zero_one + mm_ulong + mm_uint + mm_ushort + mm_ulong1 + mm_uint1 + mm_ushort1 + +def gen_random_mpz(mindigits=1, maxdigits=100, allowneg=True): + sign = random.choice(["", "-"]) + if not allowneg: + sign = "" + return sign + gen_digits(random.randint(mindigits, maxdigits)) + +def gen_random_si(): + si = gen_random_mpz(mindigits=1,maxdigits=19) + while int(si) > int(MAX_SLONG) or int(si) < int(MIN_SLONG): + si = gen_random_mpz(mindigits=1,maxdigits=19) + return si + +def gen_random_ui(): + ui = gen_random_mpz(mindigits=1,maxdigits=20, allowneg=False) + while int(ui) > int(MAX_ULONG): + ui = gen_random_mpz(mindigits=1,maxdigits=20, allowneg=False) + return ui + +def gen_digits(length): + if length == 1: + i = random.randint(1, 9) + else: + digits = [random.randint(1,9)] + [random.randint(0,9) for x in range(length-1)] + digits = map(str, digits) + i = "".join(digits) + return str(i) + +def gen_mpzs(mindigits=1, maxdigits=100, count=10): + return [gen_random_mpz(mindigits=mindigits, maxdigits=maxdigits) for x in range(count)] + +default_count = 10 +def gen_sis(count=default_count): + return [gen_random_si() for x in range(count)] + +def gen_uis(count=default_count): + return [gen_random_ui() for x in range(count)] + +def gen_small_mpzs(count=default_count): + return gen_mpzs(mindigits=1,maxdigits=4,count=count) + +def is_small_mpz(s): + return len(s) >= 1 and len(s) <= 4 + +def gen_medium_mpzs(count=default_count): + return gen_mpzs(mindigits=5,maxdigits=20,count=count) + +def is_medium_mpz(s): + return len(s) >= 5 and len(s) <= 20 + +def gen_large_mpzs(count=default_count): + return gen_mpzs(mindigits=21,maxdigits=100,count=count) + +def is_large_mpz(s): + return len(s) >= 21 + +def gen_mpz_spread(count=default_count): + return gen_small_mpzs(count) + gen_medium_mpzs(count) + gen_large_mpzs(count) + +def gen_mpz_args(count=default_count): + return mpz_std_list + gen_mpz_spread(count) + +def gen_mpq_args(count=4): + nums = zero_one + gen_mpz_spread(count) + dens = ["1"] + gen_mpz_spread(count) + return [n+"/"+d for n in nums for d in dens if int(d) != 0] + +def gen_si_args(): + return si_std_list + gen_sis() + +def gen_ui_args(): + return ui_std_list + gen_uis() + +def gen_list_for_type(t, is_write_only): + if (t == gmpapi.mpz_t or t == gmpapi.mpq_t) and is_write_only: + return ["0"] + elif t == gmpapi.mpz_t: + return gen_mpz_args() + elif t == gmpapi.ilong: + return gen_si_args() + elif t == gmpapi.ulong: + return gen_ui_args() + elif t == gmpapi.mpq_t: + return gen_mpq_args() + else: + raise RuntimeError("Unknown type: {}".format(t)) + +def gen_args(api): + if api.custom_test or api.name in custom: + return custom[api.name](api) + types = api.params + if len(types) == 1: + return [[a] for a in gen_list_for_type(types[0], api.is_write_only(0))] + elif len(types) == 2: + t1 = gen_list_for_type(types[0], api.is_write_only(0)) + t2 = gen_list_for_type(types[1], api.is_write_only(1)) + return [(a,b) for a in t1 for b in t2] + elif len(types) == 3: + t1 = gen_list_for_type(types[0], api.is_write_only(0)) + t2 = gen_list_for_type(types[1], api.is_write_only(1)) + t3 = gen_list_for_type(types[2], api.is_write_only(2)) + return [(a,b,c) for a in t1 for b in t2 for c in t3] + elif len(types) == 4: + t1 = gen_list_for_type(types[0], api.is_write_only(0)) + t2 = gen_list_for_type(types[1], api.is_write_only(1)) + t3 = gen_list_for_type(types[2], api.is_write_only(2)) + t4 = gen_list_for_type(types[3], api.is_write_only(3)) + return [(a,b,c,d) for a in t1 for b in t2 for c in t3 for d in t4] + else: + raise RuntimeError("Too many args: {}".format(len(types))) + +################################################################### +# +# Fixup and massage random data for better test coverage +# +################################################################### +def mul_mpzs(a, b): + return str(int(a) * int(b)) + +def mpz_divexact_data(args): + # set n = n * d + divisible = mul_mpzs(args[1],(args[2])) + return [(args[0], divisible, args[2])] + +def mpz_divisible_p_data(args): + (n,d) = get_div_data(args[0], args[1],rate=1.0) + return [(n,d), (args[0], args[1])] + +def mpz_div3_data(args): + q = args[0] + (n,d) = get_div_data(args[1], args[2],rate=1.0) + return [(q,n,d), (q,args[1], args[2])] + +def mpz_pow_data(args, alwaysallowbase1=True): + base = int(args[1]) + exp = int(args[2]) + # allow special numbers + if base == 0 or exp == 0 or exp == 1: + return [args] + if base == 1 and alwaysallowbase1: + return [args] + + # disallow too big numbers + if base > 1000 or base < -1000: + base = gen_random_mpz(maxdigits=3) + if exp > 1000: + exp = gen_random_mpz(maxdigits=3, allowneg=False) + + return [(args[0], str(base), str(exp))] + +def mpz_mul_2exp_data(args): + return mpz_pow_data(args, alwaysallowbase1=False) + +def mpz_gcd_data(args): + r = args[0] + a = args[1] + b = args[2] + s_ = gen_small_mpzs(1)[0] + m_ = gen_medium_mpzs(1)[0] + l_ = gen_large_mpzs(1)[0] + + return [ (r, a, b), + (r, mul_mpzs(a, b), b), + (r, mul_mpzs(a, s_), mul_mpzs(b, s_)), + (r, mul_mpzs(a, m_), mul_mpzs(b, m_)), + (r, mul_mpzs(a, l_), mul_mpzs(b, l_)),] + +def mpz_export_data(api): + rop = ["0"] + countp = ["0"] + order = ["-1","1"] + size = ["1","2","4","8"] + endian = ["0"] + nails = ["0"] + ops = gen_mpz_args(1000) + gen_mpzs(count=100,mindigits=100,maxdigits=1000) + + args = [] + for r in rop: + for c in countp: + for o in order: + for s in size: + for e in endian: + for n in nails: + for op in ops: + args.append((r,c,o,s,e,n,op)) + return args + +def mpz_sizeinbase_data(api): + bases = list(map(str, range(2, 37))) + ops = gen_mpz_args(1000) + gen_mpzs(count=1000,mindigits=100,maxdigits=2000) + return [(op, b) for op in ops for b in bases] + +def get_str_data(ty): + bases = list(range(2,37)) + list(range(-2, -37, -1)) + bases = list(map(str, bases)) + if ty == gmpapi.mpz_t: + ops = gen_mpz_args(1000) + elif ty == gmpapi.mpq_t: + ops = gen_mpq_args(20) + else: + raise RuntimeError("Unsupported get_str type: "+str(ty)) + return [("NULL", b, op) for b in bases for op in ops] + +def mpz_get_str_data(api): + return get_str_data(gmpapi.mpz_t) + +def mpq_get_str_data(api): + return get_str_data(gmpapi.mpq_t) + +def mpq_set_str_data(api): + args = gen_mpq_args(20) + gen_mpz_args() + # zero does not match results exactly because the + # results are not canonicalized first. We choose to + # exclude zero from test results. The other option is + # to canonicalize the results after parsing the strings. + # Instead we exclude zero so that we can independently + # test correctness of set_str and canonicalization + nonzero = [] + for arg in args: + if "/" in arg: + pos = arg.find("/") + if int(arg[:pos]) != 0: + nonzero.append(arg) + elif int(arg) != 0: + nonzero.append(arg) + + return [("0", q, "10") for q in nonzero] + +def get_div_data(n, d, rate=0.2): + """Generate some inputs that are perfectly divisible""" + if random.random() < rate: + n = mul_mpzs(n, d) + return (n,d) + +def allow(name, args): + if name not in blacklists: + return True + filters = blacklists[name] + for (pos, disallow) in filters: + if args[pos] in disallow: + return False + return True + +def fixup_args(name, args): + if name not in fixups: + return [args] + return fixups[name](args) + + +# list of values to be excluded for various api calls +# list format is (pos, [list of values to exclude]) +blacklists = { + "mpz_cdiv_q" : [(2, ["0", "-0"])], + "mpz_fdiv_q" : [(2, ["0", "-0"])], + "mpz_fdiv_r" : [(2, ["0", "-0"])], + "mpz_tdiv_q" : [(2, ["0", "-0"])], + "mpz_fdiv_q_ui" : [(2, ["0", "-0"])], + "mpz_divexact" : [(2, ["0", "-0"])], + "mpz_divisible_p" : [(1, ["0", "-0"])], + "mpz_divexact_ui" : [(2, ["0", "-0"])], + "mpq_set_ui" : [(2, ["0", "-0"])], +} + +fixups = { + "mpz_divexact" : mpz_divexact_data, + "mpz_divisible_p" : mpz_divisible_p_data, + "mpz_cdiv_q" : mpz_div3_data, + "mpz_fdiv_q" : mpz_div3_data, + "mpz_fdiv_r" : mpz_div3_data, + "mpz_tdiv_q" : mpz_div3_data, + "mpz_fdiv_q_ui" : mpz_div3_data, + "mpz_divexact_ui" : mpz_divexact_data, + "mpz_pow_ui" : mpz_pow_data, + "mpz_gcd" : mpz_gcd_data, + "mpz_lcm" : mpz_gcd_data, + "mpz_mul_2exp" : mpz_mul_2exp_data, +} + +custom = { + "mpz_export" : mpz_export_data, + "mpz_import" : mpz_export_data, + "mpz_sizeinbase" : mpz_sizeinbase_data, + "mpz_get_str" : mpz_get_str_data, + "mpq_set_str" : mpq_set_str_data, + "mpq_get_str" : mpq_get_str_data, +} + +if __name__ == "__main__": + #apis = [gmpapi.get_api("mpq_set_str"),] + apis = gmpapi.apis + for api in apis: + tests = gen_args(api) + for args in tests: + expanded_args = fixup_args(api.name, args) + for args in expanded_args: + if allow(api.name, args): + print("{}|{}".format(api.name, ",".join(args))) + Index: contrib/isl/imath/tests/gmp-compat-test/genpytest.py =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/genpytest.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 + +import gmpapi +import sys + +def print_header(outf): + outf.write(""" +#AUTOGENERATED FILE +import ctypes +import os +import sys +import binascii + +verbose = False +fork = False + """) + +def print_cmp(outf): + outf.write(""" +def passt(line, name, a_s, b_s): + if verbose: + print("PASS: {}@{} {} == {}".format(line, name, a_s, b_s)) + return True + +def fail(line, name, a_s, b_s): + print("FAIL: {}@{} {} != {}".format(line, name, a_s,b_s)) + return False + +def cstr_eq(line, name, a, b): + a_s = a.value.decode("utf-8") + b_s = b.value.decode("utf-8") + + if a_s == b_s: + return passt(line, name, a_s, b_s) + else: + return fail(line, name, a_s, b_s) + +def bytes_eq(line, name, a, b): + if a == b: + return passt(line, name, a, b) + else: + return fail(line, name, a, b) + +def run_test(test, line, name, gmp_test_so, imath_test_so, *args): + if fork: + childpid = os.fork() + else: + childpid = 0 + if childpid == 0: + eq = test(line, name, gmp_test_so, imath_test_so, *args) + if fork: + sys.exit(eq != True) + else: + return eq + else: + (pid, status) = os.waitpid(childpid, 0) + return status == 0 + +# custom tests +def test_mpz_export(line, name, gmp_test_so, imath_test_so, *args): + # do not use first two args from the test. need to create our own pointers + used_args = args[2:] + gbuf = ctypes.create_string_buffer(b'0xdeadbeef'*1024); + gsize = ctypes.c_size_t() + gout = ctypes.c_void_p() + ibuf = ctypes.create_string_buffer(b'0xdeadbeef'*1024); + isize = ctypes.c_size_t() + iout = ctypes.c_void_p() + word_size = args[3].value + + #Test with a NULL pointer + gmp_test_so.test_mpz_export(ctypes.byref(gout), None, ctypes.byref(gsize), *used_args) + imath_test_so.test_mpz_export(ctypes.byref(iout), None, ctypes.byref(isize), *used_args) + gb = ctypes.string_at(gout.value, gsize.value * word_size) + ib = ctypes.string_at(iout.value, isize.value * word_size) + if not bytes_eq(line, name, gb, ib): + return False + + #Test with a provided buffer + gmp_test_so.test_mpz_export(ctypes.byref(gout), gbuf, ctypes.byref(gsize), *used_args) + imath_test_so.test_mpz_export(ctypes.byref(iout), ibuf, ctypes.byref(isize), *used_args) + #print("G:gbuf", gbuf.raw[:gsize.value * word_size]) + #print("I:ibuf", ibuf.raw[:isize.value * word_size]) + gb = ctypes.string_at(gout.value, gsize.value * word_size) + ib = ctypes.string_at(iout.value, isize.value * word_size) + if not bytes_eq(line, name, gb, ib): + return False + + return True + +def test_mpz_import(line, name, gmp_test_so, imath_test_so, *args): + # do not use first two args from the test. need to create our own pointers + gout = ctypes.create_string_buffer(b'0xdeadbeef'*1024); + iout = ctypes.create_string_buffer(b'0xdeadbeef'*1024); + + gmp_test_so.test_mpz_import(gout, *args) + imath_test_so.test_mpz_import(iout, *args) + #print(gout.raw[:70]) + #print(iout.raw[:70]) + return cstr_eq(line, name, gout, iout) + +""") + +def print_api(name, outf): + outf.write(""" +def test_{0}(line, name, gmp_test_so, imath_test_so, *args): + gout = ctypes.create_string_buffer(1024*4); + iout = ctypes.create_string_buffer(1024*4); + gmp_test_so.test_{0}(gout, *args) + imath_test_so.test_{0}(iout, *args) + eq = cstr_eq(line, name, gout, iout) + return eq +""".format(name)) + +def print_api_map(outf): + outf.write(""" +def get_wrapper(name): + test_wrappers = { +""") + for api in gmpapi.apis: + outf.write(' "{}" : {},\n'.format(api.name, "test_"+api.name)) + outf.write(" }\n") + outf.write(" return test_wrappers[name]\n") + + +if __name__ == "__main__": + outf = sys.stdout + print_header(outf) + print_cmp(outf) + for api in gmpapi.apis: + if not api.custom_test: + print_api(api.name, outf) + print_api_map(outf) + Index: contrib/isl/imath/tests/gmp-compat-test/gmp_custom_test.c =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/gmp_custom_test.c @@ -0,0 +1,24 @@ + +void test_mpz_export(char **out, char *rop, size_t *countp, int order, size_t size, int endian, size_t nails, char* mpzstr) { + mpz_t op; + mpz_init(op); + mpz_set_str(op, mpzstr, 10); + //printf("%p,%p,%d,%zi,%d,%zi,%s\n", rop, countp, order, size, endian, nails, mpzstr); + *out = mpz_export(rop, countp, order, size, endian, nails, op); +} + +void test_mpz_import(char *out, void *unused, size_t count, int order, size_t size, int endian, size_t nails, char* mpzstr) { + mpz_t op; + mpz_t rop; + mpz_init(op); + mpz_init(rop); + mpz_set_str(op, mpzstr, 10); + char *data; + + //printf("%p,%p,%d,%zi,%d,%zi,%s\n", rop, countp, order, size, endian, nails, mpzstr); + data = mpz_export(NULL, &count, order, size, endian, nails, op); + mpz_import(rop, count, order, size, endian, nails, data); + int eq = mpz_cmpabs(op, rop); + sprintf(out, "%2d:", eq); + mpz_get_str(out+3, 10, rop); +} Index: contrib/isl/imath/tests/gmp-compat-test/gmpapi.py =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/gmpapi.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 + +import sys + +class CType: + def __init__(self, name): + self.name = name + + def __str__(self): + return self.name + +class GMPAPI: + def __init__(self, ret_ty, name, *params, out=[0], inout=[], mixed=False,custom=False): + self.name = name + self.ret_ty = ret_ty + self.params = params + self.inout_params = inout + self.custom_test = custom + # most functions with return results dont need extra out params + # set mixed to true to check both the return value and an out param + if self.ret_ty != void and not mixed: + self.out_params = [] + else: + self.out_params = out #param location of the output result + + def is_write_only(self, pos): + if pos in self.out_params and pos not in self.inout_params: + return True + return False + + def __str__(self): + return("{} {}({})".format(self.ret_ty, self.name, ",".join(map(str,self.params)))) + + def __repr__(self): + return str(self) + +void = CType("void") +voidp = CType("void *") +charp = CType("char *") +iint = CType("int") +size_t= CType("size_t") +size_tp= CType("size_t*") +ilong = CType("long") +ulong = CType("unsigned long") +mpz_t = CType("mpz_t") +mpq_t = CType("mpq_t") + +apis = [ + GMPAPI(void, "mpz_abs", mpz_t, mpz_t), + GMPAPI(void, "mpz_add", mpz_t, mpz_t, mpz_t), + GMPAPI(iint, "mpz_cmp_si", mpz_t, ilong), + GMPAPI(iint, "mpz_cmpabs", mpz_t, mpz_t), + GMPAPI(iint, "mpz_cmp", mpz_t, mpz_t), + GMPAPI(void, "mpz_mul", mpz_t, mpz_t, mpz_t), + GMPAPI(void, "mpz_neg", mpz_t, mpz_t), + GMPAPI(void, "mpz_set_si", mpz_t, ilong), + GMPAPI(void, "mpz_set", mpz_t, mpz_t), + GMPAPI(void, "mpz_sub", mpz_t, mpz_t, mpz_t), + GMPAPI(void, "mpz_swap", mpz_t, mpz_t, out=[0,1], inout=[0,1]), + GMPAPI(iint, "mpz_sgn", mpz_t), + GMPAPI(void, "mpz_addmul", mpz_t, mpz_t, mpz_t, inout=[0]), + GMPAPI(void, "mpz_divexact", mpz_t, mpz_t, mpz_t), + GMPAPI(iint, "mpz_divisible_p", mpz_t, mpz_t), + GMPAPI(void, "mpz_submul", mpz_t, mpz_t, mpz_t, inout=[0]), + GMPAPI(void, "mpz_set_ui", mpz_t, ulong), + GMPAPI(void, "mpz_add_ui", mpz_t, mpz_t, ulong), + GMPAPI(void, "mpz_divexact_ui", mpz_t, mpz_t, ulong), + GMPAPI(void, "mpz_mul_ui", mpz_t, mpz_t, ulong), + GMPAPI(void, "mpz_pow_ui", mpz_t, mpz_t, ulong), + GMPAPI(void, "mpz_sub_ui", mpz_t, mpz_t, ulong), + GMPAPI(void, "mpz_cdiv_q", mpz_t, mpz_t, mpz_t), + GMPAPI(void, "mpz_fdiv_q", mpz_t, mpz_t, mpz_t), + GMPAPI(void, "mpz_fdiv_r", mpz_t, mpz_t, mpz_t), + GMPAPI(void, "mpz_tdiv_q", mpz_t, mpz_t, mpz_t), + GMPAPI(ulong, "mpz_fdiv_q_ui", mpz_t, mpz_t, ulong, out=[0], mixed=True), + GMPAPI(ilong, "mpz_get_si", mpz_t), + GMPAPI(ulong, "mpz_get_ui", mpz_t), + GMPAPI(void, "mpz_gcd", mpz_t, mpz_t, mpz_t), + GMPAPI(void, "mpz_lcm", mpz_t, mpz_t, mpz_t), + GMPAPI(void, "mpz_mul_2exp", mpz_t, mpz_t, ulong), + GMPAPI(void, "mpz_export", voidp, size_tp, iint, size_t, iint, size_t, mpz_t, custom=True), + # The mpz_import signature is a bit of a lie, but it is ok because it is custom + GMPAPI(void, "mpz_import", voidp, size_t, iint, size_t, iint, size_t, mpz_t, custom=True), + GMPAPI(size_t,"mpz_sizeinbase", mpz_t, iint), + GMPAPI(charp, "mpz_get_str", charp, iint, mpz_t), + + # mpq functions + GMPAPI(iint, "mpq_set_str", mpq_t, charp, iint, out=[0], mixed=True), + GMPAPI(void, "mpq_canonicalize", mpq_t, inout=[0]), + GMPAPI(iint, "mpq_cmp", mpq_t, mpq_t), + GMPAPI(void, "mpq_mul", mpq_t, mpq_t, mpq_t), + GMPAPI(void, "mpq_set", mpq_t, mpq_t), + GMPAPI(void, "mpq_set_ui", mpq_t, ulong, ulong), + GMPAPI(iint, "mpq_sgn", mpq_t), + GMPAPI(charp,"mpq_get_str", charp, iint, mpq_t), + ] + +def get_api(name): + for a in apis: + if a.name == name: + return a + raise RuntimeError("Unknown api: {}".format(name)) + Index: contrib/isl/imath/tests/gmp-compat-test/imath_custom_test.c =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/imath_custom_test.c @@ -0,0 +1,24 @@ + +void test_mpz_export(char **out, char *rop, size_t *countp, int order, size_t size, int endian, size_t nails, char* mpzstr) { + impz_t op; + impz_init(op); + impz_set_str(op, mpzstr, 10); + //printf("%p,%p,%d,%zi,%d,%zi,%s\n", rop, countp, order, size, endian, nails, mpzstr); + *out = impz_export(rop, countp, order, size, endian, nails, op); +} + +void test_mpz_import(char *out, void *unused, size_t count, int order, size_t size, int endian, size_t nails, char* mpzstr) { + impz_t op; + impz_t rop; + impz_init(op); + impz_init(rop); + impz_set_str(op, mpzstr, 10); + char *data; + + //printf("%p,%p,%d,%zi,%d,%zi,%s\n", rop, countp, order, size, endian, nails, mpzstr); + data = impz_export(NULL, &count, order, size, endian, nails, op); + impz_import(rop, count, order, size, endian, nails, data); + int eq = impz_cmpabs(op, rop); + sprintf(out, "%2d:", eq); + impz_get_str(out+3, 10, rop); +} Index: contrib/isl/imath/tests/gmp-compat-test/runtest =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/runtest @@ -0,0 +1,3 @@ +#!/bin/bash +export LD_LIBRARY_PATH=.:../.. +python3 runtest.py $@ Index: contrib/isl/imath/tests/gmp-compat-test/runtest.py =================================================================== --- /dev/null +++ contrib/isl/imath/tests/gmp-compat-test/runtest.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 + +import ctypes +import random +import gmpapi +import wrappers +import glob +import sys +import os +from optparse import OptionParser +from gmpapi import void +from gmpapi import ilong +from gmpapi import ulong +from gmpapi import mpz_t +from gmpapi import voidp +from gmpapi import size_t +from gmpapi import size_tp +from gmpapi import iint +from gmpapi import charp +from gmpapi import mpq_t + +def print_failure(line, test): + print("FAIL: {}@{}".format(line,test)) + + +def run_tests(test_file, options): + passes = 0 + failures = 0 + fail_lines = [] + for (line, test) in enumerate(open(test_file), start=1): + if test.startswith("#"): + continue + if options.skip > 0 and line < options.skip: + continue + name,args = test.split("|") + if options.verbose or (options.progress > 0 and line % options.progress == 0): + print("TEST: {}@{}".format(line, test), end="") + api = gmpapi.get_api(name) + wrapper = wrappers.get_wrapper(name) + input_args = args.split(",") + if len(api.params) != len(input_args): + raise RuntimeError("Mismatch in args length: {} != {}".format(len(api.params), len(input_args))) + + call_args = [] + for i in range(len(api.params)): + param = api.params[i] + if param == mpz_t: + call_args.append(bytes(input_args[i],"utf-8")) + elif param == mpq_t: + call_args.append(bytes(input_args[i],"utf-8")) + elif param == ulong: + call_args.append(ctypes.c_ulong(int(input_args[i]))) + elif param == ilong: + call_args.append(ctypes.c_long(int(input_args[i]))) + elif param == voidp or param == size_tp: + call_args.append(ctypes.c_void_p(None)) + elif param == size_t: + call_args.append(ctypes.c_size_t(int(input_args[i]))) + elif param == iint: + call_args.append(ctypes.c_int(int(input_args[i]))) + # pass null for charp + elif param == charp: + if input_args[i] == "NULL": + call_args.append(ctypes.c_void_p(None)) + else: + call_args.append(bytes(input_args[i],"utf-8")) + else: + raise RuntimeError("Unknown param type: {}".format(param)) + + res = wrappers.run_test(wrapper, line, name, gmp_test_so, imath_test_so, *call_args) + if not res: + failures += 1 + print_failure(line,test) + fail_lines.append((line,test)) + else: + passes += 1 + return (passes,failures, fail_lines) + +def parse_args(): + parser = OptionParser() + parser.add_option("-f", "--fork", help="fork() before each operation", + action="store_true", default=False) + parser.add_option("-v", "--verbose", help="print PASS and FAIL tests", + action="store_true", default=False) + parser.add_option("-p", "--progress", help="print progress every N tests ", + metavar="N", type="int", default=0) + parser.add_option("-s", "--skip", help="skip to test N", + metavar="N", type="int", default=0) + return parser.parse_args() + +if __name__ == "__main__": + (options, tests) = parse_args() + gmp_test_so = ctypes.cdll.LoadLibrary("gmp_test.so") + imath_test_so = ctypes.cdll.LoadLibrary("imath_test.so") + + wrappers.verbose = options.verbose + wrappers.fork = options.fork + + total_pass = 0 + total_fail = 0 + all_fail_lines = [] + for test_file in tests: + print("Running tests in {}".format(test_file)) + (passes,failures,fail_lines) = run_tests(test_file, options) + print(" Tests: {}. Passes: {}. Failures: {}.".format(passes+failures, passes, failures)) + total_pass += passes + total_fail += failures + all_fail_lines += fail_lines + + print("="*70) + print("Total") + print(" Tests: {}. Passes: {}. Failures: {}.".format(total_pass+total_fail, total_pass, total_fail)) + if len(all_fail_lines) > 0: + print("Failing Tests:") + for (line, test) in all_fail_lines: + print(test.rstrip()) + Index: contrib/isl/imath/tests/init.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/init.t @@ -0,0 +1,12 @@ +#Unsigned integer initialization. Assumes sizeof(long) == 8. +initu:0,0:0 +initu:0,18446744073709551615:18446744073709551615 +initu:0,567:567 + +#Signed integer initialization Assumes sizeof(long) == 8. +initv:0,0:0 +initv:0,-1:-1 +initv:0,9223372036854775807:9223372036854775807 +initv:0,-9223372036854775808:-9223372036854775808 +initv:0,4324:4324 + Index: contrib/isl/imath/tests/invmod.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/invmod.t @@ -0,0 +1,452 @@ +# Modular inverse tests (no undefined cases) + +invmod:-25,37,=1:34 +invmod:-25,37,=2:34 +invmod:-5,11,0:2 +invmod:22153,514,0:383 +invmod:6521,442674856,0:28104185 +invmod:83,8990271,0:2924546 +invmod:643111,73,0:23 +invmod:6756751,5,0:1 +invmod:4310757,655173482,0:578093623 +invmod:67658,37989,0:29720 +invmod:140,456739,0:394753 +invmod:8363,2152,0:1827 +invmod:6067,5554,0:1061 +invmod:134706247,840181,0:713245 +invmod:581,8525,0:3096 +invmod:991357,2885,0:2243 +invmod:9820551,53210,0:5931 +invmod:366,3905684875,0:1846129736 +invmod:4582993,6971170,0:6590887 +invmod:4261,5,0:1 +invmod:2089582769,72370,0:34059 +invmod:1385486874,274843,0:100773 +invmod:2496082853,33877892272,0:25370727693 +invmod:29,77842490059,0:18789566566 +invmod:160735723,837433,0:536522 +invmod:33,92874448,0:39401281 +invmod:17,801910,0:518883 +invmod:1243,47177637,0:28769629 +invmod:5553626,17225545633,0:4551550593 +invmod:493375452,7744903,=1:5021402 +invmod:505,75126821802,0:15917960263 +invmod:8082104357,6160949,0:64657 +invmod:4793,63911,0:44243 +invmod:846,4453189,0:689560 +invmod:5475,596527544653,0:311392826049 +invmod:239,28531,0:9192 +invmod:71044,91829,0:4016 +invmod:2923052473,673,0:362 +invmod:40113371,396,0:23 +invmod:799762079,671587,0:280457 +invmod:6137106,72083,0:61684 +invmod:2663959394312,7297021,0:6396652 +invmod:16314,437519,0:121837 +invmod:5409920801970,224827,0:146917 +invmod:1701531745,565383113204,0:392963934477 +invmod:6702285244447,4818940,0:3886523 +invmod:3853762105973,7986397045899,0:4649165556065 +invmod:83203877,17340640,=2:1474413 +invmod:349,3756,0:1765 +invmod:513237329,6426867498383,0:5161899757325 +invmod:218717486055,4764721,0:3629102 +invmod:5697807566182,23837,0:17052 +invmod:640499,3706953268445,0:862821487954 +invmod:74365895080186,37008968409199,0:35062440514236 +invmod:5447180,17521,0:6484 +invmod:87747,309211711,0:64843296 +invmod:65052052,72604563,0:26029330 +invmod:1200121,9944190318201,=2:5066700447199 +invmod:487321393172,41829673981,=1:18173847806 +invmod:3762709971997,877939264220,=1:575680399733 +invmod:78323027,3830390625030,0:1772587463183 +invmod:1324701179,57116535299,0:4144192403 +invmod:663267333048769,9458708,0:1445501 +invmod:925655,3262585612,0:2494330419 +invmod:809760047,253746243247,0:109619303279 +invmod:6962181619,44237293531835,0:34688460868884 +invmod:32137986591347,450053710,0:207388563 +invmod:171464220392,1821508963,0:85136287 +invmod:4866698,1559814931871,0:875727775988 +invmod:83084876,852948279591,=2:67614759050 +invmod:3087717,3533808897939368,0:3296313572604861 +invmod:685072,47729803,0:7913327 +invmod:3403087579775453,307599045,0:85279967 +invmod:618837304,2026545,0:580654 +invmod:1617142737,5396772102241213,0:309489822606449 +invmod:398279389,695426305815576,0:548019512309869 +invmod:807807859,101277481,0:1799573 +invmod:4399921090,93999639721573,0:23138878622757 +invmod:6198378859,5720311022,0:2650981593 +invmod:86572714,9776668159093959,0:99027417792355 +invmod:1106685402600,781883021,0:593993010 +invmod:788429239716,54846845,0:23729486 +invmod:26682164884969,84892199507532,0:38639429314105 +invmod:490223409,87336215488172224,0:60928799099783953 +invmod:11687153,155174158,0:112979329 +invmod:81995673521,1680666567,0:4778198 +invmod:36278417230108,2563749243683,0:97972077091 +invmod:81100161947491318,626490251,0:10036586 +invmod:84353708437,789691774074278,0:384046667492909 +invmod:4784222527,220196213,0:137693182 +invmod:656338347,17114903662,0:2025727201 +invmod:205944554689,55544669634,0:45790392391 +invmod:58311406949710,684448841,0:398362627 +invmod:2984553893,39836508385650164,0:23063415225053961 +invmod:1226833387651,868339671575144482,0:861301708657625181 +invmod:7850491405,3995878481964,0:222583321669 +invmod:60187945992,93467753554255,0:39782639687763 +invmod:26790048589,54188485741,0:37088225013 +invmod:2047388699,2277281699,0:1326800159 +invmod:437698007378203709,87810457123843238,0:45519261037663357 +invmod:10176318725,798739962893,0:680424092570 +invmod:784178983329613758,151005933385,0:62880260387 +invmod:774192548697746,10018080225753177,0:9683250774295598 +invmod:726085395694283800,277010088622579,0:180332658128036 +invmod:734218324557247853,1620310233702,0:916743102467 +invmod:707389886770553113,418168493503742,0:189385161021501 +invmod:171716270659493,2040489403879802122,0:1953367125622896751 +invmod:78774439204,843419490844271841,0:461564113792074643 +invmod:9092444912687,92042830376149639,0:47447717686388633 +invmod:61162406254,726431645806031683,0:276675014746837850 +invmod:6502138975909229,1737018911640,0:657596399549 +invmod:87574684954665,78519506900538949759,0:47230364038284735522 +invmod:1306210408858148,134301015531,0:130837017359 +invmod:44107140793537552339,77941696100292187182,0:44195935179151712467 +invmod:67019007414976,320349107407,0:230029544613 +invmod:251668932025135,35962140459304117641,0:27454542509813399095 +invmod:1960384563191744911,414832971260173594,0:324345091445220853 +invmod:9693842669955456325,3433846821305106979,0:3209295184025178668 +invmod:95824904457431,207730473678560854,0:115346241869098615 +invmod:8243018284897799671,54774169173707248,0:44653415179102455 +invmod:311780668918,56602194650033,0:19477344474056 +invmod:5901525417230160,6175539028945276481,0:2734302477909765310 +invmod:15817645817088013342,83873087573263156355,0:40986420565770894283 +invmod:2776285597517168189,3599586054083,0:1736805497387 +invmod:5082710450857887,9056726269284017335,0:4011503044106438893 +invmod:8584682476237466436,7357902067222453540607,0:5765479814487665631684 +invmod:2319480092078509424,6781626293282491,0:6716281365540188 +invmod:1240939184380232105,937916010642767528344,0:266041850377015782033 +invmod:658085025934773092927,87790861684417147140,0:36756492918534162863 +invmod:2569452374055474,1282307723894094781,0:817830828946766758 +invmod:888631770342009119641,963322788372149745005,0:58576054803607756901 +invmod:89415261698482,94033558717297,0:55696542331400 +invmod:56380027660316644352588,35652220511128407,0:2604464463341384 +invmod:996226476453670075,45399567279611724302531,0:4432450575006272604766 +invmod:34615237368338359171,8816907924734450,0:7867417936877631 +invmod:57100661310425224095499,80123941311371854,0:35581152205723201 +invmod:4003341194576048121,875086915466219,0:805682679112747 +invmod:6669592405841477476717,4551036259229300,0:1731901161660553 +invmod:4899954396030393,8249234915987429715052,0:8042076059164143158753 +invmod:457015587799729799209,94904436585339172647,0:67495506193470607315 +invmod:2416330080921791,12841205070842866551072,0:9627123487316001173279 +invmod:315334615429521629,57080600687534315852534,0:35876106943989391629797 +invmod:245635836236733543965,350204895578119,0:266548953036562 +invmod:534172301537220853627465,54572957533260480823618,0:28391508956926418431025 +invmod:64835058866700508778320,82305874730776723,0:57154164927574349 +invmod:2935419197344029519,38389371660425629010,0:28166170186967145769 +invmod:3817779121449271,177996364073619,0:33676152326515 +invmod:738146746050725,4141892900866715689963,0:1939330976850898748447 +invmod:92817796396830036287569,23833760274805751,0:18027905863154323 +invmod:324768538678274222,672713761279277469419167,0:179185315765267484078532 +invmod:145806963849046841647,254534976684286765771,0:200530074654889210574 +invmod:5843892547087945,8037935722129342683168,0:4622521916530352817625 +invmod:635350174582720198578,895650784125257583255317,0:608770468357452782491563 +invmod:64902256585483042893,64861417659113483501885,0:48500544464636732858792 +invmod:1348003478873768067340578,79797413707905564041741,0:40891858728897888244861 +invmod:6267734989419158151778,3802309231789144649797859,0:283176065685623872919005 +invmod:3615002399473406,3318504485101385132081323,0:2767667426638532783172948 +invmod:899009032038735494294979,792084588352351084,0:424508678737216543 +invmod:81206746001376489750557,7237607374878187597720,0:1600326671975281670573 +invmod:3627972699304722008437199,5520898889538066465900,0:2272155478759642709699 +invmod:34685989123390710817647,6655359456977349621184,0:2132453240661862741327 +invmod:7144620105437275474852,753995169282415124087,0:275860832898605149106 +invmod:3535338302168469766025701,5721768567217856428,0:1398947754214548293 +invmod:966210500401822916283782,66395891256125996529,0:10363406607924246032 +invmod:5107776515340409,616676046831960893161433,0:328705736461746618977486 +invmod:205573655301723270437,35922475780693975,0:13536061393525448 +invmod:6678162870767249806,72542902715331741208361,0:27163420735919994491369 +invmod:4198363950348197654359,656021938174219663877448,0:30249336864266481152527 +invmod:6624293151166291066603,935090767412780504,0:703056406859110987 +invmod:1425474699733426865447,74057791800633068553,0:32399215003249997555 +invmod:535428418244353401,5758069448318181075415,0:651913765960044782491 +invmod:511900281901325868358066640,7525380451505858160279157,0:4065406882222502194971660 +invmod:212919955640465965,878153960566548562,0:662636940932888511 +invmod:889569596018809758462291211,81473326768558522502336,0:56487291469860004699555 +invmod:443144861277824063183398,3761174124237053075,0:3604887025386113137 +invmod:33394484114211334386,72967632167182065995369,0:31523450321558696309323 +invmod:4146649809313089447250,2358753923413902348191,0:2114494919004119612967 +invmod:9887121613180137575733557,461028287216014552,0:243298503783102749 +invmod:97465366227467312864072367,488220214874854052,0:130500775756515095 +invmod:19292649676011135522471,7877659035660734746,0:283664033368712393 +invmod:88902959369842150471660679,458945796034863505452,0:116241488588017347323 +invmod:1839945988509816044751,9750948399412779544,0:6294451275142512167 +invmod:9857520075588286024975851,1918199730912356922553,0:1407196181358170021243 +invmod:98092461637270194063,69938396621942574346694,0:39897238269802969068339 +invmod:219033411512598606789840689,795134880363756976388,0:639110818118499283141 +invmod:88186459451009468808509156,931160442943017676802173071,0:629562198515766072504373649 +invmod:9710794978083575389221590569,4251433051225510685,0:1014964735988867489 +invmod:8101415155618280845453190902,1531876453912452699591,0:368176555527134025784 +invmod:29409670089331883811,535811823788496989270023400,0:370280198672135017584348691 +invmod:8305842606005328583,9579564753339003236281695,0:5722440512759901640334872 +invmod:39386484402035672640779147,405797130275770630884183427,0:110208599835163794381201071 +invmod:832687365793006297742,184982557537022296058374571,0:83904068232925523197663651 +invmod:6553207532807060406664,502238468947067021963,0:454270228642816251641 +invmod:37454379370943067757286870211,36494426305368965154254726536,0:33638650562651500684923138787 +invmod:38605483438466601679,682239274139689477361679,0:13199577887729473047769 +invmod:7965022961827711681795,2285716672004926097772197,0:2122955484406134178638446 +invmod:300057798344833538558206311,8931778125815914295,0:6565813118197443911 +invmod:324842828083012251597681011,187662727615575337969,0:123961367799983618478 +invmod:59548842983097072068081,529556931168692661765381,0:204382555679859518219042 +invmod:876100791904547219529602,984558128732533432702173965429,0:90974750030008269191789684241 +invmod:412262036467011789370687,7642721479883866583632505,0:2279185286560398311684903 +invmod:35558590466031758855977117,887974042467941992656,0:704625358717245867829 +invmod:626663442467211390440132060640,1374148771090265524803717173,0:590755849649898431023419435 +invmod:85901909124840045452734003634,27175621479815508400005,0:6884774470049680531679 +invmod:4803896245161574921869066442,515522173785247100331641258677,0:82575699585005426552163954975 +invmod:30894573328276878531856,4087591712675305723294627,0:3493627083082495776432430 +invmod:9141841986580679278669126,505635384209785163519211124141,0:336188649744514864135515371530 +invmod:188695176591763873562433787,661611817437909433157465,0:375067540836983193116438 +invmod:241487793644307094737649980023,4603295709537644102260078209,0:1875185676154036094527511246 +invmod:5293130391697702045129223682241,4410288170386013446930,0:3281121803360293450491 +invmod:6033846664871710576440686677569,96946807752243502281276550,0:45266733495357578832984479 +invmod:89038378306924494551626,95628444614978025043615,0:23786747307100516932196 +invmod:12710922165960068258466731689,4790016424576553135438840,0:1207752742860172910912249 +invmod:2735034594918378899070448537355,1893682211859850854604,0:435685035552133636619 +invmod:68329358155371632083140828250982,6288770840498808006152991055,0:5931193047490714028593816373 +invmod:83897752529920362009921,66649056389057335553727631393,0:43268302813732520149524641842 +invmod:9689473529426673026778331,88076063449762644474294178,0:68554034321312192241642365 +invmod:73977485020743016621210217010220,53253046617921140492481,0:34299048109456536013621 +invmod:9682622686213510676332035159913,126726573785394345551110507947,0:87562143297844604196976477132 +invmod:5131707842034728461484683196411,9833933722624780748771816760,0:7636914556132154008767009131 +invmod:622466933719692949758353,8720875070568727490840986966,0:2243063168207109573811220613 +invmod:371914469040335929323957821,29979763825336998478908474,0:19112551112998202208882569 +invmod:460040264854684284500867207882,176619007178719669689957899985,0:84600278607589920579666033533 +invmod:7814781702042412652917732124,44974092645758858215810834392705,0:22525065545650129764783444827969 +invmod:689879593008118336507276219555,7029140833503782253304852,0:1657942681146249790361611 +invmod:588753311584356398728925335104347,655245595214265213328588954,0:5370808165845253986418065 +invmod:215270851453007875328537243236,930847670919175461277424586154331,0:854093280868657781869727944640825 +invmod:554018901896459973640131751591,9763486748180940629420083557,0:4943017226299795649673145282 +invmod:13807862007846696356170492992,218480252372917913755483,0:162381198060244352285330 +invmod:3647663862216963935039311,3498263635673871413147938009,0:815287510808909642460179901 +invmod:1394556521513041955902249647007,8314730285674311054788894925503,0:4701759015019363383377776837184 +invmod:765922458203903632153317653598,772684127072442440623494065,0:681475643232329050740648777 +invmod:1636182686335177476661316231316713,898482806249393672761387906057,0:629953274075151653191843542345 +invmod:584489430664515187742143663,3226379401343487951747550753985,0:2300722785510258273879270270657 +invmod:70597555974027836626331232,9067577360780247310463700060912415,0:1343885645550828326227031879126813 +invmod:83016782422655848478468587,3574392772750510684744014,0:2160375438947262160886701 +invmod:9509632620059688913461744335927,2001546646968510097453590971258811,0:1579171227651658107693890864008934 +invmod:5305698102006965934646514142,1880423512328598313144733245,0:1158802006274691372231434298 +invmod:25818273392182891028387183709,372712587491320607948739787619341,0:83620423512820588265929334666867 +invmod:2062301690726594241599730508623,1295011898282606475280524130169,0:1126618128280194264421190196682 +invmod:15525882195404306532803603053735006,524851347004182298259949574931,0:117558057158627958293103758908 +invmod:98049989631901137366836343057866,2132117143964644775000173275,0:1776678869002856275917157286 +invmod:68035486069315280099382173380,136804376642014663925354513,0:116540031317166597205778667 +invmod:930885787290248986653715917201,839163742792309140697583306,0:467450716792956567729742385 +invmod:618219232165541881120714807027054,551811312165885959528421318411,0:241084816664595048546274133494 +invmod:607491972766521656095997601,4258761064370347279045518650,0:4106442789435765086100078351 +invmod:1794059822501926214368058365897,641293693468680328700219247,0:412236704145068075117115904 +invmod:66038046351270827218975238,828243810057190999751749430463827,0:201240403207654658512757471515946 +invmod:22489979027542119833361766314814004,4267735327278945325377118240414149,0:831989298493288398125903826182123 +invmod:96656949043354906812270332568634084,17593722554451983298697234832943,0:10389378262088955098639501532940 +invmod:1475127063531246543305342130787,5712802933759973674949655288556,0:911126023377734859289288839875 +invmod:94805314820797148511000189717800001,64899576259694613046461539176,0:48109809959614533507389959049 +invmod:5787223135405198552481837574149,5421074820227552626308319526063,0:1887880601492799950765024255248 +invmod:28973562312482088535256834009,12322004931428309561996283040268471,0:6951695655429544292118574942872356 +invmod:3696872012110541582072428310551341,1523878544437625304694982047192609153,0:120514356890624212938061146933103186 +invmod:7388600304197232842534029909,773289223233970187052705366304,0:734898540650399983999883872093 +invmod:7331236475650961531766667058913110203,693192479825024022606662504949920,0:571670151801413885792817856265587 +invmod:5235989645992380877547648143027,9843490764540995482808427936563,0:7792497103048946162851333200848 +invmod:7889040487772265051508734223198,970333028842680057477545240961989231,0:820851624929176605383247534276742509 +invmod:636939509978082435344561123977,8632390068721323171174332473333535190,0:993190319417433889538526784654541983 +invmod:91838639727927578174237486907982,9330677294050455577402341248771486991,0:3372468877355534050061501496367400668 +invmod:10921336389827150720097811900009211076,7589092431150460928351199116667067691,0:866721211802572827148277173383125007 +invmod:658155257851240068821873115015976,558927662049398106193187373360428065,0:209745203635098313869122201832200296 +invmod:5585592751467684477444331029739,27200783107220910874350734817147653,0:1132197483918030242577531292806291 +invmod:7637148852097915353546826493,42198395510943407752409176135,0:38579422829892871530093056797 +invmod:228011811609919943842937730868521189,269359008901950141311260148678129,0:204220292063517008126064637465387 +invmod:85379073141618507288535187863547,3311778009260578617664169854013,0:1251094538034868342736717399878 +invmod:178538609345684608529279115948180,3209187922934820372906185622931,0:625228980755918910363724543435 +invmod:514451212940578583651534706134690,261960849561824473447008674451593,0:131626741363323972030200440147547 +invmod:9634204149807611579602377719343249239,91352833806659059550235201423093,0:43744490808833751862541187085697 +invmod:180205999846263895162745909652272689,61037131972980180275583850831,0:22758511829661545789258800814 +invmod:21945771136787811201569306864610194,240543080450829974515246807891357405,0:181461539213602660625514174427621814 +invmod:35517481628882114783536774508289,73933641713139782399722231157687221982,0:55192567983407494884175622090344427645 +invmod:61133421177402004520562281574369023,490575463215034765455424331786,0:428078344043933589235114932577 +invmod:61997134551496924667492900578768215075,53694317203253417994456413131837794901,0:5127049382196704081839504435078188237 +invmod:149407595591992713390607359968523153,9733723254627254068241609649090688,0:7103143213776435125430106007909873 +invmod:724677347918056918707332818251,4206398531197287079326882898987,0:3352013813776874655296817354068 +invmod:904144691211996824768615430166153,57579709060839020187927414941125095,0:54557924391254568447415464374061082 +invmod:464828030341876048255162748051,16315883710383791874911854058033061,0:1898204461581732360730698325426064 +invmod:19170845621606248311569905259730887097,911211106537315652144761781751982143011,0:11609063390937807744161998275631424941 +invmod:857469002074663726099005122270054136,767466745792444095098639793741965637031,0:72659426270163915638661477107149562702 +invmod:130093804885990385658501097171753042,91493100398010395343582415770659586075,0:71562287103402903271519248491284598728 +invmod:3558394519963770405007494484958693,5649100976897692393477567234571091,0:1778327570753831461149235315785758 +invmod:827172132916351233103886705694689183,7406200609002751101596817359849513044605,0:182683152383530805186420471977735101947 +invmod:44588398105132907935221361042363023,849039192087829478839986564159076706,0:756327512592089069079417038566139671 +invmod:87482753881086943893477139352309,15136288595019926379451404752790558,0:7380826408731655136881662259683287 +invmod:2816393010081341842764909636597751163357,666424385901140622144416941996627540,0:37970402623680773312812150346972833 +invmod:44160925420830144883476086426186778817,3964315773874336539018935736605912590999,0:3339494318496833279004795765823107883695 +invmod:7784294051005222901032501449689049491,82221954950326057541175302867376355231,0:35060237646445852249886804139112143661 +invmod:8782186458787754387943640751003,287196330910083697223737780139934653,0:151169934658998501405294488263167850 +invmod:52961061996773303218378119209138937,4138078150303278572595508400662,0:2334686283357105837861457163873 +invmod:120067972673320339436684163684521541899,5003127736361658398228918751147,0:2804153651535384761721045391262 +invmod:21160862616768687388014009097902145,984271481536213754460622644543049509,0:110991439312803462463226099820276772 +invmod:94870103291793687661854548564670156557,4654396151789059038730576061157487355,0:4545904732262329435720397277692160608 +invmod:126765551422438407604981735815319,4526482948583699374467868274935682,0:1340347586087681863052878791652111 +invmod:561052644739230772711625537622190085922,182709904797036712378783653059935117,0:81730760740395808028866350847708745 +invmod:8440958912355253192980982965295847,99976107874430648288932536807344574289,0:44322197083360812344238924546434599316 +invmod:622818497925638835644269035686568759453,5506232467142585446362605183461,0:5370963830087767870403236824410 +invmod:57453345384809312296011379661001742955,386140250699346346360045382167776159,0:63476384227956307102053350966611778 +invmod:83416537340827284838496955161681676081,12832473375703257825108506495959421,0:499463210654774129441986832321381 +invmod:6764203692091211849546587544996797291,56141668772394375440300081823159,0:33236198277199128613406762379601 +invmod:40370041535056934456885738109160412,509721817241840184167083180099626991,0:11491022410510426082577074611522170 +invmod:878180470796147113848439165151873,17763546710042203623413235393081,0:14204683605998536689672179103545 +invmod:55590867394053732499429322189218399778872,43372981951757571058338676426693,0:33510348378637076952275179882521 +invmod:7546327535456972783460913206047380047,86726167905648033666208453441434584,0:5322052162117479044160819033125903 +invmod:329955968415706177763208593030907,50516382401253954262072882036248004026668,0:34401169217941393127943862147280363000747 +invmod:87048112982262598454925291684403335,805959667741585911092793285492264429037,0:379430630180430216461244147576608482936 +invmod:71555142355447318269121083903394685,87398662401733013244354964840378552,0:67043514123128780636096809791233709 +invmod:1711583735940653927946109180989149,26241424080043582566688947607871596,0:23154984666365483606784578156029249 +invmod:542489709314546955942774519697358722621,143873444084042887511916303711981530841,0:121457408531791726256743734440607914263 +invmod:3781041336068211601179549569884186970409919,327900172706652019993358885788160915208,0:285215395500809506516326193309579388695 +invmod:6149927428146656336227133345815170519,7588487705630577686965956743882876270164,0:4653797610323419583601822953872210529815 +invmod:559049983877521594210938163489019460719,951902276119605669127355840612003004,0:683326157826438593722386803692042151 +invmod:9570949170433291990391807356653340234145159,8534474723057896563545270622977282626469,0:7559467634929916340724978098594978746637 +invmod:987849800664220039883494398655886160465,6831497903141449539539967513122604383199548,0:246607561273243347599128464506339845374005 +invmod:916515834175745144405438914198070103556585,4056859814803168890581397499472591207566757,0:1770209812768098816334392652319997964773464 +invmod:1228631771902154967504229180729583591093,695152447128287511961827228275915906161196,0:68820532783317596490391949047646875295925 +invmod:85204895476713840095779420329627903803,797154697565857850707103989977884356052456,0:189834737137977542797303467784002206530403 +invmod:459421385046429900048441785147457350775932,7698087947447355511478579587800901996173,0:1050954140018038340522121385945573583123 +invmod:8211730416251817740382555577378910158254614,52604175850251752026919899874340035,0:40445721575495397750278068202293844 +invmod:13222111757762648331396301846656536813259327,266888325807002880450404100257370089541565,0:109298344157958287037388161546711172781058 +invmod:563240385133071678994472898571956920719,3993868915925455184846327870408751385272,0:2785525939806848082603069961895833469023 +invmod:521639521589957338674682854605577427535430,91720686816082732671407774270039351,0:17647263388578210512345389034742837 +invmod:5156816003277235939668801939908183725744,5153042308730983383934473837808025008231,0:1734593135670097399582886018375080924055 +invmod:9790574355124996717257076778746595337,7094481197220145398883635593951185851053,0:4633443452058944189941546476417089729612 +invmod:3738689158705918826996178299424238668515201,6395182435555998218010243005378643333837,0:4032119940417970860053188513124120286092 +invmod:13614043167840054636971961619348110233,9922954903164743574284496007816459280672855,0:6390894157193464477433210223562314675849502 +invmod:7722989551905267507172665225415434299,285028691296471922732299049703480528,0:80127272552190846362411085374898803 +invmod:34955948774875418184052263202780817611505383,25511643971935598979339727281441119179,0:24793574418979515087827479198686647984 +invmod:9752514502992806699558935311322486653812,3763087306264536914043797765340033186467793,0:1025569723180811973169033467813546203362574 +invmod:27465132713599700004772511614559440798,13274810225615043094606232580958497359,0:10132125917976802477194900566349825181 +invmod:875919373810765425715940434040195178,5349809266782277700868243297033816292139395,0:2651731185643620478354040628390151701549142 +invmod:6881906840916466478584802007995526309234459,756717805668582535693388931894211346359,0:145296958725486236992417439558326443417 +invmod:334311791774893954611025022303233183505395489,584529866497361400618684187440397242,0:292400244436936079523712480681940227 +invmod:65712090641887119990742721342873930,4336182528635667934371588198046750892623,0:558253505423903869478690367363302598682 +invmod:4492701702646633574790657588147591497,887008290240310205861702963649926144764,0:434334236746323412542488940776733666249 +invmod:411586476025579573736047981166427386223,60898553483467476285120690698220614489936966,0:19455038575262424591552585688228685688467833 +invmod:6367597108696643245107048337012153376861093,65889932274525424609098394737176730568661,0:65870071424966086215554796795651660966036 +invmod:1049560658786859350707338961047775237,5274992996959254283334337773536473890159,0:624593399529926255525711013688044195635 +invmod:107527378432083555117117943876656903468876,716429394528758636372948757175038602405647,0:444454875067125022527116753199711164880725 +invmod:555145963886409519368431903982210135919242,8268229830304970030006026946953367235680701,0:6387083941953876784249641453937804161251014 +invmod:77948002708019596204938559286354567269,455121612933774657179682813659815211,0:364811843921650022521340876006123246 +invmod:498360659435361921366498611099013149316057,5728485554979561072455795106370849106458,0:3102501845651843687065534092900673818593 +invmod:726843237990292819218621975265928124471239641,2887158075124871990135103381732069919679,0:1068470994113776781214157184472987715710 +invmod:14490257580500837566390302262779531170047157,32393480535449409499704778950027988096,0:30287826764106717477700071788946051485 +invmod:6270142013450141253944931199020500202121765035,3763601356640037994669890437848434673885751057,0:3156243150557294814061853765553333562512998545 +invmod:809245912199158373741272239723610868982823,8030588855423774308237502000480454393456840856,0:904571791041508997839920338301126020187933047 +invmod:19533970453895817522762076874428022848,66299209695045887406306821511839592998483515,0:13599402726209549954335916901935358290831417 +invmod:23199633133008878062415683980086247896344005,61479113901097914563017676528126502674819176957,0:50989713359156907028812686282866020892767441337 +invmod:2862728440518115487475964440740584330473078140,51210656799701051518059629917289349291243014631,0:17918271858261676405666583245056315801120815006 +invmod:14971096876073425168884018562366418693791183,9559636375986473567719335761058531628207,0:5109731903973538125843601711325876342232 +invmod:532670798205641227016874816346924933526518,8612651409966775146216925722782469875353075,0:3211535369857991680135616378366713231520582 +invmod:5277579668620044053588021313993390529699415,7623352070936849233565453286144593741688259,0:2195179503632503483804554417001536677298355 +invmod:1703242284411257170432455927132332917751,91946197833078813303494400074098343464254335961,0:78127206681265732452981591549234092643891370502 +invmod:661687018626315126767845163322826263674289,28536010760826245705236059697847500278395679313,0:9982270980885276298051810649502841807467187592 +invmod:71856999282924192732858943855372784788,27823718424741468425870327772094802246951559365,0:18935276857302206232390405420351565823103424567 +invmod:4662964353558658735645456824027896151772,33878933564208336888348089073090367622314169867,0:10548442440909583945565305765948929087304389925 +invmod:62009389758664279395604249729164619334196,538359108562320297007051503463417099077320173,0:398148791843022164991556905409865960939044422 +invmod:6183332385813041506672156000574955880665,871559003971682075020587679481749233390914546267,0:361446020046797748452828311000569764812530143855 +invmod:9155753362316784223456266001165269228274821262,564516474013187481573175782767769679250281341653,0:119205620905238875198589061317020547195431291469 +invmod:2381725363012237979273240212723131218823907332557,627105554257965120883096528911164566660356,0:171572488325502115512339758443240079349533 +invmod:98450611484841078779323233743949010093062874462,498474891646461337593869229973450784375275,0:479013309851681824382144106029434631482323 +invmod:302941267046246453138910366044154426837953622,83818905504557213907433754163930101975463487685,0:77920560252131060387953578558356224479003138993 +invmod:3017383944801662240691138696888601411338516995657,61737866641820357298733518758961763874892655287,0:57869330891359519120660303033767633391977224135 +invmod:374917274538161669733321516492506551738043651,77803838634333688188670502424982439317036,0:68639725794250011077961000847054314676555 +invmod:5358355766108806240333647212584488077935,587627440281100756115550692187455782420924,0:314618325830273870368608880986071270807683 +invmod:86122802573518542982029793217367784359435,4444541935970557301558909662301636875859,0:1955320382109976216143063234526457146856 +invmod:623824975419641052226172487141306430801018589,20768350634786110695583221446196247762848997250,0:12103767314840562576462750961286924811261413809 +invmod:7590027145148728758973273983569196467947062255394,90068309971049962266103924501064672741412670385,0:6331972725698812300523110784176833763986644684 +invmod:686524668697820444915978210393072714624818,186650354938328642532017629073639972204995691795,0:65611028587457585490550162776486984373381347012 +invmod:8533533853350881783993052422423559214064752671,63016121594055151516162786594467518419073,0:131371511974154164830815450922802421883 +invmod:5344740912348618433699936772348773718405033080,754609660139342129058931248435676900268044223,0:601779294202074328690589293303990212685307436 +invmod:2630687964404181803667484048857594086603863164778,42030243673690269464501320091336384623277873,0:36838170059220383772604498138745951997014365 +invmod:5306175182479523993478999645749970458659031750359,758113498568456349896540610013930582835369681777,0:501795105681317857414510503515044239126764236204 +invmod:806866598044057476584935940512202394402119521,947641922298177262021501581582394143250064926,0:76703572909587691543666595336149993104408285 +invmod:3752967247553075344733410201251369307099526185073,4402571726399572455553419679967331632378787202832,0:2918979067711444062792869424130652843352323160497 +invmod:40984400287710529101974761448375262101587597378,7767837478658170863917839375734721468526147967,0:2136424825671493001327961172463161875887529706 +invmod:401457319584326150334816297804779451405784588169,540188815699793070242075787313955763858504,0:67372106144949744344758423425304866564305 +invmod:7328132145926961595815732345858284613765167,9787719863595769932092399021858175294652078,0:2230156054528184544247089349526629112621319 +invmod:77171202039883192025885180439962488662357894253,12064457568855376162922164978659009383963542,0:352639382534756831500079601223680437740983 +invmod:1689300510107332942753596615492360305248158883808,5021685778114233976935875054258022503184892416233,0:1762404213252802117851393076433629721481995643743 +invmod:413626471608667549603757397530674300567855542919,759613621964327430276342657441698817566357,0:642374968767231560916741285504168484044924 +invmod:815487836506353402229957209437685304756474,231515992882606539156732730332354159627815,0:55964822173154353392771255475917621969154 +invmod:296426386298708272323405866802864845229206612199046,342337072550591175877277735718537487310584965,0:76144006758731629943626088879647674452875321 +invmod:1368837997243033258097250654549080178537403,72416746615410564704099840606609957868938364467,0:42273580850321891614742957751910595825483883404 +invmod:9641372200812485192345151698897221555588679358147,287806137472581046723231335880874585176303828,0:255252466811823779617792436926094192052670967 +invmod:46719509859424879114122464677053888891786863,210544160158454559735214754459187198735974410,0:140373812459197552193672103292254446400518517 +invmod:69471867059868794437449477784309966908311269,475692585941773291840125734394747164491541976266150,0:329429867057697325602436904654233483107661273264729 +invmod:7405667221685129649068997020918698026393175001749,796216300173551602800332455600650397180944683116991,0:130410302259950789489978656088071644453583901435057 +invmod:9875331536196145287163751005066164594069492626,2201640116844513333140292091820792899163450729637,0:2047598928737481788502134745016206195377427587363 +invmod:62945526176222857740120186454769067947012290363570,44934526527044082707728840604580666450874671024251,0:43861879034315837687481092531336507739461347512032 +invmod:5812420662398017239905743494134134746465045897292,52956025052699844938819589327012098626977604723,0:13815068782356510869666523823706600133524973512 +invmod:62988324661142084736397879043193595721220178,7404210351476786487650626340728674929309799,0:5036483589239858803333996442909574578899948 +invmod:286333666557475431954356887797614991091286553885,730177931071629647633748484619415338517839601274,0:363260706789674293461306138407487067104937300831 +invmod:49616721004820516975071365326319319198923021689,132795538845737308034029046093145336156955241,0:56876640900410852290230149182444669136767187 +invmod:5446872665716082344009604433844511709028377538969,2280298209842444269643398464555071512122870262,0:375611662251833543184276080958156903157176019 +invmod:48133060961114172650826182330907073912078935,8721390832897265296674009086319009860242439839,0:7702992209702028145739081817455455176622350078 +invmod:40807573183755241530172346993573440974806877031,21200726747362217929091368487884445712920776,0:11454862264524468743635374252060129893516039 +invmod:4876011850332170585030918362754881792191414391238,883237429556989698304596380266521788568157904911,0:527685501843148925165860150493838048613672434138 +invmod:9004216524525198565187718452531030887145904294,8878366789568435967650795187708828058761785,0:4981848279005575310485064446844029075803929 +invmod:6993868737949430623485012912067313181948980567149,72587842808105829695332807775836181652781451620987015,0:29356657469761942723664151650917553481140935005518584 +invmod:75838243096115096340554120168203104139210864575119,6451996398231430323660940321776782700563518057974,0:1345394845933169255579194602505266246529197837419 +invmod:485790318680850515659798197857065903571954663516221,67351781195434836704429039169834802850340728665,0:34078566883503330914204885404291533157887033436 +invmod:371333400895514427330799618912986292421266652,74735768661976283216974595800490448686381913090033,0:775734485942448008241221468847983305862557765286 +invmod:6097834709804461306077622570209088350134909102,13260744904604742982854800098901232265425978195193,0:7180051176576380055634721013915424214485695619650 +invmod:600881693193364832300600937554551319012583954782229196,796027198454713309819370879215945879338962169620342457,0:305489886166685871022060158652320831304722506678707663 +invmod:5662964710494261101411655474670941615613599315,444220509796947509810830805138094482931853315876829854,0:83502974856377599186566250358062403371236716847533769 +invmod:6270395747183927103046939721473439728631174048403114,8803495340207614105802361410280441129955119276551,0:7638483007340998905004349443806488928949129256475 +invmod:5312750065420550632940178685674720232414077135667861,57930039498945162545687903211875639956633916330,0:20906112474411708869764963749645301466537400461 +invmod:8502626964451493813784509478933179204113913861,151683587165616476059679476891877738245602771985126484,0:17577340844446441446896817780642040689999518731337537 +invmod:4941004253366524324322788098717712122185453894,507952581732578381349957316858286666961520136240812511,0:312115745275256030023730055964263277096930720173778858 +invmod:423987861634880847990099692392247549547399923116457,6773005116228586899620384151284037878817381874,0:2411264735887581238523319245355992628456396037 +invmod:526342378928843427610581233811595257981048046869299,7096065565042815656938985029340106874450131548364,0:2266210293557852404933929618783723210631424222303 +invmod:78446630124873873738016711675224033887037462247129,7662020477272785489947682873719507826211767799272559,0:6618353901163261801200450611723749392144591388751943 +invmod:146724084718984069653032415105637599783153962,30298034422463313667029878130649415526567724423891,0:15840758667632633447433042854062793488919393155550 +invmod:532466063698619582407914116981870172085275218057609611,503389009870258977998715866699908326167138509155621,0:429130769700630834787501129352450771879630731320433 +invmod:664376039724377171384810644630468503764696090762,224298076389079709612544590641569981088172697659695,0:191050396356473488451331811254972158658440851245723 +invmod:835483973043657359948123633363211141824404441813878015,69643224478201509070483710852895974722854115357803189,0:53721439884173124810110466416454653383681843157933247 +invmod:813970262809468815021442298539024428784964079319,429074523317944731991730858790207763790104061278625586,0:158332012181946654631830290462479503904893230674781917 +invmod:3905569509910236582271054510190653771408672274545828967,21054133848316667891192282660059320939317809341779587,0:17094616510862655692939144695877501853951076117185513 +invmod:4691307104554605783547935208868795800777868512,942772133788456146227915931545461264049922041187188131,0:469683594104330994724852019245006601277880263578881551 +invmod:6344527026541951916306965449095645749422549760,76368107869275310020917570118694704915444730867,0:41500809372700676201512721693097909656425890041 +invmod:1532687328617246474516893240843261381746745335187504567,32537955155074651543885535513776259898758463526907,0:31592260213499097541600572787744360343931765806593 +invmod:7018504221615574834208014706510055329334098873351018,101610242334178923059833344503899037186775079202559303,0:10649252292552342413027086385381658365781051021861494 +invmod:614235942250741815189766632484724986765317349320542,9362550248383847419253207491333265608402756140737,0:8160460781303503000366571190909239384952542647609 +invmod:7775933593191150830308054268586415011508980457,368533946098442033007225558534059472616584669800220,0:253801676862101461324685686415984317623566854941793 +invmod:114994724586756601240947074309582797715956747530865,3876970882437444481290779177938795657877704941299426992,0:511133484674702237970986949221474571854159368113080049 +invmod:967002084921847074704293339527143050334641639867373423,67184311934061779941934593909885344171962367245011554,0:54742265392939905619225231956123009510166549574440811 +invmod:6280498620763463276942694339653106561075254543429361993,12246227880575723984287633819537276950692995636118272,0:6888911322746399525364250058022364228815026516488953 +invmod:44275278051846293224710462815690831294050926191,3528785552950193331450403045205521284400464217,0:120514793436107018084728538690789624267772938 +invmod:77233427780696709885390992536748673614121634321979788104,491164926805617690128308614539794239093995145700823999,0:199381937154931303182568760928699286043016185484364692 +invmod:2935661752367750120971963892075802637450138243541560,9020651236069334749255637029615697294334736998960171627,0:3125819936094028800430390470247841155021420396038210016 +invmod:302473523210899830602993285719361792150121191223306880,65877646712326499599771065429073023167212168003911407,0:52297679713827579628631563559676964578000626147057904 +invmod:267895147221485475464503294804253313969059499267,749147805746876465294375899176118315575206244421458271,0:129024846433542980463213625490720174159069030878062276 +invmod:3781978240476513092005529074451902150648006057998586,27364485741607024708356504480914129745315051983385,0:25329045084429371227591358650591561585384348697251 +invmod:948013514376879058094102833630021404464006764852569,8353743535195396401876310124547966294825033103946,0:7927522032829817758549574325420299949503254620703 +invmod:6773542220739678376382399310753118322321830877020076563,23546371430476080325875311266723651505011788851,0:23034799134897779290547258699648209277778406267 +invmod:56696856401426408452242119629657459089185724508184784934,7221005627051658808617341708011763226860565840269,0:2227292432795108865092977039762847004980273813910 +invmod:92662353717508325061448569170875221120898258909234857491,562238642230582644285673923363000274985338785203064143,0:82872573566192386039048139131290614037215257242199497 +invmod:89468591435176366016645724528914029419829867195549,705411786218184999265977265146374736801000908422516,0:485602435630685604293519285770866831844583644332693 +invmod:2277395840205666058520703175677485655050927000860231,792131783062753783192832245011815485211186317516729,0:36274050046894199444508304306949846655815849306835 +invmod:612911230333178233436163590340359496090089351991282071005,572255259654004408298629798022675847670239895312539448,0:403266920799126234196133278222931567019309289982594389 +invmod:213241578824971760442836297601417939805892681628568881016,3475071686128494213859357380055444712046960621996643,0:314926700961595267117992983958097210528266000605468 +invmod:89881958503908564448695138563460417549093214244379,33280210266097827064329998950581767848637995197241605416,0:12771855655553092160496981250440547140648269015354531011 +invmod:73159396554894592455810450837975467585529573360122965037,161924163103234420910961871269258741990082667722423375,0:55900291355504579400968626517795006263004157119627223 +invmod:869777439024092504944123032140706083242764771562615,3691156600535012715499994551919740723415019969643,0:181436500307965243185392814904512789376492449509 +invmod:9146539798430854552628645300653561881701305853292111330247,6627303121361849299873564751355803129746293824560475542,0:2409578230798119285960935905755578839375100707728705163 +invmod:24992448558250395162546529057033728367963608818369,97104418275857998682685499767517746419160351530467647181,=1:62070924902659777799435874506647028956762328885724256288 +invmod:11569840794297110873922272445085763696814732411121,3856710587570728871230191743757018008573821992755,0:80733435598402588027986814199605794544352758136 +invmod:649787313291617912250345498890431010716418004127770,550784775616289426175030973861257697988532404146125403,0:190014706473838692857161698137541544033343388692933291 Index: contrib/isl/imath/tests/lcm.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/lcm.t @@ -0,0 +1,780 @@ +# Least common multiple tests + +# Basic tests contributed by Hal Finkel +lcm:2,3,0:6 +lcm:2,3,=1:6 +lcm:2,=1,0:2 +lcm:123456,34,0:2098752 +lcm:123456,34,=1:2098752 +lcm:123456,34,=2:2098752 +lcm:-568,34,0:-9656 +lcm:25,=1,=1:25 + +# More involved tests extracted from gcd.t +lcm:0,0,0:$MP_UNDEF +lcm:0,0,=1:$MP_UNDEF +lcm:0,0,=2:$MP_UNDEF +lcm:0,=1,0:$MP_UNDEF +lcm:0,=1,99999:$MP_UNDEF + +lcm:-7,328492456,0:-2299447192 +lcm:16522181,930,0:15365628330 +lcm:844378,24,0:10132536 +lcm:209,3,0:627 +lcm:70522336,34102,0:1202476351136 +lcm:32557663,995533,0:32412227919379 +lcm:641,701,0:449341 +lcm:290748,-233,0:-67744284 +lcm:290748,-233,=1:-67744284 +lcm:290748,-233,=2:-67744284 +lcm:-95,4770,0:-90630 +lcm:6839092,7,0:47873644 +lcm:787590783,-6789049,0:-5346992417735367 +lcm:721,15845,0:11424245 +lcm:-37028,-949534667,0:35159369649676 +lcm:618,-3,0:-618 +lcm:16657,-544851,0:-9075583107 +lcm:28271,6,0:169626 +lcm:-35357673,5207718,0:-61377596706738 +lcm:99,-565,0:-55935 +lcm:9311525,-5,0:-9311525 +lcm:6221599,7764515429,0:48307701428550971 +lcm:21590339,486739392,0:10508868477933888 +lcm:335,3699183948,0:1239226622580 +lcm:14,8755508782,0:61288561474 +lcm:-5302,9,0:-47718 +lcm:8236,9462435,0:77932614660 +lcm:43040,2766705,0:23815796640 +lcm:863478587,63,0:54399150981 +lcm:8874055124,10,0:44370275620 +lcm:8204,-89955,0:-737990820 +lcm:3303887262,3,0:3303887262 +lcm:75504,-62,0:-2340624 +lcm:436,2123372,0:231447548 +lcm:3361227,943089540,0:1056646008421860 +lcm:37340421,223177728,0:2777850107114496 +lcm:-35694701,238293550,0:-8505817017478550 +lcm:4263,15500547338,0:66078833301894 +lcm:1493,38730799,0:57825082907 +lcm:-635007,298501,0:-189550224507 +lcm:4968,-98492710997,0:-489311788233096 +lcm:3367542606,17576297,0:59188929003209982 +lcm:232155550,3921719,0:910448831390450 +lcm:4860966,700,0:1701338100 +lcm:2323372237,867,0:2014363729479 +lcm:4268,-29035,0:-123921380 +lcm:8,-73804207633,0:-590433661064 +lcm:395170,26163606,0:5169536091510 +lcm:-70027196,6945032910,0:-243170590407510180 +lcm:5871172260,26773591,0:157192364779785660 +lcm:17125540,836,0:3579237860 +lcm:1988202315,-68060596,0:-135318234527479740 +lcm:554434367524,-909419,0:-504213148079308556 +lcm:-40457802353,3398,0:-137475612395494 +lcm:410791452776,4492144466,0:922667275633904368808 +lcm:135751970,7417878752,0:503495826902570720 +lcm:9593,31047471995,0:297838398848035 +lcm:-18387143,50226,0:-923512644318 +lcm:413450673851,-124,0:-51267883557524 +lcm:-618513698871,-318914624,0:197253063714294189504 +lcm:37416674596,-8817,0:-329902819912932 +lcm:6242382,-943205,0:-5887845914310 +lcm:-4949666413,1501091102,0:-7429900210422557126 +lcm:-6385784303120,899228089,0:-5742276615660794337680 +lcm:6308,-79643949,0:-502394030292 +lcm:2421,136928,0:331502688 +lcm:333180111,442438,0:147411541950618 +lcm:723761305,611024432789,0:442235840862251429645 +lcm:-91289,-9223787613074,0:842030347409912386 +lcm:10944,57098,0:312440256 +lcm:57145099,-94544476,0:-5402753440923124 +lcm:9327105307,88173695233,0:63261949288116530887 +lcm:73230770347,67182928,0:4919857571607036016 +lcm:4810254287,-4310,0:-20732195976970 +lcm:7200253992,9893,0:71232112742856 +lcm:-92709373682,-664752121448,0:30814376416612439465768 +lcm:-2236424417,-69570761,0:155589748609671337 +lcm:781963714,61084006246,0:23882738195060678822 +lcm:781963714,61084006246,=1:23882738195060678822 +lcm:781963714,61084006246,=2:23882738195060678822 +lcm:78553,-3773682081509,0:-296434048548776477 +lcm:24811454802,-26314981001549,0:-652912961735421705488298 +lcm:805866671,8061826,0:6496756880801246 +lcm:4281823377004,2916710,0:6244418530970668420 +lcm:15229,320560332911,0:4881813309901619 +lcm:6093153060,357460,0:108902924641380 +lcm:624794507388,3264784,0:509954777752056048 +lcm:2632503413711,-514594728450,0:-1354672379322310051777950 +lcm:7216089,86034,0:206943000342 +lcm:112578025,4532680608704,0:510280230883694129600 +lcm:-972617496,-1100642928524,0:267626142282779963976 +lcm:-972617496,-1100642928524,=1:267626142282779963976 +lcm:-972617496,-1100642928524,=2:267626142282779963976 +lcm:86658,-56860,0:-2463686940 +lcm:2292080,40552081391276,0:3319593382689853360 +lcm:57144144326678,3579498119,0:204547357129208422518682 +lcm:77390585076,614924,0:11897332034318556 +lcm:685579,959286825595306,0:657666902604804292174 +lcm:346354116,451435163995,0:156356427156803253420 +lcm:443946215999,260668,0:115722572232027332 +lcm:640447120070,-441698,0:-141442106020339430 +lcm:1253208493501,-8521171736,0:-10678804794135860887736 +lcm:8507343,62395589,0:530820677310027 +lcm:81126006,461820852819773,0:37465681276782021316638 +lcm:87891707090,40954510522233,0:327232894803129615339270 +lcm:-767589,-991593,0:253711959759 +lcm:86229155,43027930,0:742052409059830 +lcm:-431963821,48986055721,0:-21160203804962069941 +lcm:101557073166691,-74080192,0:-7523367479146517284672 +lcm:-34269048183,250074,0:-2856599318438514 +lcm:7650667716360,-959482143,0:-2446893018624669653160 +lcm:-176432105527291,712269105001105,0:-125667137897384071121162656555 +lcm:91973525400419,-52180215632622,0:-4799198387886300095948868618 +lcm:9054526,-21388581343089,0:-10192813993374435306 +lcm:19326311972,3180878,0:30737320286435708 +lcm:501569850634,39035351302,0:9789477660994928712734 +lcm:-3470290487760846,622612793613,0:-720215751744466904366758866 +lcm:827793089252612,77591849874263,0:64229997108241062748844324956 +lcm:19866668332,4414961,0:87710565885715052 +lcm:136274450771,8659380001,0:1180052253653656430771 +lcm:952660786088689,171372582380,0:163259939044179413638699820 +lcm:429415374,9140880954,0:654205802258564466 +lcm:-368107346,2945634,0:-542154757013682 +lcm:2147845929,79983807840463,0:171792896056056736025127 +lcm:77885771608,-51236668812562,0:-1995303742544970246669848 +lcm:62272695670,208399244,0:6488791349735036740 +lcm:61973019,-1405255816878779,0:-87087945439289091663801 +lcm:286206733986,212837117931767,0:60915416394244148267933262 +lcm:-131938894,1048695278656631,0:-138363695208977699906114 +lcm:27109492,306933238851468,0:2080201045794490233564 +lcm:-314477095129839,3837918787896,0:-402312517253922259873876248 +lcm:4116345,9101435151,0:12488215692214365 +lcm:63853435249810,902940229903,0:57655835504559765637068430 +lcm:80076033,14791385,0:1184435433375705 +lcm:-31038678,1454704764,0:-7525352125810332 +lcm:-31038678,1454704764,=1:-7525352125810332 +lcm:-31038678,1454704764,=2:-7525352125810332 +lcm:20638192722,-14267370499730,0:-147226371004802594482530 +lcm:8065790684,-1977228453431,0:-2278272977117641090972 +lcm:362687955673,99742877979696,0:36175540507397430642015408 +lcm:1235326072088,201675880263044,0:62283868250058987186578968 +lcm:568009735,49546482048450,0:5628576827704468332150 +lcm:849579042,-3197920541,0:-2716886269614901722 +lcm:1808291492597692,96814519920612,0:43767218183093114768373606876 +lcm:6275712123233717,739880208952795162,0:4643275197065752315694969352877154 +lcm:774075573665981,7523229210171,0:5823547966683781965601892751 +lcm:2944466357361,497012903828640,0:487812591499242877115539680 +lcm:282862415058866,-6240991940068,0:-882671026265275987882021444 +lcm:571225883598025,189932649930728,0:108494445780794463607647612200 +lcm:815309478,-371377784,0:-151393913606918376 +lcm:320172590239,777220834144,0:248844807655600692320416 +lcm:654332382,7919190746613,0:575753660527071413574 +lcm:-5094673003562,268414312780910,0:-683741576547274437277800710 +lcm:-77841790209187781,35267718271550,0:-2745302326850733800658699930550 +lcm:735762990564598234,-32739891496,0:-12044400238928708979996609032 +lcm:-5999905013129575,144027889596460,0:-172830731364054662969688260900 +lcm:6861193105404525,-4725324526382425,0:-1296854562448559876288579018925 +lcm:859748569384694164,98523184164,0:21176291659055938820647004724 +lcm:570460270963,-54720108308,0:-31215647812506387460604 +lcm:61750383079701,3452251304617,0:213177840547497299540279517 +lcm:-1738716695,8560399484936237,0:-14884109500328036282376715 +lcm:9953417006786660,90085339160,0:44832847342864414393180280 +lcm:188523146978,954842405502,0:90004947576640310936478 +lcm:198834734074395695,171072375577893,0:34015130305505499211880376370635 +lcm:-102893613303732727,155104650554,0:-2279896847959124297878354394 +lcm:90836124710855,-98332551310,0:-1786429578786341640294010 +lcm:10512242068892,84377075433,0:886992242016856266730236 +lcm:-726835478343584190,29339956106373,0:-7108440343718461118245907014290 +lcm:5033847480079150451,-69469662902517,0:-349699687543783241256712189585167 +lcm:3869558083241,-8770208065,0:-33936829509626159538665 +lcm:46079368203995132,23609959311256,0:271983002096177133105574201448 +lcm:979137194422864421,-1378816153373947,0:-1350050180039492392646639294639687 +lcm:-72618673468,-244198092166982349,0:1612121956052969066631874212 +lcm:529564016606,376298866055896536,0:99637169476421881457260938408 +lcm:554186920892,-629719688885314,0:-174491207704210180689290044 +lcm:3455963977845612750,271884481278417471,0:313207657811150223746536093433451750 +lcm:-41270780965441117,-4124462824121691009,0:170219801814430998805436931657817053 +lcm:47581683736,9394210662450,0:223496180345027475456600 +lcm:8196306676684,76732052476696223555,0:628919434030412315441895170091620 +lcm:2939970750639,-2013582768244,0:-5919874442628068251907916 +lcm:70476757656499,-100957934015971,0:-7115187849144405009597945529 +lcm:3674841030712174173,540185467629182772,0:661698573546054604863388890438315852 +lcm:82915322420038008,123799513890,0:1710812768272220630953988520 +lcm:466513077506,73565730651787738,0:2451383957524498065361030102 +lcm:-38890216282311653,91459939591112,0:-3556896831865504089438972828136 +lcm:-38890216282311653,91459939591112,39285:-3556896831865504089438972828136 +lcm:576595981539992,20909590051109791,0:12056385599118501431228849261672 +lcm:956905636477652,8381376662473,0:8020186569762664723411553396 +lcm:9187294026565993,54295427509,0:498828056823282593136101437 +lcm:8866081281165098,6545042142269515,0:58028875622012459166053127387470 +lcm:338772425501,-750860960783,0:-254370988898468150127283 +lcm:6750486296504,8609697533187,0:58119645214823136262078248 +lcm:736067207074328,329259058372493427315,0:242356795500164369960320250670469320 +lcm:680100030114145,52232423165123,0:35523272567534917195872964835 +lcm:22697310250913136791,365228836596285515,0:8289712216805950219366224267686882365 +lcm:30594845950075862222,37349482121506846253,0:1142701651822614557685156508694964954166 +lcm:866936756424,-1765396942933391,0:-1530487499507519421423353784 +lcm:6939438360479781,24559856763503,0:170431612152541518812930232843 +lcm:927595346004843560,7670228140092963222,0:3557433962772809951143296742471775160 +lcm:-357321286444971587,7925597841132985664,0:-2831984816439127983772762412958328768 +lcm:6673370692769029,520191499051311630305,0:3471430704396611186160057152801823845 +lcm:9013236794945,1008467412252240244,0:9089555586614859880726704766580 +lcm:406532185466775673747,9519149309169118189,0:3869840572441069484183117712436347484183 +lcm:548046408595014443,777065152533771,0:425867766090470284154159790254553 +lcm:23897406396584,-8555442893510156172118,0:-102226447864489365824170750635622456 +lcm:54729344028716311850,2026849525600172204,0:55464072490506137031056639711882908700 +lcm:-7936445752013,-98698488318151151,0:783315198342695407195996516963 +lcm:6309028281362257922,271678876766048827,0:1714029716965733695518439315219557494 +lcm:6357785774765671053291,56936125648067424,0:10969323930774361884705778197353487648 +lcm:11095109588014,9104811531028000846,0:50509440857484599522180551729922 +lcm:-921590308699737078,472826384755153630,0:-217876106943941345664446493248646570 +lcm:652120832633171211942,-3387083844442113181,0:-2208787936835953406166467995677302807502 +lcm:32731949302549,335896184427699,0:1570648125658156079680986393 +lcm:3635516318567409721998,16713986701316425,0:60763971400954533716595371769881217150 +lcm:6746198240933100303896,2007405485449,0:13542355354775500078274959306009304 +lcm:-19072614334803913032,-240759760944833349,0:1530639355946797274927793576109768056 +lcm:828472954262165857,127978158379025077,0:106026442953302260750986298136195989 +lcm:8306750095431507743,6378030328941226919,0:52980704043597587430846783712468533817 +lcm:7938532173109072,7646615157112938170608,0:3793931277507783816896749585208034736 +lcm:25274397567311,3125247753747112,0:78988754224550174717491855832 +lcm:0,-6378030328941226919,0:0 +lcm:-6378030328941226919,0,0:0 +lcm:400327281633151431,37147489147345586,0:14871153349853852722430493627433566 +lcm:28164658061513141691,818613450005821036296,0:7685322634656510878949613649488100605512 +lcm:476291935913056166817,170589720180888384,0:27083502690607291480376538585587184576 +lcm:84130837655605609,16051948347568699941145,0:1350463860485469013094700782617631882305 +lcm:438146043336536562159,-2206822496905640873917,0:-966910545365262749689560255553699552306803 +lcm:8120293725815373571,24028314574527126,0:195116972081450718759827878362986946 +lcm:-667658265953408,8440015504605457600699,0:-5635046116424757633428637247402232192 +lcm:53314441150262832895,283247085055963859,0:15101160047199676268547968068076341805 +lcm:6658153298145442,2140281300389057549,0:14250320999144418995877331910041658 +lcm:213046498706732967,784948480361985741,0:55743508468763934304784144916207849 +lcm:-3857522843819,419578526133778265155,0:-1618533749336956944635887834826945 +lcm:-4948941087660882967,-779517282262677550602,0:3857785106731510951136294197380142396134 +lcm:4277076043224464,448010594023993,0:1916175378810781677476700564752 +lcm:-644113523059324254840,-71225587742718143,0:45877364252933205602125580469623562120 +lcm:264902435468141506,-823887292259809475,0:-218249750270876020336340975899569350 +lcm:1538706915662950684,448326823774496344436,0:172460896054755625075686197059836448556 +lcm:2036808313025110180,30422160628736748027,0:61964109668796220999356441366572614860 +lcm:7385426850078311,9871854919284839,0:72907862380963907579111265026929 +lcm:804644713550364054117828,8379163811459445,0:2247416621621120599518832306788891161820 +lcm:981008037679996757191201,-641409668917881464,0:-629228040654107304092567432937180101798264 +lcm:64201713053871850,879119102660231895102,0:28220476184584758536715661672075339350 +lcm:1033957429367195,1113485105415049436,0:1151296197233604656037339121652020 +lcm:14455075580451942850,-1885962875546302716,0:-13630867953974143493153933318215890300 +lcm:2615475057635555327591,71606675442458157933637,0:187285473579953754910128144228132079173078467 +lcm:596676024530775,2621192750454214313695,0:312800573973981674572351390206292725 +lcm:71665682789483848832034,351563529541544408090967,0:8398346796158551916852810998534107080858545626 +lcm:5092055214749737510271,-1833800774226189505,0:-9337814795210574311088704576082129905855 +lcm:600508413963341945,5057063373752305154,0:3036809105884103889579068197287884530 +lcm:-92318043858914149,958444935645415778103,0:-88481761605267642819033271229511079347 +lcm:385447683586530283,1775981280157037775814,0:684547870529570889684189390051875975362 +lcm:80717517906672139,362327909576030289130356,0:29246209529290308450092391020660324351484 +lcm:31249856290116188,7875872084416640,0:61529967699339457577602450142080 +lcm:5339381130045070,-287550419156538713298378,0:-767670640990486609645612376307748948230 +lcm:-28993892995370333046,698005135756870427,0:-20237886216353643864566444205658230642 +lcm:9179674525723481348,81469928617693608886,0:373933714172176229761960288978914029164 +lcm:7522547789649675160016,285918417200326088447794,0:1075417478665223340089057247433582968006102352 +lcm:-901774653467788803,236000195734098992,0:-212818994726447447848669649751186576 +lcm:142671415131788790,-2583777714764598301032762,0:-61438537158574095028788610137898909056330 +lcm:951078283105727024828,1487627587101952300275691,0:1414850291441640178530450466337072693601856148 +lcm:19185476025869672486,2445736876347152429980675,0:4265693291522152053797221279874464505382550 +lcm:6741226163186521681303,2568160083399218078514720,0:17312547945462088421236893499979478635434280160 +lcm:3987919571578399660412212,9884144363611069680876,0:9854293188987727688997011704065958289363314428 +lcm:99431631881940059268,-291965406586754754564989,0:-29030596829995156232729757591886192217768052 +lcm:36727416735327035,-1612205593089728906670,0:-11842429336086311491916222123088564690 +lcm:19590774006340220367562,984968880458891391,0:19296302740348077288926838014277057458742 +lcm:70695613219926859099201753,62591913993270611799645,0:4424973742363186825608316839246937058962268777685 +lcm:77425442645246583405,-296832015660977965,0:-656638577252342429795743277063990595 +lcm:807971872592227526408,40230405885131399744453603,0:32505036378154987781247713889763216622213248024 +lcm:965370212546292322,92058451234918953535616,0:44435243317668098531171705039686887170176 +lcm:418561885926860582,239657399821326936,0:50155726622771131306218069956618376 +lcm:4657697584188823828175,78713797195009784682708,0:366625063037526091489561582727843402285697900 +lcm:-38091455008728662,5763777114003492300442812,0:-109775328309201979538317902240813878138772 +lcm:54943065861736600767,6268390929335695219433,0:344404615677603400985934681975925581105111 +lcm:-697639190379957186138,2936028900796584636,0:-341381470880647489965333380835887162628 +lcm:96018089280939789090187,29566309848085271814423786,0:2838900578701380961562729671686086004548591987982 +lcm:-1112368751522257152114,1995174854903534746993983,0:-246596684713071723298909011042483787097081118 +lcm:-84342841213955171500540,5699084396809137598518,0:-240338485172501289667138051435146885070099860 +lcm:225675029492277024520800,92998377812004114915728728,0:2623426456932243737035123197311725507407124192800 +lcm:7655269162163547244,594548791001649285,0:4551431025156545678791700910016320540 +lcm:17608380663675562604,264448308193844308642824889,0:4656506476542203967645749547080047894928850956 +lcm:223093179893694063251643,17908241494426478956477995,0:1331735513765267693007651331958962321896225698595 +lcm:-9501451313199296478183,164266650410143061944307590,0:-1560771581254303549338241248628058185171476308970 +lcm:4558730178677382262,3122005086984557462,0:7116189404010403994895797264339269522 +lcm:54440882483631228680923933,4478571958703194374379,0:34831058528320962440312711060757171496803301801 +lcm:36855929355558415329723,308635436762628905,0:11375045853945367585945011810669865443315 +lcm:28683868680975381560,42902583850929860163229,0:1230612081254607193977374775224312156657240 +lcm:24731088466679335541839144,81462858536522998396,0:503666290303833545129681622218515211800503256 +lcm:-72335534127835253275,-227166439208550011362,0:16432205716068881729381218555965397710550 +lcm:474777034176054735892,839001319154604024448982,0:199169278989010220914577285259796918419130972 +lcm:6299666296143449904,797331145004636509,0:5022920141051174455685525850770945136 +lcm:8540885149755672764459236,41765710483565552588310,0:178358068219039923285097732763708140948642565580 +lcm:385990739803366398,2963466700114736836981086,0:190645117326654704160162372267660375658038 +lcm:-37246197932269024,3005402223074948482,0:-55969903033365437079467727082210784 +lcm:-751622018429096822596,3003864133422104297,0:-2257770423049491832679123307914818295012 +lcm:-6108319432277782804,-82931541043539126216389,0:506572343704992558730984950135146447174756 +lcm:30921518942393713547539642,721143788088068568685,0:22298861303554770289882384831917605974237310770 +lcm:570903751254308471830202651,-564896588437884119958,0:-322501581409949262735089396741686909437933608658 +lcm:1054271475454361570597270062,16484741384321323400,0:8689696310866008240570033696584650327520025400 +lcm:6529831639822170310307759,85346429845722052312845786,0:557297817952459046702350223377401463955562766253574 +lcm:-754058902141939454006,69516695016006129145191,0:-52419682724305615903366455441899934040585146 +lcm:976193241125104191848393,33823563038032982713854,0:33018333628496693179640404511073605465668736622 +lcm:2920092456500658009757,8895875497550350532901302605,0:25976778934365816392930294156133718389132099516985 +lcm:9994369499844252132394601638,93334243646132127297454621,0:932816917987935116609350111907831170748502078677269198 +lcm:569015432462996733746,16322837154963292812416483,0:9287946242754509292015515862839485902412735318 +lcm:192500272569416024937360278,-235265435750733300361,0:-45288660508178593749288683427056889794244460358 +lcm:5267095375035104443898399000,-764192677627393558125306,0:-2012537858983468571142965526423649868280387392547000 +lcm:51025753118541843018,-1664207936338749988204,0:-42458731648769528582814028192013959879836 +lcm:-62402848465899883613105,12900108782353988220438351,0:-805003533538860189408921682314395887504788189855 +lcm:-8212641700259728565,297115088713153106682478,0:-2440099767342009818056382435156531921584070 +lcm:-5313586393962705049080,-76998532453336088964044527295,0:81827670879828485147952271763338965987967674927720 +lcm:463290189242313601142817059,969769350842083604500926,0:64183518010432075137644646337185534388781059156662 +lcm:1917277332460964412252,-708614825339303498360550,0:-226435190344805337091761225274903062722243100 +lcm:99562752968815530108,23844471852654970991199350,0:1187010630368881028219592827335680236477514900 +lcm:3003923448532254675001,7732856831499478812681071,0:23228909960284118604870886637597256802569606071 +lcm:5794073936773633607324540860,-76553654622431077040278132,0:-110889383753149576103727978239709891143940060899618380 +lcm:-644932980169883872037968349,42642515095105038480,0:-27501564342225351457715028479060110852667069520 +lcm:41892582203464757978762451494,68041907390182959305068217308,0:1425225599311887918623588695629495898803810573641200629076 +lcm:-5550794996398648089925,-61773015425098686639107,0:342889344934094297210650346841878123357696975 +lcm:26506218374693057900,-167675112099207386871,0:-4444433137302729109790367830963302830900 +lcm:145568384864275126584,40072954892382195328941863291,0:5833355320423028246614959434448834158605847827944 +lcm:3161170925861501561771687,413220145707787390821,0:1306259510591710846827739981054213899841485027 +lcm:723440854928237000349411,-71208223609049472714282072,0:-1907960672801919279694226377330300776949407891096 +lcm:94994080481292730137,4307839512004666207932600136,0:409219253303864061854413637026462925940577498632 +lcm:7821178378958515500742,3087104738440174209004586,0:12072398416934336857114452721997626257582201406 +lcm:869891649236864909625695,991848579874131467931448097,0:862800796939950559315938082847205513561495590052415 +lcm:17628160996789341122894,299337591195948255548811,0:5276771249993287502058785568793774940966579034 +lcm:99527056994641754235498057471,655773087035017085668857,0:21755721802962104371752823247713242761829805420293549 +lcm:596721281791001887739,-328175786669349585798669238390,0:-195829476074104675040288189805440291150559409100210 +lcm:266802917073126657350936,148259550527207353925931727,0:39556080564609535241696861668682911763097415546472 +lcm:297095531532857951877,8071469565512676957784213778,0:2397997540817274789320989692996853463867804361306 +lcm:-64574484904487858142015156737,351049851111701482889769,0:-22668863311335277552737854676715612712147868228723753 +lcm:9213606993296693767546,-974475310790221342435,0:-8978432538291752468015873684497297955614510 +lcm:-6506246525097752180174,-95653949321972166356216836249,0:88906882198279699370047684476316613423860643189618 +lcm:7211807452760603826715508,25981532388511222064867790,0:93686904456803121715837451769742014367676981343660 +lcm:244358078258267292267766114,6788410077941126965241803849,0:1658802841074748272013529977344553715539817794996972786 +lcm:-84498071017578145227329893,51359077717175899950414794158,0:-4339742996343244440353286358071234877760977371555165094 +lcm:315675121566194900458712010,607326754590110945679173086,0:95858973542817944770878937652762380762977850708481430 +lcm:3336777364604897112789890,24326442512123908471776,0:40585961367908674095931490287547594986841572320 +lcm:-631164366791648249399815693437,224085205047080377284686,0:-141434596550917146771849565583627819691166316250805782 +lcm:-9374071452933990971885163627,-8124264246742383054580586,0:76157433551480046450059234199385450235104896467545422 +lcm:-8986611810629266612086889,39090932189616079255587,0:-351295032903711635666432166463380265071682698843 +lcm:131042125952122412011234961669,-603299752062616670818260436,0:-79057682096673636704088945577099341952975178863719227684 +lcm:-5931135084197112120929525527383,817854717051260202081870677650,0:-4850806806078831488870903900854502497422338114185819841089950 +lcm:37076034350171687718404493,6575825691817817445639700141386,0:81268513076859634022073542658756708736205992975479215766 +lcm:6586877468189252639017707825771,813151310907233772623665199797,0:5356128048043411806613358165516537614499231407192441180568487 +lcm:2933337084774328653741904208050,516673656644156545121601676651,0:1515577997760262602679690085554979355436376363966312331240550 +lcm:-9902991686684787357658450,173313993122814232472956,0:-858163516540686876248980610636336072294554939100 +lcm:9274522469490915283112908394363,44864081129175577116760112,0:416092928505602244504563614588785724831758965222564048656 +lcm:9608655195311416270604257657,65867528105907714734959487,0:632898366137150893335309426569727530606624485604541959 +lcm:853239911600142024011098491,17829323361272785163230303,0:15212690288662738268179355293062413175232317048772773 +lcm:23972081642808055559504902,-4501717580058722285684735,0:-107915541362031999704526719592126415237678659070970 +lcm:5314236376598680151908105,3994830160691915764873,0:21229471758282529614266075257916580301482995665 +lcm:4935319583093232012062136782,881389216056886912824752493825,0:4349937458332745712903267792817007035077166975812760371150 +lcm:580231659494763900889556,96767644291944525456085901,0:56147650832913989511127904567807102400387849749956 +lcm:303622305001319462939309066150,-27984889540977885375442171280684,0:-4248418333819511268163760331043084702315340960497818786623300 +lcm:8908131273613694428163643,418798812110676949375564324,0:3730714795515386967446577233797553865021052144672332 +lcm:604960317372762640669451812,820482420778387317631260055,0:496359305672865772215202726749222319854411791662969660 +lcm:3125355862613621420823337,52123353846012574000878521623,0:162904029521719649924422263486125418351967284017515951 +lcm:35876668588605457895900,-237986271303986771473105323,0:-8538154584211078670353490608427234416302669875700 +lcm:-43001262189486935668928474222321,75601013836677651900921245468148,0:-3250939017782005364312622194873995196088464819832369459876131508 +lcm:50360054222226284955381499,-7538629547593198554710875138,0:-379645792778070687264466482409787805710036592944271862 +lcm:16303655607623383537122,23252538460647040924816117157,0:379101379065406527294500251303186510479764610602154 +lcm:29876051059586965106021953,26235768232838079362376,0:783821151311760139992194729309972935608098240328 +lcm:29623076251397963944271763623335,47441755805615786352682527,0:127760977248178043763492761350640873496807885066769451595 +lcm:9892811422980328964557595259,603482574014084208448431822759,0:1990046433925368031040084916604965307795191807343715566527 +lcm:-2549498483308845928405350,2555383871703609992631017913548,0:-3257473652590120103062390285427854673645669471900340900 +lcm:-935906971037827073384146870,879641356065373793312781,0:-823262477154750723009760282203349336801144752145470 +lcm:19597038710644290533555897021,2985160892106475439715913026,0:58500313560112043537702497574448903543850923995448495546 +lcm:-5608937456930306694772980,836399586633606428927522624674,0:-180435114247317699327868488365007039436425700237558020 +lcm:7718522069758342120350478031,7389561033066750535580836572,0:57036489919551968141273365317951375124662579683087349732 +lcm:718875898101761373218778459,686314096776480574628984874102515,0:493374662700091643313347796063672168629137876643552239724385 +lcm:1300200863593962819188902,525922101427424561614551608409976,0:341902185229544560458110713971475236149786740307102643176 +lcm:539220635752920237029329058,29487916769600117002583914582181,0:15900493227532973069876042371837383552914044277544832315498 +lcm:5654437789656914341120143121414,6765853316633901505298664574837,0:5465299524692900146239549597899398996727386837109100340037074 +lcm:103114174998937498500059583,920095995082794389728025430890882,0:94874939452788796816569177101730218978113456477925771422206 +lcm:29882936700790118228421849,-1860889369990333700884198092,0:-18536279750198114735901679591403044437012106352304036 +lcm:8909623809613954310018698,-462806578041198407432067106139,0:-4123432506961820007043026316146032423296431299840587022 +lcm:7230230288816368650543810,22162946284655819337870476,0:80121602758364354591303319881368491740552371776780 +lcm:734442358589456361847988629,1647427465162259118128391711,0:1209940513118819039348215846845414818873067603985854219 +lcm:47616626651192848094181030316,2182277257935167463613810412,0:25978170360121936072057209849558211193870620332212112548 +lcm:294703827229370598691617,63046555168872062038888853,0:18580061101894254060770213008323255399294285845301 +lcm:-533653415261740333749397,-51216937243134223196656339350075,0:27332093479044801759907744737948616465079304814903154775 +lcm:784368839220787531616946253680351,39613735771181195550018240677,0:31071779944040382951244796866071327091341523727977793343837627 +lcm:5770744507580580048400572,231937913382367374762373686161,0:1338454439750996843543440906327507234975603867940884092 +lcm:388816489715059942531589642,82051838197217717225950877,0:31903107702510265086302832415272579698669593814016034 +lcm:60241729629297025142644618709,85181464884435369517497693388632,0:5131478776995614297555781224894400552133266197008401795116088 +lcm:1560786485638020475934392460005620,8850527081981124295638445,0:2762756612065888665370691207806362094705896562533237612180 +lcm:8296622334734688413856037840,-83875508267086319614619277276,0:-173970853806483090137656801493133601685389930382427030960 +lcm:-45794179084517723375284971259238,-49063790774577780701852303,0:2246836021296323435311993617164824492625064891225000325114 +lcm:1752071933321291709931075226933,57773126045256149501100162,0:101222672644126613791673432521136796654007466067313063146 +lcm:730668796977177255106481634556,938608337106204028806933670639254,0:342905912253069470166105593930151155858159563381855355668230612 +lcm:921730456287198291208119641693911,5458708493078803375257300,0:5031457870064330030425732359718797657583243087557468300300 +lcm:213400535376420556914942871216081,4183995847570912793889135547893162,0:892866953884353287726737673843872033409506009951957939872404338122 +lcm:32806047880829491896013320805772,753489056993475245589087354,0:12359499040704505410450582731649402374098432708182687703644 +lcm:15218771998961411533589410518,23457061020403160442042221,0:356987663435240813815179640133949762707316007457480478 +lcm:9046617676720978441798060,7479379807328977629621989162,0:4833077826849448212160770633271094897459555793758980 +lcm:2219170169044655639393672927,-5391273013704097527490654785062,0:-11964152245187612169646728984856115656974060298999913416474 +lcm:277590531551034474232270111103,579362077865358674190909581933,0:14620493377741521712796730933686046346752536860927744682009 +lcm:51422590325724235826789079575,2121952875387495603452158,0:109116313401543756339172704192689685091698905367472850 +lcm:511034032165016743768820348,458982236103828060996895790272,0:58638885702063744673892798532850716778223793123163513664 +lcm:4440454508740215531301617636697,3258309525326637800581711028116821,0:14468375222607860310511042523813260258037478238688128668452580237 +lcm:6330009746329830092300048092,-6167250670699283492360751201828007,0:-39038756853585645999814749830700965509494204090781844412512644 +lcm:-9374602262965156933926707655416,-30595740075402425097079774283,0:286822894147961315557763521486314502763707907853113422466728 +lcm:83645893910576549628700447097824,49931389572768584324081547829643,0:4176555715011469153471691311085610269167538819874387285307996832 +lcm:8030747712125824227213267818544,63329417394086865663449328880556,0:127145643461956118439868630218929081813205737418762248914457616 +lcm:378845361147099357535431194,38180105668041356349238612217040,0:7232177960221771411730351326884973759795619786776357172880 +lcm:25958762365949818177158173188075174,40582859445868015162861781,0:1053480804486029724349686454924029433193919106275980799524894 +lcm:95871031013239291309686124,64936572493882710890460913285902999,0:6225536155454490886042480192744349881519233810545112600285876 +lcm:455128054133718561191432952712,39088645380524987234419335395029,0:17790339110761304357582067458548970370146644724724054396868648 +lcm:1307047523348091088814812136,44132853285705545682051355847561,0:57683736585366097743814172916945483114493512756215268800296 +lcm:1418285824252402530993393665755,636810955908181043849421782278,0:903179951493194917152704617449910466299855863874287914489890 +lcm:3071172872783184341780369192882346,-58125204065109316437571977973,0:-178512549949750604044117019967590439630943828607057692292564658 +lcm:56958148205198214736866933854,4922289245511311172745764679844,0:140182240177343281524353792167921226808367574258629117519388 +lcm:4836813580368584281452577588,-5400032605107989894617874622172581,0:-26118951038819470026364723997465834517846139303988539028714628 +lcm:493001845960066187429806680791,4028800209124423703294502145421185,0:1986205940102641576976415454897329744147895770653902923543957335 +lcm:71197215106470682909632132625,70077573297929109151274279,0:4989328060232124924682056253101608707528304143079252375 +lcm:486722080146274783096432055886,505595939085965376271620470551,0:246084707185430303071142220010478564391091338964955649213186 +lcm:-194536785271632924316130857883181,8276525052027013498990299177664024,0:-1610088576841469642302988316918048088947156051499250583217058380344 +lcm:241211965193448971857220311,2710726738427327769580581757190,0:653859723678484041534242084550730982398579984949338286090 +lcm:667013805494915469984846976421,118549400818390788595763048,0:79074086979016886300666397440542951393124558234159091208 +lcm:507926799850267721181735296662204,67253859677995358015731931706714,0:17080018861911569471437509381376023258751803251807601040628418828 +lcm:448088677681619431331494894631309,779948091351174817338856782981850,0:349485908913850840791957607115202038571061594442475706481388741650 +lcm:187408370748924381155985806145,495794563709904959946586644094587256,0:92916051411047078205447640432962006059741039970472932758203488120 +lcm:868633158815673181555237006,836615025635832190680248872,0:363355776215354156722969079237153819583812159512078616 +lcm:945386362083356835627622353491,8230893874122803805176630038821,0:7781374816351144698349349350957993282560652485452042714874111 +lcm:5596932048341890824814087121,-2850793263280920843358756089,0:-15955696178454147555303366966824500182482049050635229769 +lcm:92079468846004092188293849,65000203344267255501708018874742834,0:5985184198822387758738668838849529371861013959766705099028066 +lcm:284485059147524530505559245415623974,-52174853366891975161102679787418,0:-7421483123046841473739983029315899581631043634755295287353072179566 +lcm:225019940499042054289943285,88057001889802818516938839002453179,0:19814581325767463952213083138864703402608880611447063777953015 +lcm:267625311635136684363577960127905,2364801628264216400078340665206601706,0:632880772719489569595591177205490383145217286350462293583250151205930 +lcm:-43414374537943144129863577734786164,-7033210862612719519352562332,0:76335612648449696783117174288123936538806867445493650875293612 +lcm:32883132771659855270849300682688,359989040176539024964573548207106,0:5918783702233763351390712750327251738350635067527850802106390464 +lcm:8225754994306229461538669946760,79816684330375527507314556065816,0:82069061219943782694121246737779709549970645203965267471994520 +lcm:7425838080456254658426507595,-1772612320788255147892065709861,0:-13163132073595363322916797538873046375619972048032782894295 +lcm:1660461221569443640519526747903779,1120888096894032723781619067526671,0:1861191218611314482654724970474950053651690424934372619599424189709 +lcm:-11718764104457037189982579964973,581785925357694644406822708535571,0:-973973145508581880509230586205500094467304746237860191614936369 +lcm:6811677000322905212875962023,8457366124986245338105030092893823455,0:57608846316878860294885890656152159404437095902874498977846649465 +lcm:234277964462994083732538315234,60350281492645017737168270090,0:7069370551432789506447807101173043521312584531845436775530 +lcm:4183588612759663468880479337,-629574038019737820951243554610835051,0:-2633878776348494576596482359410905898287329191507888206720841187 +lcm:2509727174403533842481294816277585179,366325095871570289922697736369296,0:919376047774859744204436335735246570640422606903982773682501840263984 +lcm:9652053493694317708921453500950,-91539642994112368354952933916454,0:-441772765486426429307043005631104317228468588998611266554815650 +lcm:35148593969489612322148628595,-82585065708416968121031576511657,0:-2902748942528768024032450841226352229253814757005116581031915 +lcm:2800741702103544119527140802733199,46761480207188283686223358035,0:43655609222787234193883724749974391389581728627052774652634655 +lcm:441336276433669766301405280032,2656936104993980830437872804,0:293150571825055340462835975394089506580252706417004262432 +lcm:19746122571650880858695931178058857,104545112367422664420669962306,0:2064360603074142331524120459909153582079341868724637548439444242 +lcm:74432478600289091913597803372,1021411507303737809729230605483660893,0:76026190159474490029899083115858462446496838080724392481739931196 +lcm:37218119790882940825047165121,-9786692593914842780007874460688,0:-364242297316869514078703840625474873421751340567491159263248 +lcm:68400175404962139133336849460667620753,8111497426974768586772111911266,0:42679065138613326270921172084657529459737080671434543323843052007946 +lcm:-36411507888779255237781266679960702586,288273015425729999064058691683,0:-10496455175296151796260705657513107808386313037221881095512634792238 +lcm:-93804297004149089553676142929158,72597578405766612297542242292431,0:-6809964806556531666828055851398144826196098989021186645152603098 +lcm:-82026709713179475197473688526642531,5827788603588390535677091203646382966,0:-478034324056320484117325267961249121989480834362662252362566162209526946 +lcm:545760067487517393173385480028,42151112506666653978439280505,0:23004394006312331510547051427125022225825594077610367254140 +lcm:-697412421088675986809554647004214,6926944054264140642234974161460,0:-2415468411815081649186019052688434218369772793280624742868196220 +lcm:57812799959867792819685059219,779735108345604313576941265627654,0:45078669840470262146069880262711457187904686148856378194042226 +lcm:1472311567166258003445083977221663144,83378953824849274359711951741465,0:13639977574949655229291079317010538142583886970067850684854934118440 +lcm:570337459673916278308389115966167469,6333660822968779197930730584647562275,0:76857957961877010509843395509780188770354864577206186663499194154396425 +lcm:-388785693105293562593219349398,820248784628021659491960244881371621,0:-318900992250380064850834487637248605290643186101012034699480634158 +lcm:11679788667362042415563834445557578,-5819547639993570526822921884507,0:-67971086574770424077123666817486620774164160205639229582134644046 +lcm:-3982959591737356792197606403519482273,-333248358612381656382679653253,0:1327314746365915910353403610458733118195746910957791963061720284069 +lcm:17221610285774362123428353448280602,11458184790118982447972303969280231679,0:28189770433973774114920757867056877758202824175213356039046635823084394 +lcm:772738633297996807166456840381926971,785759122171938805714543081571173360415,0:607186430168577693296664258953260658244617930008242877365346151059192252965 +lcm:125784145401376536208808801528812039333,452055550313139515567680226389953055,0:56861421070087227190049678638474498681709153815504817562127254516683512315 +lcm:32903571905950760393177782893378791,6631740924411766007832465757451477,0:218207964368018909275497254276866261100277667630506488424913763424307 +lcm:8742677352155721160009371273251,25083360125803108633092433384973055,0:219295724487824718593455764107115931859507036987734897375677251805 +lcm:36273669132247708836176424212020,533102320793846929600697481505030771,0:19337577198109381261236591896304826004083902938845516133439528067420 +lcm:11965144674509690079804137520044857,9349045655011350274674885782216185552,0:111862683830807014974569906953845003630437520055543213513177982475306064 +lcm:3321305668226664033356712162893,-403949753985171409898849824686029161,0:-1341640607589716272160331793818630136041627867704613639659980122773 +lcm:7395363159337411027760652209127419265,44729331460301249556947662501414682,0:330789650023303701714182934884591650253917627482713804287730858240648730 +lcm:871058047335719958990871843414,28094200616974302760918376942978068402,0:12235839765439807545562104355459585845290919144959079858231362602214 +lcm:7704699734056436938779166257084,546898541513497897846722209401,0:4213689047354900490455012376163453543698919981174872047646684 +lcm:950290435067652970604023856243611,4001208123591666075058892234775,0:3802309808564151732408385790073534886035212910698424588605772525 +lcm:3119293215232541154035748455321571,808684220462127868482572087900610,0:840841067384377328832287433031234586779556451356106729978612352770 +lcm:432360858532087298548744564083197299,240846574096518547683557847064319535,0:104132631550882737065113576806715978014672912813529852776264204584935965 +lcm:-310788798729818682147559678302,-2172955391250831365155305151397888,0:337665097870164518242716524072816191896004699076265879441113088 +lcm:649283478652713472152371045373000641269,9179675498867400603641823155076,0:5960211640807708792849652271953975864417053692073644908051640832431444 +lcm:79980532708199255123596245351024866045,35273005660545430889304120342364,0:2821153782949751307464444766122322349363016295719088889624882638630380 +lcm:-83351007958684418946822288153831314277,-51634644710916030743119182132599855,0:100088364703334986444002041507106189114327438112522438638963055385805345 +lcm:4992915740405389949821656927954249501,4523923119542484578579105473053048,0:1075598426283215515120154478613079151358480623324833686397654095263288 +lcm:-801991401381703662108108758716412,1462655905419442096496214673085035312112,0:-293259364831640743777507251364478142142085309047027174124191748729195536 +lcm:679369055865583831572651301119431385801,6364653911974833953564963906049365,0:4323948919089537646576384302944771028193868888345656961053886629066066365 +lcm:32178714589413433072024739357148883,2182815001928827996341206621079833349525,0:3696851628871457289339239307548138692732309404324005056784243872842227925 +lcm:604754886257955637472038235002006997,75686581968330008368600832791867,0:4161075479046440938277498574104870338592618123335252527305070790309 +lcm:287068066584060661996114628597630371136,52011890293701406927883275870768865,0:14930952785995133944874986127466642449246463907028312778992290363623480640 +lcm:3979837024286745384581666788748758,7350136706945206821986896298939283,0:29252346199869589826241656345690372038181000414430037048634183660514 +lcm:7385865195603313817759905903511277,1520983986703891701713359953638,0:11233782690466247146504034010039435409908987896556224062130175726 +lcm:764457193068206149728854992613,27858021258550102776458498820919,0:21296264735745627187463264202183322605488975579352986954871347 +lcm:-4155789385717252736363125208379519,513716864065732253356348104577569642,0:-711633030316107622405824053747853916334740454203908038895636729654066 +lcm:97365354260983249124725672833811771,5020029690975786355406829440294084209626,0:488776969262511703376009046688465573304498084561257966650740834323390307646 +lcm:83139160308299020652846789174256754,3913486804605023733190361150860684,0:162682003406234977077539172530366012958142362329068266990181550029868 +lcm:-17691166446369130975076403772363811082668,94600134419678935394632555907142,0:-836793361933716751903610096654309723151466648559815713270120684946807428 +lcm:634823647473707443708903538054380,3956996255499668253479385484122050809317,0:2511994795956101788922355113644864677876582447280810271598141786556658460 +lcm:-3637804742599340390876015169076139565692,783241759542604459838225899706055858717,0:-2849280587465938677344529171806295752584262014073034029610817921718004492337164 +lcm:585812248650822285457691267576462,21534520461947113931625020852108318,0:6307592927715191546338604981717905869057205471110964228553485605458 +lcm:11281432653044672416448534028211038025,711109480140515578563170257201359462,0:8022333709146834455095073412796362253303159149746025747385289864175542550 +lcm:676293649029453415159585825583394,97280549393475973449516311017466882903,0:65790217728903847286239146189723168106268785797184624412977724659312782 +lcm:-60552656313655809329731693060696763524,493007935144068742422888317617165,0:-29852940056683907903878516926766558721475796609356660329816267168289460 +lcm:499127054152037037035927375386500,1203956412395744650060889503126393,0:600927217446543074982206780295985557213897685478460386666725894500 +lcm:50094686288665713475507184834256049095574,-832478827433992238527275985275884802100,0:-20851382851131060794973993277969178760786122158514529534407995697925158487952700 +lcm:3587136855297236649460183411772356035310,-712398604370738955166219235841134498742,0:-1277735644700296381952103446442115125860633433942353227167692631711417651290010 +lcm:-8101551106022390770336067301182994,9185799272249263720169676176910186035467,0:-74419222253790694721684461955969753328255728462706287902254787547941248198 +lcm:68680574795029722620883183609775450677,-84158462638889794851250260034014551972363,0:-5780051587904985041122626676950144438458787116758152359160332249952887573639751 +lcm:155258118178686765062886673806448566,-6850017870177195667059084688029341396610,0:-177253480669014543271712665559172404205382093546240559566299352291761960210 +lcm:285166743996114296479394289968524943,559627723033455856754700399288311,0:159587215627409862324848662934458300983070878875254327058667651841273 +lcm:97635198013817214038209538637709608537616,-43337611052093405089732573050042882425535,0:-4231276236516932968241697386864918819022381398914657632453889680479868318366424560 +lcm:2025635628106428290541842218677337,8363403252785996217814021695187802,0:16941207601064506909583426911328603088283663942724754575178256243274 +lcm:39403341320445818916772945982544618,-3081545887974055895915003777735743,0:-121423204418458019221260007112987567988534380636151689137057510881174 +lcm:66538675039876745133366881210395320367369,385523580015310377616062750074359,0:25652228210848657783496179630561675959121693223651695460689142031947191471 +lcm:568797587304724025372575349953868,-809993079501337508688725757864677957,0:-460722109353884289924314758764698126555664169725436270804746626487676 +lcm:87438670031005707662235517162074411507878,762858503307630620547057859718065131261504,0:33351666475531395026558166505559631395861641079699397271443823762152715254487064256 +lcm:-135539991676075663249711183869449098,3187117064807540583340853903135708355720,0:-215990910217346375421192415314259011732701914127161619020473509115908570280 +lcm:3623316226168035106420698863103708,281527696822113339094642926844583498510,0:510031936005639216824268963288080554001943557921657188124458629796737540 +lcm:462743256592937700094228107961335,-6269566498572477078237555404177435,0:-580239923795081947084080072036122971178457338970051983328091895145 +lcm:-685484600842741055621576203380446857767,871551172534175305655069705808532,0:-597434907618612100896516584776549623778036010575252420692205107539068044 +lcm:220964518681325411201409247135357488007,-5641829172229111635876189209726787450,0:-1246644067523866218886679493927269969586873926750864717926006590010013112150 +lcm:302531333113895329527974519952510,186535245939488501803212618851457571589,0:56432756626801787093558631197271214562205468328076903171812192205238390 +lcm:817537141270922830542026664184986,7821981713799768623509532856543951,0:2131586856457765504425364967419253491712890096440257591636701106562 +lcm:8468979244486855292413811013010058,-209488808243349961649691393540068,0:-887078184482608830617084669743435658018755140226162895602555001972 +lcm:879852422051274089521663230058530,49497155404087571445757965616479604,0:21775096033467380006952525371180650761765159390311330589646735611060 +lcm:21764922287301916637920770938954126,164044760066720848860497915166650797335,0:3570421454491268052799273529790558940088345201564664677181891708888054210 +lcm:59469732179854673335933541543666124,33859516881008254191737434099260638598,0:47943247634591169393256397833360901700530080487187711490425670722367956 +lcm:5622782096444522942366700649751601671560,1818924766888381565955786591467033096941030,0:1022741761403951928879352842728218349531334767337439634606427252402319167074810680 +lcm:-83658234598433632746857009684831849359505,-29016349811234824466750396183186748,0:2427456599698498400779164525993522755993904434491695109250156524973603839740 +lcm:7054089120269602821498711515003074,4095832337673576318592596805192095781914,0:14446183165815794387548075169511726311756130919745539387698300521071801818 +lcm:990394898068553803695514279851854605418847,-7739084020331097221051527297005947155388,0:-7664749329459790605184280312841813382942964148487855083039273635724968309932797636 +lcm:54075935489906064661012070011939942732,7918292813066039667153314788962651008581,0:428189091349545982631162674290883455991732907828213951097897291399359180583292 +lcm:8772115771437424285869834799732506658796,-932849018789404004804426567212331569,0:-8183059590092457014103801212671744691867340048481623621821910552497102330924 +lcm:-474373401937043543973615567508636867124,-23736477393422078122335330115520892673,0:11259953531119359125561737495585820068714950649943932579707916447562566182452 +lcm:8436352086792195283692976718955932574,-24226347745891111460405966918193715809620,0:-102190999680700937261627650760472234672389538208298360366751473305837270280940 +lcm:814519302031186083731939523439915121,55324835095437197264275880684820442585,0:3466395851301998018482796204627115585152729004909209666935241139850294445 +lcm:-237764758709584162016066869681905512952347,27730963225107998869867496093972168,0:-6593445780002155177144945210712636481509108047897422208741783636396128278296 +lcm:7518474854158787395750001309747813,8381114315785290417935232114225100106214,0:63013197233061936586019793610222181046567760778431006705881553819854209982 +lcm:57926271609377407522025180011097851547,-460438760475654775684236043340437433561,0:-26671500698797845620038488129522785806400814035581845817517898599701653568867 +lcm:6638349918167655693810387712273716693403,55308325418124425819340246954531134649556,0:367156017513396353523080763860964198057435071526450849007117311720362229502079068 +lcm:-792096039638367514268257857215475476214,17985352918594429617981644232595132,0:-7123063409158501091874013108015475150372207113988264273740643324379095124 +lcm:17523605051927467343416676052611136060682,32818776862511079287568864844380549,0:575103284025979425337961066906823946761256491065774387656701755680364474418 +lcm:435598204136143930685119666237820390,902306362378699323196514142749053448065695,0:78608606206555625579369041525511439839013315758266695141072573521539666104210 +lcm:7246625600474134146152993995542881524104,84045078681310625106949990828070364497,0:609043218765848459070950953243439359310276390319003636791153856018486171335688 +lcm:-787638361574460696958641849383712843152717,-98972482600264920015196417920239935812005,0:77954524036229481100840641198098180090516196148063542559493953965332234357616967585 +lcm:82374608290966933640517911377351376793038534,3375365592517566879211534105358267232412929,0:278044418522442081159379773928407521481969102832422171826378968402371349113290496806086 +lcm:-65869507968457359071511077346860349916,233541308077986424091233056554170108328607,0:-15383251053406881762895333316227673851604711244588922960984017463587249932847012 +lcm:434965647854018848199731601803786298508849,6881642201690537465635377223216241,0:2993277958557881269328249998872265799210459572563672559065439071522179016609 +lcm:719612999193225374224745692059996056358,-315519530953816852193901984099603790510,0:-113525977986857927473880514812648272923195988059593175472980415910454192781290 +lcm:3371856558784507755414140667220962994794,-46940188151078159734582108552804551252391781,0:-158275581287791729316741990876515371668219778704190560942981767461139678285151388114 +lcm:4803433840417804894873156694592939602852,-72456645795090954873268375616538340122311,0:-348040704375306339795449754303228838077133852627838127804760032434988381444430972 +lcm:48568835567133010333265540506612310476167,-10706367926604784868082114989212135746648832,0:-519995823348494578419271225922535589824979430677892239954987805560794580396454386944 +lcm:-640514959144433868933444881224466486263623,495227035072426375802319189512972514543836,0:-317200324136634298803490410310491121240672331811889843420769547754733113081885677828 +lcm:-6488859550432975345382980598094012298,1739553070312394609661279054142037504040,0:-5643857776890793418849823122431638031104808487025959819767412990038492341960 +lcm:62439762329215278757554454849955204768025718,79602289985731119990152260854511851,0:4970348067570324615570705607275557501940237030878572771873031709232361903784018 +lcm:6054057220822234921996955072468282902047103,-41461621564455176604944655360416823,0:-251011029419288750464457350960394818104993744337372045669164809905502059613769 +lcm:41593335543156355768394832800525873230,751910447000975730197547607815241920,0:284313304731966064820099773565043464563065151891136193714105004651834560 +lcm:994454253731718339598418586069934146007,674502407982587721309172287657440910774,0:670761788770571291425639315014529979293655007270270606543282922218043975379418 +lcm:467599304203676521904495847137440151064429,1065364075426775111107441639016359411726,0:498163500393153194363286906417357715847233221784448787935167388300077631164094454 +lcm:-50006834540638623993722097585899096403763,-5313099491095445109561808031972399857647,0:265691287149161199757555723574229252417144350517780818574650795718178070835125661 +lcm:80633786527554906657368596063180401716797,60423064130048311342811193512905633441,0:4872140454403075663557443919045087358815687394738194780627830508431609174608477 +lcm:7515721962363288712694440724080300383839,847957688242291310060264069657345589412622,0:6373014220677391433202574116816230429840218559515683152967957040454035241151415858 +lcm:27726212382161724111674518621229053817654,844465139764626291093420179330707907,0:23413819814445912412285655292812080594927908481755534067419056195692713990178 +lcm:-9817131728229141224738800156068771165515,5514447437310670168515402768125807553,0:-7733722414353494049116967432808422342245494692973084146482292477938628590685 +lcm:1101490427405231724327190816394483390794764,-1715150116840413365727028822839059671039358,0:-944610717631340024199197825772309008665579808517055858746594565467440593828772160756 +lcm:8714614705512806124985108394035361802445153,2277516152797095323407597912040972562623326,0:19847675757208518019561453963926275072330819370134031638574421823784137713762913438878 +lcm:-40241069975197162607015133362864260639182295,92350494843755720369837991386076354459722485,0:-743256545050331739906343199965798133902862257044301031935484830446583922737000605080615 +lcm:94926798565178929705057494111757110129555,654944641739167114202854904453615515658738188,0:62171798077717196972382133382107571708777354355494810646721424261049356268684505946340 +lcm:265280847975099333384365084677641815670787,79159871617113409657206914064640126799879245,0:20999597868187843053561037716605216806384147652131248848290439305459650098340274115815 +lcm:116347226264838928071222153238640922289035,68573180747149861177662470447052670907671443,0:2659433125362780479271819825899011059848120776197137181515334033569979255463087175835 +lcm:1040609825768545533315151293676302487896884,-81323728160947963681253577857302080515,0:-84626270592412620351087782103887368619510384932135633101731317980537259985615260 +lcm:995902591817252306534602024050315471330353754,5332558356879676808399004303967153306,0:2655354344316609212808731137647072862609841217315610320176187816399151656665305362 +lcm:2001969035383918099033090062929650143669765948,4190101466247488888803682714062857957220,0:2097113347636056547892257576607870417625666910651072024691458074358445968441699186140 +lcm:520711239532941932960582838954921846930386522,-3853096594619017503346777573808512971,0:-2006350703824226084150485654917370322708059670415383459171549901585565143080576862 +lcm:60199373689261241651972446393273631317362,4966864098864732001544113870901038040,0:149501053975666897103050547412658552280636970592772990519302688978409237225240 +lcm:945149245494027792287917914515672725163081263,8902933189066222709145663761457459365794,0:8414600586329679076832097202813182563472890369046719691038445973643576962794864517822 +lcm:42113632082774519107063284261972952560637120,550965713086089226514793739995356299364345,0:4640633466226213589957981239329763407434377391979443407814888806055710449184842297280 +lcm:699130208513509445029837360613055447835,1388996167624703080432361535173321299212301763,0:971089180295924181746449876683106046223557368848629195863225292564207370057125033105 +lcm:2708864861499120155181972404884433662661130826,-9669434874243213781569557549324652869447,0:-26193192361391605615558952560977409140576479476697591006776382263831361618654765273222 +lcm:-2663320619224926510783240759799877830,-9288856838720796348912703146202293649985994,0:12369601973796782329028816697760192304592616771255092738637656832851511205556510 +lcm:129339208558322679510730678747389994722,12274162664070343010820636150243461714,0:793765242343485804331099446227740401740373258846764856738702670720734536754 +lcm:7927826382521640149002540477963715500150746,169024688202278131082480706237325364215068990,0:223333063737919130606048178474544752216924447740470128636366880733694566431051631661090 +lcm:136906526225769628858637915191370345692692,539213183682016621647404279498623014328141,0:73821803873042744699575963663268898393281778327505656899589792517391459419633645572 +lcm:30681142365936990868501835461428152495,-5027491490146180677917496407674117704,0:-154249182152711677657936575800296045756593757870287279358854312185891271480 +lcm:-971981137022757867271162004648718096950546,4334305792750860480761829171455584581712,0:-2106431736321153641881651019375387709927826224608513058301342860436792581080007376 +lcm:578802014801938809246604894083179003839,4755521418153118560811649969223227339815203,0:2752505378260798366799002210776469662264057939931455802132200174149940527887564317 +lcm:-85637729865865539531457719920611651870241486,974400175977421869121902925057819107693817,0:-83445419051606298238772725013236132640041467317129471694684769066837807060528339092062 +lcm:-168964790731095355351979412256338118430524648,170138331609580398941494555432555720911428772,0:-7186846898937614525591235743048196241372711495546492763752347187132124897827551810593064 +lcm:790938498909251314495722876378080005340582079,5214770204816378474402582970231763702140978,0:1374854172651385139955310854649879453753928013886594694727948344749512222152267012777754 +lcm:3097935765451813281781983641770574025792276,42609404056306319259222360596281494320705429231,0:132001196770618914910107580782114196079241607233335405092295156225025350707315539424419756 +lcm:-98485087154927525975034391790808080098982,19775664577849930783360381707025488283978,0:-973804024748081746850819013189941767013339940621603669747325245218966911782355198 +lcm:25900464334299058097279910365875929228,58255952834922520501042331752256379575,0:1508856228661518846300670852569471328709790883165326524402490612694204718100 +lcm:79400185595521899110261406600117591081721314118,201740226840130845073877991057259510967,0:16018211453189077537841902603464990449906833086676810898799136608951219916977272932106 +lcm:981167299738316185980724229187020822277,8133607419206585086507618470282084549435045911,0:7980429628634459820355488852068596406179426323528568158104015662222056961076466559347 +lcm:81466412463591236560961446462245299836549126707,866192944729287017177690246604876328497,0:23521877236122927651693163907061883464266675326601201698284201208926249964967269289793 +lcm:6534998388738554052417315288897046254899165842,46609611771478693989087838979597248775,0:304593737826342807250457708401174251945994165789414852595908172190369819865656343550 +lcm:948084924179221265735435784532032916982,31095014697784883179376411641933005719333,0:29480714652101151829666949589520351343767111464822561182540749953951625181413006 +lcm:2750322192684776089555518232723747026,16282797711115835147148988819960931175880625768,0:22391469951939378515729446954104603778487035357551482666768260498213644003304482984 +lcm:-916832268194684002726682872945582785046,80175456371164380904577325966825746198033406059,0:-73507445518318567912336331397416597212835389484585058461161628079009895397414630993714 +lcm:282231592138255672195189656428026230056,96673996679717919403145753072968455552546,0:13642228000642615449413724806392411795013641635130782296987254387670532396261288 +lcm:550580097204590201609373226827993784219420731,60517713169991893657707958780297059239491,0:33319848399733645437661395589377990023027893949147177182635468091834964459423419287921 +lcm:31526794192792048622410273704705620482050682,70537996848502378104686898733501905256490,0:1111918454707274300580233711800474352600757530537587705043968883837787075495194713090 +lcm:-923613180033278870451470473112995033306843225,62635452857298067541908563173475507759656054707,0:-57850929796353591491544159777994055136678493390586182701070726329142717640752659048072310075 +lcm:469196843768624413897755875308788890398465291232,-15296277161521766221056511754171865009042943213,0:-7176964965596105854796051880140430745806790021143791822882675477990460153884190250962482808416 +lcm:2628065716223500508449356215564412668664236,713708318009199991674271791693482010536664884,0:468918090485879510666557537656446407094985302907396727300429235150492228937795661972156 +lcm:604553604369312265623368647573085123221252020,990982890678004704551740474471789043760433700479,0:599102278427707884215998875763263404402845043498163599628915781601939770631217226224053717580 +lcm:97586462652371414650265963064033775148721243,969409880443270812997088798402379069080662,0:94601281092717085428971288705993159426354381047162321909314102361504796669908919902866 +lcm:-765406874969209688613302257358735487317,687488505077706911028822098735771705823765697808,0:-526208428248781293790355829561494931467780389995278558390525263117575307179181438701136 +lcm:85075624707999635862443444914978287825359,778046486301986342411165862027907781749497,0:66192790874005569505967522431892177262190586520494284537342391004284567008622094423 +lcm:8227248806783006644129224253415431417213104067,-96883503079217553138854609209329008354340832050,0:-797084685105450364093424636607878440722968607757607323583949926033112024630877523264018947350 +lcm:5027554007771258456873599804445876368468,9124875242153734630106913217321584664013715,0:45875803094102741048036279096734905134493820588179489085096405521013297169145538620 +lcm:39245745484403729199058188063461104557810253,220067769421357576954105356315871937975114,0:8636723668031045203182769468262937482316831571209371261835666035163932603354648043842 +lcm:12265626358518464602956912462337886264411404165,-62808539324142868756473505816723401975937,0:-770386075474250281180131471535743658895165686987724121596740049447065305055237711577605 +lcm:-12272356051659726939876917766506363796290,17656166644036956054896242696928896080969790493,0:-216682763563059549497954402078347159387989008283715984882662478463368364976841430670970 +lcm:637223594292638303876168193085997138882431056,94504571343119776477559774058446419793557358444,0:15055135657086962151475550300387890956134219709831955986646383218960383823718063770077359216 +lcm:5571012420064356266635359647247635200655740,-21295217227115690481188602248443089551209070396,0:-29658979915057488281375910245844852139690143598685009046127888233506587535909343755368260 +lcm:5263843748978600609740419748581371970418448276216,5384845751134428162699702180820131424931650492254,0:14172493323161468463600107052030558175510328324645921496255479072988481662969199337241737080215432 +lcm:886573921242233631853410597832339291851986573,91564665302299543163193474542608720062467,0:81178844364292397724319168352869382688643286956887488649289119221530204376834605255591 +lcm:26539751625701457124278640373644598585396,2325338527842485879693477585982320189921160388553,0:61713906974613847646349243530903967347131153357438117664659209426320342893497093511371988 +lcm:353508003643539157483752498296868928280378,10742495675871104458509832622060247315860,0:1898779100263273019527576105561544611151524288153407344701797320631121810003097540 +lcm:-4734613561112436559828705330418786656799216681,5767402184612349878575526105980302509419976764,0:-27306420595655124123966761566392172844463942752586247604702902500841784311547866248421200284 +lcm:82083010698635736174070971617820650592649198695,632174562080517027772509374721051956918078145045,0:3459386089510696037697607329475150733631394015157940860209532577771197095497123578020748981085 +lcm:6173991144338684494350090118957116722781373,-738485502817232028305101940854863776286515,0:-4559402954616091182455382994371638790076884277447195239272169152306248043072153085095 +lcm:-493513047233893983448577482415236886372545860,510358065314512191744416886029069217313650,0:-2798537377708440066088399588452377494483186344049452196318380194547765420639340322100 +lcm:326654054139623246358073868314669601484091,-749350879522921841553744544029160051092161118734,0:-244778502769254807928944561265310682694306143662100245399456722534220714864996773263060794 +lcm:1402621524995633967650615579165227953957890517212,-4307813373241246419295301377872133252586,0:-3021115881486111596495041468952452755324614644604079117686302481886685354889693688255116 +lcm:429404746005804957738561594094664667352987,378882853314853204091011966904771925997210303,0:162694095393619197081345508962117529189396776805991399292350948184192266104441374225061 +lcm:332341701384724523211310134953299492552149033413,851224516641538736779656410258860743437969813415,0:282897404121038737349436193561640178534459124296792792204901752510516940857699900180164210635395 +lcm:8093542646198882950722808884458624246299608906958,-36537804019444103265563497755234936603188804846,0:-147860137514913904634692391142170680202258776956700982397999849944457772330156859656606216759234 +lcm:22659814113479956892126670971189905912120035824,-7769923990496178313173088170032841760727,0:-176065033300511807783943084226119789640585676482818345603663798333554090985834476284048 +lcm:-66431972193306385702365512934093484764859082,36581996652652744665199423002405565247156,0:-173586727457475315287286644140245293266784314041722406717122380794776682723917233628 +lcm:-888473800362239868616054745127669042022317,142999759078860850560633007783677610020527766,0:-42350513133226737836563925020363583106497633262140965689620958730476127814149430051274 +lcm:5971942663513046812876552589351160577576206860,5155119487765712370432570496238254289228130147,0:30786078004495581876769132581215368897074670048309664867385023649025961965929287514674208420 +lcm:36328343589972083920724771391132711614346,626466814451530915421088090957480792070888316,0:1034477349232295636348590401427803652375984824843092173570332762552453722767574062788 +lcm:5293116409600323220539205506696278195160522774280,-89478075685508708042860880549625934136374,0:-236808935355212916308616284114978382722590502180363697942174473357408509364368655169830360 +lcm:79576614103508536656978289576589750212587261,852468870734033057111244131505440601392558836846,0:67836586361655850604287977041894979998590061103440929502231721634765812139562797406437018806 +lcm:8225066772418695359596812838151452668642167,32895491347247919323385073727832554930053,0:270567612842635564451661105276011053846580530826552326236219991362408128533171344851 +lcm:6163942593967174125699747500635651388266851958125,35785148285967657728202559017385960485415693874,0:220577599751307459197829958073417379960145796516327396960366172323789774042408250526882467026250 +lcm:2768453763718344802615194690925869147682838954,295289393573622382700104229276698254424111309,0:817495033025002504068133964169976601685138884223266625508984010676066936521469461617130786 +lcm:543530772918490900335995207569824317804903920459,3816523263571207729432080444412751436592123632,0:2074397839310259902661375133149465196577634869313509399704184579022798133468044005917222187088 +lcm:1092477340633785505464776554395206472561372312061,-80145274095041381989361699268630409045305877,0:-87556895907716629238600642139851536991533588781637223712321645442750907264691471870441282497 +lcm:5221300639042222043517187865188827094681806,28716457589092549537459686031371792838180039728,0:24989543060159632642010593077696572867622550344397734652621919451008087743078495099798128 +lcm:-468871256127286679587501070578429844680401783,7709908112767006788780052051800778651016113933,0:-3614954301459024712014678778499413536274302047069226791616378154943247688691115133744342539 +lcm:60187668034435065431875732180204005950423,6575730301760601160210842777500398231559661,0:395777872486342581314679269175741080629857948827943943881264571589081297075932686603 +lcm:85750547893356514086330287277441673045104762,79743140579005364490235586620393656130064,0:3419008997693330405464249977225918848757344180361491250868746891061450981564188882384 +lcm:4548581293372942515724176487253593549214930,4238661184062900689214356649238748109095650,0:1927989497077451677556406438992119682437686855444693788604757451990503919504977805450 +lcm:870890539340345883811990618518239041519315472381,-326492148393756245001717974027772662339968,0:-284338923205026619246910784734503794029639825911870769385331694156076881647046490736423808 +lcm:66987553698256227716875714961629477167428173612,90975165679807773385648454136069587671757554212,0:1523550949045970063245867032701707546441284497509992114155614817828087572926246444944809463436 +lcm:55214217278725852504312036656428464058159216571,-38639629611220548541845337991516346077285504,0:-2133456904923420705886788529419803172916228952081562524788395230166386012381289930934886784 +lcm:891217139364757949280558543150622433360536923866,30525879876993440244467275213072433106397646327,0:27205187340566323080358381531226152260280933712987740283334272666071747659070919682319193540182 +lcm:-27569366446500582408824975793718887457276922405388,634666021153562229559368735956062829411322343,0:-2499620015475006770093631859600965442502552615908591007003664916282081612538456035180769712012 +lcm:502864235446447920785714797929749621810588808385,-661761137717295415776353819805381820532626437501375,0:-66555201713275857902811739936791100923712566713387105483008138592982591252568436643492447609805875 +lcm:846540274257645306570757431119674434472851673,8616613565185012233547219046445322085886975,0:7294310410643867160484254450457795378883045914986526511813394090546583372432655817659175 +lcm:-3309007371119113533010968742743901666008447,-54456422219293958622124113256532150483182055,0:180196702528418384342054817105817441009885252753576126005393548812004572770935068818585 +lcm:3808438337556464123872249539607274641406985997532,8958313515020597801994910602927304472155060964765,0:34117184630454650095284221741033298990688190756311433174116017572873358206925691228892157828959980 +lcm:3966980856734279836284487724100931405197679196,7991199588345191911654938564028578389298180118364,0:7925233947327058439656989443340159765395723535993677440234885472317622785961246017870345088836 +lcm:65639444382189527381103754239686068124303248439,57344187472963481946737524023690750337279473205806,0:3764040604273435895633212274119116479837782295002539485107922790189834206416168312084346995236834 +lcm:415167227201847402226579925485934896345892,586575228633844519664975226407615633553394085108,0:60881702804300728422164607733352957690389009263077497409872743056634977203755428913544084 +lcm:61619333876398280418219395631027787927517659829394,919912829682211281138193507951318719985265,0:56684415789370483176959265833922690931907142380410669255035534110985337015940545738093879410 +lcm:-868753784405826481862596863379498777711457154096,545880080147628730834302628389405153791727839,0:-474235385460008330984602458660116725933386690418517481411723635621365531412330794841516078544 +lcm:9429941770445780812848883836626433106364646270218,13789105660912116612159357433833332620650429,0:130030463448925543470092963482754387029792169816829218586198208779745648441067644420051623522 +lcm:43608475425036256086742701999180132009804867174088,26543470249142438881834938827109299420258184885237,0:1157520270054909035662868646857940204973664076401942399990577391349752558661122837219065938780138856 +lcm:57684506610503798187871631196324475714333617510881,471695506003883133237678946411955700467360,0:27209522534225930626068350341042360052253774045631066166444663548471852016504199451585344160 +lcm:45545031179301366913301053296868047362176530184,-91968879037454375774626628433933013352182139387,0:-4188725463286255430640627639956152535588659815635253627540812068959602079281136816961500757208 +lcm:-390021533721654785753654976920878586915091,77031076759836910371783959035306703983828680,0:-10014592900700703269560078738266286134110215752142363776248874904012749586637416869960 +lcm:423541795082126371645621560317104281087986536944,8300998559716429411460238557591751288655280830676799,0:1171939943652147365555234596255224305456012312168414340835337509553512002426738855055186061245720752 +lcm:-22004254439719621882091733525180851819037175217519,99335356922776842325949741933027888097618837,0:-2185800468589145609464205476226975010639204222945574205629223171319215468510436674371426805403 +lcm:-568617824838411255064542027229734991599889058339286,663945656360600870466864889023341282183894393751666,0:-20973963051704229852295393571808922528386258405366303052934095222591753315525189202845488663836430582 +lcm:79416546968775553905606945911160893343240489,57823044209535496953371020115352329847370545,0:510234056260462346114599875341456302082293607904671871750490172957566065355271803332945 +lcm:944931014689390846530685010237152128723129879051,9132010491010578008428313272813386452749469110941235,0:8629119939424787805155145456276331139041940822281098763310858175298740567987777487797475766318567985 +lcm:10724730362623743957337791385603755532922863,72480373654893123070601266938859686093303005387292,0:777332464030946381953104911976964384403745616151494866542937429270491850221347238960076456996 +lcm:7713352208339235603081099644445084271357860,603624463205826416829628929324533190899935786563381,0:1551989362092082286509226742932313310071126914988546921498365356500657461247063016086607508220 +lcm:-374652992235609318781751374140306949494493761487551,-8211631925711097443824357620157273567158306960781,0:3076512472105121389035620380499987642797429799314779956051883946663228512561940943539675904376737331 +lcm:148033237001979427358794216800322662159772216729882,-2761071692676096788505988250569937615812882,0:-204365190130688570487960579178439169815175152384146484286930819001830464147276002695624969962 +lcm:8799836897423935827052239970797993642793054321869,7294647877437509677171255169879966954414823484,0:64191711545589794049942507329622817162690486075145161653225201426081306037945865801824955971596 +lcm:638050122120135743843926357476168630346968836720976,-521011870575614667006902791543319211035082259559038,0:-166215843823405648565930328412825365823057474431930443033112986539191112250557243418309377653802490544 +lcm:-17589569754541719055752617853886490778777621596833622,-757763302557856615098419826290170728613135917189,0:13328730467773320372749612468589169429951770262414798041479922130537436948993914504659373603202928558 +lcm:-9391500830250456597029446286855934735787373415653,28432489383197015180933073382445953529667174,0:-267023747648382060661246943486871855039477521250741910116209365765385119618211444260651874622 +lcm:597671128380217947385553643776956963479914986403,71727950226724858021016384499343090206442916,0:42869724948406755644439192851387407923848606069058040508413206852418378147081162495135671148 +lcm:220524861586728547654066186650842017022514113,99830670175055229565653522851124444573641171168883370,0:22015144722464404290431089740908195479979690191563438782672166808199720494718314317705872276000810 +lcm:-19711747183549435340491469077888147043386014913558,-1141914280129478236596364286858351511269528735,0:22509125595197123566803201916751380078133670163026469768611121772532745591006866402480422089130 +lcm:-8382072953685010521572064715326232892979307367,8986558828596332338706049003428573784660004270,0:-75325991703876567601582024901200837475422482663143278160590315962341962045355062611862457090 +lcm:8502152308582607794375019565844324676023491104593,10470050208175536662422671560468368371690332,0:89017961548415452362336397742460566038542969501801207576446421265423116103719862689218894876 +lcm:594601725521916181847167140525593251441576703983,963458725567603941710493681498226412426881800,0:572874220691643607273440473752072791294210386705034629979437739545297813514469057230330209400 +lcm:7141961266638507042734562322157608790427840009,-4549724799885066646710284284349071123364728193387,0:-32493958294643778569864068941415075147150500523994618476463881411873140452414616492271247820483 +lcm:-556279059738139499395948604306347001411150129841210,96265906951839620646630096006130967227739083772932,0:-26775354102004285429276113769844676372118786237607285907901215316500732869575305395080596584428063860 +lcm:9097507009232650355633416767082868346314279788737,-12952310876092402836370081770801404571317963729609,0:-117833738981010925067125768441840140051091195908538031159411055746004033932320364747308545111613833 +lcm:4268792759888467657870170840963084681877952381149,45230992824683770972952637110379461673717665076497477,0:193081734692577312252243894972856695658000409843190512520961090560296517492619302198905276169040861073 +lcm:-14981624589272129153412283534256311120144659052,-3422881033749335138988900898217088225431538419464,0:12820079665343060974655754692608143432268798103331572831567462724320648718570784069585310147032 +lcm:1220927142068793741881867214403185329458765760024,30622524744504892825380221509502752145574896,0:4673483952404909633169042534451903822067192939697796248187569718957914620535643481481844688 +lcm:37912807996403481194979034824173466165481184382714959,-90878397829297201187948170371749592240094934625,0:-3445455247922915696812807051659782073986976942393793434021443082292576682286942256582247061114555375 +lcm:11421510093950565340830017403217629128966938056,2237414009357389011349863244579333296452235392013656,0:3194330836527727905955302104398524198341681114056770994737458183451820031389704288272506307261592 +lcm:192657988036570687555057992620686662908295387946910176,931495134488306662235768448970442482109561110,0:89729989238185994297883659301090589093198151954531577310187242340555592504853957169920465976427680 +lcm:3406199971289940059753501832956133340637816361746774,21717729758322757474808809344766892648120530501033,0:73974930479281653383172304844520436444384314366038505444774962096871058594711397484185935845291417542 +lcm:6909979467876024377878180024452018966109074368033,842722308262405734840545048662350517397572773044955,0:5823193847214313361590850639006414894786757219881236880655209757454129105445924052644535803723923515 +lcm:373077837411940479742523640303846004174658252010,174968689985940718533112057941120724001834591,0:65276940474755009773288570940982140032743912931132908824689438802225554298870445697213277910 +lcm:69447921082122879577796325457481062492384026062297,4859735149388070292660864796695584862286590039960,0:337498503134721348480339150893268639814027256856202938192556796481021571996594857372873378679388120 +lcm:97668956744134573191931364533568770116368809990432277,32650097939706033583832290610502297382443475332059,0:47595537363655312568235002972649323651425354794543144885024534520500637904064737938316663353067559229 +lcm:-1130623853521736649164698623052358825973875071086,97117938880122601762963490311393663414262844,0:-18300643050455451520453923979067578852655453746004433917321519890785213164382247444464754764 +lcm:5196766948376722446473792182397797566282488000645,612809465745222737408369151997835003504928829,0:3184627977237170791819733844305891092484494030274488141848280463948439552688134126307231094705 +lcm:-260800009832764286426719551521843883719112476,-4764630548313512861236355180550436291099515479440,0:310653923462413311921327308749420033511079033275390302805253842034181828205601401085106373360 +lcm:446884272848375074930942162217302913946161786743256,21042882325490620038960351129083746002919260315816,0:1175466645832599956073813923052542976086932578597582904412735700346940000639354255670643544083517112 +lcm:951599922613172445123982155673072679115439437787116,170174123089259663169419228763721448308107859122519941,0:161937682362503977661236466402707947708915167258582987092600978773889146161299886218655580651394622880156 +lcm:21383950451514823653827321489681070470148156716394,474049024111864801681311013604155672359293053819708610,0:5068520421598536425525321235142815292646675811310319106405942660104400045766803347060423723469744976170 +lcm:-470414357544256461922663993336752968654129573423633,9062081906619161788388889503790336651084511675587,0:-4262933438115683672713863671510520101815219800470041585560023172590216986734948687990123769014947571 +lcm:780091812513073375693179028189802313142318232500,3497278556984926411479728842600230671778387696053,0:2728198368381477015989505443597065418103138169441425077910216137727395317905388139191010186322500 +lcm:-1625948018138433921639232759767284243608022009577,842118879046315463699452834842435152085239651627,0:-1369241522422316177317692449844295269090380811960323302423745772493265931792379448342891937631779 +lcm:25026283351500865895404594716390919370787136725638,193605742569640932386538365909397399503766353419,0:4845232172025567337840956469216133356563858466840983726314706900481952782728859639508827146256322 +lcm:4935030558829975380051283297334807636335988292915939464,826975811338155401386754284486847375740824437795565,0:4081150900367009340504991854566589470179310873827349635534175745385923686159595506846989467997551147677160 +lcm:692976306506130156561485116659173381923120836885557,770158528298664593632506223863839610768381103479684,0:76243087480657930190487337287128939416904506467283930926671128904847462858452992556512523992854646284 +lcm:79877139216893064041018839082816187503862428735,7269106113282857654532427145534479409503583394410641,0:580635400993063264937521052415287406491591842310757481379039941960972027583729569639227998188169135 +lcm:2539745404867281753796678186777103230989134057269,1232562503892732555700624680547460824244298064,0:3130394955473278587381949607908298163614591827039064669019870794477245183817740184883281827216 +lcm:-12342369542383197426854745694214905543911988477283,900468407001638487525579769577535461149066925224901,0:-11113913840455339589057682433788692760910363591045622111658103604207392316252364497138359285304423983 +lcm:25508383419230789798346692675791795579961116333703,-3196912743165527117167038251788165837584914845275,0:-81548076010491152335265692912387445585857263580983374333387917442921969005827781555255165512803325 +lcm:-1299528036083269250543034346520127753461072609198859,600594652353551219594047525595273354045086799190,0:-260163196351708086868697255894653649721720334580389492055788614848359699200918752705348100836708070 +lcm:2299157394917175882710807816574923359426328448491205413,-72838172890838078649390158065336999589794176457016,0:-167466423834226138899695762647031472841630725693307898812516233189758231307075087592787449022731421027608 +lcm:-7349901043851956691882158234459042155688766310737050452,38963935506607940884321914070762438994955796523516,0:-71595267563149505923669861270167245818680944504703982056789830331584906867289180261861884773409374107308 +lcm:958387014018743982544025716556283287504010616036,1443504353635051762579994152447131178181054158,0:691717913601677162440619033523279055938959283051812778789604206481811449086596467058729638844 +lcm:246125390054194220242986809766512103907648232140291,244701030143825150512131468437935457382757506654,0:60227136490812102782907271910174306533407908424359655603867506529129414912591634812915769093996314 +lcm:-704660850546084071765145007935951186831012905395382833,5588984198927622386999113229239134076765551765835797488,0:-3938338359304962728083277304047487715370320826599483665593576088149516002866532798742909925478892863619723504 +lcm:50682657377075501007405908966255159073041913889268,-221227972486061875975200412557047324616212536548,0:-2803105382934039975715503660314214227088117486692399200394931533988665689815391470714606568741716 +lcm:-65153936048938235385603864221810574284616709045012408,2620409042204728497893539911547700871421142555353,0:-170729963157866373963111608067452447067616052160696883002411341925443387533862472832785201804711820024 +lcm:2124140486540339235997181873057458560557130144031198,6337118390151757487365380009696068490770095523526655,0:13460929740520685472324728914077419222468164771987370279610883339996690538208206652608006128131304582690 +lcm:70505951289040282645383932312380844925860919298,7547000534925894125969206219651626162975048702546706065,0:532108452093846047616616850898050963751081524640768880912328456268423081073299532380834291122692142370 +lcm:-41539404414450841529694974131865311088044938789,-87120273993379326877611820290578462959192080166852098,0:1206308098036249351756945897983313304106264694400442480326890301234582878846035432318850625075409774 +lcm:8365100924146743906263010309561180555381451232169,64464903694507870558459227754837948332608708108908133757,0:179751808489986211172946844019445427528755317573706157771373596620024395670275172869683254867277971076311 +lcm:-607028381550248615720149092346152462853976790359415563,-638047705393414341349283089715056902457142563666819,0:387313065956814142347580416821601619522788233833564805598190281345003710840619549824608697022583095304097 +lcm:9617834842433276206013447576300042077483363020815285,528061422615472570377974310003284316297281680382590494,0:461709777215997755037224920599333096287843157872778309854711289206537291450554735917549911763077470081890 +lcm:86576571095874523146332767288469633576872568596,28806568894922815646464384363885717260300665904363145435,0:2493973959959492744618741686252959362351894366493500719340778231935540767761675386859282345646361759260 +lcm:307009198563449723583109556832166934014223122475324,138726608616028283757694379054230076836833023549,0:42590344930632202620089538756907194977499968842538325319841912047531571749213635995957120063404876 +lcm:950446831200123302940271854492691726825599408858,-72101792770002156123347099210449392040964040896942,0:-34264460231048255033825169994117823623249265283681750151900757832396404944731172193421125649956118 +lcm:981208671446974342191660850214776536471793694644642,42331603864003005956059961823201488180622810810249336717,0:41536136787617995005181391797616187316701801094427498210675495592371812354190764162938589949104015517920314 +lcm:436034751789860072246023599184144455891992330310990,72833959249163120346712529298424162613591559886645,0:6351627468616324890653950471065605238944270582911744198034275769361278389558892161259769728399545710 +lcm:90712859511805773491925085535825623597765615019643547,-747515802065477997196092836504038150570958532540685162,0:-67809295935620517600810302668580552577312402195771262364310764109361834590609187219719805153318608391949614 +lcm:397399782669545823592934194763075791833495372998,-59196779886291303828419299835113054892183602687860135035,0:-23524787461549105672926147613053790427130112546635830152219683595731769479837306026216856302451972784930 +lcm:32400956990211215478801690694170683149459902468,-4583955972534683626923454093368608704790928252299,0:-148524560311118107934748825020984325384128831537817042673475700215519245003301091136794236773932 +lcm:987205647053507741802554416690401353287928887038,99876648283232575129630115679242229378848334523759990898,0:7042770799570301963626168264039468160084000109548666284236360269531859091326565782062357924306725012866 +lcm:613843278686603793281546390730144010908586402122774247,-5096436233192165525303465082471737429087562092805456864,0:-3128413126999883739898127525581773020068974144641842702264583891275711281299548031054626111037897411968581408 +lcm:-976952961430926103170472845979881570029763109667,935178486322270132160329332160301439376977149568344208099,0:-913625391679032626735612276016819847879751832378461622543415386714525380228017439645010525807254806593033 +lcm:-14766907052440196735362466027665124699631240785562617,56185497908476101017098165076418921931361374576783903,0:-829686025309539659436877109175759992995713482163632861241130851163598589293178881677705053185350284154151 +lcm:8086945629611784458016532027184114429962417844094,915144274243273504802165174453120299631299876477769004475,0:7400721989055888996136233798580013159529233408791044035035967083245349723159601722480356017380766138320650 +lcm:78088762763327100616786616097147636046671948600444,567540241084477255158834032762283528860020033647985833,0:14772838414895737660959188658560357264170049117788265097974792165237624507227111109881234062081296503284 +lcm:719986964333569855824423695658491299542433105292,-615276910378191482694097418592439439457014608822814,0:-221495677463866003861265966742219836258928444486382973104855851549896711750780958155476829316865844 +lcm:45518095176552517046254533808850801860612235127698055,35562211507032265793347677842985571735031362689772443740,0:323744825613157159148934641716894736150323375120651628592606014999068335232090157998718113595333671638985140 +lcm:9347651927739244225461883666785850681796998039204,-49878021756813856103391637115956958358002286487531,0:-35864798940530846688181260694471898202801103161830397888280327472734771199678233550132451645781948 +lcm:-918018144578664428004161449615771398954961013294489,-670699097650597095681408528960639081653596263477957,0:615713941195785615974127065795375976710193022314921690147944271007135254397488569454896629925801078973 +lcm:27390700201762535100035783959539579449610388231,-1589447744597072139866306928627083981945967837919031841,0:-43536086658626030220375532900736667658969827278059194645833847995230392704902546272550528175660663271 +lcm:2277199840598187516900058221233481999025368188568,9608219845154413235861538421470991851896216584568613,0:7293278899939323922333519302858351340649305819231682068123769660826907879720133355526830831172738728 +lcm:-384224188940171310851587214747099156035618205974037811,-365155157346205326208918238248019306559191342503,0:140301444168666379290296176915045491501178018946537404762619540722359114634558549786149744296773380933 +lcm:286446854858822908871115682474835177238732522628,-57158496101544373650727927690968913495792599007869,0:-16372871436747676262278174307506297592132492975051635951931260785772478739228382233254016392559732 +lcm:-381089856197823678538852020226946248080829424869589,-3010621081997078653311455126099557341287585438919,0:1147317155204403033538417293781061706820038418656862236980125391331092308923135144143540086900134291 +lcm:116824003493453841699155925492342665434851317689062,-23510392931055495213857939210838689217666922526899551035,0:-2746578225910099677716238357776888697288117665636655886289546239917490129557481316738650939508921530279170 +lcm:580076669302513896163920831671903321718154827187111,57642903862300589084685292813271561699366462736142,0:33437303681368339826568875036607309078951222489453540109258834689115591802250959764588162866456265762 +lcm:5760449410973032312996903274730533429280588604119,54924391723347076414566698417788233810196808558058264,0:35154353327867417497336892157787775216597147261438145141426040243888036287697412053742388607203598824 +lcm:5657781195595763129830083459999757852112323789572340704,692061618840647789470644193517118113508111433346167161307,0:3915533213270179560961108305159334536041508008965034741386030883311266330352593550098270684221170821027129940128 +lcm:-411686824144764716061907353842274549877341843077020461,64596348790121485579427789661619008385819947602752810318,0:-26593465684752629063594295950004957994828988051383949912582218957039523707407380651277297287183402393737916598 +lcm:632256394728894097701649213009572878755743290206395156077,831219707790000649838963373434914934485492976701321111,0:525543975674910659026260706288720204381515414601996591588570479429744161463440855422928774392151685316940041547 +lcm:1670481530219772906326138470230000469885289884882422,468290338328174403769157221534943442214405575737600,0:391135180478791974386986543598623230679031886475719459105679828323568651046861349186906657695962233600 +lcm:-5940255960924729598832299636442321100271324046668226,57672031765846684220194592702663453624777841860734299817,0:-342586630475711125183923927161946766514304847978409032225317328682383801381008087781458635612556537811514642 +lcm:1070320750308710183653165839089007570013512879851785,1457798154372592051774290334996812066679847800239,0:1560311614386725640264706359282306460222595994684719021358994107802507336028163090509939936607576615 +lcm:4878833860261622243309660185570248437064542060170266009303,2713399212910344466363698742990679778889654409261764714,0:13238223956354223315835115083131058404743853065832322244195207641759173433600815039556809272534689440156121134342 +lcm:-153727669883775746511963322850970227020812560900211022,967696702028565741720227898697068313091723784217356354,0:-10625839939790418437169093271198280114670637344943720676814969693439380312693668799845699120787148112323842 +lcm:-540592613733911579302709730020084890208422708295834255759,1487237786400760689794761062671094249214728767786149324317,0:-803989762194224119099880670025468825040986939150865705871247661626924722104597624198557832395582009863760415991603 +lcm:6147134348286513705872901614503400707429078163757093529,477008107151085089956583728568535862114663515203848020888,0:225556378452274534034927784413743699904109572650798922040352209009358253405098100518908280809464240096750894904 +lcm:7614680849639684551334463800131196276563566036683927,25187069984138015151555984154271413618496480687947851,0:191791499466750257309658251576197471575523021858632537910036998866329759048429339136517641910254745890877 +lcm:34751974072174908316243318351151710272413759348773,8306602488518142539700335965542308143538343391985,0:288670834308846061096235572592461254734354939539314534410107250770305649520412166539742961467784405 Index: contrib/isl/imath/tests/mod.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/mod.t @@ -0,0 +1,754 @@ +# Modulo (remainder) tests + +mod:-52,67,0:15 +mod:-54090198,1,=1:0 +mod:-76,427,0:351 +mod:-84,576007732,=2:576007648 +mod:0,9268611,=2:0 +mod:0,807,0:0 +mod:8268,487413,0:8268 +mod:1146574,836443419,=1:1146574 +mod:68387,38,0:25 +mod:822,3971,0:822 +mod:6236,52183125,0:6236 +mod:3339,8463,0:3339 +mod:-6911,492807317,0:492800406 +mod:38291,7924,0:6595 +mod:768,7974,0:768 +mod:-753573,5272420932,0:5271667359 +mod:422,509441099,0:422 +mod:930,3648323446,0:930 +mod:2427,67,0:15 +mod:88,9301062895,0:88 +mod:7238405237,35596,0:29829 +mod:791480,518904571,0:791480 +mod:451304532,47,0:4 +mod:92202398,405459259,0:92202398 +mod:349,6205,0:349 +mod:-4,9246262,0:9246258 +mod:-5200,499,0:289 +mod:605,411571,0:605 +mod:343980431,136,=2:119 +mod:-5765,7596,0:1831 +mod:43599271968,8373850989,0:1730017023 +mod:41585052,17623,0:12395 +mod:-2409446,38,0:20 +mod:181096791,3565,0:1921 +mod:424266851,9078599,0:6651297 +mod:8187966,773,0:350 +mod:2,628566175,0:2 +mod:5095350857,5051807279,0:43543578 +mod:-93,65,0:37 +mod:2833717,10804793,=1:2833717 +mod:3929,893,=1:357 +mod:-8433693,960816587,0:952382894 +mod:79150,8266,0:4756 +mod:8999807,39604219825,0:8999807 +mod:71019,11742958502,0:71019 +mod:62049796028,8668788,0:7280312 +mod:663,501536125446,0:663 +mod:9405339512,4946,0:1182 +mod:8398326144,695282,=1:14866 +mod:2040205440,4831,0:1675 +mod:80471943965,888059767,=1:546564935 +mod:69485028101,554070,0:217541 +mod:673,944658680,0:673 +mod:670561,90183207,0:670561 +mod:87072012,7500022,0:4571770 +mod:910888567055,779049027843,=2:131839539212 +mod:963684578354,34003127,0:1956047 +mod:909044,302,0:24 +mod:5117486344,275346901,0:161242126 +mod:946663509903,66919981611,0:9783767349 +mod:80280109,35551,0:5951 +mod:92755422,4885132452638,0:92755422 +mod:404434561,300368787584,0:404434561 +mod:7641992913,2639,=2:464 +mod:4268,10435873,0:4268 +mod:-16867245244,3938443,0:1106125 +mod:7471011989,656899,0:99662 +mod:10540460484,86682087637,=2:10540460484 +mod:284094,8671306,0:284094 +mod:9452633,5574,0:4703 +mod:87858,294942647,0:87858 +mod:-6925741,254505734568,0:254498808827 +mod:5567849,8785,0:6944 +mod:5715920872437,47382,0:30681 +mod:-7228582013,17846758280596,0:17839529698583 +mod:-4825967237258,629489737727,0:209950664558 +mod:-97364920350289,7307271,0:982130 +mod:-5267574,1302960,0:1247226 +mod:36680428,6651498734,0:36680428 +mod:80778366511135,18049323,0:11222506 +mod:5246691699374,70706752,0:38580718 +mod:-76528261247430,881359,0:586489 +mod:2510155,9882180356,0:2510155 +mod:205710633,89629157572,0:205710633 +mod:38304,635189,0:38304 +mod:61339988670,8789855847549,0:61339988670 +mod:-95895,39680647996348,0:39680647900453 +mod:3783159,35551417,0:3783159 +mod:434657,27849425,0:434657 +mod:-922645,2692809,0:1770164 +mod:9973857,61929174655,0:9973857 +mod:491931072,76925934085,0:491931072 +mod:36870777851,79112622642,0:36870777851 +mod:38419240,600490113,0:38419240 +mod:4286489,4746879,0:4286489 +mod:-5967532,617005,0:202518 +mod:-50370862538738,6877482182,0:6694444412 +mod:948978223,306059033,0:30801124 +mod:1939139989,7192751179579,0:1939139989 +mod:871928,56723606527336,0:871928 +mod:5777442393,771454160,0:377263273 +mod:-2052133016,7833337,0:201278 +mod:200227,787554274823,0:200227 +mod:3616468166,851332729232285,0:3616468166 +mod:-48554766181,2252075,0:2222894 +mod:2085689725679,557651117,0:74548099 +mod:2079714930,6441707850091,0:2079714930 +mod:-464256354428,40650020675934,0:40185764321506 +mod:-209095689322770,332963733020,0:5535013790 +mod:92840725060170,4953669615741,0:3674671976832 +mod:6233198674119,5752924138093,0:480274536026 +mod:-94439733,73783193078726,0:73783098638993 +mod:524856,25938632,0:524856 +mod:-3642534,51609507988,0:51605865454 +mod:556443616571,195489997,0:79085109 +mod:747271697917685,801669727071100,0:747271697917685 +mod:4017563378374,1995926813097,0:25709752180 +mod:-13638096565,3048867,0:2534393 +mod:304947884525,888510602,0:188748039 +mod:5378877455085643,43074731164862996,0:5378877455085643 +mod:89177886913,4817647675701342,0:89177886913 +mod:-865014493293680,219168754644,0:44581286188 +mod:6321573844,258781732494,0:6321573844 +mod:1400577334033142,14009914614715892,0:1400577334033142 +mod:-337804687,158388274759,0:158050470072 +mod:-3733377356597,469670806,0:35880297 +mod:51974564129148100,903237315049451,0:490037171329393 +mod:56996153270005410,2396515,0:7985 +mod:-67091637443329,19220071611,0:5632550672 +mod:9064750093935233,171857609,0:35046324 +mod:-71156951211655456,39266481994,0:466181614 +mod:4362072502442,7301990213272,0:4362072502442 +mod:-86003145010044,116261682333982,0:30258537323938 +mod:56216118551114756,455637223,0:305042665 +mod:262802582,8458718157713811,0:262802582 +mod:364016243349347,542092606375782,0:364016243349347 +mod:519321257779118,727275719430783,0:519321257779118 +mod:350650081861106,54037636428,0:53896716242 +mod:-342917424075566,19042847036414481,0:18699929612338915 +mod:3486471961809,6003086967,0:4681520949 +mod:693821889,68575560399616,0:693821889 +mod:3401139672999,693846027567975612,0:3401139672999 +mod:676404815653530286,614916221034390945,0:61488594619139341 +mod:4874055499517062,6434678789,0:5095928388 +mod:-9967718379562,6518969637,0:6305165048 +mod:10248458540,38512788750888978,0:10248458540 +mod:934811913,2221199202368,0:934811913 +mod:-6684245035389913,2828258378747,0:1757771967995 +mod:970708744192,5063581816300,0:970708744192 +mod:8778023537730,865180741691,0:126216120820 +mod:651572737854772745,819932061443536802,0:651572737854772745 +mod:31675213895884,13227242908836,0:5220728078212 +mod:-977172760207173,171558790519620575,0:170581617759413402 +mod:-45853408229656454,238503345091356,0:177737372975254 +mod:24097409593,335638746639,0:24097409593 +mod:13695822253044092,1732994051411821,0:1564863893161345 +mod:33933477593,3772615655961401,0:33933477593 +mod:1359484164716016,16485762808614,0:7651614409668 +mod:6194976547,9790288403118,0:6194976547 +mod:35165676304962247,326491511837,0:255039534488 +mod:50698603380253,837874905080656658,0:50698603380253 +mod:-6677472401203205,206803331886510165,0:200125859485306960 +mod:-2753237124185,71096000432140,0:68342763307955 +mod:1652954342334,4660678399996257311,0:1652954342334 +mod:762003770264,58114453785466092291,0:762003770264 +mod:83319117929825,29022700876993701,0:83319117929825 +mod:-437222911638931,2017017077397633602,0:2016579854485994671 +mod:50533577363426220,29452376981671,0:22750839860455 +mod:9775773078526862,883620114446,0:283752410764 +mod:86103820030464773010,9526822249,0:7814958303 +mod:472571956027154222,812207565469535,0:679360489354387 +mod:383374451459403337,4477129646684214,0:2818431491245147 +mod:7081720213022716854,503311092329338,0:133143948931194 +mod:4630128377779,800171178832441,0:4630128377779 +mod:54693593051710401,980996545405933,0:738783054384086 +mod:150482763687955095,749819481017,0:742223172348 +mod:593450696047000,13586015736,0:13528698520 +mod:-730500097181725110,728537309580,0:620447592990 +mod:-767181280549335,8336534436990434,0:7569353156441099 +mod:42981969692069,6887667892543850584,0:42981969692069 +mod:-28591748475152,101365562837426064,0:101336971088950912 +mod:-7968036669154,98303283928623932,0:98295315891954778 +mod:494411386598,8574532520081676103,0:494411386598 +mod:68913463428,37113484763365761,0:68913463428 +mod:79048317647131571,4246788999212,0:2834004798615 +mod:-7998703715314196040,603932675107699279,0:456353736193593866 +mod:37189110674330836953,371484075669789573,0:40703107351879653 +mod:4919085789477,6627653096140609,0:4919085789477 +mod:1124829404566321352,1113121353192745,0:576837841648902 +mod:73970998780022288,690593097938779270,0:73970998780022288 +mod:406559451598,291528733390141,0:406559451598 +mod:8337041054557098684,144564322413327450,0:96874676997434034 +mod:33602045710930,3944255323850,0:2048003120130 +mod:36881013741727574167,2358692215512,0:2217232253623 +mod:6055783116809477,665900361366484113746,0:6055783116809477 +mod:6874334379769379421,7685349776541,0:4194447198069 +mod:4114973877055494,6202439146871230,0:4114973877055494 +mod:3926099959854080246,275452944727,0:275423967496 +mod:4029793101439201031,660396995221451032884,0:4029793101439201031 +mod:301872874428635697,54874102367289078,0:27502362592190307 +mod:5569303592565,237882890299906,0:5569303592565 +mod:-5030250164815763124,20652997723024,0:14613601685340 +mod:228359514067103,297994781044164,0:228359514067103 +mod:-424197230384775822561,35518873718705666052,0:2029254239692170063 +mod:264447937587468968,14314680638460766,0:6783686095175180 +mod:6394566749820905145,9683844165303,0:4880613879246 +mod:-8688948887808654898,734279103507671775,0:122400354283406402 +mod:-626916205862869883,94382847154774,0:69047786293799 +mod:1626914326860229332,7062310571812316625,0:1626914326860229332 +mod:54001071080896262095,42490007593568841,0:38761437063834025 +mod:24728563187886295882350,709499139923539295422,0:605592430485959838002 +mod:-1107994585324963758433,26155793492434894341,0:16704534849736698230 +mod:654008549965770,51389913007264,0:37329593878602 +mod:-519456375679038,4624572350871880932563,0:4624571831415505253525 +mod:-82236922719413533430,72103334739677626,0:32982218558637836 +mod:-323874523758275336,8012542519209926,0:4639719529331630 +mod:28055503703579420,59306141019480998333,0:28055503703579420 +mod:331202177649495634,20031374822914022410,0:331202177649495634 +mod:-130081790443955,81911619024148257,0:81781537233704302 +mod:12392000130570253028635,427646582276340386,0:85115948737663513 +mod:-3408044901060955810,3826012386295493550,0:417967485234537740 +mod:-2520566214354390679555,7522956445489849326,0:7147151330198693981 +mod:1980291342375366442,2779172585704919,0:1520461353464114 +mod:81051547602981,72198401841564,0:8853145761417 +mod:-92876397580264953214156,67027595927289169530,0:23850374957835754424 +mod:5011749939685736607,233831869913631792,0:101280671499468975 +mod:-809134913749137460747114,775995673975034727,0:431478675099304148 +mod:643341365602570,69924772710009984856,0:643341365602570 +mod:27791967964909927,59009798124981438889038,0:27791967964909927 +mod:-113914260724456,4611599197279102,0:4497684936554646 +mod:363308545066340586,9662463842692591834,0:363308545066340586 +mod:27756526116505105,3891223619279919535107,0:27756526116505105 +mod:704802873683670599667791,7264024574741209,0:546567259370500 +mod:787136088375328,120969078621542,0:61321616646076 +mod:7670850065383883511434,877940228500467933,0:286288975295180813 +mod:702943840459603392464,184873925058119829752751,0:702943840459603392464 +mod:346820606266075751,258033318226999763369665,0:346820606266075751 +mod:-19738877253014425,881986541366353479688437,0:881986521627476226674012 +mod:43236561155260520835698,38481338895759451581,0:22017575322656710235 +mod:482681206446127491983,75672199144043749590770,0:482681206446127491983 +mod:-9003595768210252773151956,24542596402501089193,0:2977625686803835252 +mod:500595090938893533,22068045096454773348,0:500595090938893533 +mod:2380288714663108486927735,564958976857884405,0:163611608764475305 +mod:-61794208268134898961577,163988560200473972889023,0:102194351932339073927446 +mod:-801112647021780575,5997315269791230838613,0:5996514157144209058038 +mod:3375858304586431,650460337591609485545992,0:3375858304586431 +mod:8320311342983951,42251663165732904527,0:8320311342983951 +mod:7459256407267723209637006,417970890631288166,0:349337361754478408 +mod:848180762170013347,7469835660313775,0:4089332554556772 +mod:8089787096351751904254417,50129556268942208341,0:29694338665148808860 +mod:-34903538093781704569582,183184852451752183835379,0:148281314357970479265797 +mod:48619014890072452,80354799021914778903,0:48619014890072452 +mod:-815988375058446388,8738660656145657284,0:7922672281087210896 +mod:31813448306518054090072,207434655868203321566266,0:31813448306518054090072 +mod:-8633600698002819419017,586048397265776638134,0:157125260983830152993 +mod:-857216833834708698,9172367193130972108680,0:9171509976297137399982 +mod:5504547056103565303478,13822143042666022,0:2988649206036176 +mod:9870113591998328200,40859674965133754765576,0:9870113591998328200 +mod:5384435851045720977148,202201600690593374,0:9426255910020902 +mod:-2551078867778519184089893,60228847348701786402454201,0:57677768480923267218364308 +mod:91679210346975867109461657,9997426629350491363488423,0:1702370682821444838065850 +mod:2292649799687862201,546378248247723870,0:107136806696966721 +mod:588814820029030818332181,8113490218013508525654874,0:588814820029030818332181 +mod:65454498830100158031,780288548110175467735,0:65454498830100158031 +mod:4709646238170145522365,55608341104804744,0:9004980917338773 +mod:-225535148248500667,8159132039306813709871312,0:8159131813771665461370645 +mod:76763315297183633054184,85934198951388076635,0:24075633594080619129 +mod:1133129576897649900,54644763452092731277,0:1133129576897649900 +mod:-67382808234452914542138,8955363760101370992534,0:4260101846358053398134 +mod:-90953375293336830190945,6853448055620747690936,0:4994897485353637482159 +mod:443616999780543985329,602650474818987637619854235,0:443616999780543985329 +mod:-32726760956482080293262442,7257539124551086281136,0:4740495243318834660918 +mod:8064248346280114405840575,2215292120106396321855736,0:1418371985960925440273367 +mod:-7028166529953061572415,793014187917784076,0:318217562258693173 +mod:-24801752752631583807972,746849063653448560403834425,0:746824261900695928820026453 +mod:866033908626319182842,6382377566902718089,0:4412937094452240827 +mod:-5696109440363786526866,467357847433239609373,0:379542576268328394983 +mod:-10407234425686004311,628564472015312749963777,0:628554064780887063959466 +mod:209459609329564838657,2486115412259790740945969,0:209459609329564838657 +mod:83211005582689134709,427365949717166750,0:302011337558785209 +mod:522043226813009221,84636707853907370269,0:522043226813009221 +mod:505480107359090528100756,628892849069663750,0:562098008522737006 +mod:-310708269201043467381433563,29010904881853615009335053,0:8411684499346297721252020 +mod:945016205353589874668951,176007434590298672,0:79677746280043975 +mod:3611093895058265247,4523612444279050027926505809,0:3611093895058265247 +mod:2248073915672967969228420426,417993946449832515848531,0:102471665768698995020708 +mod:75483556005338850007382,767992806236118220580991044,0:75483556005338850007382 +mod:349175730044864846750,194542620085155145157549,0:349175730044864846750 +mod:5214057366956683393,6766485378347583109969578772,0:5214057366956683393 +mod:42801122269815033051372,76491121430284940146293642,0:42801122269815033051372 +mod:1504356843590479398148441,98825538637920229212984,0:21973764021675959953681 +mod:1422956549105294508549700,73999528905391695937,0:19607783517587377127 +mod:199912292615681783148398065,5625251527460055267035,0:2103832806339068508235 +mod:8738762075990650132321428,8066858358673855106257,0:2354473546865052245097 +mod:8744971293400903575143822441,2181608008778482293077393,0:1086394216746544489631297 +mod:63912100585682096593583,11361184476808394745245,0:7106178201640122867358 +mod:64684262754316464701,22376578863907224393672,0:64684262754316464701 +mod:13792618112420611117,792966702790880958054,0:13792618112420611117 +mod:1114011944265093423883128,24116689971306070038294352,0:1114011944265093423883128 +mod:39678469855084024947237050,42142535719623301934525721,0:39678469855084024947237050 +mod:83034763665077760046967629,82778559778204667638,0:4244359548962628019 +mod:2396471122363838882513850900,59747356384740003525,0:57225475716145829475 +mod:864549729107840811638,74264623502102569648,0:47638870584712545510 +mod:293471055432367196531,95629011563915920942031898043,0:293471055432367196531 +mod:805770771235800281066969751,444417493982143896834,0:79401739074580625355 +mod:99254856446162105637797829350,101981775402621358245361,0:73717806842511917782490 +mod:22541739862903307325,418383569773975023302632076,0:22541739862903307325 +mod:13599043000903587396023017,686395340986063801303,0:178505287691364607981 +mod:-921575422288638694625782546,2041485695291750177603,0:216222744337548474126 +mod:-489269754337315502376167081,501875735917569336224,0:368721212244829894711 +mod:-80044798953445460081243,6139390882382293287544714,0:6059346083428847827463471 +mod:1697244421022884241204,9839911566031781174211,0:1697244421022884241204 +mod:940445668109981090346872,1166998590007295684475234,0:940445668109981090346872 +mod:399066130721328784362180646,2466979168009327704701836,0:1882484671827023905185050 +mod:-48110448286951664808938217,6924833390360325487794,0:3294109271876680254495 +mod:8202438083226798875527459,2712253233103808901251657,0:65678383915372171772488 +mod:5450714727456153005642027367,100450439174668838374882,0:72996960272497744180283 +mod:409375235483978782700540,154442023996251499419641,0:100491187491475783861258 +mod:75895449457418931569869638,96657756211092917375958176,0:75895449457418931569869638 +mod:-337896716384821901508,136332254359196503233175760151,0:136332254021299786848353858643 +mod:286597911534314020993735125,8939960441559894748118849,0:519177404397389053931957 +mod:-3629523279922780081559669,47176221977787068435634953,0:43546698697864288354075284 +mod:721006898368058427667864053628,560134433649198454347279482,0:113882261540016922915360294 +mod:5816434052384442045783498,8295493150888286278058,0:1293353611753364864840 +mod:609810757121108447302938155,91911350135942492551802190,0:58342656305453491992125015 +mod:-19105264771397651242810,62812840189408438467870,0:43707575418010787225060 +mod:-3384023484275449303514510512,36865912947085723132571998682,0:33481889462810273829057488170 +mod:794103148636604290205719396698,60830693353207800202838586376,0:3304135044902887568817773810 +mod:-872647162068256604091329081711,7171269767341809905452128,0:3142110266217873424018225 +mod:1741864928041849080630509776343,4019228270224295025021,0:3953212345502485484813 +mod:46472481719179435494357769,7926074597166240368807886225357,0:46472481719179435494357769 +mod:-8260893021299279875407235,8110427213374126288611,0:3632309128954812687374 +mod:-12778559515327410738082,60133073412668338924778,0:47354513897340928186696 +mod:-33979239742647553347892336,6474568036342863013409,0:5767880116134609491505 +mod:983404512267124852163233,80477942869108029021719,0:17669197837828503902605 +mod:3832523396251835150772,9395631266939763227204675100039,0:3832523396251835150772 +mod:88670226724007548654482766,32452353295811216769641,0:10397519851304439823554 +mod:96278532026543994019519712307,129820052877663606606885,0:86210882333451655589757 +mod:-5810653163494420168043,36986477497409060096423733207,0:36986471686755896602003565164 +mod:3126207974581460571577891,32180478067769596422373325424,0:3126207974581460571577891 +mod:51956357441149158122167659,1003490769172375032993217,0:778328213358031439513592 +mod:-561702379847624714751550,53922991187327968536105231702,0:53922429484948120911390480152 +mod:446077868534077880774451137,67277848506923282427435882416,0:446077868534077880774451137 +mod:1575047464232207678249043,70194506692490651832280909556,0:1575047464232207678249043 +mod:814270662793297992963934,403564259479336969832400620632,0:814270662793297992963934 +mod:790699201198504136904045859970,68724106656555736601709440224634,0:790699201198504136904045859970 +mod:8110552276797224689344660171,3909333328494414590072213560549,0:8110552276797224689344660171 +mod:-65870994230220283146814283,3379239242265180710762324,0:1713790615083331068432197 +mod:4019795295333902960419848174,50295832366163431551511941,0:46424538406991867850404835 +mod:11568598680110024328705699675,22452048595187151195492,0:1025051083178018882739 +mod:387522780739724474268318533074,9155092309434144095404353111490,0:387522780739724474268318533074 +mod:2391972635448121089016589,39976990962848470908868,0:33330168640061305393377 +mod:866848655025962221176014879,40996252765546194841051793,0:5927346949492129513927226 +mod:9039212181347754641685676061753,1413755859430626067769418378148,0:556677024763998235069165792865 +mod:62309693047935174482238300219097,1448468173515469111051509167,0:937627820239732135530382258 +mod:10235771277419233732197767436,47759815237747782490291,0:30955110842232226071189 +mod:4510445237186840834301611,9536931548375816882114508,0:4510445237186840834301611 +mod:32374689605351221312665153746,773865694054081649089543,0:18294598715523004122341 +mod:58121462593501432960291,544699189690679924713807,0:58121462593501432960291 +mod:487815493709763477417262324977,100467558757425018298664228901,0:85945258680063404222605409373 +mod:98070875983658870659113425694,60099405211091721761658040174,0:37971470772567148897455385520 +mod:918364128985502035087214237,2299858822935844817555228747,0:918364128985502035087214237 +mod:98947035094409552251212724,2825141475757917666304644602636,0:98947035094409552251212724 +mod:1526039375858118801195007,9842198071310595711976222424051,0:1526039375858118801195007 +mod:956310510459469197042596,12660491958158211655462388289,0:956310510459469197042596 +mod:712022876493637494246773,6907620845496782089063213,0:712022876493637494246773 +mod:-127487606866501768951687217731413,97214150491566835275008318146,0:57358578433918929123695676139 +mod:6751815551565439795678949,31071725936607844864896266530950,0:6751815551565439795678949 +mod:207247716655973517840426399106,8676153294057052584605417,0:442920832702751956803227 +mod:-966202956730918757628959,506872112425906694585759,0:47541268120894631542559 +mod:-68170698773654086579499859368,5144430238993385147152349982479,0:5076259540219731060572850123111 +mod:183149199419924949681672,26683244363440548441986070029128,0:183149199419924949681672 +mod:-9975221264569424411536101126696,74192946761934634594295284416,0:40826548291751258693762269464 +mod:225922343593361728051942267585750,5683400149678094053656150,0:3825868296308226483712150 +mod:1590802748651151308839006,37444237944901366482969738035104,0:1590802748651151308839006 +mod:9067619839451785696827107956190777,87355497973165371903530913,0:84293482668838694674156358 +mod:-86293581881377444715621610358507,7692884519189179893063221146996,0:6021032348892714001137043405445 +mod:797270639908743442539388404065,246054564304506055627938724988881,0:797270639908743442539388404065 +mod:205038144424990428525674376,85234961390603945529096075,0:34568221643782537467482226 +mod:35844939430843764162712556,653126866666115633914185924567756,0:35844939430843764162712556 +mod:4259287602245499035603599602,50729589724528668468977995092499,0:4259287602245499035603599602 +mod:2261834480876028227185763,424795020529636248111781917,0:2261834480876028227185763 +mod:39152906040428126999262088,4297272364540702463008576,0:477454759561804832184904 +mod:-5930922183829543621704345694286,197786250025515478569975835009,0:2665316935920735394929355984 +mod:13648638091639720241268467,60685727322075123781463007100346,0:13648638091639720241268467 +mod:-668319624482464990058154959802,710719216881033542598449292474287,0:710050897256551077608391137514485 +mod:642021199249584712913865808325586,543227057645582873078752689,0:152765287910622645761540601 +mod:-2656447484733675418860019290432,205011691602629984379183426293586,0:202355244117896308960323407003154 +mod:-76116380282907702927282762504,936328544643249459199496754,0:662560377838752727075971324 +mod:8093358695607350358964677676389573,829984096904096704239626252,0:340210087590552445135735881 +mod:-9278168173113556399784725246186,4280082896252256282175389133291,0:3562080515643212446741442153687 +mod:2802211761443428677828547316,747494545678197065832762122247199,0:2802211761443428677828547316 +mod:23492204756311184079845536545,337250910922702955980510700463272,0:23492204756311184079845536545 +mod:64710301838085669236316870323,868170439410850659865082898,0:465689321682720406300735871 +mod:2741127245480801383259770751238076,74176417788834011756636699109536,0:70776205082776960020849583294780 +mod:415065500982033616775933433,28746890219519286864975018117944504,0:415065500982033616775933433 +mod:-89217744891275021874139963535100059,3290121624016777142908239971,0:2829430817460639915155471175 +mod:-9317836992515247957659739610258,361276376419354526411745198556357,0:351958539426839278454085458946099 +mod:298421168958661320791582460540,9311321600116774390269301187799304,0:298421168958661320791582460540 +mod:5274155275590071857725575099101060,98122204238639783506999069,0:57734636536655754953174064 +mod:865783349805109330441131327,162630826994678660982290958,0:52629214831716025529676537 +mod:708516761779855069848378277411149,35904666994288818268923584882788350,0:708516761779855069848378277411149 +mod:6609496417442545300703371471487286,5902561608289411469926303,0:3737357682418540243913209 +mod:206488861625670348490519145948,55768433595490812270050489117,0:39183560839197911680367678597 +mod:235462255567476370046316727231771335,90122239517029363511961434219818206,0:55217776533417643022393858792134923 +mod:7378753800396502033389928296562,22504168678875184770299793837483,0:7378753800396502033389928296562 +mod:2757925654768646392546972258732,66265998215956320290751023811589600,0:2757925654768646392546972258732 +mod:-4495627928966379121510140686227227,4292233509252118764895120750881,0:2632788729841344099945860696061 +mod:60075078241755197289597987901298258,85793760621445664196834659007562403,0:60075078241755197289597987901298258 +mod:640202717640040770302982685361,1043941556622236018146973420441,0:640202717640040770302982685361 +mod:981675333306953772484178502284,14989243876208586685329510289358317,0:981675333306953772484178502284 +mod:87715989707184594635823373687043380,2924631585179762875239333452363500,0:2901673736971471253882703568501880 +mod:-323249437311463874466227132752562758,54630285509683054247993598313342182,0:4532275746634451021734457127490334 +mod:-14647356048136737851231147317,175677379713875589633642881,0:109543847828811677994854687 +mod:-6268327123157272100193046712,31032884392623150618360081127,0:24764557269465878518167034415 +mod:8830187989453831993186309990340663,959494270231543012302622845163608617,0:8830187989453831993186309990340663 +mod:2102106468815389931443009975417,244048361348982984508269787947,0:149719578023526055376851671841 +mod:767756521870180222085097228863,5629352943535035124861550483062,0:767756521870180222085097228863 +mod:852449392775158289272424932198,564809949353895492950864832457,0:287639443421262796321560099741 +mod:-94075133584459673485423491471,7078005136840583876255761330997303,0:7077911061706999416582275907505832 +mod:94026202014853579487205142874162,363228855132321701963096787271215,0:94026202014853579487205142874162 +mod:78501236594767796495670623879783,7018641410498793931533837751986,0:1296181079281063248798408607937 +mod:-83121914354650984352606847805013,52556446964608987755585827141661,0:21990979574566991158564806478309 +mod:554612894627846154817277112226378,90600992903463982226644139632,0:44217065743119607988333538906 +mod:525293194961196331029028416806301039,736093318498847487453110088942,0:72734093290490277635805244173 +mod:157610281371549009553406136918536,976813980235355373377808309891,0:343230553656794439578999026085 +mod:-266509790805154856208324746487,7013639425300014015101241233380,0:6747129634494859158892916486893 +mod:59653129021803829007632144466094,6178618914324116986866641510962341019,0:59653129021803829007632144466094 +mod:-1025495993097568795964701500702,857271481493597231020277064636,0:689046969889625666075852628570 +mod:481051936536536822112378933191985353,9466673918671293738127743696345889772,0:481051936536536822112378933191985353 +mod:848825342321881584621547504882,5509051479604448499464250938005578,0:848825342321881584621547504882 +mod:-26930177732304779325732093789608,5553144086178691095750038113040,0:835542698588676153018096775592 +mod:-930412667133937228253381813097,66449017645940693043271729675,0:66322597555173167395694132028 +mod:393034277242496542604957925805,4799386565947366109662393955284617,0:393034277242496542604957925805 +mod:86603638626688955985063356610183,1769014799372327392140745286156481,0:86603638626688955985063356610183 +mod:40877446922338785512028664714,3627227112486512731974346137499409882,0:40877446922338785512028664714 +mod:951744546236842962508833599628258421,802365455425080101863813995676143,0:139116102697961698350200756352823 +mod:30829284319654404192904595052,1296652777164452508914199335388219666,0:30829284319654404192904595052 +mod:73660971721825840324689412056336,5684533154366812172288342524757974326,0:73660971721825840324689412056336 +mod:8127358843185844147904557106702570660,3688282607387577967901654384422862,0:2072259111009884617212497819005674 +mod:36532892525294324678919117123848496713,92715061891153280227822277460692,0:5828075633057629393846902185185 +mod:-8597748351805543505111910190253821104,9557218184864474744270904051127420194,0:959469833058931239158993860873599090 +mod:774575051270128492444548860406,78181627397979349461399043516039569227,0:774575051270128492444548860406 +mod:71412172829277670593171097931971081,734737459512775442295997263661678,0:142639256538452690459363356788315 +mod:6184659289209085822436564762850,90249969123878877878427941364168671,0:6184659289209085822436564762850 +mod:188404876454609678788443725411,6011866633368206495263558549515721,0:188404876454609678788443725411 +mod:81043932065078534018074416730418,8372433471866735006229336375535354,0:81043932065078534018074416730418 +mod:6912342702093810814710065121185782090,79053815437751598622884440565862252,0:34660759009421734519118791955766166 +mod:-3169060990465931351414443670,3481005717923100913496633725151171,0:3481002548862110447565282310707501 +mod:-3677873239878011216446421508552,39945867794076672579972752013115,0:36267994554198661363526330504563 +mod:-88408316452809240011823526997216147179,430749395485673956071441817182,0:247080945638127516958667217647 +mod:-7006029462687996724256881439538686,5752004602477767685988190527369919519,0:5744998573015079689263933645930380833 +mod:172663755283332370937921725543,6631081406973798665639408060368,0:172663755283332370937921725543 +mod:877725872115390827864622867155990409562,3246622975450958412670313198657575,0:1350702224220999203693898915008312 +mod:1162325904966484479085618134964501604,9810351533284785336335637682672874,0:4704424038879809398012888409102472 +mod:-67246779579026319613494857580231,4479147727625713736723230094972,0:4419584062985100174076823939321 +mod:-83311824891620553984522523676903100800,570821292295355560082171193531,0:517563010884629547920243561062 +mod:25686998142667809989182628560877290,2025104174001151569408893055981534120,0:25686998142667809989182628560877290 +mod:-6182593212766128996183974088677690094,21672462542175162551645329360574,0:18538952890500736647244660057756 +mod:-294700116350712193407358863563690,47602175104818483716891162778987,0:38515109383017192610879275889219 +mod:99318338781646049264027201614,31132733056517268309209622249797280421,0:99318338781646049264027201614 +mod:-2566422039368713945896870934278082067,3422938407926845108634793366952796,0:781766576419885579224090936514933 +mod:1798229479312127271076623168674216,146420794203382070378885907918865097585,0:1798229479312127271076623168674216 +mod:-10575907960389417493180423047371,548554000428335526399148116041,0:395172048177293034802539273449 +mod:-41585237394069668771815671048852049750,6620785900949628605472441451228089,0:6539635695898127762206147762805348 +mod:1375415227799292140480888477226023092,123029527135707896415325486765764221416,0:1375415227799292140480888477226023092 +mod:-2079331025811185903148784604677,95045957198248711390742316452607286039,0:95045955118917685579556413303822681362 +mod:-212508186835656490444057415261195182,4829012565342247873891632422752490038715,0:4828800057155412217401188365337228843533 +mod:-560425113540022327972433105315966740,96209074671864129929198408439658600,0:16829334491162451602757345321984860 +mod:878336664644268081456398188824415429,932061958650634766658892044044056328852,0:878336664644268081456398188824415429 +mod:28882941735745195429234419733039022447,64140280097846201870647655651438569,0:19815691714404587442974689891666397 +mod:88232952784596907289907603989240788,93349243418019298106177761581992320992,0:88232952784596907289907603989240788 +mod:792301762499682540474009585487691810,421120400044388668787389960907,0:367290969121964719876967770219 +mod:76111941484805465095241888868932546,2831856059624821529741336978732478,0:2483683934560105321967127421888118 +mod:-5427708288474184011690247672955482270191,671682251167994228841481066017358827,0:155983214377351577760821530794410796 +mod:-8530853102666682143315062468746465,213498385560089813626810097876341271155,0:213489854706987146944666782813872524690 +mod:968866609367366454712369109246988,628634209852159542629660518990065356620,0:968866609367366454712369109246988 +mod:96097393485358514676281731274665078,3957833123075932141830397414925844074923,0:96097393485358514676281731274665078 +mod:-81978182783653208012914682683646556932,972774031969126613105009607688574,0:403212480999053283791985092639770 +mod:313104324214756365552882262334038,5945062360867852334605007338592823936,0:313104324214756365552882262334038 +mod:2735884017629695152167391129737071822780,3290205739029218948898407572995748,0:2270894901924122540569416928458576 +mod:-97466756197931651810599360815010262,3315237020945784440159312220994155,0:1990354430441881394180005814814388 +mod:4287211941100891093508540048565501812,594177978658290517920278334613052052,0:127966090492857468066591706274137448 +mod:5617959241381925678540184778777695094011,4078448937249847013764977403503471090,0:1935054788886340585810894153415403081 +mod:-3548112469563645005797230889810299281193,34963401912331074261420878238937,0:23794960044874975729481854354116 +mod:4922552264219521070158559671565380834,5646798983979557962421505933015709,0:4190349173326084889428003908698295 +mod:32565692680193961073474123363666015,878047053403499712307729237883224199,0:32565692680193961073474123363666015 +mod:768830069274599347793505224871406391916,49256101034975375638954310064864965,0:40844320703684820706353378994018196 +mod:642199331170025417801554157178084,71675957995271890601200242650759107386,0:642199331170025417801554157178084 +mod:42268335126087027949341092958250555849,386269043855800901191675132738936,0:72464078302734639658208027006177 +mod:61951474950542877141809186776499309394,1575592140257546405587708780583660678216,0:61951474950542877141809186776499309394 +mod:-50372525688338317312158892618403161,479484240404243987384900356318490043390,0:479433867878555649067588197425871640229 +mod:44683217172537023841274434066246364,58011321282881808274541027575827116208550,0:44683217172537023841274434066246364 +mod:114588115678254964728743791898564,4589417972133701399012552730584485633,0:114588115678254964728743791898564 +mod:787749081823153927726813864184041,31678364830089024747329753309219782268,0:787749081823153927726813864184041 +mod:-4210686607729439615194829247147791999288,202013476656713406344999304149677576978377,0:197802790048983966729804474902529784979089 +mod:-201317765219861856053478772267939948214725,28008182775029748896931627041800444,0:11094152473662864315215654119177355 +mod:-232349757997193586311539481768342879244,86500898319812757120814118782924774,0:78155788143292072088055401375988494 +mod:3459368213898794108935715830804259,645307545853931027509103766501511211,0:3459368213898794108935715830804259 +mod:-28214486245399572630623366879671715,4787018465719437691521185074756254,0:507624548917053518503743568865809 +mod:3106180109929449357402363559818380895066,469482281886594475593365429169214,0:356674718833276575481292181443332 +mod:770130766600035002140959295669804,926634653367571574740533619678875292928275,0:770130766600035002140959295669804 +mod:-6708203696875914373713983952300480,1838061152155611054471652207874138,0:644040911746529844172624879196072 +mod:-7022023536539325666545120950542389888,61599165978198027775591136704700507491129,0:61592143954661488449924591583749965101241 +mod:-3443533443745355681222242435436421990276,114311172439204299235358268154904366,0:90625985673833242925392730072035474 +mod:110440434921544638432764637319049273043,85855605443431360697149818939494456029,0:24584829478113277735614818379554817014 +mod:46258128333769427123848668553344812866281,2571328063101410768335059965106947440246,0:2545551261045444062152649146526706382099 +mod:363228842811153324360949224721752071886096,519776907108357809938962249484450996075,0:424561649519573023553574581605276625746 +mod:-7481133759236874924421451125199442,918037057467449661018383366170845,0:781199757970172024743999170338163 +mod:150233345756076313394229291485865,5605171356421762519368513553022673456091977,0:150233345756076313394229291485865 +mod:3185172342747413751304414848146001953,6651506504167945767766564692832116791091,0:3185172342747413751304414848146001953 +mod:605932275764163370707058593099297764806358,14520707105209378213724439334671383,0:12284018060727065660013089171020638 +mod:-47981623369556624178550389594061247212904,9181422689232628129475009481374015950,0:491604373090426086009955599360141796 +mod:874599738760971500384056236606682756504,44920344543206332304195675515171507,0:630504744210421366434326293515214 +mod:-5100339758640008895519382671699671,18538376885121966053582708191078256,0:13438037126481957158063325519378585 +mod:965966374431724388594710850103760963,51329769618720367882036219795372158,0:42030521294757766718058893787062119 +mod:55365396231165487163722749393764963,742461596124505780223115709313334341,0:55365396231165487163722749393764963 +mod:6538244814994833769942887762335568415335737,235589470700074178427678879883234150432018,0:177329106092830952395558005488246353671251 +mod:-19650261899708426741119367893002798,8812987996700889285483125610332533544693,0:8812968346438989577056384490964640541895 +mod:97698921976137171810654806439140172,2150746254976033978038152730412247,0:915340502215642798937933570589057 +mod:89923455582480950213180680168369292947024,990694177649308076053947944961089214039,0:760979594043223368325365121871263683514 +mod:723635984996285778841783493422287881642264,32276235065854550279733766315134173,0:19063611098078828395533076621443386 +mod:-5037258901456714281661245286129845002,306535320966797925963773461282861033272807,0:306530283707896469249491800037574903427805 +mod:166532365585666920632121582151238444,4667090491545163201419847209865957,0:3184198381586208582426929805929949 +mod:911936886147819373421198830106569057199,5615756921004609557346343726386068926525410,0:911936886147819373421198830106569057199 +mod:86811484072885033355160274493374615256,37068107901315780002032584004147872592,0:12675268270253473351095106485078870072 +mod:900473503013044141279558739534891246414484,563077317551901922040540262359036981493665,0:337396185461142219239018477175854264920819 +mod:296206604339420484011101863526048420,6943888401750337638037748772448658766,0:296206604339420484011101863526048420 +mod:76766227336308707540545234943801585701916947,862719523018962547718304126230369079803,0:581458558401082022815487697114611966204 +mod:82054010479033741262889658973891816396202551,74207348922359582189434798229625162234441019,0:7846661556674159073454860744266654161761532 +mod:5755949428068825531208655649279932079247416,534856249135883824768051408128323875,0:303149412971297936011710552241756791 +mod:-4452928490319786360637181545589562421706,303160457106458311370564160984723696,0:195464116979775085035415115043948838 +mod:-33234789698150515963593845391683006297003,247588244673392242851888266520387546,0:218325582291755629376064681215940307 +mod:45977596818262545665224859936336489390180665,27112842992285248552330285939262767,0:7978970070244814382475981419198853 +mod:19746632039239597257084558812475187,78543233940000315537304287419172400279725,0:19746632039239597257084558812475187 +mod:5238660120000018347305860723869512579464,9519590072642166905656304842744016323,0:2885580046826549194893060360303601814 +mod:421929309968572623211165422203258159204,6170672461209605966222290081308608002126042,0:421929309968572623211165422203258159204 +mod:97091659698518128542501333936202976578952,9041846719954776582047878587371155342936,0:6673192498970362722022548062491423149592 +mod:23139165317306380078171479574331055567930602,3235715510499720116696692085743763585,0:687224054572373129244754482756731812 +mod:7726755134733624542969321051092429534,137447273592584087361585543516012636379,0:7726755134733624542969321051092429534 +mod:-8035318446247202234206121089089275957949,1797181404653889821209194311109353672704806,0:1789146086207642618974988190020264396746857 +mod:44241982166867606755367641125284961693,185309069767665166238795112362391081,0:138423562163297190534404383035884415 +mod:-65785436012415799791107145824395590258329666,325370594025067544378522706736314963998472679,0:259585158012651744587415560911919373740143013 +mod:821027673057722511274869415993294010068508911,57940761411167592399099541246011867856,0:15088585564533356226393273829101110479 +mod:-897376592880832081463108433977538716243727,63994684847881571668961590693909662872,0:20872741011198050739952323156486210329 +mod:191486322813809144772467638907874658537,8919158359079954072103703171632009622394,0:191486322813809144772467638907874658537 +mod:163217130341378273663281863598861624,6240813543901974803730523328640195566309,0:163217130341378273663281863598861624 +mod:642113355959693728339535203311987630159829,323941666913544410706066077917137340119619,0:318171689046149317633469125394850290040210 +mod:90922298984492607133074207595203967287,4174997092394433838709995127446401945171627,0:90922298984492607133074207595203967287 +mod:-56138446847378331284150081036618044197,841578896703894278645078028402014609956835,0:841522758257046900313793878320977991912638 +mod:160326346782265576182652967313761281,561264601142183384980166754221561305236177968,0:160326346782265576182652967313761281 +mod:62576995621135938138768719119421725807,52496992618170687901372956534626144856655,0:62576995621135938138768719119421725807 +mod:-810322268830690053691854099385548648,520427764614796522518452921164896518986058,0:520426954292527691828399229310797133437410 +mod:-7946357739653867559456965124148378449835470,5327876492137615168373368729394652862957684,0:2709395244621362777289772334640927276079898 +mod:51331569935780141651744430445423490878343,752393011036235424760251760776480444081267,0:51331569935780141651744430445423490878343 +mod:6390091523604851953175389451017692789149570,538026068781142884378652825927355725561390604,0:6390091523604851953175389451017692789149570 +mod:50795967128946679209456313061694178754547719,2799907523414076596435050064346492259123881,0:397631707493300473625411903457318090317861 +mod:931794725698638185508827954509566305382537413,188887874108390274677254477767965547955941480,0:176243229265077086799810043437704113558771493 +mod:45956761520600045904065879294257993751858393,2754559558487710326209328606488100503,0:1112021195932856302477743058115163232 +mod:86998056199797702223316805148045842457568,853454763663288996214888780372138920872593497,0:86998056199797702223316805148045842457568 +mod:-20704801388339426733036642845379116124827,1435867681437150310057862989648368134,0:410577984280737997741465350352367453 +mod:2856130129221222388492861978859662650626462,3415046666744379998032348811600467386135912906,0:2856130129221222388492861978859662650626462 +mod:9174094790970904280083488936332437588,80223089031357892324412497824961233579,0:9174094790970904280083488936332437588 +mod:4534642237573685930694951916760916917,1687939078118830937441972536472082033553313,0:4534642237573685930694951916760916917 +mod:4953285485878049171718509399492969344,8438715605646215951383851878799856179,0:4953285485878049171718509399492969344 +mod:-5473561371563615410812461706913472604,214334897451541211570930222077036158481210,0:214329423890169647955519409615329245008606 +mod:32314040316433349581573558346471215798,854672171304077635036322002646520921344854,0:32314040316433349581573558346471215798 +mod:984601652834979681176881179524440398165232732,6010771562748020948016078628902359752985473102,0:984601652834979681176881179524440398165232732 +mod:698822785190474223385164957713213782961023671,150442537951079536547656264208689393334480936,0:97052633386156077194539900878456209623099927 +mod:-832138567182782528876254228044578514024849,377042837783032738781722401918006460405664,0:298989946166315687468912977709440867192143 +mod:-271707131793885697341132963275474633346,74513535025253601112542022792779088685,0:26347008307128707109035127895641721394 +mod:44640484386299773856766873434498216561663,5213123770976745902224829213477542076627816299,0:44640484386299773856766873434498216561663 +mod:-8174713099269176537506457338358109028363056209,7202185449263765965193807505095247595858978029,0:6229657799258355392881157671832386163354899849 +mod:12355340492830472409960851629397705304982,6132966232951258768476406645904988676022226517,0:12355340492830472409960851629397705304982 +mod:740672577198687499703984527131597058855628260,62988497968425244096425380714180031243,0:25908678444459756553419138341753752738 +mod:319004336538265669049369604224595570722530952,61211042298242370348907837021107959589032437,0:12949125047053817304830419119055772777368767 +mod:4806439359677487573544166219831820280885,5343125957234791643541038079815655996180160,0:4806439359677487573544166219831820280885 +mod:323024441762812965484474248139147756931591832,5765121910212312442407559411924073985538984,0:177614790923468709650921071399613741408728 +mod:4723337975870144045814369863570042890658212,89287300568064096399722912162338068807417604,0:4723337975870144045814369863570042890658212 +mod:4046612007916961296580001696582058791225882326,5729739966517853346267035412515108513431626770,0:4046612007916961296580001696582058791225882326 +mod:540533121775179300141141525507624112998,4914658151314087364162157813143111418270829,0:540533121775179300141141525507624112998 +mod:66280283111826907749579181590044353153733,204172771634272898466853823821147342141093,0:66280283111826907749579181590044353153733 +mod:925538924182292886302889784301398233703,1123951844806914762874832168405952076336884530,0:925538924182292886302889784301398233703 +mod:-9277230270610927782719268661989105709153,55678956296429757152650874683611007657644,0:46401726025818829369931606021621901948491 +mod:50293591559684931942237588278999569425818428,141131236033928957276244084171780508793074,0:50871531606223151894694313845708295484084 +mod:227536874010521150326799753293426594405370122100,5663713263329817356263170887251834777947840,0:2857369509067856283126068971384036093597940 +mod:-159636069245107191231315124801771805922519,5376563717710166640876235141463100221226553282,0:5376404081640921533685003826338298449420630763 +mod:296211412518831858845632004066852419532092957,9193193936667373505606545836126920558776593,0:2029206545475906666222537310790961651241981 +mod:86602967441811929071383589926953279497600400,29113787967675780279817029258848956369351891,0:28375391506460368511749531409255366758896618 +mod:935808235992985547250049168223094462501588,823359169504337998748976932597778859831206424,0:935808235992985547250049168223094462501588 +mod:1241588731631743791569571581848113730164929826,171962803446046629060145060037355991426961,0:17290751287129755324248378403472062271406 +mod:-74403542912395173151108580799350125207208,117394870062241902513223079179473780570881,0:42991327149846729362114498380123655363673 +mod:-97438192951192117314716964768364222640372905637,8024586066648229541713894611454280576509407,0:4355656117334010314857498525106400180823564 +mod:-737958699044282011354135601107494488027530,158340104707707507507946829328121909848911613226,0:158339366749008463225935475192520802354423585696 +mod:7238206747053249220557962252149262130217519,26583927802751023597693302694515406325578,0:7378384704970801985383919241071609660303 +mod:-76298303799498407827228786401180081621564,305509547184311996384274460275527665616703456,0:305433248880512497976447231489126485535081892 +mod:8484126595409899812717896552747684329372,304175476902105667248597679191320877778921077,0:8484126595409899812717896552747684329372 +mod:16618292546225677123057630920609252345178704453,1759703193372771615772702336566528721798637962,0:780963805870732581103309891510493848990962795 +mod:-86688490323412015602068918712338617474038884337,68055712910244091518751770267361236110795,0:60113101985245418861232982916749058457123 +mod:-2147105590126324395866565651207583306108779,8080551616254563514320925568870382437821720942,0:8078404510664437189925059003219174854515612163 +mod:8351518777266745029929974668820179263529631715443,175331741086869721483946575985451578498971069791,0:110926946183868120184485597503955074077991435266 +mod:-1795087841202144142663615322625965929380012985,35306979241856773462781084288773766694122468,0:5568100132551303938219976101496172020232883 +mod:1223266620160352395848150839920704951768,4664479506170256011858225502160377500533300400637,0:1223266620160352395848150839920704951768 +mod:39982725086518866718673198942063749137891,461771175994919359694841662569213792123219861,0:39982725086518866718673198942063749137891 +mod:357581778914196308302086292874528466152700626874,3109407409714291140644239657248083936467914372416,0:357581778914196308302086292874528466152700626874 +mod:149499532166554918559602886813953835372516,4116995844742979208794059184185312557100182485,0:149499532166554918559602886813953835372516 +mod:30162948061054933954336062823716515388316534139,210277285976133726432524140550436988594139754,0:93296166467811074485110725004026019354549317 +mod:52810485653680320320369005564031524621022350,82825120387123890672981225414839234585635496,0:52810485653680320320369005564031524621022350 +mod:7208022814700388108567430430861339898438,2633586073486065955736662183793128252475,0:1940850667728256197094106063275083393488 +mod:1133096693748508212236566391854344691508408508,2601250202595579849376374699877144432325855432,0:1133096693748508212236566391854344691508408508 +mod:24110493767768334678283829225780182918079966113,62617472892345734441670381366941494160023,0:11535407963705925298902727562240728070101 +mod:2029154393292042830677214368668639182381808222081,82610125404955917046846600049858255083588,0:65547351731225346301018769765882024339145 +mod:950870388742015370309491008506921827067333129594,9135792372038219712944984119888962386493530278645,0:950870388742015370309491008506921827067333129594 +mod:646334826846693204541658068926128186360010,54407099890316510058892785158311428336873182,0:646334826846693204541658068926128186360010 +mod:428552882985823327962705708694562616508577,141639571156330467462518777812629657176255,0:3634169516831925575149375256673644979812 +mod:21509351141318679646739001694607822320768,21896381149810489046647085552887947819439418684,0:21509351141318679646739001694607822320768 +mod:632728454831941197355087764542806015137812368262,222724285350635099362081058306677746403035965,0:191484436137515166777558951841215353190227662 +mod:29001858864232179857863618818997005925607,263069727005942155120496500688512817218817,0:29001858864232179857863618818997005925607 +mod:2833859942689944963761411216780529093075213667,24836085579076290404924895501933094503621863,0:2546186675247857599973129560156319662321285 +mod:87503819229335363919830481339117453040132756753,7265931585748836565776184592881080221565467,0:205142162125158187890287050603931819837672 +mod:3785119298527941754940929232952910144091163,384452066294060303214343786012747535262261,0:325050701881399026011835158838182326730814 +mod:38179577399511020742387225982022507255362,265561978107157383888631215376392729015255,0:38179577399511020742387225982022507255362 +mod:-42541955629872910052396184385091366868620,7073377596138431111003761711368230096543870670658,0:7073377553596475481130851658972045711452503802038 +mod:962822498059104139629105773638997541722777,291785910412123339651738662863457030701079,0:87464766822734120673889785048626449619540 +mod:-610694008008712552303733816313602703956727091,10013831675645158459604313031569589122775,0:9530562183081513694818229700258284829059 +mod:25840001817997722382069756182552718470600133,8684986931293242801082346374758755111010579020,0:25840001817997722382069756182552718470600133 +mod:65515204463103763906150928285942229386532511441,6904523147545678419356084749116545717835399,0:5088839190367063300396186324443615710245729 +mod:88029876839939054322959996030895683781141381988805,87155086119890274408175255450625302996948,0:42833542489532412926993261659835596440801 +mod:-140728222219088662551331451181555518857060,85465120005353614253381442147197316880331584686,0:85464979277131395164718890815746135324812727626 +mod:9386187660146534186830943256786039971200765327416,587965300048494341491681576852042742249853,0:156828577987386328282882864848506418512778 +mod:8015087164840320324802166753130112000577091656,6127305412955855242353538605784472950012242,0:571684694061667803738256764021381961079120 +mod:200585481998602232012071307195117379072828517,688377212094972591154108498471394888446887,0:267713278965207986225734139941466534784400 +mod:-2500594129935211199120603938323647766148423982331,1361156037555715012439087715972060812276689,0:599374805963096380934653500844754016423148 +mod:117111132825449273925221124600613715199470024967190,6687987114639191794225780163327374060501630866595,0:3415351876583013423382861824048356170942300235075 +mod:17302923664832474983271296805121649995183106066,41453082247135300103242413890739246798747574758,0:17302923664832474983271296805121649995183106066 +mod:804590820827842054650903665300245592864154,31922670356859924926370586627082780796917147,0:804590820827842054650903665300245592864154 +mod:1419527821402660938221344683778268760948333788257,28865159616287527805126478593002688908873146865,0:5135000204572075770147232721137004413549591872 +mod:-6349296345256358340236015836865079291052256775642,178072362342080585886203440168430935242413913,0:51806412867030122454025780494135951253706286 +mod:83483775554984848270591505226690350944356856326,500899723948831224438405152518791040164077250979465,0:83483775554984848270591505226690350944356856326 +mod:-5202440839318488047646864687648754749799822,423723177170085295356066936482198199652980649761,0:423717974729245976868019289617510550898230849939 +mod:525675600985546172797713152878987836214364203032,52969787195069967379407272322490869598290122,0:3432861671816524475382350588446320933032304 +mod:37858860128097787570803474618858008892810909590,5748777360917412753508983838083899279156995949,0:3366195962593311049749571590354613217868933896 +mod:45957868400560169903622579655897442394944091417163,62063277048172505864034466895124800993363976911,0:31043384912515564237074153505089659854748503023 +mod:18051383988929839561139635711444280609605686,829384533321617231836740782712342923300954,0:634308789175877692568079274485079220285652 +mod:2455769442319397759077734120262920951648644195950,902538521133892788023206849882232725042383975,0:864664835209375654611488583247939533359783950 +mod:4589658345087491870839566381729330015793440,513428177661658876831707141329481947688426657,0:4589658345087491870839566381729330015793440 +mod:-3573981672918561820060475190255839052046119,6138097283471921734295336167784166932835047133,0:6134523301799003172475275692593911093783001014 +mod:651620293244411254456830208908605775265324147,49737728886554678175954115600491082303192404,0:5029817719200438169426706102221705323822895 +mod:-16650974859063823766693159687850998551426028,945869854077417138401154817030148430752804974724,0:945853203102558074577388123870460579754253548696 +mod:-965598273519770488416791785443027019154228220991,58147062667685853263523283369280759917430291182,0:22901791830889017063104031834745899442086729103 +mod:28701469969197750610229907539580754650086642,3909053247766771922418857228732717683752395675,0:28701469969197750610229907539580754650086642 +mod:-8748391241949190130773015442145843092096091103,42809713885017092071880308569574525272117288,0:27600104479313743962447814616934588687952937 +mod:-6130419437464601359973583052365059560631450,2868142672962642021474985766046232299028848,0:2474008581423324704451374245773637336455094 +mod:95640797562953613006161464063899219827371659541,19819192346118145486800692560690336691790893,0:13194492933561032348122458568345289480600816 +mod:-5004080847919147880779643424152795003888630787668,21840420756428944369875564516044464145680642454,0:19215926059509324291736414537431749617916976752 +mod:2939482810778921033958889604777113454839240320170,566855177384622843277537161088088916192047616362,0:105206923855806817571203799336668873879002238360 +mod:291726867119014526479710686475643665173438062,202885774177743860764627132154911476520592335058005,0:291726867119014526479710686475643665173438062 +mod:8683025332039408014362977905935333328608348,78614799730964514801510410033797138266803757860,0:8683025332039408014362977905935333328608348 +mod:869468342614628804595566251564864548106595266,73624620788538462644074114115939464475401814111645,0:869468342614628804595566251564864548106595266 +mod:4728910553503250598863512353801889257516953314,648895113009231703768170210292430028966664779037,0:4728910553503250598863512353801889257516953314 +mod:760566451760297307988377549048192013905533937,2697105353808446098263423690773776969485171497,0:760566451760297307988377549048192013905533937 +mod:918153477317716353524438631647119722202588746160,40888243303074949046907063669422917592190788906358,0:918153477317716353524438631647119722202588746160 +mod:-1473776558819659703245310105293049377337981709,31054248040311137303584740614306271791161270545,0:29580471481491477600339430509013222413823288836 +mod:905086443229432348861962052611640110347186013855,16319880347082113262021644716353623982591699522702,0:905086443229432348861962052611640110347186013855 +mod:-3948357993060778828570152166999624499401960763170,77670033625089877508398637915359376482388910,0:75836304290184446800990065584763456761865590 +mod:-784992783303820924306757780883007042021257440780615,463574560419641941889185992215306604381633902571284,0:142156337535462959471614203547606166742010364361953 +mod:3823677606013902933129598925384688189274201201551,99529942495899622221328610053601822241548249,0:35805148927146252817712955466984220642119718 +mod:12254504447986771204864826285146960991558427605699,6125051499311360686388425114933437945893268599,0:4401449364049832087976055280085099771890407699 +mod:-2580894945525990910646902811077109168493411986,572510241156643657546678509117136144990147708808871,0:572507660261698131555767862214325067880979215396885 +mod:343089829587091844514156149817937152291781907,43377295017128784286263228943698366029281236815,0:343089829587091844514156149817937152291781907 +mod:7853011116124010483217978861490662971029642862525,552677408447001109928623269020934228695696472,0:17819500571712242170831972208515492491691877 +mod:887815431705947711841094597810602130602260715,8486574430538892118817816797303238023509341587403,0:887815431705947711841094597810602130602260715 +mod:67620759311796073899200379294956624554814285201520,87303800600842937580229698689028406709310049288843035,0:67620759311796073899200379294956624554814285201520 +mod:-38490591886267408374352863050032614782701178357,66475506278603268018635318767149490286581760362179844,0:66475467788011381751226944414286440253966977661001487 +mod:-544395011810833021655729041737889469872310533646777,731611503205277837707380015577043727374026342728599368,0:731067108193467004685724286535305837904154032194952591 +mod:8890962095194591840604729292735591304316116728,517571143480065164208802281191733497859755993101179949,0:8890962095194591840604729292735591304316116728 +mod:40588319468481766273347382652716318465741545598763,1536971037850601936767123301111618687777305090,0:1525271960920929137957640261803777606250087133 +mod:48235707095020151632145028961335649832134676937,794868261145529770762797624857872107306805378170,0:48235707095020151632145028961335649832134676937 +mod:-9523841594085891512065672092684699107288546273626439,473487777070786775175577792880772873295554421457750,0:419401724400630766621461557811531231918096576986311 +mod:90074633895471637214960779532906651648038212359500386,820079595762158387084577717033680869242497989232,0:371415339208611139101404795279693919203214214434 +mod:502553209306579947121167024397370721577297298727046100,52494082558436951205873151813775449908847817944715,0:27356974663013227343342084098339599897137542289405 +mod:5790702792462693399581381818523043045468711777,48910417508813857701976328940621637734412004053009,0:5790702792462693399581381818523043045468711777 +mod:8115756631582685507536476067391256503367264361488762,84450889017264877905314659939101106548473815858544561,0:8115756631582685507536476067391256503367264361488762 +mod:8194219075070331821784044970434313099982993771,652282608320462546135364960046755034411967968039334154,0:8194219075070331821784044970434313099982993771 +mod:75033785162139990322256697516355737268216190660,50448201882288504062521017516515948614320857837,0:24585583279851486259735679999839788653895332823 +mod:-310420971441772166248782136661913235149811988,52251157147894938842540415683732209931823110303,0:51940736176453166676291633547070296696673298315 +mod:-465851374976907401549861928175506333511972756050,404205507663774789620852323466440811463681452434704718,0:404205041812399812713450773604512635957347940461948668 +mod:86727934051201027780798621123886995870064920795,2623457841745489387377116124239592088889194223622807,0:86727934051201027780798621123886995870064920795 +mod:-2164209564341937597697994551840383739114494141322,5822096741927098565898057075974774660691292113200355,0:5819932532362756628300359081422934276952177619059033 +mod:-21572594290097356729450557279398987661535311983806,95173892429181732470545230031265828462190645462413613,0:95152319834891635113815779473986429474529110150429807 +mod:896154498632105428944035878874928031422856104434543133,2920373159440158169043176499665564441266475422,0:603088578315357918226288933626857244348602913 +mod:-28106796449976334513237948147051254770072052831429,8250476728385872623793527898989079209376092358,0:2577763634333516026601404804538096272293832277 +mod:-5910781525258418818015395848760618489911223430349957,51598547888760073234245679451691550056130732598,0:38529590602611260383715148455335218776511681335 +mod:7727963353453460964292856120418469526804141877435331,9692488255114907303703797109203796514048948603078,0:3050214126879843240929824383043705107129840782165 +mod:937009697498591315869575189938875974899784631458,9231715369857992569685209191243252034527233388658,0:937009697498591315869575189938875974899784631458 +mod:190934454146310086697642361797951041146551500749,10448518118997830258656577725632025806308987954,0:2861128004349142041823962736574576632989717577 +mod:716842295935464600709869948911248187992875653195892447,401547841844896246538515909881184133363330747247974,0:79398242324800638619049773334509939330269358258857 +mod:-538446228722400194015060345964154302722009578079,57520540642458327434814547831209263785958735384,0:36759177702183080333085132347938335137577775761 +mod:96967488061013453069137268213397106742518252838974707,4323900098433218426906897807465481156203036443592813,0:1841685895482647677185516449156521306051451079932821 +mod:4248753403571933538992485400308861658493364877663,939067422305299585909602271217318347813010825877,0:492483714350735195354076315439588267241321574155 +mod:-107460187565073890428227205420824162161759055432,282612401032124761876915123928433707969500860981828349,0:282612293571937196803024695701228287145338699222772917 +mod:6649481706449462881752315195565911763474357952858741,659725471155847914828668487679599556025560898493899721,0:6649481706449462881752315195565911763474357952858741 +mod:6305756385410127441079092163742836866873755879,9919320027008577000539126363765101039097548804251,0:6305756385410127441079092163742836866873755879 +mod:-38180683008697554526126494541279186939566773312,4697678019691033242250502480954454444789783096,0:4098419168521744654128027787310903063541274552 +mod:627353070533528810361133250533207881585454632738,247981734193053924842956535127898645616700024063945,0:627353070533528810361133250533207881585454632738 +mod:-977100235060594126432793245647088458561713536019153,711683384963018548537977961275571093400571875056194861,0:710706284727957954411545168029924004942010161520175708 +mod:1498139275498305618541952433970427820083740864078175,3957896946470021688374936335906211866428578229500974,0:1498139275498305618541952433970427820083740864078175 +mod:597201805617750253952058296204205724608800648357149,4978798146323419820714075023507404888549551451,0:4925562548693297046425284539523037059050912601 +mod:-56676822442119009829407208281675487240867001784809049878,6406684614200209335872193933373288202798878241606,0:2690987740863316857560626374071228113763853811606 +mod:8685426845950882129513316465433060160017749608742,5862536885517747336130664930278619887073507404339873116,0:8685426845950882129513316465433060160017749608742 +mod:-758552875949625615550950682460830448030408807239369540,6928982530621565423313581311775944174511467885237190,0:3635202418746581013543261834523411165852660136721360 +mod:165930319304414878413873653644927162776703980852674518,70941371417197323006528137030561117730233179743191461,0:24047576470020232400817379583804927316237621366291596 +mod:-30974844728461949004845422334486602888821195017,323336199778314705263073710488111629703644763021,0:292361355049852756258228288153625026814823568004 +mod:6133073724222023714159452874993644151837626947339205812,7463402457118308536507525382128605388905979122243374,0:5620306927892405686774536266059127545818087977395758 +mod:45342828302867171033162078210088228770176829233725,826633934789479436275857854693648185626420538347806062,0:45342828302867171033162078210088228770176829233725 +mod:-26272751936716551812042161754718676251990474722,3726791277147420607688434457942745910700285747248,0:3700518525210704055876392296188027234448295272526 +mod:-39318997476790646356737814318350583742657677501,1994697821466452959618065249537163794020403205602,0:1955378823989662313261327435218813210277745528101 +mod:8027107780836872755806128697397537471698261298622,1333439935985760787392296885353944866764267524928758610,0:8027107780836872755806128697397537471698261298622 +mod:-55936499409386931117510358618192060334282485918550322,398438202364094320499957997907168092925880758462,0:239820508270537478744707995268231581913761929858 +mod:4986596463362462090356441596215520136635434728102133698,904796510225702345660178949801987674355175932951442952042,0:4986596463362462090356441596215520136635434728102133698 +mod:206550560537111820336709370332003111271041434735753,8863245846520291116010486302557366093750491313639489405,0:206550560537111820336709370332003111271041434735753 +mod:576258003770289338613512178842212632031473801519,112928562274312812079466249863533328301249309332,0:11615192398725278216180929524545990525227254859 +mod:5044250943493799862304047991036206572453520324334513,35881021726135630824830413448736592392545545812443121,0:5044250943493799862304047991036206572453520324334513 +mod:905588871665990684975164361624636275705950128546215874,53243625735815790460446478875365074647441813141773592808,0:905588871665990684975164361624636275705950128546215874 +mod:5991116388159027989458739990542641030328044128925695503,721278676327052740788584942208715418345142864101,0:431868180450652741834416094047706629629986812960 +mod:-3474677351996973979038623915159768162722810109611432906,763685814389121867002329466465821059768201256128129,0:93103473530515821975157259717659222505605771554044 +mod:8460371705356400367952890710394988728910116421931757,6311797752969747892862660456068082967585770509045488820,0:8460371705356400367952890710394988728910116421931757 +mod:-264756559717037431451787362436705748418817738411460,7816554223015299624827224356467518163226383802462318164,0:7816289466455582587395772569105081457477964984723906704 +mod:84752881980947180661815959615676455311403364453605403063,52250068596287507582088091160391730925462299132305704,0:3270717768843363669075753521067750303515261005551175 +mod:64938454622435247872445936607970411171632403906819,964092617858022639258083183616152671542900110410,0:344249225947731042154363305688182178258096509349 +mod:40144089093980612505699952982513757457937212093962271,10902061466143734099157856887908326325446558980281568,0:7437904695549410208226382318788778481597535153117567 +mod:107130104935801948815478025681375166396055326914961974,6641641026382469722494881921027536542476581953333157,0:863848513682433255559914944934581716430015661631462 +mod:375770000201081420238670197853908213239792155799109438568,741847952379716980656595421052880669705080727039,0:186232142856874724410035514392651753500883140216 +mod:314494472877016149904621158951181139298853721401432703777,2289213676835383723493513562354885152593212937649884,0:8739694298587358772241304662150445534814153989973 +mod:491754906560818931573946605055051948215890543148276100,5346198427406770324055146743032112633140429155293,0:882811089383626706097337472163994367588586115374 +mod:831402402931313770942586028473722467913682852291371107996,249203176454681279672468752353764682559981472637056324863,0:83792873567269931925179771412428420233738434380202133407 +mod:-927301671513394245404756806010463865731294755475136031104,128994162476254345599482066271274174336327781183511925567,0:104651628296640519391099724159729528959327493992959373432 +mod:49063903583376380376914162724558461583861450724317254,941774744692403469242853096809411489238020290379296849870,0:49063903583376380376914162724558461583861450724317254 +mod:95814446741364664911508702682923954900446789248313,2444989997188453542574239416826458624894367967952,0:459836851014976751113365426692068529566438498185 +mod:96634339550441353817958772505469549255037435683448,78081012036785909772650615373227006202901241216144834,0:96634339550441353817958772505469549255037435683448 +mod:930319417728873563211760140268194907413484971952354004,89121326206650943149280333205573781193492882117302434,0:39106155662364131718956808212457095478556150779329664 +mod:296149508458734377319788304412051836966914377456545014105,5775874526745986573435749392656102466476051398568,0:3756015598637200337676470424188468229410269716225 +mod:42844020401978935822457442747009223068912783208882,70773879393663215011878508613578824050038059978191899,0:42844020401978935822457442747009223068912783208882 +mod:-90593635206751701986722625420716592016545661236480979772,6587808211180976790034063002169935351319078136248018,0:1903313409090829825808985124358934794301293201763764 +mod:5733125812846132405536083211632006878958607745362254467,12605191511011498307650361584364883404677231252914573,0:10368866846912173862819052330349813235144756539038325 +mod:95998165422977408040950062135290204359238945742902842,40371405656826836301445165513921557692353024588296,0:35334176700018152414903708698661724515806296523250 +mod:95998165422977408040950062135290204359238945742902842,40371405656826836301445165513921557692353024588296,=1:35334176700018152414903708698661724515806296523250 +mod:95998165422977408040950062135290204359238945742902842,40371405656826836301445165513921557692353024588296,=2:35334176700018152414903708698661724515806296523250 +mod:95998165422977408040950062135290204359238945742902842,40371405656826836301445165513921557692353024588296,101:35334176700018152414903708698661724515806296523250 +mod:-76855972323011457703707050993748256077521513979037807,1910956865546821689289334552684591792222791353473,0:801852416163817820695380673341213886931466292780 +mod:-9872019059197505082121902831056682448354872822219660550903,908082149115602660075723278246449391327542696231965833,0:650065987327038221360650038715334158171371214271985473 +mod:595855064966654171339977100486303810714342893653637711,594549781214651234933649045428169123584477791281395609,0:1305283752002936406328055058134687129865102372242102 Index: contrib/isl/imath/tests/mul.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/mul.t @@ -0,0 +1,864 @@ +## Multiplication tests +## Generated and verified with GNU bc 1.05 + +# Regression for zero-sign bug +mul:0,5000,0:0 +mul:0,10235,=1:0 +mul:0,-58382939939929385885,=2:0 + +# Basic functionality tests +mul:0,0,0:0 +mul:100000000000000000,0,=1:0 +mul:102328632557663,995533253464107,0:101871556492663391138178301941 +mul:1099511627775,-65839281,=2:-72391055023845629775 +mul:424417695707616156,78196371461084006246,0:33187923788210071918733291062874510376 +mul:8785533773682081,509516924811454802,0:4476378151193669633826349848802962 +mul:3149810015499242805866,671806182669824281823,=1:2116061842647726364810477474851492861573718 +mul:7004291671016071522932056033,291108610609315306035746008,=2:2039009616651887991790118373228449729743842556412066264 +mul:62479450738832647,8434970263250341371151,0:527012309046267948145296885851102766697 +mul:9472845009207216089,8603477481125780254532680,=1:81499408718909018140819102866811806472288520 +mul:8704164997261749,601100642928524,=2:5232079176009991665860326228476 +mul:-18665805686013,-2922920804055208139127600955,0:54558671764099393911694170691186688942415 +mul:44144326678357949,-81195051773905850760614924,0:-3584300890173486959579517806592053823430876 +mul:9685579959286825,5953064636346354,0:57658883538135357049439528986050 +mul:-7,328492456,0:-2299447192 +mul:16522181,930,0:15365628330 +mul:844378,24,0:20265072 +mul:209,3,0:627 +mul:70522336,34102,0:2404952702272 +mul:32557663,995533,0:32412227919379 +mul:641,701,0:449341 +mul:290748,-233,0:-67744284 +mul:-95,4770,0:-453150 +mul:6839092,7,0:47873644 +mul:787590783,-6789049,0:-5346992417735367 +mul:721,15845,0:11424245 +mul:-37028,-949534667,0:35159369649676 +mul:618,-3,0:-1854 +mul:16657,-544851,0:-9075583107 +mul:28271,6,0:169626 +mul:-35357673,5207718,0:-184132790120214 +mul:99,-565,0:-55935 +mul:9311525,-5,0:-46557625 +mul:6221599,7764515429,0:48307701428550971 +mul:21590339,486739392,0:10508868477933888 +mul:335,3699183948,0:1239226622580 +mul:14,8755508782,0:122577122948 +mul:-5302,9,0:-47718 +mul:8236,9462435,0:77932614660 +mul:43040,2766705,0:119078983200 +mul:863478587,63,0:54399150981 +mul:8874055124,10,0:88740551240 +mul:8204,-89955,0:-737990820 +mul:3303887262,3,0:9911661786 +mul:75504,-62,0:-4681248 +mul:436,2123372,0:925790192 +mul:3361227,943089540,0:3169938025265580 +mul:37340421,223177728,0:8333550321343488 +mul:-35694701,238293550,0:-8505817017478550 +mul:4263,15500547338,0:66078833301894 +mul:1493,38730799,0:57825082907 +mul:-635007,298501,0:-189550224507 +mul:4968,-98492710997,0:-489311788233096 +mul:3367542606,17576297,0:59188929003209982 +mul:232155550,3921719,0:910448831390450 +mul:4860966,700,0:3402676200 +mul:2323372237,867,0:2014363729479 +mul:4268,-29035,0:-123921380 +mul:8,-73804207633,0:-590433661064 +mul:395170,26163606,0:10339072183020 +mul:-70027196,6945032910,0:-486341180815020360 +mul:5871172260,26773591,0:157192364779785660 +mul:17125540,836,0:14316951440 +mul:1988202315,-68060596,0:-135318234527479740 +mul:554434367524,-909419,0:-504213148079308556 +mul:-40457802353,3398,0:-137475612395494 +mul:410791452776,4492144466,0:1845334551267808737616 +mul:135751970,7417878752,0:1006991653805141440 +mul:9593,31047471995,0:297838398848035 +mul:-18387143,50226,0:-923512644318 +mul:413450673851,-124,0:-51267883557524 +mul:-618513698871,-318914624,0:197253063714294189504 +mul:37416674596,-8817,0:-329902819912932 +mul:6242382,-943205,0:-5887845914310 +mul:-4949666413,1501091102,0:-7429900210422557126 +mul:-6385784303120,899228089,0:-5742276615660794337680 +mul:6308,-79643949,0:-502394030292 +mul:2421,136928,0:331502688 +mul:333180111,442438,0:147411541950618 +mul:723761305,611024432789,0:442235840862251429645 +mul:-91289,-9223787613074,0:842030347409912386 +mul:10944,57098,0:624880512 +mul:57145099,-94544476,0:-5402753440923124 +mul:9327105307,88173695233,0:822405340745514901531 +mul:73230770347,67182928,0:4919857571607036016 +mul:4810254287,-4310,0:-20732195976970 +mul:7200253992,9893,0:71232112742856 +mul:-92709373682,-664752121448,0:61628752833224878931536 +mul:-2236424417,-69570761,0:155589748609671337 +mul:781963714,61084006246,0:47765476390121357644 +mul:78553,-3773682081509,0:-296434048548776477 +mul:24811454802,-26314981001549,0:-652912961735421705488298 +mul:805866671,8061826,0:6496756880801246 +mul:4281823377004,2916710,0:12488837061941336840 +mul:15229,320560332911,0:4881813309901619 +mul:6093153060,357460,0:2178058492827600 +mul:624794507388,3264784,0:2039819111008224192 +mul:2632503413711,-514594728450,0:-1354672379322310051777950 +mul:7216089,86034,0:620829001026 +mul:112578025,4532680608704,0:510280230883694129600 +mul:-972617496,-1100642928524,0:1070504569131119855904 +mul:86658,-56860,0:-4927373880 +mul:2292080,40552081391276,0:92948614715315894080 +mul:57144144326678,3579498119,0:204547357129208422518682 +mul:77390585076,614924,0:47589328137274224 +mul:685579,959286825595306,0:657666902604804292174 +mul:346354116,451435163995,0:156356427156803253420 +mul:443946215999,260668,0:115722572232027332 +mul:640447120070,-441698,0:-282884212040678860 +mul:1253208493501,-8521171736,0:-10678804794135860887736 +mul:8507343,62395589,0:530820677310027 +mul:81126006,461820852819773,0:37465681276782021316638 +mul:87891707090,40954510522233,0:3599561842834425768731970 +mul:-767589,-991593,0:761135879277 +mul:86229155,43027930,0:3710262045299150 +mul:-431963821,48986055721,0:-21160203804962069941 +mul:101557073166691,-74080192,0:-7523367479146517284672 +mul:-34269048183,250074,0:-8569797955315542 +mul:7650667716360,-959482143,0:-7340679055874008959480 +mul:-176432105527291,712269105001105,0:-125667137897384071121162656555 +mul:91973525400419,-52180215632622,0:-4799198387886300095948868618 +mul:9054526,-21388581343089,0:-193663465874114270814 +mul:19326311972,3180878,0:61474640572871416 +mul:501569850634,39035351302,0:19578955321989857425468 +mul:-3470290487760846,622612793613,0:-2160647255233400713100276598 +mul:827793089252612,77591849874263,0:64229997108241062748844324956 +mul:19866668332,4414961,0:87710565885715052 +mul:136274450771,8659380001,0:1180052253653656430771 +mul:952660786088689,171372582380,0:163259939044179413638699820 +mul:429415374,9140880954,0:3925234813551386796 +mul:-368107346,2945634,0:-1084309514027364 +mul:2147845929,79983807840463,0:171792896056056736025127 +mul:77885771608,-51236668812562,0:-3990607485089940493339696 +mul:62272695670,208399244,0:12977582699470073480 +mul:61973019,-1405255816878779,0:-87087945439289091663801 +mul:286206733986,212837117931767,0:60915416394244148267933262 +mul:-131938894,1048695278656631,0:-138363695208977699906114 +mul:27109492,306933238851468,0:8320804183177960934256 +mul:-314477095129839,3837918787896,0:-1206937551761766779621628744 +mul:4116345,9101435151,0:37464647076643095 +mul:63853435249810,902940229903,0:57655835504559765637068430 +mul:80076033,14791385,0:1184435433375705 +mul:-31038678,1454704764,0:-45152112754861992 +mul:20638192722,-14267370499730,0:-294452742009605188965060 +mul:8065790684,-1977228453431,0:-15947910839823487636804 +mul:362687955673,99742877979696,0:36175540507397430642015408 +mul:1235326072088,201675880263044,0:249135473000235948746315872 +mul:568009735,49546482048450,0:28142884138522341660750 +mul:849579042,-3197920541,0:-2716886269614901722 +mul:1808291492597692,96814519920612,0:175068872732372459073494427504 +mul:6275712123233717,739880208952795162,0:4643275197065752315694969352877154 +mul:774075573665981,7523229210171,0:5823547966683781965601892751 +mul:2944466357361,497012903828640,0:1463437774497728631346619040 +mul:282862415058866,-6240991940068,0:-1765342052530551975764042888 +mul:571225883598025,189932649930728,0:108494445780794463607647612200 +mul:815309478,-371377784,0:-302787827213836752 +mul:320172590239,777220834144,0:248844807655600692320416 +mul:654332382,7919190746613,0:5181782944743642722166 +mul:-5094673003562,268414312780910,0:-1367483153094548874555601420 +mul:-77841790209187781,35267718271550,0:-2745302326850733800658699930550 +mul:735762990564598234,-32739891496,0:-24088800477857417959993218064 +mul:-5999905013129575,144027889596460,0:-864153656820273314848441304500 +mul:6861193105404525,-4725324526382425,0:-32421364061213996907214475473125 +mul:859748569384694164,98523184164,0:84705166636223755282588018896 +mul:570460270963,-54720108308,0:-31215647812506387460604 +mul:61750383079701,3452251304617,0:213177840547497299540279517 +mul:-1738716695,8560399484936237,0:-14884109500328036282376715 +mul:9953417006786660,90085339160,0:896656946857288287863605600 +mul:188523146978,954842405502,0:180009895153280621872956 +mul:198834734074395695,171072375577893,0:34015130305505499211880376370635 +mul:-102893613303732727,155104650554,0:-15959277935713870085148480758 +mul:90836124710855,-98332551310,0:-8932147893931708201470050 +mul:10512242068892,84377075433,0:886992242016856266730236 +mul:-726835478343584190,29339956106373,0:-21325321031155383354737721042870 +mul:5033847480079150451,-69469662902517,0:-349699687543783241256712189585167 +mul:3869558083241,-8770208065,0:-33936829509626159538665 +mul:46079368203995132,23609959311256,0:1087932008384708532422296805792 +mul:979137194422864421,-1378816153373947,0:-1350050180039492392646639294639687 +mul:-72618673468,-244198092166982349,0:17733341516582659732950616332 +mul:529564016606,376298866055896536,0:199274338952843762914521876816 +mul:554186920892,-629719688885314,0:-348982415408420361378580088 +mul:3455963977845612750,271884481278417471,0:939622973433450671239608280300355250 +mul:-41270780965441117,-4124462824121691009,0:170219801814430998805436931657817053 +mul:47581683736,9394210662450,0:446992360690054950913200 +mul:8196306676684,76732052476696223555,0:628919434030412315441895170091620 +mul:2939970750639,-2013582768244,0:-5919874442628068251907916 +mul:70476757656499,-100957934015971,0:-7115187849144405009597945529 +mul:3674841030712174173,540185467629182772,0:1985095720638163814590166671314947556 +mul:82915322420038008,123799513890,0:10264876609633323785723931120 +mul:466513077506,73565730651787738,0:34319375405342972915054421428 +mul:-38890216282311653,91459939591112,0:-3556896831865504089438972828136 +mul:576595981539992,20909590051109791,0:12056385599118501431228849261672 +mul:956905636477652,8381376662473,0:8020186569762664723411553396 +mul:9187294026565993,54295427509,0:498828056823282593136101437 +mul:8866081281165098,6545042142269515,0:58028875622012459166053127387470 +mul:338772425501,-750860960783,0:-254370988898468150127283 +mul:6750486296504,8609697533187,0:58119645214823136262078248 +mul:736067207074328,329259058372493427315,0:242356795500164369960320250670469320 +mul:680100030114145,52232423165123,0:35523272567534917195872964835 +mul:22697310250913136791,365228836596285515,0:8289712216805950219366224267686882365 +mul:30594845950075862222,37349482121506846253,0:1142701651822614557685156508694964954166 +mul:866936756424,-1765396942933391,0:-1530487499507519421423353784 +mul:6939438360479781,24559856763503,0:170431612152541518812930232843 +mul:927595346004843560,7670228140092963222,0:7114867925545619902286593484943550320 +mul:-357321286444971587,7925597841132985664,0:-2831984816439127983772762412958328768 +mul:6673370692769029,520191499051311630305,0:3471430704396611186160057152801823845 +mul:9013236794945,1008467412252240244,0:9089555586614859880726704766580 +mul:406532185466775673747,9519149309169118189,0:3869840572441069484183117712436347484183 +mul:548046408595014443,777065152533771,0:425867766090470284154159790254553 +mul:23897406396584,-8555442893510156172118,0:-204452895728978731648341501271244912 +mul:54729344028716311850,2026849525600172204,0:110928144981012274062113279423765817400 +mul:-7936445752013,-98698488318151151,0:783315198342695407195996516963 +mul:6309028281362257922,271678876766048827,0:1714029716965733695518439315219557494 +mul:6357785774765671053291,56936125648067424,0:361987689715553942195290680512665092384 +mul:11095109588014,9104811531028000846,0:101018881714969199044361103459844 +mul:-921590308699737078,472826384755153630,0:-435752213887882691328892986497293140 +mul:652120832633171211942,-3387083844442113181,0:-2208787936835953406166467995677302807502 +mul:32731949302549,335896184427699,0:10994536879607092557766904751 +mul:3635516318567409721998,16713986701316425,0:60763971400954533716595371769881217150 +mul:6746198240933100303896,2007405485449,0:13542355354775500078274959306009304 +mul:-19072614334803913032,-240759760944833349,0:4591918067840391824783380728329304168 +mul:828472954262165857,127978158379025077,0:106026442953302260750986298136195989 +mul:8306750095431507743,6378030328941226919,0:52980704043597587430846783712468533817 +mul:7938532173109072,7646615157112938170608,0:60702900440124541070347993363328555776 +mul:25274397567311,3125247753747112,0:78988754224550174717491855832 +mul:400327281633151431,37147489147345586,0:14871153349853852722430493627433566 +mul:28164658061513141691,818613450005821036296,0:23055967903969532636848840948464301816536 +mul:476291935913056166817,170589720180888384,0:81250508071821874441129615756761553728 +mul:84130837655605609,16051948347568699941145,0:1350463860485469013094700782617631882305 +mul:438146043336536562159,-2206822496905640873917,0:-966910545365262749689560255553699552306803 +mul:8120293725815373571,24028314574527126,0:195116972081450718759827878362986946 +mul:-667658265953408,8440015504605457600699,0:-5635046116424757633428637247402232192 +mul:53314441150262832895,283247085055963859,0:15101160047199676268547968068076341805 +mul:6658153298145442,2140281300389057549,0:14250320999144418995877331910041658 +mul:213046498706732967,784948480361985741,0:167230525406291802914352434748623547 +mul:-3857522843819,419578526133778265155,0:-1618533749336956944635887834826945 +mul:-4948941087660882967,-779517282262677550602,0:3857785106731510951136294197380142396134 +mul:4277076043224464,448010594023993,0:1916175378810781677476700564752 +mul:-644113523059324254840,-71225587742718143,0:45877364252933205602125580469623562120 +mul:264902435468141506,-823887292259809475,0:-218249750270876020336340975899569350 +mul:1538706915662950684,448326823774496344436,0:689843584219022500302744788239345794224 +mul:2036808313025110180,30422160628736748027,0:61964109668796220999356441366572614860 +mul:7385426850078311,9871854919284839,0:72907862380963907579111265026929 +mul:804644713550364054117828,8379163811459445,0:6742249864863361798556496920366673485460 +mul:981008037679996757191201,-641409668917881464,0:-629228040654107304092567432937180101798264 +mul:64201713053871850,879119102660231895102,0:56440952369169517073431323344150678700 +mul:1033957429367195,1113485105415049436,0:1151296197233604656037339121652020 +mul:14455075580451942850,-1885962875546302716,0:-27261735907948286986307866636431780600 +mul:2615475057635555327591,71606675442458157933637,0:187285473579953754910128144228132079173078467 +mul:596676024530775,2621192750454214313695,0:1564002869869908372861756951031463625 +mul:71665682789483848832034,351563529541544408090967,0:25195040388475655750558432995602321242575636878 +mul:5092055214749737510271,-1833800774226189505,0:-9337814795210574311088704576082129905855 +mul:600508413963341945,5057063373752305154,0:3036809105884103889579068197287884530 +mul:-92318043858914149,958444935645415778103,0:-88481761605267642819033271229511079347 +mul:385447683586530283,1775981280157037775814,0:684547870529570889684189390051875975362 +mul:80717517906672139,362327909576030289130356,0:29246209529290308450092391020660324351484 +mul:31249856290116188,7875872084416640,0:246119870797357830310409800568320 +mul:5339381130045070,-287550419156538713298378,0:-1535341281980973219291224752615497896460 +mul:-28993892995370333046,698005135756870427,0:-20237886216353643864566444205658230642 +mul:9179674525723481348,81469928617693608886,0:747867428344352459523920577957828058328 +mul:7522547789649675160016,285918417200326088447794,0:2150834957330446680178114494867165936012204704 +mul:-901774653467788803,236000195734098992,0:-212818994726447447848669649751186576 +mul:142671415131788790,-2583777714764598301032762,0:-368631222951444570172731660827393454337980 +mul:951078283105727024828,1487627587101952300275691,0:1414850291441640178530450466337072693601856148 +mul:19185476025869672486,2445736876347152429980675,0:46922626206743672591769434078619109559208050 +mul:6741226163186521681303,2568160083399218078514720,0:17312547945462088421236893499979478635434280160 +mul:3987919571578399660412212,9884144363611069680876,0:39417172755950910755988046816263833157453257712 +mul:99431631881940059268,-291965406586754754564989,0:-29030596829995156232729757591886192217768052 +mul:36727416735327035,-1612205593089728906670,0:-59212146680431557459581110615442823450 +mul:19590774006340220367562,984968880458891391,0:19296302740348077288926838014277057458742 +mul:70695613219926859099201753,62591913993270611799645,0:4424973742363186825608316839246937058962268777685 +mul:77425442645246583405,-296832015660977965,0:-22982350203831985042851014697239670825 +mul:807971872592227526408,40230405885131399744453603,0:32505036378154987781247713889763216622213248024 +mul:965370212546292322,92058451234918953535616,0:88870486635336197062343410079373774340352 +mul:418561885926860582,239657399821326936,0:100311453245542262612436139913236752 +mul:4657697584188823828175,78713797195009784682708,0:366625063037526091489561582727843402285697900 +mul:-38091455008728662,5763777114003492300442812,0:-219550656618403959076635804481627756277544 +mul:54943065861736600767,6268390929335695219433,0:344404615677603400985934681975925581105111 +mul:-697639190379957186138,2936028900796584636,0:-2048288825283884939792000285015322975768 +mul:96018089280939789090187,29566309848085271814423786,0:2838900578701380961562729671686086004548591987982 +mul:-1112368751522257152114,1995174854903534746993983,0:-2219370162417645509690181099382354083873730062 +mul:-84342841213955171500540,5699084396809137598518,0:-480676970345002579334276102870293770140199720 +mul:225675029492277024520800,92998377812004114915728728,0:20987411655457949896280985578493804059256993542400 +mul:7655269162163547244,594548791001649285,0:4551431025156545678791700910016320540 +mul:17608380663675562604,264448308193844308642824889,0:4656506476542203967645749547080047894928850956 +mul:223093179893694063251643,17908241494426478956477995,0:3995206541295803079022953995876886965688677095785 +mul:-9501451313199296478183,164266650410143061944307590,0:-1560771581254303549338241248628058185171476308970 +mul:4558730178677382262,3122005086984557462,0:14232378808020807989791594528678539044 +mul:54440882483631228680923933,4478571958703194374379,0:243817409698246737082188977425300200477623112607 +mul:36855929355558415329723,308635436762628905,0:11375045853945367585945011810669865443315 +mul:28683868680975381560,42902583850929860163229,0:1230612081254607193977374775224312156657240 +mul:24731088466679335541839144,81462858536522998396,0:2014665161215334180518726488874060847202013024 +mul:-72335534127835253275,-227166439208550011362,0:16432205716068881729381218555965397710550 +mul:474777034176054735892,839001319154604024448982,0:398338557978020441829154570519593836838261944 +mul:6299666296143449904,797331145004636509,0:5022920141051174455685525850770945136 +mul:8540885149755672764459236,41765710483565552588310,0:356716136438079846570195465527416281897285131160 +mul:385990739803366398,2963466700114736836981086,0:1143870703959928224960974233605962253948228 +mul:-37246197932269024,3005402223074948482,0:-111939806066730874158935454164421568 +mul:-751622018429096822596,3003864133422104297,0:-2257770423049491832679123307914818295012 +mul:-6108319432277782804,-82931541043539126216389,0:506572343704992558730984950135146447174756 +mul:30921518942393713547539642,721143788088068568685,0:22298861303554770289882384831917605974237310770 +mul:570903751254308471830202651,-564896588437884119958,0:-322501581409949262735089396741686909437933608658 +mul:1054271475454361570597270062,16484741384321323400,0:17379392621732016481140067393169300655040050800 +mul:6529831639822170310307759,85346429845722052312845786,0:557297817952459046702350223377401463955562766253574 +mul:-754058902141939454006,69516695016006129145191,0:-52419682724305615903366455441899934040585146 +mul:976193241125104191848393,33823563038032982713854,0:33018333628496693179640404511073605465668736622 +mul:2920092456500658009757,8895875497550350532901302605,0:25976778934365816392930294156133718389132099516985 +mul:9994369499844252132394601638,93334243646132127297454621,0:932816917987935116609350111907831170748502078677269198 +mul:569015432462996733746,16322837154963292812416483,0:9287946242754509292015515862839485902412735318 +mul:192500272569416024937360278,-235265435750733300361,0:-45288660508178593749288683427056889794244460358 +mul:5267095375035104443898399000,-764192677627393558125306,0:-4025075717966937142285931052847299736560774785094000 +mul:51025753118541843018,-1664207936338749988204,0:-84917463297539057165628056384027919759672 +mul:-62402848465899883613105,12900108782353988220438351,0:-805003533538860189408921682314395887504788189855 +mul:-8212641700259728565,297115088713153106682478,0:-2440099767342009818056382435156531921584070 +mul:-5313586393962705049080,-76998532453336088964044527295,0:409138354399142425739761358816694829939838374638600 +mul:463290189242313601142817059,969769350842083604500926,0:449284626073024525963512524360298740721467414096634 +mul:1917277332460964412252,-708614825339303498360550,0:-1358611142068832022550567351649418376333458600 +mul:99562752968815530108,23844471852654970991199350,0:2374021260737762056439185654671360472955029800 +mul:3003923448532254675001,7732856831499478812681071,0:23228909960284118604870886637597256802569606071 +mul:5794073936773633607324540860,-76553654622431077040278132,0:-443557535012598304414911912958839564575760243598473520 +mul:-644932980169883872037968349,42642515095105038480,0:-27501564342225351457715028479060110852667069520 +mul:41892582203464757978762451494,68041907390182959305068217308,0:2850451198623775837247177391258991797607621147282401258152 +mul:-5550794996398648089925,-61773015425098686639107,0:342889344934094297210650346841878123357696975 +mul:26506218374693057900,-167675112099207386871,0:-4444433137302729109790367830963302830900 +mul:145568384864275126584,40072954892382195328941863291,0:5833355320423028246614959434448834158605847827944 +mul:3161170925861501561771687,413220145707787390821,0:1306259510591710846827739981054213899841485027 +mul:723440854928237000349411,-71208223609049472714282072,0:-51514938165651820551744112187918120977634013059592 +mul:94994080481292730137,4307839512004666207932600136,0:409219253303864061854413637026462925940577498632 +mul:7821178378958515500742,3087104738440174209004586,0:24144796833868673714228905443995252515164402812 +mul:869891649236864909625695,991848579874131467931448097,0:862800796939950559315938082847205513561495590052415 +mul:17628160996789341122894,299337591195948255548811,0:5276771249993287502058785568793774940966579034 +mul:99527056994641754235498057471,655773087035017085668857,0:65267165408886313115258469743139728285489416260880647 +mul:596721281791001887739,-328175786669349585798669238390,0:-195829476074104675040288189805440291150559409100210 +mul:266802917073126657350936,148259550527207353925931727,0:39556080564609535241696861668682911763097415546472 +mul:297095531532857951877,8071469565512676957784213778,0:2397997540817274789320989692996853463867804361306 +mul:-64574484904487858142015156737,351049851111701482889769,0:-22668863311335277552737854676715612712147868228723753 +mul:9213606993296693767546,-974475310790221342435,0:-8978432538291752468015873684497297955614510 +mul:-6506246525097752180174,-95653949321972166356216836249,0:622348175387957895590333791334216293967024502327326 +mul:7211807452760603826715508,25981532388511222064867790,0:187373808913606243431674903539484028735353962687320 +mul:244358078258267292267766114,6788410077941126965241803849,0:1658802841074748272013529977344553715539817794996972786 +mul:-84498071017578145227329893,51359077717175899950414794158,0:-4339742996343244440353286358071234877760977371555165094 +mul:315675121566194900458712010,607326754590110945679173086,0:191717947085635889541757875305524761525955701416962860 +mul:3336777364604897112789890,24326442512123908471776,0:81171922735817348191862980575095189973683144640 +mul:-631164366791648249399815693437,224085205047080377284686,0:-141434596550917146771849565583627819691166316250805782 +mul:-9374071452933990971885163627,-8124264246742383054580586,0:76157433551480046450059234199385450235104896467545422 +mul:-8986611810629266612086889,39090932189616079255587,0:-351295032903711635666432166463380265071682698843 +mul:131042125952122412011234961669,-603299752062616670818260436,0:-79057682096673636704088945577099341952975178863719227684 +mul:-5931135084197112120929525527383,817854717051260202081870677650,0:-4850806806078831488870903900854502497422338114185819841089950 +mul:37076034350171687718404493,6575825691817817445639700141386,0:243805539230578902066220627976270126208617978926437647298 +mul:6586877468189252639017707825771,813151310907233772623665199797,0:5356128048043411806613358165516537614499231407192441180568487 +mul:2933337084774328653741904208050,516673656644156545121601676651,0:1515577997760262602679690085554979355436376363966312331240550 +mul:-9902991686684787357658450,173313993122814232472956,0:-1716327033081373752497961221272672144589109878200 +mul:9274522469490915283112908394363,44864081129175577116760112,0:416092928505602244504563614588785724831758965222564048656 +mul:9608655195311416270604257657,65867528105907714734959487,0:632898366137150893335309426569727530606624485604541959 +mul:853239911600142024011098491,17829323361272785163230303,0:15212690288662738268179355293062413175232317048772773 +mul:23972081642808055559504902,-4501717580058722285684735,0:-107915541362031999704526719592126415237678659070970 +mul:5314236376598680151908105,3994830160691915764873,0:21229471758282529614266075257916580301482995665 +mul:4935319583093232012062136782,881389216056886912824752493825,0:4349937458332745712903267792817007035077166975812760371150 +mul:580231659494763900889556,96767644291944525456085901,0:56147650832913989511127904567807102400387849749956 +mul:303622305001319462939309066150,-27984889540977885375442171280684,0:-8496836667639022536327520662086169404630681920995637573246600 +mul:8908131273613694428163643,418798812110676949375564324,0:3730714795515386967446577233797553865021052144672332 +mul:604960317372762640669451812,820482420778387317631260055,0:496359305672865772215202726749222319854411791662969660 +mul:3125355862613621420823337,52123353846012574000878521623,0:162904029521719649924422263486125418351967284017515951 +mul:35876668588605457895900,-237986271303986771473105323,0:-8538154584211078670353490608427234416302669875700 +mul:-43001262189486935668928474222321,75601013836677651900921245468148,0:-3250939017782005364312622194873995196088464819832369459876131508 +mul:50360054222226284955381499,-7538629547593198554710875138,0:-379645792778070687264466482409787805710036592944271862 +mul:16303655607623383537122,23252538460647040924816117157,0:379101379065406527294500251303186510479764610602154 +mul:29876051059586965106021953,26235768232838079362376,0:783821151311760139992194729309972935608098240328 +mul:29623076251397963944271763623335,47441755805615786352682527,0:1405370749729958481398420374857049608464886735734463967545 +mul:9892811422980328964557595259,603482574014084208448431822759,0:5970139301776104093120254749814895923385575422031146699581 +mul:-2549498483308845928405350,2555383871703609992631017913548,0:-6514947305180240206124780570855709347291338943800681800 +mul:-935906971037827073384146870,879641356065373793312781,0:-823262477154750723009760282203349336801144752145470 +mul:19597038710644290533555897021,2985160892106475439715913026,0:58500313560112043537702497574448903543850923995448495546 +mul:-5608937456930306694772980,836399586633606428927522624674,0:-4691312970430260182524580697490183025347068206176508520 +mul:7718522069758342120350478031,7389561033066750535580836572,0:57036489919551968141273365317951375124662579683087349732 +mul:718875898101761373218778459,686314096776480574628984874102515,0:493374662700091643313347796063672168629137876643552239724385 +mul:1300200863593962819188902,525922101427424561614551608409976,0:683804370459089120916221427942950472299573480614205286352 +mul:539220635752920237029329058,29487916769600117002583914582181,0:15900493227532973069876042371837383552914044277544832315498 +mul:5654437789656914341120143121414,6765853316633901505298664574837,0:38257096672850301023676847185295792977091707859763702380259518 +mul:103114174998937498500059583,920095995082794389728025430890882,0:94874939452788796816569177101730218978113456477925771422206 +mul:29882936700790118228421849,-1860889369990333700884198092,0:-55608839250594344207705038774209133311036319056912108 +mul:8909623809613954310018698,-462806578041198407432067106139,0:-4123432506961820007043026316146032423296431299840587022 +mul:7230230288816368650543810,22162946284655819337870476,0:160243205516728709182606639762736983481104743553560 +mul:734442358589456361847988629,1647427465162259118128391711,0:1209940513118819039348215846845414818873067603985854219 +mul:47616626651192848094181030316,2182277257935167463613810412,0:103912681440487744288228839398232844775482481328848450192 +mul:294703827229370598691617,63046555168872062038888853,0:18580061101894254060770213008323255399294285845301 +mul:-533653415261740333749397,-51216937243134223196656339350075,0:27332093479044801759907744737948616465079304814903154775 +mul:784368839220787531616946253680351,39613735771181195550018240677,0:31071779944040382951244796866071327091341523727977793343837627 +mul:5770744507580580048400572,231937913382367374762373686161,0:1338454439750996843543440906327507234975603867940884092 +mul:388816489715059942531589642,82051838197217717225950877,0:31903107702510265086302832415272579698669593814016034 +mul:60241729629297025142644618709,85181464884435369517497693388632,0:5131478776995614297555781224894400552133266197008401795116088 +mul:1560786485638020475934392460005620,8850527081981124295638445,0:13813783060329443326853456039031810473529482812666188060900 +mul:8296622334734688413856037840,-83875508267086319614619277276,0:-695883415225932360550627205972534406741559721529708123840 +mul:-45794179084517723375284971259238,-49063790774577780701852303,0:2246836021296323435311993617164824492625064891225000325114 +mul:1752071933321291709931075226933,57773126045256149501100162,0:101222672644126613791673432521136796654007466067313063146 +mul:730668796977177255106481634556,938608337106204028806933670639254,0:685811824506138940332211187860302311716319126763710711336461224 +mul:921730456287198291208119641693911,5458708493078803375257300,0:5031457870064330030425732359718797657583243087557468300300 +mul:213400535376420556914942871216081,4183995847570912793889135547893162,0:892866953884353287726737673843872033409506009951957939872404338122 +mul:32806047880829491896013320805772,753489056993475245589087354,0:24718998081409010820901165463298804748196865416365375407288 +mul:15218771998961411533589410518,23457061020403160442042221,0:356987663435240813815179640133949762707316007457480478 +mul:9046617676720978441798060,7479379807328977629621989162,0:67663089575892274970250788865795328564433781112625720 +mul:2219170169044655639393672927,-5391273013704097527490654785062,0:-11964152245187612169646728984856115656974060298999913416474 +mul:277590531551034474232270111103,579362077865358674190909581933,0:160825427155156738840764040270546509814277905470205191502099 +mul:51422590325724235826789079575,2121952875387495603452158,0:109116313401543756339172704192689685091698905367472850 +mul:511034032165016743768820348,458982236103828060996895790272,0:234555542808254978695571194131402867112895172492654054656 +mul:4440454508740215531301617636697,3258309525326637800581711028116821,0:14468375222607860310511042523813260258037478238688128668452580237 +mul:6330009746329830092300048092,-6167250670699283492360751201828007,0:-39038756853585645999814749830700965509494204090781844412512644 +mul:-9374602262965156933926707655416,-30595740075402425097079774283,0:286822894147961315557763521486314502763707907853113422466728 +mul:83645893910576549628700447097824,49931389572768584324081547829643,0:4176555715011469153471691311085610269167538819874387285307996832 +mul:8030747712125824227213267818544,63329417394086865663449328880556,0:508582573847824473759474520875716327252822949675048995657830464 +mul:378845361147099357535431194,38180105668041356349238612217040,0:14464355920443542823460702653769947519591239573552714345760 +mul:25958762365949818177158173188075174,40582859445868015162861781,0:1053480804486029724349686454924029433193919106275980799524894 +mul:95871031013239291309686124,64936572493882710890460913285902999,0:6225536155454490886042480192744349881519233810545112600285876 +mul:455128054133718561191432952712,39088645380524987234419335395029,0:17790339110761304357582067458548970370146644724724054396868648 +mul:1307047523348091088814812136,44132853285705545682051355847561,0:57683736585366097743814172916945483114493512756215268800296 +mul:1418285824252402530993393665755,636810955908181043849421782278,0:903179951493194917152704617449910466299855863874287914489890 +mul:3071172872783184341780369192882346,-58125204065109316437571977973,0:-178512549949750604044117019967590439630943828607057692292564658 +mul:56958148205198214736866933854,4922289245511311172745764679844,0:280364480354686563048707584335842453616735148517258235038776 +mul:4836813580368584281452577588,-5400032605107989894617874622172581,0:-26118951038819470026364723997465834517846139303988539028714628 +mul:493001845960066187429806680791,4028800209124423703294502145421185,0:1986205940102641576976415454897329744147895770653902923543957335 +mul:71197215106470682909632132625,70077573297929109151274279,0:4989328060232124924682056253101608707528304143079252375 +mul:486722080146274783096432055886,505595939085965376271620470551,0:246084707185430303071142220010478564391091338964955649213186 +mul:-194536785271632924316130857883181,8276525052027013498990299177664024,0:-1610088576841469642302988316918048088947156051499250583217058380344 +mul:241211965193448971857220311,2710726738427327769580581757190,0:653859723678484041534242084550730982398579984949338286090 +mul:667013805494915469984846976421,118549400818390788595763048,0:79074086979016886300666397440542951393124558234159091208 +mul:507926799850267721181735296662204,67253859677995358015731931706714,0:34160037723823138942875018762752046517503606503615202081256837656 +mul:448088677681619431331494894631309,779948091351174817338856782981850,0:349485908913850840791957607115202038571061594442475706481388741650 +mul:187408370748924381155985806145,495794563709904959946586644094587256,0:92916051411047078205447640432962006059741039970472932758203488120 +mul:868633158815673181555237006,836615025635832190680248872,0:726711552430708313445938158474307639167624319024157232 +mul:945386362083356835627622353491,8230893874122803805176630038821,0:7781374816351144698349349350957993282560652485452042714874111 +mul:5596932048341890824814087121,-2850793263280920843358756089,0:-15955696178454147555303366966824500182482049050635229769 +mul:92079468846004092188293849,65000203344267255501708018874742834,0:5985184198822387758738668838849529371861013959766705099028066 +mul:284485059147524530505559245415623974,-52174853366891975161102679787418,0:-14842966246093682947479966058631799163262087269510590574706144359132 +mul:225019940499042054289943285,88057001889802818516938839002453179,0:19814581325767463952213083138864703402608880611447063777953015 +mul:267625311635136684363577960127905,2364801628264216400078340665206601706,0:632880772719489569595591177205490383145217286350462293583250151205930 +mul:-43414374537943144129863577734786164,-7033210862612719519352562332,0:305342450593798787132468697152495746155227469781974603501174448 +mul:32883132771659855270849300682688,359989040176539024964573548207106,0:11837567404467526702781425500654503476701270135055701604212780928 +mul:8225754994306229461538669946760,79816684330375527507314556065816,0:656552489759550261552969973902237676399765161631722139775956160 +mul:7425838080456254658426507595,-1772612320788255147892065709861,0:-13163132073595363322916797538873046375619972048032782894295 +mul:1660461221569443640519526747903779,1120888096894032723781619067526671,0:1861191218611314482654724970474950053651690424934372619599424189709 +mul:-11718764104457037189982579964973,581785925357694644406822708535571,0:-6817812018560073163564614103438500661271133223665021341304554583 +mul:6811677000322905212875962023,8457366124986245338105030092893823455,0:57608846316878860294885890656152159404437095902874498977846649465 +mul:234277964462994083732538315234,60350281492645017737168270090,0:14138741102865579012895614202346087042625169063690873551060 +mul:4183588612759663468880479337,-629574038019737820951243554610835051,0:-2633878776348494576596482359410905898287329191507888206720841187 +mul:2509727174403533842481294816277585179,366325095871570289922697736369296,0:919376047774859744204436335735246570640422606903982773682501840263984 +mul:9652053493694317708921453500950,-91539642994112368354952933916454,0:-883545530972852858614086011262208634456937177997222533109631300 +mul:35148593969489612322148628595,-82585065708416968121031576511657,0:-2902748942528768024032450841226352229253814757005116581031915 +mul:2800741702103544119527140802733199,46761480207188283686223358035,0:130966827668361702581651174249923174168745185881158323957903965 +mul:441336276433669766301405280032,2656936104993980830437872804,0:1172602287300221361851343901576358026321010825668017049728 +mul:19746122571650880858695931178058857,104545112367422664420669962306,0:2064360603074142331524120459909153582079341868724637548439444242 +mul:74432478600289091913597803372,1021411507303737809729230605483660893,0:76026190159474490029899083115858462446496838080724392481739931196 +mul:37218119790882940825047165121,-9786692593914842780007874460688,0:-364242297316869514078703840625474873421751340567491159263248 +mul:68400175404962139133336849460667620753,8111497426974768586772111911266,0:554827846801973241521975237100547882976582048728649063209959676103298 +mul:-36411507888779255237781266679960702586,288273015425729999064058691683,0:-10496455175296151796260705657513107808386313037221881095512634792238 +mul:-93804297004149089553676142929158,72597578405766612297542242292431,0:-6809964806556531666828055851398144826196098989021186645152603098 +mul:-82026709713179475197473688526642531,5827788603588390535677091203646382966,0:-478034324056320484117325267961249121989480834362662252362566162209526946 +mul:545760067487517393173385480028,42151112506666653978439280505,0:23004394006312331510547051427125022225825594077610367254140 +mul:-697412421088675986809554647004214,6926944054264140642234974161460,0:-4830936823630163298372038105376868436739545586561249485736392440 +mul:57812799959867792819685059219,779735108345604313576941265627654,0:45078669840470262146069880262711457187904686148856378194042226 +mul:1472311567166258003445083977221663144,83378953824849274359711951741465,0:122759798174546897063619713853094843283254982730610656163694407065960 +mul:570337459673916278308389115966167469,6333660822968779197930730584647562275,0:3612324024208219493962639588959668872206678635128690773184462125256631975 +mul:-388785693105293562593219349398,820248784628021659491960244881371621,0:-318900992250380064850834487637248605290643186101012034699480634158 +mul:11679788667362042415563834445557578,-5819547639993570526822921884507,0:-67971086574770424077123666817486620774164160205639229582134644046 +mul:-3982959591737356792197606403519482273,-333248358612381656382679653253,0:1327314746365915910353403610458733118195746910957791963061720284069 +mul:17221610285774362123428353448280602,11458184790118982447972303969280231679,0:197328393037816418804445305069398144307419769226493492273326450761590758 +mul:772738633297996807166456840381926971,785759122171938805714543081571173360415,0:607186430168577693296664258953260658244617930008242877365346151059192252965 +mul:125784145401376536208808801528812039333,452055550313139515567680226389953055,0:56861421070087227190049678638474498681709153815504817562127254516683512315 +mul:32903571905950760393177782893378791,6631740924411766007832465757451477,0:218207964368018909275497254276866261100277667630506488424913763424307 +mul:8742677352155721160009371273251,25083360125803108633092433384973055,0:219295724487824718593455764107115931859507036987734897375677251805 +mul:36273669132247708836176424212020,533102320793846929600697481505030771,0:19337577198109381261236591896304826004083902938845516133439528067420 +mul:11965144674509690079804137520044857,9349045655011350274674885782216185552,0:111862683830807014974569906953845003630437520055543213513177982475306064 +mul:3321305668226664033356712162893,-403949753985171409898849824686029161,0:-1341640607589716272160331793818630136041627867704613639659980122773 +mul:7395363159337411027760652209127419265,44729331460301249556947662501414682,0:330789650023303701714182934884591650253917627482713804287730858240648730 +mul:871058047335719958990871843414,28094200616974302760918376942978068402,0:24471679530879615091124208710919171690581838289918159716462725204428 +mul:7704699734056436938779166257084,546898541513497897846722209401,0:4213689047354900490455012376163453543698919981174872047646684 +mul:950290435067652970604023856243611,4001208123591666075058892234775,0:3802309808564151732408385790073534886035212910698424588605772525 +mul:3119293215232541154035748455321571,808684220462127868482572087900610,0:2522523202153131986496862299093703760338669354068320189935837058310 +mul:432360858532087298548744564083197299,240846574096518547683557847064319535,0:104132631550882737065113576806715978014672912813529852776264204584935965 +mul:-310788798729818682147559678302,-2172955391250831365155305151397888,0:675330195740329036485433048145632383792009398152531758882226176 +mul:649283478652713472152371045373000641269,9179675498867400603641823155076,0:5960211640807708792849652271953975864417053692073644908051640832431444 +mul:79980532708199255123596245351024866045,35273005660545430889304120342364,0:2821153782949751307464444766122322349363016295719088889624882638630380 +mul:-83351007958684418946822288153831314277,-51634644710916030743119182132599855,0:4303799682243404417092087784805566131916079838838464861475411381589629835 +mul:4992915740405389949821656927954249501,4523923119542484578579105473053048,0:22587566951947525817523244050874662178528093089821507414350736000529048 +mul:-801991401381703662108108758716412,1462655905419442096496214673085035312112,0:-1173037459326562975110029005457912568568341236188108696496766994916782144 +mul:679369055865583831572651301119431385801,6364653911974833953564963906049365,0:4323948919089537646576384302944771028193868888345656961053886629066066365 +mul:32178714589413433072024739357148883,2182815001928827996341206621079833349525,0:70240180948557688497445546843414635161913878682156096078900633584002330575 +mul:604754886257955637472038235002006997,75686581968330008368600832791867,0:45771830269510850321052484315153573724518799356687777800355778693399 +mul:287068066584060661996114628597630371136,52011890293701406927883275870768865,0:14930952785995133944874986127466642449246463907028312778992290363623480640 +mul:3979837024286745384581666788748758,7350136706945206821986896298939283,0:29252346199869589826241656345690372038181000414430037048634183660514 +mul:7385865195603313817759905903511277,1520983986703891701713359953638,0:11233782690466247146504034010039435409908987896556224062130175726 +mul:764457193068206149728854992613,27858021258550102776458498820919,0:21296264735745627187463264202183322605488975579352986954871347 +mul:-4155789385717252736363125208379519,513716864065732253356348104577569642,0:-2134899090948322867217472161243561749004221362611724116686910188962198 +mul:97365354260983249124725672833811771,5020029690975786355406829440294084209626,0:488776969262511703376009046688465573304498084561257966650740834323390307646 +mul:83139160308299020652846789174256754,3913486804605023733190361150860684,0:325364006812469954155078345060732025916284724658136533980363100059736 +mul:-17691166446369130975076403772363811082668,94600134419678935394632555907142,0:-1673586723867433503807220193308619446302933297119631426540241369893614856 +mul:634823647473707443708903538054380,3956996255499668253479385484122050809317,0:2511994795956101788922355113644864677876582447280810271598141786556658460 +mul:-3637804742599340390876015169076139565692,783241759542604459838225899706055858717,0:-2849280587465938677344529171806295752584262014073034029610817921718004492337164 +mul:585812248650822285457691267576462,21534520461947113931625020852108318,0:12615185855430383092677209963435811738114410942221928457106971210916 +mul:11281432653044672416448534028211038025,711109480140515578563170257201359462,0:8022333709146834455095073412796362253303159149746025747385289864175542550 +mul:676293649029453415159585825583394,97280549393475973449516311017466882903,0:65790217728903847286239146189723168106268785797184624412977724659312782 +mul:-60552656313655809329731693060696763524,493007935144068742422888317617165,0:-29852940056683907903878516926766558721475796609356660329816267168289460 +mul:499127054152037037035927375386500,1203956412395744650060889503126393,0:600927217446543074982206780295985557213897685478460386666725894500 +mul:50094686288665713475507184834256049095574,-832478827433992238527275985275884802100,0:-41702765702262121589947986555938357521572244317029059068815991395850316975905400 +mul:3587136855297236649460183411772356035310,-712398604370738955166219235841134498742,0:-2555471289400592763904206892884230251721266867884706454335385263422835302580020 +mul:-8101551106022390770336067301182994,9185799272249263720169676176910186035467,0:-74419222253790694721684461955969753328255728462706287902254787547941248198 +mul:68680574795029722620883183609775450677,-84158462638889794851250260034014551972363,0:-5780051587904985041122626676950144438458787116758152359160332249952887573639751 +mul:155258118178686765062886673806448566,-6850017870177195667059084688029341396610,0:-1063520884014087259630275993355034425232292561277443357397796113750571761260 +mul:285166743996114296479394289968524943,559627723033455856754700399288311,0:159587215627409862324848662934458300983070878875254327058667651841273 +mul:97635198013817214038209538637709608537616,-43337611052093405089732573050042882425535,0:-4231276236516932968241697386864918819022381398914657632453889680479868318366424560 +mul:2025635628106428290541842218677337,8363403252785996217814021695187802,0:16941207601064506909583426911328603088283663942724754575178256243274 +mul:39403341320445818916772945982544618,-3081545887974055895915003777735743,0:-121423204418458019221260007112987567988534380636151689137057510881174 +mul:66538675039876745133366881210395320367369,385523580015310377616062750074359,0:25652228210848657783496179630561675959121693223651695460689142031947191471 +mul:568797587304724025372575349953868,-809993079501337508688725757864677957,0:-460722109353884289924314758764698126555664169725436270804746626487676 +mul:87438670031005707662235517162074411507878,762858503307630620547057859718065131261504,0:66703332951062790053116333011119262791723282159398794542887647524305430508974128512 +mul:-135539991676075663249711183869449098,3187117064807540583340853903135708355720,0:-431981820434692750842384830628518023465403828254323238040947018231817140560 +mul:3623316226168035106420698863103708,281527696822113339094642926844583498510,0:1020063872011278433648537926576161108003887115843314376248917259593475080 +mul:462743256592937700094228107961335,-6269566498572477078237555404177435,0:-2901199618975409735420400360180614855892286694850259916640459475725 +mul:-685484600842741055621576203380446857767,871551172534175305655069705808532,0:-597434907618612100896516584776549623778036010575252420692205107539068044 +mul:220964518681325411201409247135357488007,-5641829172229111635876189209726787450,0:-1246644067523866218886679493927269969586873926750864717926006590010013112150 +mul:302531333113895329527974519952510,186535245939488501803212618851457571589,0:56432756626801787093558631197271214562205468328076903171812192205238390 +mul:817537141270922830542026664184986,7821981713799768623509532856543951,0:6394760569373296513276094902257760475138670289320772774910103319686 +mul:8468979244486855292413811013010058,-209488808243349961649691393540068,0:-1774156368965217661234169339486871316037510280452325791205110003944 +mul:879852422051274089521663230058530,49497155404087571445757965616479604,0:43550192066934760013905050742361301523530318780622661179293471222120 +mul:21764922287301916637920770938954126,164044760066720848860497915166650797335,0:3570421454491268052799273529790558940088345201564664677181891708888054210 +mul:59469732179854673335933541543666124,33859516881008254191737434099260638598,0:2013616400652829114516768709001157871422263380461883882597878170339454152 +mul:5622782096444522942366700649751601671560,1818924766888381565955786591467033096941030,0:10227417614039519288793528427282183495313347673374396346064272524023191670748106800 +mul:-83658234598433632746857009684831849359505,-29016349811234824466750396183186748,0:2427456599698498400779164525993522755993904434491695109250156524973603839740 +mul:7054089120269602821498711515003074,4095832337673576318592596805192095781914,0:28892366331631588775096150339023452623512261839491078775396601042143603636 +mul:990394898068553803695514279851854605418847,-7739084020331097221051527297005947155388,0:-7664749329459790605184280312841813382942964148487855083039273635724968309932797636 +mul:54075935489906064661012070011939942732,7918292813066039667153314788962651008581,0:428189091349545982631162674290883455991732907828213951097897291399359180583292 +mul:8772115771437424285869834799732506658796,-932849018789404004804426567212331569,0:-8183059590092457014103801212671744691867340048481623621821910552497102330924 +mul:-474373401937043543973615567508636867124,-23736477393422078122335330115520892673,0:11259953531119359125561737495585820068714950649943932579707916447562566182452 +mul:8436352086792195283692976718955932574,-24226347745891111460405966918193715809620,0:-204381999361401874523255301520944469344779076416596720733502946611674540561880 +mul:814519302031186083731939523439915121,55324835095437197264275880684820442585,0:45063146066925974240276350660152502606985477063819725670158134818053827785 +mul:-237764758709584162016066869681905512952347,27730963225107998869867496093972168,0:-6593445780002155177144945210712636481509108047897422208741783636396128278296 +mul:7518474854158787395750001309747813,8381114315785290417935232114225100106214,0:63013197233061936586019793610222181046567760778431006705881553819854209982 +mul:57926271609377407522025180011097851547,-460438760475654775684236043340437433561,0:-26671500698797845620038488129522785806400814035581845817517898599701653568867 +mul:6638349918167655693810387712273716693403,55308325418124425819340246954531134649556,0:367156017513396353523080763860964198057435071526450849007117311720362229502079068 +mul:-792096039638367514268257857215475476214,17985352918594429617981644232595132,0:-14246126818317002183748026216030950300744414227976528547481286648758190248 +mul:17523605051927467343416676052611136060682,32818776862511079287568864844380549,0:575103284025979425337961066906823946761256491065774387656701755680364474418 +mul:435598204136143930685119666237820390,902306362378699323196514142749053448065695,0:393043031032778127896845207627557199195066578791333475705362867607698330521050 +mul:7246625600474134146152993995542881524104,84045078681310625106949990828070364497,0:609043218765848459070950953243439359310276390319003636791153856018486171335688 +mul:-787638361574460696958641849383712843152717,-98972482600264920015196417920239935812005,0:77954524036229481100840641198098180090516196148063542559493953965332234357616967585 +mul:82374608290966933640517911377351376793038534,3375365592517566879211534105358267232412929,0:278044418522442081159379773928407521481969102832422171826378968402371349113290496806086 +mul:-65869507968457359071511077346860349916,233541308077986424091233056554170108328607,0:-15383251053406881762895333316227673851604711244588922960984017463587249932847012 +mul:434965647854018848199731601803786298508849,6881642201690537465635377223216241,0:2993277958557881269328249998872265799210459572563672559065439071522179016609 +mul:719612999193225374224745692059996056358,-315519530953816852193901984099603790510,0:-227051955973715854947761029625296545846391976119186350945960831820908385562580 +mul:3371856558784507755414140667220962994794,-46940188151078159734582108552804551252391781,0:-158275581287791729316741990876515371668219778704190560942981767461139678285151388114 +mul:4803433840417804894873156694592939602852,-72456645795090954873268375616538340122311,0:-348040704375306339795449754303228838077133852627838127804760032434988381444430972 +mul:48568835567133010333265540506612310476167,-10706367926604784868082114989212135746648832,0:-519995823348494578419271225922535589824979430677892239954987805560794580396454386944 +mul:-640514959144433868933444881224466486263623,495227035072426375802319189512972514543836,0:-317200324136634298803490410310491121240672331811889843420769547754733113081885677828 +mul:-6488859550432975345382980598094012298,1739553070312394609661279054142037504040,0:-11287715553781586837699646244863276062209616974051919639534825980076984683920 +mul:62439762329215278757554454849955204768025718,79602289985731119990152260854511851,0:4970348067570324615570705607275557501940237030878572771873031709232361903784018 +mul:6054057220822234921996955072468282902047103,-41461621564455176604944655360416823,0:-251011029419288750464457350960394818104993744337372045669164809905502059613769 +mul:41593335543156355768394832800525873230,751910447000975730197547607815241920,0:31274463520516267130210975092154781101937166708024981308551550511701801600 +mul:994454253731718339598418586069934146007,674502407982587721309172287657440910774,0:670761788770571291425639315014529979293655007270270606543282922218043975379418 +mul:467599304203676521904495847137440151064429,1065364075426775111107441639016359411726,0:498163500393153194363286906417357715847233221784448787935167388300077631164094454 +mul:-50006834540638623993722097585899096403763,-5313099491095445109561808031972399857647,0:265691287149161199757555723574229252417144350517780818574650795718178070835125661 +mul:80633786527554906657368596063180401716797,60423064130048311342811193512905633441,0:4872140454403075663557443919045087358815687394738194780627830508431609174608477 +mul:7515721962363288712694440724080300383839,847957688242291310060264069657345589412622,0:6373014220677391433202574116816230429840218559515683152967957040454035241151415858 +mul:27726212382161724111674518621229053817654,844465139764626291093420179330707907,0:23413819814445912412285655292812080594927908481755534067419056195692713990178 +mul:-9817131728229141224738800156068771165515,5514447437310670168515402768125807553,0:-54136056900474458343818772029658956395718462850811589025376047345570400134795 +mul:1101490427405231724327190816394483390794764,-1715150116840413365727028822839059671039358,0:-1889221435262680048398395651544618017331159617034111717493189130934881187657544321512 +mul:8714614705512806124985108394035361802445153,2277516152797095323407597912040972562623326,0:19847675757208518019561453963926275072330819370134031638574421823784137713762913438878 +mul:-40241069975197162607015133362864260639182295,92350494843755720369837991386076354459722485,0:-3716282725251658699531715999828990669514311285221505159677424152232919613685003025403075 +mul:94926798565178929705057494111757110129555,654944641739167114202854904453615515658738188,0:62171798077717196972382133382107571708777354355494810646721424261049356268684505946340 +mul:265280847975099333384365084677641815670787,79159871617113409657206914064640126799879245,0:20999597868187843053561037716605216806384147652131248848290439305459650098340274115815 +mul:116347226264838928071222153238640922289035,68573180747149861177662470447052670907671443,0:7978299376088341437815459477697033179544362328591411544546002100709937766389261527505 +mul:1040609825768545533315151293676302487896884,-81323728160947963681253577857302080515,0:-84626270592412620351087782103887368619510384932135633101731317980537259985615260 +mul:995902591817252306534602024050315471330353754,5332558356879676808399004303967153306,0:5310708688633218425617462275294145725219682434631220640352375632798303313330610724 +mul:2001969035383918099033090062929650143669765948,4190101466247488888803682714062857957220,0:8388453390544226191569030306431481670502667642604288098765832297433783873766796744560 +mul:520711239532941932960582838954921846930386522,-3853096594619017503346777573808512971,0:-2006350703824226084150485654917370322708059670415383459171549901585565143080576862 +mul:60199373689261241651972446393273631317362,4966864098864732001544113870901038040,0:299002107951333794206101094825317104561273941185545981038605377956818474450480 +mul:945149245494027792287917914515672725163081263,8902933189066222709145663761457459365794,0:8414600586329679076832097202813182563472890369046719691038445973643576962794864517822 +mul:42113632082774519107063284261972952560637120,550965713086089226514793739995356299364345,0:23203167331131067949789906196648817037171886959897217039074444030278552245924211486400 +mul:699130208513509445029837360613055447835,1388996167624703080432361535173321299212301763,0:971089180295924181746449876683106046223557368848629195863225292564207370057125033105 +mul:2708864861499120155181972404884433662661130826,-9669434874243213781569557549324652869447,0:-26193192361391605615558952560977409140576479476697591006776382263831361618654765273222 +mul:-2663320619224926510783240759799877830,-9288856838720796348912703146202293649985994,0:24739203947593564658057633395520384609185233542510185477275313665703022411113020 +mul:129339208558322679510730678747389994722,12274162664070343010820636150243461714,0:1587530484686971608662198892455480803480746517693529713477405341441469073508 +mul:7927826382521640149002540477963715500150746,169024688202278131082480706237325364215068990,0:1339998382427514783636289070847268513301546686442820771818201284402167398586309789966540 +mul:136906526225769628858637915191370345692692,539213183682016621647404279498623014328141,0:73821803873042744699575963663268898393281778327505656899589792517391459419633645572 +mul:30681142365936990868501835461428152495,-5027491490146180677917496407674117704,0:-154249182152711677657936575800296045756593757870287279358854312185891271480 +mul:-971981137022757867271162004648718096950546,4334305792750860480761829171455584581712,0:-4212863472642307283763302038750775419855652449217026116602685720873585162160014752 +mul:578802014801938809246604894083179003839,4755521418153118560811649969223227339815203,0:2752505378260798366799002210776469662264057939931455802132200174149940527887564317 +mul:-85637729865865539531457719920611651870241486,974400175977421869121902925057819107693817,0:-83445419051606298238772725013236132640041467317129471694684769066837807060528339092062 +mul:-168964790731095355351979412256338118430524648,170138331609580398941494555432555720911428772,0:-28747387595750458102364942972192784965490845982185971055009388748528499591310207242372256 +mul:790938498909251314495722876378080005340582079,5214770204816378474402582970231763702140978,0:4124562517954155419865932563949638361261784041659784084183845034248536666456801038333262 +mul:3097935765451813281781983641770574025792276,42609404056306319259222360596281494320705429231,0:132001196770618914910107580782114196079241607233335405092295156225025350707315539424419756 +mul:-98485087154927525975034391790808080098982,19775664577849930783360381707025488283978,0:-1947608049496163493701638026379883534026679881243207339494650490437933823564710396 +mul:25900464334299058097279910365875929228,58255952834922520501042331752256379575,0:1508856228661518846300670852569471328709790883165326524402490612694204718100 +mul:79400185595521899110261406600117591081721314118,201740226840130845073877991057259510967,0:16018211453189077537841902603464990449906833086676810898799136608951219916977272932106 +mul:981167299738316185980724229187020822277,8133607419206585086507618470282084549435045911,0:7980429628634459820355488852068596406179426323528568158104015662222056961076466559347 +mul:81466412463591236560961446462245299836549126707,866192944729287017177690246604876328497,0:70565631708368782955079491721185650392800025979803605094852603626778749894901807869379 +mul:6534998388738554052417315288897046254899165842,46609611771478693989087838979597248775,0:304593737826342807250457708401174251945994165789414852595908172190369819865656343550 +mul:948084924179221265735435784532032916982,31095014697784883179376411641933005719333,0:29480714652101151829666949589520351343767111464822561182540749953951625181413006 +mul:2750322192684776089555518232723747026,16282797711115835147148988819960931175880625768,0:44782939903878757031458893908209207556974070715102965333536520996427288006608965968 +mul:-916832268194684002726682872945582785046,80175456371164380904577325966825746198033406059,0:-73507445518318567912336331397416597212835389484585058461161628079009895397414630993714 +mul:282231592138255672195189656428026230056,96673996679717919403145753072968455552546,0:27284456001285230898827449612784823590027283270261564593974508775341064792522576 +mul:550580097204590201609373226827993784219420731,60517713169991893657707958780297059239491,0:33319848399733645437661395589377990023027893949147177182635468091834964459423419287921 +mul:31526794192792048622410273704705620482050682,70537996848502378104686898733501905256490,0:2223836909414548601160467423600948705201515061075175410087937767675574150990389426180 +mul:-923613180033278870451470473112995033306843225,62635452857298067541908563173475507759656054707,0:-57850929796353591491544159777994055136678493390586182701070726329142717640752659048072310075 +mul:469196843768624413897755875308788890398465291232,-15296277161521766221056511754171865009042943213,0:-7176964965596105854796051880140430745806790021143791822882675477990460153884190250962482808416 +mul:2628065716223500508449356215564412668664236,713708318009199991674271791693482010536664884,0:1875672361943518042666230150625785628379941211629586909201716940601968915751182647888624 +mul:604553604369312265623368647573085123221252020,990982890678004704551740474471789043760433700479,0:599102278427707884215998875763263404402845043498163599628915781601939770631217226224053717580 +mul:97586462652371414650265963064033775148721243,969409880443270812997088798402379069080662,0:94601281092717085428971288705993159426354381047162321909314102361504796669908919902866 +mul:-765406874969209688613302257358735487317,687488505077706911028822098735771705823765697808,0:-526208428248781293790355829561494931467780389995278558390525263117575307179181438701136 +mul:85075624707999635862443444914978287825359,778046486301986342411165862027907781749497,0:66192790874005569505967522431892177262190586520494284537342391004284567008622094423 +mul:8227248806783006644129224253415431417213104067,-96883503079217553138854609209329008354340832050,0:-797084685105450364093424636607878440722968607757607323583949926033112024630877523264018947350 +mul:5027554007771258456873599804445876368468,9124875242153734630106913217321584664013715,0:45875803094102741048036279096734905134493820588179489085096405521013297169145538620 +mul:39245745484403729199058188063461104557810253,220067769421357576954105356315871937975114,0:8636723668031045203182769468262937482316831571209371261835666035163932603354648043842 +mul:12265626358518464602956912462337886264411404165,-62808539324142868756473505816723401975937,0:-770386075474250281180131471535743658895165686987724121596740049447065305055237711577605 +mul:-12272356051659726939876917766506363796290,17656166644036956054896242696928896080969790493,0:-216682763563059549497954402078347159387989008283715984882662478463368364976841430670970 +mul:637223594292638303876168193085997138882431056,94504571343119776477559774058446419793557358444,0:60220542628347848605902201201551563824536878839327823946585532875841535294872255080309436864 +mul:5571012420064356266635359647247635200655740,-21295217227115690481188602248443089551209070396,0:-118635919660229953125503640983379408558760574394740036184511552934026350143637375021473040 +mul:5263843748978600609740419748581371970418448276216,5384845751134428162699702180820131424931650492254,0:28344986646322936927200214104061116351020656649291842992510958145976963325938398674483474160430864 +mul:886573921242233631853410597832339291851986573,91564665302299543163193474542608720062467,0:81178844364292397724319168352869382688643286956887488649289119221530204376834605255591 +mul:26539751625701457124278640373644598585396,2325338527842485879693477585982320189921160388553,0:61713906974613847646349243530903967347131153357438117664659209426320342893497093511371988 +mul:353508003643539157483752498296868928280378,10742495675871104458509832622060247315860,0:3797558200526546039055152211123089222303048576306814689403594641262243620006195080 +mul:-4734613561112436559828705330418786656799216681,5767402184612349878575526105980302509419976764,0:-27306420595655124123966761566392172844463942752586247604702902500841784311547866248421200284 +mul:82083010698635736174070971617820650592649198695,632174562080517027772509374721051956918078145045,0:51890791342660440565464109942127261004470910227369112903142988666567956432456853670311234716275 +mul:6173991144338684494350090118957116722781373,-738485502817232028305101940854863776286515,0:-4559402954616091182455382994371638790076884277447195239272169152306248043072153085095 +mul:-493513047233893983448577482415236886372545860,510358065314512191744416886029069217313650,0:-251868363993759605947955962960713974503486770964450697668654217509298887857540628989000 +mul:326654054139623246358073868314669601484091,-749350879522921841553744544029160051092161118734,0:-244778502769254807928944561265310682694306143662100245399456722534220714864996773263060794 +mul:1402621524995633967650615579165227953957890517212,-4307813373241246419295301377872133252586,0:-6042231762972223192990082937904905510649229289208158235372604963773370709779387376510232 +mul:429404746005804957738561594094664667352987,378882853314853204091011966904771925997210303,0:162694095393619197081345508962117529189396776805991399292350948184192266104441374225061 +mul:332341701384724523211310134953299492552149033413,851224516641538736779656410258860743437969813415,0:282897404121038737349436193561640178534459124296792792204901752510516940857699900180164210635395 +mul:8093542646198882950722808884458624246299608906958,-36537804019444103265563497755234936603188804846,0:-295720275029827809269384782284341360404517553913401964795999699888915544660313719313212433518468 +mul:22659814113479956892126670971189905912120035824,-7769923990496178313173088170032841760727,0:-176065033300511807783943084226119789640585676482818345603663798333554090985834476284048 +mul:-66431972193306385702365512934093484764859082,36581996652652744665199423002405565247156,0:-2430214184404654414022013017963434105734980396584113694039713331126873558134841270792 +mul:-888473800362239868616054745127669042022317,142999759078860850560633007783677610020527766,0:-127051539399680213509691775061090749319492899786422897068862876191428383442448290153822 +mul:5971942663513046812876552589351160577576206860,5155119487765712370432570496238254289228130147,0:30786078004495581876769132581215368897074670048309664867385023649025961965929287514674208420 +mul:36328343589972083920724771391132711614346,626466814451530915421088090957480792070888316,0:22758501683110503999668988831411680352271666146548027818547320776153981900886629381336 +mul:5293116409600323220539205506696278195160522774280,-89478075685508708042860880549625934136374,0:-473617870710425832617232568229956765445181004360727395884348946714817018728737310339660720 +mul:79576614103508536656978289576589750212587261,852468870734033057111244131505440601392558836846,0:67836586361655850604287977041894979998590061103440929502231721634765812139562797406437018806 +mul:8225066772418695359596812838151452668642167,32895491347247919323385073727832554930053,0:270567612842635564451661105276011053846580530826552326236219991362408128533171344851 +mul:6163942593967174125699747500635651388266851958125,35785148285967657728202559017385960485415693874,0:220577599751307459197829958073417379960145796516327396960366172323789774042408250526882467026250 +mul:2768453763718344802615194690925869147682838954,295289393573622382700104229276698254424111309,0:817495033025002504068133964169976601685138884223266625508984010676066936521469461617130786 +mul:543530772918490900335995207569824317804903920459,3816523263571207729432080444412751436592123632,0:2074397839310259902661375133149465196577634869313509399704184579022798133468044005917222187088 +mul:1092477340633785505464776554395206472561372312061,-80145274095041381989361699268630409045305877,0:-87556895907716629238600642139851536991533588781637223712321645442750907264691471870441282497 +mul:5221300639042222043517187865188827094681806,28716457589092549537459686031371792838180039728,0:149937258360957795852063558466179437205735302066386407915731516706048526458470970598788768 +mul:-468871256127286679587501070578429844680401783,7709908112767006788780052051800778651016113933,0:-3614954301459024712014678778499413536274302047069226791616378154943247688691115133744342539 +mul:60187668034435065431875732180204005950423,6575730301760601160210842777500398231559661,0:395777872486342581314679269175741080629857948827943943881264571589081297075932686603 +mul:85750547893356514086330287277441673045104762,79743140579005364490235586620393656130064,0:6838017995386660810928499954451837697514688360722982501737493782122901963128377764768 +mul:4548581293372942515724176487253593549214930,4238661184062900689214356649238748109095650,0:19279894970774516775564064389921196824376868554446937886047574519905039195049778054500 +mul:870890539340345883811990618518239041519315472381,-326492148393756245001717974027772662339968,0:-284338923205026619246910784734503794029639825911870769385331694156076881647046490736423808 +mul:66987553698256227716875714961629477167428173612,90975165679807773385648454136069587671757554212,0:6094203796183880252983468130806830185765137990039968456622459271312350291704985779779237853744 +mul:55214217278725852504312036656428464058159216571,-38639629611220548541845337991516346077285504,0:-2133456904923420705886788529419803172916228952081562524788395230166386012381289930934886784 +mul:891217139364757949280558543150622433360536923866,30525879876993440244467275213072433106397646327,0:27205187340566323080358381531226152260280933712987740283334272666071747659070919682319193540182 +mul:-27569366446500582408824975793718887457276922405388,634666021153562229559368735956062829411322343,0:-17497340108325047390655423017206758097517868311360137049025654413974571287769192246265387984084 +mul:502864235446447920785714797929749621810588808385,-661761137717295415776353819805381820532626437501375,0:-332776008566379289514058699683955504618562833566935527415040692964912956262842183217462238049029375 +mul:846540274257645306570757431119674434472851673,8616613565185012233547219046445322085886975,0:7294310410643867160484254450457795378883045914986526511813394090546583372432655817659175 +mul:-3309007371119113533010968742743901666008447,-54456422219293958622124113256532150483182055,0:180196702528418384342054817105817441009885252753576126005393548812004572770935068818585 +mul:3808438337556464123872249539607274641406985997532,8958313515020597801994910602927304472155060964765,0:34117184630454650095284221741033298990688190756311433174116017572873358206925691228892157828959980 +mul:3966980856734279836284487724100931405197679196,7991199588345191911654938564028578389298180118364,0:31700935789308233758627957773360639061582894143974709760939541889270491143844984071481380355344 +mul:65639444382189527381103754239686068124303248439,57344187472963481946737524023690750337279473205806,0:3764040604273435895633212274119116479837782295002539485107922790189834206416168312084346995236834 +mul:415167227201847402226579925485934896345892,586575228633844519664975226407615633553394085108,0:243526811217202913688658430933411830761556037052309989639490972226539908815021715654176336 +mul:61619333876398280418219395631027787927517659829394,919912829682211281138193507951318719985265,0:56684415789370483176959265833922690931907142380410669255035534110985337015940545738093879410 +mul:-868753784405826481862596863379498777711457154096,545880080147628730834302628389405153791727839,0:-474235385460008330984602458660116725933386690418517481411723635621365531412330794841516078544 +mul:9429941770445780812848883836626433106364646270218,13789105660912116612159357433833332620650429,0:130030463448925543470092963482754387029792169816829218586198208779745648441067644420051623522 +mul:43608475425036256086742701999180132009804867174088,26543470249142438881834938827109299420258184885237,0:1157520270054909035662868646857940204973664076401942399990577391349752558661122837219065938780138856 +mul:57684506610503798187871631196324475714333617510881,471695506003883133237678946411955700467360,0:27209522534225930626068350341042360052253774045631066166444663548471852016504199451585344160 +mul:45545031179301366913301053296868047362176530184,-91968879037454375774626628433933013352182139387,0:-4188725463286255430640627639956152535588659815635253627540812068959602079281136816961500757208 +mul:-390021533721654785753654976920878586915091,77031076759836910371783959035306703983828680,0:-30043778702102109808680236214798858402330647256427091328746624712038248759912250609880 +mul:423541795082126371645621560317104281087986536944,8300998559716429411460238557591751288655280830676799,0:3515819830956442096665703788765672916368036936505243022506012528660536007280216565165558183737162256 +mul:-22004254439719621882091733525180851819037175217519,99335356922776842325949741933027888097618837,0:-2185800468589145609464205476226975010639204222945574205629223171319215468510436674371426805403 +mul:-568617824838411255064542027229734991599889058339286,663945656360600870466864889023341282183894393751666,0:-377531334930676137341317084292560605510952651296593454952813714006651559679453405651218795949055750476 +mul:79416546968775553905606945911160893343240489,57823044209535496953371020115352329847370545,0:4592106506344161115031398878073106718740642471142046845754411556618094588197446229996505 +mul:944931014689390846530685010237152128723129879051,9132010491010578008428313272813386452749469110941235,0:8629119939424787805155145456276331139041940822281098763310858175298740567987777487797475766318567985 +mul:10724730362623743957337791385603755532922863,72480373654893123070601266938859686093303005387292,0:777332464030946381953104911976964384403745616151494866542937429270491850221347238960076456996 +mul:7713352208339235603081099644445084271357860,603624463205826416829628929324533190899935786563381,0:4655968086276246859527680228796939930213380744965640764495096069501972383741189048259822524660 +mul:-374652992235609318781751374140306949494493761487551,-8211631925711097443824357620157273567158306960781,0:3076512472105121389035620380499987642797429799314779956051883946663228512561940943539675904376737331 +mul:148033237001979427358794216800322662159772216729882,-2761071692676096788505988250569937615812882,0:-408730380261377140975921158356878339630350304768292968573861638003660928294552005391249939924 +mul:8799836897423935827052239970797993642793054321869,7294647877437509677171255169879966954414823484,0:64191711545589794049942507329622817162690486075145161653225201426081306037945865801824955971596 +mul:638050122120135743843926357476168630346968836720976,-521011870575614667006902791543319211035082259559038,0:-332431687646811297131860656825650731646114948863860886066225973078382224501114486836618755307604981088 +mul:-17589569754541719055752617853886490778777621596833622,-757763302557856615098419826290170728613135917189,0:13328730467773320372749612468589169429951770262414798041479922130537436948993914504659373603202928558 +mul:-9391500830250456597029446286855934735787373415653,28432489383197015180933073382445953529667174,0:-267023747648382060661246943486871855039477521250741910116209365765385119618211444260651874622 +mul:597671128380217947385553643776956963479914986403,71727950226724858021016384499343090206442916,0:42869724948406755644439192851387407923848606069058040508413206852418378147081162495135671148 +mul:220524861586728547654066186650842017022514113,99830670175055229565653522851124444573641171168883370,0:22015144722464404290431089740908195479979690191563438782672166808199720494718314317705872276000810 +mul:-19711747183549435340491469077888147043386014913558,-1141914280129478236596364286858351511269528735,0:22509125595197123566803201916751380078133670163026469768611121772532745591006866402480422089130 +mul:-8382072953685010521572064715326232892979307367,8986558828596332338706049003428573784660004270,0:-75325991703876567601582024901200837475422482663143278160590315962341962045355062611862457090 +mul:8502152308582607794375019565844324676023491104593,10470050208175536662422671560468368371690332,0:89017961548415452362336397742460566038542969501801207576446421265423116103719862689218894876 +mul:594601725521916181847167140525593251441576703983,963458725567603941710493681498226412426881800,0:572874220691643607273440473752072791294210386705034629979437739545297813514469057230330209400 +mul:7141961266638507042734562322157608790427840009,-4549724799885066646710284284349071123364728193387,0:-32493958294643778569864068941415075147150500523994618476463881411873140452414616492271247820483 +mul:-556279059738139499395948604306347001411150129841210,96265906951839620646630096006130967227739083772932,0:-53550708204008570858552227539689352744237572475214571815802430633001465739150610790161193168856127720 +mul:9097507009232650355633416767082868346314279788737,-12952310876092402836370081770801404571317963729609,0:-117833738981010925067125768441840140051091195908538031159411055746004033932320364747308545111613833 +mul:4268792759888467657870170840963084681877952381149,45230992824683770972952637110379461673717665076497477,0:193081734692577312252243894972856695658000409843190512520961090560296517492619302198905276169040861073 +mul:-14981624589272129153412283534256311120144659052,-3422881033749335138988900898217088225431538419464,0:51280318661372243898623018770432573729075192413326291326269850897282594874283136278341240588128 +mul:1220927142068793741881867214403185329458765760024,30622524744504892825380221509502752145574896,0:37387871619239277065352340275615230576537543517582369985500557751663316964285147851854757504 +mul:37912807996403481194979034824173466165481184382714959,-90878397829297201187948170371749592240094934625,0:-3445455247922915696812807051659782073986976942393793434021443082292576682286942256582247061114555375 +mul:11421510093950565340830017403217629128966938056,2237414009357389011349863244579333296452235392013656,0:25554646692221823247642416835188193586733448912454167957899665467614560251117634306180050458092736 +mul:192657988036570687555057992620686662908295387946910176,931495134488306662235768448970442482109561110,0:179459978476371988595767318602181178186396303909063154620374484681111185009707914339840931952855360 +mul:3406199971289940059753501832956133340637816361746774,21717729758322757474808809344766892648120530501033,0:73974930479281653383172304844520436444384314366038505444774962096871058594711397484185935845291417542 +mul:6909979467876024377878180024452018966109074368033,842722308262405734840545048662350517397572773044955,0:5823193847214313361590850639006414894786757219881236880655209757454129105445924052644535803723923515 +mul:373077837411940479742523640303846004174658252010,174968689985940718533112057941120724001834591,0:65276940474755009773288570940982140032743912931132908824689438802225554298870445697213277910 +mul:69447921082122879577796325457481062492384026062297,4859735149388070292660864796695584862286590039960,0:337498503134721348480339150893268639814027256856202938192556796481021571996594857372873378679388120 +mul:97668956744134573191931364533568770116368809990432277,32650097939706033583832290610502297382443475332059,0:3188901003364905942071745199167504684645498771234390707296643812873542739572337441867216444655526468343 +mul:-1130623853521736649164698623052358825973875071086,97117938880122601762963490311393663414262844,0:-109803858302732709122723543874405473115932722476026603503929119344711278986293484666788528584 +mul:5196766948376722446473792182397797566282488000645,612809465745222737408369151997835003504928829,0:3184627977237170791819733844305891092484494030274488141848280463948439552688134126307231094705 +mul:-260800009832764286426719551521843883719112476,-4764630548313512861236355180550436291099515479440,0:1242615693849653247685309234997680134044316133101561211221015368136727312822405604340425493440 +mul:446884272848375074930942162217302913946161786743256,21042882325490620038960351129083746002919260315816,0:9403733166660799648590511384420343808695460628780663235301885602775520005114834045365148352668136896 +mul:951599922613172445123982155673072679115439437787116,170174123089259663169419228763721448308107859122519941,0:161937682362503977661236466402707947708915167258582987092600978773889146161299886218655580651394622880156 +mul:21383950451514823653827321489681070470148156716394,474049024111864801681311013604155672359293053819708610,0:10137040843197072851050642470285630585293351622620638212811885320208800091533606694120847446939489952340 +mul:-470414357544256461922663993336752968654129573423633,9062081906619161788388889503790336651084511675587,0:-4262933438115683672713863671510520101815219800470041585560023172590216986734948687990123769014947571 +mul:780091812513073375693179028189802313142318232500,3497278556984926411479728842600230671778387696053,0:2728198368381477015989505443597065418103138169441425077910216137727395317905388139191010186322500 +mul:-1625948018138433921639232759767284243608022009577,842118879046315463699452834842435152085239651627,0:-1369241522422316177317692449844295269090380811960323302423745772493265931792379448342891937631779 +mul:25026283351500865895404594716390919370787136725638,193605742569640932386538365909397399503766353419,0:4845232172025567337840956469216133356563858466840983726314706900481952782728859639508827146256322 +mul:4935030558829975380051283297334807636335988292915939464,826975811338155401386754284486847375740824437795565,0:4081150900367009340504991854566589470179310873827349635534175745385923686159595506846989467997551147677160 +mul:692976306506130156561485116659173381923120836885557,770158528298664593632506223863839610768381103479684,0:533701612364605511333411361009902575918331545270987516486697902333932240009170947895587667949982523988 +mul:79877139216893064041018839082816187503862428735,7269106113282857654532427145534479409503583394410641,0:580635400993063264937521052415287406491591842310757481379039941960972027583729569639227998188169135 +mul:2539745404867281753796678186777103230989134057269,1232562503892732555700624680547460824244298064,0:3130394955473278587381949607908298163614591827039064669019870794477245183817740184883281827216 +mul:-12342369542383197426854745694214905543911988477283,900468407001638487525579769577535461149066925224901,0:-11113913840455339589057682433788692760910363591045622111658103604207392316252364497138359285304423983 +mul:25508383419230789798346692675791795579961116333703,-3196912743165527117167038251788165837584914845275,0:-81548076010491152335265692912387445585857263580983374333387917442921969005827781555255165512803325 +mul:-1299528036083269250543034346520127753461072609198859,600594652353551219594047525595273354045086799190,0:-780489589055124260606091767683960949165161003741168476167365844545079097602756258116044302510124210 +mul:2299157394917175882710807816574923359426328448491205413,-72838172890838078649390158065336999589794176457016,0:-167466423834226138899695762647031472841630725693307898812516233189758231307075087592787449022731421027608 +mul:-7349901043851956691882158234459042155688766310737050452,38963935506607940884321914070762438994955796523516,0:-286381070252598023694679445080668983274723778018815928227159321326339627469156721047447539093637496429232 +mul:958387014018743982544025716556283287504010616036,1443504353635051762579994152447131178181054158,0:1383435827203354324881238067046558111877918566103625557579208412963622898173192934117459277688 +mul:246125390054194220242986809766512103907648232140291,244701030143825150512131468437935457382757506654,0:60227136490812102782907271910174306533407908424359655603867506529129414912591634812915769093996314 +mul:-704660850546084071765145007935951186831012905395382833,5588984198927622386999113229239134076765551765835797488,0:-3938338359304962728083277304047487715370320826599483665593576088149516002866532798742909925478892863619723504 +mul:50682657377075501007405908966255159073041913889268,-221227972486061875975200412557047324616212536548,0:-11212421531736159902862014641256856908352469946769596801579726135954662759261565882858426274966864 +mul:-65153936048938235385603864221810574284616709045012408,2620409042204728497893539911547700871421142555353,0:-170729963157866373963111608067452447067616052160696883002411341925443387533862472832785201804711820024 +mul:2124140486540339235997181873057458560557130144031198,6337118390151757487365380009696068490770095523526655,0:13460929740520685472324728914077419222468164771987370279610883339996690538208206652608006128131304582690 +mul:70505951289040282645383932312380844925860919298,7547000534925894125969206219651626162975048702546706065,0:532108452093846047616616850898050963751081524640768880912328456268423081073299532380834291122692142370 +mul:-41539404414450841529694974131865311088044938789,-87120273993379326877611820290578462959192080166852098,0:3618924294108748055270837693949939912318794083201327440980670903703748636538106296956551875226229322 +mul:8365100924146743906263010309561180555381451232169,64464903694507870558459227754837948332608708108908133757,0:539255425469958633518840532058336282586265952721118473314120789860073187010825518609049764601833913228933 +mul:-607028381550248615720149092346152462853976790359415563,-638047705393414341349283089715056902457142563666819,0:387313065956814142347580416821601619522788233833564805598190281345003710840619549824608697022583095304097 +mul:9617834842433276206013447576300042077483363020815285,528061422615472570377974310003284316297281680382590494,0:5078807549375975305409474126592664059166274736600561408401824181271910205956102095093049029393852170900790 +mul:86576571095874523146332767288469633576872568596,28806568894922815646464384363885717260300665904363145435,0:2493973959959492744618741686252959362351894366493500719340778231935540767761675386859282345646361759260 +mul:307009198563449723583109556832166934014223122475324,138726608616028283757694379054230076836833023549,0:42590344930632202620089538756907194977499968842538325319841912047531571749213635995957120063404876 +mul:950446831200123302940271854492691726825599408858,-72101792770002156123347099210449392040964040896942,0:-68528920462096510067650339988235647246498530567363500303801515664792809889462344386842251299912236 +mul:981208671446974342191660850214776536471793694644642,42331603864003005956059961823201488180622810810249336717,0:41536136787617995005181391797616187316701801094427498210675495592371812354190764162938589949104015517920314 +mul:436034751789860072246023599184144455891992330310990,72833959249163120346712529298424162613591559886645,0:31758137343081624453269752355328026194721352914558720990171378846806391947794460806298848641997728550 +mul:90712859511805773491925085535825623597765615019643547,-747515802065477997196092836504038150570958532540685162,0:-67809295935620517600810302668580552577312402195771262364310764109361834590609187219719805153318608391949614 +mul:397399782669545823592934194763075791833495372998,-59196779886291303828419299835113054892183602687860135035,0:-23524787461549105672926147613053790427130112546635830152219683595731769479837306026216856302451972784930 +mul:32400956990211215478801690694170683149459902468,-4583955972534683626923454093368608704790928252299,0:-148524560311118107934748825020984325384128831537817042673475700215519245003301091136794236773932 +mul:987205647053507741802554416690401353287928887038,99876648283232575129630115679242229378848334523759990898,0:98598791193984227490766355696552554241176001533681327979309043773446027278571920948873010940294150180124 +mul:613843278686603793281546390730144010908586402122774247,-5096436233192165525303465082471737429087562092805456864,0:-3128413126999883739898127525581773020068974144641842702264583891275711281299548031054626111037897411968581408 +mul:-976952961430926103170472845979881570029763109667,935178486322270132160329332160301439376977149568344208099,0:-913625391679032626735612276016819847879751832378461622543415386714525380228017439645010525807254806593033 +mul:-14766907052440196735362466027665124699631240785562617,56185497908476101017098165076418921931361374576783903,0:-829686025309539659436877109175759992995713482163632861241130851163598589293178881677705053185350284154151 +mul:8086945629611784458016532027184114429962417844094,915144274243273504802165174453120299631299876477769004475,0:7400721989055888996136233798580013159529233408791044035035967083245349723159601722480356017380766138320650 +mul:78088762763327100616786616097147636046671948600444,567540241084477255158834032762283528860020033647985833,0:44318515244687212982877565975681071792510147353364795293924376495712873521681333329643702186243889509852 +mul:719986964333569855824423695658491299542433105292,-615276910378191482694097418592439439457014608822814,0:-442991354927732007722531933484439672517856888972765946209711703099793423501561916310953658633731688 +mul:45518095176552517046254533808850801860612235127698055,35562211507032265793347677842985571735031362689772443740,0:1618724128065785795744673208584473680751616875603258142963030074995341676160450789993590567976668358194925700 +mul:9347651927739244225461883666785850681796998039204,-49878021756813856103391637115956958358002286487531,0:-466242386226901006946356389028134676636414341103795172547644257145552025595817036151721871395165324 +mul:-918018144578664428004161449615771398954961013294489,-670699097650597095681408528960639081653596263477957,0:615713941195785615974127065795375976710193022314921690147944271007135254397488569454896629925801078973 +mul:27390700201762535100035783959539579449610388231,-1589447744597072139866306928627083981945967837919031841,0:-43536086658626030220375532900736667658969827278059194645833847995230392704902546272550528175660663271 +mul:2277199840598187516900058221233481999025368188568,9608219845154413235861538421470991851896216584568613,0:21879836699817971767000557908575054021947917457695046204371308982480723639160400066580492493518216184 +mul:-384224188940171310851587214747099156035618205974037811,-365155157346205326208918238248019306559191342503,0:140301444168666379290296176915045491501178018946537404762619540722359114634558549786149744296773380933 +mul:286446854858822908871115682474835177238732522628,-57158496101544373650727927690968913495792599007869,0:-16372871436747676262278174307506297592132492975051635951931260785772478739228382233254016392559732 +mul:-381089856197823678538852020226946248080829424869589,-3010621081997078653311455126099557341287585438919,0:1147317155204403033538417293781061706820038418656862236980125391331092308923135144143540086900134291 +mul:116824003493453841699155925492342665434851317689062,-23510392931055495213857939210838689217666922526899551035,0:-2746578225910099677716238357776888697288117665636655886289546239917490129557481316738650939508921530279170 +mul:580076669302513896163920831671903321718154827187111,57642903862300589084685292813271561699366462736142,0:33437303681368339826568875036607309078951222489453540109258834689115591802250959764588162866456265762 +mul:5760449410973032312996903274730533429280588604119,54924391723347076414566698417788233810196808558058264,0:316389179950806757476032029420089976949374325352943306272834362194992326589276708483681497464832389416 +mul:5657781195595763129830083459999757852112323789572340704,692061618840647789470644193517118113508111433346167161307,0:3915533213270179560961108305159334536041508008965034741386030883311266330352593550098270684221170821027129940128 +mul:-411686824144764716061907353842274549877341843077020461,64596348790121485579427789661619008385819947602752810318,0:-26593465684752629063594295950004957994828988051383949912582218957039523707407380651277297287183402393737916598 +mul:632256394728894097701649213009572878755743290206395156077,831219707790000649838963373434914934485492976701321111,0:525543975674910659026260706288720204381515414601996591588570479429744161463440855422928774392151685316940041547 +mul:1670481530219772906326138470230000469885289884882422,468290338328174403769157221534943442214405575737600,0:782270360957583948773973087197246461358063772951438918211359656647137302093722698373813315391924467200 +mul:-5940255960924729598832299636442321100271324046668226,57672031765846684220194592702663453624777841860734299817,0:-342586630475711125183923927161946766514304847978409032225317328682383801381008087781458635612556537811514642 +mul:1070320750308710183653165839089007570013512879851785,1457798154372592051774290334996812066679847800239,0:1560311614386725640264706359282306460222595994684719021358994107802507336028163090509939936607576615 +mul:4878833860261622243309660185570248437064542060170266009303,2713399212910344466363698742990679778889654409261764714,0:13238223956354223315835115083131058404743853065832322244195207641759173433600815039556809272534689440156121134342 +mul:-153727669883775746511963322850970227020812560900211022,967696702028565741720227898697068313091723784217356354,0:-148761759157065858120367305796775921605388922829212089475409575708151324377711363197839787691020073572533788 +mul:-540592613733911579302709730020084890208422708295834255759,1487237786400760689794761062671094249214728767786149324317,0:-803989762194224119099880670025468825040986939150865705871247661626924722104597624198557832395582009863760415991603 +mul:6147134348286513705872901614503400707429078163757093529,477008107151085089956583728568535862114663515203848020888,0:2932232919879568942454061197378668098753424444460385986524578717121657294266275306745807650523035121257761633752 +mul:7614680849639684551334463800131196276563566036683927,25187069984138015151555984154271413618496480687947851,0:191791499466750257309658251576197471575523021858632537910036998866329759048429339136517641910254745890877 +mul:34751974072174908316243318351151710272413759348773,8306602488518142539700335965542308143538343391985,0:288670834308846061096235572592461254734354939539314534410107250770305649520412166539742961467784405 +mul:1973284924569393016522181930166284437824113120930085705223363410232863255766399553325346410701486329074823374249547700471683909277697787590783678904983357211584574690370289495346677331618312561665754485123402827162476353576735207718451299565526093115255556962215997764515429748902159033904867393928929335369918394864191487555087825530530292436823694624357846430402766705368186347858763649288740551240105434820489955559033038872623623075504620415436212337263593361227009430895404467373404212231777284568356947010238293550872942631550054733886261493387307990754063500729850132294968984927109971586336754260617576297578,5023215555039217191451486096670046812323372237867852342682903508090873804207633443539517026163606065770027196694503291009850587117226026773591715017125540836707619882023150680605967194554434367524090941938814045780235333982097410791452776449214446635671357519707417878752761895933104747199582531838714305022614904134506738511247696618513698871318914624938137416674596881724436242382943205716649496664131501091102879563857843031208992280893614063087964394912022421136928015233318011144243860597237613050611024432789921991289922378761307428111094457098264457145099945444765267932710530788173695233378407323077034767182,0:9912235527621363370177765461045903296757346464251250997934314384765381968455767811674327750035883028560327843635490083086230089733649800500491928845965808260177110097000550870708488183060088779215210481900113545281854124601490142211180660492441361405426298053896802091578235012988730731854809702026093664780523793649405978324745399501432045298507869343282835244908856693641856464415460033802080004246708824900236489959461486545994943320360059459917374730418136788819890973086342429995201653932338829740545718352667527142958499428354077966431655595175455785104618218647409782931121099857213491801531717606789462812743975739913830932552436532349361163108142395102143904119547756730321871557900417573185916761969667939077354954258105548072267528998411702020631497735552158986372677452750936969993423245268272976429454770189221077520557005286622417163333812030510164503314440581497599501417407932697447376958591635071781976491704916693799964449632893911830806101578411062044010045678256608720149155356874608716245388282176400921764516344436742619757576145128777884235797616593795005421758664915151768829194432974835591116318659671888399376705850603804666493415116788205809451378581533592708248188469927900316495904963905315042780485196 +mul:5693930165221819,3016628443782411,0:17176471693318822194099185625609 +mul:19732849245693930165,22181930166284437824,0:437712683949801303830876080256140560960 + +# Power of two multiplication +mulp2:7328492456,15,0:240140040798208 +mulp2:9301,45,0:327249844798226432 +mulp2:221819,104,0:4499023815872409881769555333012783104 +mulp2:1,3,0:8 +mulp2:28443782,108,0:9230534995215592279593651121258540040192 +mulp2:131,76,0:9898080148094776367906816 +mulp2:93,36,0:6390911336448 +mulp2:85,4,0:1360 +mulp2:522,113,0:5420757920310360044185838167705780224 +mulp2:634102,29,0:340430919041024 +mulp2:86325,31,0:185381525913600 +mulp2:6639955332,101,0:16834286724196864462774406457915724529664 +mulp2:4641070,109,0:3012226647655029057743003824831688867840 +mulp2:86329074,43,0:759358565425078075392 +mulp2:337424,112,0:1752005575194255677729274193390761672704 +mulp2:477004716,31,0:1024359827628883968 +mulp2:90927769,62,0:419330320984095270608306176 +mulp2:875907836789,55,0:31557905658990701020815818752 +mulp2:983357211,56,0:70858354704507043363946496 +mulp2:4574690370289,41,0:10059850511215301155094528 +mulp2:534667733161831,94,0:10590185513519716577933182844778629828706304 +mulp2:61665754485,104,0:1250730090982990067823267062394063169781760 +mulp2:34028271,97,0:5391994769734856490537202784887898112 +mulp2:47635357,28,0:12787018778017792 +mulp2:35207718451299,38,0:9677823956166718317920256 +mulp2:5526093115255,15,0:181079019200675840 +mulp2:696221599776,31,0:1495124500903360462848 +mulp2:154297489021,86,0:11938189976268266978253598864697196544 +mulp2:3390486739392892,71,0:8005560469361491387429364912321724416 +mulp2:35369918394,31,0:75956321382209421312 +mulp2:41914875550878,28,0:11251438731683187130368 +mulp2:5305302924368,42,0:23332969016866530784182272 +mulp2:694624357846,102,0:3522163936626521236224897501281415419920384 +mulp2:40276670536,50,0:45347499604413458849726464 +mulp2:8634785876,54,0:155550473814310487519657984 +mulp2:492887405512401,103,0:4998472123541838661247665060074167267342942208 + + + +# Multiplication by small integers + +mulv:39,34165,0:1332435 +mulv:1331169483,45488,0:60552237442704 +mulv:967,3873,0:3745191 +mulv:4609944,12208,0:56278196352 +mulv:-9187510646,-19674,0:180755084449404 +mulv:-9187510646,-19674,=1:180755084449404 +mulv:-705904,-32646,0:23044941984 +mulv:-494,61105,0:-30185870 +mulv:31884502736,41742,0:1330922913206112 +mulv:124758920,14754,0:1840693105680 +mulv:1578359,-34693,0:-54758008787 +mulv:66733360927656,-31832,0:-2124256345049145792 +mulv:25747369,-31317,0:-806330354973 +mulv:241723337947,63112,0:15255643304511064 +mulv:7902551,11307,0:89354144157 +mulv:-9354271604,39887,0:-373113831468748 +mulv:952191019,55813,0:53144637343447 +mulv:809248646915194,9772,0:7907977777655275768 +mulv:-2633237043,16406,0:-43200886927458 +mulv:764186567812009651,1311,0:1001848590401544652461 +mulv:866541923,29701,0:25737161655023 +mulv:-834567728673833890,4681,0:-3906611537922216439090 +mulv:332307463075,323,0:107335310573225 +mulv:27691642758,54832,0:1518388155706656 +mulv:2202473525085705,16772,0:36939885962737444260 +mulv:2202473525085705,16772,=1:36939885962737444260 +mulv:-16583738845087,37131,0:-615770807056925397 +mulv:9196926997210,10181,0:93633913758595010 +mulv:514078180671038315,62002,0:31873875357965717606630 +mulv:514078180671038315,62002,=1:31873875357965717606630 +mulv:-3412120508850357,36908,0:-125934543740648976156 +mulv:549214983476935,10691,0:5871657388351912085 +mulv:651367312269732,44154,0:28760472305957746728 +mulv:-9584205879196113,22814,0:-218654072927980121982 +mulv:987433915942054416876759,34616,0:34181012434250155694605889544 +mulv:98036280382191791,23951,0:2348066951433875586241 +mulv:80662726244584753,2712,0:218757313575313850136 +mulv:47866183268822904587301,56393,0:2699317673078730058391665293 +mulv:-6912574313961965048871386,30037,0:-207632994668475544172949821282 +mulv:-6912574313961965048871386,30037,=1:-207632994668475544172949821282 +mulv:727313511777411140493,-48518,0:-35287796964416433714439374 +mulv:465780278683330104360026,58793,0:27384619924629026825639008618 +mulv:9089195999415213350558115,62437,0:567502130615487675968797026255 +mulv:9089195999415213350558115,62437,=1:567502130615487675968797026255 +mulv:1956713589673152168482712,-63098,0:-123464714081196555526922161776 Index: contrib/isl/imath/tests/neg.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/neg.t @@ -0,0 +1,9 @@ +# +# Negation tests +# + +neg:0,0:0 +neg:0,=1:0 +neg:-0,-0:-0 +neg:-0,=1:0 +neg:-1050000000000000000,58392:1050000000000000000 Index: contrib/isl/imath/tests/pi1024.txt =================================================================== --- /dev/null +++ contrib/isl/imath/tests/pi1024.txt @@ -0,0 +1 @@ +3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788 \ No newline at end of file Index: contrib/isl/imath/tests/pi1500-10.txt =================================================================== --- /dev/null +++ contrib/isl/imath/tests/pi1500-10.txt @@ -0,0 +1 @@ +3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952035301852968995773622599413891249721775283479131515574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012858361603563707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104752162056966024058038150193511253382430035587640247496473263914199272604269922796782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955 \ No newline at end of file Index: contrib/isl/imath/tests/pi1698-16.txt =================================================================== --- /dev/null +++ contrib/isl/imath/tests/pi1698-16.txt @@ -0,0 +1 @@ +3.243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89452821E638D01377BE5466CF34E90C6CC0AC29B7C97C50DD3F84D5B5B54709179216D5D98979FB1BD1310BA698DFB5AC2FFD72DBD01ADFB7B8E1AFED6A267E96BA7C9045F12C7F9924A19947B3916CF70801F2E2858EFC16636920D871574E69A458FEA3F4933D7E0D95748F728EB658718BCD5882154AEE7B54A41DC25A59B59C30D5392AF26013C5D1B023286085F0CA417918B8DB38EF8E79DCB0603A180E6C9E0E8BB01E8A3ED71577C1BD314B2778AF2FDA55605C60E65525F3AA55AB945748986263E8144055CA396A2AAB10B6B4CC5C341141E8CEA15486AF7C72E993B3EE1411636FBC2A2BA9C55D741831F6CE5C3E169B87931EAFD6BA336C24CF5C7A325381289586773B8F48986B4BB9AFC4BFE81B6628219361D809CCFB21A991487CAC605DEC8032EF845D5DE98575B1DC262302EB651B8823893E81D396ACC50F6D6FF383F442392E0B4482A484200469C8F04A9E1F9B5E21C66842F6E96C9A670C9C61ABD388F06A51A0D2D8542F68960FA728AB5133A36EEF0B6C137A3BE4BA3BF0507EFB2A98A1F1651D39AF017666CA593E82430E888CEE8619456F9FB47D84A5C33B8B5EBEE06F75D885C12073401A449F56C16AA64ED3AA62363F77061BFEDF72429B023D37D0D724D00A1248DB0FEAD349F1C09B075372C980991B7B25D479D8F6E8DEF7E3FE501AB6794C3B976CE0BD04C006BAC1A94FB6409F60C45E5C9EC2196A246368FB6FAF3E6C53B51339B2EB3B52EC6F6DFC511F9B30952CCC814544AF5EBD09BEE3D004DE334AFD660F2807192E4BB3C0CBA85745C8740FD20B5F39B9D3FBDB5579C0BD1A60320AD6A100C6402C7279679F25FEFB1FA3CC8EA5E9F8DB3222F83C7516DFFD616B152F501EC8AD0552AB323DB5FAFD23876053317B483E00DF829E5C57BBCA6F8CA01A87562EDF1769DBD542A8F6287EFFC3AC6732C68C4F5573695B27B0BBCA58C8E1FFA35DB8F011A010FA3D98FD2183B84AFCB56C2DD1D35B9A53E479B6F84565D28E49BC4BFB9790E1DDF2DAA4CB7E3362FB1341CEE4C6E8EF20CADA36774C01D07E9EFE2BF11FB495DBDA4DAE909198EAAD8E716B93D5A0D08ED1D0AFC725E08E3C5B2F8E7594B78FF6E2FBF2122B648888B812900DF01C4FAD5EA0688FC31CD0 \ No newline at end of file Index: contrib/isl/imath/tests/qadd.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qadd.t @@ -0,0 +1,803 @@ +## Rational addition tests +## Generated and verified in PLT Scheme (see imath-test.scm) + +qadd:3/13356872859954085399,9/62913230326443414581,6/70815656362754309351:308951546718917012334/840324018679312348674627422530435802819 +qadd:-1/10707768797352318399,-7/98320256665411314243,1/73359800109931088847:-57758212748959181012/350930192156520858413194622860526552319 +qadd:3/8871935578221811012,=1,-3/4866674049828142891:3/4435967789110905506 +qadd:9/4322444789227983625,0,-1/968244430692371869:9/4322444789227983625 +qadd:2/225379267690226671,1/650264369025696376,1/34848592015687152:217986857963088489/20936586756579823441422616437606328 +qadd:-3/68292234169742612,0,=2:-3/68292234169742612 +qadd:-6/86190045205685135,4/67524620320880421,7/25266746450126878:-60387541102541986/5819950077953408572132977712241835 +qadd:3/32384565517809325,1/12077081878824172,-5/29092772826669868:68615811154281841/391111049368729137348856297003900 +qadd:7/8696576917665055,-1/7581339998976754,3/1629599527000648:44372803075172223/65931706440072050529006903131470 +qadd:2/2271361357023875,3/7926992193500824,=2:22668068458073273/18005063745747695119878000173000 +qadd:1/149242689846961,=1,-8/422836348382141:2/149242689846961 +qadd:1/8658078704679,-3/951317712555992,2/558713214761595:925343476441955/8236583628464972469619886568 +qadd:1/16676404623347,-5/33326850326497,9/43833507346994:-7150738970034/79396005838055435322703637 +qadd:9/79221016041680,=1,=1:9/39610508020840 +qadd:-2/2334176395033,=1,3/4196164230632:-4/2334176395033 +qadd:6/8258476677649,3/2022168438715,7/2650901397286:36908440665237/16700030889405718666781035 +qadd:2/89237876621,3/593210741974,0:1454135113811/52936867002527677989854 +qadd:-1/86244958313,4/307620567537,7/284049788408:37359265715/26530723023449966085081 +qadd:7/30268895338,4/83657377701,8/72832717953:706677225259/2532216409883104057938 +qadd:-2/16397609979,9/46846025410,=1:53886438991/768162853739503566390 +qadd:0,1/192040267,0:1/192040267 +qadd:9/9089766539,=1,0:18/9089766539 +qadd:2/331584881,4/272560309,=2:1871460142/90376877625088229 +qadd:5/832601742,-3/639383129,=2:99872917/76050215287258674 +qadd:9/36166996,3/22041145,1/5580628:306871293/797162003050420 +qadd:8/17901539,=1,3/89155358:16/17901539 +qadd:5/5040389,4/3388433,-1/7168517:37103721/17079020420437 +qadd:-3/1713461,=1,1/4488431:-6/1713461 +qadd:5/516179,-1/59578,=1:-218289/30752912462 +qadd:-1/244201,2/201199,9/174458:287203/49132996999 +qadd:-1/41212,3/27175,=2:96461/1119936100 +qadd:-3/13547,4/29889,0:-35479/404906283 +qadd:2/1907,0,-1/9340:2/1907 +qadd:4/1341,4/9919,=2:45040/13301379 +qadd:3/160,-1/799,1/705:2237/127840 +qadd:4/85,2/265,1/5:246/4505 +qadd:-2/59,3/89,=2:-1/5251 +qadd:-7/55,9/74,-4/33:-23/4070 +qadd:1,1/2,1:3/2 +qadd:2,4/5,-9/7:14/5 +qadd:53/70893980658822810696,=1,9/9193530480905424214:53/35446990329411405348 +qadd:86/71933586324624884067,0,7/18408383381035284932:86/71933586324624884067 +qadd:35/378921420794267711,24/6551623471410322667,=2:238400935598423718409/2482550474295871845608778066489505237 +qadd:36/3722553911462108789,7/3244440092917636530,65/8189167080175627777:142857720725269676603/12077603158395035547949185323620462170 +qadd:74/204211327800791583,=1,-4/261650327849481535:148/204211327800791583 +qadd:14/190596241295804639,=1,5/7319468293717642:28/190596241295804639 +qadd:11/20832946214725250,=1,34/81808092645053823:11/10416473107362625 +qadd:-2/36273895397703103,21/88730391521225765,-11/10905700152968561:584291020309313633/3218596940638185709301052104048795 +qadd:39/8019234291976340,-41/686183563094027,47/1842385817838468:-302027447010362887/5502666759754131835671079321180 +qadd:27/3512663969871511,=1,-21/6043832798535571:54/3512663969871511 +qadd:-5/2985747324014,45/607698145828948,29/712218076096765:-1452066049782055/907216556358525513388378636 +qadd:19/46107312122174,92/20099305290153,=2:4623759515752915/926724942451947423255152622 +qadd:17/10280669487307,=1,29/71287679743652:34/10280669487307 +qadd:7/48006164806589,=1,=2:14/48006164806589 +qadd:-21/5174158635853,55/5726484671487,45/4364076509257:164322546870688/29629740116054290765023411 +qadd:2/515061581267,81/3885600123095,62/1777317903213:49491188328817/2001323343572560546061365 +qadd:59/587566787929,17/530520857961,37/408187963651:41289366014492/311716436441482018352769 +qadd:87/16848388346,=1,-29/793777748404:87/8424194173 +qadd:13/40356316605,-16/35824973661,12/36053750683:-59992136029/481921326476367313635 +qadd:62/58964244603,=1,-41/7476886656:124/58964244603 +qadd:49/2379119051,-9/250852979,16/749619475:-9120275488/596809101339002929 +qadd:35/1381737807,13/332249103,=1:365324816/5667668480949841 +qadd:-29/262819147,-44/212418643,12/429833273:-17724183115/55827686560157521 +qadd:14/189466127,31/78740185,-7/602930208:6975812527/14918597891213495 +qadd:19/15866903,3/8919802,67/8901141:217076947/141529633113206 +qadd:8/44756143,33/6935255,44/26346673:1532434759/310395264521465 +qadd:9/9886228,0,=2:9/9886228 +qadd:-31/5061520,-19/3104202,43/3631883:-96199571/7855990253520 +qadd:-31/302786,=1,31/132480:-31/151393 +qadd:10/50561,56/854269,-17/764873:11374106/43192694909 +qadd:-12/40781,=1,83/13428:-24/40781 +qadd:-7/5458,17/6090,1/14614:12539/8309805 +qadd:85/8919,25/1261,=2:330160/11246859 +qadd:25/2609,3/832,-17/7121:28627/2170688 +qadd:29/910,=1,-19/91:29/455 +qadd:41/715,2/15,64/97:409/2145 +qadd:22/3,-3/31,22:673/93 +qadd:35/29,=1,4:70/29 +qadd:-14,9/2,-20:-19/2 +qadd:-60,=1,43/2:-120 +qadd:375/18696391582109365451,-131/32949770573031503434,166/56750232802998421883:9906936667630486913669/616041813174061083543307811398267458734 +qadd:615/80348516296708248277,=1,=2:1230/80348516296708248277 +qadd:-150/1530888833706527119,136/9537020524274172927,=1:-1222352197257038250866/14600118227441300399114525155221107313 +qadd:89/1394353050192727085,=1,819/2322159924711043043:178/1394353050192727085 +qadd:62/46458468892037221,813/119745041246081149,-121/356270572095961665:45194927766483291911/5563171273706775007904337294446929 +qadd:809/639945078105944091,400/118384885068174771,-713/209608760084814514:117250467754177008713/25253274840505439393971462380909387 +qadd:1/576267190309129,=1,207/61006148560056413:2/576267190309129 +qadd:-515/3615716945775737,83/23367471127892459,454/27760785001119423:-11734143124365230214/84490161337046038094355667467283 +qadd:73/835205561268243,353/4576154733864164,=1:5197412055370031/31587023826011126162743214412 +qadd:159/1356415561313968,=1,610/1188572111871663:159/678207780656984 +qadd:17/27804219463543,=1,480/45536329454957:34/27804219463543 +qadd:-313/103858729128189,97/192554775266034,53/819834763511200:-16731782644278103/6666164748898110732454544142 +qadd:-497/99654168988628,739/9692326546155,144/61549637278907:68827344589157057/965880747523495532712125340 +qadd:-215/35851399647701,309/1276360474687,-79/2088545670863:10803664989081904/45759309472532992928244587 +qadd:-121/9491608537990,-109/8274027606869,1/42153880273:-2035742671072059/78533831076922767571453310 +qadd:513/9899067246839,413/3814421378956,43/320124503991:6045112940348935/37759213738065792812120084 +qadd:371/929964631846,19/164386836347,-347/394487184823:78656844289811/152873943743766506506562 +qadd:149/158337939815,305/905893441427,-73/931434015171:183271194416198/143437301207471553716005 +qadd:601/39399444858,=1,100/29792912589:601/19699722429 +qadd:7/24017912572,-55/47728203251,=2:-986887768703/1146331812901164171572 +qadd:497/5699936840,-145/2007901849,=1:171436377153/11444913720219217160 +qadd:-307/2244804442,112/2757559041,399/2539679446:-595152528083/6190180784314060122 +qadd:-15/24574214,=1,97/256299894:-15/12287107 +qadd:-79/117243052,17/136766977,280/170126053:-8811459299/16034977796293804 +qadd:245/15098288,971/75107317,120/16937981:33061730313/1133991902973296 +qadd:431/62180997,-385/41204984,-169/77089643:-6180335741/2562166986489048 +qadd:-917/102195,=1,=1:-1834/102195 +qadd:63/1841195,-479/6792243,=2:-454021096/12505843850385 +qadd:-164/387359,-783/642485,=2:-408669637/248872347115 +qadd:203/17726,557/813213,584/477219:174955621/14415013638 +qadd:696/29969,-780/92741,687/81050:41171916/2779355029 +qadd:139/11350,57/11570,949/42570:112759/6565975 +qadd:116/1819,288/689,=2:603796/1253291 +qadd:101/1329,260/2321,-115/2808:579961/3084609 +qadd:-995/559,-419/64,844/991:-297901/35776 +qadd:98/479,83/90,-941/427:48577/43110 +qadd:502/31,531/97,=1:65155/3007 +qadd:895/7,457/97,-217/22:90014/679 +qadd:60,=1,559/8:120 +qadd:842/9,-78,=1:140/9 +qadd:4707/49292519774798173060,-3367/70976135186689855734,4680/92255023230843683243:84058377121001851123459/1749296273614329067191168098769082663020 +qadd:1609/2121030704455118221,9004/45879979595713054965,-1909/56276212991908059822:92918647632416189900569/97312845442281711047521870162146017265 +qadd:1595/6629759211105345266,=1,=1:1595/3314879605552672633 +qadd:6064/3080056685556987183,4508/1637245998798276241,4554/192867820573257707:23813155275203645346388/5042810484500057739317394353730419103 +qadd:5984/719002302690645499,5551/827085169170104629,-1133/281319473813875339:8940459434549679264885/594676141154587307208842285377914871 +qadd:471/5383706422635043,-1059/135831330372294919,4069/661509955962879771:58275211503780396312/731276005720386541831883100246517 +qadd:317/23905256796561588,9403/29217659230012136,1579/93558964298111076:58510781908495614769/174613911721967007022035077857992 +qadd:37/3959930712621791,-553/29796300050913566,-467/11895602422350163:-25287874004559267/2743983341723415461995269514342 +qadd:4808/5483375732140019,-1167/2909491781718641,-442/1776182590086113:1084248143870831965/2279119518390974491600667770597 +qadd:-3671/9168542776331636,-7/406053390120221,1769/5947573797737151:-1554801794565652743/3722917876791723943159405611556 +qadd:1006/103477396982149,-8126/225516229246559,265/155176584822067:-613988001254904420/23335832379663506318642675291 +qadd:2623/84239743205954,3169/121906161822547,-5709/26194735454912:586715608680209007/10269343767154832537421844838 +qadd:443/2686896931288,3316/28495742324937,-3677/558065798916:1266668474946947/4503830741626282579878168 +qadd:4417/89265364740400,-7113/54425110575655,-7945/40916976250387:-78909765197159413/971655469314488996726992400 +qadd:-597/8004050520667,-963/5824074581732,5137/5348060857045:-11184873176696325/46616187188315454846655244 +qadd:5937/5559132885590,-4758/7557504569075,7304/2395270970465:3683710071392211/8402634436588302845425850 +qadd:4329/271647765458,626/121599326283,-7069/977356121708:696454984655815/33032185265975198932614 +qadd:3644/7586698567,-2933/927690827006,1427/63030966192:3358253586712853/7038110667865465100402 +qadd:4385/67179997993,-2494/15819866041,6466/4511530241:-98176802404757/1062778568883908855713 +qadd:-3914/47589537237,7583/20994047283,5647/65572699238:8445477569773/30275666513020217487 +qadd:1511/1463679102,1175/4782029924,32/176197467:4472735080007/3499678632448724124 +qadd:2671/2245073493,2492/4004524047,1097/1196765648:1810089652677/998938976666754019 +qadd:-6310/734134819,2131/871643491,2948/276012457:-3935629128921/639903836497813129 +qadd:-8499/333851789,1381/107324058,4694/778673201:-451097848333/35830328766039762 +qadd:7387/32996439,=1,-2169/53667347:14774/32996439 +qadd:64/927251,1425/83805722,-97/55678833:514222991/5977610733094 +qadd:-229/212766,841/1773874,-1644/3034871:-56820235/94355018871 +qadd:649/6801849,=1,6442/1282895:1298/6801849 +qadd:1093/555053,=1,=1:2186/555053 +qadd:1472/313297,-4055/65502,-988/274137:-1174000391/20521580094 +qadd:7186/53795,8849/16267,543/16231:592926617/875083265 +qadd:1855/76431,9227/21314,9319/78236:744766307/1629050334 +qadd:3649/8263,=1,2945/1888:7298/8263 +qadd:113/5086,-588/193,=2:-2968759/981598 +qadd:4457/114,=1,4229/115:4457/57 +qadd:-1210/279,18/101,2941/205:-117188/28179 +qadd:-1529/14,=1,=2:-1529/7 +qadd:1447/94,=1,=1:1447/47 +qadd:3859/4,=1,3307:3859/2 +qadd:2680,-5349/7,3131/5:13411/7 +qadd:26355/1842957535448256407,=1,=1:52710/1842957535448256407 +qadd:-23972/10860515422884440037,26937/77294406487002446441,=1:-1560351808360184484806983/839457093754789179857466996851368558317 +qadd:-40520/1003897140843598099,=1,=2:-81040/1003897140843598099 +qadd:53983/154204493365472465,389/90815930118883934,89726/3798744434445137383:4962501903526880198007/14004224493496648610131716407877310 +qadd:6730/8025480371035471,=1,=1:13460/8025480371035471 +qadd:5789/275109143231142112,-70061/298583162637001399,=1:-17545923755411446410021/82142958056310217788247049711814688 +qadd:43609/16618250357288024,=1,5530/63408107485667383:43609/8309125178644012 +qadd:87785/73225998153574891,37715/66514284957194283,=2:8600675025329377147220/4870574907461862714813485677548153 +qadd:29071/683129957825918,81512/615183458604239,24291/9113716458411940:73567287447390059985/420250250131516159851218866402 +qadd:59555/7990017410441913,=1,78329/5337044591694823:119110/7990017410441913 +qadd:5029/36615500243388,=1,-5844/782117748680987:5029/18307750121694 +qadd:-95034/708404684023045,7237/43582118287425,962/306992443764355:196988333789525843/6174755346891655642926741825 +qadd:81727/59355557665587,33706/37108442588563,-69327/385353327593:5033400114111763723/2202592303945575671784881481 +qadd:18580/8202880287033,=1,=1:37160/8202880287033 +qadd:3529/570956288395,51454/91669081267,72122/5210249411885:29701485050867573/52339038400785943996465 +qadd:1795/316792972368,=1,=1:1795/158396486184 +qadd:-17887/290287394860,-22309/449346280424,63263/662079031487:-3628369602468957/32609890283578494055160 +qadd:13131/63340483459,30113/382543142829,=1:6930545986888466/24230467610714148965511 +qadd:-14617/14636593116,1341/3731854192,-18413/12969994431:-8730210338977/13655407844135735568 +qadd:12677/16187316610,-88834/43865688355,2573/8033027431:-176379750491281/142013557143595015310 +qadd:66701/1078856211,28387/6472397775,-25495/5284061884:51371210583548/775865171069036725 +qadd:2351/2179309208,4443/1189508696,5983/1449971042:779950359715/162019203386804548 +qadd:98854/387184463,34645/227217379,11339/75650021:35875352504301/87975038872382477 +qadd:46993/558998125,79614/180403205,21187/172641639:10596352907263/20169010667798125 +qadd:-95664/49177319,32505/7903417,=1:842436270207/388668858999023 +qadd:7609/4376152,=1,-49134/16441549:7609/2188076 +qadd:-39475/6548191,9273/3028760,28453/1580168:-58838925857/19832898973160 +qadd:-71284/2152619,22629/219994,6307/1044349:33029563055/473563264286 +qadd:55471/884276,=1,70589/439282:55471/442138 +qadd:99253/702279,29725/193293,77332/452861:4451128156/15082846083 +qadd:4672/13301,=1,99701/23262:9344/13301 +qadd:11647/36600,-12718/86193,48531/86404:2942137/17238600 +qadd:81747/4862,86325/5233,34995/6364:847494201/25442846 +qadd:-12670/7457,-5355/1898,51394/8063:-63979895/14153386 +qadd:-23034/127,37704/779,-22033/804:-13155078/98933 +qadd:21121/777,88921/734,23573/138:84594431/570318 +qadd:93724/99,-81002/97,-29731/3:1072030/9603 +qadd:46063/35,84170,=1:2992013/35 +qadd:-53,53087/6,84985/2:52769/6 +qadd:6484,-25157,36395/3:-18673 +qadd:502735/93903639167159766403,=1,-182075/14327482370605034031:1005470/93903639167159766403 +qadd:964341/54574070369775729943,105355/12364735662003164536,891428/78644454680386798849:17673472736839515719955541/674793954121836196578645015875330901448 +qadd:395315/2495365929584166774,465224/7310483990485507083,179846/4219676087482572977:1350282699307880878594507/6080777559542678797435646824476753414 +qadd:484689/8598175504270279871,=1,455252/2180188091947909803:969378/8598175504270279871 +qadd:721437/15467677986707891,167201/325770348193492422,29365/5095805222384074:237608993916724138533505/5038910843474647501780261636102002 +qadd:305023/828712715944217373,760576/326121435327718203,856883/159328170084137681:243257847069985220706839/90086993466019930569059540240313573 +qadd:552495/79059081794978678,739237/4377984896396103,=1:60862213214209017915671/346119466021360760402283927291834 +qadd:-324714/14566706981425225,=1,898113/17904108312665273:-649428/14566706981425225 +qadd:678715/9330341670794893,305282/6752459700030591,-181029/707344352338564:7431381051249869095391/63002756119558606430363386571763 +qadd:29371/8832474155792490,=1,139981/1228293392110586:29371/4416237077896245 +qadd:-410473/489580012740170,138771/888182189776802,26594/728753620910729:-74158825009071779069/108709061946629702972179884085 +qadd:159641/107674771231896,751942/36141035619445,=1:86734773896978161277/3891477742407545118101817720 +qadd:74575/96461557770386,689363/40797971566422,=1:17384884394708131192/983858972792245290555894723 +qadd:82781/8818234639538,=1,755413/85622526494566:82781/4409117319769 +qadd:540719/4870455998403,227043/4599456084178,=2:3592816235626056311/22401448474575913801567734 +qadd:252638/766528476245,158438/3053066657539,180745/2135691256678:892767892946643192/2340262532877784911661055 +qadd:-110463/878079093193,79446/268839262339,12485/16768131207:40063080202058121/236062135689304156158427 +qadd:-173279/107650733329,=1,-23166/462291939529:-346558/107650733329 +qadd:227603/47564019356,=1,-433003/39021527209:227603/23782009678 +qadd:-488093/80889009444,323575/34893143332,-148268/9979738867:1142820277812053/352808975064124203426 +qadd:-39438/15658613,=1,973663/6699939467:-78876/15658613 +qadd:881284/8851714483,166494/3388645931,694663/5162409252:4460116791788006/29995326265191718673 +qadd:-114870/51892709,-65507/276496014,395733/970026370:-35160432816643/14348127194161926 +qadd:805009/674975377,-21652/70238877,=1:41928361272089/47409512483131629 +qadd:531750/53640289,-12447/5407124,-742474/12677537:2207577509817/290039694018836 +qadd:737071/19678454,-571315/70114882,66254/4831011:10109262560903/344938120038107 +qadd:-19051/242105,785139/2763106,252071/1451468:137446145189/668961778130 +qadd:-233713/2488948,-648637/4197650,196342/374913:-1297734569163/5223866286100 +qadd:122954/95949,-26357/1232,-122201/117397:-339635495/16887024 +qadd:-223119/635008,418877/230651,-13963/37538:214527625547/146465230208 +qadd:-350850/61369,36223/4210,=2:745890787/258363490 +qadd:-126959/62232,284090/70243,-7211/92126:8761507843/4371362376 +qadd:-711695/9271,-22121/1677,=1:-1398596306/15547467 +qadd:861190/3059,=1,=1:1722380/3059 +qadd:346850/883,=1,244382/179:693700/883 +qadd:-130222/837,34787/12,7523/70:9184685/3348 +qadd:59611/13,=1,284730:119222/13 +qadd:-312539/2,=1,264288/37:-312539 +qadd:25774,76897,818889/8:102671 +qadd:342195/2,=1,=1:342195 +qadd:-9963421/64053026836845890001,300354/3200175405137875241,1526802/10904004442804863547:-12646112012680203626199107/204980921107910491468445220168747365241 +qadd:1544746/18424173097448569597,=1,=1:3089492/18424173097448569597 +qadd:5502939/3595837892490654503,6889036/866793862132267183,7407877/6872500389210051386:29541770440420524774479945/3116850214433526564127456310938075049 +qadd:265311/258067740607743460,5963570/5903711115389815401,=1:3105324535591307979606911/1523557388749470699660729400565027460 +qadd:60563/46036455525940547,=1,1505826/654445038221898587:121126/46036455525940547 +qadd:-954257/72800654329359791,6813983/869337311132906228,7975903/926820989228750004:-333508793520619681655043/63288325083401809422309080476678348 +qadd:9224701/60870194897007141,=1,1821883/30701883983078087:18449402/60870194897007141 +qadd:-472292/38402815300459203,=1,516735/14385919705031017:-944584/38402815300459203 +qadd:289537/1490184116945967,532162/949630593545417,5373871/9041027854950185:1067972553205559092583/1415124427467351741680749483239 +qadd:235368/2501151346101235,-1497627/1230306186302420,3634873/991873798011092:-691243416109985255757/615436394797394918565529097740 +qadd:8661005/52512373464448,1561891/832613630894407,9705649/42723536578103:7293289423747373650203/43722517937117159639456542336 +qadd:-4730153/288796071652629,9865756/808268774461965,2287239/939894762570958:-324681130548077552707/77808282301366757649284251995 +qadd:1610793/18198109357633,-4540937/36733999418553,1841325/14250960840026:-23465598986712679592/668489338562054530332365049 +qadd:435304/45838403876965,-4386838/12812518890187,=2:-195508311263843424822/587305415569635079893842455 +qadd:8986417/9112103484695,8469481/5806694255278,4459/11976141472:129356163303090652221/52911198958077101695970210 +qadd:3544217/1265421249547,238276/343196380555,6363702/6030500114467:216840279994080201/62041141817416547622655 +qadd:4182082/59852165789,=1,21252/891696437201:8364164/59852165789 +qadd:-2035517/202890303722,1349377/178781840567,3182749/193387650969:-90137966399936945/36273101932616810690374 +qadd:-2767593/32666510356,2043425/57040767333,-2433227/14327142465:-91114064461230169/1863322816797631000548 +qadd:-1069001/77822361247,7895459/95688698401,=2:512151948229509972/7446720454217853266047 +qadd:1842385/9174964821,5302182/734041147,376177/387991044:2941159983715001/396164805934793511 +qadd:9881884/4806155721,110617/6086759637,=2:20226765065368655/9751304883906477759 +qadd:249851/7404273,698298/65948941,8016669/79629599:21647797885145/488303963224893 +qadd:3895008/857366795,9035727/613001216,2322321/896685634:10134576938814693/525566887893022720 +qadd:-3407547/17228942,84529/3672798,7629340/77644423:-2764721642047/15819605929929 +qadd:-540110/78141351,1842606/10051715,185431/9635562:138554690412056/785454589966965 +qadd:-1238471/9333511,=1,=2:-2476942/9333511 +qadd:1535971/4556655,3336373/6869142,=2:2861500402133/3477812248890 +qadd:6488119/859164,3475243/436240,3474202/209253:1454045177353/93700425840 +qadd:-1099325/87072,898870/374541,6289012/998611:-111158625395/10870677984 +qadd:-1328010/3161,1029437/61682,=2:-78660262463/194976802 +qadd:-9495731/39366,-5924095/3668,-4200041/90360:-134019132539/72197244 +qadd:8057514/1165,-3725111/9551,964934/671:72617561899/11126915 +qadd:6949552/3251,=1,2473528/7057:13899104/3251 +qadd:-1375009/860,2567011/520,-893444/341:74631239/22360 +qadd:777497/375,3031933/307,218759/18:1375666454/115125 +qadd:3512451/28,-4974729/35,-98751/8:-2336661/140 +qadd:1033229/12,=1,=1:1033229/6 +qadd:8918304,-107206/3,=2:26647706/3 +qadd:3773925/7,-2087107,1743275/6:-10835824/7 +qadd:91004807/59072744843943270902,66857083/90169331108143216589,49327406/40230329853973228555:1105024907262273351275240199/484231808118216434486399701089462490298 +qadd:23684903/30280432954739902140,=1,-97033093/13835661280927216350:23684903/15140216477369951070 +qadd:76895129/1344620316434429450,6943146/540322216560075233,-26842834/4119156804632661773:50884041715523364389289757/726528229807560676143208003430811850 +qadd:-3500080/5785508369822968503,17193686/1077431321752969609,-11569258/210771686269137723:95703118440466862159403338/6233487929911229465420510455923225327 +qadd:64737803/21853152068853546,1344114/484446976408948829,-57693827/360425471050724706:31391406050348051744010931/10586693444761065095093481009197634 +qadd:-30681157/96481087551474991,3533117/67968489447438645,-14011465/246504080723880149:-1744472925183103649335318/6557673781119831941716936724427195 +qadd:10201843/20635577001553626,=1,96155350/58811028695386393:10201843/10317788500776813 +qadd:-1930287/1991695532199008,-21005107/15139766280889058,85232497/42294449858268301:-35529935900150302716751/15076902430091964207158012827232 +qadd:48012711/4771810484651750,562029/68126124683089,-87432667/1413385161729655:5952815810837457145029/325084956041456469467279255750 +qadd:5866387/534388661369540,-74280761/494786664687655,6822321/9629582541211877:-7358437275760743013491/52881676681187080549726205740 +qadd:46722374/986410508713539,=1,21676529/310079888805331:93444748/986410508713539 +qadd:-56303815/448280769982579,=1,57376103/953365009027015:-112607630/448280769982579 +qadd:1417269/10344858882164,-51156177/69004831036706,=1:-215702512068721225557/356922619631147062206355892 +qadd:80037569/9275345057228,18450452/20021432962757,-15521502/12373106437439:1773601130997360284789/185705699269729891757657596 +qadd:6101405/2640485648371,-20543668/306400835399,14230627/825967431997:-52375784929790929233/809047008519944563485029 +qadd:27037665/2725847596723,3212701/7881968418975,3465591/735049950650:221867354952665272198/21485044672309587701018925 +qadd:4834099/48161095106,=1,72181809/308298507595:4834099/24080547553 +qadd:2911944/163084814009,-10109608/403642872445,-7803617/736030226402:-473338099824915392/65828022778751336082005 +qadd:21969634/11650585561,=1,-2791714/5600760747:43939268/11650585561 +qadd:78829897/49012267358,=1,-7604951/47216367175:78829897/24506133679 +qadd:19445492/1297091607,=1,62885411/4219108918:38890984/1297091607 +qadd:52380328/2810974779,49183495/4765727228,-4976759/496257510:387883919349243389/13396339041501582612 +qadd:8745425/897077767,15774302/979761841,20884293/386716906:22719209312471059/878922564516089047 +qadd:-57659740/421464991,=1,43283156/421488827:-115319480/421464991 +qadd:24026071/1736369,39164903/1294124,-6554987/6925344:99097438564011/2247076795756 +qadd:14218249/33339177,82993699/83617031,12153/57562:3955829388244442/2787722996723487 +qadd:87835945/5064396,2236259/32882,73177891/4440892:7106761339027/83263734636 +qadd:64270453/747130,52462151/4978177,54483440/786411:359145737780811/3719345382010 +qadd:77515742/83997,-78232069/771459,=1:17742985902595/21600080541 +qadd:16151167/91103,-68440793/300034,72464239/286942:-1389262325001/27333997502 +qadd:-47905567/27277,-20089455/87101,-96050621/89657:-4720602855302/2375853977 +qadd:-2982404/49995,=1,88907825/1729:-5964808/49995 +qadd:-98481971/1315,80677685/7857,20839038/961:-667681690372/10331955 +qadd:-6211399/6793,57937621/6057,-3438577/359:355947815710/41145201 +qadd:5865679/34,1860899/8,=2:55097999/136 +qadd:23345429/165,50130524/773,=2:26317553077/127545 +qadd:8189395/4,-30602711/48,=2:67670029/48 +qadd:31167001/15,26011293/89,=2:3164032484/1335 +qadd:87715029/8,57210911/3,8398329/2:720832375/24 +qadd:89586337/5,-20657924/5,4144685/2:68928413/5 +qadd:45374053/1934947640595205378,-878342702/35405417199994412197,25786213/6017346122507972907:-93059862349259521226926915/68507628475418090621542740789603195466 +qadd:866238635/23517962979026052651,140081155/7113881091341386771,591317773/7502259793356123703:9456742063465083425960989490/167303992143360186992226567080400879921 +qadd:187264688/2749316430368891609,74030301/204048834975005675,777410733/9632694272612564641:241743864302812512377748709/560994814594413644669245568234881075 +qadd:313283613/6685249134338162957,-295002604/168462092705930067,83793911/3114652596872305375:-1919389489962049170976247957/1126211059431114336488157420891928119 +qadd:622725611/642973530889486819,466130322/105261688931011189,-110468698/89768733490717633:365258608545449316873087197/67680479799363075510639822957017791 +qadd:172273567/735309213392006870,178508035/382275018951483603,=2:197114483889767511301022351/281090343484629926962696208068352610 +qadd:17553367/48463183083977111,292467608/23785726423353699,43459439/32702598236409962:14591430817907573630275021/1152732014440382376433523573183589 +qadd:72973408/18357258425372587,1146729/70850265929795,=2:26220985959472511209283/1300616641179617610304859529665 +qadd:201183991/7736480258952282,409452756/699726655055405,=1:3308496964840732241410547/5413421453498853777223961184210 +qadd:588622837/3660268385543296,96365803/346258205753288,877283956/8025277960045801:69567523696677926868093/158424745469213234294102294656 +qadd:928254321/705783785204222,=1,489283333/807148845748726:928254321/352891892602111 +qadd:152397935/976211791425421,-226290007/366059549380471,533087429/48259007602879:-165120253702526748340562/357351648469091954890550353291 +qadd:459988615/27514620962218,604652543/83262415165680,99455011/26970436598135:27468274284051179676787/1145466896841258418745139120 +qadd:144022423/2685255995458,33922842/6738872265491,=1:1061640226826987556329/18095597153535342866139878 +qadd:501792430/5780638369569,90233731/2388030172166,=1:1719904030652463235319/13804338840911244605216454 +qadd:464061973/6928147630370,-406560643/292003731780,-29850340/7482218860353:-268120432750896392597/202304496239080406215860 +qadd:29675674/18924786675,93377112/3121810099,=1:1859783743715414326/59079590163435630825 +qadd:125587910/783335021243,14748484/85895896271,-115687727/148918581825:22340490117693729222/67285263730130309484853 +qadd:-888517823/89522905525,=1,28721/1399760:-1777035646/89522905525 +qadd:994205969/53771940024,-568804915/41456863842,391201703/96086803818:1771819618833375823/371535999349193035368 +qadd:-84977861/360134264,-218217210/484944491,111762569/4111268304:-119797039864397191/174645127347139624 +qadd:-701405341/632889150,630062610/2192126171,-791346445/5983383139:-1138809214795597811/1387372869056944650 +qadd:-234546662/963657213,=1,=2:-469093324/963657213 +qadd:-452856/2789081,8372197/60736948,-242353549/286862486:-4154355742531/169400267664788 +qadd:-187052767/74234724,166350269/20205255,=2:952168605650019/166659058697180 +qadd:-274903712/23604721,38495599/2095174,-791027856/11974547:332706764236991/49455997716454 +qadd:-404894266/6164955,157832653/6403878,463040423/4614886:-59994899225479/1462208136870 +qadd:-540899545/680681,-21287447/2541780,2338951/144008:-1389337606201507/1730141352180 +qadd:78913331/78528,-590670400/833879,-8890225/542326:19420004369749/65482850112 +qadd:177364406/602109,=1,99001438/992219:354728812/602109 +qadd:518975591/39351,286741895/4956,-6511822/1385:1539513704349/21669284 +qadd:568231946/63665,697042925/7473,688346609/54619:48623635152583/475768545 +qadd:294003077/2932,799278104/9869,102543194/2815:5244999767841/28935908 +qadd:164683586/4895,285199167/5854,=1:2360107634909/28655330 +qadd:384813481/51,67752725/82,334380330/11:35010094417/4182 +qadd:-371677859/928,302076121/569,=2:68841938517/528032 +qadd:63675311/26,781198705/94,76504922/27:6574161391/611 +qadd:305503526/41,-254218383/23,-132508301/80:-3396372605/943 +qadd:642014667/5,421175863/7,-384744890/3:6599981984/35 +qadd:-20761287/2,278595273/5,413571671/8:453384111/10 +qadd:3167550432/27903875703136810681,-4353020263/68180687168471384344,6171494422/98306365101160490945:94499628742560480702887407505/1902505420103480375489882725653115378264 +qadd:-3183422884/37568196826955204211,9427961279/82738779554479999510,3089033603/9902435878598192629:90798980778421373608402959029/3108346755524761642315503554707229936610 +qadd:-5214220143/7727885703296351326,9213475679/2261661519763659362,-7239565223/2154991508915553068:14851971481103269456702367897/4369465431069270378226759286135253503 +qadd:519540517/134490908117547849,304460068/27850900631653987,987127340/519856570607360343:55416782343935509070885011/3745692917842731715413863484123963 +qadd:-3438305188/54619481101719075,-8594462002/390499828982107557,3593936628/135385731106207271:-604027547599991619791064622/7109632676437584813745363082849925 +qadd:-3992299182/540033726318821255,1110234925/68696689237726709,7386509615/931861031447596258:325306567387162498253078837/37098529074815619108104756710399795 +qadd:7394803302/93918095118354223,709650140/69209592401912969,-1612636291/26972979365753121:578440311773013525199364858/6500033082305387937149168159618087 +qadd:-3798450956/49564671078478937,8201952752/84323457683098803,=2:86228571904512932003378956/4179464444262829754322889925412411 +qadd:-9219410394/2493025593271873,=1,6505447590/7492751055706253:-18438820788/2493025593271873 +qadd:4539114361/8367641580192862,-1348803394/4603788574100933,=1:9610819468569602203625185/38522852699063773959572394140246 +qadd:2699722113/384212226724151,-647713391/102207743232507,1954070238/94962673621469:27073100289464582521250/39269464615811789500145176557 +qadd:168180211/23676230652675,-2799553761/104480802434474,2701278780/97731939901727:-48711277171120629966661/2473711577215174081940317950 +qadd:7857451474/65235454327413,2128537376/31498366243961,2221032207/18007954017209:386352987048442714936802/2054810232496045180328002893 +qadd:857071657/98686012424000,2073820807/52588250038741,=2:249729004524185769231837/5189724696679612807318184000 +qadd:2786190922/1961053446085,-4894735831/5462640499350,1754691331/2787361615253:1124224160076048145813/2142505995194760540508950 +qadd:3344367971/2002173783671,2783409797/7740436696732,=2:31459738694869961195559/15497699428361765200663172 +qadd:1886117201/422471806113,-7056920135/27481905959,-158290687/733655902149:-2929515699483111484496/11610330445926347327367 +qadd:5224375095/163575252188,=1,2792946472/109584621039:5224375095/81787626094 +qadd:8503914901/50951147588,5076419507/35985026241,-4565632313/3078383356:564663000383475116257/1833478382963243856708 +qadd:724347429/20249465581,3428823/41714000,2510643935/61823728396:99647261975147163/844686207245834000 +qadd:5343861871/442016043,=1,-5208128746/2708679643:10687723742/442016043 +qadd:9071089245/73007971,5216095151/4614034969,1604438701/1558498304:42235139506867257026/336861331209737899 +qadd:783186604/763828989,49730609/83655528,4913761943/765103417:1045490602777487/645439569459608 +qadd:8924999897/754869543,=1,-9645157610/502961879:17849999794/754869543 +qadd:-7684261227/59813341,=1,-2457478286/10588905:-15368522454/59813341 +qadd:355855462/12114485,2701511099/2628520,=2:6732557777029051/6368633222440 +qadd:3297355561/5434460,=1,=2:3297355561/2717230 +qadd:-992155139/1824719,-5941097341/619600,-1877283138/586285:-11455572523096579/1130595892400 +qadd:7275838099/179284,=1,6914524937/272956:7275838099/89642 +qadd:6041862082/922449,-5732991383/202771,9340070011/437822:-4063277752027745/187045906179 +qadd:-1436667881/18842,1512607713/43240,8383142315/71207:-16810482323047/407364040 +qadd:-118807714/9521,-9807321655/32654,1426332047/6126:-97255056570211/310898734 +qadd:3925687044/7783,=1,-3015747667/6013:7851374088/7783 +qadd:-2562020810/4693,=1,=1:-5124041620/4693 +qadd:3975212101/482,1639405105/322,-1189434281/368:517552889283/38801 +qadd:8766298199/223,-3219733643/528,1656354148/249:3910604846683/117744 +qadd:-1513168265/81,3248422098/35,2306426618/37:210161300663/2835 +qadd:2780622344/31,-2851908379/85,7370056704/83:147943739491/2635 +qadd:-1219272487/5,3254817416/3,6042779700:12616269619/15 +qadd:668084801/8,3276722729/2,8177104324:13774975717/8 +qadd:-28066364019/27142028496153875629,-83994986165/97945022620202828816,74560676951/94359392114426445353:-5028754966732282316332384444289/2658426595013981116986784879127641325264 +qadd:-3000528509/8658875177266760687,=1,3036743401/4590071950395407738:-6001057018/8658875177266760687 +qadd:-19793548593/942761710813665874,86192869057/7249541417045877905,-119695723/4978025286900417400:-62234813623148059219131076847/6834590068948699455368850293669113970 +qadd:92023085779/187292712323684346,26983243077/439795491723853676,-11509377282/6925087095539221979:22762551521651139809665123123/41185245256344513090796650857877948 +qadd:-39019146867/246528590445069470,28418521119/84449846740292087,98982289401/711557146503937079:3710816981145410193486195501/20819301680186352926550356806283890 +qadd:-42497869768/371989720063193939,-8478338149/81277488191100360,=2:-6607974742863148859707195391/30234390079646974039120816492718040 +qadd:88261843372/63085394341751879,-44784460532/26919006654835821,-41422100021/1786615630050841:-449324203944898245335311216/1698196150108560878202120263257659 +qadd:-24150972023/9515359277743228,42712236280/42853813844399797,35309213749/14159032046882283:-628538985474890673067967491/407769435150990797236812341324716 +qadd:5724825303/2203041349747678,27488395054/5646217321045969,59293151082/7082646499343447:92881678727922393840538219/12438850227925830110937189009982 +qadd:14619758075/4936846021982826,-16036864556/2323794990231661,39713546516/8749338469186367:-45198210415282107094702681/11472218053428795611140303453986 +qadd:14605450543/139939857109890,10799789228/278879311148721,-67807143038/835875361732289:1861492982610600772490141/13008776984352189991676650230 +qadd:65048626819/249759029072891,=1,16664913404/344763311872831:130097253638/249759029072891 +qadd:-16329783973/23223035673496,26102319760/44353999342379,7133401053/27271403075635:-118116124652153584810807/1030034508990285641359886984 +qadd:51518424902/90611385027845,21848929639/25416816549026,2259015995/982451260279:3289196130594630243043407/2303052950505897517817628970 +qadd:9823437047/2983803001614,=1,-86833764787/3363958851767:9823437047/1491901500807 +qadd:-98079469262/7501490848143,12931722520/6785167928089,-18159475732/2680006300059:-568478471106008568619958/50898875115673034643188727 +qadd:203196757/744982367287,10110532199/185236774284,56534913639/177096148301:7569807723954107571101/137998130614702004447508 +qadd:18053774608/289402099045,573966551/105073103957,=1:121357250637861762803/1788728049313487965945 +qadd:-87887709416/27708207675,6077181331/13094753558,5647506134/79889599187:-982480093181655186703/362832151038009157650 +qadd:84536683600/44724539921,14048255833/19894148141,62917100482/62400348937:2310087085710674796793/889756622726442436861 +qadd:-30706897551/6897893812,-35459830323/6252261713,31231362485/321173596:-436585704042722426139/43127437381107219956 +qadd:855281852/92743035,59782619892/1409591731,=1:6750019835289018032/130729815243843585 +qadd:-92900956537/439171163,11759229380/445905849,-96227598684/119216995:-36260765454744715973/195828990293832387 +qadd:82493426014/179464353,31442888876/890956139,-20219675248/552201081:79140902042897837174/159894867037013067 +qadd:23749016299/14965184,-98465907028/12423329,85060246231/4151941:-1178518573492073781/185917404377536 +qadd:9492555875/3149752,=1,10314585429/20597380:9492555875/1574876 +qadd:10417790685/234262,=1,28830989839/9136194:10417790685/117131 +qadd:21932976869/2808786,-13004555792/3211065,28289083248/7503535:11300400041688991/3006398139030 +qadd:-66836200744/46967,88530220745/490268,64385021287/164152:-28609651588628977/23026417156 +qadd:-77417153575/956591,18725852581/31923,43130968451/307644:15441594252736646/30537254493 +qadd:97474118123/10596,-23947620716/12055,49384521647/13258:921301504866029/127734780 +qadd:18734763309/24325,21131785949/50033,10659403415/5989:1451387105848622/1217052725 +qadd:-1439500917/9212,-33183518225/4942,-6451501592/4165:-22342898815751/3251836 +qadd:10232528693/1811,2932687043/798,34761925483/737:13476654131887/1445178 +qadd:14228896673/466,=1,-17513625375/892:14228896673/233 +qadd:5540039685/212,-15534067884/379,=2:-1193547350793/80348 +qadd:63449652064/71,828572732/73,=1:4690653264644/5183 +qadd:23839394581/78,18502903317/17,20062169746:1848496166603/1326 +qadd:98566503851/9,36994496837/4,27511550439/2:727216486937/36 +qadd:1606910501/2,-3681246287,65435551585:-5755582073/2 +qadd:750601900272/68617053518286344873,392311613561/52425272355238879732,-189516578487/12053234670522747307:66269776035679860138095215709857/3597267718910163826199560785077521814036 +qadd:728582633219/15054433453572577856,62100633056/55101558283029999661,34066971933/506753729147298419:41080928276086479104683504546695/829522742360026001203093417822576106816 +qadd:-579689114306/6008640125920920437,29545305921/385791954401533340,=2:-46112285663876043987863954563/2318085017474507283487811656942869580 +qadd:85157683276/9984413431548073099,-194463047535/4351994325185158469,110987855747/722945613070544238:-1570993709385158332729520696521/43452110594399688796381640689910925431 +qadd:-333254398312/3739752515251807,-222688186129/229969682138676072,343987180862/318762259733023233:-77471206755319178027151175567/860029697209772394782614685662104 +qadd:228232045087/269100475905208142,29685295504/987729914318359197,296390204576/285221182007931887:233419945485999538709461908707/265798590008880921671259700204981974 +qadd:186728741043/8484893283352760,907466508351/17668153885239362,242986408459/13685130290283387:5499454306559858179393716663/74956200115055216722781241669560 +qadd:167007555005/37196512845456713,32846177456/14691839559620265,643735617275/76387090563153388:525058780720595868923519779/78069314128972040645085253584135 +qadd:-406143410794/7443920130626979,569165220942/6593136079301147,=2:1559061670746557697064613500/49078778384672842351253263844913 +qadd:288899664973/5110051533246567,475174065413/4997103188916189,=1:1290608466212034033663878356/8511818270770826983316411657721 +qadd:285552853103/243786904599060,51739173381/25270326775286,-567539816837/84226741155405:9914673417298061239217159/3080287371376859806273415580 +qadd:750126891973/878577129895100,663130172971/179676426138219,-920208514541/740079136878614:717391123215580915464958187/157859598786325375229570826900 +qadd:318766376313/3618419265449,=1,34811188877/1841753199622:637532752626/3618419265449 +qadd:254236024269/14780919746920,-844586040520/76436593404511,=1:6949177131533900664879059/1129803152840031671306356120 +qadd:706710361987/1301067543579,=1,84203887945/2012418539922:1413420723974/1301067543579 +qadd:195640325029/3728726838817,603560861264/8341120578151,829455171841/8240881232572:3882373123270122662726067/31101760165560405628887367 +qadd:-70222263648/919970997005,-140598797839/277541553572,762482298447/448122269015:-148836412373857769622851/255330179749949459051860 +qadd:183632938397/738585229043,230841150433/35550437411,546670119297/439718525656:177024095248187490795786/26257027957782270927673 +qadd:-284412871457/19847149579,=1,71954251519/4976484407:-568825742914/19847149579 +qadd:80467423648/24677301847,35760826979/13928733407,-87061643423/13617181915:2003290013600243538949/343723558630931702729 +qadd:-271527910651/69743572,727102134527/552678311,235157903923/742370011:-99356886977216080017/38545759576066892 +qadd:594385696266/5016006577,171921164870/1559514399,=2:1789310745599888884124/7822534482310202223 +qadd:-274331202943/376136849,249566712436/202764467,=2:38246616684759927783/76267187706544483 +qadd:-177762749877/158322013,679117341835/140151101,=2:82605579510477149278/22189004434486313 +qadd:438527654989/19442480,=1,473198805899/30758263:438527654989/9721240 +qadd:205749903939/22577983,488255989076/24418833,755328978737/79282170:16048007965058596895/551327996353839 +qadd:-276465269559/4305250,=1,-6551354097/249518:-276465269559/2152625 +qadd:-77677567229/1108443,=1,403947412538/8640625:-155355134458/1108443 +qadd:-26363673381/34468,-404935701883/545635,=2:-28342266697745179/18806947180 +qadd:161513177189/516563,=1,=1:323026354378/516563 +qadd:63971909733/10957,29722925483/27477,-254713864821/72353:2083430258250872/301065489 +qadd:431338979813/33787,-14639411201/2198,=2:453461291380787/74263826 +qadd:604394639929/9703,-130898313877/529,19351109647/68:-950381575026090/5132887 +qadd:-436971275441/1805,-45135172974/143,150879980149/913:-143955879606133/258115 +qadd:133419066709/724,688077199855/411,308833205069/124:553003129112419/297564 +qadd:-752571481496/159,474015196916/845,-32200650919/727:-560554485554476/134355 +qadd:764385897608/49,-511836952661/77,814778276083/89:4825386205061/539 +qadd:320831977021/60,65509179103/10,=1:713887051639/60 +qadd:619010459321/7,670048524077/7,106364585881/3:1289058983398/7 +qadd:-966054954552/7,26919072829/6,=2:-5607896217509/42 +qadd:8601789733890/36226606798446835733,-9517603014260/49701591537140834451,5475796113274/19588834568871216561:82732177780862722364959957691810/1800520013873013869891754119384144237583 +qadd:2152113882697/44696374362534467140,556748656281/15909675605329183742,=2:29562040053204167968772348309257/355552408421137678797712040098560618940 +qadd:405932999909/48559005322063228,3790369457927/3702874233536819343,2557162633138/8338270525184407851:1687175416585403236677748248143/179807889613245206691727609459419204 +qadd:-6087806259569/972879120187377883,=1,7399937003904/6443577898545254653:-12175612519138/972879120187377883 +qadd:9620990949187/730309117665819684,7567489620737/569889108783714498,1735576396811/51095649586994799:1834917437585674959063670400039/69365868700532477556648779567429772 +qadd:8651924819461/863956468553652350,2187645516348/235829108485821557,=2:3930406211611089677582520538577/203746083749566560575560722713708950 +qadd:-4336348697751/46994132323169285,-8481317196881/25836479901410330,-4173835305205/32784713158384997:-102121625719989497206007233583/242832591050356154167841367542810 +qadd:9803783744995/7173215879645536,1461730234625/44252775572438103,-9376571794387/92339718365720632:444329948358750525431287428485/317434712454603074916166940258208 +qadd:1451028299837/7491788861639837,3708310594713/806013004930241,-8365440578715/8478738861000634:28951427689162292314899052498/6038479252673234548881051610717 +qadd:106500181351/1880557932860660,1907360387663/8006540878394810,-2341315210208/8571856456239177:443959976338708048693922589/1505676396363851684553219717460 +qadd:4027452706139/119900758316566,-4327345628086/101821781711479,-7365940733989/364587320094438:-108769612007597347818603095/12208508840350183550358061114 +qadd:6083358310044/255539217667673,=1,390223928059/413168482858447:12166716620088/255539217667673 +qadd:91210522789/5821394937509,=1,-2769366574049/39367880017274:182421045578/5821394937509 +qadd:1597250023359/36013018587610,665933164918/3231381509477,8810376679036/2323736290015:29143587637791868491339223/116371802364454460369779970 +qadd:68049078655/7615630087369,4706208009519/4980776034536,1596034611713/3058679589429:36179676534846948814094591/37931747827058819041375784 +qadd:1937588720533/7799363656349,=1,=1:3875177441066/7799363656349 +qadd:977734823551/117979135196,-1952291322312/890529662717,=2:640372220786512478954915/105063919473737223687532 +qadd:-9025156691504/937177282499,-361352397466/257871708085,-3807710093346/955531800671:-2665983829654588301357374/241671506616475707304415 +qadd:5896871870580/77613420173,-1845035969569/26828471132,8388653136749/65162440481:15004504808501131381123/2082249402567116945836 +qadd:231439434868/1670462139,2207560874293/16523176383,-2335974950174/54347294915:2503920488116666405057/9200446854606821079 +qadd:1929296372726/4735837665,-9028612240726/8555200715,-6233988999387/5091294091:-1050100968196714241828/1620641671109277219 +qadd:-269105387231/230611014,3594113298975/2873349794,-1154532309875/4520020294:13902050835756457559/165656527392757779 +qadd:2346217941151/799817318,-4884282294533/960803076,7966051335112/524910443:-826140075172001171009/384233469686235084 +qadd:4064314284160/311969293,199296652936/441645007,5304117147258/554326453:1857158546391753483368/137779680590770051 +qadd:815037963837/2968034,1418934409295/75864896,-339052747818/1710509:33022107966551620991/112584795367232 +qadd:7244018124286/72201723,6446019776692/10593765,7229442366932/73382069:180718386677888105702/254962695352365 +qadd:922615490114/3707093,59605234097/120775,-4190680399923/6307528:332391031902868371/447724157075 +qadd:-1218581321862/9688639,8211974626650/9377609,7971851835717/1568942:68135478463646641392/90856268284151 +qadd:-7077925805906/637155,=1,-2581658464835/734183:-14155851611812/637155 +qadd:217345331728/72451,-7227574835869/612249,3818947938173/281665:-390575562428408647/44358052299 +qadd:-3974762894203/14013,-1180890047119/1669,166220351784/5539:-23181691500703354/23387697 +qadd:-143792410986/14239,-1333280413059/7621,664497465190/6971:-20080421765671407/108515419 +qadd:5469270207451/9406,=1,=1:5469270207451/4703 +qadd:-393435064451/9103,4634513061154/615,1392205495718/1811:41946009831047497/5598345 +qadd:9578810210563/843,-4536594375665/136,4023125278157/374:-2521630870049027/114648 +qadd:993337628557/102,9593218874931/536,-4264424459806/127:755468647074757/27336 +qadd:547147143651/2,3730254823821/5,=1:10196245365897/10 +qadd:4901257128118/35,=1,5319057215527/23:9802514256236/35 +qadd:-6031845023279/9,=1,-1602500231005/7:-12063690046558/9 +qadd:-3297542082233/2,9743508972017/4,284781600324:3148424807551/4 +qadd:40957392574416/70276993727723336737,-10014910049617/17689665613055704872,-2779499153404/26725645738443989647:20704808283422464958622124875023/1243176519334238965594276156105347482664 +qadd:45844224448349/22079296648506779147,70206864303623/53740308116805165169,=2:4013800930951401093187151667305562/1186548204893097943291939751481539930843 +qadd:27961919364631/8718044862129208525,=1,-8519896737528/6252014363663191811:55923838729262/8718044862129208525 +qadd:-2067336322439/584317644440385925,2723713099539/473511695651648882,73786916799403/8182802497184968644:612605694933716051550733725377/276681238618144405533343878674785850 +qadd:32025894755248/66303294333949585,80751708273853/638681646107513563,-64873077706462/49077538736861797:25808455461998285269484001129629/42346697167557898041297541745721355 +qadd:19660637614444/956621220581308491,9683558119459/148734533812110639,10732473730492/212642830728841369:4062570985946694749593020498695/47427537092644392555022031027378583 +qadd:26463069132061/34590442491713868,1778591564927/1271271116297649,5452080117585/10453906972591852:31721334893010603543531044075/14657943479890240114084276365444 +qadd:26232104044847/79502877559485212,3370125338191/2578727156176402,63787406469289/92688221566095237:23970007227600682942443887999/14644016382629427726576098740516 +qadd:98696102763974/908742099728443,-35107937305612/133127339221267,-19866428041535/3060805116764176:-18764911111759790278837687058/120978417775194877383790397281 +qadd:-37908147551011/7228589226446608,-65775689566867/9504572716351133,=2:-835766185905903522330926482599/68704651939394172248397204806864 +qadd:-18185796452231/303760253880903,=1,18122968385557/178311473629270:-36371592904462/303760253880903 +qadd:14892304197019/46622881145226,-5611369712763/826515187978603,26394608317645/273451712601507:12047097379653626883559665019/38534519373850532904623599278 +qadd:-54139396579777/32007668492293,=1,1733479907912/25396380277249:-108278793159554/32007668492293 +qadd:-63788344296331/37589271154908,50915695251657/90027727110574,49591638223605/35445794413654:-174037989922283184534946429/153821665719064918309036236 +qadd:12071763393847/4649104873226,10020556788045/927371358623,=1:57781627015265173305975851/4311446702664405796927798 +qadd:18238074461897/2396590395463,68187595826700/5705685211381,-78696625586088/9509272732285:267478448989293363689511857/13674190377130981538364403 +qadd:-13345085506196/75622603113,-97672417230952/129165419515,-753859024931/4781291931:-9109966011214978026968516/9767825255906989950195 +qadd:3709838273470/57134914859,-5914995558694/134539418847,35401578919795/686522759833:161166717691666830854944/7686898241002684947573 +qadd:50811177302193/40048826548,32735197100597/82993263421,36780634570867/8850752755:5527991653268441530231409/3323782811400102100708 +qadd:-6542615556879/27016465451,76463178253406/72959925957,45891539817416/380667753:1588416066961789560067903/1971119318924808611607 +qadd:-21080435888478/3413079223,=1,81032696758521/2284760788:-42160871776956/3413079223 +qadd:96607459901/40160793,85203204881021/833797549,-4433713970891/1573415279:3502379337443843592302/33485970769296357 +qadd:16594106768116/498044839,23534220395438/517318473,=2:20305534981917169251350/257647795597010847 +qadd:25304409260441/118009964,72369014966310/788591957,71991883509399/461244341:28495118470309795185877/93061708456259548 +qadd:24936005724654/48277589,=1,=1:49872011449308/48277589 +qadd:24088512125936/40097553,-37235147981069/77180983,-72573429878023/38036452:366136725253403050931/3094768556434599 +qadd:32272280755220/7617329,65546010555974/1144891,-33329793981457/2504062:536233770828451454466/8721011416139 +qadd:95637195200652/7212125,33652777588976/3406657,98881012460311/8766053:568511159059561074364/24569236116125 +qadd:92571834195973/96535,59689565610747/775016,98663660317905/721679:77506784867459672213/74816169560 +qadd:78835501537635/372197,46671694263162/529757,859020873535/3702:59134723377739011609/197173966129 +qadd:20589023961027/22664,-69820834854036/30449,-24367466631311/33338:-955504210542560781/690096136 +qadd:-91531024180004/69325,1402659330981/806,21471287770931/22199:23465352631174601/55875950 +qadd:48834248870857/7428,16091745523789/5821,=2:403793648427963289/43238388 +qadd:89161018973989/1000,48863562276307/5136,=2:63349319465839313/642000 +qadd:67440349641709/582,-25644394065531/125,72123784494178/345:-6494993640925417/72750 +qadd:98894870521648/469,29922116846031,14386819758147/956:14132367671310187/469 +qadd:-51033784779973/2,=1,-595583264213/3:-51033784779973 +qadd:16012808775283/25,6902989657994/65,=2:242681462368649/325 +qadd:68123975569655/6,14855844433571/3,3396209893164:32611888145599/2 +qadd:31826754876396,-5624708171537,22269353475089/2:26202046704859 +qadd:989539922242669/82345437022131993998,-129844086283131/1228275122105070002,264019311827057/25912304890942474571:-2369160190225845180087828586083100/25285712928288631715150750102408461999 +qadd:458886340685990/45233073912526242751,-178745004976918/2119200954833746507,13324270929603/4608288006661132729:-7112713650273889105018361873484488/95857973425491043563396362893480320757 +qadd:412133102761216/1699197444312646113,134603450929112/552586191322068273,374607145779807/1505793782999860840:152152300462325569979931157947208/312984348018972438363137729558024283 +qadd:996107656472793/1538223134855538644,744500995880956/9784839986634291135,-657762555721801/3044920577968213070:10891962683834633525215962650253719/15051267238300426155470196651539120940 +qadd:735500231252758/172429147160677843,157779442625545/116184147677115296,167157993204247/685504231666635064:112659242215832711691135511285803/20033533497555240149484858223586528 +qadd:-809798210635595/265681969632351751,315376974249563/452100583295838976,-147441203225015/637765515904619836:-282320267684963796331611659915907/120114973441973604125868871487646976 +qadd:197530115746410/16154772056586701,805221852820256/61863667133511779,=2:25228112816673602730686944978846/999393441126437183906946118251079 +qadd:411518791826609/66555460731929013,73839516309311/29351284060524212,-941248859041399/40678192937974455:16993027983335510295184953297151/1953488233721913143499638751762756 +qadd:-44838693896353/4828879954536720,-214608302698603/905841390888158,945153758378794/1752566248144451:-538467237911556730436461644967/2187099667224743806751112080880 +qadd:159386221465363/4011294024192533,=1,-762687138435905/9496408082934519:318772442930726/4011294024192533 +qadd:282181219877794/834796594900371,-521732855952853/336927589199157,-509894079886271/627419469371216:-37829574829598341107104487645/31251778243494142409565798583 +qadd:-168247676776493/775628684714855,673499386955615/114978736437813,502043901819392/813501396039933:503040538376286093357421431016/89180806113436869664344812115 +qadd:-201804504690605/26153756292047,85735155596543/849483132120,546053722691518/68002507655451:2070866842412214685073860921/22217174811671243006249640 +qadd:-578160618834941/32832087076522,-257251067168429/84222664665342,-767269979542346/64606844680255:-14285079340160980125721709690/691301465027305293568825131 +qadd:682356166873497/9733351318990,138039263801749/4525351638292,=1:2215743124028395589742030317/22023418668731497795382540 +qadd:58719414801037/9289988230905,841010929365368/3284665753905,-902973183034592/8703989774549:11860526350745264583518663/45206675846272813400643 +qadd:446558621707731/443226736633,57828945916797/134385109829,-908538462064135/423200304851:85642164404908478623312500/59563073681574962665757 +qadd:-85597540319717/430995215447,152252722498749/811556745487,26984142839919/361403086885:-3847066307821160533891376/349777074368635709937689 +qadd:518235731671330/34633881143,=1,-927979812597974/20035419799:1036471463342660/34633881143 +qadd:23532022732187/25812132498,=1,=1:23532022732187/12906066249 +qadd:384857284291123/2633874476,313185874888348/8412878237,14688795975121/1210141392:4062649753475859805995799/22158465258130178812 +qadd:350680888140817/7696173335,-273757008800698/308695203,41351671290449/282932970:-1998627883448442480586979/2375771789971012005 +qadd:177593161287595/783161477,675923932791229/349011889,38454414011850/16453799:591339710238892839502188/273332666479800053 +qadd:-214254215144366/468801353,642094736898653/672467862,622095989308793/572560927:156935807429647724912017/315253843554617286 +qadd:396292476888376/40820787,78144967762423/8506238,572072869094153/34215214:6560897210173761576389/347231329569306 +qadd:-990761108038976/66972235,199957304336881/31214504,391113668586297/44776622:-17534528993910935008869/2090505097296440 +qadd:129684204888411/435077,76593779471978/829233,794637299697182/2210281:140862614063561491069/360780205941 +qadd:-316924088772521/8106207,321543746152208/2861707,=1:1699556282556306801709/23197589315349 +qadd:-273436429936583/946788,=1,209148812266786/332615:-273436429936583/473394 +qadd:-11329905072416/21011,546335249793749/483215,211883734808434/150249:6004269853848962799/10152830365 +qadd:516486908449729/1259,=1,278592054186065/36029:1032973816899458/1259 +qadd:675867112050751/79570,32097018416251/18680,522495180002645/78606:303583148169782415/29727352 +qadd:329176312670383/3138,479733224022673/9258,713130808296677/5238:379409763307129474/2420967 +qadd:-590917948306039/2612,816884550900490/4193,586769063997713/7174:-344016510295141647/10952116 +qadd:30172372558544/23,306945914193323/126,=1:10861474968822973/2898 +qadd:508708694453393/132,994695576147517/309,369736266501912/373:96163600879190227/13596 +qadd:140754426286115/21,=1,936716007464871/86:281508852572230/21 +qadd:851135198263564/93,-329349905996065/59,=1:19587435439916231/5487 +qadd:869963899450784/9,129438400763333/3,509437343941782:1258279101740783/9 +qadd:154547978608621/5,-497290343697757,216897795092209/9:-2331903739880164/5 +qadd:9731985466163977/5512338322751860171,556192589204029/57909174483790815689,-2632702504578039/18742877028358340228:566637166158105995162688554656064112/319214961745924282983965333270161022819 +qadd:649650388871168/3992465323969551173,=1,3565435999230529/84697466077371826772:1299300777742336/3992465323969551173 +qadd:605861655156859/2232205883730936795,690635835332709/557617629319401191,126519874372049/3918127150315881558:1879480514989199709022928131546724/1244717353038863867397627790868722845 +qadd:-942787630105114/2000750159815160879,6984110317895009/2298603201956044128,-1258842818920025/4276881172498189494:11806365169370987723241751703682319/4598930723665195806685719802743268512 +qadd:7833433836634319/173628534804912798,-279606913169869/51244112549651791,=2:352869626519730853604034544331867/8897440179374084695171531019521218 +qadd:7799997395732343/425865243834023704,9146433465939454/231677503759473387,1415892823490823/620146895568068431:5702232044157642641957254148473357/98663396629386077325737960315165448 +qadd:1103157747790413/55167635654497700,-8423319298239707/88661359798471577,=2:-366887144055470035037200946582599/4891237593994409584782505661872900 +qadd:-500322660362609/4271749116788519,263022279423891/3828812275602968,=2:-792076353933982410819593516083/16355725456656018147722464724392 +qadd:256405572619155/2602216073605499,2786963243737596/3122526924111005,7018660290695751/8853212585895845:8052913853397103348918187941179/8125489752187595377205654416495 +qadd:-4368184742676481/4675799278313048,9534128992433354/6253368044316277,=2:17263806580640358427509035221755/29239493788639924359785127882296 +qadd:2104015488715397/853633108483362,2250989455424197/214830172967862,1713791260754447/4504214438916:197793761447068078680364356794/15282179028881197103432309337 +qadd:2995889241927464/698314621089197,1530024756319507/462119541131685,6069020753402648/565006088361631:2452897619727218797598520162719/322704832263286198576707906945 +qadd:5394634397912672/14716326174237,-5034418169062420/75667401230663,-5368809838944386/37114054397355:334109825606166663739353787996/1113546157267298892365029131 +qadd:1863023478221507/7872199669441,183894543875548/37986075021761,94003419602892/2702656613089:72216604178533377861245942495/299033967229667971081705601 +qadd:-8112425603423209/3805513596434,-3425559927153486/4012067294371,9145612321513257/132453047192:-45583612319694234728476725463/15267976638537011973873014 +qadd:213689004449671/1644968610003,=1,1668412523740720/2790599079591:427378008899342/1644968610003 +qadd:6951530900384110/628329527679,=1,-5187804123446287/513799284482:13903061800768220/628329527679 +qadd:134541450167501/70194339817,=1,=1:269082900335002/70194339817 +qadd:1098519078141892/19462539993,1327840931140871/19058669129,=1:46779468868871976696405971/370930110136516976097 +qadd:393599031927369/19486752872,1205956039337142/5742832021,5417998674508339/69422174015:25760540437045892884254573/111909148378635314312 +qadd:-2774295194854405/200465239,-6897371711869624/4786302327,71942449286325/102497912:-14661298815608340389700571/959487239908311153 +qadd:-2018443788406565/3597931718,-2000020310248678/3595186621,784424627043279/3431202205:-14452618614207756440335669/12935235975825144878 +qadd:-1405824660836226/850566097,-4116287804839619/468886657,4256120357736763/794325993:-4160347277838789277433525/398819093779867729 +qadd:-2568463849296119/68653552,170163282864808/124349217,4853614637538325/536394242:-307704154764128593790807/8537015435468784 +qadd:5570716669286833/56389954,5139391070061720/86846191,321475980040349/37564864:773605549896559300463983/4897252715565214 +qadd:3347504025095300/41242589,8372336127620525/73791909,=1:592315530278270954466925/3043369374412401 +qadd:4075983457906123/7454814,1012312766726638/2012887,=1:15751097500406757342433/15005698188018 +qadd:615527827347805/803633,=1,-6945777364445267/2690675:1231055654695610/803633 +qadd:4703769450007771/437089,-8646742616442323/773872,7633024022889843/470014:-139280611661744758435/338250938608 +qadd:-1157040382968040/87421,=1,778971535469672/273235:-2314080765936080/87421 +qadd:7393810122090184/81127,-64368795434817/4927,501992012340776/76641:31207255204297937809/399712729 +qadd:1814818937088177/50093,4023822663774357/24016,=2:245150040289558524033/1203033488 +qadd:9908501657883705/3803,-5660305521631728/9565,2557272552018733/7891:73248676458892176741/36375695 +qadd:1377747830693440/3541,1463897897659346/1125,3757698108232021/785:6733628765141864186/3983625 +qadd:3772470251348881/322,-7016532949646302/455,388436705580099/410:-77549949346052627/20930 +qadd:334577361872867/32,=1,-5943062864162214/29:334577361872867/16 +qadd:2891305771316359/53,3527889195345726/85,-3763343617650326/27:432739117915213993/4505 +qadd:157402323585140/13,13773830296553/77,3582569222451484/75:12299038709910969/1001 +qadd:-3257588133523091/3,6604850595588048/5,=2:3526611119148689/15 +qadd:109197760602583,=1,4169449356780290/3:218395521205166 +qadd:-3861717767275060/7825274794195216053,16565852262776959/88858046256514809458,1031551014323301/4042869958710944726:-11237492096729581651889648474747087/36596769980659890200362549910023043646 +qadd:23543644363949797/98639149864308555901,55730679379575088/70634154829730489785,48139816814712375/1330063664360761159:7160212256620979254852952806236317933/6967292983788559769917597132102781971285 +qadd:41977719284209529/3751208484710673761,33643459441010377/4194025619262446095,=1:302259260626319542881502707310457152/15732664488071225574728266592393413295 +qadd:-1144293144120949/1098190461076821110,-2402308164750526/582336022019013435,-25203695452988903/938005039894823361:-132182201146680605942090063054147/25580634580908088582093143527264514 +qadd:8034042612751913/97483447149280005,=1,2973340210414523/29561736054695294:16068085225503826/97483447149280005 +qadd:60674693832444605/936779720392078057,21951623942977712/65677242692581337,9097858504748373/818881964501261360:24548782731586239427877568624602469/61525109045678996656110378925422209 +qadd:1302350266814895/5681021273569801,-6236914506844097/7270414939487546,94223237947234379/79008878766068900:-25963417158520815055488814517027/41303381938908446247501001198346 +qadd:-11497844255386016/8204893553520709,7432210588726085/14197957440789783,-6910737086418109/19876126699691764:-102265406650952939625835597880263/116492729479097473986005206116147 +qadd:83714996362880378/8618647846387783,=1,7515078968456230/3062009508291991:167429992725760756/8618647846387783 +qadd:62679487423356388/9001151280591673,56594267794644456/5882920271561917,1634168066276183/300039595214940:878151993207885545835175648690684/52953055335988261889639614117141 +qadd:83131003631837727/747131006183503,=1,17129603086958644/379709519880211:166262007263675454/747131006183503 +qadd:12501751630346081/788796894918041,-21129992690880754/254284308858567,-57956809836544559/534410517601146:-13488273351363624099898642556987/200578673254017756079725707247 +qadd:14059107156579494/6975563866089,37801476305972056/48622905291735,=2:315760415988492217755116230358/113057393739098097672824805 +qadd:23369025294115791/55396441570853,15495067710884335/11665951387764,-3995320971632302/75709901608329:1130993526142997139892946869079/646252194420679895483242692 +qadd:23916091038454111/4545952132054,4689829346138151/3614025441053,-85746958882796523/8521123688083:107753101178558963579755411037/16429186659052283048812862 +qadd:36133728528919771/1785997287207,85398862837628707/8358840780430,-11562670053745837/5200206297232:64936888705012721610457704697/2132695279720460390708430 +qadd:2214561180442189/33997391434,36979053972484369/162888179275,91720233502172759/335502577054:1617917211336886663944928121/5537773190783741330350 +qadd:77386819146397237/20397632304,-5108066159735617/907423591944,32886890778350867/330998714751:973867124217134726941645655/257073510728453452208 +qadd:61459176891343089/21824932076,2685806673289617/2388630617,=2:205420819832094399137810805/52131700970678970892 +qadd:17677723892339211/42474225106,61979558493207868/9941645861,=2:2808279389977180084128489679/422263704224247186266 +qadd:-69708713419564832/6145206843,80609591382825001/4848452972,-78928998060128503/231637472:157383193823784636159601139/29794746381498087396 +qadd:88237221032149171/9534767920,-44968975337449001/556184382,12982666497195442/788160233:-189846289596808310283200299/2651544501549312720 +qadd:-38677387896784223/788948329,9340381978275373/50293174,=2:5423870154623606862407915/39678715587406246 +qadd:26537170671851227/590770266,18034613855208113/484568177,28604184788975171/455924538:23513382039645396684971237/286268470821425082 +qadd:9355751715852854/52744199,-484818910468440/5805289,-50172393950328279/68610859:28741457430061116365246/306195318268511 +qadd:36415297589875947/29546624,-56431669004414295/28023964,31517851668463121/32802117:-161716079264478302849043/207003381824384 +qadd:22971653327178907/4250474,=1,=2:22971653327178907/2125237 +qadd:12746116741017752/5218893,725501139000903/48970,-48129279516836173/1863661:4410490152631478975819/255569190210 +qadd:-88067684618536709/385212,73238199971779517/895372,39724956709082291/929816:-3165069089046207431759/21556752429 +qadd:49757444137808553/108115,26265082097157139/107499,=1:1169789262614917960276/1660322055 +qadd:10749049993334979/14455,11334875189797027/234,77927344912508075/2392:166360898566956410371/3382470 +qadd:1195996993464494/4213,45875551157589131/5270,69424135139802925/44053:199576601182480892283/22202510 +qadd:3520647688460679/2036,2261968838807066/381,34281322264491172/471:5946735325114705075/775716 +qadd:83644190506134287/6033,55464798606172681/8524,67985855300849238/2989:1047602209865328446861/51425292 +qadd:-8698786374318557/422,=1,=2:-8698786374318557/211 +qadd:1118529795834147/2,64597983578878272/755,=1:973685963012537529/1510 +qadd:33377257316975885/26,-40430802589313980/13,97778637401253684/49:-47484347861652075/26 +qadd:82705834958465143/99,24938695531635533/58,-74579422882928086/77:7265869285222896061/5742 +qadd:-32270725150155926/3,=1,-3544924711445815/6:-64541450300311852/3 +qadd:60911268114686151/5,80821489004159773/3,4534056378518212/3:586841249364857318/15 +qadd:-969085346219845449/53998644227029731584,1246624309530693/107133612642748177,-772081460522893303/64669378244722644671:-36505591524565947914216726766988761/5785069833852173313379335508415322368 +qadd:276516649995371231/15574713369274151317,906182816129897588/83697559064365646467,750261136246505381/40984550246015537241:37257306266652922286275605079793914273/1303565492135388561581093647071484447039 +qadd:-140672089095897969/179764890360901598,555145526681662554/1124929648758424561,5984750631146458/28478509146741215:-58450529038488266189701503004255317/202222854972785735655957430027348478 +qadd:-91743425611973129/1107094290508801764,399222195217559278/8079799590284695019,-114641110490499569/4406882677696803466:-299291879701184741517973742167178059/8945099994859541614229671597869213516 +qadd:787379889340800499/956625527086654593,-285703704338782123/459459292066701282,=1:29485849930128206284237638735099593/146510162482723096999644580814762742 +qadd:70749404862883911/495750154649066152,102340090236266554/158445453266377071,27037741921079909/605403590162096:61945037083254592502710474876284889/78549357960247816623822130455000792 +qadd:424824527328220007/23301022216991169,=1,67711743764689990/11333924060290899:849649054656440014/23301022216991169 +qadd:-6663229010931365/88920552753855031,134776639101635638/5309079009270841,366231415498310197/74626301054129981:11949037637948372264801755088366813/472086240118252220339551129451071 +qadd:-32510210684122177/1231828288285445,76160397879785044/676677566334687,-672775726216560223/5675307994591383:71817602308634310869101932830981/833550568259218150148260730715 +qadd:-268284492174317874/5274188879184443,649062356676662391/7205197273636408,231369253089740151/660306726485266:1490234771907975806226632438826621/38001571332943211163847952000744 +qadd:582099480882485529/700067254239488,989829037297761831/930885508478467,561464185181264678/686338297243911:1234814867553904104143762394986571/651682461931850019474109104896 +qadd:184995254328058087/463884296042206,313384341252881473/372141661203466,996350678876136763/997053196652451:53554628948286149849685574294745/43157668133836737280672371499 +qadd:8377174919585897/71232491917440,535206177263043113/25679501875292,746828700553904237/1616624309526:9584797843777708399725583136911/457303727443905678209973120 +qadd:-996273291922997387/44830395380570,-634598527946819886/29124087104801,366443615185294376/48189152110425:-57464853049935846730538932170007/1305644340006389055869116570 +qadd:10766817872037711/8299561973528,60868128026713114/266071146523,-227636182703270761/704789537906:10368235517264478808183285205/45066815712965051739656 +qadd:-61525671534270701/3970810675288,-811892456616177891/5068701282778,-89068223096904603/546438576974:-1767863242073427178167323472493/10063426581750431012295032 +qadd:550334687546784844/502931729895,-860005583438026402/162375660659,358668116551573116/644883640627:-343163137323871850866714435594/81663871908074365700805 +qadd:260849523709491673/297757912904,692166926358108721/802149515516,-997204026651783755/55271345816:103834624609928804772316783513/59711591394249731154616 +qadd:505448870437825193/71845789337,=1,=2:1010897740875650386/71845789337 +qadd:159638929481820528/13739032115,=1,507310009865603761/12553274018:319277858963641056/13739032115 +qadd:-133426952279941451/1589703572,217840769690702699/4142491527,735044017796589411/3007360763:-206417769588551377033244849/6585333577451634444 +qadd:-101118601209663559/3745310451,885199546740371601/9397717537,-459446735274124418/3192681599:2365063061722212098564767868/35197369706872079187 +qadd:-12152036723542051/235562910,891926788712621059/872286523,697897009879673835/130239658:199504811995153362474243017/205478351711661930 +qadd:400891792612792759/54587710,697440729090382751/929044415,-386357311385415463/638053959:82103594641605549540396239/10142881420627930 +qadd:167013298876326173/1918052,47488502066189029/1167594,759419503750021473/53966266:143044571026631590544635/1119753003444 +qadd:676855379766713425/63269998,=1,-714573170617706497/94972518:676855379766713425/31634999 +qadd:409288543596204392/5585379,130886150841077932/843311,-107608169043445049/3162805:1076206289287247740778140/4710211549869 +qadd:691213642440502645/22737,=1,=1:1382427284881005290/22737 +qadd:960631875359803053/230030,228919423015609883/333487,37946707333060033/44234:373016577094395382122301/76712014610 +qadd:251068611473963959/515543,94841287315376536/22327,-479143444821261102/650503:54500370674810358811641/11510528561 +qadd:-108350199223779473/51984,111736989262785999/14705,=2:4215245970250990221551/764424720 +qadd:88108619904503621/81260,154844354458466755/2207,=1:12777107967424248002847/179340820 +qadd:-486724060444092739/5751,-246250309508757077/2993,449147573438373443/1564:-2872950642894031517654/17212743 +qadd:-850389260078463631/6276,-954710858838119571/8792,340877365239969027/584:-3367096931169472667837/13794648 +qadd:219904330718240359/222,757977245624505558/967,175510199184903827/581:380918436333178661029/214674 +qadd:318243239218041752/59,767069919224699682/347,=1:155687529242917769182/20473 +qadd:697074341020289390/53,106833670515931911/11,44958754351960065/23:13330002288567574573/583 +qadd:516501254786898965/6,-164729804637666233/6,=1:58628575024872122 +qadd:82963845478413593/7,55644033089135156,233198647629741003:472472077102359685/7 +qadd:164451756488343692,271265725719237343/8,=2:1586879777625986879/8 +qadd:5043821125454793265/5618281832502940151,=1,-543884583593009413/8012420875585043886:10087642250909586530/5618281832502940151 +qadd:1764906175362120158/31402243297654667473,2229661152827134119/6508891977220041701,1894248816526157489/7307308465166355047:81503945637767463543703614619050520045/204393809466816291062044346462348291573 +qadd:-1362907275103916799/4719984305032890358,5677647195374925883/7969616636801670538,-8231092261190079885/5235441156455608811:3984139289399363012151226105338442063/9404116360708223470362017252248218151 +qadd:290807472633374281/1258837033388879519,1699792368148991135/4469792775816725417,=2:3439610722427910580290181520680864242/5626740677772171640401250773318034423 +qadd:-9803615938594182209/179436612901884445,632531485773805909/24631423728192118,1107916995642111584/51994977769890891:-127977710890922943063734246473443157/4419779244737900457684595195804510 +qadd:212099052410103851/14112064685928255,-1546460633714174323/543797344189345181,1466382576090755442/798177433526983523:93515148908475176743400909755195666/7674103297236030685795513595989155 +qadd:2231031722816738561/15236183051646264,2143589106723393457/20940609306247892,=2:19844819918725746241023330019364515/79763739150750040606892869918872 +qadd:-9575590803372574182/19535794897504279,=1,8043316090192509079/21730235406706349:-19151181606745148364/19535794897504279 +qadd:5016235407304247978/3059319382797913,=1,1013119725862020638/1523223220476823:10032470814608495956/3059319382797913 +qadd:2894078389438839283/1569075282041943,-2665448726814208207/4452815285777552,1242049344845007051/681162286716620:8704506777937400951911781308349015/6986802400412087425201031863536 +qadd:-2761359171647944304/524718540633809,640460627361693124/51241877637449,24526182054440865/932662203109421:194564336936009885784577260588820/26887563253258451827973913241 +qadd:4377034106342870447/284491641803297,367444739727332559/187288898129576,4771977529029312743/237034833694131:924304852129543576890267568687495/53282126120413516875010012072 +qadd:-1084950831949751089/12896572149034,1068560037854748158/52652358693733,3302405312908713775/34972953328882:-43344458745114066006755621245865/679034942710545208837803922 +qadd:908971092109438313/2042877065884,=1,=1:908971092109438313/1021438532942 +qadd:7969199262095318650/6376127197957,=1,903887938076097336/594071493169:15938398524190637300/6376127197957 +qadd:4839349064327340004/3805686625309,4317900645018438773/5983979445459,-689687038324621568/7626332987577:45391142064495823172086675547693/22773150541707282934521831 +qadd:-1660640044482828405/123686665162,1468015760631904370/154714309067,=1:-75350803253335844678902090195/19136096941340209623854 +qadd:3359844750012921/70716653,290023334833820440/24901328071,446648123840546873/44205337621:104174075919044820029792711/1760938576436066363 +qadd:-8524152918701542873/27483319743,572629374273579433/1843500145,345801513474448186/34748134655:23479045766334416148429134/50665503931301862735 +qadd:461532154960869496/88629445599,-3067104818016109135/42934967742,-5658191264987110039/23622515075:-84006643809882954201032549611/1268434129261469622486 +qadd:2107778483720627369/79151569,4539993449270881832/8042518085,=1:353289677127684406239691077/12991386227318885 +qadd:-5200199645684863958/1508061869,1037044821661150583/89359314,574740187726215359/551649888:1099241478989643929419214815/134759374083397866 +qadd:6429669718772297/246412472,7129345785374382275/462920354,2455561683986174279/1566173:879868071849600067014183469/57034674384127544 +qadd:1738227802075055570/327533141,=1,2601403037612548877/229872139:3476455604150111140/327533141 +qadd:3436599097095658763/14598030,=1,958841139244535864/69388675:3436599097095658763/7299015 +qadd:6575572376501646299/89845794,1883123242302019558/2079573,=1:60955028559399331030329793/62280295788654 +qadd:8246990382353771761/1153985,7360354913817962691/3109420,528293916457716807/6436589:6827419199984137333012451/717644807740 +qadd:5939937149370464031/3123809,3641790392665278283/8453885,588122952232762701/1541615:61591803172727055602650382/26408322047965 +qadd:270376064542116947/102161,=1,=2:540752129084233894/102161 +qadd:131163854733041727/323971,3502368174871763808/31573,108739692256458838/855:1138806956366866519088139/10228736383 +qadd:2295686487125757632/9399,5192247177653340310/74391,7756262792928856511/14718:73193448228845327191934/233067003 +qadd:-1157668445283763977/98255,-6862870187854810458/92423,=1:-781306501026135719597061/9081021865 +qadd:331518036234256523/2056,815887256529953349/482,196168905129502546/4049:918627946445247864815/495496 +qadd:-2035788783736026328/8319,8303222045592699428/9011,-1864379673211519106/1401:50730011467040333299924/74962509 +qadd:2843403596885438497/227,3405071238014843037/907,410871865808099072/31:3351918233404462086178/205889 +qadd:6888377466446373262/559,-4233882656695844123/346,=1:16638198297468283895/193414 +qadd:-8544001908785450503/61,538024038063863901/19,-359823220116074567/8:-129516569945027861596/1159 +qadd:-2873163532076118107/33,599376533960103224/29,603524459540653533/83:-63542316809524018711/957 +qadd:1063922232492764301/2,6854581919241901325/6,6969845457837372101/4:5023174308360097114/3 +qadd:2352628464632327696,=1,-2926879886747018505/4:4705256929264655392 +qadd:38750299973229623063/36181224711595653198,95066204533556190887/4815411929001685731,8874164143102558897/10732317260440182753:402912262827843733479506682549361735631/19358611231345364982923389088229013082 +qadd:48742220039338674056/67138210285692216649,31818042798992490898/21353165712067248083,5900286084455262748/49045932502167224591:3177007149991956505876862526845604395450/1433613329842003680672466022985665933867 +qadd:87217932340221331903/2665309420727136089,1273107818123651579/33738995536126310,55551725128033095975/2650789751926588423:6335871691143231965413514248993402461/89924862648308245613767543263401590 +qadd:-54380689308824351360/1703471436980462073,=1,-72316980450522981244/8351933107679217397:-108761378617648702720/1703471436980462073 +qadd:37029624832139894565/54555708192540067,111936754529639081/4842509306811346,47780458168088681783/99817190816504869:185423091793508942579252306927292917/264186524662059269844548115200182 +qadd:-22582885555171871569/276061047279571597,37882169208497878632/62669917022723249,38915003092334150861/133381815208219710:9042523741043587572300262155802007623/17300722926216831696081927011958653 +qadd:33158690128759394124/27845156068309087,20040091306620091462/93471893000203813,-2800433644018142872/303526659689803:3657425005798313102460083146020310006/2602739448590962875785441279948731 +qadd:3197839850448851481/15625985746620581,=1,1644265406502320897/6242254024865644:6395679700897702962/15625985746620581 +qadd:1923674921668264769/66091808607807,47645418789767983519/2547180528667403,-94362350068612539221/364341393607160:8048919203651352698528804054357740/168347767990218650522372215221 +qadd:63079152525440745698/2231593339592783,3556320317878822237/3926878376870658,-99040920722967906187/1600307564553594:255640420818316291470533856441044855/8763195631215478802223581261214 +qadd:3155815575082653608/30192877351261,11795128154822010181/20651109856531,31816014676979512957/70387620365646:421299951848929855087786504702089/623516427065657629001935591 +qadd:23991887334900651603/96699483325270,3750668873805896041/943821328748345,=2:33586485731135365147071981775333/133236547213627390084100990 +qadd:2309692393299313895/92991584939154,13505703402565112683/18557182710305,94620445875012570863/90668308130179:1298778148869711868710408754878157/1725661832236727444233781970 +qadd:57594369573165928157/93091121490986,-8216395801314141034/4528867987769,-26450061693998675351/44029529374639:-504036203122513874440040155007791/421597400066041276891750234 +qadd:24542791235970972879/2344787306732,-64933302597803670427/4342923289956,=1:-5708415507036463291655594663905/1272903925549950743347974 +qadd:-172272128642878525/1253023290162,-56946438418624682181/1249572807253,19174037020580911223/8107587302833:-71570480197712551233049111945147/1565743830241120717144986 +qadd:3028920190202346838/805608849389,40089795752860144393/372471218723,15183822811879905592/111683851673:33424879823361049021005735273751/300066109945954583910247 +qadd:76500387765072442325/775493963262,122900265147567688/16725267965,50834815414479646533/248262732319:1374797898502481981169162896881/12970344340796815501830 +qadd:59590674910838495728/13005850369,86406272304132657397/74890842311,37835029633787556154/89471413727:5586582886484287970785818176901/974019089105240162759 +qadd:-1540621953597844070/6475929139,-8097002238368386377/33525625058,4994696033629226613/9124261493:-104085926706442851563193645463/217109572216290765062 +qadd:1020455924950028825/71307089,-15027123384295411453/4869731824,32588900069283614833/4623109762:3897806268140576872049136483/347246400580100336 +qadd:98927709935781735893/4858671845,14545842510003768295/485475574,36811564317330662262/7963827409:118700462230738581230190731857/2358766502829014030 +qadd:7968100306775934624/24002777,40497155380044030991/145085209,58654545110130593822/33483457:2128097688063097717151438423/3482447917625393 +qadd:-23611980270981239714/420152229,95487639446075722616/816419473,-5579567954544211437/617972198:20842064065896139239707560342/343020461379955317 +qadd:-41034887738055776999/13333375,84899158825411622388/47895653,30327216586322045860/36885673:-833400422192101699131885847/638610702318875 +qadd:24656093429908250495/27564561,2208448163081784406/5010537,=2:61471724170872663319500527/46037750926419 +qadd:2133095351837200006/1310507,=1,-21206650272439533589/973111:4266190703674400012/1310507 +qadd:19180784354554459582/1180789,47269383367680368601/863423,81472957723316044010/8522997:72376298287102409915675375/1019520380747 +qadd:57138477662354817611/225222,46133836132900735393/499504,97630303852343664772/247381:19465626493890525121323595/56249644944 +qadd:29853842167305129575/324248,24424888107355543894/33291,-23582416174010240026/335387:8913585378625575465223037/10794540168 +qadd:-420456923149560733/537,72302352874036923083/70362,23736761268395718034/5245:3080724488902811800075/12594798 +qadd:539720131536363641/89712,-47388649478839966234/1133,4570686076693373255/1613:-4250719019136660350779355/101643696 +qadd:-35074948988121263785/1743,46439113742337125259/3968,66374900563777261496/1307:-58234022331971565372443/6916224 +qadd:-28803141465771759543/4526,54869054724564777023/3954,1798941140485680569/657:33612430081929660893269/4473951 +qadd:725551877269445969/431,=1,32744674741853348893/693:1451103754538891938/431 +qadd:91879409948684343784/517,-92515200339135325921/86,41625165280534848151/424:-39928729319746109935733/44462 +qadd:-29166863008492740086/27,-62979221821453932179/87,14020736369187295840/17:-1412652023639374852105/783 +qadd:68001809592817590555/61,-7705962877958413589/4,38853502652707551384/11:-198056497184192866709/244 +qadd:-79744407268013845618/3,-17168463782676239957/9,40182413433838316451/2:-256401685586717776811/9 +qadd:-61204110018146728334/3,-31052192278051565633/2,=1:-215564796870448153567/6 Index: contrib/isl/imath/tests/qaddz.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qaddz.t @@ -0,0 +1,800 @@ +qaddz:1/54620799347511326707,-4,5/50425624798430340799:-218483197390045306827/54620799347511326707 +qaddz:1/212138780821487407,-4,-1/2172160838694653181:-848555123285949627/212138780821487407 +qaddz:-8/2596450420794466343,3,-5/33209689038794936:7789351262383399021/2596450420794466343 +qaddz:0,0,1/7506665947113966172:0 +qaddz:3/301921530103952791,6,=1:1811529180623716749/301921530103952791 +qaddz:1/47796551294919635,0,9/408623107847915846:1/47796551294919635 +qaddz:0,-7,3/44304529385671853:-7 +qaddz:-6/59168527940606359,-7,0:-414179695584244519/59168527940606359 +qaddz:0,3,-1/1803043485158662:3 +qaddz:4/805996063056383,9,4/4602479413908539:7253964567507451/805996063056383 +qaddz:3/908244468147226,-7,3/60173056873814:-6357711277030579/908244468147226 +qaddz:0,4,-2/385639438244941:4 +qaddz:7/59007802744210,-6,0:-354046816465253/59007802744210 +qaddz:7/80088880526056,8,=1:640711044208455/80088880526056 +qaddz:4/1915432332283,6,1/975133146111:11492593993702/1915432332283 +qaddz:-2/4374674512379,1,1/1450918107984:4374674512377/4374674512379 +qaddz:-1/176293450395,-4,=1:-705173801581/176293450395 +qaddz:-2/150047873621,9,7/862965342703:1350430862587/150047873621 +qaddz:7/90154985532,7,5/5122907862:631084898731/90154985532 +qaddz:3/35150061317,2,1/39676293318:70300122637/35150061317 +qaddz:2/865482845,-7,1/6059793299:-6058379913/865482845 +qaddz:1/7111641188,4,8/9256455537:28446564753/7111641188 +qaddz:1/231395954,2,-3/198206266:462791909/231395954 +qaddz:-1/5342717,6,=1:32056301/5342717 +qaddz:-1/1255946,8,7/39589307:10047567/1255946 +qaddz:9/48244018,3,=1:144732063/48244018 +qaddz:5/7367079,8,1/3896866:58936637/7367079 +qaddz:3/326524,0,3/4328111:3/326524 +qaddz:-7/836910,-2,9/919579:-1673827/836910 +qaddz:5/887451,6,8/592505:5324711/887451 +qaddz:-8/94183,4,8/66975:376724/94183 +qaddz:2/33127,1,-1/14729:33129/33127 +qaddz:-1/1132,-5,8/8763:-5661/1132 +qaddz:1/4973,8,=1:39785/4973 +qaddz:-5/71,-4,4/875:-289/71 +qaddz:1/125,0,=1:1/125 +qaddz:0,9,=1:9 +qaddz:-3/29,4,4/67:113/29 +qaddz:5/3,9,5/8:32/3 +qaddz:1,-3,2:-2 +qaddz:31/75290504490996366117,-89,80/87349767408470122133:-6700854899698676584382/75290504490996366117 +qaddz:-1/2025002780262471319,54,13/33364955876728529603:109350150134173451225/2025002780262471319 +qaddz:5/226091118641865964,19,98/9684762482985042665:4295731254195453321/226091118641865964 +qaddz:-1/3269119415472267421,45,-31/5732304804177650236:147110373696252033944/3269119415472267421 +qaddz:-52/674837392469005073,-1,49/926152724308138640:-674837392469005125/674837392469005073 +qaddz:-33/233752284775146865,10,1/34021154309272456:2337522847751468617/233752284775146865 +qaddz:33/37915766989934257,32,9/20112346122968212:1213304543677896257/37915766989934257 +qaddz:31/42388535088021265,-6,=1:-254331210528127559/42388535088021265 +qaddz:21/134052208089341,-81,33/306549029392024:-10858228855236600/134052208089341 +qaddz:1/2145839249313809,73,33/3181662864206624:156646265199908058/2145839249313809 +qaddz:3/712097424282067,61,1/54860371983348:43437942881206090/712097424282067 +qaddz:-27/242055520851227,81,85/884187769743491:19606497188949360/242055520851227 +qaddz:87/75610348177252,5,-63/45006979682459:378051740886347/75610348177252 +qaddz:91/22460567019277,-63,-4/5688629009171:-1415015722214360/22460567019277 +qaddz:34/5611315344227,50,-26/8764714566551:280565767211384/5611315344227 +qaddz:2/1448323251689,48,=1:69519516081074/1448323251689 +qaddz:-13/507312090741,87,-31/36494655847:44136151894454/507312090741 +qaddz:35/695649048043,32,=1:22260769537411/695649048043 +qaddz:-22/53469298165,50,-41/44921870282:2673464908228/53469298165 +qaddz:0,-42,19/22231277127:-42 +qaddz:44/1990669661,15,88/2011535859:29860044959/1990669661 +qaddz:52/911062095,39,=1:35531421757/911062095 +qaddz:7/125107130,-87,86/274603713:-10884320303/125107130 +qaddz:3/56375633,-47,=1:-2649654748/56375633 +qaddz:-1/1856173,10,71/56499774:18561729/1856173 +qaddz:7/6626238,64,32/20302401:424079239/6626238 +qaddz:15/1633807,4,52/1107445:6535243/1633807 +qaddz:99/7321367,57,26/2807871:417318018/7321367 +qaddz:-10/101833,50,32/474687:5091640/101833 +qaddz:47/89673,-41,31/421155:-3676546/89673 +qaddz:29/67933,-9,-24/68509:-611368/67933 +qaddz:10/7473,12,=1:89686/7473 +qaddz:-65/3001,21,79/2243:62956/3001 +qaddz:8/4983,-5,=1:-24907/4983 +qaddz:3/230,-4,16/53:-917/230 +qaddz:16/377,66,-61/214:24898/377 +qaddz:-41/23,96,5/41:2167/23 +qaddz:-5/9,35,95/34:310/9 +qaddz:72,11,45:83 +qaddz:13/6,16,=1:109/6 +qaddz:-277/80983188935181565796,610,=1:49399745250460755135283/80983188935181565796 +qaddz:79/15192291024925486394,143,=1:2172497616564344554421/15192291024925486394 +qaddz:-231/6313238620833887902,481,325/134903344527041052:3036667776621100080631/6313238620833887902 +qaddz:935/1485416466862593748,222,-565/6248719316822480264:329762455643495812991/1485416466862593748 +qaddz:-967/626150835751553604,-409,77/6043113279368884:-256095691822385425003/626150835751553604 +qaddz:-191/672212197195743189,906,301/296825083216628537:609024250659343329043/672212197195743189 +qaddz:323/65375330562542722,876,935/31091316170043549:57268789572787424795/65375330562542722 +qaddz:-143/40251685718424887,46,373/18639328341468821:1851577543047544659/40251685718424887 +qaddz:130/6295699493323523,-390,-174/17530058264063:-2455322802396173840/6295699493323523 +qaddz:579/8145570591252371,-21,40/2232149554773023:-171056982416299212/8145570591252371 +qaddz:265/47192654250488,316,536/603327182103531:14912878743154473/47192654250488 +qaddz:71/34035968910103,-744,327/497134848511328:-25322760869116561/34035968910103 +qaddz:254/93818137594343,-487,83/17550216682523:-45689433008444787/93818137594343 +qaddz:-824/19205768158351,727,241/53745460287591:13962593451120353/19205768158351 +qaddz:-758/4519346718465,-718,=1:-3244890943858628/4519346718465 +qaddz:75/64951063118,573,-139/8704353659601:37216959166689/64951063118 +qaddz:-187/758236499162,224,294/841106266507:169844975812101/758236499162 +qaddz:-34/37119383027,-857,=1:-31811311254173/37119383027 +qaddz:-441/57312007072,914,=1:52383174463367/57312007072 +qaddz:25/18513015668,-567,50/47247431347:-10496879883731/18513015668 +qaddz:343/904828730,-386,84/2415081317:-349263889437/904828730 +qaddz:-15/705578962,85,67/15485401:59974211755/705578962 +qaddz:-671/597940315,-297,-38/36423405:-177588274226/597940315 +qaddz:141/16827008,1,=1:16827149/16827008 +qaddz:19/1823825,304,152/12228673:554442819/1823825 +qaddz:623/94768157,753,-15/53060492:71360422844/94768157 +qaddz:5/30576,-780,515/3838063:-23849275/30576 +qaddz:85/456198,-545,278/3171433:-248627825/456198 +qaddz:-61/154737,175,230/373207:27078914/154737 +qaddz:784/22467,-975,221/842081:-21904541/22467 +qaddz:264/26219,577,=1:15128627/26219 +qaddz:648/86443,318,-751/62582:27489522/86443 +qaddz:-736/5001,599,73/1531:2994863/5001 +qaddz:58/1057,11,163/2848:11685/1057 +qaddz:265/416,564,33/505:234889/416 +qaddz:603/8,39,155/119:915/8 +qaddz:51/43,341,-3/53:14714/43 +qaddz:89/68,-261,42/5:-17659/68 +qaddz:316/3,138,=1:730/3 +qaddz:-157/4,778,-242:2955/4 +qaddz:-1220/24425361794374611191,-2739,9923/58596476391899748982:-66901065954792060053369/24425361794374611191 +qaddz:4756/68889234195734663973,9499,=1:654378835625283573084283/68889234195734663973 +qaddz:-6740/6193173096605308887,-3748,-1774/1349471376636973063:-23212012766076697715216/6193173096605308887 +qaddz:4951/5273171148713492245,2850,73/76840073320949141:15028537773833452903201/5273171148713492245 +qaddz:307/50758090271672590,-7992,4023/144759202361690600:-405658657451207338973/50758090271672590 +qaddz:4507/193110223350280382,2550,-4697/807940924231898113:492431069543214978607/193110223350280382 +qaddz:7135/87030719499305628,-2633,=1:-229151884441671711389/87030719499305628 +qaddz:-4425/57492072202943332,-9695,8774/1065824219401905:-557385640007535608165/57492072202943332 +qaddz:-2171/59546743026218,-2275,3354/2713497612422239:-135468840384648121/59546743026218 +qaddz:-420/497459043701647,-2485,6408/6394215912846235:-1236185723598593215/497459043701647 +qaddz:1796/82252594594341,9198,4191/934791612378541:756559365078750314/82252594594341 +qaddz:6624/484898002393549,-2338,4534/518674030101081:-1133691529596110938/484898002393549 +qaddz:2261/81693124807278,2477,6397/30033270473277:202353870147629867/81693124807278 +qaddz:1971/3597019637272,1116,3989/62351952484275:4014273915197523/3597019637272 +qaddz:-821/2973214305299,7102,2099/3415351232644:21115767996232677/2973214305299 +qaddz:3455/5604793125537,-4157,1475/8622435080543:-23299125022853854/5604793125537 +qaddz:-663/231000718186,2230,1885/90136214836:515131601554117/231000718186 +qaddz:9841/907754978407,475,-3707/314368976315:431183614753166/907754978407 +qaddz:388/1661926713,-9986,-4927/71849157859:-16596000155630/1661926713 +qaddz:893/2494453262,4917,6805/49826778773:12265226690147/2494453262 +qaddz:-2393/1820211958,9429,=1:17162778549589/1820211958 +qaddz:3478/4373863243,7552,9147/4954348655:33031415214614/4373863243 +qaddz:-5135/74721107,-742,4898/141314343:-55443066529/74721107 +qaddz:-1789/88275441,-7193,5814/533915795:-634965248902/88275441 +qaddz:3322/13291911,9390,-3263/50883910:124811047612/13291911 +qaddz:4577/34396558,-489,=1:-16819912285/34396558 +qaddz:8903/3869879,-4634,-3811/2146853:-17933010383/3869879 +qaddz:4014/1153681,4901,802/351473:5654194595/1153681 +qaddz:471/442073,-2998,9329/562186:-1325334383/442073 +qaddz:-893/461068,4168,2066/986911:1921730531/461068 +qaddz:336/38503,8872,653/13211:341598952/38503 +qaddz:8000/86117,1965,=1:169227905/86117 +qaddz:-8578/2779,-9006,9377/9189:-25036252/2779 +qaddz:-211/1008,-1599,=1:-1612003/1008 +qaddz:-1675/366,-4872,=1:-1784827/366 +qaddz:209/137,651,2717/320:89396/137 +qaddz:-5333/38,8162,370/67:304823/38 +qaddz:1729/8,6131,-5099/27:50777/8 +qaddz:3528/5,1915,9521/3:13103/5 +qaddz:-1303/4,104,-2439:-887/4 +qaddz:9256/43175436158473507749,-33340,=1:-1439469041523506748342404/43175436158473507749 +qaddz:43562/48013284592061748195,-32389,3543/476829824739261233:-1555102274652287962244293/48013284592061748195 +qaddz:31781/970330955234841076,25523,=1:24765756970458848814529/970330955234841076 +qaddz:72455/9090210348118255617,89034,48363/241345568170272728:809337788134360770676433/9090210348118255617 +qaddz:81871/335292796101778469,36100,=1:12104069939274202812771/335292796101778469 +qaddz:4031/299114846145519512,11847,48460/472966149918742127:3543613582285969662695/299114846145519512 +qaddz:70081/4000940087930231,28866,-48187/41751383598706590:115491136578194118127/4000940087930231 +qaddz:53565/36491429482144547,3583,22780/40933313880950073:130748791834523965466/36491429482144547 +qaddz:71053/3239886404702374,6327,5499/820365894600107:20498761282551991351/3239886404702374 +qaddz:1901/1115077430717827,78838,32029/643930274853778:87910474482932046927/1115077430717827 +qaddz:13107/6867073713490,67883,12163/313820861435242:466157564892854777/6867073713490 +qaddz:7612/71978407947133,-35439,47880/289218281250503:-2550842799238438775/71978407947133 +qaddz:487/93536104647,54212,=1:5070779305123651/93536104647 +qaddz:24139/22092733596669,7166,12083/20662610330153:158316528953754193/22092733596669 +qaddz:3756/377555799673,-90845,-6186/7949435140837:-34299056621289929/377555799673 +qaddz:51740/5334618145423,33038,30992/9506692645181:176245114288536814/5334618145423 +qaddz:-19431/313093258328,-29145,73759/467815221180:-9125103013988991/313093258328 +qaddz:45134/532171216165,-65154,-98921/239496530364:-34673083417969276/532171216165 +qaddz:-10586/5380332719,43778,-83869/38492047300:235540205761796/5380332719 +qaddz:-64073/25839289167,56469,-20852/44667409353:1459118819907250/25839289167 +qaddz:83896/6875621201,-60135,68147/7560028407:-413465480838239/6875621201 +qaddz:14947/3229243360,20054,72954/2728010911:64759246356387/3229243360 +qaddz:12569/138044852,29541,4251/162658732:4077982985501/138044852 +qaddz:28489/894461083,-54474,99821/372230979:-48724873006853/894461083 +qaddz:461/1016937,67128,-5113/48518554:68264947397/1016937 +qaddz:16058/28261309,-81920,5223/49399519:-2315166417222/28261309 +qaddz:-19094/531145,82677,89232/5738845:43913456071/531145 +qaddz:47358/4287503,-45771,=1:-196243252455/4287503 +qaddz:-44068/383233,28914,=1:11080754894/383233 +qaddz:-84061/931926,49385,=1:46023081449/931926 +qaddz:32731/30919,93827,16987/24520:2901069744/30919 +qaddz:-21037/20727,69534,11467/44693:1441210181/20727 +qaddz:-47647/8209,-53576,=1:-439853031/8209 +qaddz:50277/5119,34616,=1:177249581/5119 +qaddz:-45615/49,-81078,=1:-4018437/49 +qaddz:938/11,60282,36405/461:664040/11 +qaddz:35243/28,51616,=1:1480491/28 +qaddz:-44031/10,33851,-23233/67:294479/10 +qaddz:-40623/2,22693,=1:4763/2 +qaddz:50400,33578,4505/7:83978 +qaddz:44296/145305576996331809,-672446,887487/74206063873608800927:-97710154028875339590518/145305576996331809 +qaddz:641331/10728482754302259559,568057,480993/26722669314559144651:6094389727960678658948194/10728482754302259559 +qaddz:-10499/172183973129275356,938689,261219/9688984711512627413:161627201552746354637785/172183973129275356 +qaddz:-220611/2078134078025492204,-247650,=1:-514649904423013144541211/2078134078025492204 +qaddz:-93245/773599326123432094,810506,507053/740092254069402604:627006895418998452686319/773599326123432094 +qaddz:41051/5604661525608694,512095,417153/767762014998995362:2870119143956584194981/5604661525608694 +qaddz:256857/23764638432843923,-937980,-101171/1839317653823037:-22290755557238942638683/23764638432843923 +qaddz:-332573/48056484575068455,801985,51624/28399631222945227:38540579781936274550602/48056484575068455 +qaddz:555886/6363636074566197,531487,-826671/4672965611688254:3382189846362964900825/6363636074566197 +qaddz:-563124/5236412248020907,-719499,-431679/3372450157381352:-3767593376038795128717/5236412248020907 +qaddz:701612/201096646211621,852450,410105/341513117509976:171424836063097023062/201096646211621 +qaddz:44341/596871824184687,-222953,40264/891060847151681:-133074363817448476370/596871824184687 +qaddz:10699/24587438378106,344946,=1:8481338518774162975/24587438378106 +qaddz:227237/49603690945178,672137,=1:33340476020819332623/49603690945178 +qaddz:597973/5184695092393,114662,356604/1911748822639:594487508684564139/5184695092393 +qaddz:641047/1530353811852,785653,=1:1202327063343600403/1530353811852 +qaddz:597136/70017180317,618996,296751/321064961965:43340354548098868/70017180317 +qaddz:695839/510312151846,171207,205001/260822503888:87369012581793961/510312151846 +qaddz:809905/71504572844,73808,693901/76175273098:5277609513279857/71504572844 +qaddz:255273/62347365151,-84966,-374235/27650351674:-5297406227164593/62347365151 +qaddz:713594/3263659443,510765,=1:1666963016117489/3263659443 +qaddz:295910/3582838971,-154033,-25081/64948294:-551875434924133/3582838971 +qaddz:-630478/469725959,648937,2485/978731798:304822554025105/469725959 +qaddz:857939/546600623,-325885,374369/469544259:-178128943168416/546600623 +qaddz:4621/225308,181124,-720337/99151657:40808690813/225308 +qaddz:763904/62700883,137970,229231/94941727:8650841591414/62700883 +qaddz:65347/480512,137371,214509/5722910:66008479299/480512 +qaddz:-111067/738339,649352,84919/764118:479441795261/738339 +qaddz:171027/450233,-6580,9836/486877:-2962362113/450233 +qaddz:913138/821889,489239,134731/100945:402101065609/821889 +qaddz:701114/19829,-614638,-23827/46967:-12186955788/19829 +qaddz:326257/29870,642576,=1:19194071377/29870 +qaddz:106159/1985,574591,-569660/4723:1140669294/1985 +qaddz:148129/3938,47925,860775/3839:188876779/3938 +qaddz:887330/711,205135,-45802/45:146738315/711 +qaddz:42863/18,-93194,208961/276:-1634629/18 +qaddz:4012/29,-93697,20725:-2713201/29 +qaddz:22117,453874,196189/90:475991 +qaddz:-612637/8,-695084,609247/5:-6173309/8 +qaddz:57845,-697681,-866863/7:-639836 +qaddz:4360261/62036756574194097073,8366924,9603243/52038505911108171230:519056827462782371462773713/62036756574194097073 +qaddz:122203/37104707293639154664,6618642,2840782/70804511700211559411:245582774091386441903768491/37104707293639154664 +qaddz:2975379/3405105441588501638,1224553,-452223/338247701671728355:4169732083813524449293193/3405105441588501638 +qaddz:1236750/6927456590095070879,4061575,8656635/218877078505884724:28136384499915387506611175/6927456590095070879 +qaddz:5514100/889151389478456273,579914,4385513/526230054850522272:515631338878009496614622/889151389478456273 +qaddz:4769436/180047856472105135,9133872,5104049/860727869521825524:1644534074890579878402156/180047856472105135 +qaddz:1129619/13834516044696008,3200844,-6235960/99099205495661801:44282127674568950160371/13834516044696008 +qaddz:-4436473/31680301433353002,-5808829,2360562/31638389601284341:-184025453694802489691131/31680301433353002 +qaddz:3832873/3686022654332134,3511591,2148425/643043583198782:12943803978748836598067/3686022654332134 +qaddz:-7569910/152442797410363,8827549,=1:1345696263837044920377/152442797410363 +qaddz:4372465/567281920816919,7607995,=1:4315878017165520039870/567281920816919 +qaddz:5998833/480252391591963,727708,1934709/45746184416396:349483507380610209637/480252391591963 +qaddz:3161338/53726702330731,2061828,-609862/19212003746435:110775219213169597606/53726702330731 +qaddz:131113/3229582131545,-2913645,-2325146/23074994508107:-9409855829665300412/3229582131545 +qaddz:4389212/772304888811,-9008024,4662292/1333533763161:-6956940973722430252/772304888811 +qaddz:815149/899391465210,1866152,-3495177/4058839242973:1678401181585387069/899391465210 +qaddz:6099185/812281384924,516393,3627307/291261495421:419456421211158317/812281384924 +qaddz:2706122/517440388607,-5819,7950079/252677744377:-3010985618598011/517440388607 +qaddz:3534256/50461476673,7199887,=1:363316929902270207/50461476673 +qaddz:-341422/3319030425,9477224,=1:31455194800198778/3319030425 +qaddz:1777807/3107794205,-7728298,-3370724/3708129283:-24017959737135283/3107794205 +qaddz:-5327233/9277787037,3319889,6246449/2731964013:30801223123151660/9277787037 +qaddz:-9819076/309587449,-64284,=1:-19901529390592/309587449 +qaddz:5932665/955345021,2160126,2378998/340986557:2063665624765311/955345021 +qaddz:27849/96378415,6447655,-1830047/14377112:621414769394674/96378415 +qaddz:452633/3628007,-6184207,2601894/13372759:-22436345832816/3628007 +qaddz:1646531/1203794,-1799977,-2372416/1725139:-2166799866207/1203794 +qaddz:2641959/511223,1901148,1953355/2249527:971913225963/511223 +qaddz:-10086/1165,1012800,-8266052/33291:1179901914/1165 +qaddz:2434418/167529,2764968,=1:463214758490/167529 +qaddz:6481704/22457,4174437,7094833/47337:93751813413/22457 +qaddz:-3250889/26779,7463010,4107129/47161:199848693901/26779 +qaddz:599335/1376,7764075,-2794121/1154:10683966535/1376 +qaddz:-1446188/1023,-1120763,=1:-1147986737/1023 +qaddz:-6355319/520,8873579,-4229533/845:4607905761/520 +qaddz:-8333079/502,4777754,-2211765/838:2390099429/502 +qaddz:-664681/39,1853000,7994519/83:71602319/39 +qaddz:-6686979/41,-8893574,-1077101/12:-371323513/41 +qaddz:-188498,9478449,=1:9289951 +qaddz:-1148991/2,3210266,=1:5271541/2 +qaddz:13593663/25788635148712130170,9749642,73140616/63308113773746847799:251429960368560030228492803/25788635148712130170 +qaddz:55138471/984284327092850808,71726057,45865951/15569580966066839785:70598833749268461402242527/984284327092850808 +qaddz:-93458416/3876652721819618213,38189554,-59813819/4844052168542685795:148047638459177287911288586/3876652721819618213 +qaddz:-13202403/1193328009457250122,10267890,1513303/582767321730759548:12252960735026003941980177/1193328009457250122 +qaddz:56178208/35416123641813139,77841322,6805923/142304130637208152:2756837884394189272907966/35416123641813139 +qaddz:91725073/281875811815728492,-75791628,=1:-21363826671335698322939903/281875811815728492 +qaddz:-87952363/35128220892663058,-95959069,-6580898/40762262950663657:-3370871372486296064325365/35128220892663058 +qaddz:1593208/1779268204772945,57788357,=1:102820986216168051194573/1779268204772945 +qaddz:-40115057/1844576541622880,45148647,48149671/4721486463692100:83280135142212176128303/1844576541622880 +qaddz:71660059/7908261305514706,46408705,87309016/9251884131271557:367012165990546935575789/7908261305514706 +qaddz:12899069/900901725436207,-53144602,-36141736/346358215988697:-47878063639420484505545/900901725436207 +qaddz:12859471/415241177014271,71268555,-60349912/357890988024495:29593638662306321407876/415241177014271 +qaddz:6490779/7687148332738,-56678219,2747770/29442703192421:-435693876688402742843/7687148332738 +qaddz:-60847891/99630307357354,88116713,-98374273/39412545202138:8779095199509690009511/99630307357354 +qaddz:-25941332/4772253631053,-67231252,85813662/2010665859491:-320844586477265209688/4772253631053 +qaddz:4828372/85755227179,10688383,10501313/2337582857089:916584712345989929/85755227179 +qaddz:57153058/801923397935,80676502,=1:64696374617406976428/801923397935 +qaddz:33518641/130632158802,75978846,54844171/383744120637:9925280676298221133/130632158802 +qaddz:8437861/17969987688,54020652,-71865526/87734026923:970750451346170437/17969987688 +qaddz:4070024/3913628749,33427821,512282/796504041:130824081286095953/3913628749 +qaddz:81166629/3135890000,93859365,56814645/4127270728:294332644191016629/3135890000 +qaddz:75095946/6594060085,92035409,-11381306/3866199715:606887016968645711/6594060085 +qaddz:-6201133/708702298,47074908,22887883/94448148:33362095471537451/708702298 +qaddz:6027874/49969387,18501816,-9130290/81894907:924524409934666/49969387 +qaddz:13827470/4398317,50518578,62727273/34158559:222196734260696/4398317 +qaddz:-89138866/91998795,18780715,-35130848/77386067:1727803060099559/91998795 +qaddz:1174985/377026,86316466,16615749/3874669:32543553085101/377026 +qaddz:-9292539/4656085,1624786,65325863/1600219:7565132430271/4656085 +qaddz:-2336639/845282,-4069510,8089655/167446:-3439885888459/845282 +qaddz:-31078338/91681,89417696,2569245/159973:8197872708638/91681 +qaddz:73383631/12053,83445739,19141505/6087:1005844875798/12053 +qaddz:22853974/63407,-85636132,-6290341/12816:-5429907367750/63407 +qaddz:21369191/1915,48981131,5257100/483:93820235056/1915 +qaddz:-45229274/277,6529852,80452675/6632:1763539730/277 +qaddz:-17600350/527,60401374,37082689/442:31813923748/527 +qaddz:85256283/467,-24966013,67067455/319:-11573871788/467 +qaddz:80505325/66,13054914,=1:942129649/66 +qaddz:-4197971/62,-58438955,9669086/33:-3627413181/62 +qaddz:45758807/4,-88423268,27591403:-307934265/4 +qaddz:48139065/2,43301388,-36531779/2:134741841/2 +qaddz:-746260196/20472817142129557823,982354175,32526895/10440994669702430816:20111557393582539517581700829/20472817142129557823 +qaddz:-29549747/14838788589925929214,634211818,-74451525/12916990835817929011:9410935088534580052120701305/14838788589925929214 +qaddz:-448318501/7278955030505777603,769108616,=1:5598307029438536391798808947/7278955030505777603 +qaddz:59483976/2793541975287617267,-163303460,314082880/1773468794441614937:-456195070219702394797359844/2793541975287617267 +qaddz:-39988340/60152702435264949,648519691,73804544/228852852664255579:39010211996132972188622419/60152702435264949 +qaddz:-729061405/768059604671461839,714606502,-471314823/354142770917954234:548860387421776203265215773/768059604671461839 +qaddz:-248555917/7165349396837386,582365762,-82300902/5346138197190155:4172854161485444439422215/7165349396837386 +qaddz:543269507/64494661180201173,690548092,897863403/18149141182810736:44536665222174388734581423/64494661180201173 +qaddz:318338239/8630148497550833,845781111,-235304841/3148342727645078:7299216584353524632053702/8630148497550833 +qaddz:859971543/1629667855750118,-528676738,-821484768/9266342092322843:-861567486001426067383541/1629667855750118 +qaddz:-374749715/8438356773884,291407771,-932095108/907679125024843:2459002738379912702849/8438356773884 +qaddz:-105904217/719249349028152,954350873,-483804897/722878772519704:686416244149698456872479/719249349028152 +qaddz:215809489/24453042701551,949038292,509810695/60521395527768:23206873879683242600381/24453042701551 +qaddz:150432367/67777562170303,451848420,463171069/798174121745:30625184378103331903627/67777562170303 +qaddz:-8493914/1778903924623,-83428918,=1:-148412029657258941828/1778903924623 +qaddz:147732646/368561418133,316756885,462378256/2791638842869:116744366739139328351/368561418133 +qaddz:-66012899/43799234004,-321281986,982505097/911502425047:-14071904886149864843/43799234004 +qaddz:169940076/279466336907,-71525240,15350688/150338991023:-19988896819024092604/279466336907 +qaddz:233355217/32843819415,72601264,-758317611/7873649159:2384502804350095777/32843819415 +qaddz:285149260/19453167983,144991594,-201126001/42622707256:2820545834490084162/19453167983 +qaddz:940581418/5616720353,-615369286,215195096/2354964241:-3456357192346696540/5616720353 +qaddz:-396923483/8795362315,114388371,116424557/500425708:1006087167170715382/8795362315 +qaddz:43457937/310448072,540792846,48194518/73220787:167888096435550849/310448072 +qaddz:428882054/550113049,-311285439,56137087/291468974:-171242181528711457/550113049 +qaddz:-286703423/15020682,237972794,95770627/88535037:3574513376622085/15020682 +qaddz:-672536805/72578564,-454083180,-450947664/92210965:-32956705813490325/72578564 +qaddz:-842687259/2802968,164043467,877832687/5847351:459807745922797/2802968 +qaddz:9656746/198233,-84422497,=1:-16735315191055/198233 +qaddz:236817273/916726,899428028,-92124131/51259:824529295213601/916726 +qaddz:-32742959/6896,967049226,-375835070/139297:6668738719537/6896 +qaddz:46021278/1013,797203137,559435694/97037:807612799059/1013 +qaddz:495550757/63198,245997332,948028412/39911:15547034938493/63198 +qaddz:-760591485/8548,-293617711,573012945/8054:-2510604785113/8548 +qaddz:268239779/2820,-917135865,-106555829/892:-2586054899521/2820 +qaddz:301095018/37,-382369768,-77751485/296:-13846586398/37 +qaddz:3850763/277,-710988721,-86297861/101:-196940024954/277 +qaddz:195470025/41,-660449973,225753766/29:-26882978868/41 +qaddz:375745961/37,910651525,-88347614/45:34069852386/37 +qaddz:-91575821/2,869025199,629588221/2:1646474577/2 +qaddz:436219553/3,113713165,=1:777359048/3 +qaddz:-844868513/21771218036213010780,986546099,258641158/22466107297036584855:21478310224104386517209078707/21771218036213010780 +qaddz:833503855/8069616060533418368,463027937,-193589362/1951752452419151303:3736457676890855827326450671/8069616060533418368 +qaddz:724738643/11366387107722525,376750281,4819705753/4712039757409798110:4282289536789239288518168/11366387107722525 +qaddz:508814249/2088448235503890884,845043285,6799873277/8328817117516288610:1764829157482661583405728189/2088448235503890884 +qaddz:7996084039/717257384492120308,2419507504,2667813745/128249445552768127:1735409624078098322072875271/717257384492120308 +qaddz:7585030779/180538136040165892,489184216,1064881163/655356926166745922:88316406536909903972991451/180538136040165892 +qaddz:3584540521/91456981705312186,-9911261646,=1:-906454075034784339973677635/91456981705312186 +qaddz:3050007448/41294095103098713,6024934948,=1:248794236732695102097529372/41294095103098713 +qaddz:5293029102/2042882846608867,1387341294,=1:2834175731904754348683000/2042882846608867 +qaddz:4856278727/7671234032065848,-4714174847,-826015688/342674325919645:-36163538519415207233046529/7671234032065848 +qaddz:-1287980783/264067516251600,-7283705114,1474901722/155847550710807:-1923389918563058318663183/264067516251600 +qaddz:-5319461421/224860303990304,7455512951,889923834/139644515373281:1676448908565503130965683/224860303990304 +qaddz:2092800065/39695887391801,-8479055683,1732884799/61967662266203:-336583639581176223855018/39695887391801 +qaddz:1206911087/46584702098976,-2120326658,1346835184/16267372805513:-98774785715446160391121/46584702098976 +qaddz:569792579/414501273499,-8640944572,6673457161/7160564523311:-3581682529327701704849/414501273499 +qaddz:9313961147/9034962045642,-4887430523,6725061071/3300706280530:-44157749276007915969619/9034962045642 +qaddz:-5240204781/952774687199,-8153058385,806610703/7522631755:-7768027652488799318396/952774687199 +qaddz:1072533129/47749905913,-2190169028,7000962285/325419804967:-104580365019494129435/47749905913 +qaddz:539059499/15953197306,2833840907,3868176763/46023931661:45208823123724056041/15953197306 +qaddz:674514633/2185964591,-3939960534,6112848571/51458323114:-8612614216586936961/2185964591 +qaddz:3187633456/3615599831,3078822354,3648967863/4642156796:11131789585989055630/3615599831 +qaddz:3613164783/790101889,5924355725,1093627703/4194434934:4680844653043629308/790101889 +qaddz:7839467059/761810399,3436300760,2070395267/976614917:2617809660899070299/761810399 +qaddz:225690899/491794201,4884762823,622206155/258312784:2402298029837480322/491794201 +qaddz:-7725783503/84500941,-1043559105,9836874767/38034734:-88181734087401308/84500941 +qaddz:1162986782/14963043,1957888112,-8677864987/68949839:29295965172031598/14963043 +qaddz:-2073053051/3932529,3953921935,9300508123/4505890:15548910600070564/3932529 +qaddz:-2553049553/6593625,6886901572,2612889293/3618567:45409643824628947/6593625 +qaddz:157807783/17000,4402443990,876550711/970248:74841705637783/17000 +qaddz:810075291/750871,-6494923353,1278293443/275880:-4876848782915172/750871 +qaddz:2989273314/56921,-2790577575,3360184275/44087:-158839476873261/56921 +qaddz:3268425371/11550,7335374991,2237230499/48036:84726849571421/11550 +qaddz:-3154163419/9858,824560371,4511685191/5191:8125361973899/9858 +qaddz:7027175150/7267,-5589392198,14743439/42:-40611085927716/7267 +qaddz:4661020509/730,-1409612732,-472504172/703:-1024356273851/730 +qaddz:550638145/104,3388785600,7616106439/471:352984340545/104 +qaddz:-2172843710/11,76395123,736231113/29:-1332497357/11 +qaddz:-6453196546/63,4130453785,-5670101997/64:253765391909/63 +qaddz:1769225059,-8164754222,1531642609/9:-6395529163 +qaddz:7580730244/3,-8295939153,-1516372895:-17307087215/3 +qaddz:58423769119/50643850140797602406,90335026336,=1:4574913536225388721450090733535/50643850140797602406 +qaddz:-42124546066/6087273228356965143,-24064378632,75472938387/29014055899155453086:-146486447803619008497702570442/6087273228356965143 +qaddz:85077906583/7059686186393838266,-86403115965,=1:-609978884239495412773574610107/7059686186393838266 +qaddz:2409771251/78123085616637683,15985845324,=1:1248863562901179163797515543/78123085616637683 +qaddz:52223576739/412739442713673226,-46190346315,31453828195/12849072264316598:-19064577796804669642459685451/412739442713673226 +qaddz:-44585554037/157326507974173406,59214099831,7574929311/32876530728519241:9315947549245321588003740349/157326507974173406 +qaddz:-47861969231/60513239361297573,-63013076957,=1:-3813125408790805542688294592/60513239361297573 +qaddz:-31901636875/33882731297200408,-55696719345,31284269910/21963113061657589:-1887156975702218940497129635/33882731297200408 +qaddz:1727465561/671724526279818,-68558893487,=1:-46052690249823572892279805/671724526279818 +qaddz:17391142729/435638497115449,79866074338,=1:34792736595117065793390491/435638497115449 +qaddz:-14607124051/752098365273835,79819155439,34961447441/234817885230781:60031856323210021057514514/752098365273835 +qaddz:-33882594912/853897505052767,-69441770727,68892865654/360632311106545:-59296154770231603933546521/853897505052767 +qaddz:56393173391/95959531164605,80334900495,=1:7708899387655450534152866/95959531164605 +qaddz:76008103374/82690250931395,-41801579607,72201983593/77462511255258:-3456583107031437979958391/82690250931395 +qaddz:42873865571/227802171757,96248926412,=1:21925714465976151611455/227802171757 +qaddz:2188733045/317649531592,-27294537694,-13503437379/778368702506:-8670097113517099095803/317649531592 +qaddz:-40936176209/483902341255,59864812412,-30132933091/131952074240:28968722884917247480851/483902341255 +qaddz:29030847755/204795623153,98812754244,=1:20236419580893256259087/204795623153 +qaddz:7022832233/85729381270,286720337,65140586861/51219438458:24580357095558720223/85729381270 +qaddz:83478631598/83831440713,2447203008,78651932717/87841022347:205152553961305896302/83831440713 +qaddz:70410742832/4854173541,25635871440,41240688913/9691426040:124440968914936311872/4854173541 +qaddz:13133061735/215660389,-54580960568,73195756378/2318826503:-11770951174955479217/215660389 +qaddz:97316922721/33728456,49150998791,-43302763720/346667451:1657787397395219417/33728456 +qaddz:42314512205/91048434,3019543575,=1:274924756213023755/91048434 +qaddz:9911778891/3761798,99193069336,84599064764/16160639:373144299753805019/3761798 +qaddz:22143440303/71908,57401237223,-44550917147/46946156:4127630309671787/71908 +qaddz:13575690632/9774495,-56625307968,27090428376/1406293:-553483776030985528/9774495 +qaddz:65452607896/5739831,88854202629,=1:510008172182823595/5739831 +qaddz:-48594032321/296227,26116980382,90351957100/631949:7736506153586393/296227 +qaddz:38854983873/478381,91268688211,-37086942845/919397:43661245190050264/478381 +qaddz:-3289168101/2633,39943120731,86275372528/65091:105166947716622/2633 +qaddz:71226110755/74802,75928864342,-681828710/6523:5679702136621039/74802 +qaddz:-11750464340/9973,3631010522,-10917246741/3869:36200317471566/9973 +qaddz:15180336658/9543,75388205179,42003176179/4581:719444822359855/9543 +qaddz:37691546351/502,-21661824585,-16098775076/329:-10836544395319/502 +qaddz:-35885239812/857,34474662009,=1:29508900101901/857 +qaddz:22416794298/37,77595160739,19551745221/79:2893437741641/37 +qaddz:6506889348/5,89218535043,42795404175/52:452599564563/5 +qaddz:-17539280423/2,-76893365070,11913582381/2:-171326010563/2 +qaddz:-18732975933/8,-68638332129,=1:-567839632965/8 +qaddz:752606019983/39088539215799132539,78330421475,375459572044/17732255158454998643:3061821751615612031471862895008/39088539215799132539 +qaddz:-87137756962/6035494303898759827,-609859506482,522818453593/79286344644150136171:-3680803577550619796673205455576/6035494303898759827 +qaddz:-421506353201/1519073638798046220,841569835268,206505393657/3285765743903619005:1278406551963233090464143733759/1519073638798046220 +qaddz:313227767819/3667276491812736850,-527972639267,112687878130/8071994431605454933:-1936221648304195391507820121131/3667276491812736850 +qaddz:45625693955/874183546628376789,86870332839,316926200883/622490420207251454:75940615657984567948357767926/874183546628376789 +qaddz:307191711010/592741905927742817,469188479690,640816126728/494995852882629881:278107673690790651608739597740/592741905927742817 +qaddz:-15083287151/7156847089669175,536288677413,-968335381430/55030206560476363:3838136060165760061381557124/7156847089669175 +qaddz:494377643469/98558071038934628,454517393920,719586404719/50508704469542694:44796357598398794466182305229/98558071038934628 +qaddz:45709637656/3099309256090823,-330553962257,-99912647867/433025093788036:-1024488954860616607596429855/3099309256090823 +qaddz:-666357878153/2095670070843359,757413983851,=1:1587289817194775273218717356/2095670070843359 +qaddz:126425902111/416943810772372,-678980645165,678919705009/106535794783049:-283096777635778691091479269/416943810772372 +qaddz:585263176259/851781334135526,22092528056,485539073651/458880186297433:18818003021966803924493715/851781334135526 +qaddz:-873682780814/76616993618553,693272108938,956115786575/5882428371192:53116424746422652551145900/76616993618553 +qaddz:304885366516/59327405229613,446589528583,-184321844164/42141769957411:26494997933545783426894895/59327405229613 +qaddz:227263949507/3005012215064,-970992420883,944562884485/8363349411634:-2917844085487752336832005/3005012215064 +qaddz:256051015589/5849799282523,145771147218,425125619888/7082715872863:852731952408667058486603/5849799282523 +qaddz:922332758083/714594213406,203681203456,751751042693/26386109479:145549409370150101489219/714594213406 +qaddz:54459784009/28808646278,-878737718814,-508120353933/475490279255:-25315244112394691890283/28808646278 +qaddz:-75343229837/18301076728,-18822576757,-5004528638/1010757283:-344473421523869640933/18301076728 +qaddz:455494735961/31781276434,112071922031,-828539887333/78026709049:3561788735012400453415/31781276434 +qaddz:970291731117/7275020519,-637559590581,=1:-4638259102591722400422/7275020519 +qaddz:-982813942861/3854475224,783494985089,=1:3019962007170985992075/3854475224 +qaddz:892057818224/861585953,-595915633524,-949622564162/410937589:-513432538125316470148/861585953 +qaddz:292775249633/706174681,844137005926,193717693265/82462566:596108181172863409239/706174681 +qaddz:-4493924646/5798807,-582307144826,-746783726287/48847174:-3376686752060947228/5798807 +qaddz:-90281739197/55430389,586184656508,420537839926/78274081:32492443445788082415/55430389 +qaddz:-53911496672/874759,873541937929,=1:764138618169337439/874759 +qaddz:994025741513/6110189,974615575614,-72802324373/849950:5955086363371072559/6110189 +qaddz:624261056662/482529,-97311267314,=1:-46954884244700444/482529 +qaddz:-39993733292/46881,-841794041874,216763126337/306248:-39464186470828286/46881 +qaddz:792871375475/84839,12838795021,=1:1090023402162094/84839 +qaddz:54064516459/38317,126266853725,=1:4838221098697284/38317 +qaddz:157148550179/2580,316644803876,=1:817100742550259/2580 +qaddz:-892971311861/9503,293701366371,267061134465/5464:2790151113311752/9503 +qaddz:56861735925/22,425609853419,=1:9420278511143/22 +qaddz:975604652373/62,798330121028,9837445133/3:50472072156109/62 +qaddz:301936419421/8,401226430058,642908142507/92:3511747859885/8 +qaddz:960812431491/91,821665693935,184158030746/25:75732390579576/91 +qaddz:-288196323271/3,-6851210649,=1:-308749955218/3 +qaddz:27950016152/3,811526852805,=1:2462530574567/3 +qaddz:-1239949810170/37215316493340542309,5084146392476,-296516594614/47057875211140309013:189208117094469900857215847456914/37215316493340542309 +qaddz:-9982761144683/86065596803955058468,2050494075451,-6484572703254/4884291350957415781:176476996346664368103513547324385/86065596803955058468 +qaddz:6263655072498/2824969489983333169,5441993837821,2221750454035/2194218699041801277:15373466556521632295955651057247/2824969489983333169 +qaddz:-5989792323571/836318289746974211,-2931974130042,816998017476/3394736245988200951:-2452063590019098006588326670433/836318289746974211 +qaddz:-7698578874730/344070437345848791,6704395369109,=1:2306784246788816955726767522489/344070437345848791 +qaddz:4466480763133/830946743248529621,-996598272615,=1:-828120088956544529460779865782/830946743248529621 +qaddz:4485142594172/49082393942890253,9197604183793,-4770331797107/16903008398062353:451440431879703596984582863801/49082393942890253 +qaddz:-134312893516/16006607498131703,-5249882281532,1583762956049/37750476556875940:-84032805091878883507373502512/16006607498131703 +qaddz:2427070778131/1995258741120055,6244907615189,3514628161072/4284871651689771:12460206506693051427861293526/1995258741120055 +qaddz:5325619193316/9866683016060977,4027295598641,9237993735817/7374034428483561:39736049083768285110593525573/9866683016060977 +qaddz:4506791224955/98740859078376,-2433647151513,7230124153235/24547192761813:-240300410434031792022757933/98740859078376 +qaddz:6263613039105/662686345538291,3241626331560,6974592366933/417432893529050:2148181507262199091454803065/662686345538291 +qaddz:-1811100007460/13795113510661,11776226228,=1:162454377540672125809248/13795113510661 +qaddz:1928373998137/24092133222096,101879503692,2556288163059/81191221300450:2454494575550613661976569/24092133222096 +qaddz:247425249267/4299310767884,9656652793497,6941336412649/1087093561201:41516951336799008176899615/4299310767884 +qaddz:4375335748035/3738750520588,3905049802371,723270679177/5043873825535:14600006981541018102462183/3738750520588 +qaddz:7794911344062/83950994789,-8243600514425,-2603543493997/10276127701:-692058463821295982987263/83950994789 +qaddz:-3095785250121/322417942963,4195151544235,-8472000440819/880146461714:1352592131307205816218184/322417942963 +qaddz:-4517167531751/11212303539,1754468949877,5238909223466/69391666005:19671638411254333182952/11212303539 +qaddz:1112980425235/45979665716,8827854965263,2125854079037/42150601594:405901820293236512448543/45979665716 +qaddz:563381672458/1066429293,-8418949099715,=1:-8978213935648672279037/1066429293 +qaddz:2857062479357/2065941250,6427518036538,3720687400259/8823089384:13278874649659923871857/2065941250 +qaddz:6660515562878/864868567,3023828885557,-2827547445095/772367393:2615214561765405149697/864868567 +qaddz:3112189653770/430887893,-7852737661995,-86959631083/81894801:-3383649582346582072765/430887893 +qaddz:7683412484443/95948152,1332390320090,2759996778764/6533551:127840396638736458123/95948152 +qaddz:159684374850/3723623,-1974161463836,3321588400449/53889098:-7351032872769022978/3723623 +qaddz:6040625454008/1761191,7333833752524,=1:12916288041066950092/1761191 +qaddz:212485296160/215857,2626911385981,255098287490/595687:567037423528996877/215857 +qaddz:-954041238820/149351,8462499450675,-3418839060974/6081:1263881801416523105/149351 +qaddz:2631178437270/289589,4915496549364,-7382060007604/607303:1423476361412208666/289589 +qaddz:-4190078661321/81307,6205900529843,-4545813476917/72302:504578964301283480/81307 +qaddz:3075448966277/10503,8355956941265,3979238326369/89488:87765691203072572/10503 +qaddz:-4159327490855/1442,9824287076936,-4853919949437/3400:14162462637450857/1442 +qaddz:2105555375170/7889,5827815981584,7350815564091/1621:45977745834091346/7889 +qaddz:-970057756335/134,5386054563891,90106168024/673:720761253805059/134 +qaddz:705786323151/74,863825635194,-8448597370801/341:64628883327507/74 +qaddz:677223680197/15,1191619181913,2784760197168/47:18551511408892/15 +qaddz:1250102070269/12,7296468619064,-8785308120663/49:88807725499037/12 +qaddz:815291444846,-8875650934350,-9869792677199/4:-8060359489504 +qaddz:8187166853148/5,9378339124723,9909614166843/4:55078862476763/5 +qaddz:5422808604175/4005553410506916322,59300928198551,=1:237533035191931723527928367253597/4005553410506916322 +qaddz:10175385793742/12145808688724905047,-50946207146217,89160661571041/31082940158416923936:-618782885414101287608920784463457/12145808688724905047 +qaddz:-66447228282594/5132267228812337113,-55179117587940,46405635667194/2000839741729635683:-283193976911366915176041931499814/5132267228812337113 +qaddz:5047791146973/4721169311443187453,-99279491905591,13672396382858/7559676837928609713:-468715290440348563665526200602750/4721169311443187453 +qaddz:29394169412845/154033282520525053,-29623023279395,9504860273065/124604054480863853:-4562931513907140557523146770090/154033282520525053 +qaddz:4067070745921/152576293456659409,771698149382,82888271738589/108217943144539550:117742843300069025816248581159/152576293456659409 +qaddz:75868597092083/18545709845595165,82562069353348,62428349184891/98682364625908466:1531172182479096917186342454503/18545709845595165 +qaddz:38258707804725/80482758393493951,26694314420345,16108158643166/21949554170590857:2148432057972588200266536637820/80482758393493951 +qaddz:46555640927056/1709747501026629,-16128468753166,32141736958103/3736469425292601:-27575609146111592776953130358/1709747501026629 +qaddz:45370445351363/7110877719431711,86735990625964,-33565334246797/6384179688851649:616769023215005197115686895767/7110877719431711 +qaddz:9475910636228/981744732543279,96180861167731,=1:94425053822896329193346366177/981744732543279 +qaddz:91004040702465/936897618249146,45878038637853,=1:42983025129746861152661226003/936897618249146 +qaddz:7213181652898/7450266621563,23288667968005,30404125827566/4549937716875:173506785622698280708744713/7450266621563 +qaddz:-89229843161908/67491130269077,87276718571732,84273766896387/35434923631324:5890404382582247110442769456/67491130269077 +qaddz:6912185841959/2387122535810,95367158366052,16820307441286/172628433269:227653092911770818644164079/2387122535810 +qaddz:18631413455311/5393632894857,30541536678945,67884298820845/8941925270968:164729836891057997564141176/5393632894857 +qaddz:95264142661666/640329051433,33493375919635,26112952504575/900465490172:21446781632004027732248621/640329051433 +qaddz:26873236385920/167838163737,63857215148601,48278558616779/606456030301:10717677731926604660867857/167838163737 +qaddz:4401103056499/2897755980,-11052252274481,89598593400912/9441413885:-32026730116444816089881/2897755980 +qaddz:1318889016693/4307161820,-79377185552021,28715124462201/59240718095:-341890382987401586021527/4307161820 +qaddz:76790810847961/5450577611,68261418218311,51631448908695/2088035198:372064157912624257682982/5450577611 +qaddz:21126534617963/8738346544,57900812244090,-48117757406954/4100802105:505957362589063270542923/8738346544 +qaddz:54005121935732/492299853,-95310437087251,7343525049871/87207576:-46921314113414293538371/492299853 +qaddz:65465816406636/92490709,85963247914764,=1:7950801813045110334312/92490709 +qaddz:-1567974419029/2146031,73885253968091,=1:158560043890421877792/2146031 +qaddz:76063102421737/23698475,94901902098254,36870175818609/29433536:2249030430391022384387/23698475 +qaddz:21982490259259/3028082,35729075461978,-48666061360318/4739221:108190592265547525455/3028082 +qaddz:44090802588674/2725087,-59617101535954,4729707469385/5642703:-162461744282505689324/2725087 +qaddz:31794415201437/483367,88454206922687,23449145143186/104191:42755876432013648566/483367 +qaddz:21120858803723/196745,-97469888172037,=1:-19176692027548615842/196745 +qaddz:6353568582461/36133,71560599712641,-9946843698401/1669:2585705502985439714/36133 +qaddz:37008170564675/36399,98738162943972,=1:3594007401168201503/36399 +qaddz:-19046004662298/5177,97280021451374,27910156790976/751:503599625049100900/5177 +qaddz:67988194828572/3833,91182292091517,8505334994139/1301:349569713781613233/3833 +qaddz:-27835175210909/97,-86045963939656,69384812566415/607:-8374293677357541/97 +qaddz:-66933996037605/499,-26758226932551,44077986933749/138:-13419289235380554/499 +qaddz:-69719056900661/20,19918523107231,=1:328651405243959/20 +qaddz:9273298009097/11,72385368670495,71790012014913/62:805512353384542/11 +qaddz:21941955990125/9,52544189533470,-12392727415391/2:494839661791355/9 +qaddz:-6780461974136,98345436504870,=1:91564974530734 +qaddz:-84540612076693/19951779938951892435,-646908420217313,96551072703477/9551882373716321942:-12906974440830846345093795912803848/19951779938951892435 +qaddz:-83364626051404/25732505849792137517,-259790031036174,=1:-6685048493356028415791438435591362/25732505849792137517 +qaddz:-897066937584389/9348251282430626623,601658334644890,=1:5624453298429168053199845947322081/9348251282430626623 +qaddz:-205588700127652/1395648197045308621,722142436485815,631381416931617/2014178604201247978:1007856789491333998582718663583463/1395648197045308621 +qaddz:271688711340751/180941683917606723,-804877924901239,356634127117981/581970885207340397:-145635967079739188257214306089046/180941683917606723 +qaddz:-150593304294442/751040562206456283,-252704334790286,580538958605443/761261694295334982:-189791205672904947390115336361380/751040562206456283 +qaddz:-33791007514234/9931544134782813,644114592405109,-28689348856389/27441863478469573:6397052502328982483214019077383/9931544134782813 +qaddz:571363848651239/66311445792999286,-10840446958246,29259414259102/2538648211395449:-718845710843613051916101161117/66311445792999286 +qaddz:911329771312150/9119213968348277,389930802134286,44063137011973/945363924228012:3555862417512229944211542037372/9119213968348277 +qaddz:304065915990821/6933490862650654,-179336341462285,23446882001027/1428507361849985:-1243426884869950368991555593569/6933490862650654 +qaddz:13794668675671/40367472899842,-309167092058184,502787291762833/565691523820858:-12480294210181685647999731257/40367472899842 +qaddz:-67226439568370/155342790290953,-999058912984495,463385115124522/611519522742283:-155196599208057935177067342105/155342790290953 +qaddz:959309013745217/47174481901345,384897898127779,=1:18157358929095601304695707972/47174481901345 +qaddz:65775323516640/39878078972149,40619665002388,983890817704139/3521649399512:1619834208787531337994008452/39878078972149 +qaddz:256671220274850/66938758003,-730244708478110,930955533204827/6929373391761:-48881673823530816492539480/66938758003 +qaddz:-893936101636063/827048331634,597691527840677,-126588969738553/668190758507:494319780931514439309440155/827048331634 +qaddz:234866720760362/249576871361,816339748530719,745271148727983/265090084030:203739520406157211340598921/249576871361 +qaddz:21197614731825/513159868888,-383505627380083,188859267143231/81431113864:-196799697464152377607825879/513159868888 +qaddz:964492287424130/65578382813,954893437672646,-807333982742123/64002138636:62620367402282827454057328/65578382813 +qaddz:-177007104279849/1974354920,357812362625802,199235392833781/39880047906:706448598410069193365991/1974354920 +qaddz:91059156010499/3926511496,80812106334647,889997682906405/8258270479:317309664630025024612411/3926511496 +qaddz:451880285884181/1898972562,396985801563335,-25588857743575/1369245348:753865145124230156098451/1898972562 +qaddz:-31366502392369/134800936,883517312779341,385458521261359/159439811:119098960703493425870807/134800936 +qaddz:-10128482818698/70545329,960042254669295,158648344293111/128796202:67726496699418719154357/70545329 +qaddz:335395247847445/29367757,-244136374073097,-48337710344902/5085513:-7169737373244565085984/29367757 +qaddz:122530580993759/16204629,960637241145668,=1:15566770218879665890931/16204629 +qaddz:817780076457530/3494021,283630218235935,3662113752156/4047877:991010756531016302165/3494021 +qaddz:-217463590706488/7914657,312381371588143,-746462040054419/4436039:2472391191846106405463/7914657 +qaddz:100306351636824/211229,-198763366297580,-307504584166445/361449:-41984486793319888996/211229 +qaddz:144895746707409/536491,670873254269860,-454046918862603/780899:359917607952238168669/536491 +qaddz:334763841889403/29410,-358386406501860,411931926070123/15800:-10539809451377813197/29410 +qaddz:177232274198821/12516,750894264493456,79990853919389/37735:9398369846674294117/12516 +qaddz:179909139835812/1979,408538585432232,499794975465566/4363:808677769710222940/1979 +qaddz:374051483837827/3284,-984497815753029,=1:-3232716775449109409/3284 +qaddz:72651383395505/137,180883369883715,=1:24853673057464460/137 +qaddz:-795240710923177/87,-266514612085555,-145736783502361/320:-23982011962366462/87 +qaddz:293684182859578/93,-548418457694218,115702982878171/33:-50709232382702696/93 +qaddz:-775889557419502/17,435575409934841,891608394581532/29:6628892411472795/17 +qaddz:298220230000324/3,766606056221642,-153273190527374/3:2598038398665250/3 +qaddz:249679021051517,393498225268690,=1:643177246320207 +qaddz:3542672594684587/23493960223203744626,-8259187214851748,=1:-194041015901719887360631082447021661/23493960223203744626 +qaddz:6602377363368086/26756588963267146371,647903723659326,-14331599050621/14088246371426023870:17335693621722809158754291144574032/26756588963267146371 +qaddz:953643270036373/672267077222382067,2730834301717412,=1:1835849994394189222848787000486977/672267077222382067 +qaddz:4732337125860764/6964537546610955687,1462613230096260,1598512177911468/1847092196188952335:10186424757175331839719046730291384/6964537546610955687 +qaddz:392871539920454/124667933854771591,4222301184211601,4921205597352118/360784888091913307:526385564748215632593338807347645/124667933854771591 +qaddz:2490987481558645/273236967005544791,5809366131098920,-8409430808361398/118474537825945987:1587333581886205001306049593284365/273236967005544791 +qaddz:4255269445550164/45737089432737585,4857866077021042,1465698613834409/6912785090125613:222184655216973491505517154813734/45737089432737585 +qaddz:9210797969401333/8163980149744856,9750466506961289,6445568175713494/15481234020450335:79602615013584036398759188280717/8163980149744856 +qaddz:414318154924738/4286466178431057,-1529884082696356,=1:-6557796377397951866564056203554/4286466178431057 +qaddz:1482835316159491/9227279017181664,3761016398994804,217567654667999/4259451401870992:34703947701720897607169976233347/9227279017181664 +qaddz:-859552591107487/51274074663284,-418382458987624,-4461813189832442/202453728783091:-21452173439940648539914304703/51274074663284 +qaddz:651597097619645/119852979164632,9814527719768623,549507364552128/130838602558483:1176300386308132636435962561381/119852979164632 +qaddz:3062835747588459/29244354985217,-1153612952589391,-1697694605519151/20613920170229:-33736666701065396523928444388/29244354985217 +qaddz:-3555234895468573/82553845875899,9556279680346194,=1:788907639878281506316585509833/82553845875899 +qaddz:-3430655994829779/1022475878060,-3861606915733328,23919352405729/346214612268:-3948399921890433631600813459/1022475878060 +qaddz:8941063770802759/6431761572186,-9248680430430457,=1:-59485307385862346247287666243/6431761572186 +qaddz:-1458085892513495/865768190522,2913463648461976,2967255557005217/183961790972:2522384151079091183948077977/865768190522 +qaddz:309596223775083/196561317238,1984332827634766,-56866515384243/60782960375:390043074438804409147671391/196561317238 +qaddz:9692793587023183/17106658395,1171032202882506,9344415493288159/22347599779:20032447873948158050561053/17106658395 +qaddz:1297322765335855/78060494353,2404633388766311,=1:187706871066125196217477638/78060494353 +qaddz:8963645561434168/8924489269,421621279944751,-927728264088899/2108513434:3762754597412620773811187/8924489269 +qaddz:2904608103864485/1444422187,-8951359589722050,1306658433557061/999915185:-12929542392305138079258865/1444422187 +qaddz:-6451464021043383/499665577,-9753719382757790,-1838096568039957/168375724:-4873597829733219012638213/499665577 +qaddz:-7656575927425727/878618401,1131218876361418,9338726624701012/366586573:993909712673109853826891/878618401 +qaddz:4172728002376239/19479743,368831988655257,-6420008608192074/55268659:7184756521911324335190/19479743 +qaddz:6161530173305165/99639697,-1432201837180119,490175175009028/6720087:-142704150937940218278778/99639697 +qaddz:6918228969049918/4185569,-1641939400683084,-9043134997963566/4283597:-6872443737148726164878/4185569 +qaddz:1451717795705836/141415,-9179648440127908,=1:-1298138532442892403984/141415 +qaddz:8140278576768419/808479,112313592852123,1026877402176763/31094:90811321514068319336/808479 +qaddz:5643486834069101/530944,1715393818673080,4580531049699971/438581:910783699148393856621/530944 +qaddz:-1028760789941125/31581,6778845120322328,3983036171498424/29225:214081678984109499443/31581 +qaddz:185311071775543/30749,3825266581520702,-9282766742556431/28854:117623307426251841341/30749 +qaddz:6239950654595061/6550,297809616078377,958337836911634/1219:1956892935967964411/6550 +qaddz:1051395142542259/1190,5736372693566227,843234486155860/5981:6827334900486352389/1190 +qaddz:8170656479179803/377,1507295266275575,2218120930173065/774:576420971865071578/377 +qaddz:-2473414150338949/204,-9581413081720714,-4722755512692772/455:-1957081682821364605/204 +qaddz:-8681518748104826/77,-3407099061618709,=1:-271028146492745419/77 +qaddz:8708666762588363/78,82065604323195,16011547616829:15109783899797573/78 +qaddz:-9527121546851805/7,5686511086561176,-10800792278755:30278456059076427/7 +qaddz:-3156505883016239/9,8703260342529372,-186440241608063/4:75172837199748109/9 +qaddz:-29299633375857887/9525577839119524640,19394264263578925,11770323744387737/9435334262616904973:184741573875175155232312577746354113/9525577839119524640 +qaddz:45414752276742165/12207900549477852191,73340302679712901,-1762362316527451/5610201133037246999:895331121382539119649801382270558256/12207900549477852191 +qaddz:51287924597675777/9802415152761834211,23795752241231275,26808795167323503/4767990503572354769:233255842340811827381416634655824802/9802415152761834211 +qaddz:-11478523036790/4661848726590019,-92346960041294475,-99921528151340483/9725949381928447460:-430507558072968016697671897881815/4661848726590019 +qaddz:35557351930961/1508286209602511,-81125561093339512,267345760579243/34391099339971446:-122360565043349990608741738783671/1508286209602511 +qaddz:-4793426675094793/37007904105416450,60895517302185125,11894447435691093/106928191679495960:2253615464768995346344506445211457/37007904105416450 +qaddz:31586795072540784/44373236784764585,90702169150810719,18513292834106234/37597849772411799:4024748828620693789339255382127399/44373236784764585 +qaddz:-1049981287826468/21587060162890651,71326478095880873,17797674000912830/41386390390327551:1539728973862882607828674533591855/21587060162890651 +qaddz:7766969806666613/5323521507239637,-31539639298859404,=1:-167901948138058494538892792329735/5323521507239637 +qaddz:28336169012562031/1963339938986121,36117112871692963,6517543421786160/2515812174582889:70910170181864535729772042928554/1963339938986121 +qaddz:51605249327254279/329660326356162,44496912384848741,=1:14668866658630834332811390546321/329660326356162 +qaddz:95776204572834299/360483541928559,14896033753227230,-634271284568050/59231390665489:5369775008050814030088926295869/360483541928559 +qaddz:3199790617176713/2044034589474,61554085339919034,86943016409024831/69267518528772:125818679558232164197205824829/2044034589474 +qaddz:63207445866080934/73630340098063,62781346312315459,=1:4622611880790123804296516936851/73630340098063 +qaddz:-10562032121106923/7562195446113,2371574008330945,-12004106935992565/4243540006504:17934306165909664170696759862/7562195446113 +qaddz:74286029526835348/6426144147769,-56596118082865321,10556610079748403/5666686062526:-363694813004573972309622783501/6426144147769 +qaddz:7784837673853468/63315839471,36983417562905989,24368105233273509/482119525015:2341636129509702481462345287/63315839471 +qaddz:41230861520352699/248615826076,65301921451058132,21820151723088751/772186719402:16235091145946112952997802731/248615826076 +qaddz:7868735455391473/2376142635,24220945772157046,42112368834645777/38165511736:57552421917114088371647683/2376142635 +qaddz:16212068555703281/21768826663,22486544931183098,31430506824676803/88055986181:489505698872898192433045255/21768826663 +qaddz:18990156909977866/4288195941,41076064025528634,4353887544365053/451796487:176142211045518165608052460/4288195941 +qaddz:-52094180225299371/8295443431,97662863401423145,-9449635278901807/4480020195:810156758603891764016311124/8295443431 +qaddz:70121165050790582/884849671,9294106339201909,871866453377042/132524629:8223887006602988632012521/884849671 +qaddz:89800859106311942/275630735,48525545845357510,-21376168718994863/279135020:13375131957432945925381792/275630735 +qaddz:65595348623886377/41322369,78674639156794339,-7330652418059047/43068742:3251022535774253157155468/41322369 +qaddz:4765824965091103/13071190,9760309664863845,=1:127578866854096607216653/13071190 +qaddz:-6087229416296351/2127106,89049693910575358,21234009428205913/420191:189418132128118891157597/2127106 +qaddz:62215823394518468/8207157,27553281434116768,-10639236075124883/1311092:226134168810804865827044/8207157 +qaddz:-8994816719328305/35983,-81534831740246875,=1:-2933876845326022631430/35983 +qaddz:33370840040824831/471708,31379166699519941,-3805555942820402/57901:14801837336337193154059/471708 +qaddz:15270801632993512/43891,62114435487940553,91890892291173796/96141:2726279958802831805235/43891 +qaddz:52066031635427411/80207,79948554826885018,-32268139784894785/9291:6412485803031602066137/80207 +qaddz:30138851628256646/2271,8808985720955931,4132024812310306/403:20035345423919175947/2271 +qaddz:-48704579394955369/515,96280004013075991,96197516817859731/8348:49535497487339179996/515 +qaddz:-76138989019830581/163,-7824132792666947,84793723224519789/121:-1351472634224542942/163 +qaddz:14262406418152892/23,45957936069739248,60434066726939490/989:1071294936022155596/23 +qaddz:34014765103829171/5,12306267367411447,20552835074171214/59:95546101940886406/5 +qaddz:91849502756698141/20,-82945870135128988,79066927763083824/47:-1567067899945881619/20 +qaddz:21965479380351319/2,66229223349934130,-87992715521815677/8:154423926080219579/2 +qaddz:13175376582771327,80435538108007231,-11481476371288002/5:93610914690778558 +qaddz:233543544528899097/29308688028184850696,-313371565494318136,-546211686884835394/64310476577955517625:-9184509449976866806361166554956123559/29308688028184850696 +qaddz:615655938896447797/54625270368834900652,952119518403165605,-481883729818516183/20964479862538317110:52009786116217798007515677541374922257/54625270368834900652 +qaddz:-306096577466260199/1563899474881584021,-795305085572154223,-267651228746045877/3959443707942409072:-1243777205696945233963124085010730882/1563899474881584021 +qaddz:303249287074462526/988120532724227499,996970552281399322,-597979414385274083/1415816308850447338:985127073230663601717735166266818204/988120532724227499 +qaddz:952339724809160651/584399533289204739,-621203230425875224,-89809265051648755/476952842063426958:-363030877938627789190802770194325885/584399533289204739 +qaddz:-165153711870868787/63787766852635668,255678391566014218,=1:16309153630469804511357374991058837/63787766852635668 +qaddz:-170282783383418995/92637597632923627,745590434716695858,727513707271968617/97034490370058355:69069706690241882092088302517817971/92637597632923627 +qaddz:402676307184383008/54079780485931177,-833124989932029446,616876399608513026/73463803299685963:-45055216572867773936309791509054934/54079780485931177 +qaddz:638546632762921290/5700920505461219,866490174226616488,=1:4939791602029182823423545032900162/5700920505461219 +qaddz:490462229342420061/2997315021629032,-794115458808160581,-232736090223412025/6604604996597921:-2380214193593530011634172725167531/2997315021629032 +qaddz:989191334948063646/238829798613001,932376780689163706,-297260947715156566/95515827924885:222679358763432156823484377005352/238829798613001 +qaddz:733917544080141979/846584851419104,-407471079015324208,-856462825746108845/144065790220028:-344958842885769496528467364727653/846584851419104 +qaddz:-776150844455451188/60437639060267,140648215789491479,110557086596050071/2940144395374:8500446100355055871518908513705/60437639060267 +qaddz:40423809761966727/80515282319291,-896056243874632922,993643995036126943/67717664005426:-72146221449529496100479662331575/80515282319291 +qaddz:241416851638718491/3382660773031,667600506773221104,972636880608985845/976751193229:2258266046317632867918161964715/3382660773031 +qaddz:-311949759477562509/5272945258477,790859608208962462,=1:4170159421226114570459102727865/5272945258477 +qaddz:901115730770569756/737757545883,-294335029298267342,=1:-217147888881589502127194883230/737757545883 +qaddz:18952440190304626/427387361229,-871562962990980105,43270210830528697/42201089691:-372494994897624619964197044419/427387361229 +qaddz:368767126618980087/13867934102,408207198365664686,-388533375692412433/38881769599:5660990527265847091495502059/13867934102 +qaddz:185955534050890250/81788514027,9078725197697519,6436386921261961/22246601990:742535443365117414885489263/81788514027 +qaddz:82375478298045903/9517446343,433517004473691938,-26962495372093825/2304101598:4125974828938829453324728637/9517446343 +qaddz:44007143033079188/7383992497,504540760833169168,449177596957809274/5425450729:3725525192466799748276811684/7383992497 +qaddz:224818172747147/390111499,962172118291046785,59451455054756859/215170474:375354407362750397748227862/390111499 +qaddz:666309089683814939/682581559,-650419141072050333,2300719817124450/74245723:-443964110650091957941794208/682581559 +qaddz:542166078934696959/86595368,203399832612491739,620419080726846107/28244360:17613483898383202470361911/86595368 +qaddz:297894210502629889/46145547,12817895959056372,-291344707530390547/39774025:591489118313956392405373/46145547 +qaddz:715463509593675473/5054643,203255281666377882,=1:1027383602151494890281599/5054643 +qaddz:-658143668234554099/5196064,-351454032197965311,885876617433980026/6310607:-1826178302502356660290003/5196064 +qaddz:-864175272258886331/214462,-113193172511339576,664419730196309649/256429:-24276498338399167034443/214462 +qaddz:554632290831706045/878862,789543599984323318,=1:693900422001713191610161/878862 +qaddz:150056203172522033/10088,195421727932292330,-430213757895224789/5107:1971564447584137547073/10088 +qaddz:649664968382611201/15350,341314581999530333,172494507042296540/811:5239828498661173222751/15350 +qaddz:5864597320149566/905,489601633652276174,975732764347807769/9424:443095343052630087036/905 +qaddz:-178366641538470155/6144,334923469737215876,171402458096874349/1678:2057591431423915871989/6144 +qaddz:783919995622849413/623,278317030520011920,784978030394811864/577:174175430009590275573/623 +qaddz:-749742866135544447/698,79278627691587063,696350994873672899/683:54586739262592225527/698 +qaddz:344612331720575876/25,384322240275621066,-573701559443193526/77:9952668338611102526/25 +qaddz:99948350225973980/79,433526372044256631,233613544663506071/70:34348531741722247829/79 +qaddz:-813485941375813961/5,-73645253545358755,182695807997160858:-1181712209102607736/5 +qaddz:109732737408333914,661611874779880732,190730815184312667:771344612188214646 +qaddz:4439294254467838396/7399413423727575529,-375832621848838675,572455588779808659/2231006844433926946:-2780940947183026582974366027530945679/7399413423727575529 +qaddz:7401374720469772972/86040177417213246183,-4800899289575736825,4427571953719739521/79545327171368379:-413070226637269428522568343871874016003/86040177417213246183 +qaddz:-8281164336639608343/9930865450361852117,6652240436187019086,=1:66062504715229724855994090627548896719/9930865450361852117 +qaddz:2289593814998925046/2242678823806551791,1233211911037543012,8805138183115340751/6847414846976791820:2765698238149906948783491675567059538/2242678823806551791 +qaddz:58801253288456253/38080076339475325,4579333826855732576,-4512504820594295629/667425159645398768:174381381710607976743900573639143453/38080076339475325 +qaddz:1716963717527421640/225107768198324627,1976152916296866074,-8003061483125113466/474882649845647945:444847372606198139049564734922426038/225107768198324627 +qaddz:1034271517993599571/34228782689291755,7928647196076102620,=1:271387941894551313583006246493497671/34228782689291755 +qaddz:-43641059638095731/1029053223531219,4223820009592786988,4164140830282395355/41576160555557154:4346535596487121765588673396882641/1029053223531219 +qaddz:84297032713892287/207039580865947,440521401243831520,-6509343821181533355/9783431747165674:91205366276002625631486487141727/207039580865947 +qaddz:-100413440983654438/8617388967629029,-6540040006542842669,=1:-56358068600234775154346511687892839/8617388967629029 +qaddz:1601279569975518578/576041083643833,1520282279789457956,=1:875745051894437875280462407703926/576041083643833 +qaddz:1171909659900623927/396276655723830,1432202312057184673,-8716463823146798000/535782069662653:567548342541959482379720697481517/396276655723830 +qaddz:4919734080771991528/21359215600941,-486806183295567418,9601757988490006002/10830396257143:-10397798224876307889797677748810/21359215600941 +qaddz:-3738648400400330743/50301136962499,9954014077000284556,8872351197089153189/16636866534142:500698225413830641940352100534701/50301136962499 +qaddz:167898860851405426/29985611753,3092079056219981783,-9747501808202416505/7849158986817:92717882089562932366622101025/29985611753 +qaddz:7674883887123290368/1292702782951,7265216107539444345,5305342163772150486/5832447092447:9391765080964346281672802652463/1292702782951 +qaddz:9423076605657351418/240889071441,-6059127953500151569,-9218210247853014151/104806977658:-1459577706451435060703511889511/240889071441 +qaddz:6906236673658662814/140167346995,5953302177726308344,6858441000058123625/723669979514:834458572118358858467470489094/140167346995 +qaddz:559876427517689463/32071119551,-5256353831354881895,-4515947459706955400/25152550949:-168577152127179433134512739682/32071119551 +qaddz:4068672547617525067/1548794000,1708587743626678397,-207685545846576256/11174851881:2646250449871210288820743067/1548794000 +qaddz:-5137896362067916551/3635693101,2393661747677268624,-695423398519672103/878721119:8702619497019951948732646473/3635693101 +qaddz:234276694270475397/294461381,-3074163560486378221,-5996024834040014309/815688460:-905222447206419268373507804/294461381 +qaddz:-1281564341537166075/106650493,148338290500462844,2961154916731862131/237638921:15820350531087237503616017/106650493 +qaddz:-6081903223358942866/140515995,8576558583908287121,10228381531459438/108952997:1205143657011760730194057529/140515995 +qaddz:2904197618588220738/91768927,1341853265056004046,=1:123140437229833704797299380/91768927 +qaddz:8444844737047959/6508337,-3121162187991725782,577600780863107469/77886268:-20313575342662659863796575/6508337 +qaddz:-7581658318588584115/8539308,1829695701216611407,=1:15624327557306300932102241/8539308 +qaddz:5686384777950870687/5180266,5725674667424296916,=1:29660523493104170838730343/5180266 +qaddz:-9349000804660487281/169585,-9931090441642768328,9282213820882713035/676238:-1684173321546793527391161/169585 +qaddz:-4987687379036548499/415933,-4529830725292970964,-2701909210096535388/203425:-1884111070750660328517911/415933 +qaddz:1296987410190297797/20878,3549166774468354520,3245395317975795443/28657:74100800904760495966357/20878 +qaddz:1416158818097070767/3904,7994210571119010019,7360059100347464896/48079:31210814228466712184943/3904 +qaddz:9709919947974007131/874,-6830730629919228709,2205443246566180090/303:-5960348650601431884535/874 +qaddz:1925917894957464961/685,-6027249478829109060,-5343051367134373712/1021:-4126739975102982241139/685 +qaddz:3125021296756461042/505,-3536767182227478666,1332510672665779772/45:-1782942405728120265288/505 +qaddz:-5071777645997131741/514,8260041058129029864,-531041568629881135/103:4240589326232324218355/514 +qaddz:-2218822602969636376/29,3585630033488142992,3393420876741550072/15:101764448368186510392/29 +qaddz:880044572043278916/11,-6109313865580717394,124212297019093925/14:-66322407949344612418/11 +qaddz:6248985291450346275/2,9493162199953532306,-4130466083733148400/7:25235309691357410887/2 +qaddz:1986241673445749321/4,5178416138859731379,2046732894250340779/8:22699906228884674837/4 +qaddz:9979832122548221402/12717137847146036559,79527741365413786355,73831860449336535169/1514391878508936732:1011365249616145076974769500777993573847/12717137847146036559 +qaddz:7935653883386524088/43702671649323180779,31726785951925090635,-73129402153480840711/23070283018861257208:1386545308945341622873014968339451428753/43702671649323180779 +qaddz:-93473235956409121974/3521849589372767293,14176089406854262878,86358338521892655661/8513932339338708236:49926054656441321879828060404133327280/3521849589372767293 +qaddz:-75776234900005146680/1934924867434433667,58779385165176736174,=1:113733694048607113038507934157157223378/1934924867434433667 +qaddz:10754058131593805677/10119651272346505,54504300977159159643,95585489620287220450/323814423064533371:551564518731865556391884682101903392/10119651272346505 +qaddz:-26320122648161591867/118955488311945989,36439044282055136810,19850642639958356517/200120485264504867:4334624306192492122600675236564163223/118955488311945989 +qaddz:21672449029428526941/15150265559827046,99277026381166669676,18730584597709492865/69655516304512819:1504073313664630491063919887801384037/15150265559827046 +qaddz:85792494086863781236/50064798708777621,-76374367048497097864,-76196863606569205097/60267456232905085:-3823667312793305504369462034586320308/50064798708777621 +qaddz:82198870205394916580/3448850359841959,92122854365946272671,-9499119469817233118/381994720733569:317717939429662268414058202075719069/3448850359841959 +qaddz:6940206776533138781/442725248202698,52972508975617224025,5617429131950608687/3366289783208936:23452267184149790024086119808558231/442725248202698 +qaddz:55599986966946799564/351405696052723,81353132501416252986,2145222144601366685/198829739629804:28587954152729636171116544308980442/351405696052723 +qaddz:94458271410973778847/361353862043500,54761990849557223858,-14653194369734462194/40666523642913:19788456886678404891313989807601847/361353862043500 +qaddz:-84180062330049702321/10106997571532,34216878817519062264,43542034768301689369/65407469845390:345829911113985714017035852166127/10106997571532 +qaddz:-24742695506396929785/17404029796744,41450961372253719353,=1:721413766826363551856884212256847/17404029796744 +qaddz:34674970696505269672/434120698329,90706045368333568168,4047354904123103766/5628094003009:39377371757997599606800990460944/434120698329 +qaddz:16761364796027525373/5854257789796,65993384007951488766,2006868112336026267/163736160281:386342282403565536077626910957109/5854257789796 +qaddz:13213233170358417707/28953389411,-84133659565012740924,38441120866807154861/611830462605:-2435954607945105525978669538057/28953389411 +qaddz:-64998396976150810447/657173799966,68741723486105419807,29966320909708913126/113185344833:45175259639510928939657721516115/657173799966 +qaddz:-75993621747015299032/49530111977,64950591439466856818,=1:3217010066893177413628750610154/49530111977 +qaddz:-20552895783534231165/77134912822,22987772657101552827,59095027841080059905/57879333453:1773159839856930680727938416629/77134912822 +qaddz:23575585295873866365/354640952,10572907047388947403,63974647548865514804/2902818571:3749585844269110717151714021/354640952 +qaddz:-3423087053862335915/3563944811,14776086984480635327,87473419453510292251/150143797:52661158531801310749782602282/3563944811 +qaddz:20175953575026075815/258856713,-707977887059042238,-88657359408605704674/445245889:-183264808544835335630767879/258856713 +qaddz:5641506401094150499/81605428,27796153257209226730,-31152461920419370958/183221007:2268316988949659433944840939/81605428 +qaddz:64291966735347840169/1472255,-37813006182818155116,58751143690989021203/3131508:-55670323125718207612466411/1472255 +qaddz:-40829665387689228845/40252968,65646528058726294873,48548143291840415697/19567973:2642467552429346280592204219/40252968 +qaddz:84643493739932974309/2975141,-85925500041436529739,29931128280261616739/3657301:-255640393475285778591243890/2975141 +qaddz:49533459783522540811/7076331,28143218875743097472,=1:199150781703665812199676043/7076331 +qaddz:45584750001594149227/984336,41115590339049176247,15975001635513275306/154305:40471601316728311544416219/984336 +qaddz:6418669402794912089/164220,73293587179171456413,-2508617797150506151/19201:12036279305232939367054949/164220 +qaddz:9535512106815022878/7681,28863162607332458363,16912585483283156773/19761:221707487499027427709081/7681 +qaddz:31040563813369589503/9684,-10330625966877227525,58520741913037533005/66343:-100010741299425701762597/9684 +qaddz:25406696906821168845/637,-96989536360380372540,89275628731812608081/8978:-61756927964655476139135/637 +qaddz:12530150187862657939/1219,40341242697614742420,=1:49188504998580233667919/1219 +qaddz:80569150582987599935/2,-15179790697208915754,82993038152425243161/355:50209569188569768427/2 +qaddz:36661516357580891535/19,-66347692158873159944,2979405734116612133/33:-1223944634661009147401/19 +qaddz:-77628572518590925665/92,9553267737685350880,69073840554559304981/47:801272059348461355295/92 +qaddz:94231430591775515069/83,1462408193524266778,-64327046129355071262/11:215611310654289657643/83 +qaddz:-6524291256793749081/5,46538712122784125243,=1:226169269357126877134/5 +qaddz:1240850785353652095/2,42205460810156144332,=1:85651772405665940759/2 Index: contrib/isl/imath/tests/qdiv.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qdiv.t @@ -0,0 +1,803 @@ +## Rational division tests +## Generated and verified in PLT Scheme (see imath-test.scm) + +qdiv:3/8827981081671378268,0,3/3926508931624275206:$MP_UNDEF +qdiv:-3/474373049650626538,-3/30777320180374251050,9/1226655408788630648:15388660090187125525/237186524825313269 +qdiv:1/1306590006879123716,=1,0:1 +qdiv:4/687201385528545547,8/9869825196514386591,-3/5975430289097816269:9869825196514386591/1374402771057091094 +qdiv:1/61423611473194332,1/15455670029280858,9/557484359857054244:2575945004880143/10237268578865722 +qdiv:-5/979333377476953559,1/99869524971840393,=1:-499347624859201965/979333377476953559 +qdiv:-7/30691138649930912,1/11634392715914207,3/17315717048169457:-81440749011399449/30691138649930912 +qdiv:3/20309884568576860,5/77811383120554786,-1/10721697997657271:116717074680832179/50774711421442150 +qdiv:9/5449666303362005,-5/2861847982830984,1/1826459823357042:-25756631845478856/27248331516810025 +qdiv:7/8847841671787170,2/1586192862907947,=1:3701116680118543/5898561114524780 +qdiv:8/289082769132563,=1,0:1 +qdiv:4/404037054778449,-3/231560563043393,7/849880896656765:-926242252173572/1212111164335347 +qdiv:1/48469516794680,-1/28088185111303,2/21754840126411:-28088185111303/48469516794680 +qdiv:8/50407054689999,=1,=1:1 +qdiv:-5/3164747219031,=1,1/3512888487599:1 +qdiv:5/5486024696808,3/3947571370957,4/5612399333251:19737856854785/16458074090424 +qdiv:0,1/41619742838,3/808926099199:0 +qdiv:-7/908640056265,1/159999865095,4/624715801203:-74666603711/60576003751 +qdiv:3/31854541511,2/14382200067,7/81824133981:43146600201/63709083022 +qdiv:-2/53726093607,2/89209379771,=2:-2175838531/1310392527 +qdiv:-1/6605722316,1/2540812616,9/2982865172:-635203154/1651430579 +qdiv:9/9991323937,=1,0:1 +qdiv:3/179688887,9/702152629,=1:702152629/539066661 +qdiv:3/404963252,-5/696394373,=2:-2089183119/2024816260 +qdiv:1/6333273,1/37207089,2/31767299:4134121/703697 +qdiv:3/90875674,=1,3/86752486:1 +qdiv:5/7636188,2/3416475,-8/1655405:5694125/5090792 +qdiv:-2/244339,=1,9/4733791:1 +qdiv:1/107213,-1/229854,=1:-7926/3697 +qdiv:-1/191856,2/941299,4/169459:-941299/383712 +qdiv:-1/11772,1/30223,=2:-30223/11772 +qdiv:-7/11960,6/95509,8/90341:-668563/71760 +qdiv:7/6422,4/4147,0:2233/1976 +qdiv:8/9005,1/5326,=2:42608/9005 +qdiv:1/665,-4/217,3/278:-31/380 +qdiv:3/140,1/227,1/100:681/140 +qdiv:-5/27,2/11,=2:-55/54 +qdiv:-7/26,1/5,-7/78:-35/26 +qdiv:1,7/2,8/9:2/7 +qdiv:1,1/4,-5/2:4 +qdiv:55/20700362000632320869,=1,69/80225473900126748965:1 +qdiv:14/3091014050673014971,-28/81380133061144194395,84/40859471274765910171:-81380133061144194395/6182028101346029942 +qdiv:1/314668662662881104,98/4475605721586782695,=1:4475605721586782695/30837528940962348192 +qdiv:3/1845567143863582553,11/786490044553073944,18/1855454337971843903:2359470133659221832/20301238582499408083 +qdiv:63/385333292496806971,=1,-1/32472264092720881:1 +qdiv:3/149509460292616220,=1,89/655644037836531409:1 +qdiv:59/60850170481238094,=1,31/16962204174702505:1 +qdiv:-21/11323738586240236,89/72739976921345915,-68/47763887738600551:-1527539515348264215/1007812734175381004 +qdiv:42/8561938043647535,-93/6809871846010066,17/9985561445050651:-95338205844140924/265420079353073585 +qdiv:74/824445644271491,=1,-10/462004715375339:1 +qdiv:-91/158705946232261,66/377268980338471,1/180572218716832:-34331477210800861/10474592451329226 +qdiv:13/294374634105374,17/137508734190942,=2:893806772241123/2502184389895679 +qdiv:60/52806122696123,=1,25/35647894318199:1 +qdiv:2/70084255188433,=1,=1:1 +qdiv:-11/522366309775,29/712593081308,89/4408829724580:-7838523894388/15148622983475 +qdiv:84/102632540711,61/53857049409,15/1404297586412:4523992150356/6260584983371 +qdiv:70/902531223717,92/698425518183,18/41071684813:8148297712135/13838812096994 +qdiv:9/100549718122,=1,-29/262025912406:1 +qdiv:5/78979980317,-29/15117078653,65/7124115824:-75585393265/2290419429193 +qdiv:31/30756865282,=1,-11/69831756369:1 +qdiv:43/1638160013,-9/6652991074,36/1999878215:-286078616182/14743440117 +qdiv:4/7372173731,11/274587688,=1:1098350752/81093911041 +qdiv:-75/216042979,-19/338590753,33/292120913:25394306475/4104816601 +qdiv:5/521918956,74/512764585,-35/161566463:2563822925/38622002744 +qdiv:18/42121601,28/26500085,65/84650518:238500765/589702414 +qdiv:41/41853940,11/85956056,53/26801053:881049574/115098335 +qdiv:96/7914185,0,=1:$MP_UNDEF +qdiv:-18/2408419,-29/2331289,39/1991248:41963202/69844151 +qdiv:-21/209413,=1,38/45091:1 +qdiv:73/941827,31/311506,-28/306503:22739938/29196637 +qdiv:-80/34347,=1,76/60617:1 +qdiv:-27/34016,44/3123,11/36759:-84321/1496704 +qdiv:45/4447,95/7813,=2:70317/84493 +qdiv:31/107,16/1959,-2/1335:60729/1712 +qdiv:7/6,=1,-72/455:1 +qdiv:82/415,5/846,4/63:69372/2075 +qdiv:95/28,-25/38,28/19:-361/70 +qdiv:89/43,=1,79/14:1 +qdiv:-49,8,-71/9:-49/8 +qdiv:-10,=1,1/4:1 +qdiv:808/45524274987585732633,-72/3230580501556764385,69/50585273432898431555:-326288630657233202885/409718474888271593697 +qdiv:319/66978137654707641182,=1,=1:1 +qdiv:-669/4359545352267142613,389/6178257053522267612,=1:-4133253968806397032428/1695863142031918476457 +qdiv:991/3477727818712482910,=1,529/5027018252141619996:1 +qdiv:3/23180871072888724,592/673665479785224825,-596/518946796253532009:2020996439355674475/13723075675150124608 +qdiv:179/793396855429515116,931/387517624716045840,-695/566279872123894778:17341413706043051340/184663118101219643249 +qdiv:221/3427690629405359,=1,598/80947651271959489:1 +qdiv:-724/52750058649448927,153/12336232443953527,67/55314453014305481:-8931432289422353548/8070758973365685831 +qdiv:575/8856014113088424,77/1046092009770736,=1:75187863202271650/85239135838476081 +qdiv:639/7628460189090482,=1,3/187674005095612:1 +qdiv:167/57172907255471,=1,458/490173841920009:1 +qdiv:-64/133181712979849,571/541047169178329,495/108993178847291:-34627018827413056/76046758111493779 +qdiv:-527/33346321735789,13/1536370494056,616/27148895576567:-809667250367512/433502182565257 +qdiv:-600/42483246609437,177/7709155575481,-274/29153462781241:-1541831115096200/2506511549956783 +qdiv:-891/3797928330707,-557/8539817631461,44/93582862751:7608977509631751/2115446080203799 +qdiv:30/101373302507,64/912736019917,127/1421964160402:13691040298755/3243945680224 +qdiv:95/811213545591,967/271585517890,-221/724077624393:25800624199550/784443498586497 +qdiv:482/121409952851,873/176693357788,-173/379909953056:85166198453816/105990888838923 +qdiv:211/83869812582,=1,425/21426470616:1 +qdiv:89/16604301838,-370/14168930881,=1:-1261034848409/6143591680060 +qdiv:357/8146855082,-657/9471809692,=1:-563572676674/892080631479 +qdiv:-21/2562596293,903/2881728821,156/164990119:-2881728821/110191640599 +qdiv:-579/609663644,=1,157/25380668:1 +qdiv:-39/383217583,929/665052497,817/218315394:-25937047383/356009134607 +qdiv:937/74356752,422/14604731,959/48789395:13684632947/31378549344 +qdiv:81/64759993,-169/12649693,-554/43474193:-1024625133/10944438817 +qdiv:-277/389415,=1,=2:1 +qdiv:251/2232087,-151/728262,=1:-60931254/112348379 +qdiv:-61/65749,-207/485432,=1:29611352/13610043 +qdiv:363/228754,227/70325,569/103195:25527975/51927158 +qdiv:159/83267,-157/2354,327/82759:-374286/13072919 +qdiv:41/1099,471/99860,201/1723:4094260/517629 +qdiv:14/23,27/70,=1:980/621 +qdiv:775/8954,916/3399,-956/2393:239475/745624 +qdiv:-16/17,-337/37,753/524:592/5729 +qdiv:680/89,955/296,-767/913:40256/16999 +qdiv:671/29,69/71,=1:47641/2001 +qdiv:45/7,227/47,-588/17:2115/1589 +qdiv:309/4,=1,477/7:1 +qdiv:995/8,-542/3,=2:-2985/4336 +qdiv:709/12248686694307459921,-359/3012348473905143856,3209/3205529400054125663:-305107866856963856272/628182646179482587377 +qdiv:7039/48532814476573486698,1842/19665238977050464607,-686/59623200188183875815:138423617159458220368673/89397444265848362497716 +qdiv:451/329309233590151305,=1,=2:1 +qdiv:809/682008587763566662,8909/1007199215258353342,2888/6648659691864956039:407412082572003926839/3038007254192807695879 +qdiv:7143/477997774542113905,8817/680997252822749635,-1905/134302220820939382:324290891794193376187/280967091875854553359 +qdiv:347/219003978754231945,-8579/862605866526757805,1879/749017786570395462:-59864847136956991667/375767026746511171231 +qdiv:2252/19919238262742963,3008/30104309448888197,8998/18293466522564645:16948726219724054911/14979267173582708176 +qdiv:3132/7632328378838467,-7891/65522084848474051,-6375/16422802718592713:-205215169745420727732/60226703237414343097 +qdiv:3091/6666475760056275,-4948/972687207365139,-1089/869334750550498:-1002192052655214883/10995240686919482900 +qdiv:-1181/1328394658282401,-4449/5267675168926367,2101/2626633098162958:6221124374502039427/5910027834698402049 +qdiv:7323/118964685899438,-259/116805460794557,9535/306412793639648:-855366389398540911/30811853647954442 +qdiv:2433/121526971245398,360/82851643972451,-3062/418315498791959:67192683261657761/14583236549447760 +qdiv:6067/57796241878231,964/16961015496389,-6693/83462416525900:102902481016592063/55715577170614684 +qdiv:4159/18938105171021,-3304/15702563734975,-497/5886368665864:-65306962573761025/62571499485053384 +qdiv:-2339/6560171909556,-3315/879777839282,1570/7171072558101:1028900183040299/10873484940089070 +qdiv:1225/584214253087,-6283/3835506609411,1613/7130518143781:-4698495596528475/3670618152145621 +qdiv:608/483278255319,2413/247017404385,-9588/346021249721:2634852313440/20458779475171 +qdiv:5057/839656743164,-8443/6430957362,3191/797476829669:-16260675689817/3544610941266826 +qdiv:8/2915377743,-2073/42761112191,3028/25982265273:-342088897528/6043578061239 +qdiv:-3080/48285456271,7722/56966382901,4950/16693686061:-7975293606140/16948195151121 +qdiv:2506/7829482533,3738/894286585,1315/9318157842:160077298715/2090471836311 +qdiv:395/539727584,3101/2435581364,8543/4140459726:240513659695/418423809496 +qdiv:-2933/85901348,1075/31492019,5089/657510451:-7105083979/7103380700 +qdiv:-109/7944981,1560/35171599,8205/374231336:-3833704291/12394170360 +qdiv:351/84445888,=1,-972/45463937:1 +qdiv:1896/15952037,1648/24133709,-8841/97126097:5719689033/3286119622 +qdiv:-7849/786920,8468/8925921,-3114/6765635:-70059553929/6663638560 +qdiv:245/566264,=1,8221/9131472:1 +qdiv:79/17927,=1,=2:1 +qdiv:1970/222369,-9680/117859,-333/53716:-3316889/30750456 +qdiv:1255/31098,5871/80299,581/4346:100775245/182576358 +qdiv:2551/88863,310/16021,937/5727:40869571/27547530 +qdiv:8096/4615,=1,359/1549:1 +qdiv:4380/6089,-1293/32,=2:-46720/2624359 +qdiv:4841/137,=1,63/127:1 +qdiv:-7195/394,1026/73,2871/383:-525235/404244 +qdiv:-2123/25,=1,=1:1 +qdiv:4877/72,=1,=2:1 +qdiv:2059/8,=1,1797/2:1 +qdiv:4309/5,-928/7,9812/5:-30163/4640 +qdiv:1276/48998512603828859815,=1,=1:1 +qdiv:-87759/12642453185607565556,61169/76861786640093390298,=2:-3372656766873977919581091/386663109455214588747482 +qdiv:-73621/3641518581487027232,=1,=2:1 +qdiv:30239/2864992309604629419,69203/360791977688831821,48533/7318731980981091051:10909988613332585435219/198266062801569169683057 +qdiv:3258/375353145849458519,=1,=1:1 +qdiv:7705/911649391027518118,-4527/523603872108693505,=2:-4034367834597483456025/4127036793181574520186 +qdiv:80183/27684870128356298,=1,31447/10044082204150725:1 +qdiv:55812/2242876918063201,273/5987187297553853,=2:111385632483691881212/204101799543751291 +qdiv:4768/1013825352338725,547/51853159734450,13214/1209874359544049:9889434624554304/22182498709171303 +qdiv:6676/2650290894306779,=1,41501/3206334096847699:1 +qdiv:28681/68017529704052,=1,-17941/468955454103104:1 +qdiv:-19043/55558808816913,76696/93211283557235,37794/88565241121255:-1775022472780426105/4261138401021959448 +qdiv:58963/41164814718796,37371/41375121127588,-43794/48988525394521:609900316761492811/384592572714031329 +qdiv:12779/2181401551509,=1,=2:1 +qdiv:9529/1314170728394,48148/4767551174553,88486/9446535741037:45429995142315537/63274692230714312 +qdiv:45171/1935400244048,=1,=2:1 +qdiv:-8055/796756979512,-40221/581590215415,13256/244193996163:520523242796425/3560706941439128 +qdiv:73154/947174782947,39139/519633159803,=2:38013244172228662/37071473829762633 +qdiv:-42235/18400469972,3745/6423311093,-18889/85101890714:-54257708802571/13781952009028 +qdiv:63068/11796773127,-31/59107640,90784/7564528991:-219282390560/21511762761 +qdiv:16431/9543805406,42548/5364916925,-5126/2217017905:88150949994675/406069832414488 +qdiv:57923/8084487099,72400/4961088589,979/745380355:287361134340647/585316865967600 +qdiv:51393/552384269,8157/339410251,69420/934416791:5814437009881/1501932827411 +qdiv:16234/493942565,93863/203157564,58764/900515657:3298059893976/46362930978595 +qdiv:-43437/39051397,12197/12032365,=2:-522649838505/476309889209 +qdiv:61845/28993019,=1,-30098/34003047:1 +qdiv:-21977/2530949,7118/5886975,89761/8051121:-129378049575/18015294982 +qdiv:-67667/570818,24964/4493829,77381/5174833:-304083926943/14249900552 +qdiv:80188/494389,=1,88457/134084:1 +qdiv:15689/433436,13517/141762,7082/140371:1112052009/2929377206 +qdiv:10873/14999,=1,95341/35511:1 +qdiv:66107/92401,-30477/19660,82518/86557:-1299663620/2816105277 +qdiv:91501/4959,49360/2327,1601/402:212922827/244776240 +qdiv:-1728/335,-29231/3035,23678/2657:1048896/1958477 +qdiv:-31582/403,6626/71,-96811/384:-1121161/1335139 +qdiv:1149/28,16127/136,1326/875:39066/112889 +qdiv:13158/11,-59582/45,-5678/35:-296055/327701 +qdiv:83796/5,15431,=2:83796/77155 +qdiv:-50168,82697/4,27476/3:-200672/82697 +qdiv:43313/8,-23369/3,37118/9:-129939/186952 +qdiv:343272/40939026292046552549,=1,-149188/1630670088822528293:1 +qdiv:7090/17394546172873749111,806868/84886259115708426355,977287/27695656418221378384:300921788565186371428475/7017551340707148098847174 +qdiv:273653/494417711699854970,520824/6619891999027460951,385411/1812431346892436901:1811553305209861771624003/257504610278365264895280 +qdiv:30655/71199858589215198,=1,684829/6532276093969322272:1 +qdiv:181927/723554427646445064,996115/645768630995539314,80483/188550933731713724:19580458288520913463013/120123903115839770821060 +qdiv:72786/190019706414733673,37703/744879257576358133,926598/93783057457592441:54216781641952803068538/7164312990954703673119 +qdiv:6030/34221301230292789,254491/329459713137161,=2:1986642070217080830/8709013171398442165399 +qdiv:-374458/43126191217786237,=1,896258/14496576313551015:1 +qdiv:564923/3144080096402171,794248/4739399554899871,-434642/3276748536360521:2677395814752699824933/2497179328407231512408 +qdiv:199922/1178376836454579,=1,83513/1610790739884089:1 +qdiv:-268911/54100968009644,28397/60052294389392,81027/47026501432603:-4037180634136448028/384076297142465167 +qdiv:893838/55403243375203,986288/2293797524067,=2:1025141695658499573/27321777051021108232 +qdiv:18303/82870490401642,913885/30405433858676,=2:278255327957673414/37867049060352299585 +qdiv:5047/32151410465425,=1,176188/13701013860219:1 +qdiv:187835/1220654728179,405949/2196086232716,=2:412501857522209860/495523566249536871 +qdiv:378036/6357059248081,114851/4050423226594,862111/3515447797224:1531205794888689384/730114611701350931 +qdiv:-294719/147652614747,104431/366828548330,676351/724118840846:-108111342935269270/15419510210643957 +qdiv:-331898/628206486043,=1,-177396/338495728537:1 +qdiv:177685/26330782667,=1,-420269/95383974662:1 +qdiv:-318696/28047340105,197485/16144733252,-240020/96906119801:-5145261908479392/5538928960635925 +qdiv:-576953/5244331985,=1,2965/50930228:1 +qdiv:370624/2877285795,5441/59491598,666008/8960730819:22049014017152/15655312010595 +qdiv:-902401/154074924,-583513/621607888,790132/568175569:140234894934772/22476180282003 +qdiv:220793/55445126,-127133/589508175,=1:-130159278482775/7048905203758 +qdiv:992605/96130864,-338301/47600647,-268171/7895145:-47248640215435/32521167422064 +qdiv:200098/69076309,-713974/36753541,226577/9980229:-3677155023509/24659344320983 +qdiv:-24613/302985,301411/2633942,57255/1357249:-64829214446/91323011835 +qdiv:-224679/8931277,-609222/9892805,231393/5325206:740901844865/1813710145498 +qdiv:374358/364639,-31343/26526,-293019/312248:-9930220308/11428880177 +qdiv:-390237/256456,390385/933736,-349530/445567:-45547291929/12514571945 +qdiv:-871638/36751,61626/4051,=2:-588500923/377469521 +qdiv:-87914/16631,783263/70173,-431150/88143:-6169189122/13026446953 +qdiv:-128/2205,-668595/5258,=2:673024/1474251975 +qdiv:405269/1719,=1,=2:1 +qdiv:123781/830,=1,356120/629:1 +qdiv:-130038/131,640786/467,214577/394:-30363873/41971483 +qdiv:940928/95,=1,934701/79:1 +qdiv:-468415/11,=1,79087/4:1 +qdiv:170049,838068,204415/2:5153/25396 +qdiv:937045/9,=1,=1:1 +qdiv:-895965/11817608522407410412,1662758/31138269586404741097,1787239/8265484069296678539:-27898799709983123856973605/19649823111501100921836296 +qdiv:9485555/29939758418824763622,=1,=1:1 +qdiv:3256189/100080959665237165,9746921/1570372596135540846,7102111/7910145060985949414:5113429973437990611795894/975481207461253093518965 +qdiv:8443036/2594663966536136217,6210896/4467012950800475059,=2:9428787789018659935059781/4028797012775855571405108 +qdiv:1180903/105749612753261488,=1,5874507/437668716132551285:1 +qdiv:-96672/840052608584629,2690215/425934540850990364,4714612/192754505384388189:-41175943933146940468608/2259922128403497705235 +qdiv:2821007/83364576953405163,=1,582088/4860812540794867:1 +qdiv:-797070/17849830777864213,=1,9498931/55689637536119864:1 +qdiv:7021411/6724756422420817,852445/1318535168793131,5879850/6896277416986789:9257977338050946727841/5732484988510513347565 +qdiv:2862688/9366273253135011,-2712503/6212570364248993,6269770/1992362624741777:-17784650630891221273184/25406044297948476742533 +qdiv:1770043/227457000705496,1050787/653965284988262,4665931/732005792365452:578773337468239117633/119504429700163012676 +qdiv:-6397271/15882716560575,4689255/783371764982764,2301170/95355180815573:-5011441474343051637044/74478108045259121625 +qdiv:1734439/13086156486143,-3265601/63043422188314,8065931/40472250566091:-109344970136877145846/42734165707305066943 +qdiv:2779319/3703679337417,-2792251/56401900482152,=1:-8250467034008116552/544294859662208193 +qdiv:8906654/1989823550291,5015729/711711398937,350071/21519066915:6338967178187826798/9980415686077527139 +qdiv:1342773/5863720123828,8311991/8825950349708,1394645/2412447722267:2962811957232115071/12184797223944305387 +qdiv:4499434/306371176997,=1,3752751/959913819173:1 +qdiv:-3583690/490293948611,272623/13035328183,8190059/637847763742:-46714575256135270/133665407152176653 +qdiv:-1213471/56665475600,3817747/17865032159,-816041/17280339528:-21678698439013889/216334449475473200 +qdiv:-2100116/20836208549,4331/50448644,=2:-105948004442704/90241619225719 +qdiv:36713/12904114,883015/6814675799,7851017/3608793001:250187192608687/11394526223710 +qdiv:5022803/2809898795,8967230/3296219033,=1:16556258847609499/25197008771487850 +qdiv:781841/201099058,85007/147631535,2241175/183484024:115424386955935/17094827623406 +qdiv:3699468/393449053,829829/358610807,1152449/409680870:1326669204950676/326495434201937 +qdiv:-3463205/9915829,9661223/82242321,503777/9897306:-40688859614115/13685576456981 +qdiv:-1589921/41367712,9942811/90188714,3708164/23097593:-71696465175797/205655670959216 +qdiv:-5779163/4536533,=1,=2:1 +qdiv:2210759/3222751,5205241/5080834,=2:11232499493006/16775195637991 +qdiv:2183333/139811,5752077/430948,1225681/247001:134414712812/114886233921 +qdiv:-8070429/171845,128419/37928,290524/56769:-306095231112/22068163055 +qdiv:-3211584/2153,3758472/791,=2:-105848456/337166259 +qdiv:-6466794/31769,-3915902/42711,-7456369/21580:138101619267/62202145319 +qdiv:3729205/1518,-260137/3841,2483611/6182:-622777235/17169042 +qdiv:6860802/4649,=1,5289160/3861:1 +qdiv:-83438/7,571053/190,-1052132/281:-15853220/3997371 +qdiv:8063462/909,2183491/660,8119557/104:1773961640/661597773 +qdiv:3049687/87,-1582395/16,-1200911/16:-1574032/4440915 +qdiv:352110/19,=1,=1:1 +qdiv:2962406/3,-3345297/2,=1:-5924812/10035891 +qdiv:7149844,-6647775/8,3754198:-57198752/6647775 +qdiv:86792351/49133761328196981964,83681596/94733888541192208399,45540422/93887740620391683883:8222176905862032109831156049/4111591565426603253130734544 +qdiv:37275015/45938947789509093778,=1,-31078003/24048804548446901925:1 +qdiv:18714228/278784499974669995,28535131/7442575198888787547,-18894836/167878993350595593:139282049179150116798118716/7955152227546704989094345 +qdiv:-24811360/2159236580309869299,44687068/2174509444305355231,-2185967/982469534126187980:-13488134161515029641056040/24122487973098647608881333 +qdiv:38561291/399479362141639464,73235730/642777863686427933,-44021955/503809548217143929:24786344249970680274941503/29256162706377329542848720 +qdiv:-9532213/318095670778469600,28369139/87482667379251144,-92704577/641723560262485864:-104237927408396710637709/1128012537451580286209300 +qdiv:12970933/24974407644034125,=1,7781491/55007097983499252:1 +qdiv:-73795622/62522679678898791,-40287452/37729183605206197,10065628/1450024137592451:1392124285849196872934767/1259439728237505227635266 +qdiv:45877577/2870321629840685,62804508/3060757957189363,-24942819/194614932107914:140420158859317704613451/180269137763902339807980 +qdiv:27765340/1722659366920429,-49740100/4392314052861681,32854898/4914960185867565:-6097704653224127296827/4284262458827941525145 +qdiv:31840878/650549338557053,=1,82034659/746923000065290:1 +qdiv:-3799624/89718613403123,=1,68910040/992826933898731:1 +qdiv:31394779/66096039231279,-10511385/62803293159157,=1:-1971695509203945841303/694760915335077611415 +qdiv:86839209/60474989629672,50531989/58732772835419,-863777/980850237675:5100307535404473143571/3055921510741699577608 +qdiv:27323066/1973122068799,-78173848/609142108427,75125805/9127401261224:-489518530350884623/4536663079168781428 +qdiv:36867962/1416533338363,635443/97562183222,98853338/2812167235847:3596918863665733564/900126194129399809 +qdiv:47352329/413811029048,=1,10407191/442238417413:1 +qdiv:68800501/774974238286,-2280234/152962980017,-48441105/249265282913:-956720878147508047/160647509751258084 +qdiv:65729629/84892894017,=1,-25288745/76133875626:1 +qdiv:76580386/41315133127,=1,-96951946/56344054531:1 +qdiv:16421575/8944123642,=1,956371/8341427945:1 +qdiv:3853661/95830379,49444059/3207768145,-6661391/2303483651:1765950142489835/676891844752623 +qdiv:55380577/150811366,32344153/137899626,37704187/990478015:3818480427982101/2438932948021499 +qdiv:-1819205/194369638,=1,1770897/587958251:1 +qdiv:27198033/94223324,1701651/36639143,-5208757/47970432:332170873468573/53445071169308 +qdiv:26144007/33885110,94294868/78704229,77077115/11515724:2057643913905603/3195191974615480 +qdiv:7734047/454358,41930099/1017254,26486906/1535151:3933745123469/9525637960721 +qdiv:95593715/5378931,77945657/2828365,15099226/479451:270373917725975/419264310752667 +qdiv:64278733/781984,-55137203/906657,=2:-58278763225581/43116410550752 +qdiv:2755454/91023,-44515162/293371,53356021/607819:-404185147717/2025951795363 +qdiv:-851882/63,-75090427/4230,-20131985/3239:400384540/525632989 +qdiv:-4882658/14371,=1,60992107/31701:1 +qdiv:-11263333/2311,69417077/9812,11529690/407:-110515823396/160422864947 +qdiv:-23572979/329,15626746/7287,-22762379/5404:-24539471139/734457062 +qdiv:45146947/609,5802442/59,=1:2663669873/3533687178 +qdiv:48034468/31,50219011/517,=1:24833819956/1556789341 +qdiv:6524645/17,-58706702/87,=1:-567644115/998013934 +qdiv:334487/34,84187235/74,=1:12376019/1431182995 +qdiv:21060395,7521975/2,89723525/8:8424158/1504395 +qdiv:49115243,-71749933/4,85184626/9:-196460972/71749933 +qdiv:309597727/33672758861109919384,-177164051/55601420918529748854,895889621/23670804105482899489:-8607036767173531213539627429/2982801184090189837176432292 +qdiv:48916804/2660589522598316323,313914094/34752378183509684779,904253494/34791426109034240319:849987636068309641218063158/417598274746171497229978181 +qdiv:242729/247715169151474017,221774365/420531110603394201,93370673/386036618278885054:11341677327294585668281/6104097148826193214908245 +qdiv:16768055/4024792916152716086,-311564292/4024075770824349991,76507261/4630876961864888130:-268828381869920701148755/4995943248477037255823112 +qdiv:23219936/109884862578864265,380304636/829661649046413301,-237169652/48494008574580541:4816172598128044469692184/10447430666241248898558135 +qdiv:516810898/660599886600041083,74020472/119618011649135401,=2:30909946008682063757200049/24448957704640758091525588 +qdiv:189691986/87372198519829129,649602410/62948713754669759,162659075/29230871469718464:5970433264134411679425687/28378595362739717493300445 +qdiv:14774898/4079300020169327,819672300/24627820907020229,=1:60645590310581894568607/557281538320373108590350 +qdiv:71574531/9911187558077269,287480027/3692301867467201,=1:264274774474389069457731/2849268466798117360206263 +qdiv:719634375/1976359498657996,6512606/19580323447829,2020281/463180107697268:14090673826676267521875/12871250729117056697576 +qdiv:663048253/304000499307584,=1,26624410/650833137359949:1 +qdiv:248932257/31572538733168,-3297144/159684389656921,453206117/278240003582858:-281919117198331916317/738292245736400512 +qdiv:693286598/13147402069069,20606065/4637179960822,588199091/60290317447874:3214894719352057663556/270916221616370303485 +qdiv:1279088/487824767579,431725597/47207595894190,=2:60382669417107698720/210606439014430019663 +qdiv:78549245/8831126280331,541356457/4279964344475,=2:336187967885431171375/4780787234439578947267 +qdiv:110033578/47682346357,-152259539/1111037317327,-766205582/7952747013871:-122251411317011206006/7260092074755149423 +qdiv:47060001/489637479337,140861141/250864895102,=1:11805702214365015102/68970894015773743517 +qdiv:109248031/51582112839,562377671/23862568900,-27370055/52346954108:2606938666926835900/29008628483656017969 +qdiv:-342511511/53452279775,=1,547211519/16341758885:1 +qdiv:340877767/26494707436,-719326026/7059828707,32400255/14657164768:-2406538645044657269/19058332609970529336 +qdiv:-932440839/8204417554,-57679385/756117222,189301605/4430094677:352517288432014629/236612879398962145 +qdiv:-980924395/4737725778,96878060/5344143499,-563492138/260341141:-1048440145709951621/91796336436926136 +qdiv:-748092457/68521924,=1,=2:1 +qdiv:-72010946/931437,38577842/94683927,-194004572/356767967:-87413835311089/460677300243 +qdiv:-99158610/59323363,528264721/50347358,=1:-4992374036452380/31338439803976723 +qdiv:-273698543/89114428,65593727/66452645,-456099010/45664741:-18187992114996235/5845347461993156 +qdiv:-434183749/4880425,227158395/799133,696633020/1207589:-346970561889617/1108629509917875 +qdiv:-950455305/243592,-458911412/6191101,201783811/2324399:5884364789240805/111787148671904 +qdiv:699903049/451554,-235876093/487743,-158455564/246001:-113790937609469/35503597766174 +qdiv:220813028/437657,=1,735013805/653689:1 +qdiv:7685509/196,754004453/40926,-707049919/17530:157268570667/73892436394 +qdiv:222143479/26751,391098157/28855,193987153/3253:6409950086545/10462266797907 +qdiv:129843395/733,174902609/2529,586864566/2891:328373945955/128203612397 +qdiv:318016269/2750,486693651/2170,=1:23003176791/44613584675 +qdiv:199207703/783,697191979/15,628918929/959:996038515/181967106519 +qdiv:-822112671/383,700601486/287,=1:-235946336577/268330369138 +qdiv:702853697/90,57317887/96,6934229/20:11245659152/859768305 +qdiv:236859557/10,-12598119,-844214996/3:-236859557/125981190 +qdiv:666692788/3,837163259/5,-44955282/5:3333463940/2511489777 +qdiv:-267890720/3,994822169/2,306713231/6:-535781440/2984466507 +qdiv:8971865945/84652096998217220652,-1766409152/949158554479936975,51683336/978028041559081475:-8515723311343973731748816375/149530238873642626243696207104 +qdiv:-4783142107/20353559370672239325,1489328761/30130844818064603669,9037981957/29934040642660151619:-144120112568767560055460590583/30313141359463225930997726325 +qdiv:-5011919027/9589021627165778205,6908330432/8223014240433381075,-223144684/369584710951584897:-2747538768728001022382280935/4416275328003700232170922304 +qdiv:3264032212/4288823609663243543,127527384/8323211793086562335,3176342735/6939281510473238183:399518108822541446555675515/8043271402614567205789434 +qdiv:-4588453891/349300703246919169,-4621109572/563134654578914825,2946587906/489244399145625531:2583917396959562695328834075/1614156823280669651376185668 +qdiv:-2433362101/159409638288916225,85838756/19437108683105947,7818956051/899163746350160639:-47297523622488030397514647/13683525045130537342216100 +qdiv:4804263237/27326781078392456,875410347/26595379067270065,-7249537521/50005537812647291:42590400642321641076700135/7974048968742858036380744 +qdiv:-2132504576/319379206557339,3197623346/47180453249202543,=1:-5589585136204360627685376/56736355950816859668683 +qdiv:-17110179/337414992862541,=1,5637859401/8456872970863411:1 +qdiv:929796549/785511765727417,-8659917002/9734288265288811,=2:-74800889554022586414159/56218733018957846081354 +qdiv:2024811003/923122484568110,-2213327573/685808753095771,2505827052/382175752770445:-1388633109222027433568313/2043172448350864859497030 +qdiv:4321265761/608661263330203,-1955439753/18999520283666,1985116091/422495636527147:-82101976477230893359826/1190200430427080111759859 +qdiv:5403084171/20759093453216,1272181959/3497884340798,4111729721/4478504823638:3149893918959073884743/4401557362729400955024 +qdiv:4169845699/5710332227959,9148517943/2081193666800,=1:8678256460292019093200/52241076847974077768337 +qdiv:4493194533/2604354754064,-3502324668/5226679118353,4603317541/1537717259387:-1118308859063283788769/434347423780067640512 +qdiv:6987915227/4137866098763,801022943/1354532951118,=1:9465361434590718873786/3314525680171066919509 +qdiv:5294179409/20297663855,-1916636849/2091902413,-1119938671/198399693697:-11074906680542013917/38903250493108392895 +qdiv:1295990518/61239499731,=1,539185569/58234040869:1 +qdiv:2091734371/22379348546,3771243501/14969120476,-1020067815/19323989012:15655711901644540298/42198986380358149773 +qdiv:4013255624/2622410663,2585175687/49776501221,6260772357/9422047988:199765823468221116904/6779392287317150481 +qdiv:27739307/489082696,=1,-1635872773/284162212:1 +qdiv:1004677799/8383863362,3327131707/4220463949,234611693/146976367:4240206431040168251/27894217618865818934 +qdiv:8434446327/446741110,305497651/332988425,9725313826/929456845:561714599634952995/27295671942026522 +qdiv:344714653/17732695,=1,-3209292581/367817366:1 +qdiv:-6843554898/34497445,=1,-2081199716/16214703:1 +qdiv:5803347322/79453889,1102662623/8094456,=2:46974939550646832/87610833652290847 +qdiv:8712618248/2572733,=1,=1:1 +qdiv:-4833921086/2762331,-7642479217/5423409,-1583615993/2873706:8738777041034058/7037019085991609 +qdiv:8518925689/40191,=1,6550456120/871279:1 +qdiv:876819073/100630,-902089199/140111,9433117031/258480:-122851997137103/90777236095370 +qdiv:-110986687/426,3857966128/39887,1189959236/13549:-4426925984369/1643493570528 +qdiv:-7975883597/55733,-1666217426/13007,9979667239/98463:103742317946179/92863295803258 +qdiv:9307983176/5287,=1,-4477921884/4391:1 +qdiv:-6231410261/9293,=1,=1:1 +qdiv:4528426169/109,644958250/991,-966669111/247:4487670333479/70300449250 +qdiv:4728746197/670,-3092342009/975,5344313590/51:-922105508415/414373829206 +qdiv:-9298448594,6025771347/65,230306877/25:-604399158610/6025771347 +qdiv:8659053685/17,-5401196332/59,5062434592/49:-510884167415/91820337644 +qdiv:-9777515257/3,4806469000/3,2254605905/4:-9777515257/4806469000 +qdiv:51777408,125752274,147067434:25888704/62876137 +qdiv:-50627047179/45073388301558717898,-39488625025/47733211534284913713,32711658675/27270403149344569493:2416591552351429302575995065627/1779886129246473834093878197450 +qdiv:-91204883678/4376981341885366059,=1,92252001911/64145968577542202922:1 +qdiv:-6468661773/3340956703659991393,51917096173/4290285077565474605,-4184909817/2082344794208597768:-27752403076520125481965774665/173452770493744834242733238989 +qdiv:79042137253/2565404331216876095,46463876503/9217979332756333154,-71237527399/9032839782059615122:728608787615043443963462385962/119198630025922238587532895785 +qdiv:-71497371020/911351878610216589,35308340296/356473827680782925,64081379374/293532001774391069:-6371735379153120728201458375/8044580564842102716669092586 +qdiv:-59711844557/491536178108971083,-80079287644/210346837810811533,=1:12560197682415668432518875881/39361866994220711332435198452 +qdiv:82691530516/13829489779198215,-54368150702/41857898377267367,-23138364722/2016009305137557:-1730646840499715679485735686/375941892223608628924698465 +qdiv:-2532396359/43747227235758060,281496679/79780911611953,49395555307/46061856818743718:-202036890083810598079127/12314699182324243937482740 +qdiv:39329031241/771013386869700,23150277229/3870964064839779,42048700955/3103108290222419:50747088879624005983511913/5949724551101261166687100 +qdiv:36630047839/8265775107927151,-17088940048/166471968138409,7720288135/2420444961206493:-62864702647035107663383/1456219951233173329798384 +qdiv:3233508452/61288804249597,1009629177/396153232886351,-1862094182/304377258983311:1280964826825140313938652/61878964993834721691669 +qdiv:39400418349/280335370062674,=1,528864863/5327344259528:1 +qdiv:-30978168489/22888879909274,18822952031/21160004002172,1575282546/5389019145925:-327749084603599268979054/215418144287792067017747 +qdiv:95503923490/49551349663127,85560857352/20589539380841,30851800131/2025645536851:983190896861090417927545/2119827980062941250629852 +qdiv:37807143/340515189301,=1,-2818312259/743193551514:1 +qdiv:-83826099190/4358399428931,4772431013/6348630185134,-853009636/374419764711:-532180903619670747441460/20800160601671793837103 +qdiv:58301964846/768140939347,8148193743/65129075956,8259717541/561157474998:1265717698946391947592/2086320398576455968607 +qdiv:19788341553/40137672403,17083972289/174789239733,=1:3458789175625802525349/685710883077812040467 +qdiv:-10973954453/10832242662,34763618831/810622373,6976849061/881334394:-8895732999884776969/376567954986664768122 +qdiv:80042291705/98079883084,86963751533/70819982692,25719162328/28990442539:1417148428294028792465/2132348645725666441943 +qdiv:-62862242431/5180961911,-26432627160/2693765641,79398909214/5912386617:169336148776840113271/136946434523624102760 +qdiv:7346613183/88310017,50873662935/5009376481,=1:12267317097974916341/1497551346214039965 +qdiv:-8864563721/49900586,47950826631/18964907,-17937545168/328567993:-168115626564338947/2392774348071305766 +qdiv:24094021571/450614802,84569474563/64046670,-12933174970/817622387:257190308088453095/6351376172575046921 +qdiv:3494981654/23432223,-89282047405/11919821,48429893805/30458672:-41659555713963934/2092076844690531315 +qdiv:33495688780/3147047,=1,37167537331/76683481:1 +qdiv:5470526576/1258187,=1,17782212381/952621:1 +qdiv:1485833227/309723,-22316021107/3171654,83073086566/5001853:-1570849632582486/2303928335107787 +qdiv:-9654830/13783,68644421742/595891,6668182574/31547:-16070464535/2642810237067 +qdiv:-18629056304/310987,33795740865/249491,34685999906/394187:-4647781886341264/10510036064383755 +qdiv:58031794382/46405,-8325673530/923,7246189925/58537:-26781673107293/193176440079825 +qdiv:42752677499/79662,68629448895/67033,10722691188/21005:409405747255781/781022736839070 +qdiv:-14745678708/1589,-18308273147/872,-7354773097/844:12858231833376/29091846030583 +qdiv:36286205520/4483,16203338783/1827,78196029593/7698:66294897485040/72639567764189 +qdiv:5973900741/238,=1,-62903827999/275:1 +qdiv:15604013335/563,-83645760588/407,=1:-6350833427345/47092563211044 +qdiv:47070101778/5,9828239935/11,=1:517771119558/49141199675 +qdiv:14795131351/62,84397328746/93,29769038089/50:44385394053/168794657492 +qdiv:4462854035,72133672643/6,79206774199/5:26777124210/72133672643 +qdiv:77933302681,-41096015935/8,22243311204/5:-47958955496/3161231995 +qdiv:569473516504/74989462888441761347,16884022641/33541962454158520316,-961841214350/8067206202574290521:19101259309214790462605845295264/1266123789244879955792666657427 +qdiv:239854097519/52524719736478674886,106866734141/32499507073759497471,89805916001/5326340692191230017:7795139938988940832361667874449/5613145259908802128558135482926 +qdiv:-677983905959/5228931513669930017,90555544897/909803638402840864,=1:-616832224420067701296618308576/473508742449475516893291473249 +qdiv:200250717/41414149596190990,-189493590347/1507829061340539502,775951232712/5167695853317665663:-150971925323440008221161467/3923857949074995465316186765 +qdiv:-630502736561/79958533096752240,-705956121098/327213288587355799,256428699470/80995134791334257:206308873893452061172472667239/56447215873669265291942759520 +qdiv:660718319453/697816356986416684,128827317994/37354325475235679,331980136084/301012355599229933:24680687152298103397985363587/89897809722903725688255011896 +qdiv:545833880297/25947106528604223,8458087019/90279863958356590,720827317409/51875766695198665:49277808457075055538901107230/219462884910197530744881237 +qdiv:44847037444/5916668180191961,258200335112/6285554319853929,953656869133/47501466102410949:70472122484696276618379369/381921426718017882672108658 +qdiv:-160898376199/4244945324446856,927280098477/5862228193719167,=1:-943222997277410780922906233/3936253318482561347233038312 +qdiv:176768268366/3002473163637239,48101070360/1068329140204261,=2:31474448693140808084117921/24070362149687771109189340 +qdiv:951576739240/465019676388521,207183722946/207969918137525,-162267142743/832527824784031:98949668280657886691990500/48172253898658956359351433 +qdiv:50497726912/167462116853589,561688826809/565768492770317,-23899967761/571729295367736:28570022843329314205671104/94061599950444071831067501 +qdiv:769692991889/77684301794679,=1,667256125514/92489368710909:1 +qdiv:289207008385/46369327373772,-371984422048/18704673822691,=1:-5409522759077686040264035/17248667443887083093725056 +qdiv:584171767751/2720004210686,=1,428825886595/4631070272424:1 +qdiv:820600220165/1539493346318,780404246878/3986857306711,59567377973/1411194292060:3271615983653485532027315/1201427145506990824295204 +qdiv:-398300561149/618514875987,-626035084114/392429382255,852340023938/456860499943:52101614387840641003665/129070670804760607923506 +qdiv:91238813259/372867824401,672788008343/125652609006,163390268350/18360751511:1042217720782234146414/22805545541266931543413 +qdiv:-448368178212/59572694995,=1,525642488427/25427754721:1 +qdiv:180771359707/24203640124,257130797261/27852202428,-904507763905/73268882369:1258720125936041692149/1555875320425612225091 +qdiv:-305344025090/2609111987,165179438933/5095448550,471583662827/9986485010:-1555864769896004119500/430971654126024789871 +qdiv:18656226690/3750570061,49208551961/1566294696,=2:29221148911920636240/184560121730089439621 +qdiv:-507207818414/660318275,441940040115/475326707,=2:-241089422091380582698/291821084942167601625 +qdiv:-117224089919/84114141,716572188281/615080131,=2:-72102208583734299389/60273854081746581621 +qdiv:32648685593/8729669,=1,404404757551/92590568:1 +qdiv:11283539119/1423144,673710725321/52857428,175857709907/93503240:149104714141931483/239696844119057306 +qdiv:-783312088280/1307187,=1,-999024378776/8099417:1 +qdiv:-335550743735/9259612,=1,110401498541/2695293:1 +qdiv:-969453169592/714537,-142206723743/5688,=2:612694403182144/11290218418127999 +qdiv:915427154883/429041,=1,=2:1 +qdiv:33170923218/1141,492375916059/48304,-152255782445/12013:534096091707424/187266973407773 +qdiv:66307453504/1149,-380214630350/90741,=2:-1002800773067744/72811101712025 +qdiv:115050365732/105,-356906258167/6917,133352622384/2245:-795803379768244/37475157107535 +qdiv:-936999502170/2803,-22830683342/699,653640693595/4907:327481326008415/31997202703813 +qdiv:299176277149/342,240000696411/4,755800068407/466:598352554298/41040119086281 +qdiv:-182582420949/29,133253307768/5,-631023253657/163:-304304034915/1288115308424 +qdiv:936258791901/32,-530850202731/22,405531901705/82:-3432948903637/2831201081232 +qdiv:407182068269/13,170897351552/27,=2:10993915843263/2221665570176 +qdiv:148775056789/4,302163295511,99960897446:148775056789/1208653182044 +qdiv:-337133478853/9,213727099090/3,=1:-337133478853/641181297270 +qdiv:2931561288588/46490752158254610139,-8202572289073/5477030782824843748,406508166805/409333849870858141:-16056251419334141316586635547824/381343755351460032640212424711147 +qdiv:8659279723725/77988438020199829427,472793658484/11699334077378093301,=1:101307806357325053531850553266225/36872438931022959247544091408668 +qdiv:2933595046594/2949357762979009185,3563536035074/8149803984266631315,4953133863743/4139113595975136772:796940819965221171181561483037/350338088956698021793464271823 +qdiv:-4417286673431/7291794623128083428,=1,5735393868933/1602164499207861679:1 +qdiv:5248399908431/133410821320193982,4294585586137/263895726266579654,2738534220357/842657575741413097:692515152786424448774583831437/286472095138201924171005013767 +qdiv:4823557797176/919788364227952961,4539296003171/202991457794647718,=2:139877289857927988799859320624/596455949357591266717470691333 +qdiv:-8420302353377/39920399284053083,-5878820386633/66459700639056554,-57753189302/1760668157424275:559610773695778812487195882858/234684857153620681793355639539 +qdiv:7389413759263/1342000762039062,5356497784623/12667867863288484,-6593133123716/2889567465913753:46804058544754751951948113646/3594212054412306699594471813 +qdiv:1110445958551/1731649423193452,9842168648143/8566872566929873,-784869046327/167483466404282:1359007002766958389525956289/2434740808932786168687079948 +qdiv:1750996678106/4784358421053287,3800412570471/5372315012242984,-8798822160864/7712445715859279:9406905740176459704104908304/18182535885009697370933688177 +qdiv:2392372723343/980802467194173,-5448032534257/790892614293517,-6821479423957/326036850666889:-1892109917529246153239467331/5343443750953388433293284461 +qdiv:3989933324048/125562720671257,=1,3984983239471/152537155573207:1 +qdiv:4001595047662/49753925398623,=1,-9759772064070/51453270252949:1 +qdiv:368358730412/8572667880419,939557773577/12062683819407,8877992040917/39600926316690:4443394897078137606705684/8054516747341535313888763 +qdiv:1215069339240/989318778961,69044090164/8028108572887,3367060670233/4440041254459:12767943166236631504170/89406564104085955811 +qdiv:1791644247845/5689125725259,=1,=2:1 +qdiv:5606399066403/368046160633,-3784609207827/3426986245,=2:-6404350828181307542245/464303629479008974291497 +qdiv:-131513275529/98691678493,-561412154288/53531566077,-1122072538634/477295425653:7040111598983370629733/55406707833053807327984 +qdiv:2966189201493/3188846587,-765990729969/28303317097,94779711197/8832856319:-27984331179851201608607/814208974978428088601 +qdiv:4487898063908/86671538827,20575135814/82013021801,-4824743345930/15244374571:184033040877976247629154/891639341286949625089 +qdiv:6640651737996/5578359755,-1524912145445/1866824798,-1206385524772/935902225:-12396933339372731624808/8506508542061094565975 +qdiv:-1670244987890/2390269259,211444100122/435503801,-4113147761077/5387610014:-363699020413646984945/252704166259267374799 +qdiv:3616096167490/89600697,-3281988440649/45164705,1140366335303/460713772:-163319916656316440450/294068451828093532353 +qdiv:75228599651/227555070,4602761483680/8510461,8893663369183/844450330:640230063414449111/1047381711612106257600 +qdiv:1795848602659/48671731,2894778221972/9864249,-1468924406276/60038807:17714697782930438091/140893866924479473532 +qdiv:150328765525/5091087,1032046096177/24250562,1454940060232/550925:3645557048747475050/5254236463647474399 +qdiv:5125626061499/940322,9381566963714/9633539,-8717701934147/1648464:49377918562867014961/8821693810453475908 +qdiv:-2858213327627/534239,3443629667062/7382473,7810993394329/9751719:-21100682719446481571/1839721269701535818 +qdiv:-1463079225989/126068,=1,-6765832125078/62359:1 +qdiv:1136379360139/124039,-504843410569/55521,6082255198462/98425:-63092918454277419/62620271803568191 +qdiv:-5785459125301/48585,-980138141280/17669,6000542902487/97411:102223277284943369/47620011594088800 +qdiv:-7679165118448/26823,-944998596479/5462,1824880606740/11483:41943599876962976/25347697353356217 +qdiv:3243495212743/8274,=1,=2:1 +qdiv:-5971611956701/476,1643325077002/3767,475412157786/739:-22495062240892667/782222736652952 +qdiv:2952006102878/561,-2920328989442/43,260516724704/29:-63468131211877/819152281538481 +qdiv:9857529529369/141,664372705021/114,-6783178462275/902:374586122116022/31225517135987 +qdiv:5524525978566/67,4357728100577/48,=2:265177246971168/291967782738659 +qdiv:2336151251737/30,=1,194224488061/2:1 +qdiv:-415797686927/8,=1,-3430578037345/3:1 +qdiv:-323787783182,2111647170213,1892571894592/3:-323787783182/2111647170213 +qdiv:19507584899771/19602559368642654516,-98762473989467/63334639758731491371,-3928554750602/4788014258733220903:-411835287396622150572883462125347/645332419924184274699173167994324 +qdiv:55521794790863/72416102594186986653,6390012176892/15510036414312966041,=2:861145058994297080790192816083383/462739777379915195047434279022476 +qdiv:61284142285049/2628054567745986049,=1,-44698994133307/3227806563441401147:1 +qdiv:-85595920452185/5755403767929246941,45867122342099/7759255048184778135,45612340440994/3866169183382889141:-664160577872639158424643100974975/263983808751788330415801251269159 +qdiv:4740740764385/24661806310764913,3530577952996/95659364762369765,-69284592611657/403777287873565361:453496250024140373610112819525/87070429641844221178520029348 +qdiv:20986114241917/947849730677321165,25408740172553/922531137812244018,42932138005871/490205905567788427:19360343849853428823690688102506/24083667529404391955545898984245 +qdiv:45088960299948/94417228575271127,50050142431591/43572012598861909,20043424278442/2756764567254895:1964616746258918695428071880732/4725595738188403692879874973057 +qdiv:21661156181730/71263658579336941,45008374468118/4277846527853817,26745019699809/84174122749515532:46331550880656462369663081705/1603730715653453519692992073519 +qdiv:99154176787717/8705129313567042,-45151880678379/791205466934650,-22406681696383/1924187101524921:-39225663371923231697880847025/196526480028019185473628192459 +qdiv:-5609307442339/94365505564204,-14842593099555/1569343315609241,=2:8802929139831877689263054699/1400628801723273247416329220 +qdiv:-97037008499074/756578572377141,=1,503224365293/860417586944670:1 +qdiv:85000145508250/380984289349707,-15377953570116/246971712665843,27541060282194/114009089402725:-10496315756509182254824852375/2929379356281716958334278006 +qdiv:-24399306423841/29748858502501,=1,62060968306792/72768955027007:1 +qdiv:-4232559885721/1925922878561,864465944283/775519705501,15493915917617/18579937913849:-3282433596089696135051221/1664894739831468401216763 +qdiv:15584390849814/2278161614515,54457886654043/1079434289611,=2:5607441955329714560494118/41354622327616490710744715 +qdiv:11500059385610/2919980131561,41696366394311/9941918005064,-32114194968938/1137740395947:114332647465101300708729040/121752561429675892981949471 +qdiv:-31278600650774/453275229047,-28532854752978/575231763625,-3852037577017/756431205514:8996222308033400370647875/6466618136760442777675983 +qdiv:44062310842317/210587042386,-55360722545765/100402527517,12610888787411/239675278392:-4423967376808340040536889/11658250825264599879795290 +qdiv:48958684754698/12723573349,4149226003351/3090304164,91252399807903/12674198651:151297227361406547962472/52792981395214568292499 +qdiv:-88974567840351/35825259835,14381460656143/10545670717,97792216817499/5521151606:-938296494631719471701667/515219564813152563916405 +qdiv:-29910765212475/3946907284,=1,36882758665041/2632441948:1 +qdiv:12047819336467/160596922,21879038061983/8612278458,-76714046143249/572675448:51879587468665298963943/1756853084537657508163 +qdiv:78772359143669/473800927,10721848829934/52677443,=1:4149526458766152558367/5080021914776594548818 +qdiv:18817085731832/220202645,46482990078371/128558081,30334199853605/727511244:2419088431696802534392/10235677362766051491295 +qdiv:1071383129760/480581,=1,=1:1 +qdiv:59583931345369/53336138,-86968002500/590691,-24368993907767/80312012:-35195691990327359979/4638537382924345000 +qdiv:5688670904574/472795,75880902224492/703611,-80911142949749/9592736:2001305711919108357/17938055583614347570 +qdiv:34034170400721/362423,19314454819243/6528148,6009826067910/6552391:222180101433125994708/7000002658954505789 +qdiv:83460851334154/339967,65893345957783/584029,66032371258108/62613:48743557543834626466/22401563145229613161 +qdiv:696783133091/32893,37868822555967/926246,95224409497087/888005:645392589893006386/1245619180333422531 +qdiv:37717285918991/12822,-1013012164984/227,-18964497863773/15698:-8561823903610957/12988841979424848 +qdiv:-10788708465143/1210,35785601092532/21011,7989331652889/78460:-226681553561119573/43300577321963720 +qdiv:88903457578888/8873,3656416213577/1396,=1:124109226780127648/32443381063068721 +qdiv:12369335335111/1726,49037936736719/2202,=1:13618638203957211/42319739403788497 +qdiv:12617072789709/796,-14476116805342/121,77649458159946/637:-1526665807554789/11522988977052232 +qdiv:67256470760364/343,93944013181019/811,37737599056319/358:54544997786655204/32222796521089517 +qdiv:-91036418449252/85,=1,-14624790219589/71:1 +qdiv:90733799845020/23,12126352178876/15,=1:340251749418825/69726525028537 +qdiv:16289285460967,75541729906965,31946672959257/2:16289285460967/75541729906965 +qdiv:531095972608,-5291079364402,12305754948727/3:-265547986304/2645539682201 +qdiv:160966533905511/4967535563229348506,-442581751532572/8984740788208442429,495627298842758/79806562952710497373:-1446242582717381874997643569326219/2198540590374386626354894598537432 +qdiv:846754392871971/52993412627792440100,-675514445173562/91617804931552670537,27007423378808/1709931290008410469:-77577778791079552140504662184818427/35797815729116844431852155988636200 +qdiv:45614023605550/1179336166017880593,811804712592947/9699287451192063895,901835327286365/3950301615799586609:442423526755689695993353876617250/957390657304613583282558459977571 +qdiv:464881279654941/9833448339137766220,1646029459597/2342068146526146209,-832981812917597/18521573988396140:1088783636996150710534902035268669/16186145655645954516040321413340 +qdiv:4229214776561/171585302869236077,295560300000344/195031349213283619,362544544704566/882044098766689437:824829463985447643862206454259/50713803591681301033130117210488 +qdiv:-783158820408286/503902970658703793,28022392112882/393792758740011325,-148579890099548/819284251472506133:-154201136210076013184280381919475/7060283315322135516614328780713 +qdiv:60027070722089/3527765978642153,37939143520707/1586793930078527,=2:95250591462205287902363482903/133840419771172027935698562171 +qdiv:141700790775610/12344985164771471,448607065704321/72973195171472846,-244344912157487/80621772408426809:10340359461220627648694394086060/5538047570931503297279622226191 +qdiv:-444095239925813/951645354772783,-163717942365872/3710144267118465,179957355330809/2863453381499460:149787037133214031805625676095/14163765395040027237637605616 +qdiv:490326069822452/448476138248369,=1,-236690894605813/2698259084215151:1 +qdiv:165158943072602/623311238414071,-597025041348600/83514840703301,-552484980244026/127678064255807:-6896611410716957117792029601/186066208943603905731528075300 +qdiv:-325041244622487/131017693842736,498210461660640/209968722758669,429274286710968/922035781432495:-22749498325757227956037196601/21758128578367297773853703680 +qdiv:-238357795569557/66187456271695,39950248573653/1546335570925,90339128985173/5004173134412:-73716227579295071828866045/528841066102400696597330367 +qdiv:-359791068917359/63265515095071,-994683695475560/28650227587657,-399535391547415/31717531716704:10308096008488719777261437863/62929176350930046925956964760 +qdiv:308293748883350/6238067591429,78244308628587/806222876113,=1:248553472912393419138418550/488093285869757029225580823 +qdiv:682129460838697/3097305982387,225155835658909/2056462894529,-875562120758647/6664025303008:1402773925479852984592788713/697376516755683065693635783 +qdiv:359301682748683/2940702974,268231011568139/65687387428,-14850805009387/192019789638:11800794419122542088878662/394393866718727380472693 +qdiv:-241203400501853/332337903488,235227035230030/173322412037,846432442456450/482763093159:-623969480097129824597083/1166788951224568448049920 +qdiv:248519658251861/276786224,=1,-394213812698198/83455587503:1 +qdiv:182875910078197/27817962639,=1,=1:1 +qdiv:110911658388961/383629306,687630093841477/2420083617,155379288838024/9875847499:268415487401425129751937/263795055685120695524962 +qdiv:573112467958159/9872133118,-489234981147827/3619910406,238846563705977/489924762:-1037307893285040668351277/2414896429936784290217293 +qdiv:888923070376622/668668973,33510462457835/119313137,507394628224328/514868127:106060200078306542283214/22407406516435585253455 +qdiv:-55229371022605/427082953,265672135996511/172307189,286493947193530/652156591:-9516417671143123007345/113464040371207515576983 +qdiv:86350760735383/34763061,166332560995049/10808478,409535214096212/2843497:311106765897216992358/1927409654719036361663 +qdiv:-526887225315220/62364781,379859437167168/29483203,31678687276584/32988215:-554797250788406080345/846066093204060453936 +qdiv:726480663971978/9429277,621839044883483/2484303,282821010941771/7377203:1804798092947576861334/5863492603621793931791 +qdiv:-266940245547361/6815452,381659084362202/6793379,=1:-1813426258356285722819/2601179169834538345304 +qdiv:-52306849857668/413037,=1,851795607859277/218365:1 +qdiv:-955560519915196/876763,600541379064812/884807,258058491132109/283242:-211371659236151206793/131633115283250440889 +qdiv:83188488364775/7428,=1,909855616022861/57814:1 +qdiv:12513129780980/65681,242195762149522/26907,733634580329507/67945:168345391508414430/7953829926871377241 +qdiv:102024066442285/634,54104883041557/6299,51186522023145/1582:642649594519953215/34302495848347138 +qdiv:-26631109318613/1062,404096111387523/1555,374428590131443/4870:-41411374990443215/429150070293549426 +qdiv:963930172849509/556,429505950038041/339,=1:326772328595983551/238805308221150796 +qdiv:35409769648583/190,402498581379988/269,142263070810850/29:9525228035468827/76474730462197720 +qdiv:979207315133077/41,=1,277675341412115/12:1 +qdiv:729890422328468,-207010622708828/13,=1:-2372143872567521/51752655677207 +qdiv:664184931453977/5,263094792374994/5,612770715664829/8:664184931453977/263094792374994 +qdiv:386777398336118/9,-203562236005259/4,280368609411177/2:-1547109593344472/1832060124047331 +qdiv:846748198636336/76773803058781380969,1801233601495438/43951036051554528101,-985640234538135/13669939898764919281:18607730302427229122582057095838968/69143776892035130477190634596759711 +qdiv:3891890618737276/6895557650428977805,=1,1111068254412479/16589207394191005337:1 +qdiv:125869026052733/9512475498663033351,1424684423763397/9653552384747479895,1477787248473387/726686337264726454:1215083236617203328243121127303035/13552275674376176199352055144053347 +qdiv:-2561702659033141/64484986154218090,3571827544304442/1907338065210223751,-257437056062343/308468989548243692:-4886032993324156667740785934331891/230329249739726743799833423755780 +qdiv:251427380280479/17080042626196354,-8498494882766151/431225536698454495,=1:-108421907002135971034718918303105/145154654856157445334163190813454 +qdiv:4494233115621053/420999973410664205,8502817658603234/225118720507724895,769427242578913/224964781616403409:202347201730411498629276398842887/715937201637537517148588100207794 +qdiv:1082573471098327/16190062236884916,-9285142983057539/68911329784144138,=2:-2869291441631632483178789948351/5781809337464493137192021122374 +qdiv:-54148197646247/67087793059307529,606637391147105/10211716656528727,=2:-552946051825190099886939237569/40697963759315177457206273053545 +qdiv:1552820047883756/1409852829677289,374732588752648/1411748879243035,946186753596337/2784600373889665:548047990566502118911738159865/132079450156304156086221052818 +qdiv:-622450586504533/2629689473880042,42458393126567/46859716926298,=1:-14583929142105291235301954417/55826194741396982866540637907 +qdiv:3985435662577/336228049466,1092888342910160/28572447705111,2326116659781853/93785125130264:113873652051065741394331047/367459715820812046873974560 +qdiv:7163492071774727/830515940073459,3657279442118065/897414555540119,5964135597835892/909513080742871:6428622053706882865266378772513/3037428873982020434994650936835 +qdiv:3607952451488590/49193513780067,-3043939406564413/65486757325344,-866352414070632/19967852787311:-78757702210671087993244608320/49914025047505139104450318557 +qdiv:9495052294801966/38526321702455,6497122364756042/67241074266611,976932655859167/35062261580861:319228758260067099260465478613/125155113182403225758093741555 +qdiv:-8635923474747691/834091522151,-6012381717476054/9878110045469,9959093802197859/5095796016470:85306602427806718417312762079/5014876618482445518753072154 +qdiv:2821313461694584/702859941105,=1,3985236573834282/7019306492603:1 +qdiv:80074080855208/13358267917,=1,-1127102895421894/492325215749:1 +qdiv:2903637249590617/66609940717,=1,=1:1 +qdiv:1317275961025638/30056701615,1903028147618023/12972309420,=1:3417622271590487337781992/11439749839580218061441429 +qdiv:162369131285203/29375345061,1123696767790/4238363,580047582726290/4797152503:688179318381346842689/33008980297761640385190 +qdiv:-4786042110917887/821667120,-223845848166680/444195731,4201261485857429/7441612588:2125939474055953896940397/183926773387073235561600 +qdiv:-3647633785553978/3264747911,-2590574647212125/3171736042,1034451358224699/9321063772:11569331545658450959075076/8457573167775347067620875 +qdiv:-1182656408586511/263603111,-3183826575455972/641377267,67932666203435/9814518:758528935139251758245437/839266590174670462728892 +qdiv:-1010164506152201/73078179,1003381341185915/606903468,8716869883166609/714842540:-204357447344759374244356/24441760418814789549595 +qdiv:2146746992979571/54021,4486129793037235/14014464,4736792350294185/48933406:10028502816740150171648/80781739183221490645 +qdiv:174759124915340/38909873,808299936999437/3899591,=2:681489110687735625940/31450847894556094741501 +qdiv:1331080173593011/170345,1847682196363704/169667,=2:225840379813005397337/314743423739575157880 +qdiv:401756500827695/5268383,=1,-1785129473905456/1874737:1 +qdiv:9588863636181187/514679,-1885957167516959/372023,1236604399361407/932066:-3567277816523033731301/970662549020460941161 +qdiv:-1948318799147741/361624,=1,2127325154839916/20417:1 +qdiv:1427781136273691/76759,-7623865373435316/42907,1659481401097244/10649:-61261805214095259737/585200282199521420844 +qdiv:1719870896249226/12205,317200077044831/19050,=1:6552708114709551060/774285388066432471 +qdiv:8138959322580502/8221,-1163751251034425/1383,7539031083296853/4651:-11256180743128834266/9567199034754007925 +qdiv:169053135509582/2079,8384337995393067/1027,1100360786228606/2923:173617570168340714/17431038692422186293 +qdiv:2884372934790855/473,-3411772457185025/498,7754693992370393/59:-287283544305169158/322753674449703365 +qdiv:9645445945124801/694,=1,-928157555471025/697:1 +qdiv:526455353835711/2,6821493510127697/42,-8165061988695477/61:11055562430549931/6821493510127697 +qdiv:3494561591012431/18,1579558097950769/68,3011416104352409/38:118815094094422654/14216022881556921 +qdiv:-1075752344316397/2,1031504762905937/4,=2:-2151504688632794/1031504762905937 +qdiv:3510047439829528/3,=1,8531234312015747/9:1 +qdiv:-68345423328108071/30673713062451046410,84635933116432261/52124678834577315684,11829641732143217/15648982195593167418:-593747206798476915089200913572547594/432683054531040224143843344222038835 +qdiv:88353531187611591/15437715341399284739,24211922635091389/65206525720651916247,4391301426749866/9028296670139901087:523747891263219677852058701936219907/33979706318956630192030846045273861 +qdiv:23319878514419521/3762815638844579088,1735842457506851/1043622756122083662,=2:4056192647941777068775888487994317/1088609190946197612434792161888648 +qdiv:-44931766141664776/660272913423169311,-20934212682408103/543885314267387231,-15811898876311121/1155697907525944754:24437727748548095710058962184875256/13822293598033858379756137767327033 +qdiv:6078883422776446/585720619063886603,=1,1045243009859441/415511111781051358:1 +qdiv:90440439133569617/948175107640141387,42133680477668241/92268692005881214,845568841006347/5611357858009690:8344821023291981428329461501475038/39950107022188408181066157319590267 +qdiv:4186499515356231/14864815583978242,-18423317485074290/7509262009862299,2871933150211711/1349599950356374:-31437521764971471895320241635069/273859216860711138847895113598180 +qdiv:-29582635046879003/50061021370846352,10045103192105828/55898368325607727,-37052174592310080/96357604503422813:-1653621029892474317451914610856181/502868125572366763986389511739456 +qdiv:13407277935430429/1013601685235852,=1,12172330844000900/902390153283673:1 +qdiv:27360619531891829/446629134514741,4131082115213588/1108810664462473,1247084760967392/7561950200172275:30337746723261895886437065833117/1845061629727170372539949500708 +qdiv:61461830136885063/892616617339285,=1,33738741342160459/830691355475130:1 +qdiv:61440064505101811/137342816799395,-4711908842636087/41515812949603,-24218275768586906/186742521237115:-2550734225605349400573727031033/647146832949617421060066767365 +qdiv:5758080755122561/15095071042602,29045716031779306/2037705119057,=2:11733270630656838625131744977/438447146982952474786587994212 +qdiv:54526928002573683/59702858549279,92640788780483269/77681659329590,-71811590482866045/83384156477179:4235742245385010165548357179970/5530919908454825601037871513051 +qdiv:80792214616474631/6644270819756,63735176539398861/9296933147014,-49380745622098487/1490898600966:375559909044285990116562200917/211736886836362524703961348958 +qdiv:32030499525154974/3954323046161,31366526470107724/1768190715343,-49495147706919681/3289020191827:28318015934088697649997283041/62016689249383006938747323782 +qdiv:9328741686632077/243149745260,2480495311675799/1003030744,2895546265991266/48368547577:2339253678631596761893822/150782950788148707639240685 +qdiv:86704861543195229/19495202697,-67726887612055909/399405679895,79366554520762433/427533781579:-34630414174861729349465220955/1320349402033968246851586573 +qdiv:44938705263692416/75214947649,13088918735108810/42829053903,=1:87485555912259650621649984/44749197156510201930394895 +qdiv:44904786185636646/96125537099,24798894892177726/66253590239,=2:1487551651856539065713149197/1191903545486115802757228437 +qdiv:-40789888748879566/226781493,92548538546533322/4980935825,-18457923779643496/7489800193:-101585909083529329449925975/10494147873275438368704873 +qdiv:69711578560849724/2839609701,-17832323142587131/1317413634,70780014264413677/5219758825:-30612994681241841674245672/16878945929019074475119277 +qdiv:-59818087210738392/689533643,44169679860852171/464682497,=2:-9265472710283227069441608/10152160088199043518029651 +qdiv:13285049487986594/299383163,66537912712814595/528333412,1270866798654711/67428626:7018935524576810218278728/19920330767380344083663985 +qdiv:1503810128215281/2257159,-70775598572813631/84477811,-63395967835353025/15198273:-42346195930418758543297/53250593099671147511443 +qdiv:8428754085692575/2245416,-22542294434269243/25119135,13783461291888720/14173951:-70574337253437786640875/16872276199806368846696 +qdiv:9563262734920725/514036,=1,=2:1 +qdiv:53451507046231654/9484455,47537920203789693/4546483,-80647128625430672/4405781:243016368110072428972882/450871264966434172722315 +qdiv:-44159999533489381/113642,27485426878029480/364853,35852359000720457/949621:-16111908309792201125993/3123498881273026166160 +qdiv:32853589059772384/503717,40780321841499481/989824,=2:32519270937500140220416/20541741377034594070877 +qdiv:79928002171125410/57963,8207223112140364/45757,6211993052732583/4990:1828632797672092692685/237857636624495959266 +qdiv:19663131964133109/36425,71845241352937178/25359,86972744437274535/81994:498637363478451511131/2616962916280736708650 +qdiv:14435384562180968/755,72009011268495388/5897,49643107641306868/4273:21281365690795292074/13591700876928504485 +qdiv:24454205396414067/6880,69532248800465987/6162,26996222231515961/2920:75343406826351740427/239190935873602995280 +qdiv:-1788783461774743/10,=1,=1:1 +qdiv:2169480921871575/32,24356653728462933/275,=1:198869084504894375/259804306436937952 +qdiv:55640518711168835/32,-11942433331158949/2,49472052316509365/97:-55640518711168835/191078933298543184 +qdiv:60550088149390965/4,18432938626319732/3,-64770809459825588/55:181650264448172895/73731754505278928 +qdiv:-7803681495846471,=1,-17883711462854096/3:1 +qdiv:50341568785662927,62590376897604859,80681563059961663/2:50341568785662927/62590376897604859 +qdiv:-203151633689699473/4601599975290251067,525611526456048199/10684809311118564881,-92007105653918839/5233554995228398975:-2170636467216648863175567911942007713/2418653987152422537498561743363178333 +qdiv:65298869984225348/19019228638839514289,56379757376977511/14055232146718391290,964945810921349082/20809092926836677025:917790776546668763561146735400418920/1072299496155034051021485798116154679 +qdiv:-145588071893096095/4173101898033488969,950865051078788090/1909232631512562529,503871559562682707/9612144818358151944:-55592299523459199702887019418644851/793611349886120203227511154180715842 +qdiv:-416108982689762077/6607155238394910018,110992754943723449/1849236166477509591,-268331055516600845/4522919721232620152:-256494593328690673619763717091860169/244448787416768310712157092743870694 +qdiv:25569109100431274/108937408231316295,-72437832965809993/62540068610663445,=1:-106606255830300730275789651105262/526079318745889626493211550315729 +qdiv:877324076175281223/214264808883890725,42146916770679749/32999264126549449,285006538829039936/192084798661860001:28951048914289093786435738190696127/9030601066914945269923974086428025 +qdiv:53167133313707651/16126281481928302,=1,866634487225725687/8471335588786562:1 +qdiv:-404441666294175709/28651204642462452,737283168872077719/15929980120269742,595275127996297901/911315023660732:-3221373851937494010053214312048539/10562025475398550561404400841653494 +qdiv:-696867039120140351/7944197978612428,305556608949512209/6106076808329836,-21961011512486436/271929687123929:-81829301270403260762717504246393/46680811445545827264035485867951 +qdiv:-680855634912930787/1356189151638221,76800812974773809/4396449080201477,115900299432052362/915351235529267:-2993347129862947189365178516172399/104156429393384168102319274153789 +qdiv:858455835027039516/181700684219717,276128875832819233/429408279720099,513501697172110895/688533497518381:368628043334642145377689092432084/50172805671644532495814915417061 +qdiv:316851319525526256/292918890269407,11393663510588707/7832467998606,183243936246901525/329030327691009:2481727820499768843861224399136/3337419271624680006372401786749 +qdiv:425938764355509261/38431838740736,51646287499025181/14744319169037,61598803394948627/2198532513800:2093392362707622954000159317219/661620597573408443663531491072 +qdiv:-32900087887779412/15187739925135,-77577586584555989/5103062080335,20798656203711947/4200421664287:11192746062654396148286870868/78548547271058557114805058901 +qdiv:486662144374613085/7279800587764,370935209793408403/1211133632516,-89246445251861285/6389412265973:147353222681112795182018767965/675083589569104285293074145223 +qdiv:-964120868211092407/359784141044,-101341301532555954/2823707878015,-3905142618376867/213434004577:2722395690926323209655048732105/36460993124171644711757975976 +qdiv:523113306979362837/776795904043,-598929472099127320/298887489003,374389526725869791/822603563483:-156352022787117273091784381511/465245960737238351450759754760 +qdiv:840479323018514793/77550808147,641898923324106797/94049021855,-530841733088610489/198795819997:79046258219243902336497801015/49779780252473669714285675159 +qdiv:128459136724688363/3656348195,=1,=1:1 +qdiv:117942267177399129/15104768300,=1,673568920447088655/16579651733:1 +qdiv:-380358764362707601/4878763095,26907876636599267/4680009378,46112939804078386/9100681911:-593360861407321255383960726/43759051833151076714550455 +qdiv:-687756860919714982/4983016997,810697365335247161/2657532848,-767797307972200547/8201158600:-1827736449331510055462728736/4039718750888655206458995517 +qdiv:-671538226625519919/488528633,212340873444231067/18548520,903467856142920989/292805725:-12456040227327988727969880/103734596633736204897641411 +qdiv:264766040442810006/105576217,906671624054033815/16237552,-17400397472077592/73576121:226271176290748973607648/5038050533098478619883045 +qdiv:198599362591258655/32652407,180852394942204767/534302,330626253412331177/39365397:106112036631234681883810/5905266006577611529424169 +qdiv:193437965129974007/33032327,=1,-712641084972416324/72668161:1 +qdiv:5650691886191629/31580,778039554898468719/522286,-85572216893806154/638707:1475638631235740571947/12285244571846821073010 +qdiv:255988566078185670/3226711,=1,=1:1 +qdiv:119176135632936277/90407,742203087602826989/37340,435710884024344205/699587:4450036904533840583180/67100354540908779594523 +qdiv:601345588172172775/239872,543493254518268378/505985,-428607861122460011/847997:304271847431296841558375/130368813947806072367616 +qdiv:-384629861853292408/8659,25928764268860430/2863,=2:-78656806748998297436/16036940700290175955 +qdiv:16969933057999661/91390,899168628900829159/84974,=2:721001545835231596907/41087510497623388420505 +qdiv:-338452503566548909/60,-471242201877785904/1471,571852972365820021/8097:26203349091915444481/1488133269087744960 +qdiv:-67208679240212206/7945,-147655843020220929/3895,247227362702367322/3545:52355561128125308474/234625134559131056181 +qdiv:372479537607215503/364,287530886573098995/616,172294866607452652/419:8194549827358741066/3737901525450286935 +qdiv:182710333561165768/213,510797940135310553/999,=2:60842541075868200744/36266653749607049263 +qdiv:579561523155053213/54,988155654509496101/36,200878090425916240/7:1159123046310106426/2964466963528488303 +qdiv:515113236713830593/61,-312166546603055389/64,=2:-32967247149685157952/19042159342786378729 +qdiv:292464149557005921,89917333945444994,81421444399876118:292464149557005921/89917333945444994 +qdiv:296110466389461193/3,109472330812647154,=1:296110466389461193/328416992437941462 +qdiv:4092114512174117006/26116630455695638973,=1,-447003756121465797/20917550324131376672:1 +qdiv:259937566541134655/4158701589393004579,1547780345841112833/51410910398305904707,938595196927633599/39410655506871762710:13363626942599952654588701490085321085/6436756584280690243327152586824662307 +qdiv:-1896779359348956490/1347192914723660737,1473868522523514384/1232156863222473595,-5707768245722740379/418206171177904664:-1168564852820271637019025039914440775/992792615388954378876171247477770504 +qdiv:208447940832270699/9600679647480708145,2870404120011924515/3559456450102995519,=1:741961367506113511552059562591997781/27557830415043255728392135816485674675 +qdiv:-4297501973500096783/204423371799318060,2877397514219613038/539249559830239969,8324733346597146387/157919348439263966:-2317426047579514781946227871614919727/588207301863749530458354605484866280 +qdiv:93720929235782808/55293543050375,-7894380025587801253/181187413116917545,3736135546224315869/181899903281616836:-3396210544629034994552431212913272/87301648360171916529438973423975 +qdiv:81994885389922697/294916754436330,9443771936591527133/5056845538523172,=1:69105911727624901444765437205814/464187761529411335843377885990315 +qdiv:-1327130679702964642/1750505879782173,=1,119824008643752477/44623528623225535:1 +qdiv:3879822966686063981/3001133305530870,=1,863100334242503747/3064363459719574:1 +qdiv:4471609326841143121/3136394938408391,-2100659771756104576/2883761130954275,15497169860790465/125833380421061:-1172277560868827200679819871072025/598954425041270209782934871990656 +qdiv:-1428825541118510643/189287913101264,333610284195481532/220738789477061,670131441507861203/870560425567724:-315397220320406686290969132860223/63148394484482295041093957856448 +qdiv:8591262769553056858/438853613359311,2189525401934819634/71978219024849,5936949921650810154/230960129719523:309191896663460373602599905932221/480440567090546674289419809756087 +qdiv:-4064523795777485/244411410943,4019762771700340189/48942084942433,1825370830820857864/84013901689297:-198926268863481870604702521005/982475890687424536786577288227 +qdiv:3308449940543897586/24769809780163,=1,=1:1 +qdiv:5505516603567201356/4103863380997,=1,9200863431181416289/2198737928697:1 +qdiv:299025438242526319/7174665063033,2342598970518801198/2840711341985,-624920076676181455/1731259940133:849444953957579679543172203215/16807362990478315705960265913534 +qdiv:-1317323502669839257/383434104838,1699132754315376723/126762068816,=2:-83493326249184161811746154856/325752723325920927661123442937 +qdiv:801340903278936479/656286066237,2305646751022168759/405803179528,9784332106348628477/2005196814:154924576672907071866862888/720897492310842731598125817 +qdiv:-7034488704242870267/26137866450,1404864734358647884/61096984649,8568167552998854754/11743533017:-429786048376690545870597531283/36720166806981064794567091800 +qdiv:1957064921110117593/22698952475,-2877695287391612383/80652467816,-6543222962701862213/80347703614:-157842115563656338161407886888/65320668566033676195338497925 +qdiv:2797239636828126649/9292862128,4813087393853254410/1395246169,=2:3902837887059395018464057681/44727357561093127896237984480 +qdiv:-4315815575872328781/941797525,2364548726161022722/1932241689,7324535609142564031/6044609444:-8339198777736056212162751109/2226926138040353951048363050 +qdiv:30859738907627663/2542365,6600947823086520511/563823249,2650371430256452002/735290035:5799812751396779944979029/5594006237413787239649505 +qdiv:1239632473056172538/39020573,=1,4893570761803052153/806566500:1 +qdiv:4340355836717522794/84976723,=1,4177413596064433650/4807901:1 +qdiv:5251208912622866942/60282373,1588514721403315667/15272978,=2:80201598195892969102093276/95759436951625758474837791 +qdiv:3180027096600073679/1131489,1551586490431667735/1426711,1709665203917621573/6158822:4536979639017387718639769/1755603046472037293807415 +qdiv:8243752949511560636/648121,9011505934664251587/2857664,2654767072043691455/1609529:23557876028713004413314304/5840546237880529402818027 +qdiv:1059685344014955483/517268,=1,=2:1 +qdiv:7618913893338931327/87339,2570669407313338666/518057,289391906262782051/116872:3947031674841486746471639/224519695365339685749774 +qdiv:700273840899540863/79614,769420078468545381/1045,649456732765994158/34395:731786163740020201835/61256610127194771962934 +qdiv:-187558807564904619/362,-9545050345452388419/23068,=1:721101095484536625182/575884704175627434613 +qdiv:9871582247297764418/7063,1928022567530041238/3221,858557805597948211/218:15898183209273049595189/6808811697232340631997 +qdiv:-6853417837322192169/596,243646027011694943/64,-2802878255693787218/3819:-109654685397155074704/36303258024742546507 +qdiv:6270595962911796812/909,6451237634004612584/717,4154473691343572326/653:374668108783979859517/488681250775849403238 +qdiv:2859818002359754548/881,-978746824548811382/135,=1:-193037715159283431990/431137976213751413771 +qdiv:-163677610836218181,1125556291854647923/21,-543556322760873342/61:-3437229827560581801/1125556291854647923 +qdiv:-2743247019285632266/73,2721276457623268991/11,9892328911405524379/35:-30175717212141954926/198653181406498636343 +qdiv:3970324237073990007/4,2239223157773235406,146642702970818545/2:3970324237073990007/8956892631092941624 +qdiv:1833757668733454039,=1,-8814196290971390691/2:1 +qdiv:41577911849641052701/99022939143770450788,29562744466456608111/56837407285672400044,31020970526416154186/17913773857228432749:84399311067351185113571896143048525673/104549637365170333914120618648568826481 +qdiv:11645154448997394881/94761538126264735491,88207691494542159651/12578224627720796822,25570027647696327707/17624189500133230570:146475368483991438069574417703503868182/8358696520589854489200399496481407873641 +qdiv:36037910341862609485/5084165437585712934,14803543978704731158/4018809000761174679,40592658881592860140/1875002057807619289:2540868042991257484177217842751705795/1320415204391415532618346800916375396 +qdiv:-6362828133579539977/1405399076052451953,=1,-79310041992515227141/9766031882584814055:1 +qdiv:18995499865084840909/132084112242521874,40315757995363267494/108424549445496181,9141557851421924653/395183670085599750:294225502051972481196626700993152647/760724443457415783589919753058309108 +qdiv:-20679072031164937/331072269490614784,60303816476959382024/820747184142174667,32412125947207417888/849382221894135357:-16972290140251822462187296540050979/19964921379972472722742560644478242816 +qdiv:342025503923893090/638329775416737,6081856724756077351/10064175190260298,-12635294626204723652/12747811376654893:3442204591027121039210818623540820/3882230237230318511251099432023687 +qdiv:95772012363596472232/93464593843091931,=1,66811795410951517976/57387498829697707:1 +qdiv:39150280549083930478/221651102097297,27527655361557153686/8200729391818537,-10566813759037632949/1540621706438105:160530428198407079993270396049835343/3050767574521854917099344177093371 +qdiv:775796793430257737/1824356921264078,59648355674434946375/4234888027379937,-48407842369116658019/8912961054912311:3285412552177544656250926732822569/108819890516676835653288543143817250 +qdiv:28476387945046958277/999638881195952,58250700361065854943/221262414969004,29643575123794329851/477719531693567:525062863859610263002381953020509/4852472078151375703306701265899228 +qdiv:366203441988870367/188565554272086,94732323070906583248/862962947506991,=2:316020001685920962364670925235697/17863253007347820007476928001615328 +qdiv:8483230698254754551/15259557038423,23368061392310636478/85223679281645,32515807430078447491/85784287822340:722972132300268572088173474516395/356586265693334541919071831394194 +qdiv:49879409479136730807/66163096356056,-38087887001526926307/13816595584511,-1454659694645612910/17634310154753:-229721209589152224414677275243459/840004179226866288683545915055064 +qdiv:62960436874158600601/6181269755427,-38093682298270231594/6182059511551,=2:-389225167629298487685523755042151/235467326263142673710199028360638 +qdiv:-44149559729162857485/8838649113689,-92868732768946894695/9715947205117,7772268284865525232/3917639152071:28596986097180394710634075583383/54722276171844870774524704398657 +qdiv:2160674978760021747/440085907262,27830441916338793631/444373630892,57774193577066913529/985831440387:480073492744542921823635504162/6123892640127175948232611124161 +qdiv:36779826517186231622/593017430523,19227595668423969206/337403938281,11416362949398192276/562802104127:2068276386031765079995376420297/1900383229737324483921166079123 +qdiv:26089630323225357334/95419525743,10301251794111780015/99138956899,91414665551775455692/70400356165:152146984477946008199958796898/57820032985492584056520319185 +qdiv:-29243000664559124719/43374840118,-10759429621437816793/825473183,449211716437215496/6016537709:1270490149423407156499311083/24562554715302029930281605346 +qdiv:43740120582679037273/1380740386,-10453142250046604709/682904599,5705113158551362448/866195241:-29870329506726074294624118527/14433075665242257503894077674 +qdiv:52606375144331115549/7041068780,44326164670224665111/2919045833,89932878257209865497/5189085588:11812340011868808955042304409/24007967245896760392232102660 +qdiv:18724901946698874513/497209057,618446872748526095/146164963,15390306579353612360/304964183:2736924600217868965334288019/307497386403893657834842415 +qdiv:-73271009353030104361/888009485,6268171386817340605/445545539,-30294808731792985583/748195570:-32645571355269839130747995579/5566195645099402419715638425 +qdiv:-6170226889332372331/27347419,92903445126985172210/30514679,3697622268386381476/88810455:-188282492885145865988946749/2540669440431171711214025990 +qdiv:22447257099357853357/73571392,96930598757046526391/75068541,=2:1685082839900686088401942137/7131319077949382755350606272 +qdiv:18405537170427326117/869259,=1,-1420857565162351747/93018:1 +qdiv:49104082785088634230/2249621,37173384714202722705/3494738,82295002552935357721/1027368:34321180812839016682336348/16725205378829888650868961 +qdiv:31797840681830305220/155259,1587139799259633659/9846,26303565519013168528/557087:34786837705922353910680/27379748677027940251409 +qdiv:49251043005944454115/458557,12656810517669387971/114174,-68275280158906352129/488558:5623188584160702104126010/5803869060550921539817847 +qdiv:-64285887839653334497/93042,15579348394621354273/8674,59955417746039738115/74473:-278807895560576511713489/724766866666180022134233 +qdiv:63842413368795633893/62393,-87956339382997486493/5714,7858337204545049957/43385:-364795549989298252064602/5487859883123362174757749 +qdiv:-68051470229786982728/7677,26179928923183325293/1125,86355329936141165696/9285:-8506433778723372841000/22331479371475376474929 +qdiv:-50081439194849732369/6752,5504600376647160870/1069,14173817213125628066/7065:-53537058499294363902461/37167061743121630194240 +qdiv:47895210529721192309/101,=1,8891562052096223369/598:1 +qdiv:2023765290182261065/98,-3528906224032626601/8,210162627484795020/311:-426055850564686540/9100863419873615971 +qdiv:-55071290496801275816/43,-14530504979971463081/90,41799056582024748637/60:4956416144712114823440/624811714138772912483 +qdiv:2952763925816064856/9,-2794894328282573619/22,33252147556814701294/27:-64960806367953426832/25154048954543162571 +qdiv:-22874728508743973476/3,-97353210331533196276,78585121833788001065/3:5718682127185993369/73014907748649897207 +qdiv:-18829566175245957052/3,-20433551292296144981/4,=1:75318264700983828208/61300653876888434943 Index: contrib/isl/imath/tests/qdivz.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qdivz.t @@ -0,0 +1,800 @@ +qdivz:7/14189789968569496825,-4,4/56970792418717696577:-7/56759159874277987300 +qdivz:-1/18980926711980671485,-2,2/34538922161232588701:1/37961853423961342970 +qdivz:1/2252731937540774329,3,1/1284950176761593374:1/6758195812622322987 +qdivz:5/5990342115257096507,-5,=1:-1/5990342115257096507 +qdivz:-2/184808182320120951,9,1/93245347658569125:-2/1663273640881088559 +qdivz:-3/953191474882739911,6,=1:-1/1906382949765479822 +qdivz:-9/58755486411564677,0,4/31278777005155811:$MP_UNDEF +qdivz:-1/6574102725079796,-3,-7/53860936069380022:1/19722308175239388 +qdivz:5/3092518668717267,0,1/1348431717766123:$MP_UNDEF +qdivz:1/1711104650637484,4,5/891266886610953:1/6844418602549936 +qdivz:-3/752256450310990,7,0:-3/5265795152176930 +qdivz:0,1,1/221073922196749:0 +qdivz:0,6,-9/20067002597087:0 +qdivz:0,8,7/58718030529726:0 +qdivz:0,9,2/620702207617:0 +qdivz:-3/2637082492171,9,6/2399598811007:-1/7911247476513 +qdivz:2/989821160739,-3,1/35099223664:-2/2969463482217 +qdivz:7/596707899127,4,-3/111426253072:7/2386831596508 +qdivz:-7/90687746735,-8,2/80220574745:7/725501973880 +qdivz:1/6207705905,5,=1:1/31038529525 +qdivz:-6/7404342365,5,=1:-6/37021711825 +qdivz:1/669923792,4,7/932900852:1/2679695168 +qdivz:1/447676458,-1,-1/780010677:-1/447676458 +qdivz:-8/632835687,-1,=1:8/632835687 +qdivz:-3/34120079,-2,8/62163153:3/68240158 +qdivz:0,7,0:0 +qdivz:1/4563667,8,3/4687252:1/36509336 +qdivz:6/9767093,1,8/1612033:6/9767093 +qdivz:-1/44242,5,2/127465:-1/221210 +qdivz:3/442637,7,-1/427529:3/3098459 +qdivz:5/99573,4,2/18535:5/398292 +qdivz:-1/92756,-9,1/2349:1/834804 +qdivz:7/9020,7,2/4657:1/9020 +qdivz:1/619,0,4/4281:$MP_UNDEF +qdivz:1/57,7,0:1/399 +qdivz:3/497,-4,=1:-3/1988 +qdivz:7/13,0,-3:$MP_UNDEF +qdivz:0,-1,-4/23:0 +qdivz:0,9,-1/7:0 +qdivz:1/2,6,1:1/12 +qdivz:92/54148884014131151533,-84,=1:-23/1137126564296754182193 +qdivz:-19/23897843385077955493,71,69/61266965124498535070:-19/1696746880340534840003 +qdivz:55/6196267973202090504,-7,5/287457924210607772:-55/43373875812414633528 +qdivz:-48/83164040244933491,-32,5/1047923356026875081:3/166328080489866982 +qdivz:21/587480004246184118,-57,15/677609340847439434:-7/11162120080677498242 +qdivz:30/104315744428261859,21,33/4537728827744434:10/730210210997833013 +qdivz:63/43591673951063050,-60,-72/62642630564846123:-21/871833479021261000 +qdivz:22/49235810624301237,22,=1:1/49235810624301237 +qdivz:-67/86699263349277,68,-18/1746465712913311:-67/5895549907750836 +qdivz:4/662982233689325,-70,3/223690708572257:-2/23204378179126375 +qdivz:48/30832308107873,0,-78/969311075733763:$MP_UNDEF +qdivz:-79/719541528020900,71,29/227964213458863:-79/51087448489483900 +qdivz:46/99191502629977,45,=1:46/4463617618348965 +qdivz:-45/94030959875366,-49,1/739436814946:45/4607517033892934 +qdivz:85/1156056884433,21,70/1021249005383:85/24277194573093 +qdivz:-45/3343573640758,81,-23/371241990007:-5/30092162766822 +qdivz:9/908355558094,0,13/114278107776:$MP_UNDEF +qdivz:37/482896223634,76,=1:37/36700112996184 +qdivz:0,-62,=1:0 +qdivz:1/224399171,-96,1/829119227:-1/21542320416 +qdivz:34/3276847561,-87,0:-34/285085737807 +qdivz:8/447224053,-69,17/1706735282:-8/30858459657 +qdivz:58/337629635,17,14/309654075:58/5739703795 +qdivz:19/143535299,5,=1:19/717676495 +qdivz:89/21730150,-36,-11/3380230:-89/782285400 +qdivz:14/11625951,84,-75/90670231:1/69755706 +qdivz:-35/6938168,-92,40/1158419:35/638311456 +qdivz:81/4813535,4,7/2110299:81/19254140 +qdivz:17/267858,-12,51/311648:-17/3214296 +qdivz:-13/119265,96,0:-13/11449440 +qdivz:5/42218,84,37/8213:5/3546312 +qdivz:98/47455,48,-49/28060:49/1138920 +qdivz:-1/1148,56,7/2357:-1/64288 +qdivz:89/566,3,8/7135:89/1698 +qdivz:-21/746,-21,=1:1/746 +qdivz:-38/319,2,7/698:-19/319 +qdivz:21/11,-69,-1:-7/253 +qdivz:8/31,16,=1:1/62 +qdivz:95/7,92,-22:95/644 +qdivz:23,55,44/5:23/55 +qdivz:1/60738652894409193768,-551,107/57758377963603747061:-1/33466997744819465766168 +qdivz:110/79622749216992783521,579,251/88218014233937017256:110/46101571796638821658659 +qdivz:83/4082129227447654187,15,18/1341986384427533683:83/61231938411714812805 +qdivz:993/372817934005169,561,163/3344274496871800764:331/69716953658966603 +qdivz:961/240704079603040791,598,=1:961/143941039602618393018 +qdivz:679/875463698688215197,414,-683/864641730477058828:679/362441971256921091558 +qdivz:661/48034471229067507,803,-793/39170031634988712:661/38571680396941208121 +qdivz:301/29669334975743711,779,-15/1858966466467087:301/23112411946104350869 +qdivz:-376/9004373296401219,353,-206/1302368237251547:-376/3178543773629630307 +qdivz:-311/1125853364758500,60,219/4621090656923606:-311/67551201885510000 +qdivz:890/98890870399971,-103,=1:-890/10185759651197013 +qdivz:-368/970340921930931,911,320/23157236509251:-368/883980579879078141 +qdivz:153/17403469351714,-174,1/10019300229250:-51/1009401222399412 +qdivz:-45/41421091188493,-796,=1:45/32971188586040428 +qdivz:285/4042719934577,918,111/3917056138984:95/1237072299980562 +qdivz:232/2392703971997,-223,29/510798153426:-232/533572985755331 +qdivz:-288/16825025249,683,26/102920443589:-288/11491492245067 +qdivz:57/859553008166,-596,384/457223544793:-57/512293592866936 +qdivz:241/26996988926,711,402/76733915611:241/19194859126386 +qdivz:113/64370447211,32,654/51387222133:113/2059854310752 +qdivz:37/20055174,-333,266/1472467541:-1/180496566 +qdivz:-41/1427473740,466,=1:-41/665202762840 +qdivz:331/299809977,756,-955/46378116:331/226656342612 +qdivz:-29/129229071,339,607/422149878:-29/43808655069 +qdivz:809/62921676,331,358/1765487:809/20827074756 +qdivz:-23/2282319,-417,85/63854587:23/951727023 +qdivz:19/1064117,478,637/1700008:19/508647926 +qdivz:418/1515977,194,736/128183:209/147049769 +qdivz:2/2337,714,=1:1/834309 +qdivz:765/922036,-964,997/935249:-765/888842704 +qdivz:-574/71689,948,617/3930:-287/33980586 +qdivz:-407/558,960,817/20918:-407/535680 +qdivz:6/215,99,-59/760:2/7095 +qdivz:-916/8789,71,-23/237:-916/624019 +qdivz:192/103,-275,241/262:-192/28325 +qdivz:-641/520,803,-980/299:-641/417560 +qdivz:-808/23,85,419/23:-808/1955 +qdivz:30,160,114/25:3/16 +qdivz:99,883,92:99/883 +qdivz:249/7,435,=1:83/1015 +qdivz:8669/47763182821761519000,2612,2570/33173836138961742453:8669/124757433530441087628000 +qdivz:6761/57372086615909714512,8060,=1:6761/462419018124232298966720 +qdivz:1411/382658058312182873,825,-3109/4771378321641389271:1411/315692898107550870225 +qdivz:761/867527777386531139,5053,2023/1270134890218434390:761/4383617859134141845367 +qdivz:-9176/793276121303032795,-6985,=1:9176/5541033707301684073075 +qdivz:1369/360850321203415946,4395,-8748/566863280507933113:1369/1585937161689013082670 +qdivz:-6215/67983977826422952,-2039,922/49515404491925443:6215/138619330788076399128 +qdivz:-316/10499786595298753,2815,8687/66197583183800979:-316/29556899265765989695 +qdivz:1606/5305463362124029,1731,112/3026842383841497:1606/9183757079836694199 +qdivz:3055/1662027684799994,-4034,124/192242800980443:-3055/6704619680483175796 +qdivz:-5787/765368742920927,2169,7724/706366155708607:-643/184453867043943407 +qdivz:192/253214519977831,2403,=1:64/202824830502242631 +qdivz:-9511/57149625422873,1022,8816/23226399448707:-9511/58406917182176206 +qdivz:4230/77042165665729,-418,9283/86186701790732:-2115/16101812624137361 +qdivz:1097/8661587667062,8556,-1294/1841284483249:1097/74108544079382472 +qdivz:5073/8529249706045,4830,-1957/777278713702:1691/13732092026732450 +qdivz:3288/146119907411,9777,3763/497379016899:1096/476204778252449 +qdivz:8321/215917327006,6435,4949/764334137352:8321/1389427999283610 +qdivz:6030/96286272709,3144,=1:1005/50454006899516 +qdivz:9082/62592066789,7051,8147/63758112020:9082/441336662929239 +qdivz:4051/1918506696,-1174,7400/4885927323:-4051/2252326861104 +qdivz:-3965/8753839922,977,5991/7987170626:-3965/8552501603794 +qdivz:-5834/689611533,6425,-2453/364281564:-5834/4430754099525 +qdivz:1124/704967041,-5270,=1:-562/1857588153035 +qdivz:7944/57190105,7680,-9489/89859484:331/18300833600 +qdivz:6843/70048130,4671,=1:2281/109064938410 +qdivz:2533/9359236,1758,=1:2533/16453536888 +qdivz:1385/626883,5784,157/3146564:1385/3625891272 +qdivz:4688/160917,3538,9758/811127:2344/284662173 +qdivz:9463/781649,3734,5600/250357:9463/2918677366 +qdivz:691/30478,8036,-841/15767:691/244921208 +qdivz:7469/16264,-5140,=1:-7469/83596960 +qdivz:7515/3959,6138,-6065/3429:835/2700038 +qdivz:13/274,3740,4679/7583:13/1024760 +qdivz:1229/24,-7646,-6995/619:-1229/183504 +qdivz:687/823,6221,=1:687/5119883 +qdivz:449/4,7444,1039/12:449/29776 +qdivz:-994/3,-6901,-48:994/20703 +qdivz:1612,1197,=1:1612/1197 +qdivz:4205/3,3230,263/3:841/1938 +qdivz:2417/5769966068557054097,-28966,58670/6149020325783377203:-2417/167132837141823628973702 +qdivz:30796/2288360383424599467,99939,-42281/20938438853892364104:30796/228696448359071046132513 +qdivz:8506/579725899434273775,77119,-37442/962475407368879243:8506/44707881638471759254225 +qdivz:-61035/3482034023582042798,77561,-12752/1085806378725747165:-61035/270070040903046821455678 +qdivz:6403/315592922992076985,33571,65893/416723435457372548:6403/10594770017767016463435 +qdivz:42598/69939063133387941,43735,4765/30061903416091521:42598/3058784926138721599635 +qdivz:-8062/70710522833104625,3389,=1:-8062/239637961881391574125 +qdivz:29201/20949143115498720,38501,-83185/22636843869370839:29201/806562959089816218720 +qdivz:90114/2645706758131727,2395,39560/6948564113170771:90114/6336467685725486165 +qdivz:28967/9011742303197945,68899,70841/1427120257870104:28967/620900032948035212555 +qdivz:9374/952169153467751,15363,23536/955542414786031:9374/14628174704725058613 +qdivz:51148/254739984446201,82728,52657/828166332061258:12787/5268532358316329082 +qdivz:81421/51545697474492,-58001,7295/10940115310379:-81421/2989701999218010492 +qdivz:30074/21203238537003,-89481,-39057/81001965285511:-30074/1897286987529565443 +qdivz:68431/7698279661359,47986,=1:68431/369409647829972974 +qdivz:-65063/7943806973855,-56338,70937/1359955225665:65063/447538197293042990 +qdivz:64467/215908405691,30481,-35757/415900569994:64467/6581104113867371 +qdivz:-89549/201351835302,99827,23735/207632772853:-89549/20100349662692754 +qdivz:7871/103822521,-89272,22388/34036415431:-7871/9268444094712 +qdivz:-5548/6399177947,10277,9825/12940044851:-5548/65764351761319 +qdivz:9159/2485995284,50120,15415/595065179:9159/124598083634080 +qdivz:9078/1432788533,-52955,96908/495178011:-6/50147598655 +qdivz:47557/12504243,-82563,37658/472974143:-47557/1032387814809 +qdivz:96527/90426700,48323,75980/494535141:96527/4369689424100 +qdivz:-33033/11045147,3862,=1:-33033/42656357714 +qdivz:22621/19382503,89975,19721/94899651:22621/1743940707425 +qdivz:-3547/8566286,16505,-23598/8026213:-3547/141386550430 +qdivz:-74521/2199771,-55243,49586/7659031:74521/121521949353 +qdivz:-1886/42955,-46801,=1:1886/2010336955 +qdivz:16475/254131,5428,8394/88357:16475/1379423068 +qdivz:23/68130,-87120,49568/89377:-23/5935485600 +qdivz:46067/8205,87890,=1:46067/721137450 +qdivz:-17041/835,61576,25568/1097:-17041/51415960 +qdivz:70979/7890,-71592,-52925/7919:-70979/564860880 +qdivz:69860/859,77846,72800/971:34930/33434857 +qdivz:-2713/19,33421,2857/197:-2713/634999 +qdivz:23292/25,-64396,2263/19:-5823/402475 +qdivz:1446/19,14512,=1:723/137864 +qdivz:-4428,48879,-30206:-492/5431 +qdivz:42445/8,-64598,-238:-42445/516784 +qdivz:725105/89205530254624460472,498415,343423/44377628962630043366:145021/8892274872371730093230376 +qdivz:48277/129907785767997567,633952,44806/4308907194103851519:48277/82355300603193593594784 +qdivz:40582/400024522521846161,924653,693295/4356572124867623097:40582/369883874823392618307133 +qdivz:931685/4908062338032376156,-81098,140947/4372557097040418764:-931685/398034039489749641499288 +qdivz:766956/116055603158859563,-526495,91809/510346928234219477:-766956/61102694785123765621685 +qdivz:741603/132214366402214038,479618,515977/280622060822043768:741603/63412389985097092477484 +qdivz:-516699/76045719725268866,99626,233591/68059428628090678:-516699/7576130873349636044116 +qdivz:220269/518413710467221,624520,163971/21127267464610397:220269/323759730460988858920 +qdivz:-28142/1957881267309015,181534,320653/2331263900982418:-14071/177711008989837364505 +qdivz:-690794/3288684236568943,143025,2357/9370516939377:-690794/470364062935273072575 +qdivz:-859112/140095463625325,816822,612219/121557578324606:-429556/57216528394682608575 +qdivz:220971/363994210767806,-560494,110590/4404890122781:-3027/2794747550275214468 +qdivz:-18965/505806570474,717219,-43623/93798137994313:-18965/362774082668791806 +qdivz:-173609/8550763730716,-693162,-19411/825399841571:173609/5927064489110563992 +qdivz:183202/1439642401317,469971,=1:183202/676590178989351807 +qdivz:455279/3670831046834,369898,=1:455279/1357833062561802932 +qdivz:-278149/271832786844,243731,780869/789593611916:-278149/66254076970274964 +qdivz:-106981/327902270288,456307,146862/152267328143:-106981/149624101248306416 +qdivz:-177325/26201489293,232388,327906/60969287669:-4325/148510041312724 +qdivz:387294/30547191461,840749,353120/74968646269:387294/25682520673644289 +qdivz:302341/5821897743,177341,-55465/623909789:302341/1032461167641363 +qdivz:998005/7400105717,957579,-133949/4820770760:998005/7086185832379143 +qdivz:-143240/188037809,86894,60337/619625170:-71620/8169678687623 +qdivz:-288213/115013614,232366,=1:-288213/26725253430724 +qdivz:227311/82086188,230582,831983/50818067:227311/18927597401416 +qdivz:379211/28238460,-975706,454719/36515711:-379211/27552434852760 +qdivz:281082/1807583,231844,196945/2033663:140541/209538636526 +qdivz:14670/147551,989329,416446/5701543:14670/145976483279 +qdivz:691512/671245,324873,482828/621975:230504/72689792295 +qdivz:-112163/289428,737146,786171/133222:-112163/213350692488 +qdivz:10835/598,235729,106069/97042:10835/140965942 +qdivz:584561/52856,65410,-46519/23887:584561/3457310960 +qdivz:352640/4817,820728,289214/4691:44080/494180847 +qdivz:320159/3132,320681,-404140/371:320159/1004372892 +qdivz:-180226/529,-13347,343684/89:180226/7060563 +qdivz:-95731/17,317981,-401174/3:-95731/5405677 +qdivz:-35074/93,-199642,705874/89:17537/9283353 +qdivz:-483824/3,208717,=1:-483824/626151 +qdivz:-33504,640890,558617/2:-5584/106815 +qdivz:29565,707439,781129/7:9855/235813 +qdivz:531715/4028736917662068622,-6375863,3168443/14968317395104615452:-531715/25686674650055629830470786 +qdivz:9312820/86437123986635347829,-3647798,-9921787/17852839666224243529:-423310/14332053091100020388178661 +qdivz:4905097/1681959789098950192,8490550,5024043/8545615644430661068:4905097/14280763687334091552685600 +qdivz:9734997/1577074521689225743,-6832621,-1088972/709315347360105245:-9734997/10775552495458759285362403 +qdivz:-5219429/637213619457793955,922999,4000516/81347433120051823:-5219429/588147533545924362671045 +qdivz:-7759663/763271482741194316,5893021,-7904753/307331388791664740:-7759663/4497974876494995669268636 +qdivz:-7637867/8373635589819800,-9864736,=1:7637867/82603704453776614572800 +qdivz:-1227995/24598537455164863,6580218,6299290/38542781724475047:-1227995/161863738936150024480134 +qdivz:6988198/9489671176695433,-7796211,2820841/7357436554413976:-6988198/73983478814135878404363 +qdivz:4655307/6278254340914480,9462770,-6281733/6153291637649389:4655307/59409676829575313909600 +qdivz:-3031228/480320878032225,-727330,1226393/130648347238455:1515614/174675892109589104625 +qdivz:805552/214495438615263,1327196,-4903014/270461362054651:201388/71169372037105648137 +qdivz:-8334607/59169490017165,4126493,=1:-8334607/244162486369401252345 +qdivz:-2740096/62311500192201,5879218,=1:-1370048/183171446768495789409 +qdivz:6018950/576700070291,4317824,7475008/942911804001:429925/177863528878869056 +qdivz:2223856/5382329849761,-3906006,252260/533340995361:-1111928/10511706343572782283 +qdivz:2243556/156929905105,-3830812,-2435277/814377058247:-560889/150292240908773815 +qdivz:857583/89117603081,-2195895,-4700762/733917585385:-285861/65230966339184165 +qdivz:3208465/408709893,1515642,31276/1253645275:3208465/619457879646306 +qdivz:-4098989/29766939365,4871162,4547567/76483554090:-4098989/144999583891092130 +qdivz:344051/517335170,-8077846,=1:-344051/4178953833643820 +qdivz:-4130140/2212436731,2194454,=1:-2065070/2427545317044937 +qdivz:5542680/216220363,6891467,6087552/929545577:503880/135461408758411 +qdivz:6509555/836740618,6251993,662482/133872459:6509555/5231296486551674 +qdivz:1638179/17457984,-269806,4370443/34189662:-1638179/4710268831104 +qdivz:2432741/2349231,8748014,-5489595/31977161:2432741/20551105677234 +qdivz:4969351/8828308,4450547,-456455/409972:4969351/39290799684476 +qdivz:129047/5679221,7992010,=1:129047/45388391024210 +qdivz:1678079/404405,9368845,2425353/203762:1678079/3788807762225 +qdivz:7313393/106210,5702,=1:7313393/605609420 +qdivz:9380792/29837,3628650,8349541/69163:4690396/54134015025 +qdivz:141835/4553,1259021,651103/91477:141835/5732322613 +qdivz:3409832/4613,-6381406,6023255/7573:-1704916/14718712939 +qdivz:2693799/5507,-7732579,-8350784/4419:-2693799/42583312553 +qdivz:-3649678/783,4922666,1776512/359:-1824839/1927223739 +qdivz:1703289/146,-1364856,-1170358/5:-567763/66422992 +qdivz:6835207/52,5452267,85397/24:6835207/283517884 +qdivz:-981009/94,-4341899,1154647/19:981009/408138506 +qdivz:868414,-9170184,=1:-434207/4585092 +qdivz:-5109118/5,8155944,7055834/7:-2554559/20389860 +qdivz:4096180/71083460296902382853,39235251,45336611/9448238468873105562:372380/253543400608863592157777373 +qdivz:723497/26326545620806342541,54557113,2864637/65009482842561827395:723497/1436300324333986781126044133 +qdivz:-63087064/6014746604181337631,-68334633,56994111/8777928731228646479:63087064/411015501784727972463474423 +qdivz:-15440050/5936703417482625609,25638172,511239/234669451493331560:-7720025/76103111665203681187573374 +qdivz:55799712/219797647434406031,-82812681,79904323/310979304902953074:-6199968/2022448051281770563297679 +qdivz:11215136/271404723528588829,58952266,-21266387/195173683249926450:5607568/7999961727556913625918257 +qdivz:-22341476/2415590020263023,76303502,87999410/29375584889000487:-11170738/92158988971159808003273 +qdivz:-9005355/4510812860318998,21169081,-4695729/14923894399821824:-9005355/95489762815934554500838 +qdivz:41169514/1040429180028139,-24136462,-77184226/2867050860263675:-20584757/12556139683720167952109 +qdivz:28884631/4498836022940958,-17445318,1608549/1242177333646205:-28884631/78483625050060307534644 +qdivz:-517692/132391467827,83742505,2257283/308472757896032:-73956/1583827593779983805 +qdivz:-87141668/980473328502441,-93910964,=1:21785417/23019298863988227665781 +qdivz:75617477/37806359301546,65166173,-65048788/54754409331605:75617477/2463695750744705803458 +qdivz:-24133097/22580980458390,10165227,24383811/20074325876549:-24133097/229540792242098404530 +qdivz:16320192/467694969529,70126387,=1:16320192/32797758431143861723 +qdivz:44162765/6257622442932,44975330,12453293/412188313732:8832553/56287726877254573512 +qdivz:15976849/142509128422,56335860,17374141/76416816576:2282407/1146910615357687560 +qdivz:94840195/85872967721,98955334,4372523/2906959178:5578835/499858129553104342 +qdivz:1591668/9284581411,-66619034,59299561/82774915363:-795834/309264922347588487 +qdivz:1206823/809723910,99568171,1851220/576842863:1206823/80622728733668610 +qdivz:-85914081/8902612534,-35845304,-66045896/1499799717:7810371/29010622970494576 +qdivz:13440820/2754320367,47651570,48865911/5397347182:1344082/13124768977052619 +qdivz:15805143/461814313,31959348,=1:5268381/4919761446849308 +qdivz:-4439951/41512358,63826,=1:-4439951/2649567761708 +qdivz:87711692/59173359,-37321151,18983077/41260334:-87711692/2208417866416209 +qdivz:-79532127/7010743,44205966,=1:-8836903/34435185188082 +qdivz:-31040649/5929246,53863539,27344212/5421485:-10346883/106456724387198 +qdivz:15254977/1604492,31565106,47169776/1230755:15254977/50645960056152 +qdivz:-1314702/219071,-5786594,-13876970/230949:657351/633837467087 +qdivz:8333867/53036,72209074,=1:8333867/3829680448664 +qdivz:93469648/41061,-48263567,-83507719/46190:-93469648/1981750324587 +qdivz:78818449/16510,17504351,-32862423/35033:78818449/288996835010 +qdivz:-32873138/4311,1836189,-5349604/6389:-32873138/7915810779 +qdivz:26267095/2366,-19100210,37380469/1095:-5253419/9038219372 +qdivz:17021179/187,-47068270,11903833/362:-17021179/8801766490 +qdivz:59271380/219,18844882,10502917/263:4233670/294787797 +qdivz:71210549/59,6207655,57674913/28:71210549/366251645 +qdivz:-88171581/4,-27356653,40019704/81:88171581/109426612 +qdivz:70970263/9,44199944,72907200:70970263/397799496 +qdivz:45786297/2,18148519,62016757/7:45786297/36297038 +qdivz:96846563/1680143679448519441,128223531,=1:96846563/215433955166221295447166171 +qdivz:641178113/23637084788031433889,-195838510,-844127047/52534148496309477764:-641178113/4629051465631741845985265390 +qdivz:432203304/1867790824623873113,-180265683,581867535/6107364102548849006:-11082136/8633297146203992431289261 +qdivz:791492251/9077194570872541382,410301713,-39018983/764723471732454519:791492251/3724388481663303633697987366 +qdivz:401598712/629101484430298745,-116768810,-611873995/55698849613345913:-200799356/36729715853079756199071725 +qdivz:94055155/646161833837700334,-56357955,=1:-18811031/7283271910828518545411394 +qdivz:-31209883/602537298237104,372029853,=1:-31209883/224161862490166960265712 +qdivz:223196803/16862631810833754,64519940,21514940/2113398483862313:223196803/1087975992677085158054760 +qdivz:496016327/1750744187829919,571978386,-693142337/5039438258199861:496016327/1001387834853837912130734 +qdivz:839316921/1836121482811279,660441273,801742057/6619092013304984:279772307/404216803163509573839389 +qdivz:-526011832/776825418638849,171589931,-366007747/149875306848853:-526011832/133295419983286213829419 +qdivz:-874798883/297936367252434,15988665,127117837/184563922509306:-124971269/680514966759448237230 +qdivz:200287712/43891754665843,496594818,=1:100143856/10898208959992477700787 +qdivz:-120118254/85593269819273,351399480,-442093373/20946701297219:-20019709/5012905084332037696340 +qdivz:943959960/9218804756549,151648398,=1:52442220/77667609600301992139 +qdivz:62828073/540741708646,-657515815,53734217/983237183903:-5711643/32322384114987930590 +qdivz:45950159/229199443824,6790963,402982057/868439427968:45950159/1556484942629362512 +qdivz:259555952/42104910479,-302245151,-940909904/528170775119:-259555952/12726005025566837329 +qdivz:869315042/36645934999,382102853,163056126/74033612173:869315042/14002516313970452147 +qdivz:-77018238/88942920247,19547868,-610583685/26308049452:-12836373/289774077420480566 +qdivz:22065750/1532507797,132662602,274310661/2637894122:11032875/101653235967653897 +qdivz:648770433/2675318534,168008014,=1:648770433/449474953714731476 +qdivz:166804597/152419962,935573693,-497815717/166801044:166804597/142600106735259666 +qdivz:933126893/254794607,178086796,-10735069/659294666:933126893/45375555198709172 +qdivz:51397159/9285767,107706490,=1:51397159/1000137370527830 +qdivz:178105895/27030313,-834305485,216521075/14478702:-35621179/4510307679433361 +qdivz:401130268/4003281,538052518,=1:200565134/1076987711155779 +qdivz:-25708379/923800,928600130,113823997/4498353:-25708379/857840800094000 +qdivz:332976289/259940,255080279,848673264/268067:1184969/235962874460 +qdivz:-936148364/84001,-905995411,-39958671/407233:936148364/76104520519411 +qdivz:854254667/15661,-901412190,834007367/56:-122036381/2016716615370 +qdivz:42260654/5561,616640749,207309077/42644:42260654/3429139205189 +qdivz:664619865/9433,509452304,203966830/4141:664619865/4805663583632 +qdivz:259028563/2828,364316648,406720073/2225:259028563/1030287480544 +qdivz:130594031/195,97865363,=1:130594031/19083745785 +qdivz:295389723/478,-625249910,939847596/815:-295389723/298869456980 +qdivz:665547887/87,961350652,72648508/67:665547887/83637506724 +qdivz:434992091/6,68620494,=1:434992091/411722964 +qdivz:222412585/2,301910131,=1:222412585/603820262 +qdivz:-448528340/9,676248718,364885727:-224264170/3043119231 +qdivz:-7851824870/97663123831315122169,4309784371,3802633873/30968200362702972301:-7851824870/420907004711239553899911820699 +qdivz:-6597972451/80277297254646055387,-4726423861,614506788/44782747244718572081:6597972451/379424533240948909290644389207 +qdivz:-631085275/2899211669922691298,6256200760,1109385858/1477376676238012019:-126217055/3627610050554242087958597296 +qdivz:8122235215/7961846503387897018,-3385709171,170279399/599714842989628708:-8122235215/26956496724614685504246152078 +qdivz:8261293608/498905904925989803,9279441956,-5669550521/863022032183383926:2065323402/1157392096566594213196593667 +qdivz:4361752127/48434501579131773,4643568393,2837826733/313554877060481877:4361752127/224908920663564889484850789 +qdivz:1238532920/10342162106427481,4398535564,97283990/2793043923274571:309633230/11372591958443607041358571 +qdivz:1061671387/8926232998705307,-2409354436,=1:-1061671387/21506459072200213677191852 +qdivz:-478800359/400345400504704,4108770541,=1:-478800359/1644927387818574327124864 +qdivz:2240956275/37562621401834,-2396455893,4846367786/7863206958381267:-746985425/30005721804984336769254 +qdivz:-259707383/982049805001181,4636408668,6879601421/49291522336164:-259707383/4553184228315185338636908 +qdivz:5932730501/332075016507041,-3894649593,2459475717/779834134547543:-5932730501/1293315827884615512284313 +qdivz:-2057182763/13014783789192,8587041446,-4768423874/14397276670449:-2057182763/111758487808520630851632 +qdivz:544766933/18794715195475,3843484670,1238159/14363532070842:544766933/72237199730824215868250 +qdivz:8675465767/2586185536443,5059401119,646332059/108654428878:8675465767/13084549997021329479717 +qdivz:3854967983/5468883986994,6390198126,-6884594048/8486977568151:3854967983/34947252205000467173244 +qdivz:541574464/220372973361,2389280993,-4542506150/573414247061:541574464/526532956622332627473 +qdivz:144295607/6358031172,-2226616241,1616092046/415267417411:-144295607/14156895468359464452 +qdivz:1715167848/17579438791,7716353084,2811755179/17556657680:428791962/33912289182480520361 +qdivz:-1808697444/20783950595,5667762702,=1:-301449574/19633083330425284615 +qdivz:5251262150/9823505053,218984165,-2695819927/4710996795:1050252430/430238410280897149 +qdivz:122042670/3353616721,1385474924,1555979149/4749223195:61021335/2323175935826302102 +qdivz:2041370077/380755116,8288872003,=1:2041370077/3156030421011417348 +qdivz:3260509647/206408810,9791591411,=1:3260509647/2021070731150730910 +qdivz:7724750931/66875293,8447158841,-620411053/9335500:7724750931/564906222509415413 +qdivz:706240133/12748079,-3365211444,-4450693274/12511769:-706240133/42899981339816076 +qdivz:-4328713944/3919369,-1733697840,45793219/349446:3403077/5341982365930 +qdivz:818576409/220484,9554360290,204076967/1272406:818576409/2106583574180360 +qdivz:2094971528/577573,5542056593,1522762903/828023:2094971528/3200942252588789 +qdivz:299769258/28325,3451090138,379284289/47694:149884629/48876064079425 +qdivz:2123785501/46271,2031913159,7477551790/28249:2123785501/94018653780089 +qdivz:6633067290/30347,4413188467,5089795320/58789:6633067290/133927030408049 +qdivz:-7112896220/5109,-9041858703,430997275/23:7112896220/46194856113627 +qdivz:563583963/22,342636729,1107784533/167:1479223/19784798 +qdivz:1874300309/184,5945511402,1330452647/672:1874300309/1093974097968 +qdivz:6102614776/341,4776190614,2538216797/925:3051307388/814340499687 +qdivz:283161881/17,-4413775423,9396385745/58:-283161881/75034182191 +qdivz:7062815342/5,5942475325,289745847/4:7062815342/29712376625 +qdivz:5072516583/5,3510162870,318579195:1690838861/5850271450 +qdivz:2105745668,3143294016,1921002976:526436417/785823504 +qdivz:-1047110342/1520484401571884685,33570074404,-12800824587/53544087850846460:-523555171/25521387245444791714979051370 +qdivz:29090953702/20807090234619537879,26907026532,343923157/1724556694370271427:14545476851/279928464498313005317916002814 +qdivz:20274428231/782012114750379463,-88508960784,2548101185/1234460670163112687:-20274428231/69215079597054243839785978992 +qdivz:364228775/25798969587651672,93590422630,4800580791/290037163980705493:72845755/482907293425367362341227472 +qdivz:30300488563/217177830796613151,808037800,26450907691/304742055273554844:30300488563/175487896605667537985107800 +qdivz:84660469437/541808431985810570,-91050654470,6869670021/226059831962560205:-84660469437/49332012329672534151943747900 +qdivz:13781377279/60189448291173846,-36341022321,81142451811/20267863492743986:-13781377279/2187346083838224044777416566 +qdivz:20924076749/75205484440042707,-68511555523,28223428025/76572972653264741:-20924076749/5152444722848098485121720761 +qdivz:46695010459/6765513820287504,19044605306,=1:46695010459/128846540399663729123896224 +qdivz:-66175030565/5858633997091474,93479386801,-6761739565/4747871813360411:-66175030565/547661513539602607025234674 +qdivz:29131927391/449117587317440,27430643163,35826296405/904412982359957:4161703913/1759940610847455863808960 +qdivz:12733873489/203020759589798,68338967211,-7646512609/133308860316557:12733873489/13874229032759519332113378 +qdivz:-645828418/378314206231,91802202116,11814523540/19896454006763:-322914209/17365038611886184292398 +qdivz:55466225485/59966137745571,70085230918,-14564033191/25111688968965:55466225485/4202740611158939466764178 +qdivz:-14856273101/1292859110750,39649293376,=1:-14856273101/51260950175961225392000 +qdivz:54049381867/5879084180264,10563421937,-8536204093/2085088741998:54049381867/62103246799270400051368 +qdivz:10813111460/44728598989,94458376818,34307963680/466563642229:5406555730/2112495428922087918501 +qdivz:93261299995/267442344697,9903554506,31033940419/872316913124:93261299995/2648629837919179554682 +qdivz:12549853509/27452668204,73694908624,84554555332/43906568651:12549853509/2023121874778770191296 +qdivz:8281869761/28644261980,6672638864,60920170655/80750564561:8281869761/191132815718345590720 +qdivz:43507585065/1174891541,-53678216040,32027177949/130065692:-2900505671/4204405464091101176 +qdivz:25929389985/1191490339,67589366380,-51298542/1154628703:5185877997/16106415412180280564 +qdivz:78073658759/979680027,6317031065,86759420379/440052299:78073658759/6188669164319038755 +qdivz:-1688695990/26584499,18370342534,=1:-844347995/244183176362390233 +qdivz:1093701401/17134573,60199324609,4846366/2474809:1093701401/1031489722063606957 +qdivz:-49418541321/28244834,85425839011,83976874051/40710896:-49418541321/2412838642176419174 +qdivz:79131936038/3214193,-5558256386,-26510849221/5257598:-39565968019/8932654384043249 +qdivz:-44020502387/1517047,10832005700,-20237312053/142503:-44020502387/16432661751167900 +qdivz:99090532609/635608,91162874201,92103313957/556384:99090532609/57943852145149208 +qdivz:-10413698662/166089,-12227395873,-37758281071/634722:10413698662/2030835953150697 +qdivz:2134574971/96453,42160589664,-2962999062/10723:2134574971/4066515354861792 +qdivz:37471609877/76548,-10791609390,96390037129/790:-37471609877/826076115585720 +qdivz:34436605878/9079,25235264504,-5473970461/203:17218302939/114555483215908 +qdivz:-14044198283/2389,54080143852,-29150502929/8884:-14044198283/129197463662428 +qdivz:-32522069000/223,48339047086,=1:-16261034500/5389803750089 +qdivz:-47657246803/22,33211359811,15968947072/113:-47657246803/730649915842 +qdivz:40172527838/11,-82213794272,61587574503/76:-20086263919/452175868496 +qdivz:27802957568/21,79643351356,9332219979/56:6950739392/418127594619 +qdivz:10869296351/9,8043862316,13139931706:10869296351/72394760844 +qdivz:6168104465/3,-35878945212,9249477620:-6168104465/107636835636 +qdivz:855395000587/50302555595400936176,-739889806971,934181630371/48600397687605686625:-855395000587/37218348149629194642613330882896 +qdivz:484488645113/10462406400933872953,705670704066,-83884715081/4591650339979326617:484488645113/7383013691171631206651704526898 +qdivz:-60021930656/539548570059923399,866917492648,964805949204/3786090076085699239:-7502741332/58468011689770319521503208819 +qdivz:-323220399515/1857859825012903162,-788928410025,301006918611/23405385204846061:64644079903/293143679559350883341190999810 +qdivz:392310421262/286746574017601209,468810964000,-451125775206/166219155256444865:196155210631/67214968894444487879427738000 +qdivz:36808331478/114061000248894023,792934455019,322932243230/14273224315648399:36808331478/90442897071278805484991451437 +qdivz:-854660221869/89384740128760649,-840396118326,47272992199/15238716217232049:284886740623/25039529547262898284245517858 +qdivz:364501470786/21056530096076939,437727978403,-169280538543/19694582326526369:364501470786/9217032351137685869618348417 +qdivz:71356988859/8140449733588631,579541019218,69993159032/6814665237998029:71356988859/4717724535496851778477310558 +qdivz:-237216301461/7153189855202122,-161521837361,-24951260167/8892014308929978:237216301461/1155396368404312289466080042 +qdivz:431477529919/178167681211025,-114268327380,=1:-431477529919/20358922925156879565364500 +qdivz:136650073403/64126482201233,196314646772,114459442486/14287429741873:136650073403/12588967702066001417869876 +qdivz:254431970614/7700634905305,510462127446,-344404274238/84068115219161:127215985307/1965441238223458525750515 +qdivz:557911675619/47397240043195,418224715021,-700096857791/79702988081428:557911675619/19822697209847158605332095 +qdivz:509038039199/6767048040929,-112750471412,-57732832309/349479521105:-509038039199/762987856682395820421748 +qdivz:314926419471/416369156102,370112646694,101848419292/3456057303355:314926419471/154103490366658460226788 +qdivz:669453679465/415999590924,504198456391,-678536387896/77061621151:669453679465/209746351603168253395284 +qdivz:996528817883/413322921728,812027139903,=1:996528817883/335629429987139374512384 +qdivz:492391623289/48007797318,7318358317,3301219779/801312566:492391623289/351338262783035593806 +qdivz:477172365974/23061409419,-801074911982,627397031659/99184274295:-238586182987/9236958260253145379229 +qdivz:156485412607/5990175067,451647154411,916340057749/8763032403:156485412607/2705445523434271270537 +qdivz:-4814205663/243854698,67090415688,2686305709/2020120843:-1604735221/5453437685430567408 +qdivz:-549975755753/904821260,98226499545,752428923516/928266565:-549975755753/88877425083696326700 +qdivz:-309048114689/24846497,-1027875635,-731863243448/852411331:309048114689/25539108881400595 +qdivz:735435298793/17969395,-793419545872,=1:-735435298793/14257269220494587440 +qdivz:112260296237/20255278,879986635350,=1:112260296237/17824373935298877300 +qdivz:849848647754/9226151,940056683244,3943593549/6913084:424924323877/4336552454084156922 +qdivz:156304200464/4695153,280896701707,=1:156304200464/1318852991709726171 +qdivz:12581766711/139577,982981763154,=1:1397974079/15244627283971762 +qdivz:863623603829/424182,672081287592,=1:863623603829/285084784733349744 +qdivz:190774034338/47111,-939969971749,-882099739304/68161:-190774034338/44282925339067139 +qdivz:-293504193833/44336,348399896607,119682154283/44562:-293504193833/15446657815967952 +qdivz:608003901167/1524,473035881782,-7627832953/121:608003901167/720906683835768 +qdivz:66826129837/54,-738128447998,=1:-66826129837/39858936191892 +qdivz:221009262571/863,-39203245082,38984729793/29:-221009262571/33832400505766 +qdivz:828342264708/529,709893608236,400041569779/479:207085566177/93883429689211 +qdivz:221541593/3,-88280231556,238738747697/64:-221541593/264840694668 +qdivz:11413495397/83,431669407366,283046372607/77:11413495397/35828560811378 +qdivz:148010319127/2,283123647274,766433621663/4:148010319127/566247294548 +qdivz:-219763168201/9,403340924550,-394706926259/3:-219763168201/3630068320950 +qdivz:377661739960/407441308456322857,3965410406437,409422859704/8533399553263788433:377661739960/1615672004565010305438863030509 +qdivz:-1577626903713/27731663323669186172,649610924029,=1:-1577626903713/18014791436549869335907349326988 +qdivz:-1441250962158/8452258866175538849,-2826627450251,8230910671546/264485663157889397:1441250962158/23891386927759171604534865301099 +qdivz:7298594401893/3589655286076871768,1676532872705,4840525305175/826954630150879953:7298594401893/6018175088787146414664952292440 +qdivz:9145310463313/352206858008877943,-9694904568093,-4656627107317/287736322428206292:-9145310463313/3414611876623953391939969272699 +qdivz:3287696310569/218686848623222483,7362954795926,-3636594668023/794551016990788636:3287696310569/1610181380876299151381760004258 +qdivz:599942736859/30109315615210643,190070517001,-686708523847/586022538036179:599942736859/5722893185529369294527641643 +qdivz:6159561616093/1221874427807450,3318286558379,=1:6159561616093/4054529489820493155396123550 +qdivz:-7739149193382/3880813118083787,6945256949005,4243108324360/3938879550941241:-7739149193382/26953244276161183291576281935 +qdivz:1077598865290/1420892515750957,-8741057903714,-2560579494365/3856299969810329:-538799432645/6210051877566485960454677149 +qdivz:9251474975963/380092713862583,-3533706170376,4397319568897/444497940948049:-9251474975963/1343135968291168939649441208 +qdivz:5170689991479/478812422664503,7425515194305,=1:1723563330493/1185142973239084926623751805 +qdivz:7874754009227/86289133604325,567464832332,=1:7874754009227/48966048732851832955035900 +qdivz:82573188125/1723837997186,4858404577211,905066106196/67917513655023:82573188125/8375102415898705337728246 +qdivz:-9462453261891/6333904291327,8882376900652,-1608766513594/2059986591551:-9462453261891/56260125168223520744245204 +qdivz:-8513062446331/9309761450169,55542992537,551347179830/367528742439:-8513062446331/517092010747987064388753 +qdivz:-2148550912058/152802731413,9178119603028,=1:-1074275456029/701220872288938832759282 +qdivz:9881319422543/919461731150,9752261044456,2668885280159/266136830885:9881319422543/8966830822562220870004400 +qdivz:174799529246/781938781,8700555467056,=1:87399764623/3401650867966327149368 +qdivz:-5466205515503/29452452729,-4883930408328,8925441835689/10852340635:5466205515503/143843729483006087927112 +qdivz:996316459693/238035368,996971641405,=1:996316459693/237314511547403212040 +qdivz:1902828237558/232472863,3969221099083,431690216313/4984136728:1902828237558/922736192783831684629 +qdivz:-700150402156/107303867,8389748159752,-2823896211587/556014406:-175037600539/225063105174380840246 +qdivz:3646364186929/738179758,4245401666232,6967936345729/416110377:3646364186929/3133869574591934531856 +qdivz:9885648196055/10155847,7815948425404,9809097272675/14454357:9885648196055/79377576368293937188 +qdivz:1619034630643/74258174,9375949496558,-4811471214059/75060117:1619034630643/696240889130616365092 +qdivz:1807183853299/633460,119735977641,=1:1807183853299/75847952396467860 +qdivz:-57391852197/471910,6490287173297,3578414422277/7633819:-57391852197/3062831419950587270 +qdivz:-8336245595520/207563,8055731289499,3690368841008/41405:-8336245595520/1672071753642280937 +qdivz:-8756280094194/474401,2163225064362,2304316378414/178391:-1459380015699/171039355626399527 +qdivz:-6768110876428/4537,3853268548159,7478518386005/7254:-6768110876428/17482279402997383 +qdivz:7491881449711/45820,9360962689034,=1:7491881449711/428919310411537880 +qdivz:4479515335651/4767,6272480778873,-2550653613043/2315:4479515335651/29900915872887591 +qdivz:7706167334141/6871,-8364277232473,-1312275143305/3942:-7706167334141/57470948864321983 +qdivz:-2426531262302/211,-896936798776,=1:1213265631151/94626832270868 +qdivz:-2687168859651/241,421602999976,4265602937489/57:-2687168859651/101606322994216 +qdivz:4672875535991/32,303500575463,7776212095088/97:4672875535991/9712018414816 +qdivz:712016736313/97,-6773597996516,5238170108147/45:-712016736313/657039005662052 +qdivz:547412039147/8,6440922645756,=1:547412039147/51527381166048 +qdivz:-1428482346861/7,-8578332426693,-208991442483:476160782287/20016108995617 +qdivz:25213882136563/37677676095840232484,64266404189577,-44312529469891/58632890416616303769:25213882136563/2421408760899231901491771289619268 +qdivz:-45348211232/48259765821376689,-86097912542683,25703493789011/20122118862740312269:45348211232/4155065097019252383615533716587 +qdivz:-7699657076461/331713197807190681,69957368331562,36084589185595/8895782428451727263:-7699657076461/23205782359437922808235364573722 +qdivz:4499486281079/570447738950937327,6819787346072,41829452180703/8951562452396016457:4499486281079/3890332271692985934718131629544 +qdivz:9448778776929/55266922938454378,-40211563540804,22791382037077/589181316944364437:-9448778776929/2222369383444376336380695439912 +qdivz:-80693445937604/625638820483329699,65119781059396,28243613851117/411802455862213751:-20173361484401/10185365753033296882775942450451 +qdivz:7104789360034/25829280707927279,61192880702082,50820501919963/43237529502234417:3552394680017/790284046490391045278259947439 +qdivz:8521395225131/866934246203151,-82917276854296,50387683303757/41145275653408716:-8521395225131/71883826906897082331043086696 +qdivz:3654753854813/686472765655654,-56741825130219,4118082438861/3391784320237708:-3654753854813/38951717625490926599463608226 +qdivz:-53486312991974/1510968952191653,-40818569959148,56568646790883/6563654620617722:26743156495987/30837795940567768880638295822 +qdivz:77025810489670/955683320748827,16606084180096,99547352892542/681947908769761:38512905244835/7935078836934353698524373696 +qdivz:74081757285323/779580189169978,71513450124198,62733533615096/994702038569703:74081757285323/55750468976020063538632927644 +qdivz:-90918473901171/23110032090851,57668788153374,33840460487482/35925709609791:-30306157967057/444242514954987040163393758 +qdivz:-12377636482606/6273569332391,52950805470840,6788467435942/28776860168659:-6188818241303/166095274663631704608989220 +qdivz:93826301723233/2510365316368,8687161712184,40792305870208/5978756664845:93826301723233/21807949459946763720227712 +qdivz:754174119367/993972659135,93465132406737,=1:754174119367/92901786194729238278592495 +qdivz:3107915597273/143157120432,-70507843259804,755175597775/219130414:-3107915597273/10093699808944340692715328 +qdivz:44648757800580/573796175549,60618257654342,5117941512382/33291591973:22324378900290/17391262205252667597041879 +qdivz:-66400850026133/11907331494,74065123644406,=1:-66400850026133/881917979378039620722564 +qdivz:62277709926279/87663640784,32094657146865,=1:20759236642093/937844831736137230580720 +qdivz:26142101996176/1749516045,84074622586348,20940287104039/705860031:6535525499044/36772475298033805988415 +qdivz:59312790288505/3662730144,48869114267557,77585738312243/4878987018:59312790288505/178994377938361505138208 +qdivz:73640138898581/622848187,-19896806552263,18788319190513/316012039:-73640138898581/12392689888166730297181 +qdivz:19740823110531/278732932,24473700094823,58579762311988/962128055:19740823110531/6821626184318692811036 +qdivz:-7512635132051/87400601,56390496123957,=1:-7512635132051/4928563251922012298157 +qdivz:-59462887076699/29087597,-98512108079751,-53172761880889/67978482:59462887076699/2865480499444240948347 +qdivz:17522488582105/961216,-76067863891111,-3856252477211/1860688:-17522488582105/73117647857958150976 +qdivz:36565698728205/302902,21351159032601,-36216528579083/54119:12188566242735/2155769591097636034 +qdivz:54644193228042/614773,89311395526262,63456896848754/648461:27322096614021/27453117280933334263 +qdivz:19396300373560/247,-57733371755730,-58481097237257/238727:-176330003396/129637662033321 +qdivz:26129074926522/54241,-57172817810638,=1:-13064537463261/1550555405433407879 +qdivz:-47857708640267/48873,-84095778752769,-78411459424021/96980:47857708640267/4110012994984079337 +qdivz:24471666012555/2128,10834057048867,19163873777357/2355:24471666012555/23054873399988976 +qdivz:63633303713482/2687,29541404498726,953013369111/994:31816651856741/39688876944038381 +qdivz:4028083282444/441,96229912034129,36156251433089/641:4028083282444/42437391207050889 +qdivz:5620157071221/38,1464098099632,45826452102283/555:802879581603/7947961112288 +qdivz:44121126176093/28,49295425845300,-98014359584905/87:44121126176093/1380271923668400 +qdivz:2550244740088/11,7860358429697,32007329912968/13:2550244740088/86463942726667 +qdivz:10610786242282/3,-19942871503520,30442870787715:-5305393121141/29914307255280 +qdivz:-10891422163510/3,65100387657340,=1:-155591745193/2790016613886 +qdivz:28206974750888/38115226610958658587,-233840177846781,184067617831263/10199552995144872193:-28206974750888/8912871369376932568520833775958447 +qdivz:239195932154190/21076639992981349247,-514159353179396,914824331702763/33476179921636595855:-119597966077095/5418375792993139989042719660257406 +qdivz:-66879959134324/1938245828723753153,209078692564075,380314134341760/3263898700497131471:-66879959134324/405245903737334354397466935778475 +qdivz:71631704547265/1127077312973478953,-677425993025946,-808670179854036/6156571467702669689:-71631704547265/763511467958073910363035213914538 +qdivz:369630784942559/118575247636594640,613604398763706,556292057837293/356846295264834699:52804397848937/10394041933472886416968552305120 +qdivz:-86151087673799/115845793068186375,862616462453012,956063729712120/826089658093596013:-86151087673799/99930488206542589968510496111500 +qdivz:305051097653790/20518755287717797,895836082087101,-207160117973632/3362842864667699:101683699217930/6127147115417699363488953945499 +qdivz:-963596685314854/20268707545342331,-188056921260034,-12535707088197/650540922052135:481798342657427/1905835369448549878334199349627 +qdivz:-361781987716599/9794167747947700,61965144850569,=1:-120593995905533/202299007730783467390975747100 +qdivz:189992621219183/1819811590183344,793680743322061,618571148115319/5988770433957028:189992621219183/1444349415602818312690629951984 +qdivz:856347688913222/833832195611433,218162022813457,-653168377938073/524530934347885:856347688913222/181910518481576385943015453881 +qdivz:49096910346166/27167376161979,245243955457352,15314702197043/62138236025303:24548455173083/3331317394680752204689209804 +qdivz:-18418259567905/83404618779589,692976050847437,=1:-18418259567905/57797403344315565768168563393 +qdivz:-505057419418589/56875557275862,337407904218594,63663406245825/3267267474824:-505057419418589/19190262581713202780407778028 +qdivz:107117033307349/8727332158297,-351480699835352,-603596441776797/4327920729574:-107117033307349/3067488814693802582700715544 +qdivz:929542050791479/3668117137877,663512077337021,67789990327315/790180646928:929542050791479/2433840022068296146453444417 +qdivz:198372512149532/147050745673,-256607148991758,-639475502955856/973546370361:-99186256074766/18867136302130312015581567 +qdivz:-186632417034836/209907050713,808174748926739,886289373295672/873782379281:-186632417034836/169641578007931045594714907 +qdivz:-433532847360621/40950919442,-576406278836993,=1:433532847360621/23604367090516689792517906 +qdivz:426046356532532/90956948929,290346527980677,-331137473378042/8913098829:426046356532532/26409034317250907387844933 +qdivz:98321029610961/463670608,840238741926244,-202415965355421/170277763:98321029610961/389594008334096646636352 +qdivz:-8445364920981/3222384187,208373591158613,326878150369073/994641488:-8445364920981/671459765137917540052631 +qdivz:-12366828657410/23205153,25335150548712,=1:-6183414328705/293953022380447956468 +qdivz:182273448529439/333188695,-870663173311865,-167558565067223/158996098:-182273448529439/290095126500339127366175 +qdivz:-841149634523738/46300587,-648674774105803,-8859347501816/2523457:841149634523738/30034022813191079006361 +qdivz:-556504745441829/86432147,-538986011588748,=1:185501581813943/15528572728194123560652 +qdivz:302832240895229/9849955,168669637931783,925930262366551/701582:302832240895229/1661388343494355619765 +qdivz:27790516823081/1265414,-488301813246538,-597901356054121/7828129:-27790516823081/617903950707554636732 +qdivz:-155301832641753/1177,299291205321873,288662739041159/190030:-17255759182417/39140638740427169 +qdivz:372814194432298/771897,-14946141179470,-1945868184959/21200:-186407097216149/5768440769004677295 +qdivz:24153012223489/97155,-97727981983126,=1:-24153012223489/9494762089570606530 +qdivz:488549717772225/7997,385195948307290,57330617868723/9730:97709943554445/616082399722679626 +qdivz:-511124198199268/703,508244053643154,-24599890934580/757:-255562099099634/178647784855568631 +qdivz:-571545380467859/5484,706501320657340,-7318997946516/1867:-571545380467859/3874453242484852560 +qdivz:-284559894164173/378,663811328424393,203252169231125/424:-284559894164173/250920682144420554 +qdivz:-109817805722539/89,-620669084280112,39821179505019/355:109817805722539/55239548500929968 +qdivz:11285503834151/3,347837157467787,135711185047364/3:11285503834151/1043511472403361 +qdivz:483084770349435/13,381226764584849,-76288343397587/2:483084770349435/4955947939603037 +qdivz:465649032901606,218384912976294,72781764311433:232824516450803/109192456488147 +qdivz:2587491587702,-476034210750545,547126738337031:-2587491587702/476034210750545 +qdivz:-8100465584109756/15951781239270673877,4434864932667510,-2144439357097081/43731124302263504971:-122734327031966/1071878715630681611032444680055095 +qdivz:2420885235857233/35605779901295929638,9928092538101335,169386594008780/70879024157212713427:2420885235857233/353497477751334607275098664273866730 +qdivz:-4826446325397187/4335807137383577415,623898962956291,3104677505409659/2952033752437342756:-4826446325397187/2705105576592098688280821859767765 +qdivz:3460717723437681/6443180553972666128,8557703279186741,4156537546937142/3658329170710024787:3460717723437681/55138827355124127379787243357408848 +qdivz:6418458390147775/525897417578055896,8516136495382838,=1:6418458390147775/4478614190664069842626272283112848 +qdivz:4636780176511991/360039743434849768,-1921496410524246,1079563866860541/62772477295468231:-4636780176511991/691815074656134293438079131474928 +qdivz:-1880397818415029/25639914407226400,-6097850633731512,4908502670581090/24912440236773367:1880397818415029/156348368316927228082170198316800 +qdivz:9061727133564523/34045084539204615,5247972528183639,6748794006344619/18625898906279159:9061727133564523/178667668381435363770511716293985 +qdivz:2823293208362365/2802436154127691,4344250613703671,=1:2823293208362365/12174484982434577158035769453661 +qdivz:-226020206421378/2415797606868827,-3145163610465586,3727841238983986/2416072176043039:113010103210689/3799039361686841134188549843811 +qdivz:7567999278230394/732026114358407,-3551640041571087,-7309583636430426/277839170663653:-2522666426076798/866631086410337974581762192803 +qdivz:5055638466899535/704743836609472,2779539095014541,4752310879883735/726255451787449:5055638466899535/1958863045826567351435978332352 +qdivz:9361673562558585/20268733803869,7535815261448418,-312199448698385/81273711157128:3120557854186195/50913811176477152039890776414 +qdivz:213432378367195/87716207315137,-9593838267023732,-844717112346841/14374978538996:-213432378367195/841535106378148359979581831284 +qdivz:1415632181545693/2202115097784,3788146011770250,=1:1415632181545693/8341933525129513693692126000 +qdivz:497714829654563/1407922386147,-4578675319921841,-2297925204832173/1152646493548:-497714829654563/6446419481816736986261136627 +qdivz:7238175376569958/872602199065,-1798229516982452,1067716420123708/311724963591:-3619087688284979/784569515471240189107903690 +qdivz:738345515106893/400467504556,-8952340232264677,-3533763215436655/727067491856:-738345515106893/3585121352751316634695368412 +qdivz:4439193856281818/48510248187,-5941306515090639,9229814236640615/58818462063:-4439193856281818/288214253602086958690421493 +qdivz:1236698199957439/43126617136,4908265726375467,-9469441985248292/19058730389:1236698199957439/211676896783145702292202512 +qdivz:-311681312393881/449133469,8687512018285914,-729773020888143/39573781:-311681312393881/3901852409751943988655666 +qdivz:-6619381459773073/8173378245,7168326441455265,579725052503743/3234923130:-6619381459773073/58589443389648729091709925 +qdivz:-81712138569107/178893283,-9704334752710585,-7534731886719068/64598471:749652647423/15926975259113666967895 +qdivz:-2039906652413491/230491475,2966890829958620,38485631968165/38014698:-2039906652413491/683843043561136512764500 +qdivz:1307529988460267/97135692,-255437889763972,9189367430908049/30495394:-1307529988460267/24812136185243136888624 +qdivz:-2353939854827795/25170878,-7155659041948110,478284130849579/21650202:470787970965559/36022844150894551828116 +qdivz:5285315302178007/3864043,6787737381344610,-6416436174036663/5502097:1761771767392669/8742703038074323619410 +qdivz:-1620957348585296/705477,-6328720613670438,-397716845432416/1806409:810478674292648/2232383416185189794463 +qdivz:244904073732822/142115,9255574655214839,-3718997235951973/328812:34986296247546/187907998875122406355 +qdivz:6808168673302291/647890,7830240386186476,203370328672627/153273:6808168673302291/5073134443806355935640 +qdivz:672164644892723/10287,-2016544002156618,820674735348423/173:-672164644892723/20744188150185129366 +qdivz:-4941575984804663/35536,5225959626506022,-1182801330040787/90307:-4941575984804663/185709701287517997792 +qdivz:2600309343681884/9179,3312191343161384,=1:650077335920471/7600651084719585934 +qdivz:5790050438041746/2783,6180418749108229,-3626128271180059/2055:5790050438041746/17200105378768201307 +qdivz:107486754622047/8,8496429460563751,7528748815319577/995:107486754622047/67971435684510008 +qdivz:257452794220597/45,9163478257322473,=1:257452794220597/412356521579511285 +qdivz:4203249688209209/58,2060439753326067,626942582428365/16:4203249688209209/119505505692911886 +qdivz:543611975572423/6,1815241525016751,1962341163379185/19:543611975572423/10891449150100506 +qdivz:-7648363691373965/3,4559746429342130,=1:-1529672738274793/2735847857605278 +qdivz:-918087881293513,5561326460996979,=1:-918087881293513/5561326460996979 +qdivz:51876939499714691/40566929845814543304,-89899615206821411,90157161726220241/15742168992505626198:-51876939499714691/3646951383260846475079804250453881944 +qdivz:-92711941104471994/57341166703993040251,88283676761336977,-83588601643014818/86753416972940797783:-2261266856206634/123470464058859999703545311456967347 +qdivz:79135269280147891/2531825814704286331,70208234934351669,3930634830491194/3988582117396219449:79135269280147891/177755021611614851116084128823736439 +qdivz:29633672003664449/2815846487521571106,99099377722862940,5605342417119218/208728995495935907:29633672003664449/279048634676497041224317165102211640 +qdivz:2100328802578405/93877410719555637,81107589989236009,=1:2100328802578405/7614170537892827983896229599332733 +qdivz:8852742285354040/39609437377376719,94466432126141813,-67648481041296353/37350723131289264:8852742285354040/3741762227564622406488872518651547 +qdivz:20443075139781274/87402553055221425,-87873934817191987,=1:-20443075139781274/7680406250030691855905267020721475 +qdivz:1452523479130/11854581599599,-35488163365355406,78636907153845391/29302687132551467:-726261739565/210348664217252759959311041097 +qdivz:92799074911223618/6644370845911803,-52469970294585343,-45890868424331740/1359965199072733:-92799074911223618/348629940911201190718038634503429 +qdivz:34907583570918158/2475636741287023,94165624835942786,=1:17453791785459079/116559940305054879266393616133039 +qdivz:15873033385646407/99383771605820,73196542989966161,3460464368471384/198333558453857:15873033385646407/7274548510850381916754430657020 +qdivz:1205053067450735/262488203376077,30733894353467375,53421057721886303/633789433238185:241010613490147/1613456942318361773929214997575 +qdivz:-373343591218193/282481077944,73439972957893897,12246923120614379/86081958852861:-373343591218193/20745402725324078148538907768 +qdivz:98454579819453042/381442416277,-37303102933686841,85678232948136701/93297430238089:-98454579819453042/14228985717655155931079110957 +qdivz:28585002988764732/467382454421,-37834555341081422,-25757017600863353/6081527848100:-14292501494382366/8841603668620894913382433331 +qdivz:-45530451111310855/1372526430242,-40793761192434411,=1:45530451111310855/55990515425596635347551857462 +qdivz:23497143673035545/674205230796,-82036200658508885,23227625077965886/378696171279:-4699428734607109/11061847119719389998528324492 +qdivz:-5439825078047807/781667528452,-36280770053733421,62043822362915397/125125654100:5439825078047807/28359499858237138428340794292 +qdivz:52872401646278523/59676713378,67021996329285655,=1:52872401646278523/3999652464964148140921992590 +qdivz:27899585299889689/9025464642,20767876354773754,31681740022949549/49333571558:27899585299889689/187439733729438364636606068 +qdivz:1612507427821399/412205953,7689706161876916,60532795827702091/8889697996:1612507427821399/3169742656746446428480948 +qdivz:-2370552431010137/60156297,-51229313115187306,69322269011837461/8761285893:215504766455467/280160524987563890033262 +qdivz:-72331493811733128/886163875,-64577202816965274,7822570842692148/107135921:12055248968622188/9537664047490477158046125 +qdivz:4366277947142681/145491389,-13081234312671287,-56811447013180333/377612058:-4366277947142681/1903206949985005846047643 +qdivz:8486006017858987/9980479,-24529516802858110,=1:-8486006017858987/244816327331072506834690 +qdivz:28765525203974723/18854856,63876884071748580,=1:28765525203974723/1204389450901513144104480 +qdivz:50689647321811649/4174791,-88774599859715468,38991799931837226/1986029:-50689647321811649/370615400522941398367188 +qdivz:4028476261308141/506452,20953755384460338,-14414987917829359/8085713:1342825420436047/3537357107323569033592 +qdivz:-15211724165753775/479404,50635361545852096,=1:-15211724165753775/24274794866527678230784 +qdivz:94548235714131649/113748,19684972847420899,15048888921861289/28846:94548235714131649/2239126291448432419452 +qdivz:43163174224614713/12275,-67469365909284359,8363004649561645/2984:-43163174224614713/828186466536465506725 +qdivz:487376363804060/24673,74326537358419014,=1:243688181902030/916929328122136166211 +qdivz:23590462962759737/3701,35930020296127129,-81369453202826375/8982:23590462962759737/132977005115966504429 +qdivz:1287959610890411/751,-2752233067297776,=1:-1287959610890411/2066927033540629776 +qdivz:47419841749950097/739,17294603489855144,13019548234372720/81:47419841749950097/12780711979002951416 +qdivz:41222280346047241/236,-20868388796109651,-65701770111449667/440:-41222280346047241/4924939755881877636 +qdivz:1277752625943784,37792680427691834,-6412847033615904/47:638876312971892/18896340213845917 +qdivz:67522291597229246/85,21305635915392026,=1:33761145798614623/905489526404161105 +qdivz:4778080537828640,39298543484658950,5712499781249450:477808053782864/3929854348465895 +qdivz:5230198800503153/5,64523362154424947,-8862961476704027/2:5230198800503153/322616810772124735 +qdivz:892228662088796613/55871131066606758934,-874654732190677980,-36329885559726251/4321287510517614884:-297409554029598871/16289316393417734432300732645294024440 +qdivz:19014600443315842/3635806154264505107,541063770937137802,551834048493969267/73475868368583023383:9507300221657921/983601494111403049141592316295877407 +qdivz:960011603483042729/5573258293787849080,883388531252731256,=1:960011603483042729/4923352458441350993032321575526844480 +qdivz:-8376282180171729/7720902655804022308,-800983354073748858,=1:930698020019081/687146056191424567616374972113502696 +qdivz:116917619245235244/358157856258765917,570339576544638471,=1:38972539748411748/68090533358253348864814413793930969 +qdivz:320704389821337359/41927154801173284,-360426920157069569,-15910915765693733/13475685473321241:-320704389821337359/15111675275935579272421848412194596 +qdivz:-138439708845709407/32918991643825253,-940108679873295360,=1:46146569615236469/10315809925678866587700717698575360 +qdivz:970565625200394526/38338183236067883,631903906064227282,146768067456204299/9085366117028492:485282812600197263/12113023869138686327460801246292003 +qdivz:-237868081084134539/1372485474016210,-358431791982152326,-311316021142488176/2766391185298279:237868081084134539/491942427921103914038343213204460 +qdivz:332386869754970911/2877063091007380,502102596500253116,-436556878102354567/7463983139447194:332386869754970911/1444580848289849529363513423996080 +qdivz:106788340885301441/156094902691284,997093725815999582,150197112369503143/3864734454843:106788340885301441/155641248105338263941318419043288 +qdivz:17951502946479831/18686629102921,-914598187042218818,-383890255715028479/297113456238268:-17951502946479831/17090757099461910397356724967378 +qdivz:61985927342201863/6333741907873,555288860578968755,-665022931937982622/73070869666115:61985927342201863/3517056327224061861672555508115 +qdivz:985136746217353770/810626219569,-532891374649286107,90081452985518108/33151508539021:-985136746217353770/431975720472878440142083227883 +qdivz:143995044786248406/2685894875017,382397533219560186,365144521255985214/1875114894173:23999174131041401/171179929115593285232696545527 +qdivz:-668702556701908142/4219524530635,393298966987097359,-770735308573122464/4820919926275:-668702556701908142/1659534639075462343835523092965 +qdivz:148895105999031617/190301395132,758758290981884265,977117467972369255/294292572918:148895105999031617/144392761341824589767658397980 +qdivz:-159087329306615872/225087429725,785549672595251591,503557620532730284/373822340619:-159087329306615872/176817356725780450857906942475 +qdivz:-264022644302396773/2278029929,-94916617158321237,547322042930742335/21894307611:264022644302396773/216222894646090709282302173 +qdivz:93285450160979197/42311784283,977744763769178683,521203752538227113/68917709707:93285450160979197/41370125528434282439178039289 +qdivz:535979926641145527/7557767498,-195852721847511858,=1:-178659975547048509/493403111857986544187330428 +qdivz:497372041980721506/7001070781,652079344505507428,-957979276256614831/9655170879:248686020990360753/2282626822855570473874630634 +qdivz:-308477546715083617/648505124,-322354321277070579,43631988559711523/304411310:308477546715083617/209048429091722494191146796 +qdivz:229255530959827383/245022904,-929912624059332484,-557747976237829033/297792845:-229255530959827383/227849891613277913531213536 +qdivz:85541435254879863/96620519,-637208165779243712,-502341106189163895/82331053:-85541435254879863/61567383688628566880926528 +qdivz:-781828043684967758/50968901,-514071001383910979,-568353562372526923/25358389:781828043684967758/26201633976507421681464079 +qdivz:-13517195129753927/89604,354643244723994523,-137336510066384067/3891763:-13517195129753927/31777453300248805238892 +qdivz:-421164540114456588/3586045,-739455098265925151,509210588483978045/6456831:421164540114456588/2651719257861029558117795 +qdivz:-879920640850630235/133271,18621800712996172,-357671116753856630/910903:-879920640850630235/2481746002821712838612 +qdivz:322932399357668253/730313,627619261687036063,=1:322932399357668253/458358505860444368277719 +qdivz:-364883615147378315/33847,666046695114786100,13578684277466669/25549:-72976723029475663/4508736497910033025340 +qdivz:795558880287747297/61163,-462149548616214218,-286678576882420657/73369:-795558880287747297/28266452842013510215534 +qdivz:423565867626533294/3487,663348607243920780,-268080787907842069/600:16290994908712819/88965253594598144610 +qdivz:463684384112493971/66,9600800466060656,494151647146512593/1842:463684384112493971/633652830760003296 +qdivz:272532100018311708/11,236412793340595928,-232492590540804763/131:68133025004577927/650135181686638802 +qdivz:888837359363262418/647,288183337717513478,506854295189807838/361:444418679681631209/93227309751615610133 +qdivz:65038385358943464/19,219207500423093598,-571150506348571411/29:833825453319788/53396698821009979 +qdivz:122838851344159513/4,178669373587933922,=1:122838851344159513/714677494351735688 +qdivz:75127173364928321/3,-719408551485655001,184094967898684200:-75127173364928321/2158225654456965003 +qdivz:332631009005835885/4,255241857170957110,-440453245937965789/8:66526201801167177/204193485736765688 +qdivz:8651470154378974507/17855010711510236057,7926925697505572502,2359552014591739654/44197656807230847567:8651470154378974507/141535343238307746317424286970948104614 +qdivz:-9258523409855044611/72817011870762460894,-9836632014308325438,-2001929228208721648/26641513880861526269:3086174469951681537/238758050051403796832749165221700140524 +qdivz:2243990531384570717/4903143680262418520,513680509693509864,=1:2243990531384570717/2518649344777710905795876032116281280 +qdivz:3229047086296059355/1050027622905630278,8584437716830130217,-3362919728113850665/830531783816835201:3229047086296059355/9013896729784577725673410081197910326 +qdivz:1683852085488062225/4857420952010518,7164575837264288367,7898318645722989656/613199579838648691:1683852085488062225/34801360784195853683892011169044106 +qdivz:2826288843276183739/128602532883722306,3829393882550729957,127913369503544038/812393212269404395:2826288843276183739/492469752705455283388475363583320842 +qdivz:3267515387857773576/19788818533922063,7234907474289428118,8550140884041497495/89127291303108631:544585897976295596/23861711853071649439652573975461239 +qdivz:3591918287029728077/26158481474501713,-158972065062790868,=1:-3591918287029728077/4158467818908295918993227426756884 +qdivz:4798456495725994078/330079170984695,2736684033993685237,416706803708991651/565680585712340:4798456495725994078/903322397187686493123625174447715 +qdivz:7907479278535852409/2240934380307407,8862559007732946109,=1:7907479278535852409/19860413177931857471235489184529363 +qdivz:-333158333301384053/63917873172107,-6335880101587543826,=1:333158333301384053/404975980766949041296129503261382 +qdivz:2512095977043224818/186022607546865,3143294313990366846,1041287894968201417/730622989945241:1256047988521612409/292361902287861129299814743618895 +qdivz:1274272592636105089/26697305210030,-2195064786710266047,681737259161578753/53927973677595:-1274272592636105089/58602314566593376440660512851410 +qdivz:435567843178733800/7824464301393,-1530121566691353530,108560750121051577/2239246150016:-43556784317873380/1197238157536802415656503446729 +qdivz:8594280929749775777/7218293710841,3358259648255124921,-1654228833035760850/3200131211923:781298266340888707/2203718590761007005154646088051 +qdivz:2666142904810159355/7661408856438,74495464765250039,8914192677969935341/9257821421719:380877557830022765/81534316216707374773732128726 +qdivz:-2813129058989480351/107454595872,6627104473551194269,=1:-2813129058989480351/712112833006966892878357457568 +qdivz:7810650428805644969/454117323713,-4146816455262026097,6439502069195252290/747129258447:-7810650428805644969/1883141190592620687327602938161 +qdivz:2811634895903387877/51784821665,6857012694304662549,-988798368309320691/15871152061:937211631967795959/118363059843069370425989774695 +qdivz:844641921898571653/10223671754,8695453332203823704,-9669505387765352006/55085569839:844641921898571653/88899460620677410973380456816 +qdivz:1280215145483357467/3963886285,-9844640072994781020,-4883072007726792453/4475614424:-1280215145483357467/39023033766105411361756310700 +qdivz:8508531253450917863/5170848284,6541528151885306706,195667348757972251/193073972:8508531253450917863/33825249618913829545533792504 +qdivz:5090255825205050242/938312789,-2249350715632037117,5726029167151411771/608233380:-5090255825205050242/2110594543423842645003789313 +qdivz:6901648669928190531/404204557,388389149829747057,3901523146891681931/452461991:2300549556642730177/52329554750179844865579583 +qdivz:9627420596709784057/83296898,-3895759694963765953,5505547607500595567/18124602:-9627420596709784057/324504697943907926282913794 +qdivz:1174645111081751713/56929752,2346454010752872977,=1:1174645111081751713/133583044911566391868111704 +qdivz:1162048514429174393/676516,-5892528680047690487,-2798438907700034207/778641:-1162048514429174393/3986389932511143377503292 +qdivz:2802096388147231635/3081196,-8573957939952598135,970876650595882421/4869143:-560419277629446327/5283608981750037112633892 +qdivz:4679180719452784893/441080,304160869162181754,2151119934944642187/178355:1559726906484261631/44719758723351709351440 +qdivz:8915672976425207388/574061,4193291428000099624,=1:2228918244106301847/601801267612291297563266 +qdivz:233328281895908391/72184,4033877823255275355,=1:77776093965302797/97060478931286265408440 +qdivz:670971715759982761/58495,-1227774851840231708,-617885163678792671/7645:-670971715759982761/71818689958394353759460 +qdivz:1582888827826888415/526,-4801669718395979914,-8104940476272206965/8931:-1582888827826888415/2525678271876285434764 +qdivz:8026229622881496370/1921,-5372178278550968118,9440287299726019407/6073:-4013114811440748185/5159977236548204877339 +qdivz:5824855751154958045/228,-4324004042888845516,-2405077946267326653/169:-5824855751154958045/985872921778656777648 +qdivz:2255437467774544874/267,3199447325094606021,2771405119280841611/270:2255437467774544874/854252435800259807607 +qdivz:7543826031595607035/52,-9104546088044346141,-5010810875416710359/35:-7543826031595607035/473436396578305999332 +qdivz:7512950202725008087/52,-8401436384345753975,3578777756405806355/83:-7512950202725008087/436874691985979206700 +qdivz:-1398241246515482350/9,9068233703219211833,-2193751108198388733/4:-1398241246515482350/81614103328972906497 +qdivz:1221529554903080379/7,2438945293435843068,1698434551175058380:407176518301026793/5690872351350300492 +qdivz:35763638816437199755/2954907322691529008,18266557204434993168,58451171309683368843/18764957235832345259:2103743459790423515/3175057861396980374605962360114930432 +qdivz:-24539890933020861364/63297755114471972871,42384166620484371822,18890782875418251817/33137608653031131951:-12269945466510430682/1341411299737198460228945187043730420481 +qdivz:-41296371891007796845/1613315363510257239,15249898379502770099,=1:-41296371891007796845/24602895347621994343929388600567496661 +qdivz:26968473073125515519/4145542541499550935,90024588359492067484,=1:3852639010446502217/53314394403608519170705602182959328220 +qdivz:-9108355348050007705/76661950335475401,57055375045772530625,-2298296977286102063/15036407448001952:-1821671069610001541/874795265626187255366630363241331125 +qdivz:28017281112559674142/994247002684615355,67802491332771845215,17786655481004019427/236849374499644614:28017281112559674142/67412423782158018128691815375872276325 +qdivz:-49891914618525842453/68768611655263204,-56174819664217997775,-258643868421169477/1911028715949526:49891914618525842453/3863064358293050425485529901511371100 +qdivz:15475896177646886296/49664524240516277,35025891777986572339,11898387681595445269/681838705009854:15475896177646886296/1739544251253513882654242570967461903 +qdivz:28737321045177790751/2199012471009842,24823078729899234245,-40602612518778238915/4253179813373998:28737321045177790751/54586259695907565418964937658439290 +qdivz:-82233023866669302835/5439768388360516,-73950538660865410929,81261743259100627124/9245809803784267:82233023866669302835/402273802509607867490064466938479364 +qdivz:10167079364078493161/151110174756962,88181742728859483214,16304278265161179899/143495911599289:10167079364078493161/13325158554131419669540551368635868 +qdivz:-6087130765566978973/5927625468935,65819308108627037451,40718993650318423604/883073647363335:-6087130765566978973/390152207092377590789503682084685 +qdivz:7330732280399983999/37205998622295,20406176085943153899,13830294786103284155/92667712731961:7330732280399983999/759232159339910159481881157578205 +qdivz:-48332340643030107345/92304258311717,35076831981288534479,-73321763690952610021/86494140631565:-48332340643030107345/3237740959957552893702829684190443 +qdivz:98273075027659873937/84269635133,52859353248248533455,=1:98273075027659873937/4454438411596262285555193874515 +qdivz:20915233355720477899/1963896569345,62221892038256747576,-76661712514256465617/9116980669558:20915233355720477899/122197360312087396058804044657720 +qdivz:1656128732718013893/12013991167,91363850016657817300,38483305820933684114/470970043279:1656128732718013893/1097644487083239819903699789100 +qdivz:11764945144680543887/509229952865,93152505052059419404,-49961035800951489551/291905091165:11764945144680543887/47436045756916892514278186392460 +qdivz:-7317867086622619121/13130133210,58387376454076686929,-27069412842327211975/63749547479:-7317867086622619121/766634030624444346933235812090 +qdivz:94954386229766199286/91332072561,-41015693032911100387,=1:-94954386229766199286/3746048252221538781607839181107 +qdivz:49271375056669735877/3964274332,27367616211878761468,=1:49271375056669735877/108492738476778047583543039376 +qdivz:19003279723108075157/3672679837,-87707256449781680395,22197086023892167841/2380460690:-19003279723108075157/322120672321701380638694695615 +qdivz:11453151955554782667/792819445,-44970402143698368284,43746116839109616727/406009345:-11453151955554782667/35653409268993750590326482380 +qdivz:66060084310215517861/632772858,5686208043365730020,66618392442628601603/239006406:66060084310215517861/3598078114783120924011797160 +qdivz:15607406135041638145/12850627,92675124740491579124,82466968677513464623/33726515:15607406135041638145/1190933460218529079963510748 +qdivz:-84968644713302015482/30765501,21907086830543047075,=1:-84968644713302015482/673982501792158945328959575 +qdivz:-75708685189598590459/7543159,87636428496926088857,99286949010117671967/464174:-6882607744508962769/60095955849494954499679933 +qdivz:19413781778784807559/7455,70419417237119401006,87759888274980374477/7600561:19413781778784807559/524976755502725134499730 +qdivz:-44073071620584783758/137977,97178052623075418323,2336605012039492891/4902:-44073071620584783758/13408336166774076993952571 +qdivz:25141254449395000414/853567,48818099403147552704,72006961628028408314/367953:12570627224697500207/20834759326623223559447584 +qdivz:48044965246872284768/97133,69155615859736994978,-45313300536339105253/86233:24022482623436142384/3358646217651916766599037 +qdivz:-4395289710243518173/8350,744289141150282917,-29095078709708260253/88548:-4395289710243518173/6214814328604862356950 +qdivz:-92303054169340161069/4319,6791173325830567613,=1:-92303054169340161069/29331077594262221520547 +qdivz:64997783212580413369/6291,44933069571459793043,-20474362763124554371/1858:64997783212580413369/282673940674053558033513 +qdivz:93945477444073241773/141,88011071920496381723,23904352473973528984/197:93945477444073241773/12409561140789989822943 +qdivz:-25808752242439690169/552,-34114701969246980307,41196336212393917073/475:25808752242439690169/18831315487024333129464 +qdivz:16573231794217629809/25,80794581544602285996,=1:16573231794217629809/2019864538615057149900 +qdivz:42187260212039274209/87,70929718370679041273,41380731918827034219/13:42187260212039274209/6170885498249076590751 +qdivz:-34161590626563013397/4,-31069588081719868852,=1:34161590626563013397/124278352326879475408 +qdivz:60823156242773368161/2,-90388088707709016642,-91947828450656458545/7:-20274385414257789387/60258725805139344428 Index: contrib/isl/imath/tests/qmisc.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qmisc.t @@ -0,0 +1,49 @@ +## Miscellaneous rational arithmetic tests +## Generated and verified by hand + +# Basic negation tests +qneg:0,0:0 +qneg:0,=1:0 +qneg:1/37,15/16:-1/37 +qneg:65/18,=1:-65/18 +qneg:-6/7,=1:6/7 + +# Basic absolute value tests +qabs:0,0:0 +qabs:0,=1:0 +qabs:1/37,15/16:1/37 +qabs:-592384293849818/1000001,55:592384293849818/1000001 + +# Reciprocal tests +qrecip:0,0:$MP_UNDEF +qrecip:1/2,5:2 +qrecip:-3/2,100/995:-2/3 +qrecip:655378011918000000,=1:1/655378011918000000 + +# Reading decimal fractions +qrdec:0,10:0 +qrdec:1.10000,10:11/10 +qrdec:1.01000,10:101/100 +qrdec:1001.001,10:1001001/1000 +qrdec:1001.001,2:73/8 +qrdec:12.05,10:241/20 +qrdec:-5.00138,10:-250069/50000 +qrdec:-00000.5,10:-1/2 +qrdec:.5,10:1/2 +qrdec:-.005,10:-1/200 + +# Rational exponentiation +qexpt:-5/8,0,0:1 +qexpt:-5/8,0,=1:1 +qexpt:13/8,0,0:1 +qexpt:13/8,0,=1:1 +qexpt:509252236125428/47889593208724507642867,0,0:1 +qexpt:509252236125428/47889593208724507642867,0,=1:1 +qexpt:-5/8,1,0:-5/8 +qexpt:-5/8,1,=1:-5/8 +qexpt:13/8,1,0:13/8 +qexpt:13/8,1,=1:13/8 +qexpt:509252236125428/47889593208724507642867,1,0:509252236125428/47889593208724507642867 +qexpt:509252236125428/47889593208724507642867,1,=1:509252236125428/47889593208724507642867 +qexpt:509252236125428/47889593208724507642867,4,15/39:67256115255216568118287656956157205834289880165948820377856/5259743820161714626344840164714583399959974116151536869550562774750827767486998189660536721 +qexpt:509252236125428/47889593208724507642867,4,=1:67256115255216568118287656956157205834289880165948820377856/5259743820161714626344840164714583399959974116151536869550562774750827767486998189660536721 Index: contrib/isl/imath/tests/qmul.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qmul.t @@ -0,0 +1,803 @@ +## Rational multiplication tests +## Generated and verified in PLT Scheme (see imath-test.scm) + +qmul:-3/26206484091896184128,1/693472590887743985,-4/70335584174882085859:-3/18173478421265693438940076224084470080 +qmul:3/91130421678723294601,2/1511297448571716895,-9/67416878129472613559:6/137725173770319192750843847801453983895 +qmul:3/3660941890584665578,-9/8380105656182991401,5/2848423294177090248:-27/30679079844245810042603985831234694778 +qmul:7/2164077499217694058,0,-1/333401876099655555:0 +qmul:4/904017211204226053,=1,-1/248448496161174245:16/817247118153466254734904646723958809 +qmul:0,-4/100568637457389843,0:0 +qmul:2/73650052097202983,5/4552230994414799,0:10/335272049897152087881722802145417 +qmul:7/999642011115757,=1,7/12191208784714605:49/999284150387555241548053683049 +qmul:4/4748171647596839,7/4194009713619088,1/878273774653032:1/711209928998281855823737102244 +qmul:-1/3272725541181013,3/1299116858075758,9/9062356618866682:-3/4251652922403362359365945182854 +qmul:1/107669261142969,=1,2/427008086776155:1/11592669795072854172258134961 +qmul:9/886384410786908,=1,1/143876368001899:81/785677323686054067227784200464 +qmul:3/35807911942040,=1,-5/90295680789497:9/1282206557648890844319361600 +qmul:2/68986921725007,5/77598287457417,3/43453045339831:10/5353266982819419037696526919 +qmul:-1/1109481330540,-4/9404058215555,=2:1/2608406755367394881137425 +qmul:0,=1,5/4715212234981:0 +qmul:1/68986716212,-3/2931468080,=1:-3/202232356519496512960 +qmul:1/26808054670,=1,=1:1/718671795189708808900 +qmul:7/43068832781,0,7/19211808304:0 +qmul:1/9608906275,4/5041381803,=1:4/48442165241517513825 +qmul:1/1228681579,6/2225293505,2/749381381:6/2734177137461844395 +qmul:1/8574959114,=1,6/1956551185:1/73529923806771664996 +qmul:-5/861495024,=1,-2/67979545:25/742173676376760576 +qmul:-2/140727827,1/692019033,-7/753572629:-2/97386334756731291 +qmul:3/95516372,=1,0:9/9123377320042384 +qmul:3/21198931,1/3432139,1/3530668:3/72757677843409 +qmul:7/6222866,4/1833695,0:14/5705419134935 +qmul:6/615053,=1,0:36/378290192809 +qmul:5/568461,4/392783,-2/643261:20/223281816963 +qmul:-5/510613,=1,0:25/260725635769 +qmul:2/14663,-8/93277,=1:-16/1367720651 +qmul:9/49612,8/73143,1/20024:2/100799181 +qmul:3/697,0,=1:0 +qmul:-4/2403,0,1/2247:0 +qmul:3/196,9/422,3/424:27/82712 +qmul:-1/309,2/257,4/233:-2/79413 +qmul:5/67,9/11,7/8:45/737 +qmul:1,-1/22,=2:-1/22 +qmul:0,=1,3/8:0 +qmul:0,-4/7,=1:0 +qmul:-85/86153854226096021421,=1,-17/21068656717268700162:7225/7422486598011403290090823970405290859241 +qmul:-5/43607938850040716426,27/16056333585184134128,32/52338799857236448113:-135/700183613138564743562274537293596786528 +qmul:17/1822698577891414141,=1,-7/8417742332722538862:289/3322230105847383502431373884774767881 +qmul:16/4598825929956443605,49/4847943197216974161,27/3451375546922816345:112/3184978126045337954130178471819812915 +qmul:-13/308229631559916894,7/23027204844472228,=2:-91/7097666865066408240206510971019832 +qmul:9/407734736332167529,=1,=1:81/166247615211862175599509955321965841 +qmul:85/4942792842537911,76/69829540258955019,-91/17762034363033874:6460/345152951789675772143408751225309 +qmul:54/48159800199427181,=1,5/15794694767846184:2916/2319366355248746342818800521606761 +qmul:-1/11155623059888,5/2213190858263331,74/4478858739544117:-5/24689522974375729479887366928 +qmul:28/7444112023597965,94/2835981424363017,44/965216022716111:376/3015909059971602514096088922915 +qmul:61/275448071365986,=1,39/801040431549668:3721/75871640019241316559957752196 +qmul:-16/122979260248953,91/861294833601044,69/330950567465674:-364/26480350373125364764230176733 +qmul:-5/15361734038378,-4/21146843499433,-42/41820111648961:10/162426092794746228321619837 +qmul:31/27515949153680,42/8919478678031,-31/98260871319338:651/122713960891016949829402040 +qmul:-96/7797764223407,-71/8834811164017,1/1862795966742:6816/68891774415328515707545919 +qmul:15/5131534941574,57/7059500713061,=1:855/36226074579139089973698014 +qmul:99/412586992259,-70/740258455507,2/72307587241:-6930/305421009651925904920313 +qmul:79/741601059426,-1/218034913785,-91/880841444516:-79/161694923054812571587410 +qmul:-31/7229094496,1/4120337146,=1:-31/29786306583812948416 +qmul:55/83518896547,9/29598222046,-49/35480447526:495/2472010845035008675162 +qmul:-70/3176137243,=1,1/170734393:4900/10087847786371641049 +qmul:19/8816510816,16/688207893,1/526411545:19/379224520768191918 +qmul:-3/77923064,=1,29/420820637:9/6072003903148096 +qmul:7/886358404,71/63529999,3/267607006:497/56310348519761596 +qmul:1/2981721,46/37858403,83/6367099:46/112883195251563 +qmul:-31/938629,-15/8290882,1/1023462:465/7782062280778 +qmul:37/410302,4/1757463,=1:2/9744467349 +qmul:28/8167855,=1,81/7643948:784/66713855301025 +qmul:-97/992628,13/93468,-47/39726:-97/7136842608 +qmul:-23/674165,7/523911,47/942664:-161/353202459315 +qmul:-7/19181,54/85811,=1:-378/1645940791 +qmul:5/7653,=1,-76/63829:25/58568409 +qmul:11/4265,=1,57/520:121/18190225 +qmul:65/6957,41/389,96/2993:2665/2706273 +qmul:-23/297,-9/83,14/891:23/2739 +qmul:2/31,86/985,-4/905:172/30535 +qmul:-12/7,-10/3,62/67:40/7 +qmul:-28/23,16/87,4/15:-448/2001 +qmul:37/2,=1,-16:1369/4 +qmul:-20,=1,35/4:400 +qmul:437/75577860178450821941,=1,572/74570847326022239185:190969/5712012949153462506928348371418487007481 +qmul:-189/57565050795595180562,-59/2655741179562929534,963/98951958258639716842:11151/152877875901493900051494486844412518108 +qmul:392/9223441830913061231,10/126887593668291297,102/1854286196997300457:3920/1170340339264017235848151367305406607 +qmul:255/3855767718884073169,129/2905792024958436842,-235/3219625969384677757:32895/11204059087625523831085398908193292298 +qmul:-47/35122532617610421,-117/122052767037802280,319/272062018205952087:1833/1428934097118272207801649688519960 +qmul:979/892962159830670377,-375/273191235681889997,70/47294962936566903:-367125/243949435861310195658594938880518869 +qmul:117/20991277911775766,=1,-92/47578690454158995:13689/440633748369405163321411464886756 +qmul:-243/11407352500485733,587/76385498874294444,-614/81454021700493267:-47547/290452103861510956341405887722484 +qmul:174/900283464250993,229/9496538222605715,-274/3248450234623149:39846/8549576329439440824503236224995 +qmul:-690/8145214566421669,141/5752215623742809,71/3004747651790415:-97290/46853030487708234314403900528221 +qmul:226/102973529231733,30/68951726615689,=2:2260/2366734212079704520104819679 +qmul:-815/885459835828344,37/163413072330166,-43/147651688219350:-30155/144695712197674089868869025104 +qmul:75/6638760558632,-138/35179390065353,413/82329576156442:-5175/116773773621297956634138548 +qmul:147/95595835551176,6/10399082254439,189/19869218037638:441/497054478539251611118835132 +qmul:-610/7116766665669,370/6178271155283,-170/1991438380331:-225700/43969314209382356444079327 +qmul:-22/3906839603439,=1,495/2629172214638:484/15263395686999402780626721 +qmul:145/9760768489,529/803913134519,3/3085831861:76705/7846809991306273371791 +qmul:30/130533848429,-291/232962676405,413/647890196158:-1746/6081902938292888923549 +qmul:218/45496969487,53/7721267751,312/52099708697:11554/351294283268204113737 +qmul:277/88084217182,-643/95570881719,=2:-178111/8418286301611629495858 +qmul:97/9657661098,472/161930139,400/6505391099:22892/781933202007016311 +qmul:137/1394596885,923/2175332507,-63/538078336:126451/3033711938101440695 +qmul:-99/123912484,299/998630381,359/807136797:-29601/123742771107576404 +qmul:281/377026117,-970/10165277,80/672610947:-272570/3832574915539409 +qmul:641/45327247,95/3702049,-31/16613945:60895/167803689429103 +qmul:-737/25452329,363/67508236,825/73130323:-267531/1718241832881644 +qmul:51/7250464,112/8927185,903/6361594:357/4045389591490 +qmul:199/4639977,588/7971809,322/8874233:39004/12329670136131 +qmul:665/703012,329/294996,787/209117:218785/207385727952 +qmul:133/29650,307/137037,809/690522:40831/4063147050 +qmul:553/42863,161/16139,552/86389:89033/691765957 +qmul:-568/72299,-953/23177,798/52267:541304/1675673923 +qmul:-907/7588,47/7619,=2:-42629/57812972 +qmul:37/1428,-161/1853,-140/3279:-851/378012 +qmul:69/659,194/7,-183/238:13386/4613 +qmul:-365/824,264/503,-421/698:-12045/51809 +qmul:747/74,-15/94,12/19:-11205/6956 +qmul:12/5,113/37,=2:1356/185 +qmul:-807/7,943/8,199/3:-761001/56 +qmul:591/7,85,-156:50235/7 +qmul:853/18759654468263598130,-2841/40750915886836631585,=1:-2423373/764473101302328863323172599481304936050 +qmul:-4752/16314480916934323241,1675/15223840982975523171,=2:-2653200/82789687733065614038692540422933105737 +qmul:-877/6101604969629738233,=1,3917/3506403215407013175:769129/37229583205410318824680729796101962289 +qmul:3511/9447760616772726092,2633/1439700094583390479,-1093/3530171944589695778:9244463/13601941853568925322985028756947678068 +qmul:1947/430992381411198689,=1,6905/150990131770718358:3790809/185754432834496165241461379835318721 +qmul:8719/646714849991103264,=1,5786/734533820409647257:76020961/418240097199015197424619951911453696 +qmul:-901/11042787574357099,-1492/25943871895296763,2003/71983717831437714:1344292/286492666196095454208761540770537 +qmul:248/45424964911300681,-2828/10155871660092285,1922/24482631313347631:-100192/65904301971909291827634263335155 +qmul:2932/167088922177995,4285/8315956341564334,=1:1256362/138950418199124701072469163033 +qmul:63/96864941445455,1217/536600078187501,-1363/813397840648021:25557/17325911717752953043818085985 +qmul:2028/952222976621975,=1,-4447/132247057152414:4112784/906728597206814347382052900625 +qmul:-2672/564653311125411,=1,593/245849676591157:7139584/318833361764890193787369918921 +qmul:8811/12688709770015,-6995/78357482492503,2405/8730288903721:-12326589/198851070731280426018339509 +qmul:-6216/89020593811217,2073/8676827195515,-43/383215257478:-12885768/772416309342061967459091755 +qmul:649/679490122076,-1037/2294439110154,6125/672996983517:-673013/1559048711054490271159704 +qmul:4001/986338046878,5/3558981731,-2511/3763709597086:20005/3510359089429023585818 +qmul:-1523/69241899473,=1,7123/515464482213:2319529/4794440642629037677729 +qmul:-6869/800191115742,938/461384295473,-3029/66737130644:-3221561/184597807090188234817983 +qmul:3554/16260606585,-2909/10951382696,=1:-5169293/89038062790716326580 +qmul:-8706/24347671943,-2333/75528831647,6568/10275254341:20311098/1838951215179232380121 +qmul:8843/2387867375,3806/2482665293,-478/3437714583:33656458/5928275456199515875 +qmul:676/469237349,=1,=2:456976/220183689696547801 +qmul:4381/415783140,=1,-9189/160372247:19193161/172875619508259600 +qmul:5209/647900590,31/76532430,5022/774082651:161479/49585406551133700 +qmul:6785/98653728,1643/10927961,-3657/22982951:11147755/1078084092088608 +qmul:-131/3707540,-3070/95931603,8132/10434367:40217/35567025538662 +qmul:3495/4205702,1768/4495963,642/2009179:3089580/9454340290513 +qmul:-3081/1925708,-557/52210,=2:1716117/100541214680 +qmul:1824/515329,4783/215399,-80/428083:8724192/111001351271 +qmul:-1259/116291,686/450649,=2:-123382/7486631837 +qmul:2158/8127,4919/28127,=2:10615202/228588129 +qmul:-8479/13630,228/39107,-6607/63539:-966606/266514205 +qmul:-3929/4639,1292/907,4288/3241:-5076268/4207573 +qmul:-2277/9067,379/5790,-503/3539:-287661/17499310 +qmul:7172/525,4813/272,4472/631:8629709/35700 +qmul:759/64,=1,1976/105:576081/4096 +qmul:3255/4,-1567/13,4881/26:-5100585/52 +qmul:3089/89,=1,-8984/35:9541921/7921 +qmul:5031,-5481,=2:-27574911 +qmul:1479,6716/7,669/5:9932964/7 +qmul:-79907/42073633953804470386,9649/39994826473890828375,-32061/69201000109873943624:-771022643/1682727689108411078225149789999696002750 +qmul:7869/4137317017220625920,-46300/94718332275370703049,-79642/60022119059401889179:-6072245/6531329466094147648450013992237207168 +qmul:-29138/1677259660137772757,55969/6796400935123913154,-10129/967130263887253020:-815412361/5699664561302987764528483645927572789 +qmul:63296/9530224706297545807,2348/322614345457502213,958/9427355800897598701:148619008/3074587205685099009151203658171370891 +qmul:8775/40604046784024133,-33221/144310822954936081,=2:-291514275/5859603406703248409743984976442773 +qmul:21115/310091896403808544,11297/311633467720059450,=2:47707231/19327002597641657788985081219588160 +qmul:-7541/568197224156233,78686/80834506129161047,=2:-593371126/45929941998629309750410745855951 +qmul:-69371/45833711711077260,45306/56585412779622335,7626/54270702558063797:-174606807/144084416466306503713223267033450 +qmul:-47821/557744909539529,-35381/1596080991630467,27735/4832267108379043:1691954801/890206048294696559875897230043 +qmul:39463/2836203973039415,5893/5755385978253006,39369/9842567552327876:232555459/16323448577896515754725680231490 +qmul:59563/93078116326943,=1,39162/530318464795213:3547750969/8663535738971933065667725249 +qmul:-6422/219350698334991,12009/451668291281128,38643/184068500609632:-12853633/16512292518047925598650058308 +qmul:6353/29487362288887,18649/10109618056586,-739/5084432721670:118477097/298105970236825097644959782 +qmul:82991/13932554844361,44258/40391647302859,-4103/3232141273561:3673015678/562758841301169080175328099 +qmul:68609/2797606749368,71293/8880170450370,=2:4891341437/24843224787493384272866160 +qmul:69352/1282840784633,51360/5155457119681,=2:3561918720/6613630656553360226662073 +qmul:19996/284659901481,91975/649935845164,992/22386886571:459783025/46252668413338677571971 +qmul:95164/291066123381,=1,86173/926768430166:9056186896/84719488180043514871161 +qmul:58599/35278850458,=1,=2:3433842801/1244597289637926809764 +qmul:16793/50880968745,32965/31422146373,5133/4972604243:110716249/319757849501085622377 +qmul:10537/861910652,22310/9378414407,=1:117540235/4041677638131781682 +qmul:79317/9648480088,22265/3941357964,=2:588664335/12676037945111406944 +qmul:11221/182565205,56092/543156657,49073/666425232:629408332/99161506432319685 +qmul:85751/945688766,15325/126345977,14001/74129827:1314134075/119483971078194382 +qmul:-70533/6456184,-11237/1159737,36975/90043007:264193107/2495825154536 +qmul:56162/84955139,=1,=2:3154170244/7217375642509321 +qmul:559/4445450,87073/9891852,=1:48673807/43973733473400 +qmul:2247/126982,=1,=2:5049009/16124428324 +qmul:87205/903493,=1,4007/74486:7604712025/816299601049 +qmul:20400/957959,=1,-9955/111633:416160000/917685445681 +qmul:31836/73595,11609/39450,46021/33218:61597354/483887125 +qmul:84969/75326,-86068/92037,9321/65618:-1218851982/1155463177 +qmul:49337/4359,71033/6220,-25745/2781:3504555121/27112980 +qmul:15077/1290,20527/9232,-259/71:309485579/11909280 +qmul:52867/502,-63033/451,83228/635:-3332365611/226402 +qmul:1852/17,45130/359,67421/50:83580760/6103 +qmul:57233/78,37817/35,-23454:166490797/210 +qmul:9693/26,82259/68,46811/66:797336487/1768 +qmul:-53957/7,=1,57497/7:2911357849/49 +qmul:-95413/6,-29374,-4257:1401330731/3 +qmul:-198736/12940720433326325129,125852/5925853683093665567,12760/97357765177854120733:-25011323072/76684815841712259623316096046234133143 +qmul:921572/61142247716597287729,-236568/70364185507196351425,204596/87367262923771962827:-218014444896/4302224460657604084043267617199724163825 +qmul:-175852/3759159397994001893,12753/21663430571600165,=1:-2242640556/81436288626021332583545141049112345 +qmul:-268026/6357464651647716983,=1,8534/1795261387346998395:71837936676/40417356796950227447969273156066622289 +qmul:841695/829965893010784622,-533003/287367841069761182,-70387/77776025771352596:-448625960085/238505506836045568256258975978143204 +qmul:285995/137908752412413419,=1,=1:81793140025/19018823991948344014771004171269561 +qmul:523332/10397730659818265,-637807/84218842967037343,38109/5089543807331942:-333784812924/875684845652784039249421848469895 +qmul:331806/46798346659133905,390599/19460297756850316,-839360/33343052356070147:5891049627/41395898205229409605128422071090 +qmul:-618133/4917065118673735,=1,-92527/257257853329058:382088405689/24177529381277951659005378850225 +qmul:821668/9309756380607047,319410/1721325229930259,-409819/4033682794066002:262448975880/16025118542443120997155893935173 +qmul:-463245/974985643441198,-676781/102650194991381,67531/763750320751138:313515414345/100082466413036044472790314438 +qmul:3292/15168814078843,786853/187996862965898,126658/126696595422875:1295160038/1425844730867715885896148007 +qmul:-108514/9407475910099,31445/45805965278381,209927/522813819096:-487460390/61559787842171498837752817 +qmul:206519/25307336797263,439291/97571104143841,-52486/22231146494461:90721938029/2469264794249007720607107183 +qmul:755819/4678998804414,132779/513422592641,-154155/1796861274557:100356891001/2402303697126375154717374 +qmul:-610422/8953796367011,=1,34600/946679301111:372615018084/80170469381899382209074121 +qmul:-168796/96200349399,=1,459815/414314841334:28492089616/9254507224489679661201 +qmul:448040/938638294207,-940391/987312987781,877652/581123018277:-421332783640/926729778699174474084667 +qmul:367299/48916956722,-234746/31600745479,19962/10415742905:-43110985527/772906149489590079919 +qmul:540492/60952022291,=1,=2:292131602064/3715149021362560888681 +qmul:48241/1850039638,600695/993394588,=2:28978127495/1837819363974679144 +qmul:-73469/4702579939,910622/7776354127,71768/6903692213:-66902487718/36568926916190058253 +qmul:165889/228901970,3743/140713319,=2:620922527/32209555924338430 +qmul:208098/645461621,-637539/213089255,-987707/763332694:-18952941546/19648705135711765 +qmul:978743/66626510,16328/1482253,=1:7990457852/49378672163515 +qmul:336035/68124509,=1,245361/31402036:112919521225/4640948726491081 +qmul:191473/9297613,135059/7858162,-384667/8715020:25860151907/73062149167306 +qmul:-118451/7012982,-685529/5952631,=1:81201595579/41745694055642 +qmul:142154/901271,422448/305711,332653/165374:3532510176/16207556393 +qmul:52759/177236,850321/697129,72248/85023:44862085639/123556355444 +qmul:-88178/95391,=1,277011/11863:7775359684/9099442881 +qmul:-466226/55653,24107/11550,-273396/37003:-5619655091/321396075 +qmul:825492/3685,102991/306,60368/1041:14169707762/187935 +qmul:166834/1709,340151/1908,=2:28374375967/1630386 +qmul:-212681/290,424751/190,845448/971:-90336467431/55100 +qmul:134907/163,-69685/79,=2:-9400994295/12877 +qmul:-539594/3,15173/4,-877571/28:-4093629881/6 +qmul:247756/31,94120/29,-147220/11:23318794720/899 +qmul:910742/5,63428,2990:57766543576/5 +qmul:132140,=1,214219/9:17460979600 +qmul:-1882407/73787858412488449855,-434970/15504199196668297319,7152438/32357487418268793473:163758114558/228804331024555497710598988747312487749 +qmul:697417/2168456434664834658,1334383/40514117254978695797,1660012/19534585395934841435:132945912673/12550442608046308674759866845069218918 +qmul:767157/4500296443907797052,4954462/555593595680231401,3839270/8356753330266434437:1900425102267/1250167941448845883802900321752814926 +qmul:3855435/1910412651584231024,3929628/9286414633188139915,6450211/7279093857125478452:757521266409/887044200154977924360507801609786148 +qmul:-713297/2131510505574811,=1,8006203/547537770085302559:508792610209/4543337035375786395109517685721 +qmul:-3176335/541746203963633741,-438253/349884327285711674,2546202/81167937975645853:1392038342755/189548506133403938761872538263992434 +qmul:4172837/3155683016816501,1634359/1130730609779385,3449963/73677939584796131:6819913706483/3568227381875371425040637631885 +qmul:1250071/25258841326965282,-32307/1353739173264256,=1:-13462014599/11397960991859667942696774520064 +qmul:7965329/6993004096201475,2973773/6634186275128268,3335672/4941418095538311:2153370937847/4217535617903234884469745072300 +qmul:924761/7142709941575765,8302365/4849337439058259,=2:1535540671953/6927482147203397401610419498627 +qmul:6563249/71417076489085,=1,3793878/305677884396037:43076237436001/5100398814247817470124137225 +qmul:123256/2387254101849,6673623/563071687944596,-2966203/120995731224497:68547006374/112016266390064743737763167 +qmul:11601/9690796184885,-313729/29163002094366,=2:-1213190043/94204236478625099184285970 +qmul:-1548191/1118347883822,693213/16160970245026,=2:-1073226127683/18073586874035135921369372 +qmul:4730021/1257111596731,45335/50784818897,9472521/3164110107311:214435502035/63842184773302332225707 +qmul:8511317/4540489631064,-6359369/2005086337073,=1:-54126605478973/9104073722868052915635672 +qmul:-929873/867693641561,8138971/698148180183,9405551/179909067138:-7568209380683/605778736812172445385663 +qmul:9281874/795726121805,-9968150/721200783579,4661824/364533493543:-6168207487540/38258553504002986522673 +qmul:3865094/4084662077,4259784/19883113093,=2:16464465579696/81215798023679274161 +qmul:-416924/286477113,826597/6309334211,-9773164/19019652193:-344628127628/1807479849719412843 +qmul:-9662220/20572447,=1,1141747/1832358244:93358495328400/423225575567809 +qmul:616787/710447851,-5149637/86667498,5336551/335300034:-3176229156319/61572737705646798 +qmul:-9976984/843714569,=1,613447/59557955:99540209736256/711854273942855761 +qmul:-6026602/975541545,9908792/76315713,9315535/212827209:-59716345684784/74449148567796585 +qmul:317525/4130814,-794909/3724657,-7514646/67549867:-252403480225/15385865280798 +qmul:5284147/75357219,-2845520/19763971,1559210/15974883:-791376103760/78387257418771 +qmul:6632185/1141092,2427283/1559559,=2:16098189903355/1779600298428 +qmul:-1099211/2368184,=1,4294432/3557597:1208264822521/5608295457856 +qmul:-90319/172637,8164133/19492,-7639232/876753:-737376328427/3365040404 +qmul:-2193898/79229,542172/63719,=1:-1189470066456/5048392651 +qmul:-3656336/69523,1911911/39486,833550/557:-3495294509048/1372592589 +qmul:106251/11335,-7809497/82381,-4910754/43655:-829766865747/933788635 +qmul:656544/4345,-9528986/1963,2350355/5553:-6256198584384/8529235 +qmul:-2189554/2039,-5393104/7563,889038/2857:11808492435616/15420957 +qmul:3890213/508,186330/17,-1198413/262:362431694145/4318 +qmul:3102225/578,5898937/910,=1:522852280995/15028 +qmul:-1156863/5,-8420942/61,1460661/13:9741876224946/305 +qmul:-2254787/5,2862624/83,3361/52:-6454607381088/415 +qmul:-7630885/4,5547065/8,=1:-42329015102525/32 +qmul:3371673/8,1927246,=2:3249021651279/4 +qmul:-14442357/30313364574216985165,21011896/19717180229164582119,=1:-101153767759624/199231357554069726942322822323082421545 +qmul:73015500/34914714923282785961,10709547/16405893500986887200,19061786/4299472658767378545:7819629289785/5728070946486949421088979169452505992 +qmul:-5213601/648973976600394322,95110449/6292591997485345693,10223157/1491031081544864086:-495867932016849/4083728451731883302073525200284355146 +qmul:81716702/9420867468902388767,-3659716/561353788976535007,16436845/12448406189105001:-299059921776632/5288439649114135016294765892899066369 +qmul:-50829049/681481015656967334,78493193/406094838848924705,=2:-3989734353163457/276745923231817683251713267210586470 +qmul:-70639608/210570392897683795,=1,32857499/484390875545236076:4989954218393664/44339890365084922016231475805602025 +qmul:-42306075/32432310313264277,-86992166/48265729471703217,59197803/99727495871692084:1226765699736150/521789705240781269523990077359703 +qmul:98949619/2882304121717510,-30259679/61942044859153494,=2:-2994183708112301/178535811205149016934639997479940 +qmul:-33943246/547508652618667,-9155497/325768016112482,3909688/9222108480297609:155383643461631/89180403784000610709262450747 +qmul:-4005853/831711723057253,-65053249/3453104157068793,=2:260593752666397/2871987208371849027864998605629 +qmul:30466505/131811990296054,80480517/129751865511763,-66851989/905703806093822:2451960073583085/17102851637731408230589483202 +qmul:67778441/221052041028359,31145967/736730375785315,=2:2111025086697447/162855753254933795304810748085 +qmul:-27930623/83735524881404,=1,26062637/38713631506284:780119701168129/7011638127164228368265011216 +qmul:91874289/55178817284824,2081222/10998714287097,=1:31868465250193/101149341002618103726185988 +qmul:-81097913/23224035213,86134633/913902046268,-44110346/4612785602109:-6985338973320929/21224493303760787235084 +qmul:26946729/330400702820,-5376007/957000244373,72609687/3803755771964:-144865803731103/316193553339750950231860 +qmul:5847347/83932240013,4198391/162033797450,41563965/225583428284:24549449018677/13599859577791227366850 +qmul:19548965/189470438789,2465153/48226118390,-16293845/384490679461:9638237943329/1827484762488712445942 +qmul:-55395086/15848355167,30834213/24733216753,3746720/49399574807:-1708063880877318/391980803523938512751 +qmul:-58079954/9010951227,53522457/51897896711,=1:-1036193946842326/155883138682234904799 +qmul:15721758/4667399077,-40891342/1328104821,=2:-214294594406412/2066265071898216739 +qmul:70233722/7303211237,8646406/3990640707,33916940/2735563757:607269275303132/29144492054192024559 +qmul:6933207/288152,3665663/23826937,-56545561/920522000:25414800371241/6865779550424 +qmul:41800997/62123962,-38919041/683603632,-76160505/964998499:-1626854716083877/42468166057429984 +qmul:-30010802/20468051,19506739/20221851,38792870/36677751:-585412881794678/413901877582401 +qmul:11813175/26779288,=1,4038299/10717148:139551103580625/717130265786944 +qmul:-54308089/3363111,6223152/1333435,12297998/2068949:-112655830892176/1494829972095 +qmul:47572280/4867129,99908399/5832503,6381834/2396879:4752870331579720/28387544493887 +qmul:-62682614/784029,8201676/813035,86261045/879573:-171367496953688/212481006005 +qmul:-52450671/559382,31930301/348148,81333805/486957:-1674765712681971/194747724536 +qmul:53187047/34080,40744921/16199,37085536/50799:2167102028238287/552061920 +qmul:11558111/11033,48139409/27484,-90392545/80713:556400632696399/303230972 +qmul:-25583995/4897,-94434044/3561,2921273/9343:2416000109525780/17438217 +qmul:-5090656/611,=1,=2:25914778510336/373321 +qmul:-13641055/103,35989446/451,-35512409/41:-490934012305530/46453 +qmul:99505255/181,-312642,12835678/5:-31109521933710/181 +qmul:25097277/5,85216417/47,73513489/51:2138700022396509/235 +qmul:64784087/19,-41764336/27,-39313651/72:-2705664376921232/513 +qmul:22866666,9187561/2,-79296567/8:105044444370813 +qmul:32433429/4,-57952559/6,=2:-626533402564937/8 +qmul:142379769/6580458265088042332,=1,829632764/47313440042888292183:20271998620493361/43302430978565528007566299412223998224 +qmul:952160697/53449785406826630773,=1,123350541/21685565106900565733:906609992911525809/2856879560035817059690375116110870577529 +qmul:134379194/7288875631759851537,262306997/2039219084637508550,=1:17624301418710209/7431807146916983147195344504784070675 +qmul:893718997/892104296345812908,=1,287136425/3171192156119780019:798733645598686009/795850075558657977797692103339416464 +qmul:148747375/98802457575041086,24743438/63078605847781653,=2:1840260725487625/3116160639084092662997866715997579 +qmul:881257471/447180652093139622,=1,467458692/434203794165327853:776614730193315841/199970535606445577794662077186302884 +qmul:-328833244/8368942920923449,71377107/4810747268694941,=1:-23471165642145108/40260869298696343876296794571509 +qmul:158379101/1326421417689989,-189428893/41659788909099497,196884323/11300332885720816:-30001577776765193/55258436265473435094327901835533 +qmul:10782829/45891552641500,764396030/8166229459391987,-237359023/5307605981413862:824235167976887/37476094911825545799378366050 +qmul:-176383510/8720957474390283,=1,969790455/2816113324098863:31111142599920100/76055099270123743567802604820089 +qmul:153319337/75604684811316,-66073159/9855025487116,=2:-10130292931375583/745086095760891109449004656 +qmul:-152252295/92990423831326,58928296/433772431956189,=1:-213618293010460/960397197475024603484708967 +qmul:968728976/89630394861017,122952071/77095083081384,=1:14888404229613662/863757842303419891847500941 +qmul:421854586/98110047748469,777827572/98264750833133,=2:328130128365445192/9640759396230087578575223377 +qmul:321360259/1519003205844,=1,648154609/8326351267679:103272416064547081/2307370739364349435752336 +qmul:-623994359/2983440638275,548017609/4525469063166,313238822/1462111109367:-341959896648667631/13501468310305737332278650 +qmul:105901696/125767654005,11356251/3169320047,37580987/3123470749:400882080367232/132865982367402112745 +qmul:257717002/338572086809,=1,-516598417/866703725253:66418053119868004/114631057966201031802481 +qmul:-315718685/10965934391,730969133/99436604662,980080011/95127007262:-230780613446350105/1090415282787296730842 +qmul:357633989/52052235576,=1,499101847/17405036021:127902070088052121/2709435228459400051776 +qmul:83154971/2959266631,=1,=1:6914749202010841/8757258993350090161 +qmul:74008543/143708417,-38807917/3997329896,49374533/1136791926:-410302484862133/82064278797276376 +qmul:147247586/394684533,-46611929/47003797,417377757/202754149:-6863494024053394/18551671668171801 +qmul:190874443/241889832,65505550/154148559,=1:6251667684829325/18643484519776044 +qmul:-494401746/19681,407904654/21651245,69321355/12439911:-201668773139125884/426118152845 +qmul:365885228/56568973,4250982/8521637,960401966/74768881:1555371518293896/482060253368801 +qmul:255177714/7055753,814922797/4572404,187054293/4701449:103975068212473029/16130876620106 +qmul:-588905892/5841913,=1,832554893/1175043:346810149632315664/34127947499569 +qmul:135837085/706833,-289514879/255430,725428338/928723:-7865371445497543/36109270638 +qmul:122186761/430279,=1,619259689/728443:14929604563671121/185140017841 +qmul:775073757/30757,695907415/51279,944630725/67207:179793191556069385/525729401 +qmul:95477167/3960,-871735667/38397,-714770441/33262:-7566441078001399/13822920 +qmul:-884857813/4929,70752241/2056,154069499/3880:-62605673236108933/10134024 +qmul:229619449/1615,957611614/1161,10452182/285:219886251162680686/1875015 +qmul:111146789/136,146738413/445,169865033/157:16309503427905857/60520 +qmul:9871622/41,-808689707/803,=2:-7983079102794754/32923 +qmul:-288336467/9,=1,850175175/86:83137918202042089/81 +qmul:558230684/47,805462654/41,167574699/11:449633968278875336/1927 +qmul:339929608,29235627/2,=2:4969027612872108 +qmul:881780865/2,443292701/9,=1:130295673778655455/6 +qmul:2838001100/91389568002455572881,=1,1986643253/20570864960839080487:8054250243601210000/8352053139675451489580240654173902640161 +qmul:3251591241/344636720089928137,-1113406027/3139375771816261090,-3172679089/93012796738201713479:-3620341285069809507/1081944169128542879223598266129289330 +qmul:2151380941/4425085028680839366,6291439247/670381381077695674,-1225149433/257062097818706652:13535282487455191427/2966494612913295666228911591427102684 +qmul:6158301795/2455047697567864031,-5798372309/5521291989057645588,-157042968/9556961002892580965:-3967569622065888295/1506115020592873902921765927885671692 +qmul:-8451954373/975723814918920513,4784366210/605780426352481313,8465359637/69665667013568159:-40437244910642936330/591074388603853235233268628964873569 +qmul:5825412784/511571458045271039,1008046458/332866639017254645,1740022059/196312276491243337:5872286723299119072/170285071856685864496671466706726155 +qmul:1850720900/45716430562358967,-3131316310/52356049605863119,539696323/19977050509485334:-5795192539427879000/2393531706325862841899110744238073 +qmul:-999008939/40305492823224241,-149362865/49775456964489,4606037138/47949128805635417:149214837289650235/2006224323454918453607620977849 +qmul:-4057348745/579860156310338,1212653237/2742714067824482,-3833477943/1278732708982538:-4920157089262137565/1590390608083267111519706094916 +qmul:9177815341/2326648645173174,371635999/876014400872787,-2149851912/2031850250792911:487258081841437237/291168245563265658397194145134 +qmul:149460870/500654885667917,8207530879/259222934708685,=1:81780313715146982/8652081915938573470536383943 +qmul:1089507559/134057483313428,-7987532800/42390827366211,3382946045/262278399004573:-2175619340840108800/1420701908072059536662445327 +qmul:6048157042/13712987352923,=1,-2693371451/4466222589529:36580203604694189764/188046022141426146556643929 +qmul:2603227553/49609180587155,471640162/92076035059005,-663933503/13520440154956:175398094974254798/652545235855913432995725825 +qmul:4393500955/6416432605233,-3583476841/7979065549803,441355864/1454382446413:-2249144131879126165/7313876621863906114274157 +qmul:64145470/8127876011853,-4488303205/666124315584,=2:-143952159293615675/2707087922773595548308576 +qmul:2220237721/64548387245,-703263819/579214597702,5697314686/589964874375:-120108681442947423/2875951396186583316230 +qmul:7022991149/836362149630,-1984639629/975088070,-1171252556/150772930335:-663719359448649701/38834607347798472100 +qmul:7911754989/73811019085,=1,8326854813/74451049034:62595867005966390121/5448066538366234237225 +qmul:8670773721/75336074123,7789940197/98427175582,=2:67544808748309163037/7415116995363087664586 +qmul:3813777004/9138760931,3878060903/1782466818,-496564577/8664398681:7395029745986437306/8144769058571143779 +qmul:4360854339/9648497864,=1,=1:19017050565975126921/93093511031612562496 +qmul:-1306392307/687643073,-9598905761/422850143,4622499059/88598595:12539936641788380627/290769971751009439 +qmul:4779917420/76898307,1792785739/166010625,2225422443/217138286:1713873556834734676/2553187201302375 +qmul:-7341873007/81873962,1385231861/3699454,-4877758523/40734069:-10170196408712276027/302888956216748 +qmul:908541847/68126894,3798368094/17436611,175898188/3762149:1725488181854314809/593951074658117 +qmul:-7938465013/6277994,-362880881/3869862,=2:2880717177705116453/24294970416828 +qmul:6036183652/5477115,-1788527459/1739644,-2727500049/825193:-2698970052292225067/2382057561765 +qmul:1659028493/577907,1961575125/200776,=2:3254309023535036625/116029855832 +qmul:2324185733/425376,-6101126398/443667,=1:-7090075464730639867/94362646896 +qmul:158821375/2278,5716179055/50437,-700123827/1726:907851417261300625/114895486 +qmul:6937745972/64507,-657862356/10135,=2:-4564081910469430032/653778445 +qmul:-688655549/3844,5925620489/6516,-2612322997/6399:-4080711431017943461/25047504 +qmul:1356483025/6163,=1,2367819633/2590:1840046197113150625/37982569 +qmul:6911498420/997,-520233898/887,8567846181/167:-3595595764057441160/884339 +qmul:-5665580795/223,245568655/53,520214901/133:-1391289055621980725/11819 +qmul:6848382683/88,-3930604705/78,-4380032639/66:-26918285195440323515/6864 +qmul:7058656941/92,-2614182743/76,1606422009/16:-18452619163919369163/6992 +qmul:348409636/3,-58882183/4,8721866869/5:-5128779986478847/3 +qmul:-7530659939/2,=1,6943419397/7:56710839116859483721/4 +qmul:5479036571/2440360696983602620,49554857924/4707522136067292695,14037572034/1860137811841092895:67878219709076284651/2872013000259729052687425327777215225 +qmul:-90287321301/55986373996879974676,79056497918/57955348234225101999,68036645565/23598836282510831821:-1189633238075717258553/540784966893457334425356770707772829554 +qmul:-31154471814/4775267091317819455,20452466931/8265429859332817919,7980554951/34755849271476873:-637185804528606582834/39469635202867679038129686483630814145 +qmul:85271504414/7465316608452879443,=1,-10606469222/1904172971848733911:7271229465026821483396/55730952064442402518704478477891990249 +qmul:-16339852699/127321792148125915,3040615183/55882163298738283,-51110404691/61653999585316250:-49683204204562928917/7115017180309586101368162514903945 +qmul:-63804908144/277883532447300683,-720647040/27229766739402803,14615586307/46658500039754383:45980818191445493760/7566703769261267728805752794014449 +qmul:10341018519/94245221741052416,87590141171/60174320543406768,=2:301923757310378448583/1890380727576845520968582099050496 +qmul:94172173704/61262926143770059,=1,=1:8868398300136349079616/3753146119697024991735097864863481 +qmul:-27044253543/1053895278738638,=1,-26863808373/192367352651581:731391649698068052849/1110695258547591485248314095044 +qmul:13955551844/8914953109146301,65978266931/1477260665198022,38242091460/2633752121605511:460381562366420635382/6584854780113319521064766908311 +qmul:21380540693/46366763004112,4413417248/3293403036539,22792743143/98178838808334:5897577941628254554/9544027379514164158953023 +qmul:54517956885/536986169058356,53087744133/624679940801624,-12768510380/23381528319939:2894235345764805705705/335444488298664683363875570144 +qmul:15631958865/98900123425043,57461678219/38736535635779,10636904565/14357297124671:898238590233274461435/3831048155437119617055413497 +qmul:11306366194/20614966646301,=1,48649167285/72083597787241:127833916512826045636/424976849828102699236982601 +qmul:-38850808449/5270347545016,-80555988964/460100649873,=1:260805441388343496403/202074194209869310181914 +qmul:2473793897/257329894608,35125602539/6570210827640,-58955090604/1845404251483:86893501189425904483/1690711659828941653365120 +qmul:8389450307/94247305842,5879374061/445968667154,46708714783/778418252722:49324716521024286727/42031345369212137713668 +qmul:10005721251/317400686611,11885509039/202069710332,=2:118923090370474887789/64137064802662680764852 +qmul:53843304483/15517809130,-37493619897/27992722981,-69059984171/37850731407:-2018780392284038098251/434385732248122616530 +qmul:4936875434/5558111491,-78071231962/38058507841,11261412306/45256951175:-385427947175313421508/211533429761375700931 +qmul:-51013899132/7547986135,18679893598/8111901153,-1770753005/1840835446:-317644735934954852312/20409505810444837885 +qmul:25767898320/6199052159,24344608263/317305927,55665198980/5479278553:627309390361215818160/1966995991832846393 +qmul:-7303061735/68386022,=1,=1:53334710705221210225/4676648004984484 +qmul:20359304675/219624604,16344153007/211704953,-82591435031/427080722:332755590724330407725/46495616467463612 +qmul:2652747256/1352133,-25367065339/52123374,23447425715/95023951:-33646206485402479892/35238867028371 +qmul:48463976225/65809761,-35504206691/75941530,11794361717/16873414:-49162143684574569185/142791255407838 +qmul:82320116481/5180912,-76359077209/9271893,46566602503/1634915:-2095296043408850793843/16012287235472 +qmul:-730645673/7142476,-70390135745/551403,34012585939/9989481:165370572681565535/12663609948 +qmul:-51855352987/140641,=1,21714825731/757834:2688977633406369822169/19779890881 +qmul:-59100071699/229458,-12541528262/72971,17155877720/17761:370602609749617428569/8371889859 +qmul:19150460726/80285,98656519537/34995,-82017816286/22501:1889317802757170203862/2809573575 +qmul:56611908394/98549,76064158111/38373,31178576993/24120:4306137151046664083734/3781620777 +qmul:-96850333567/5969,-11666596495/4102,39126150628/3881:1129913762132343047665/24484838 +qmul:71357908657/3994,7273127113/380,-93120031916/8579:27315533693694953539/79880 +qmul:5232641313/278,-1351690114/51,-35248603917/754:-1178818255481679947/2363 +qmul:22060731824/219,89417675500/637,-9595385874/103:1972619359530955112000/139503 +qmul:37188356744/5,=1,=2:1382973877319010281536/25 +qmul:12414356869/26,=1,12979259021/2:154116256470887483161/676 +qmul:11782172818,32822292611/2,46218809976/5:193358961912883223899 +qmul:-13859731454,7084622496,13548345935:-98190965247527189184 +qmul:321169783966/82442472722749202597,728527457037/49184101549953208178,-116751888207/19107774656803205945:116990502994936318234371/2027429475212472071101744494655719619133 +qmul:554171781160/81669314174466653821,=1,-943011129301/98221859405082497556:307106363034046930945600/6669876877727739897311710883496653900041 +qmul:908239534764/8881960367460059525,321942265297/2978409748429418777,=2:292400693254215542284908/26454117343606783848277419057572700925 +qmul:-293031348403/5516820790390895330,=1,278931224397/2151761313912895609:85867371146880370650409/30435311633289223066668620559015808900 +qmul:766830499115/867319503385856977,853658890931/417340410748453263,960525534527/690526698684531078:654611673406576077026065/361967477793198051355224772486965951 +qmul:-197174946287/216799088567900459,769225126373/927398327060743836,=1:-151671922975207062127051/201059112046164919860050113345820724 +qmul:349764090584/42391126842026521,126613453358/49564405785108583,47812347985/3864181199117983:44284839369460570981072/2101091012486211034301711750729743 +qmul:794966910230/98579318608567187,107830796401/4405388705587841,856324471442/41561939350641701:85721915042543174082230/434280216802727167073601578773267 +qmul:-179910941947/302835045319248,=1,206545791527/3108222449901933:32367947032256804150809/91709064673510989994239285504 +qmul:390922759353/8379914783143840,539029053922/2783352468162407,377026177321/4659432906395457:105359362565312633416233/11662128247327024341591580811440 +qmul:-30764803124/12561782256971,-539449006376/482535642547081,580743800830/469238701287641:16596042476595060718624/6061507672904022859307951651 +qmul:-569617603186/169437350142461,73746787167/436340763191759,=1:-42007468148734603114062/73932422674350728263711178899 +qmul:869918621105/65172531895443,=1,489477033911/47131389526667:756758407345224551421025/4247458913662535154284166249 +qmul:-8609389849/44096958877799,224885883076/88640280149647,-627519969739/56922930432434:-1936130238937915295524/3908766788675566748905986953 +qmul:471174356951/3605083055021,-674320263703/7196435655733,32653595707/4448011615939:-317722416629289771049553/25943748239031977053085393 +qmul:-321789321980/1418987991609,661459092590/3534157194181,275403065624/8396219756123:-212850472922042142128200/5014926619001395811627229 +qmul:239520095411/796512451093,194140409620/80232450203,352671980162/687407449757:46500529435313022253820/63906145568388595421879 +qmul:2337932296/15976804799,891988698331/936480654559,185442793337/376858000885:2085409185495046197976/14961968615928892428641 +qmul:935302241221/78956895643,-101991808861/3724031317,979935584834/36290437707:-95393167413877147259281/294037952067632851831 +qmul:961545851/11884552,=1,185080005240/12501042413:924570423575314201/141242576240704 +qmul:58050869295/1757344829,=1,11607624876/16788707:3369903425905173797025/3088260848013039241 +qmul:363276341759/9253851473,=1,406409104036/7111288491:131969700481801767214081/85633767084344269729 +qmul:939766494010/411615661,=1,=2:883161063263847365880100/169427452380466921 +qmul:95392761314/73563601,412095417791/369293182,-720870043827/236439997:19655459913964986068687/13583268146334191 +qmul:-283241870542/75087435,=1,-46818914283/44014963:80225957228131087373764/5638122894879225 +qmul:443163826526/66515353,-29122331797/35808847,186565142908/1472243:-12905963996518321847222/2381838098727991 +qmul:-24774947444/1227689,-306928083461/7644000,333533328161/4876266:146233214169883088917/180470283000 +qmul:113920584697/1429782,163887873152/2653059,=2:9335101167111804177472/1896648001569 +qmul:90035464372/14941,-388195481621/80696,941463087781/51880:-1248262873387818796679/43059962 +qmul:67426970975/82846,-112582136156/206687,205395396001/267511:-291964324111311925850/658584277 +qmul:588160655449/37102,68128342139/34512,685450911404/43621:3082339259009843589647/98497248 +qmul:106389170475/11959,10438395803/2811,-17763245232/3457:370177423523630505475/11205583 +qmul:957920630589/1100,-65200663999/4804,-495801128911/3213:-62457061172743590465411/5284400 +qmul:86819672583/656,170251645086/1615,-548605083301/1646:7390596041541820438569/529720 +qmul:945486048523/580,28855850251/335,140898494269/717:940786338985841645837/6700 +qmul:-942729414451/606,-155199725039/485,483080000839/479:146311345908972673138589/293910 +qmul:581542707907/80,200631032151/4,19978821934/5:116675513727268918917957/320 +qmul:122743007281/50,559800662157/65,225369102329/50:68711616751045272165117/3250 +qmul:35327132396,=1,-649864145447/7:1248006283324512700816 +qmul:308054644516/9,-604402431775/8,119532524081/5:-46547244066263391973975/18 +qmul:3861743183656/92552781226942245973,=1,114427276291/73077495457803798401:14913060416513578545526336/8566017312842233033877184833269634716729 +qmul:5469306927311/39880346228597657723,5296888632971/77121945726781675037,-3329987784143/28763591448200709046:28970309693503183254970981/3075649897407170819117742626456739360751 +qmul:-4797915047085/1960347615737482622,7417719670675/7273127653602457926,=2:-11863196274329991106244125/4752619484897976601830464968970387324 +qmul:1723762402189/606999775863219192,-7434692936637/9420435145331634673,-763069528725/1760517742915668356:-4271881385331661962366131/1906067340583431653778258276488748072 +qmul:1247346376719/305242807686295279,-8174066739160/92487214707299057,864841572942/954533768467866835:-10195892530150517269616040/28231057092341186368611708660251903 +qmul:8115256720883/749493161740626651,7922190030123/83578659421247020,7349631862907/82560331952121241:21430201962022657324386203/20880544567891147401285999555443340 +qmul:1753584378376/56804157255787803,213889152627/40140349321665607,5387174104820/22251532318661783:41674741861198575821528/253348746130016489574409435021269 +qmul:3381018621303/55670925159235316,-1242546983419/8405146979568516,2994898998212/76089681788376449:-200051166132548046722617/22282014688187220091206580424336 +qmul:7888297086927/3953740879862848,2176178614605/2418237546542311,-2065888373875/9727383036996952:17166343426221456116768835/9561084644983571534390308961728 +qmul:1741311395143/229412472933092,2666488500577/3024227444254530,9874403395326/1841428086863885:4643186811072502030497511/693795496698556358912507906760 +qmul:6845501734987/168012430428203,3889846647591/491851863425965,-3888780746586/199780562527063:26627951974917556063966317/82637226984836948219538490895 +qmul:-1284195095943/549849541303853,161668973970/13553314165481,-1448576168827/183855043551637:-29659214791201502800530/1064611939576677294763556899 +qmul:-980146856483/7876738616913,817692682927/16494848113266,-6731998495411/30165003479004:-801458912740049493365741/129925607113876840407267858 +qmul:369161816291/12273827592821,4261359385017/20241923902166,1173948411280/40404643959651:1573131170441574491911947/248445884122187978887950286 +qmul:621724265513/2926458480357,5890921582229/3168077061735,=2:3662528893906004858368477/9271245983738877773839395 +qmul:4707387599849/1922231158856,-798328469963/4676681253515,5101926004665/1755468911768:-3758041540110251059835587/8989662425544269173378840 +qmul:9303566596976/14895662221,171128850459/80855092303,=2:1592108656909253425611984/1204390143793264984963 +qmul:-1614421541843/173435332903,8142990982280/901238217503,804529656112/153754860089:-1878031436689446098791720/22329507182505589485887 +qmul:-5960114035004/31883313095,1873973661895/29899945043,6761957056543/92101155065:-2233819344697646018194516/190661861865852447617 +qmul:258875168272/22951320927,3271990041276/1787602169,7831605696304/53881261029:282345657506544241865024/13675943690173430221 +qmul:-3741159259/841057,1140691661765/3674903711,117686209034/892146331:-4267509172076226032135/3090803490462527 +qmul:20024244473/524834174,-9933799893095/4311996268,1282763801711/933012946:-198916837605195544613935/2263082999606862632 +qmul:9690216301431/721938703,=1,6855538744648/1038547:93900291968519089052647761/521195490889322209 +qmul:9772645191158/606342281,4046423002077/832945094,-9924558382428/71076263:19772128146319455948017583/252524914121859707 +qmul:159522763697/46674038,=1,-924733338517/15943657:25447512137528901107809/2178465823225444 +qmul:9885845356901/75377901,=1,5061603222137/99444337:97729938420561060068323801/5681827959165801 +qmul:-3014509110363/533159,-6677531265927/3294029,=1:20129478835870717944501501/1756241207611 +qmul:278495797709/459094,3008292413757/8715826,=1:837796795511188800682713/4001383421644 +qmul:9263458041541/380854,-749140991886/18803,9474188106647/58449:-18166586768414575214493/18746591 +qmul:-6233175654833/507607,7036736213809/354450,815399146191/197662:-43861212857395998672188897/179921301150 +qmul:759911289647/22797,-4620304106965/4804,581754997430/2403:-3511021252485103785091355/109516788 +qmul:5617203937033/39335,3723507511221/6193,2744191857630/46241:20915701051602548624947293/243601655 +qmul:6420686828307/451,=1,-1838097053444/3113:41225219347195003296486249/203401 +qmul:-230435506159/3050,3395048403224/1759,-7515243692907/841:-391169848615613583728308/2682475 +qmul:9537534272745/521,8952214414132/843,5712074011478/809:28460683930581916956810780/146401 +qmul:-7519755017367/994,-1817484841018/15,5714574669259/496:325405732196037376760943/355 +qmul:-6778271913655/47,1098941771956/15,59404867523/3:-1489785229518322546491836/141 +qmul:-2383271627938/37,=1,-1307389832067/19:5679983652534244702131844/1369 +qmul:6051325942003/3,-2529633865827/2,819845568100:-5102546345349420428543827/2 +qmul:193126426699/2,9833682493639/8,3235704083583/5:1899143961289011867267661/16 +qmul:92112640764600/11163413455400457479,51791476178419/14329005607185776493,-13205225377669/4458612884103206586:1590216546630349267393055800/53320204665922099816203131218014747049 +qmul:22529406302098/17968547726331516709,90921027222753/2166236440992021142,=2:1024198381852757628328617897/19462061438241829125530785318127130839 +qmul:-53737977727933/7683225139372625170,82909671587883/8352188215577205409,=2:-4455398085219896100673435839/64171742466694571547497029664653544530 +qmul:9092501686631/9417724412639248549,-76436516279586/7751295678592549727,5796309029559/364193213335723936:-694999153192333594154414766/72999566541866165880702093299195096123 +qmul:3136955253055/79379115811095793,2712229195967/40950870811518088,74321528780980/800208315081442781:8508141623777819670429185/3250643916712716666840937120203784 +qmul:-15679427832242/304946032535805217,39088311244217/271842618581639769,-44522979753228/676520091746633939:-612882355237913950168644514/82897328010615208848930336644874873 +qmul:58297984629025/79211523461014146,62851948787804/71793418809815961,70122280069093/70263603402410591:1832070972167832036692205550/2843433039200075640773122338792153 +qmul:3395759457623/8856655409516280,80356132877828/35186041698707317,16595221216126/25184750109463717:68217524549473731850570711/77907661637580389256034066655190 +qmul:25595373885269/2107431405075994,56934769844557/4108548181624632,88071750654219/1721697405597152:1457266721243175200282130833/8658483467223618408882342284208 +qmul:5741950765088/69374989603141,-20852939430084/837468342763903,71732839501654/4900087435552233:-119736551514904546484107392/58099357572205493945030219323 +qmul:60636029091157/828828822290712,15933414624847/515795094226125,=1:966138992713689089520177979/427505840490766008807415251000 +qmul:68154525908584/447018537159783,-53054791972077/814484661933752,-70920570409331/22166122764311:-150663508084810679482608707/15170405921529425529107695659 +qmul:3803110014020/54088464597551,8401206536763/81355553929736,20928341840506/38139684449589:7987678177453412143854315/1100099249635669192942919134 +qmul:-23763903446216/81519641545907,=1,88937586611085/34349668275946:564723107001076681204718656/6645451957773166616788452649 +qmul:46601565963875/3780648692562,-40570846513055/430918579048,82143257528821/7547555659366:-1890664979988380613845888125/1629151762478496046640976 +qmul:-14254006674106/532459447725,51813993717043/1845962555644,5112664309595/4080729032211:-369278506127408636439494279/491450101449616910854950 +qmul:18869803536517/528732466966,25637726635604/291934133291,-45103838882314/248345183985:241889432368388223683175634/77177527243265749182553 +qmul:14394788665063/18929691934,7293379245648/106206553763,-1412717946745/2868209191:1418738552638642755032376/27168342487910789833 +qmul:19814466847315/45927017182,31387249087211/83776988054,866410007468/44667970667:621921606466960354656188465/3847627169812266743828 +qmul:-84789189148688/68506660259,-2668232889482/7021853339,31544016021473/26570873119:226237303159039621969299616/481043721083397754801 +qmul:47144909009231/2853410746,-18254711672997/1611442139,47906136756089/4532570474:-860616720813190565726435307/4598106315979825694 +qmul:-88984055558977/5497567684,-29028728538235/9008297936,22366306780529/477338571:2583093993052764435041985595/49523727620797500224 +qmul:-22301781837379/314747366,-55932418652881/999474189,6168064682011/82717920:1247392598433499880191838899/314581868372736174 +qmul:-69455755003925/425627363,69330030826593/45004450,36456142539195/445137553:-192614785420256450548375101/766205015070614 +qmul:43441277702263/29813565,11503955305028/11366299,=2:977977528532569481665124/663150477585 +qmul:-63910040173409/12354709,-70800414587599/73292555,34497242288193/35625551:4524857340587464687180954991/905508188891495 +qmul:-7828296754760/3568223,-2036289302690/840627,7170972735213/4627145:15940676940000630338304400/2999544595821 +qmul:21326380201837/9337727,-17663536047163/4880532,26768558322470/1065127:-376699285450651185091238431/45573075430764 +qmul:73980502263403/962358,-21947232844793/591723,21986948107511/9185:-1623667309149641199103010579/569449362834 +qmul:11206027962511/331874,-1256483151365/547727,36460011888012/776539:-14080185328620131358477515/181776350398 +qmul:24401059998574/37451,=1,-59473261910475/49718:595411729054008176882033476/1402577401 +qmul:-60818257728179/86203,31465212303166/90637,6184562112579/9476:-1913659391325818531369114714/7813181311 +qmul:71004965949889/9037,7059443197743/235,3055009450153/4139:501255523880917233655900527/2123695 +qmul:39294675031972/2789,59869119724423/5716,9542643866131/1571:588134401005356710838563039/3985481 +qmul:-41787574848379/366,64572657701526/571,-32471089957981/546:-449722461143545734347821059/34831 +qmul:56523234971544/89,91170129020768/233,58883776410491/503:5153230625026852353065025792/20737 +qmul:22661601391845/32,=1,9300929081980/9:513548177642871241232504025/1024 +qmul:31371000692905/28,78617790969393/17,23430144401503/6:2466318774975488254647256665/476 +qmul:-97166077882733/5,557907250924,-67696293193377/8:-54209659394622846477895292/5 +qmul:49131886852510/3,44123944198873/3,=1:2167892633865493233459221230/9 +qmul:11078630778023/19971767689676985138,5498810148139/653213547400621899,-28047430739573/8529087351247312093:5538117031788903405049927/1185984474585002385862227360780030642 +qmul:225961652216941/7065181247481573942,-551303465095893/52284679786625043776,12334914241622/807684136438179561:-41524480615330881905534707771/123133579719680720019267336626376961664 +qmul:-140752952779551/667166575947606995,=1,=2:19811393716162513576803761601/445111240061654052498343266972930025 +qmul:97203673992431/3238422544888880032,=1,810591359275652/4195094984894633475:9448554237626806783045289761/10487380579244570205870590527288321024 +qmul:-167516702376095/716105586249718324,97868227848619/242920547738562082,=2:-16394562796592961287264362805/173956761250425686574425765286990568 +qmul:-709927885497849/861328058843025997,496445275118167/289296738986245691,-290819441307632/13291786866431071:-352440344430038207159099322783/249179398620640561552626620942228927 +qmul:425323787423127/77722671910833479,317441925005700/19142048058380233,=2:135015601830312569987786823900/1487771120942893870562005728220607 +qmul:268865886927957/35135976545503325,123771762953727/25295982530865037,276904755282677/20891637935797169:33278004823190660692373645739/888799048899935778999904809748025 +qmul:-28086740887571/7601230497184463,100947908107803/430543690291880,118463785601217/2540243084118529:-2835297738166190579370816513/3272661829016980468206671060440 +qmul:-103171508624837/2023211396120145,142320636082678/1434318582636373,-735609507967093/4547494153253362:-14683434733096301226416273486/2901929702056803783817555034085 +qmul:-220041868728731/487356763210567,11401923921896/63654265331715,-621742292531267/238183796053545:-2508900646876817363255193976/31022336716611231326648232405 +qmul:500876116381607/333341742549014,=1,236931212585485/143461697112113:250876883961521120142447902449/111116717325613130586192372196 +qmul:27571394309122/1874139359093,126354562695342/663284435945,=1:3483771470829951376257509724/1243087467678324311797885 +qmul:1227588316119/3212397849532,273285780765847/3937050058645,177000179976745/33792263075573:30498402857237483359526163/1149761012899184771436740 +qmul:935605828517486/1504497672649,142177975023733/2313039446120,394962145699157/847510134854:66511271059509072349527747619/1739981231716436016585940 +qmul:848730874297608/1142939979439,56376353318381/3143925208632,-237516636617763/1280813501326:1993681318400848339723780527/149721575554650494388227 +qmul:57281039318273/114674810495,6245708686714/18061176617,39223096410155/17868534091:384275708758478900851262/2224663808669387965 +qmul:-154031591323851/83034647227,983277618862577/807648489169,313967727668057/230581524944:-151455816346529785816271424027/67062807381567445384363 +qmul:-926888573138874/48704635267,6005840682571/273079429,81726441309104/13903294547:-5566745100767635280134365054/13300233988365622543 +qmul:169804184361113/49086554885,384285590061633/44857652581,=1:65253301182144623556398477529/2201907625429518408185 +qmul:-225793750988921/2498217360,=1,171352487415765/2208376327:50982817985646863065464744241/6241089977805369600 +qmul:-929534096793899/9204730148,8408973696/70382485,=1:-1954106942368753656070176/161962945392664445 +qmul:-27418637405473/910326852,=1,81707725335094/491085905:751781677172803165010353729/828694977472229904 +qmul:-223297515785450/193612253,-474964608127809/679335356,=2:53029208540474751774311289525/65763824408858534 +qmul:3933126433661/878772,9000930134181/1427513,476332935917525/79251326:11800598746094380908355547/418152818012 +qmul:703078612387607/27834381,373006385325321/46624543,=2:87417603935414581043747898949/432588431270961 +qmul:28193205330738/1040371,26659473685633/1938099,=1:250538671876152577201295718/672113998243 +qmul:449065926671750/1450887,=1,153785599009868/2460537:201660206497557548032248062500/2105073086769 +qmul:108938909775878/133591,917154127926373/709564,=1:49956885396372608707157715247/47395682162 +qmul:987814971089463/782828,=1,930147796775719/981962:975778417108476622509149628369/612819677584 +qmul:175113052851196/12305,-227591234473631/6533,64742021370129/15710:-39854195870849886350828812676/80388565 +qmul:-161174581471221/66310,=1,=1:25977245712423255688851230841/4397016100 +qmul:-1469325465654/4457,=1,582669979881900/2099:2158917324019343933647716/19864849 +qmul:102435434692175/7466,-187593100206263/1358,174025094651948/1265:-19216180764881294058412092025/10138828 +qmul:489625099725000/347,-332985825161621/684,=2:-13586518154314174697304518750/19779 +qmul:-832879871119661/546,=1,817644952915049/828:693688879716303117501780754921/298116 +qmul:810059612480081/97,-378237813607713/41,=1:-306395176716377100781960464753/3977 +qmul:-534858850780477/21,-597970346506983/25,=1:106609910777842848826760190297/175 +qmul:950469485177429/4,=1,423712356772633/4:903392242253446925539611050041/16 +qmul:463433346779246,599836163536496/3,225455874511593/2:277984080786941465486776362016/3 +qmul:2132350013169985/49772441764072596049,-6499905025666569/10288915167781867756,-272858606518027/93421129408183888508:-13860072567083760096603328731465/512104431003906236530336497276926096044 +qmul:2042725727410133/27578306884656676115,=1,-7376907052537410/47153921627935428199:4172728397423256990351591077689/760563010624301820302156974840011493225 +qmul:1904035906025563/789989122373815219,700724530060177/1554126856272208244,-1373172495932670/1505401488389199241:1334204665467465969877290304651/1227743311244058254809898816344465436 +qmul:6705450642041083/4046641113087645351,236666376333371/9320552548004534960,-6289242797407739/4040540787026624125:1586954705134139142713085880793/37716931137448960379165612296160970960 +qmul:-5772878945452494/146823071716041731,=1,-1872446183124785/135874056483712011:33326131318848699195882410820036/21557014388133933331867562533476361 +qmul:3589764099796053/928994578492406984,1705996612666706/892580995601505897,4870605263289071/654751374199986585:1020687565754102262148510551903/138200484296525657161313541766664108 +qmul:2824552679707636/22642111815107669,8553369491681540/46601368890320207,-8526667827191440/6342142386526223:24159442718258634195461218239440/1055153405151710120834997591367483 +qmul:35430767900375/179014168662113,8330204183383419/90063013345106792,735637729618171/16696810462910716:295145530984190781866218882125/16122555461179081195997749371496 +qmul:-749012909078762/116545251178673,2437513877538073/992308910607094,-4884979809735527/4653837505135631:-912864680167322642003505352813/57824445616769571297747653131 +qmul:4715463621576807/1060495506862783,-1063435887535687/201313562930691,8544123110589389/5820955775073193:-1671531080517925550574808003803/71164042986178638246892124351 +qmul:8571923230143950/770828515798001,731727930435031/3506899807300,-1965908269773871/252650249852419:125446312900823969405125054249/54064367470267094252504146 +qmul:9586220341682297/144114066713962,8236658921505002/167483669474359,492069171252854/82950316475131:39479213650415110088905890174797/12068376358063466929473150179 +qmul:7229812835375017/5756294662713,905126544819761/4153935003623,-5202620176105898/3258193118931:6543895511376548680891107310937/23911273890611781218009199 +qmul:9842204333944723/52899600131954,1723939662409201/39238775342850,4378255309793533/73130188348848:16967366416823040750958140596323/2075715525304341221590428900 +qmul:-4908316732166843/1357513064850,1991070604269898/8806978369757,4254810663841145/2351480888682:-4886402580931743595080769296007/5977794099398240809870725 +qmul:274318025224231/1931992361708,-3590098558074758/5846677514951,57908255856314/1134380359933:-492414373405713403344305530549/5647868150127621484948154 +qmul:735894125946707/55761889279,3377584488978728/61428633213,=1:2485544585328156063980584648696/3425376643783608023427 +qmul:-1690249237930933/34238968152,3446531515472379/225376230292,-428431726758614/563113867237:-66959738707265887616299668961/88697121507880524832 +qmul:-1626151698227417/13809511809,3803324818338850/20014571999,8945616470363923/70396608712:-6184783112252203187079466250450/276391468372271236191 +qmul:2032027608247493/71600869449,1568676792624142/1225766355,6648151008356102/92054212485:3187594551029383836749262776006/87765936759331588395 +qmul:8570254081381348/584635199,833484957898327/779308020,=2:1785794465549524494136774551199/113902724838748995 +qmul:-51136063956207/124926985,237718332836713/43997825,=1:-12155979871501058567713827591/5496515623807625 +qmul:7279740565485383/495827506,380399580451240/42684993,-8253225185096257/179789767:1384605128452256161054382112460/10582196811408729 +qmul:-3582542718233341/437814906,8075748423185005/259890457,473970333141547/96599174:-28931713707765825242358002251705/113783916001752042 +qmul:-4332079095957017/44663887,=1,-2662542824998505/6313513:18766909293627765704435111538289/1994862801948769 +qmul:3371800081330173/11806858,=1,9890158011622886/66900743:11369035788458161257397040209929/139401895832164 +qmul:-3682944955162964/2466265,-355431368138229/155860,-9055791203817172/8090387:327258541047840188915493337689/96098015725 +qmul:7504952243792624/7720459,=1,6076575545940466/7559395:56324308181607941582939516805376/59605487170681 +qmul:-538608400556109/199304,-938340266223845/397242,-646694290244130/361681:168465983322739554802492073035/26390639856 +qmul:-727793735158436/238619,=1,972430738127054/625301:529683720935867681422021966096/56939027161 +qmul:6931913813817249/19931,=1,=2:48051429122190398233188769928001/397244761 +qmul:6291923102424872/90007,5686581845796881/19366,5042254583042820/677:17889767844699633282716137212116/871537781 +qmul:-5554695053757275/6432,6945167426101948/8185,5702999642802475/2694:-1928914357464231764593229833585/2632296 +qmul:2346204224991933/394,1993188578793011/992,5657592821492399/465:4676427464769828756406351780263/390848 +qmul:10931191773819/59,9918357253026368/565,-1883501998767878/147:108419465214079847823899059392/33335 +qmul:5137390097848632/355,2441231132619748/159,3483872315060623/865:4180518882426831300124305994912/18815 +qmul:998295698183777/66,-66459889053732/5,-7667707076954093/93:-11057770224018624245927284294/55 +qmul:1731949876588457/12,7146744265770853/16,277946983627531/22:12377802849111091588166946843821/192 +qmul:4833330269678962/7,=1,=2:23361081495794907533662545397444/49 +qmul:4819457078692447/9,=1,-8437238110144547/7:23227166533358735275059214847809/81 +qmul:41244630307260683/19566167985724232189,-19443176533044379/82985325719207603055,-72237473765794569/82811331956111155429:-801926628104221886667557960850857/1623704823372057546563828915880965737395 +qmul:-37802618179190435/86632766813453833079,18052713986379148/47810592068654841423,7865481647337074/9519629220475921943:-682439853925221807159327605049380/4141963873896940191789582700970256831417 +qmul:19604614792857791/565916848676700071,25954734261578645/2626241461504040026,=2:508832567249237638495290647473195/1486234291758457454242685700381041846 +qmul:-50232902667050876/443948998116187511,-43501226416110749/2403446154007360893,1072605872716961/3220822759958359344:2185192872457833663604613633466124/1067007512097771979528373151836407323 +qmul:-14994187874938337/764476959662103704,-33213154437024890/559246869916170493,-82827329689594088/466257548265395579:249002138774046516984579242103965/213765673407031013718036719955403036 +qmul:5736891872168725/77162101379651687,62325478498146677/137153821651647001,-18320014200167058/208017523087093295:357554531025044304704709142076825/10583077090891052476054011258140687 +qmul:88925222453111571/10971132513398300,-1434252874823377/1536739410012178,-23821379824785146/29460096443622911:-127541255947683583837180699995267/16859771705805127088751164497400 +qmul:24175746316538219/53267154590314585,45382600351882515/10887587811518971,=1:219431646658389958690970919068157/115990164614361176557282717098407 +qmul:6404581190281274/1974919158789793,70447714998202471/6402341997956028,49530122164311697/8312624539331270:225594055187891770083262445914027/6322053936443940716188054611102 +qmul:92136543904285079/3155539462802804,15181471002529652/4087143424836463,25144211605663718/418936831080179:15204002929958740164475777811549/140186330078331141119949106981 +qmul:-97970673283608013/593909853478849,56972616762762010/241259986786383,19037324141894916/620131018874825:-5581645622976766094030156047986130/143286683402609773344371713167 +qmul:73158390938899175/379989099030207,71464686184078751/642455545049147,12129094284454088/244856744399541:5228241450180579956236327448930425/244126103730185933897852583429 +qmul:1586267657723262/7744841531795,15363089519026552/9850991413231,-22902559865915557/6801969550956:24369972026739044413538846052624/76294367426547369870179645 +qmul:18929755299266541/13128569349373,=1,-44651987164496438/25396774874437:358335635690109691215372562104681/172359333161296196535493129 +qmul:80561540824410061/2163952339904,=1,2086973582459110/2490108327963:6490161860003088890959828678023721/4682689729375996750729216 +qmul:78697609896523577/5434699087585,65526206295867334/2106565485155,456371042378372/32324922977:5156755821071294622615308595133718/11448549520109931362300675 +qmul:-47473161024846652/621907871141,-96761692332772358/887316304237,-65934541786023949/449412506848:4593583401150371824007100974445416/551828993796732548324417 +qmul:-14783030669421870/467861289269,=1,-23413922007662121/167402876249:218537995773067621857840034296900/218894185996450894554361 +qmul:63487097677098051/89903303933,-44532336344734228/31521473625,40321416288169527/20383337494:-942409595769175172584041963929876/944628207908139422375 +qmul:74416958364864933/47087590129,-26664478457249131/9883383278,9944734731289232/14129955379:-1984289383173946522947645546623223/465384700882276462862 +qmul:10292005168487623/3482492353,-13044085486904942/9174614883,-10587235554824230/4781845077:-618662650918986430811618914898/147237447796163547 +qmul:-6144278338130361/94748822,=1,4769179777732015/4767529558:37752156296417990780857029990321/8977339270387684 +qmul:42358656711205552/153537321,1887261908080343/399926027,=2:79941879288510016603861603664336/61403570783753667 +qmul:-46666950687843206/336186639,38668781410567001/444012970,=1:-53075121036644655437487007224859/4390330236961995 +qmul:37185667641742945/20035026,-22282077470907101/78670922,-91228561955942315/41271552:-828573927200719662619441817152445/1576173967713972 +qmul:42236447866339404/44996449,16229676747835589/11939847,15179360621924853/92208979:228494631949166233448275154749652/179083572201101 +qmul:14470604449517903/1841454,-26915603513076747/6747551,-30708091604466747/2448316:-43276116884198675180320043277949/1380589419906 +qmul:9101509000956136/4152121,20427468979289790/3465161,-3271799016139078/320637:185920792781758275773092222651440/14387767756481 +qmul:3901016944389149/228999,-12417812802023553/360344,12000955177317426/2675:-16147366050982125724725565208799/27506138552 +qmul:8669125566587600/469719,45940493589390645/423401,-42531240992326551/367483:132754635839146726987952004334000/66293164773 +qmul:5938430877112711/95612,6188074245922706/6253,=2:18373725585926676351062678057983/298930918 +qmul:21515481020492051/20064,43874545790741615/95584,=1:943981957243410623387527502402365/1917797376 +qmul:96468586146884551/4608,-79928708129965834/6685,-48993051068173945/9779:-3855304732922400319985402586215267/15402240 +qmul:-75478054000012419/5456,26589933777011524/3359,-72036212797226203/9505:-501739114369507496870468176529139/4581676 +qmul:-72899856135461282/473,5291266619094049/285,55496817136408/17:-35066597755120434743929959646438/12255 +qmul:41749939409527385/879,1093119177525389/32,-62509807806005818/473:45637659429077399966594328277765/28128 +qmul:32236549357972163/25,=1,-8149826384158677/14:1039195114508975474515043482898569/625 +qmul:24629347956178358/19,54301261705267425/23,24457116479256857/3:1337404668998534392792361387388150/437 +qmul:2790015469580797/2,17009277246386333/5,38190184436799791/6:47456146643806530617054620047401/10 +qmul:24781556873646101,42986775647721679/2,81575207729973183/7:1065279225528679999746318391523579/2 +qmul:515152885774965653/15080197507802975795,=1,-424832628935135224/94106513082678027465:265382495722274809438289573329716409/227412356874347082213525456257355882025 +qmul:846127691843273154/45393076460118791167,107731662129978485/4427725736529596013,856145822802565237/90388573766016577258:30384914205492685300912483332697230/66996030967574580526139479740140939057 +qmul:678813466845095843/4312328116586154098,456413709574125389/4100698962952630264,=2:309819772511642767874990940604657927/17683559435596311365398737033122421872 +qmul:189404516219742695/1881568644309026479,-990060962742696423/9938184412328540522,684558164600705533/1843391051573289937:-187522017676333112700620971556879985/18699376171598111009073165236722482038 +qmul:192924629174279610/915194634829559941,-505412960023216745/330833788805155829,115339652249094077/577677115897920453:-97506607892354095477504410264069450/302777308534814344556633116001046089 +qmul:530864983303082949/770272174330693891,=1,=1:281817630497382538228809007974536601/593319222548134880807536517544719881 +qmul:175427266863787420/37379184998319363,-737495252249552281/10171255350907481,433186573015158365/49314816010026687:-129376776427158427582783706960105020/380193235426716462103801903854603 +qmul:463395468161836969/36199229685681434,-381172902361185896/73861948752008031,951086817685754053/44721463664985715:-88316897770133955247493298327094612/1336872823952984931159738037798227 +qmul:388421361132459241/3796589587440279,-520242627647240191/4183488460948680,=2:-202073349549868206476119002444555031/15882988730014316745493183881720 +qmul:255643017739843159/5399110517536783,649866517463532383/2945752280295836,613430013767040536/234544931788503:166133837652459903075867976537517897/15904442118603209765181251735588 +qmul:155181948901437661/35620018080307,17101221587255570/264465563715517,-129836961434774282/466340126852825:2653800894505656514308728430021770/9420268161165298444608023719 +qmul:-839143559403582175/463688071748743,=1,-142780189059606272/172165382315553:704161913288513246519800221977730625/215006627882067436250122080049 +qmul:346621266229749718/59475689434557,=1,178397168700747228/42081103836349:120146302202715032285390908921079524/3537357633715875158385786249 +qmul:-375320695921875535/16168337083266,911110281599467718/34637020854445,777071986002999094/76066266020689:-34195854495148821384333396824647913/56002302873478088643121737 +qmul:-379308371310412479/968244496075,364865258770202694/8926182578765,249116584254479273/678952630517:-138396447051877776676786583577018426/8642727152849761420847375 +qmul:-10969933869374653/142543298333,=1,395828837569758458/4480744606673:120339449098453146428785278870409/20318591899650640578889 +qmul:357124791031669775/761802845389,917629329624700777/456858033563,774468512475077245/2887603961:327708182586752487826277715049915175/348035749907116661791007 +qmul:64954492028958167/95392360685,985096782515221787/715883047223,-29344192999567326/73661198051:63986461107637310581155676549984429/68289773848973303627755 +qmul:23618182683258131/18112927883,442655807275151908/16356517261,=2:10454725722029641395907751401163948/296264417565537688463 +qmul:732585647194345626/45048543997,=1,16467867097466398/1145670835:536681730475158241367430266345331876/2029371316249644736009 +qmul:157646812856286773/2982936935,123752181092126225/1627719293,-433800406988365539/1824179539:3901827386637546694386616182784385/971076799780357391 +qmul:18335836145139783/1476948589,=1,100294147058610519/4053918910:336202887141414537392732609287089/2181377134549090921 +qmul:-500900480985214557/585315200,=1,822543455056953279/726431948:250901291851219289979222443324706249/342593883351040000 +qmul:5430413424253854/29413111,737754500982617905/865566667,-431507384954955136/126635381:4006311945939711393067198205655870/25459008454371037 +qmul:69732083733340845/57018307,-850680479702859385/88346816,101371097024811051/77572577:-59319722440958347782449205312080325/5037385877160512 +qmul:935028252174165503/84545212,137808471873317260/91516351,=2:32213703647625121220176793216620445/1934317324190353 +qmul:350565565504682243/9619524,=1,=1:122896215717617656580228756399511049/92535241986576 +qmul:-470988077361736572/2840381,624215376275621564/9300947,748400046271858043/8643413:-293997999931687952811725899730638608/26418233140807 +qmul:238657877711036557/147228,760003504393876182/402581,40545524725498725/11806:30230137235265489411523617722264229/9878532578 +qmul:129309397398813154/103143,99499262875055329/104050,2865516124888405/1398:6433094861999752891251268341498833/5366014575 +qmul:576594622826994119/24550,764054211007945383/64450,196951790705325699/2321:440549549615502846208286120014202577/1582247500 +qmul:34307832224344795/5419,755936660033161242/53857,=2:25934548104649265347571596038435390/291851083 +qmul:-28093068552310343/6519,963611383601696677/3318,306035391422838526/3427:-27070800657309083458092703055830211/21630042 +qmul:144703609571824207/1943,353612545017871990/3809,419690158507626277/2547:51169011653965259593108361509261930/7400887 +qmul:533530159200500829/854,84950875994057867/97,561763750303203654/161:45323854393331697896795654407471743/82838 +qmul:786023983959036523/653,=1,35801962841884787/949:617833703358835705221613270447929529/426409 +qmul:977510365280960078/55,232111556352335897/28,846828806350115358/59:113445726117952006128263047051659983/770 +qmul:575356062531111409/48,127909051677869039/2,331562163778887361/52:73593248335467179491251257420765951/96 +qmul:223865459457586997/2,-255265991273068741/5,785308709687044221/4:-57145238420241926425388851168760777/10 +qmul:-89489266878597587/4,408356339430510509/2,320811062710131617/2:-36543509440864137915495881385541783/8 +qmul:6960121193016437767/41673724634003604035,=1,6854483270886536984/32457251506686121265:48443287021476560949924862262183946289/1736699324870758821080322609369068281225 +qmul:252294933101143378/671664801173160007,101031884553475048/1683990887624654527,6217560315186323017/75520308794957242947:25489832554501428241776271993432144/1131077404713826819460225518267901689 +qmul:95022283125541691/1892238412758904932,6220850886629533101/1296487687523964914,-3552806481592836635/292967787422034901:197039818077029516749136819680004597/817754601333936827050096136476518616 +qmul:-9650628580381886023/7106748638657239958,4387498480617035975/5131806125901481009,=2:-42342118233424867760904547954540677425/36470456199103234725545247832492957622 +qmul:933857454927346529/770907817024018505,2627554012834724721/741765905423985850,939220528406657553/251830131719517146:2453760903109972444306223754689843409/571833134893249499170644981258154250 +qmul:5863194086945812212/700078829279068399,9185022137361371361/111682660170098792,=2:13463391871060894578417924384075215133/19546666495663701071851276388818502 +qmul:-1393200667079143151/45785790746761243,-6119736754307708291/97236710970831949,=1:8526021328450249564289054954738564941/4452059701413814892014912979352607 +qmul:3607026924237321910/1072023164691893,248422707771439167/17526050077246094,942295846706978669/71124490430949583:448033697761760632546411047280624485/9394165834178976731308723857971 +qmul:2219105460493025188/4992146804272097,-654894851214548365/261880809182257,=1:-1453280740378971565345857635989217620/1307347444659395118592692582929 +qmul:5112830206310124118/4808519639244359,3895059152513717718/2399893258942939,2005821980379451972/672164805197423:19914776090336848562178934098195722724/11539933867717270078741058631101 +qmul:4465488275906636401/885680900323781,-1104529468377254183/50717559226303,-1531096850412298649/70636195562356:-4932263391432018452889201367737315383/44919573517776726756551611643 +qmul:5805379505512562993/802580360628120,7576393837591505509/381671212464334,827391747551350507/404055288015098:43983841510445403745585851020069028437/306321819340996990853337472080 +qmul:1568069089872115495/10344068691049,6482258105462122875/51585142886372,983293776583976867/13619011887634:10164628567748134676970172369881448125/533600261454209647780484228 +qmul:5123357244469621862/61996475985149,784192904118738215/19232930497666,7315968239528825344/72839297342337:105728957799431815835771283411022535/31378260887436578268293743 +qmul:310186678678899798/454385367511,496289849974746528/1664255858611,4370884482132758378/6990813743219:153942500225716088309659706960401344/756213509947294088987221 +qmul:6896960984221904702/8037366999007,=1,1507716158461831143/4162951083794:47568070817879184399769535232769708804/64599268276726789138986049 +qmul:4124205900530951507/699562645532,2446863765306479999/780453290054,2180063751257648537/428993105150:593609998745433301395350821902024029/32116233429666446066984 +qmul:1901990540997243863/309938083197,1828919653744696177/128932373995,=1:3478587881666366604445148811312811751/39961052858049029262015 +qmul:9909007556102284175/35699264171,=1,2257564478754303350/23996542561:98188430746892162461878914652455430625/1274437462350844317241 +qmul:7540576467990933273/59047654891,-667411621026349909/24648144492,49933771491922816/70442999897:-1677556121324992297591622679189540719/485138376555706170124 +qmul:7181294574913207518/3819238427,-5066099946607930227/3123415729,-1161733643221201723/183317684:-5197308008934802800386778397102263798/1704152767956145469 +qmul:-8059696125757072209/4595320696,6578165258606498110/3168033531,=1:-8836335508230093636747850255982004165/2426355008437709596 +qmul:1945331074426594741/151710177,23896636516777288/9647063,-8779812176082283037/763148559:46486869590364160149493061329042408/1463557635260151 +qmul:-3667612169703754992/456403523,-7174409726077474195/172294113,3512697218966135831/927221535:21444948999024227916663287692324720/64087726296137 +qmul:2801308578321040429/7008589,40646058755682747/3928091,2242284013880005543/86049101:113862153067235113557787361284778463/27530375373599 +qmul:7755272402005383603/37065862,7920705443805205865/32575293,-9791686678342842374/5250627:20475742777585438947450807922570143865/402477104982522 +qmul:-1833317998287765958/869351,2549513447231770664/4194999,=1:-4674068889686691615296143605162256112/3646926575649 +qmul:-9862573495076415071/3231099,-1012500145079952918/2881015,=2:3328619031542189525129501104301875726/3102948228495 +qmul:1848318375383620325/62739,2496061735601929291/71058,-3577860376337084987/826120:4613516772004977608237698310240439575/4458107862 +qmul:3935629218278546095/380289,272948451544220369/89992,728063154313892053/11066:1074223900981319628581080745604409055/34222967688 +qmul:1383092141504746774/6843,9725813952719193095/86512,9563731803386892083/450:6725848423871567383357583818792162765/296000808 +qmul:4310844810185467807/68701,5335008431625026234/79247,4165066621321185249/74158:22998393409766456521092748601937448838/5444348147 +qmul:-1231083168271826293/1767,2942557339085135869/5628,9747542072617181491/4658:-3622532811822443740742409486671603617/9944676 +qmul:2563045864459171017/1901,=1,=1:6569204103321259248191885398852814289/3613801 +qmul:3519211776742706458/741,3845395982348454948/319,-5561268787397081165/773:4510920942439923739354839714733884728/78793 +qmul:8737995292054242122/619,5446863961283262201/940,7037490695241026988/493:23797335825076532425122443838432315261/290930 +qmul:-6758789406646036953/11,3116671878311801932/31,40838395516557640/7:-21064928875125413266537275696088793196/341 +qmul:-2984260832879482631/3,-2187683625033562767/25,4114578793904862147/65:2176206185639821933770592463208266659/25 +qmul:228695312943600692,-8259900599013409474/7,1324126718913604639/5:-269857221767772356131493369277965144 +qmul:2275696080893255434/7,-1435737280894850537/2,294080994708276309/2:-1633650851662375193596252292396534029/7 +qmul:-84829337473700364773/56707961321161574960,-29927022646809239114/25185347367370413937,=1:1269344751844627231939227965424189665561/714104852184429966256312155357027108760 +qmul:17614709128893699831/24236675989376645657,4599289230585863713/53851416063001125139,55430594239089793855/41774891940497902166:81015141996423294341239778695297132503/1305179322688071182919814999640717871323 +qmul:67846551326033993002/4393005431010178629,-25740230532097127103/7368476450475338660,11432245987550154811/3453986965906439686:-41580615998568452669495076840090631743/770708501552589672691163995377845170 +qmul:78323538212378809869/7187022102980425966,=1,-32829495858735303110/2068874202909402271:6134576638105963615443551925372851797161/51653286708729184578994636138807033156 +qmul:12686256534955947787/123247933988654253,81930708153077686114/345994724232647617,16126072813581949987/95957301898986922:1039393981720550346819611040155758929718/42643134932647985540794888997365101 +qmul:90635825716321359861/838907685684947420,6188791645900690243/226601399055279660,-65993207203297829068/942167862280779399:186975413670826858643911432008098178741/63365885084811963416497113498492400 +qmul:4256124534146569459/8100972293435918,-36362420289668860861/78362919838311158,46047806868639334273/57305818998350828:-154762989115808645716121851999543044199/634815842442898538160822217373044 +qmul:60947370495538663/3595354440833372,20498068986391916397/59798876860276456,=1:73488435585690517250320078551597483/12646950439790760312580408864096 +qmul:57111050113208289287/8750146592672703,95339879919848747558/9349828098304853,63474468255902925315/5956909304899564:5444960659889742520776395286830698811146/81812366476457707866224945527659 +qmul:31476714111665882746/1411948296801679,=1,91546635306734179873/2545140299680338:990783531267546121976022657443420500516/1993597992841162212620657219041 +qmul:28478043672580107559/271169292774531,=1,-12639098468391030777/83575724512750:810998971417379900383655158076008938481/73532785343839310404002269961 +qmul:97963124075098523020/223158531052969,=1,=2:9596773678553147851290017119785469920400/49799729981718929459883714961 +qmul:38023234767709122291/95410827766256,=1,-80027616607132061503/68758430907707:1445766382200323790987914636817593088681/9103226055042166894572257536 +qmul:-6852061478866431364/19230239212017,31234498342946092331/39453881908226,=1:-107010351453709150647505423887409134742/379353793468927863275175921 +qmul:33119990811859699401/1776514189342,65254455762623773903/8901520474749,11459125607986399870/8150100596607:720408991763668201816403420648589510701/5271225810036644905308386 +qmul:27841303391142022233/8340519171100,=1,61584898160284417471/4425828128209:775138174517616267035460754520666306289/69564260043486631075210000 +qmul:-78679695834397046203/681862256264,22320479732932316543/573216980545,=1:-1756168556264938480239345612201392236229/390855023683251092383880 +qmul:25675370768619544394/174778199339,=1,-39853005701576084539/982343364060:659224664106082973870755584440136827236/30547418964183220036921 +qmul:-24756905032793568159/99453729989,14882817849764444595/70923843844,10502311373057494209/91914989726:-52636072589569046967201515845844521515/1007662973634739405388 +qmul:95117421914973587797/80826708744,-23193036682039936606/20563195751,-4893123371481302110/94686383639:-1103030927787525886919861317615127598491/831027716905967673372 +qmul:-80983109490183607947/8058699274,-15405016985195778462/2629510637,2177028333237582055/2780215797:623773088605123959908040865328237318757/10595217730683588769 +qmul:42899406282841568991/1560723895,-22471941706408087493/1005041792,22818416959151070688/2105105663:-964032957227532597560482503451723729563/1568592740248019840 +qmul:-10792553451566883852/995956003,86483521167692451511/50100662,91257203536302258983/95707725:-466689012441018414437879124662439450186/24949027536586993 +qmul:66678150407960284786/528696663,496074447844907103/89728426,17869991738879780164/44060669:5512887774491427594627575949932372493/7906519900407073 +qmul:96591001707842941940/16266781,=1,26004126355523142571/17591389:9329821610924518126580594334274210963600/264608164101961 +qmul:-19258452690165788842/64571275,55666814298088453153/92756359,54411077014502701176/23247995:-1072056709571980969162640959031807118826/5989396364987725 +qmul:-4640013132163513704/239663,-52209871104438592227/332773,=2:242254487553159440830522450019582378808/79753375499 +qmul:-56411630621727285797/272706,15691212266654685658/1914927,15271170464235431859/4561235:-442583435196820139258606231600281499713/261106041231 +qmul:62583023330306722367/644511,42379004056489714974/217085,=2:884068733194153019519400490169326874486/46637890145 +qmul:53067206328944584675/275618,=1,37102608540172266636/214843:2816128387558776183269875887008244855625/75965281924 +qmul:50636929045250773605/38387,30182307121185668404/29215,16057737093809242633/17297:305667868823489166641648659224001135284/224295241 +qmul:-26760988055984279099/53119,44684512572473420625/89488,=2:-108709246112676414811336722275383910625/432137552 +qmul:-17331655588145624486/2353,24408931125891445861/334,55315381482361596884/2933:-16271045674950697968739133244742498171/30227 +qmul:-9697670177570290081/926,-1158917529680599882/175,-11682447562930993064/1259:5619399982923492491507494162417185221/81025 +qmul:-24744828849467423601/305,706079506961442174/13,-12411541580915002667/54:-17471816553877228863576699595124348574/3965 +qmul:74993389160967099973/124,-20280570219362183984/677,28316389090053904551/13:-380227173716737042352800246412036858108/20987 +qmul:43291079967737078989/47,-41261412311052788301/4,81583584176718755579/67:-1786251099939557456367856008793532107689/188 +qmul:-63431471455230924013/94,=1,69816003657973600474/97:4023551570975775516902820423729780024169/8836 +qmul:10484919345725066249/3,=1,-37631393326791641801/9:109933533686359751306619094875438930001/9 +qmul:76285024187842291525,15471681970508023553/4,14287488305535091904/5:1180257633346808064019424884594192288325/4 Index: contrib/isl/imath/tests/qmulz.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qmulz.t @@ -0,0 +1,800 @@ +qmulz:4/21116887005095188595,0,1/17609283250378275381:0 +qmulz:8/84271584737450207059,1,=1:8/84271584737450207059 +qmulz:-5/7724990270619098661,3,-1/8550465692384773913:-5/2574996756873032887 +qmulz:2/8610596429506001887,7,=1:14/8610596429506001887 +qmulz:0,0,-1/273384650324881125:0 +qmulz:1/140233715878844976,0,0:0 +qmulz:0,4,=1:0 +qmulz:-9/45090872528594267,8,=1:-72/45090872528594267 +qmulz:1/8811965128522223,2,2/1793564191974955:2/8811965128522223 +qmulz:-1/3188926048219934,8,-1/5467596237009668:-4/1594463024109967 +qmulz:6/640657208066881,5,1/137611762075086:30/640657208066881 +qmulz:3/82322597857883,-7,7/654813178322036:-21/82322597857883 +qmulz:2/3688100583837,-5,2/10618253469093:-10/3688100583837 +qmulz:-7/83059280440216,9,1/11745563556453:-63/83059280440216 +qmulz:9/6593641787929,5,=1:45/6593641787929 +qmulz:3/6450530990042,8,-3/716358093439:12/3225265495021 +qmulz:-9/518988418619,-6,7/365408602532:54/518988418619 +qmulz:-1/122175964907,-8,2/24455846617:8/122175964907 +qmulz:3/5927038874,3,-8/86686893619:9/5927038874 +qmulz:1/7836708131,5,=1:5/7836708131 +qmulz:5/498008886,-4,2/1679653213:-10/249004443 +qmulz:1/7271098513,6,0:6/7271098513 +qmulz:6/363428537,-7,2/874745017:-42/363428537 +qmulz:5/766453791,-5,=1:-25/766453791 +qmulz:-4/90120677,4,=1:-16/90120677 +qmulz:2/53848349,-1,9/89746135:-2/53848349 +qmulz:-1/58093,9,7/9595979:-9/58093 +qmulz:9/2605786,-7,-5/2800212:-63/2605786 +qmulz:-7/355662,7,-1/161621:-49/355662 +qmulz:-1/55532,-8,3/126767:2/13883 +qmulz:7/6254,8,=1:28/3127 +qmulz:7/22045,2,=1:14/22045 +qmulz:0,2,2/2115:0 +qmulz:-6/3715,8,-4/2861:-48/3715 +qmulz:1/93,5,1/5:5/93 +qmulz:2/267,5,8/311:10/267 +qmulz:1/11,4,3:4/11 +qmulz:7/89,4,0:28/89 +qmulz:1,-1,0:-1 +qmulz:1/2,2,-3/4:1 +qmulz:40/4765370066151782869,-24,3/17739079731156497618:-960/4765370066151782869 +qmulz:10/7947188161398728933,31,-29/17781982876586594643:310/7947188161398728933 +qmulz:8/970140630929619417,53,13/8387936313655403107:424/970140630929619417 +qmulz:3/1360678434809756573,41,-31/7551541168373851760:123/1360678434809756573 +qmulz:86/511769393768474807,-69,-1/14040574288485846:-5934/511769393768474807 +qmulz:56/95496257521849925,9,4/211197580286155545:504/95496257521849925 +qmulz:3/12596246629196159,46,37/18952775459563721:138/12596246629196159 +qmulz:77/94995682269709624,37,=1:2849/94995682269709624 +qmulz:13/113349891854596,-40,60/1320165562768511:-130/28337472963649 +qmulz:-41/8305688624807961,27,-89/2632217443748796:-123/922854291645329 +qmulz:50/294091273453599,83,31/297861651301595:4150/294091273453599 +qmulz:27/300155905937375,-31,=1:-27/9682448578625 +qmulz:-31/21736762942232,-27,80/61942176807321:837/21736762942232 +qmulz:59/71835777121419,67,=1:3953/71835777121419 +qmulz:9/1200430381838,-23,19/83497011269:-207/1200430381838 +qmulz:56/4578602367429,97,-20/776186296021:5432/4578602367429 +qmulz:31/25481124930,-86,=1:-1333/12740562465 +qmulz:45/421348839203,-96,89/480034443271:-4320/421348839203 +qmulz:43/18027020463,18,50/87497424067:258/6009006821 +qmulz:-23/3151206468,59,57/92709199715:-1357/3151206468 +qmulz:-33/718223267,-66,-76/2839068079:2178/718223267 +qmulz:98/8237370817,72,79/3563183593:7056/8237370817 +qmulz:37/508616845,22,72/569831387:74/46237895 +qmulz:41/364836167,-39,17/275414470:-1599/364836167 +qmulz:61/59566303,79,-1/1125330:4819/59566303 +qmulz:-97/83330456,63,73/93898689:-6111/83330456 +qmulz:-1/164718,22,-65/5152738:-11/82359 +qmulz:0,24,1/452605:0 +qmulz:-1/74711,-40,56/389891:40/74711 +qmulz:49/301825,39,54/550045:1911/301825 +qmulz:1/29,75,-29/23058:75/29 +qmulz:29/24685,14,=1:406/24685 +qmulz:8/4141,88,-12/2819:704/4141 +qmulz:26/3215,-38,11/500:-988/3215 +qmulz:-1/11,11,1/2:-1 +qmulz:58/779,41,-35/237:58/19 +qmulz:43/87,-51,=1:-731/29 +qmulz:-93/46,10,4/85:-465/23 +qmulz:76/3,36,0:912 +qmulz:73/4,-77,=1:-5621/4 +qmulz:432/74155281191151829175,472,=1:203904/74155281191151829175 +qmulz:43/114735919860201111,635,=1:27305/114735919860201111 +qmulz:301/3325247703900970462,388,=1:58394/1662623851950485231 +qmulz:47/344661002338469478,-106,860/1407842422947199591:-2491/172330501169234739 +qmulz:805/331439221582368712,128,=1:12880/41429902697796089 +qmulz:2/38222077254594263,-769,366/33431432349396613:-1538/38222077254594263 +qmulz:262/61689298838409327,985,63/11550912720533723:258070/61689298838409327 +qmulz:29/21271356349676377,424,920/27960990422138801:232/401346346220309 +qmulz:205/2415752549117554,210,=1:21525/1207876274558777 +qmulz:634/9928964068012837,847,95/1012378898508494:536998/9928964068012837 +qmulz:760/992730779954457,-482,=1:-366320/992730779954457 +qmulz:13/176143690239813,-422,349/7765280463032:-5486/176143690239813 +qmulz:-408/41555001527117,-384,-66/88241293613239:156672/41555001527117 +qmulz:27/282651453443,321,23/49707873373983:8667/282651453443 +qmulz:337/906250195499,80,-199/1511077632489:26960/906250195499 +qmulz:149/1870083861838,-448,281/4154228004961:-33376/935041930919 +qmulz:662/109646911569,763,126/297204337159:505106/109646911569 +qmulz:-887/964555633809,146,-947/9332491491:-129502/964555633809 +qmulz:188/73532880181,760,163/15869550943:142880/73532880181 +qmulz:-221/8950730813,505,=1:-111605/8950730813 +qmulz:22/13208815,793,=1:17446/13208815 +qmulz:193/637058385,-354,482/2363181035:-22774/212352795 +qmulz:921/151700978,356,-124/176851221:163938/75850489 +qmulz:-304/528635925,-222,259/831832289:22496/176211975 +qmulz:-4/3008665,170,37/7388125:-136/601733 +qmulz:52/12087973,-255,-249/6720565:-13260/12087973 +qmulz:-91/601229,444,125/4420518:-40404/601229 +qmulz:224/1546297,-262,-392/1085417:-58688/1546297 +qmulz:-184/301489,348,643/741106:-64032/301489 +qmulz:245/409686,380,356/35003:46550/204843 +qmulz:31/27883,-943,151/26608:-29233/27883 +qmulz:53/4847,612,=1:32436/4847 +qmulz:-105/3832,445,249/1553:-46725/3832 +qmulz:-930/539,770,=1:-9300/7 +qmulz:951/374,362,106/887:172131/187 +qmulz:-963/277,320,383/272:-308160/277 +qmulz:487/53,717,11/2:349179/53 +qmulz:104/5,428,263/20:44512/5 +qmulz:728/5,676,=1:492128/5 +qmulz:-100,626,218/3:-62600 +qmulz:8051/79574306408456131157,752,-197/7460413732106301606:6054352/79574306408456131157 +qmulz:-3008/38400803020121033225,9712,=1:-29213696/38400803020121033225 +qmulz:119/587342139200366012,-7227,=1:-860013/587342139200366012 +qmulz:3185/2510393047749702379,3840,-1461/382245232883802373:12230400/2510393047749702379 +qmulz:-8497/801072423164046277,7259,-2828/415904520883959335:-61679723/801072423164046277 +qmulz:2322/194611268129140181,600,-887/21344410544427618:1393200/194611268129140181 +qmulz:311/62962162974221664,-8282,579/2914497438443599:-1287851/31481081487110832 +qmulz:5073/93332615871851278,6836,=1:17339514/46666307935925639 +qmulz:2466/5537476809280789,8950,48/94598016177721:22070700/5537476809280789 +qmulz:231/1712288358365785,70,-6151/1963648192541132:3234/342457671673157 +qmulz:3639/430934070927460,5689,7044/387572482090793:20702271/430934070927460 +qmulz:1017/411489477643922,6940,7618/907239626952957:3528990/205744738821961 +qmulz:9453/75593644627417,-2623,-2593/2251196683387:-24795219/75593644627417 +qmulz:216/48287649084937,1544,=1:333504/48287649084937 +qmulz:-9415/2492316493411,3873,8599/637176704155:-36464295/2492316493411 +qmulz:4082/7751065050029,-283,128/8321097090765:-1155206/7751065050029 +qmulz:-487/249512316942,-9582,9041/750949778159:777739/41585386157 +qmulz:649/133850377085,-5935,=1:-770363/26770075417 +qmulz:6342/41044749355,-8924,-9491/43668795550:-56596008/41044749355 +qmulz:7139/68729276289,6836,-9917/81477149162:48802204/68729276289 +qmulz:143/2037944234,2833,4555/3599790156:405119/2037944234 +qmulz:-9325/7317954198,-9218,5503/6043847166:42978925/3658977099 +qmulz:7044/653529617,7307,4797/199351315:51470508/653529617 +qmulz:-673/115994640,-7148,559/911781164:1202651/28998660 +qmulz:3076/13783363,-9612,-2927/62873576:-29566512/13783363 +qmulz:-4161/34536929,3313,98/1321839:-13785393/34536929 +qmulz:738/526535,-118,=1:-87084/526535 +qmulz:2233/2825257,7157,765/8600573:15981581/2825257 +qmulz:107/83440,3370,401/179110:36059/8344 +qmulz:-1667/14564,-6138,913/586918:465093/662 +qmulz:-7994/44789,404,=1:-3229576/44789 +qmulz:-5363/98880,145,=1:-155527/19776 +qmulz:842/29,-8855,8672/6371:-7455910/29 +qmulz:2310/1103,2603,=1:6012930/1103 +qmulz:762/293,2709,=1:2064258/293 +qmulz:5789/529,7420,-6538/957:42954380/529 +qmulz:539/41,3855,-7655/53:2077845/41 +qmulz:-579/13,7973,=1:-4616367/13 +qmulz:883,5006,1627:4420298 +qmulz:3573/2,3540,4139/9:6324210 +qmulz:98250/53192196970205269513,57716,80717/96027247156109827970:5670597000/53192196970205269513 +qmulz:-6945/12166748375847716977,80289,23625/38713117494337198876:-557607105/12166748375847716977 +qmulz:-58986/296440433764715149,-18018,-97378/3396272899236095159:11679228/3257587184227639 +qmulz:-6149/262153684309837118,56309,89961/7445277782705094481:-346244041/262153684309837118 +qmulz:-15446/149480531273251391,31846,4749/106265662702068574:-491893316/149480531273251391 +qmulz:2451/55473133472349607,90444,20837/279735266283810098:221678244/55473133472349607 +qmulz:28710/35478143894265917,69724,=1:2001776040/35478143894265917 +qmulz:96358/34167706730231777,49135,-2041/69865271163769782:4734550330/34167706730231777 +qmulz:7283/1176116854930460,77815,62454/5465876769829379:113345329/235223370986092 +qmulz:99551/5426188854503002,-89899,=1:-8949535349/5426188854503002 +qmulz:7860/83586510191743,23843,-4213/144664072126997:187405980/83586510191743 +qmulz:-3898/13601562574049,-61855,4031/27837453043985:241110790/13601562574049 +qmulz:-6928/5371829731249,37664,4835/26749096759358:-260936192/5371829731249 +qmulz:76651/81457027187160,-85014,=1:-1086068019/13576171197860 +qmulz:14709/484402153529,30047,10715/9214198729207:441961323/484402153529 +qmulz:30365/5730836776783,61734,30655/2550068903118:1874552910/5730836776783 +qmulz:13241/55328034593,-80183,11617/428864198314:-1061703103/55328034593 +qmulz:35410/387788826057,45514,15158/46042980249:1611650740/387788826057 +qmulz:-41739/96062733370,-76701,=1:3201423039/96062733370 +qmulz:71383/88228655146,74491,74665/42443189917:5317391053/88228655146 +qmulz:-3181/8533129823,78945,19451/1917063317:-251124045/8533129823 +qmulz:-35563/2781995353,34546,99624/7403972285:-1228559398/2781995353 +qmulz:-46639/190543771,20318,=1:-947611202/190543771 +qmulz:57710/227557263,65393,41129/661804772:3773830030/227557263 +qmulz:-41473/34008654,19343,68754/48463157:-802212239/34008654 +qmulz:86172/41261945,23098,-67843/42705974:1990400856/41261945 +qmulz:-23642/477003,-74773,75259/5922193:1767783266/477003 +qmulz:-2299/7593,-55092,47078/3719425:42218836/2531 +qmulz:89923/436747,27372,38454/602545:2461372356/436747 +qmulz:35133/245788,37530,-26959/814296:659270745/122894 +qmulz:54300/83317,6506,=1:353275800/83317 +qmulz:-2710/16637,92724,49071/5768:-251282040/16637 +qmulz:-23308/1133,56278,=1:-1311727624/1133 +qmulz:12925/464,48445,5188/4977:626151625/464 +qmulz:-15500/139,75561,45107/89:-1171195500/139 +qmulz:68128/739,-47269,46324/271:-3220342432/739 +qmulz:-98213/47,41522,-7190:-4078000186/47 +qmulz:95819/64,12916,907/10:309399551/16 +qmulz:-1123,10413,63874/9:-11693799 +qmulz:30369/4,-41524,7423/2:-315260589 +qmulz:-269467/4029498660068277497,646984,265727/52332437650027766625:-174340837528/4029498660068277497 +qmulz:-206269/81809654998485085274,50405,=1:-10396988945/81809654998485085274 +qmulz:119347/1701867915016265609,618013,703201/8136517399464628384:73757997511/1701867915016265609 +qmulz:199044/306712361923985717,233710,201675/571526199709385944:46518573240/306712361923985717 +qmulz:267977/894840013682442654,-489375,=1:-43713748125/298280004560814218 +qmulz:12471/7140902397278600,350289,253704/144540771450708869:4368454119/7140902397278600 +qmulz:832882/5818152789924367,-80256,108955/22849940119123234:-66843777792/5818152789924367 +qmulz:494497/18234011706116519,-14822,68902/17499952371352627:-7329434534/18234011706116519 +qmulz:232520/1052550357505571,557021,32429/440602163340406:129518522920/1052550357505571 +qmulz:526093/2240655675408643,11119,-126354/4970690629417277:5849628067/2240655675408643 +qmulz:54605/174895846259434,-184199,544176/97043233594967:-10058186395/174895846259434 +qmulz:764692/11187705426133,576048,-646413/892215624306868:440499297216/11187705426133 +qmulz:593840/66545119469401,569003,81868/70640307758063:337896741520/66545119469401 +qmulz:109999/9745609238872,665854,=1:36621637073/4872804619436 +qmulz:-133443/8282237150,-495649,404461/485555508119:6012808137/752930650 +qmulz:224276/6824310584317,712269,=1:159744842244/6824310584317 +qmulz:787126/341737321975,925666,71517/134877228043:104087967988/48819617425 +qmulz:19969/20124955446,-804254,68212/739707535809:-8030074063/10062477723 +qmulz:-484342/14331066017,154663,640199/41001808194:-74909786746/14331066017 +qmulz:234567/15529177385,951383,104501/13280956901:223163056161/15529177385 +qmulz:447401/2005170496,-162639,25513/657762574:-72764851239/2005170496 +qmulz:88392/370535737,889107,=1:78589945944/370535737 +qmulz:69608/19589055,197889,391089/111921502:4591552504/6529685 +qmulz:-742188/976205903,-835265,198303/463857278:619923659820/976205903 +qmulz:30951/7100042,826901,37665/16004119:25593412851/7100042 +qmulz:-8717/23405419,749796,584744/90701721:-6535971732/23405419 +qmulz:375053/1615401,682230,-413113/4604306:85290802730/538467 +qmulz:-682135/9626652,-686085,=1:156000863825/3208884 +qmulz:459639/139961,-545993,55641/809527:-250959676527/139961 +qmulz:137069/131640,556346,=1:38128894937/65820 +qmulz:653137/44831,-33774,=1:-22059049038/44831 +qmulz:377111/93851,119783,=1:45171486913/93851 +qmulz:61290/967,223671,-198269/2596:13708795590/967 +qmulz:108931/3561,890354,99191/837:96987151574/3561 +qmulz:-566567/566,72845,=1:-41271573115/566 +qmulz:-856110/823,-344105,71629/306:294591731550/823 +qmulz:103589/16,-597818,73435/68:-30963684401/8 +qmulz:531370/87,698278,92947/30:371043980860/87 +qmulz:93564,802315,-69936:75067800660 +qmulz:254421/2,-51596,=1:-6563552958 +qmulz:5908447/27508951891576930555,-8046857,=1:-47544428101079/27508951891576930555 +qmulz:3067750/30055512795875714167,9308933,292151/5218560370048727971:28557479210750/30055512795875714167 +qmulz:5909595/1610510865059257451,1081732,8279906/1034011738653690921:6392598018540/1610510865059257451 +qmulz:7300703/4024857129457733561,-6809974,=1:-49717597611722/4024857129457733561 +qmulz:-411181/366261858643871279,-3873525,5670428/945102376345780573:1592719883025/366261858643871279 +qmulz:1840028/328098015717866549,7760,-1208094/324612123643160461:14278617280/328098015717866549 +qmulz:5902528/35455662246885099,9372866,-2383248/38025857091093589:55323604005248/35455662246885099 +qmulz:412808/8383418920359061,7136425,8412475/90427613237122747:2945973331400/8383418920359061 +qmulz:4721348/1016481387773127,-4909375,446916/600970820960263:-23178867837500/1016481387773127 +qmulz:346575/543489633400996,2082315,=1:721678321125/543489633400996 +qmulz:-54603/142207419353230,9721544,-9944420/520274639700813:-37916104788/10157672810945 +qmulz:9128453/94269601342538,-1680681,9401887/439581199104749:-15342017516493/94269601342538 +qmulz:327135/14576866729679,-981216,=1:-320990096160/14576866729679 +qmulz:-2772009/35771247225944,7269361,3999881/49166513232805:-20150734116249/35771247225944 +qmulz:7777936/4972983657531,932701,-1921805/2675875584873:7254488685136/4972983657531 +qmulz:-4107413/8839115797940,-7894930,-67679/4109002145737:3242773811609/883911579794 +qmulz:6418119/522734321117,-4364508,=1:-28011931720452/522734321117 +qmulz:-9554439/610908255599,9002767,5125943/687195405407:-86016388132713/610908255599 +qmulz:1541453/67134868472,9336624,124122/1242309641:1798995884334/8391858559 +qmulz:-4420171/60924329483,4658729,597333/76303665689:-20592378822659/60924329483 +qmulz:2321560/479530207,3712372,-8303185/3259591614:8618494340320/479530207 +qmulz:6497537/8003497458,685910,622458/2979408511:2228362801835/4001748729 +qmulz:8707355/324035343,-5890611,=1:-17097213714635/108011781 +qmulz:-6368331/430504267,6080736,2843024/389993407:-38724139571616/430504267 +qmulz:7148576/43643579,9752788,1882739/80695462:69718546229888/43643579 +qmulz:-78515/22600098,-9269764,=1:363907760230/11300049 +qmulz:6642519/3513320,6950670,4303599/4263095:4616995753773/351332 +qmulz:8291036/3791843,-6165764,187574/1468847:-4647324662864/344713 +qmulz:3378069/104710,4099164,-3130847/477201:6923629417158/52355 +qmulz:-1837947/540683,-7963396,4977946/317377:14636299788012/540683 +qmulz:-2439283/46175,3316377,4423369/90864:-8089582037691/46175 +qmulz:24851/4671,-9457747,=1:-235034470697/4671 +qmulz:-3996265/3851,5644784,2130071/6485:-22558052731760/3851 +qmulz:-8787752/5255,-8904351,=1:78249228308952/5255 +qmulz:1051819/121,7786465,-1689328/223:8189951829835/121 +qmulz:2910419/264,-4517287,4103/10:-13147197913253/264 +qmulz:1470867/8,9831206,3981716/39:7230198237801/4 +qmulz:4240055/91,-8952034,=1:-417111170570 +qmulz:327409/4,1172921,-3686633/6:384024891689/4 +qmulz:463486,9343153,-1978362/7:4330420611358 +qmulz:29585813/42067907033671980893,71292790,-70324603/70286665753964458740:2109255153188270/42067907033671980893 +qmulz:-65065601/40632930795671537185,4699856,7303041/5446641871295709464:-305798955253456/40632930795671537185 +qmulz:22287116/6961884952768846975,-61223561,47414597/4915453243825873928:-194928086562868/994554993252692425 +qmulz:13726613/4388684468226482322,5689324,=1:39047574389806/2194342234113241161 +qmulz:86674641/912048412696230206,9154212,418913/1017052367067494:396719019368946/456024206348115103 +qmulz:39606657/62493216618497137,-64895609,-93307621/528183512506792540:-2570298126469113/62493216618497137 +qmulz:-61860905/97141961244876374,29603964,95495204/34743879357106645:-915664002313710/48570980622438187 +qmulz:23026739/8268491868362646,49125662,=1:565601898538109/4134245934181323 +qmulz:74731767/2153002560742688,79046765,=1:5907304424083755/2153002560742688 +qmulz:-33040734/8080107924352231,16695468,87206576/5598768033775299:-551630517193512/8080107924352231 +qmulz:-85831719/652429006985885,-12207796,-56798629/203624822018813:1047816115881324/652429006985885 +qmulz:13811539/218314616664013,-33361377,41774225/444858687471486:-460771959529203/218314616664013 +qmulz:46578727/4151263590571,94131401,=1:4384520829306527/4151263590571 +qmulz:5864747/4619802266479,-14340682,9374233/85220400863050:-84104471737454/4619802266479 +qmulz:-20695/10292597787,19239092,=1:-398153008940/10292597787 +qmulz:-79354991/1226479246337,-85100492,-31036795/9391557241804:6753148776755572/1226479246337 +qmulz:13497139/220655551780,25874045,16158669/209860028875:69845116371451/44131110356 +qmulz:-14641436/673965441365,35697635,=1:-104532927640772/134793088273 +qmulz:42076810/47634122699,92555216,-99965382/7603386991:3894428238140960/47634122699 +qmulz:-2547044/961062465,-61423853,-64578371/3954121219:156449256240532/961062465 +qmulz:12398632/375040743,76607359,19460171/1399871191:949826452732888/375040743 +qmulz:99063929/927095607,-33074282,-31824927/5567689051:-3276468323773978/927095607 +qmulz:13710043/915838933,-63538218,-80907032/55218445:-871111700923374/915838933 +qmulz:-14266908/173792753,79812889,39774414/947866123:-1138683144577212/173792753 +qmulz:46031321/23827793,47288874,-29016530/26535747:94642145166198/1035991 +qmulz:90667631/37118866,68275195,25790129/31607133:6190350186713045/37118866 +qmulz:133784/168291,-36246595,-13384939/1286209:-4849214465480/168291 +qmulz:20243420/9836407,-29971865,=1:-86676150196900/1405201 +qmulz:55262636/961595,-79684445,-18606712/267721:-880714495779404/192319 +qmulz:18521596/447339,13342158,98234108/465429:82372686748056/149113 +qmulz:-52333722/83537,75454299,80265841/5748:-3948804307570878/83537 +qmulz:27849895/19463,2814646,51492641/14404:78387595562170/19463 +qmulz:2229413/2657,47131782,=1:105076207503966/2657 +qmulz:37693829/4546,76862997,85444575/4597:2897260665345513/4546 +qmulz:47895391/838,51616823,67901608/79:2472207919762793/838 +qmulz:94793222/407,45108781,26019479/298:4276006691482382/407 +qmulz:-28219652,28509688,-69052146/5:-804533473988576 +qmulz:89329658/41,24254853,43325377/63:2166677723330274/41 +qmulz:-28028843/2,57869496,97143787/2:-811007508936564 +qmulz:17180663,49123793,31747639/3:843979332814759 +qmulz:-440812167/25592398472985127969,-67895040,305636107/90241943612023813864:29928959710951680/25592398472985127969 +qmulz:469436899/89801410067219467595,339956414,=1:159588084783320186/89801410067219467595 +qmulz:624505646/8457866426911473529,55679196,735790506/1487411086627672243:34771972266740616/8457866426911473529 +qmulz:-530285107/6030437060176995577,933495870,999692847/7638706602391224839:-495018957307008090/6030437060176995577 +qmulz:811800624/481147127809268303,96179572,377106279/130131554630880295:78078636565652928/481147127809268303 +qmulz:-249975856/304587360170486515,826091985,851744230/630784049926628227:-41300610217022832/60917472034097303 +qmulz:-268512055/31691499965821404,202698168,125655067/11939065745546055:-4535575136201270/2640958330485117 +qmulz:52009618/27516701583858369,702923265,-368845548/80831610779378597:12186256831987590/9172233861286123 +qmulz:375702102/3296151167632583,-434951925,-521756507/7691136311577133:-163412352491446350/3296151167632583 +qmulz:-384209743/6191488089335748,227570856,78931552/6926107452102541:-7286245008170834/515957340777979 +qmulz:113980250/183755547250927,437813246,556573714/9774511713479:49902063232391500/183755547250927 +qmulz:-472996853/423024426303975,-368827764,986763127/429084644953681:58151457223675564/141008142101325 +qmulz:-23658043/2283802118115,740396103,17376279/1797109931431:-5838774280602143/761267372705 +qmulz:4078811/40918803323,-845485209,=1:-3448574370806499/40918803323 +qmulz:154841851/4593031526275,12617826,-972933704/2547790338703:1953767533435926/4593031526275 +qmulz:735542560/7626156428987,778206922,-293104268/2631653460189:572404311617600320/7626156428987 +qmulz:-457656798/567001008887,493454600,-366343915/981801223003:-225832852194370800/567001008887 +qmulz:-945200662/928772265773,975297818,34885945/9938748237:-83804740292795956/84433842343 +qmulz:104875267/28207551782,954147586,=1:50033241419577731/14103775891 +qmulz:609918635/17074425662,-224065632,-400611797/35807663040:-9761557458560880/1219601833 +qmulz:-864006772/2174255357,384303177,=1:-332040547429114644/2174255357 +qmulz:-109536551/482079758,63549943,-10441546/8480554803:-6961041572466593/482079758 +qmulz:512697337/200332783,429480437,6412690/26797243:220193476343496269/200332783 +qmulz:-789241399/555269030,318371906,755945889/20176822:-125636144246868247/277634515 +qmulz:-462528503/5399724,117919312,195760496/23231881:-13635260713537484/1349931 +qmulz:-768369531/84617918,630525111,869606481/10643699:-484476283822792941/84617918 +qmulz:881987483/8541727,899430760,=1:793286672145177080/8541727 +qmulz:435026027/9075006,667517326,-976648275/5125397:145193705141721901/4537503 +qmulz:-382388178/685121,90758124,-658289938/398425:-34704833675058072/685121 +qmulz:215727059/244359,-726765650,401344067/859586:-156783016256723350/244359 +qmulz:300168110/44829,-382517050,-848645422/63521:-114819419941275500/44829 +qmulz:240997441/17745,-160000865,=1:-7711959804557293/3549 +qmulz:497024455/1871,-967339431,891801689/2782:-480791353492785105/1871 +qmulz:159802693/5520,17435365,=1:557243656087589/1104 +qmulz:-503495399/548,350245727,=1:-176347112063910073/548 +qmulz:-10883201/487,215755629,756773575/299:-2348111877288429/487 +qmulz:366108695/3,980458645,-27946686:358954435022418275/3 +qmulz:890190708/5,-785135991,-213354065/14:-698920763704571628/5 +qmulz:10221149,961494206,348141954:9827575542162694 +qmulz:-44158489/8,918744696,-871474083/8:-5071297194015543 +qmulz:-2894598477/3168041449931268761,-3793825512,=1:10981601549038945224/3168041449931268761 +qmulz:-165305510/4444729020519250969,9650534485,2185861399/5133889833495479703:-1595286524815512350/4444729020519250969 +qmulz:-6642522053/7993901796893679282,2810456878,=1:-252277321501628791/108025699958022693 +qmulz:4075114142/2324601722262376857,7319061324,224603716/1867619918809913859:9942003435865881336/774867240754125619 +qmulz:174975715/284043772444194,6235601626,2532940399/455179300056502113:545539426482256295/142021886222097 +qmulz:9511153214/515183582083251763,8998409775,1916260097/49971689447357059:85585254052380266850/515183582083251763 +qmulz:9561479651/87091900188234189,-9070226563,-31724150/149115720086953:-86724786712084169513/87091900188234189 +qmulz:257684521/4786959313773388,7785131961,6853032479/92097657977675380:2006108000292075681/4786959313773388 +qmulz:-4787662186/3232352240839707,-4724762630,=1:22620567381476909180/3232352240839707 +qmulz:4815469783/4351554535472742,-3809867113,7127662378/9454193567725933:-1411253843068995883/334734964267134 +qmulz:-3134766359/276266993500284,-5054392552,-1084728996/261757765208747:3961084934297439542/69066748375071 +qmulz:887520891/240452975602433,8724686676,990724100/235457211073037:7743341692379348316/240452975602433 +qmulz:7273936918/90562759963967,3897937854,=1:1667844356487076116/5327221174351 +qmulz:-119387249/2501098635936,9536603772,7558585050/14605366326499:-94879074095175269/208424886328 +qmulz:1526390275/2230210659804,4788548573,9380637171/7768045927396:7309193973192327575/2230210659804 +qmulz:3728595181/1876804971571,9224083630,=1:34392873771958987030/1876804971571 +qmulz:4093958623/457077991802,1483219640,9490772153/415966894045:3036119917490477860/228538995901 +qmulz:2144803614/309751929683,2542484861,3609691879/286244057812:779018674059012522/44250275669 +qmulz:3560518143/86265554695,4399548470,-9491920365/12079543438:3132934429688578242/17253110939 +qmulz:-2249859505/6734537978,1110886234,=1:-1249668976269277085/3367268989 +qmulz:3262790941/1025060151,5749937770,122130955/253972334:18760844867269741570/1025060151 +qmulz:-4710833503/6631683846,-3411512444,=1:8035533558548305666/3315841923 +qmulz:-9032027690/956483333,9063301527,=1:-81859990354683282630/956483333 +qmulz:-266187969/112068472,6338182319,-7905751808/945700693:-1687147878646320111/112068472 +qmulz:4156902964/946699,6705660672,=1:27874780723015031808/946699 +qmulz:2651274071/91222015,-5032057829,-2464896493/13519125:-13341364445800251859/91222015 +qmulz:318661412/1743,370464187,-232620732/1501523:118052640924852044/1743 +qmulz:899914724/512321,5465209352,=1:4918222365607298848/512321 +qmulz:3131360803/353764,-2320875649,=1:-7267499035915786147/353764 +qmulz:6443807425/863022,84008208,110674088/12311:90222119078557400/143837 +qmulz:-3068580532/73491,8795547050,=1:-26989844445920030600/73491 +qmulz:696531051/11483,376305292,=1:262108320533621892/11483 +qmulz:9419114609/574,7568524581,1555156138/2439:71288800449472703829/574 +qmulz:6076760418/5639,3137249772,1485476093/6609:19064315235869124696/5639 +qmulz:3390029532/479,4688058595,=1:15892657084796427540/479 +qmulz:1638519591/92,3009448307,2877648480/173:4931040009121282437/92 +qmulz:516117057/8,8303497266,-9173174800/47:2142788285867733081/4 +qmulz:927642007/6,-2879248175,-3421337621/43:-2670911555708087225/6 +qmulz:2611149335/3,7293202790,1060208041/2:19043641615128644650/3 +qmulz:-4787695612/3,-5387504428,-8004477624:25793731309566169936/3 +qmulz:1237812305/631690268983111653,77842709902,51259842584/29388862631694313447:96354664171240944110/631690268983111653 +qmulz:5976818503/79879634485079515072,-2490419914,82254088463/65538055479070681595:-7442393911117434371/39939817242539757536 +qmulz:-17969301863/1215487409718772165,14907617468,39498072491/8401888749150831870:-267879478340623742884/1215487409718772165 +qmulz:62921948190/5765043819856032331,-39453740869,-1868833945/7119552876031525503:-2482506238860903577110/5765043819856032331 +qmulz:-15610313710/78152311777353923,92919343081,-49673392741/841288090131527967:-1450500095221527940510/78152311777353923 +qmulz:44648474983/288454490007214845,47861920531,11617817909/33454275945577992:2136961761466687575973/288454490007214845 +qmulz:-13826523213/28036931389675264,-88421093554,=1:611278151271612834501/14018465694837632 +qmulz:40547667371/53177876256600915,49909556335,9076503202/2880089154076223:404743217781153169057/10635575251320183 +qmulz:76668523587/5077067067443611,85512171223,-39577211701/3956684840165784:6556091916386158136901/5077067067443611 +qmulz:-80228153797/602596042922155,22421445270,24751353255/2432806998119141:-359766231894515638038/120519208584431 +qmulz:47062274633/166002450060687,86101072410,82448790716/626049533394637:1350704105318413058510/55334150020229 +qmulz:8841820465/21786582003342,53402955559,268303508/5469783598063:472179345353051714935/21786582003342 +qmulz:23713841211/21537439736900,-82708390631,-1600362701/2915831487207:-1961333642240894094141/21537439736900 +qmulz:56721050875/77459601877944,59578456497,32477270555/35734686972211:1126450887340103761625/25819867292648 +qmulz:8928356444/2663712341261,-3648881786,-28952940554/2770799359187:-32578517207427328984/2663712341261 +qmulz:18227203995/5958086852101,483256270,-90041196376/5523075085255:8808410615152798650/5958086852101 +qmulz:59211032239/570207052514,26723970763,-9542991461/881963470657:1582353894402086428357/570207052514 +qmulz:1776113132/40223369371,41111960068,44832213814/478452935141:73019492159034412976/40223369371 +qmulz:-15285833580/2156369081,34934254636,-90933367585/31370134781:-533999202607239476880/2156369081 +qmulz:91516992782/93740428151,-65378876169,-67776976360/2244262427:-5983278138453644812158/93740428151 +qmulz:72779505484/1621504307,-52125941410,5672754165/602683781:-3793700238707757692440/1621504307 +qmulz:11740145697/1515672656,87909174824,-48408939345/3034260044:129008315067100541541/189459082 +qmulz:79961831072/773650431,-41330850050,-74967019083/977759203:-3304890449760262753600/773650431 +qmulz:6884563893/49029205,40219988393,-23059747673/353633216:276897079867326893949/49029205 +qmulz:30501090798/47322791,28853148760,=1:880052510136961110480/47322791 +qmulz:-18451888579/10709259,11599135921,=1:-214025963626968546259/10709259 +qmulz:8926155052/4290885,75202195645,=1:134253291715621829708/858177 +qmulz:88656392423/4830649,47619732899,36734598432/8696993:4221793726972187424277/4830649 +qmulz:34368523182/239537,-72478917605,-71850709745/331701:-2490993359913710419110/239537 +qmulz:-7591160179/904815,-41442417941,84402195575/876773:314596032795194371439/904815 +qmulz:78012684294/13529,-92124971658,32782603063/49402:-7186916329549251739452/13529 +qmulz:-77476701398/48451,84100140997,84733570363/49436:-6515801511554267013806/48451 +qmulz:9785922698/313,99923625908,60518701590/3703:977844878839558059784/313 +qmulz:13272361617/790,77228020379,-14315026641/2773:1024998213435133392843/790 +qmulz:1977713551/2,92621074895,=1:183177954928027402145/2 +qmulz:-8125102987/193,40843068681,=1:-331854139338239250147/193 +qmulz:87788302687/10,73718602709,708527495/34:6471631008280390179083/10 +qmulz:-17073092947/16,82903130217,60258726452/11:-1415412847792085279499/16 +qmulz:-6943963154/5,67700561949,=1:-470110207678950427146/5 +qmulz:-86521942923/5,52316853740,74747686643/9:-905311166640643816404 +qmulz:-745167514955/75202612388076732241,992589631308,139312742559/34578187132141654765:-739645548931882026211140/75202612388076732241 +qmulz:27932224059/2111108032966941227,-779689866177,8856089863/3931386633265401342:-21778472038587689752443/2111108032966941227 +qmulz:140525061611/3407680707744152962,127477722944,169676929421/277484368047590363:8956907435367794151392/1703840353872076481 +qmulz:341584864563/1420632012141667135,55437156492,=1:18936493592077656192996/1420632012141667135 +qmulz:-999027740190/525162199932669211,400522397538,500019558441/907820980265694569:-400132985707868959652220/525162199932669211 +qmulz:-339453308372/462366486602163829,952918460297,-90778090002/71370169251458863:-323471323956568979706484/462366486602163829 +qmulz:-271650817828/7565295758442605,768776296466,16994985550/10329125142493:-208838709661769886195848/7565295758442605 +qmulz:225422010721/10111430949630829,746974776114,-168224996466/53086145704663327:24054936569926668959742/1444490135661547 +qmulz:349236361403/2805449982440828,193882264108,-1449692674/936603179147519:16927684114413345855881/701362495610207 +qmulz:-197651146031/4351789591405316,-808105729932,58049683298/4854765675888749:39930755908819394924973/1087947397851329 +qmulz:271384975109/452447489612746,354118404591,-732534914633/555297542185947:96102414415567326325419/452447489612746 +qmulz:88111433664/28798189724783,207968836059,-261683363229/138358019377265:18324432302591869690176/28798189724783 +qmulz:67604819101/43380824369659,884187650678,50163356115/7011438059051:59775346175424370000478/43380824369659 +qmulz:979853557479/27364774048301,185814534089,376723696931/23421481855538:182071032258409566401631/27364774048301 +qmulz:-129581462881/1185999957929,-649615443760,=1:84178119512510783072560/1185999957929 +qmulz:631378962263/4697504353981,356337990468,353616095948/3759830408947:224984310636568625709084/4697504353981 +qmulz:419208380799/252872515073,306292997739,313894879763/25683953874:128400591632237958013461/252872515073 +qmulz:59754817607/502657252480,-190176172167,111686020133/78750756618:-11363942481036514944369/502657252480 +qmulz:639847514587/81987662799,449279495706,76285885523/11877258141:95823456227461612954474/27329220933 +qmulz:699678831667/15232840363,-328557525533,412748319154/35151716111:-229884745600329961453511/15232840363 +qmulz:887054398617/2906111779,840756960767,-7837140210/882145159:745797160216227848059239/2906111779 +qmulz:-455315204427/506702237,-175722319764,101353072197/4927140688:80009043945732322395228/506702237 +qmulz:18629315637/336690086,163583642465,-428561144079/630858776:70870960663503295935/7830002 +qmulz:26610877449/497721338,494401478093,656965629789/571606768:13156457144137281224757/497721338 +qmulz:308447566844/63211619,626332529102,389974552910/53161277:193190744636760720294088/63211619 +qmulz:432089290445/43417161,381832677443,-993787713167/43836749:164985810665060426932135/43417161 +qmulz:259672928141/1911242,33898844506,477785491015/5001727:4401306106734735321673/955621 +qmulz:72860807605/947904,836184405122,132459766271/26668:30462535531947709276405/473952 +qmulz:8111715299/126471,73018318330,-966100886117/960478:592303809904713130670/126471 +qmulz:59136150795/124661,-183025911988,998950795145/902212:-10823447930714766230460/124661 +qmulz:-52072229129/344,24297646661,-819340099671/44129:-1265232624227073788269/344 +qmulz:462624622089/91900,463652425988,182901467689/69000:53624257088336635612233/22975 +qmulz:-12928412440/521,528884765734,937253218809/8798:-6837640384641931330960/521 +qmulz:27765652319/2634,-126780088278,=1:-586688642016512569447/439 +qmulz:-967104161735/274,750172960968,-709612304/49:-362747696286610257079740/137 +qmulz:66752761957/243,243055541185,151935508582/7:16224628683052114699045/243 +qmulz:751278773537/66,713221018437,659908640320/37:178609270664053141567223/22 +qmulz:-586344498928,-568318448089,521816699255/14:333230395676283284148592 +qmulz:161194888214,484546649439,184699645268:78106442990787850811946 +qmulz:793578182621/4,-808113765664,=1:-160325363376662447831336 +qmulz:561935468909/32803049500299178880,2101294187063,-3358814917919/26371576797557955745:1180791734323002866524267/32803049500299178880 +qmulz:-5868873358301/6442991402115355335,2339686618745,-1536954575653/43556673213605193423:-88589190087263739148079/41567686465260357 +qmulz:-7979894125724/9674261753856826205,-1852913383532,3286095553311/7067777496639467900:14786052624722387839177168/9674261753856826205 +qmulz:515507640950/169593134508951507,130457186386,9764491091569/7319120645126181160:67251676398821316106700/169593134508951507 +qmulz:-9365485392019/329669514832033195,2420807490629,=1:-22672037190376071733889951/329669514832033195 +qmulz:1709304465717/260423845962574106,2761288775682,-9625873444279/32296180368255957:2359941617703735036146997/130211922981287053 +qmulz:215090735926/98137745784701417,1193894989684,=1:256795751949495738187384/98137745784701417 +qmulz:2462657897367/2405626367061101,-6540272761466,956548940780/2817455913381063:-16106454366958522300460022/2405626367061101 +qmulz:242208253035/596343213619654,5151615220303,=1:1247763722818106293369605/596343213619654 +qmulz:228002384282/59111672575229,4689640217907,8887530790232/4265423449943033:1069249151107554031737774/59111672575229 +qmulz:1065463662219/36125337508585,-1135495312868,5987819337289/651384630027642:-1209828994480848476134092/36125337508585 +qmulz:6023110141478/670453839669919,5713937267309,1998947610187/134406089553918:34415673502497927694342702/670453839669919 +qmulz:-9838734646098/73658633070811,3898971866431,=1:-38360949586416063311336238/73658633070811 +qmulz:-2320378876107/3544145932211,-9742994143220,8635863424885/42773859269883:22607437799961906994044540/3544145932211 +qmulz:1282067863135/7152781512234,-430962905775,4287050590505/9492196607247:-184174563899134867034875/2384260504078 +qmulz:2972203649953/4110957928466,-1076925462656,6468360579859/5380802762138:-1600420895416743198827584/2055478964233 +qmulz:7745401204821/811506016039,-7138418453884,52955801256/2587064107:-55289914893229593626974764/811506016039 +qmulz:-4394166471713/351201211519,1682246763941,2661332639201/255305706936:-7392072327257235964900933/351201211519 +qmulz:242477453617/2530363014,7850634381002,-728870121674/37749087679:951800916991718980492117/1265181507 +qmulz:-4495597725068/18530739005,-295776565976,2058781523476/32738808743:1329692457130130811086368/18530739005 +qmulz:-627713346013/6292366913,8991851477846,-476950295807/2244817575:-5644305178010651601927998/6292366913 +qmulz:-4583081886485/1415176577,769919000693,-869103658209/9579044:-3528601826136720462334105/1415176577 +qmulz:-1182275059809/252123671,-904658392050,-8972966355829/539780886:1069555054567627520118450/252123671 +qmulz:4559690190362/241596515,1670678554004,7140063697224/280561433:7617776613940209657309448/241596515 +qmulz:1432554287/2209567,7757230863986,=1:11112654329451858207982/2209567 +qmulz:1106108950528/6849831,-6298163069823,=1:-2322151514472041772238848/2283277 +qmulz:5088803191704/8136929,-8625507078,-35324495791/106583:-43893507948591842880912/8136929 +qmulz:7539081819837/6889238,7284561918683,9960043148827/9194287:54918908326619940050314671/6889238 +qmulz:391441941525/125384,7929833985877,3351067478098/711859:3104069611402622309842425/125384 +qmulz:9009538508471/742821,-4924002212923,9527002197826/376781:-44362987553126188781170733/742821 +qmulz:-9259291631862/58961,4703549016027,9448940593567/14975:-43551532044151545221852274/58961 +qmulz:3476127453492/36715,3322870685572,308545119513/7234:11550722014520612585417424/36715 +qmulz:-646877695651/729,2845152282117,=1:-613488517344009605324389/243 +qmulz:-2520612775732/3305,5509026264687,4380524270328/7049:-13886121984613190802175884/3305 +qmulz:1963077614302/267,-825362596397,=1:-1620250836669127260869894/267 +qmulz:7889439316771/713,5863316933906,=1:46258283145047187204337526/713 +qmulz:8748734240327/23,6371236745698,-7157017762004/53:55740257070317659715363246/23 +qmulz:-1296384169421/6,2899800596916,464588384950:-626542598053244779017606 +qmulz:-5167288008794/7,-3300699869865,1931056190640:17055666858181330775592810/7 +qmulz:6696697914261/4,4069021265747,5631057961007/6:27249006223411589102117967/4 +qmulz:23865486379535/26918789012953275954,94873123748548,=1:1132096621302455418116582590/13459394506476637977 +qmulz:3092832570307/2006024783468333419,-69091492632924,9214275673435/28417924226192114256:-213688418746233489772987668/2006024783468333419 +qmulz:99742200190859/1397162492835988177,13135144429552,=1:1310128205228222025079865168/1397162492835988177 +qmulz:16157052816541/834217349232726593,19133269076621,18278786726642/1173386622722504913:309137239024056146385187961/834217349232726593 +qmulz:-15154486378645/471850975689269841,83584432024123,14569830702843/38977738569109946:-1266679136576350929552053335/471850975689269841 +qmulz:-70285613046769/438550102087486245,58305445024728,=1:-1366011315842564998875167944/146183367362495415 +qmulz:5620626946546/16483309748982467,18213910616022,=1:102373596810393507725160012/16483309748982467 +qmulz:-87110361266406/28658861993511733,50462053430058,8350373847003/21134055318706744:-191120334979871062479392676/1246037477978771 +qmulz:42263850161473/2487221560052869,70196784710879,=1:2966786390837768841769764767/2487221560052869 +qmulz:2305968062717/1295096854935771,89753857010368,-1448986636213/88097527127243:206969527771576926343249856/1295096854935771 +qmulz:54792800436741/962961846570596,81148189103692,=1:1111584132840379068733886943/240740461642649 +qmulz:118089073191/117603203952236,-88682518170219,8843505968368/446344763404861:-10472436378965178887498829/117603203952236 +qmulz:4370360581061/33937836375304,24828310773456,=1:13563583837330531311889602/4242229546913 +qmulz:44999946775270/77691532844719,19675574610517,90987690124989/70801686470002:885399810246118760377514590/77691532844719 +qmulz:7388469159437/80827214538,12962289697895,-39739510822103/1124530750930:95771477668585155318285115/80827214538 +qmulz:-4438357163019/354300196838,2800216938058,48604674898545/5905387400293:-6214181452518427865638551/177150098419 +qmulz:-1115976535244/90660833629,-84198411580247,81927230020875/605448344659:93963451628372333929725268/90660833629 +qmulz:-14354364205035/137076592739,-60231717901669,29779963372229/288489332426:864588015455483313484703415/137076592739 +qmulz:28410403793917/8317372959,94611442054559,=1:2687949272294801418906317603/8317372959 +qmulz:-26238968575867/81875709363,-41798837075253,94070973760679/3467355102:365586124175115989639573117/27291903121 +qmulz:49964458440323/3849731307,3475521417184,-94000433574238/5577825597:173652545407342463250710432/3849731307 +qmulz:63054816328381/8314862510,31407375891502,=1:990193159097540038129659131/4157431255 +qmulz:15690728254037/869383378,22615130488585,1475502145196/107482041:354847866925974243808667645/869383378 +qmulz:74263848858589/607431119,87079437180738,43892391010643/973943857:6466854161481322249396658682/607431119 +qmulz:23023853281324/23656491,66652947880105,-31945062874493/5458316:1534607692759273053987659020/23656491 +qmulz:3506276105087/11638761,41170764577395,440230047929/1761776:48118689355294122721569455/3879587 +qmulz:-93363094505152/3545929,76526518299725,24762745460028/9476321:-7144752560167469121292683200/3545929 +qmulz:-2458728669037/893246,74281956367289,10383331533388/299139:-182639175712408990493930693/893246 +qmulz:-5121601980421/33999,20660659077801,8112621331106/52165:-35271890816556237705911407/11333 +qmulz:25877846847031/404920,75489603155313,-38374243475879/901678:1953508388996337946045925703/404920 +qmulz:66471726351654/51695,28218300697455,-2687434510961/88806:375143832413983194158568114/10339 +qmulz:-3436425362877/67400,87107727529435,8150807016773/30347:-59867840836945902514756899/13480 +qmulz:64658311574074/1471,54380155658036,79155462122195/5662:3516129047983934816427358664/1471 +qmulz:9680963797950/229,-14929130816650,28202159724489/2789:-144528374970848369095867500/229 +qmulz:816481395175/17,-99383084980450,71300027130653/105:-81144439881633403599328750/17 +qmulz:638399693884/125,-59707159904100,34949260444218/785:-1524681304218419151860976/5 +qmulz:38337688583813/25,46682828260030,66019999840333/85:357942346408931005122578878/5 +qmulz:-4362866892015/19,43253153678106,=1:-188707752157445489971723590/19 +qmulz:80038414225429,58791342870753,-71193599831017/3:4705565853558550737752978037 +qmulz:-8931381288/7,27056505490713,37222461138097/2:-241651966858423345978344/7 +qmulz:-103292201629591/24903444183827008678,811061948698381,=1:-83776374339042161969543392171/24903444183827008678 +qmulz:-108233246344215/10921524390718392772,336628265620018,=1:-18217184999638624584411247935/5460762195359196386 +qmulz:-242546210473995/3227191274694658997,117559616638474,-200514522282738/1463600762469566069:-28513639520437479372093483630/3227191274694658997 +qmulz:346557608752347/7091232122596884343,-890608472719639,764299440148772/741441034955506561:-308647142640297959088714242733/7091232122596884343 +qmulz:752322662466430/796990587047794081,213680028681761,572521425296816/937517719580878925:160756328093765562145815783230/796990587047794081 +qmulz:34927180981080/55520878875379453,-865283782342577,989438973302993/881309897241401311:-30221923265872621723515443160/55520878875379453 +qmulz:274082612801409/53154246781994009,971799838064389,448110955601401/45559104250121531:266353438736673897727411924101/53154246781994009 +qmulz:-124555667888037/14097174308038652,829678276357628,125094809716795/35133120466800502:-25835282960979923394918724059/3524293577009663 +qmulz:505323718065074/2128598622243549,-277690520595781,914993855209755/9726536089876778:-140323606338886062971007852794/2128598622243549 +qmulz:-902895852073028/9135983164951921,833620594767907,842531169585879/9544376880879779:-752672577218593777816474712396/9135983164951921 +qmulz:811564634419288/453082972179167,60327882243393,51265177937813/73949934423745:48959975698149096053229764184/453082972179167 +qmulz:250179460716837/290886574637551,340496244659932,9798345091684/451481890082625:85185166865129977930011675084/290886574637551 +qmulz:-582653512523981/99348978999674,379317852190649,460594514303380/74887958609607:-221010878941933880917996453669/99348978999674 +qmulz:863679006697/1635434858422,924063163904185,-729545153826413/62812666295337:798093955526053605281326945/1635434858422 +qmulz:304709172702197/5457282848355,882318039223156,=1:268850399791912468175214473732/5457282848355 +qmulz:463908939133169/6691921051406,-552915136065320,-601471563981221/8781918044231:-128251137101367195825081299540/3345960525703 +qmulz:-752373946530613/846634747661,284479627123896,50536119796472/513050133075:-214035059766762852800707828248/846634747661 +qmulz:328225703018604/433509767335,197654409561196,-3782967558290/93869557971:64875257532950641256264490384/433509767335 +qmulz:184785598182871/11617410807,895346115182373,=1:55149022491561504431189910961/3872470269 +qmulz:192803285928028/90953336419,332075196148197,=1:64025188992566808558163965516/90953336419 +qmulz:-399599786249880/7362537623,-981001390019795,957969995178032/4517518129:392007945762745245102016374600/7362537623 +qmulz:82589051366095/1626512642,398617970248743,137619262887145/9949579469:32921480020321964131106568585/1626512642 +qmulz:-907650909511793/772837941,990867777654644,=1:-899362039594166707200599216692/772837941 +qmulz:-358503288380739/383532866,697173774576334,-51289684132425/110529764:-124969545379213895872305415413/191766433 +qmulz:275838241610846/67525047,469977259127432,28053789338265/5265202:129637700754795766556067327472/67525047 +qmulz:53930640918734/7001103,693055155395270,=1:37376908722499699209717988180/7001103 +qmulz:-681238687980343/5030205,-582879269862290,-990800444969909/4579368:79415981810385344493567393094/1006041 +qmulz:520602003913013/4593382,308897366106910,-466584092376547/2221166:80406293899354484531049109915/2296691 +qmulz:-405474039012091/243080,-154710965359365,-172296604865771/908379:12546256000744284661479016443/48616 +qmulz:588023971610839/411117,884974921870604,55791283769330/230429:520386468334344508549001876756/411117 +qmulz:540840030461611/7002,-380104715492010,-205957826883233/40847:-11420880328072259499071234895/389 +qmulz:-753807927054263/53929,915393419376816,35196013565764/3461:-690030815899551293936076166608/53929 +qmulz:237522311694659/6300,580421631136666,118641235907757/8270:68931543792582787509445633447/3150 +qmulz:-703556714392601/3647,26296886058971,559465758581845/6674:-18501350754406230744932073571/3647 +qmulz:240687231749867/206,-784485320110706,=1:-94407800022927047065270388051/103 +qmulz:-93887798635737/127,-575220251243142,-652322307871805/572:54006163119914161845877365654/127 +qmulz:-396521866192559/70,394474102270905,182300183108827/15:-31283521439418725353582639179/14 +qmulz:58431834428363/5,-485860188905084,792920518125413/98:-28389702113435038144004497492/5 +qmulz:94346378811421/7,897687299600400,=1:84693546022300913680256168400/7 +qmulz:606162442576909/6,95792984784316,-12377831317439/2:29033054819296832459303479622/3 +qmulz:-3880722889823905/5802853163792252251,6995189470105129,723671795237053/94804862094718615043:-27146391895292126926964647308745/5802853163792252251 +qmulz:-711255950576391/38557928701418837140,-8914163822970630,5504820920293812/83891195583846813871:634025206350065106283436439633/3855792870141883714 +qmulz:471011076275411/1268773388114902240,4280756402169772,-3446853649893419/6906782713522266814:504070920064710111468162769073/317193347028725560 +qmulz:7695205331550676/3582847162742099607,-144661167043645,1213893998753526/600058503660029491:-1113197383902599946494421254020/3582847162742099607 +qmulz:-3199289405937703/365472303862404370,5173907772378010,=1:-1655282832346770788786622711103/36547230386240437 +qmulz:2758027287264869/155052934325555752,-7564742138218573,-6257710286765285/771615064482957592:-20863765238329215589609266211937/155052934325555752 +qmulz:3955143821106077/91399737124804255,-7263645778507290,7804375725987635/91077647617338438:-5745752743913269680040361560266/18279947424960851 +qmulz:6713507007062553/74150811777510379,6266298995262737,528130351899129/2709757324123282:42068842213045420456548828987561/74150811777510379 +qmulz:-6877567017527963/1489247567416462,-4521311499760591,-115573898280262/923926913012529:31095622846723329241375147906133/1489247567416462 +qmulz:-1586799572294172/4730804077270513,2121219051102928,6786948620547679/9912102833874252:-3365949483032375529047866535616/4730804077270513 +qmulz:-9501087403079799/923245070947319,5606803416408299,1323793614080105/21826353763174:-53270729311181670439383462851901/923245070947319 +qmulz:1083936794899597/58977209646283,-8747830330029136,-4634270584400088/47878110359797:-9482095170257265523833204658192/58977209646283 +qmulz:-3719900694014304/36234265212301,-1494306375099641,-1975217081214247/65326075776641:5558671321803153433440279264864/36234265212301 +qmulz:1103608308470404/8630287542765,4527264291311725,-6050102349432119/65604233367649:999265297306599031900300137380/1726057508553 +qmulz:185603093644419/1285147223476,7441353681336558,961853358112541/9035783508083:690569132079175618373558684901/642573611738 +qmulz:7656576001713938/5697164099281,387954634853982,4891764604516329/9388026384014:2970404146976692276584364201116/5697164099281 +qmulz:-8608538284429615/24304320924,-9300930568944394,1012277413814075/307338098963:40033708441789768251278470914155/12152160462 +qmulz:-2298250489792159/192401665676,4151647369458953,4637677731066783/854611972340:-9541525600303367226221251749527/192401665676 +qmulz:-4958597485118384/18914385675,-8391716685524037,=1:13870381750888490254448674198736/6304795225 +qmulz:-8775066120996947/26819677230,8537625341965974,-8617075263155655/41305030346:-12486371148675098768666305313563/4469946205 +qmulz:8632423322860386/9616021081,5042628174507057,-6506115385718735/7975459194:43530101062127611384934782744002/9616021081 +qmulz:-3848534615760728/9274753529,2104642248786963,5619621461116310/5343995473:-8099788548249129154859453789064/9274753529 +qmulz:271301194709322/33552569,1917863106025352,-3970383512818995/409886044:520318551953609085962402731344/33552569 +qmulz:225678582778501/66976167,5457450818595612,-1586701099858817/141482387:410543255441342622436562179204/22325389 +qmulz:-5691916212714825/75531979,-3677441922214847,186124889390004/78334747:20931691298371858008446792006775/75531979 +qmulz:9683640970785183/21432671,6061708788245552,3666308965635053/8459353:4515339351909479419918957481232/1648667 +qmulz:8423905758112927/2462761,-1402202086438487,4991587911230636/4020141:-11812018229987130827123385021449/2462761 +qmulz:110629337771891/244490,5329540769616160,1715961548659264/49589:58960356597093007948570735856/24449 +qmulz:2768082072858327/11996,8431038603161226,=1:11668903406493550143637918814451/5998 +qmulz:-5632710453612631/282213,8269803080914635,-1089107539381719/990995:-5175711807020645232938163194965/31357 +qmulz:513164615298521/2937,-761654779947971,6308090089559589/34312:-390854282142280204811013250891/2937 +qmulz:2399352646293603/26699,5936082314225321,246326307317325/1064:14242754809253178957252862921563/26699 +qmulz:1917463706144480/173,2784408494403777,-5268002443544296/9923:5339002231099637846089019700960/173 +qmulz:-299651250103083/304,8512720924447435,1696619119714772/2041:-2550847466789346268098564942105/304 +qmulz:567861836090453/137,1194683804539166,398775012895933/117:678415338793138672840757182198/137 +qmulz:5855010424286591/141,-3387352251576542,-6842084179082795/92:-19832982743711308513005380748322/141 +qmulz:1839091525348225/37,4835017725039396,3258229037788442/47:8892040123028407522020743672100/37 +qmulz:689624656142569/50,-1436205069429607,1650564655275659/9:-990442427155607164133701640383/50 +qmulz:887987723713419,-3871030680937173,=1:-3437427722790206595690596024487 +qmulz:-6321481694612935/6,9155176113205281,-2076666497659035/2:-19291426070194927792191164303245/2 +qmulz:47535841066367704/25874740830854221899,20217596491741418,386741628388289/10612132664990412300:961060453575373318717870874364272/25874740830854221899 +qmulz:80223166731461168/79315578551274076339,19941312492318563,-6517563635718293/15173501904275140121:1599755236915441531514785120061584/79315578551274076339 +qmulz:-94966952144940093/814524592733157116,-8833229520058195,55047972140476464/8182255352181738995:838864885116638749899220148712135/814524592733157116 +qmulz:19023061829222254/8275414709591200245,42825769994498364,40342865387732273/6423424085911584926:271559090163131188965234998464152/2758471569863733415 +qmulz:-45164511230863025/205230894764003516,95431251431037353,9088808827059225/537242774047899907:-4310105827032399655884245201572825/205230894764003516 +qmulz:78978348840218612/30892480489678495,22023635711834354,=1:1739390383979149957558284891796648/30892480489678495 +qmulz:-148958689172671/102037781856410,18768909665863199,97201659871254553/14233090955064268:-2795792181027256577300375434529/102037781856410 +qmulz:-13899781468245877/210298830514748,-40323281693369663,=1:560484803620357867773725936629451/210298830514748 +qmulz:88175738959378971/4244405961829309,49633440309199351,91798871890211817/4618870882937021:4376465276359879854575633196247821/4244405961829309 +qmulz:-196047733461491/273753721482047,-28937490043883541,-8575700230869559/2512020324451605:5673129335167829946904412219631/273753721482047 +qmulz:-19132451907214205/25824658302078,18312961377925295,-48090033092819861/431889830006992:-350371852841826885918246052815475/25824658302078 +qmulz:69382145113501751/380297809139977,2745327554581026,12801801952051298/753948686518799:190476714776035644694264522376526/380297809139977 +qmulz:1915274245412291/3788421267711,48395753953886595,6801592121612027/29575658734452:30897047045063015615882544379715/1262807089237 +qmulz:-41044766089612839/3600558205679,20994850850464225,-35435905322101302/25097049433951:-861728742243613295588013670184775/3600558205679 +qmulz:42597494937030563/139066009314,65616555969864940,11098362865249168/1843997772651:1397550455355852172511957881080610/69533004657 +qmulz:74024369507729486/8798209628891,-48540197369243101,=1:-3593157506038970019752620879776086/8798209628891 +qmulz:-78176595124115512/936929521175,19202167121582858,-99925056698963177/191994309327:-1501160044569585652613332671093296/936929521175 +qmulz:82802252720820771/664875719702,97327360089498817,-27164056917268865/462863761311:8058924666781006338043050273527907/664875719702 +qmulz:-79012216554892489/70097745469,18109121557124146,-26372881204544091/13780169332:-1430841834090364897003709055939394/70097745469 +qmulz:-70054799672271272/45482963493,7787932643225419,22281182451081849/9895333688:-545582061182298824047255613862968/45482963493 +qmulz:38317664305319638/2445394649,31654407463814347,-43227662278819145/8020766369:1212922958982242534681702525246386/2445394649 +qmulz:91685907685022135/618530726,-65256514026907419,84454182812530114/7990613223:-5983102720917385677413600610719565/618530726 +qmulz:-9319036791983210/326561129,48383470752719549,-21563116260711314/160888617:-450887344068437052714708646772290/326561129 +qmulz:-10319092612953469/85265494,-55462305741126344,942196671950729/100675391:286160334735311815060828261043668/42632747 +qmulz:24190194708441624/10753379,88757165826516370,33675430745281060/75133189:2147053123112872034250339425384880/10753379 +qmulz:-11468596832661746/1766525,56376469108104767,96014028182502185/4186386:-34029420792098057856142633744378/92975 +qmulz:-40039747951909081/6069939,-55718774097961657,-38493857988408833/3718928:2230965671071745008018063888107217/6069939 +qmulz:-37290139983929779/799087,11981560139468355,-11746974507966646/3218933:-446794054826648164153652712643545/799087 +qmulz:41894225992589221/366814,74540431481275887,-66854308231170017/431055:3122813682061684114056083763414027/366814 +qmulz:4577566343641272/36389,56889856836673491,=1:260417093950126892755280695920552/36389 +qmulz:88284563154658136/23691,63742381682886541,-30323740102908723/9056:5627468321311120786042358530547576/23691 +qmulz:-35239011702626416/1503,-96377199381969204,-61186369864860723/42751:1132079085629190722429226942964288/501 +qmulz:6204324005181542/3263,9242869672214658,5888893248603815/2661:57345758184085853188298483442636/3263 +qmulz:13023563233102553/2092,-18292948555955590,78624947167647851/9735:-119119686119189830929040691810635/1046 +qmulz:8668988413765031/12,87487198824736036,24608302652702701/174:189606378241098583267909375589279/3 +qmulz:-88604450607713147/253,-57197213811690954,-65274907046510203/195:220344682872903450186081523772706/11 +qmulz:33666476522294146/13,67039261791546104,=1:2256975733177017899095506408307184/13 +qmulz:-19043783688556820/29,-46927274804274505,15813572639616397/59:893672870466066256149790569874100/29 +qmulz:-94396743394101937/7,29360199416108739,=1:-2771507210282078156031800042527443/7 +qmulz:32378539760159572,74380454651945304,-15922753341092935/8:2408330508326757024819007256049888 +qmulz:-515970186826451384/25959078573251600323,-481657180143660888,855482564716356613/45268895425503079014:248520745225026458245551027714268992/25959078573251600323 +qmulz:-130967478747895251/18589421418033360838,147641505075499109,-55563959724327169/34005532994986142887:-19336235678282698393435282075831359/18589421418033360838 +qmulz:-860266011517441547/2553655932637699066,-299807248907353740,=1:128956993120773018576083159450917890/1276827966318849533 +qmulz:145239559532108435/807509961508023596,576064609905367511,401973572562411248/7006133492934535601:83667370204691447066198253378055285/807509961508023596 +qmulz:-203788329869580393/934147712305627115,977955003052547263,34371785465644891/24153024504080070:-199295816759679001811043775610614359/934147712305627115 +qmulz:-305697857540446967/103403955365462673,-568720855877228261,=1:173856747180237996116028815024134387/103403955365462673 +qmulz:226166409746766031/13002990761630932,789981405518661663,-113466700430225377/10401766053678468:178667258252859769569650633510369553/13002990761630932 +qmulz:3220063708444885/86759191901981914,-436274250898667434,=1:-702415441123888629947969466687545/43379595950990957 +qmulz:-67396315446702174/385366352018695,935081661792652149,-625977217802097815/9842734508647274:-63021058646604060109741387184071926/385366352018695 +qmulz:24319453787590069/147313838530763,247065078929176318,=1:6008487769545396355634476406785942/147313838530763 +qmulz:100629482109427385/145102206127588,493200833830327566,587248475105746167/360845897573321:24815272242141808191386545620397455/72551103063794 +qmulz:68125647111849775/751431108442761,573247979073143838,74386340727896222/930067472967985:4339209947768671307372114758104050/83492345382529 +qmulz:315260234123867071/28724643212088,340944306756538261,-53419962261027213/66345800395925:107486181971265805844870978489503531/28724643212088 +qmulz:-236430702618704929/20104762237425,598324387971999776,114120042986736600/9261982109063:-141462255442126511362707327398095904/20104762237425 +qmulz:40711881042093025/722627757269,-916183636373594020,59862621134038918/36564773153:-37299559216753971995016222423710500/722627757269 +qmulz:-520309382707815761/931737166517,259750055972789770,-130681632611383930/845007490973:-135150391281522837582794926345564970/931737166517 +qmulz:-744723510370875375/104328014528,392776247476475915,645297290772722121/747416253776:-292509705810980823923192458654093125/104328014528 +qmulz:150326873930054465/220440980183,184204467758877126,446972731209163483/312751250617:27690881802141504054899212422667590/220440980183 +qmulz:115421167528373279/5250405410,771027268136349173,=1:88992867484509542530759922626948267/5250405410 +qmulz:84701761403492795/44355610023,965802039756702720,=1:27268377978159632125207673492300800/14785203341 +qmulz:894229992015313913/3163831833,-785572023936143576,681929403708376856/586412675:-702482064691871660107123412278372888/3163831833 +qmulz:74634858785325581/142443768,427912086580428045,263236478364528529/7486986306:10645719384821420242829855889439715/47481256 +qmulz:-332428641831574483/344279073,908684289900488822,-638499266082892652/390482433:-302072684345308192917372015601929026/344279073 +qmulz:415890959805425615/192542692,57300089077177939,200778229355831075/85157704:23830589043243917548894324983507485/192542692 +qmulz:806988421881608649/16389833,666714975759989998,994687425328887678/8586277:538031266133389292509645688390292702/16389833 +qmulz:99978136901356657/62362649,-421321213914285499,477860583712193259/43057685:-42122910004168208858812125922216843/62362649 +qmulz:134226773204000444/2213319,457929073299284411,=1:61466341865261143971298267726278484/2213319 +qmulz:203692403587646607/2530234,198709333320751525,654497348349770852/9852495:40475581719402713398336251356325675/2530234 +qmulz:1932413671793631/11008,605844360169614539,271988563133914698/256283:1170741924570827879369734025201109/11008 +qmulz:78300870419392545/300541,9938443225300603,474105168486707610/456971:778188755154752224021438282204635/300541 +qmulz:731791251673481239/82178,-375066073302435963,897701210637687185/8253:-16145298308367486968573476887023421/4834 +qmulz:-244865844794445459/20764,633837473482998794,-572503688932727221/18042:-77602574203395710948196720797888223/10382 +qmulz:-871079916851090199/6190,-933271236207286315,165562923533871377/1253:162590766166991424800556971016665337/1238 +qmulz:278477012608289079/6904,166601452640247459,=1:46394674827457467509510753167200261/6904 +qmulz:50351542334760530/697,74118063280217581,=1:3731958801024335445119077930877930/697 +qmulz:716113366657554965/773,292433182475186613,55790708408336567/73:209415310824688987980879304679683545/773 +qmulz:266171451721629402,838958222079312932,186531239281784779/61:223306727904647880295582119690026664 +qmulz:-191048663820313019/17,-335221912735777740,-104282880591219422/9:64043698511459908763402007212397060/17 +qmulz:918486165864351700,-754751323324354742,107963234237522909/3:-693228649141232227471800102650761400 +qmulz:-263050925547501061/9,429366864986261421,-369906620681745801/4:-37648450411354997741362101140289227/3 +qmulz:-8908762588791502798/9682457258957956871,6517968147068840217,=1:-58067030783541555611439264126370427166/9682457258957956871 +qmulz:7658247927733463351/71097873025711495885,2645904249530727710,-526743598589435636/3308522377463446025:4052598147189972001038980978729031242/14219574605142299177 +qmulz:35178382688557660/101323881670407613,7331418798392863213,232580837460702659/1407098737763013928:257907456139949700482063020643361580/101323881670407613 +qmulz:1263699762126537691/454699906557876874,-4542833552105116827,-2210388710075629538/661648401890741827:-5740777679175690401542804846573826457/454699906557876874 +qmulz:-1832647602190411445/226947754154888126,5643404261053171972,-1097284930177831457/619682865758859799:-5171185643605123184522851420511009770/113473877077444063 +qmulz:1823011844211832737/592442421313405007,-1035458481118632295,-6389536796987914382/963103956263803057:-1887653075268861046971124680746441415/592442421313405007 +qmulz:3241180647893831993/47706456259746618,401191978478284716,8203697741103525736/82629569130745973:216722612789009192825658264487286498/7951076043291103 +qmulz:669385746027781985/4358673572763459,-3232260578078726488,3369728187950184564/4211286946970669:-2163629158413418191796114556108718680/4358673572763459 +qmulz:-8416424642111725238/6365835551441079,4033684793967464839,623945245518632503/408732809111644:-4849886299779875487264451230199129526/909405078777297 +qmulz:1670670426691770676/933711771783465,4268278044364566390,-4259333158202693983/1474131926823072:475392393441177774546174414803811976/62247451452231 +qmulz:-2026621003312993155/235607922312922,-6449641809771356053,4984273563952773559/458950128766224:13070979555528254543461227718656817215/235607922312922 +qmulz:2110680248476630645/95785011231043,4324730695176379682,-1722968689643087720/615704293887179:9128123658289392651639137372596554890/95785011231043 +qmulz:-641839465597711103/9456066925611,1548277416348552437,-2507922761391944404/21340298450009:-993745549506159751964209714572608011/9456066925611 +qmulz:2741589907602153339/57948673895524,1590482362679123180,-2499147223466166660/93552475783027:1090112598435077963801396817107324505/14487168473881 +qmulz:1105127694202188183/6381230280571,6999165228541352101,-1962335544251498845/1250684067374:7734971330358035931095740815664422483/6381230280571 +qmulz:3388900892142215022/3450834628513,-921940083605878001,6734092499539471533/5162430112340:-3124363571833628263304768671241531022/3450834628513 +qmulz:-386348847054518292/323004206381,514411028349585069,3189676746121428640/214488726717:-198742107714991314988148399870582148/323004206381 +qmulz:2621996699851800211/639729174738,901100719762883014,9556760707097111231/962924737943:1181341556726180554328723203646757977/319864587369 +qmulz:-2049289271073576417/18016913114,7508216114633285941,-9469235071531039565/67942461077:-530569197538611262694579912395698393/621272866 +qmulz:1639764361637752909/49863322429,-3667535081176061352,=1:-6013893321168728538238660340400472968/49863322429 +qmulz:4212865081507184639/8422182797,5317645517552525584,826928849605057287/795440204:3200360445247176534048939736551329168/1203168971 +qmulz:4093224907870688472/8446810835,-4394239498678494479,221730631562040646/480114129:-17986610567140020861411212830180946088/8446810835 +qmulz:8729905651613329077/131452699,-9507557452223167406,=1:-83000079535201453087454918169138464262/131452699 +qmulz:4738064793602310889/451996055,4531489655540363995,=1:4294098319897772319607429689642408311/90399211 +qmulz:7744273453919740331/974912,4029995544880393387,5229428187412633641/38528578:31209387517632050003517673680169591097/974912 +qmulz:-8068802747587440815/29032004,-9849867648134802759,8503993416585326183/5318819:79476639142642740206984820735611208585/29032004 +qmulz:2861631232576326878/6980153,2635765392614151917,=1:7542588569248461690745630176942325126/6980153 +qmulz:-1779740841595132817/3012373,9922862571979507578,971621845586608480/521437:-17660123784887653006801622709167987226/3012373 +qmulz:4023122851061736595/781603,3458044068302173434,3738807635979349585/665988:13912136111164966581427463952914617230/781603 +qmulz:586647455438577923/33279,4526301832916840671,3608109198062688989/33159:2655343452827635863034403318209106333/33279 +qmulz:9196111739041159411/1211,3157226438241334248,-5764176110323692119/75991:29034207111522241973647178465501807928/1211 +qmulz:-128347641900306833/12774,-7554445682363002392,5759447892271827483/18544:161599214865874288341552651985490756/2129 +qmulz:836992725257147861/4133,-8611487193024899504,7678442646525158846/9511:-7207752134206937140419355427193560944/4133 +qmulz:8699549138022640117/5811,-6972026102209810211,549233631824230415/177:-60653483667750701802929732179724834687/5811 +qmulz:3156470757655913741/841,-6926959212561953600,-840701905979711979/41:-21864744193927041320056800380044417600/841 +qmulz:509258565369492935/912,8179603403105663140,-6092933483503672408/101:1041383273589253055649823422179978975/228 +qmulz:4260013411623757232/75,-7652070371810821485,=1:-2173194827373526007681124278141981968/5 +qmulz:-5571230682641213483/85,5687608093861986954,1592299486970268628/23:-31686976723362408587412758204074900782/85 +qmulz:1224310285715487476/7,7384878353077411745,1489674084056377327/2:9041382526430324573993691487042805620/7 +qmulz:532608537074668190,5378987672829123810,1299009834218541099:2864894755368193556998428824178603900 +qmulz:-16831183915817756170/2753858239387681579,59557538310440342273,14474171978684251754/88138472845001942881:-1002423880876383309855786104105657574410/2753858239387681579 +qmulz:-76852233908089385223/89591433315005827168,-16827322555441357812,-13261671210390977146/47829058560152879137:323304332269411910681014536231862103019/22397858328751456792 +qmulz:69150327729675178449/8650125162732904421,14293920797793407650,50884780102476306733/6026568253305189080:988429307709434226307578722449551734850/8650125162732904421 +qmulz:30499040613205460343/8988598618848438770,30570026052354339437,51811261931566266659/3748183226209013484:932356466117503990794086213419264446891/8988598618848438770 +qmulz:43819658523452866810/102194429295876731,70504335913014047202,=1:3089475924131090053789938711687559165620/102194429295876731 +qmulz:69656424488183436907/30102774811906661,984948427407800828,-39906369295800321023/155750850550041643:68607985758486503850804077075560358996/30102774811906661 +qmulz:33641878290673988917/12925928405761371,-5396171272119458800,19436319690765846760/70381750662978231:-181537337172274262921911758331238119600/12925928405761371 +qmulz:42954819767647340359/97571649192732270,38715654116595663589,=1:1663023944764940538514016228488546488451/97571649192732270 +qmulz:-99002754944524890631/7986465915924126,-97203975364529818705,12484199575939692941/2326957254470028:9623461352648180166996658939078383052855/7986465915924126 +qmulz:88352255172275736854/7933296505985257,42489727492090669013,98815810269903702196/2382358470880605:3754063245581654384182755776192399905102/7933296505985257 +qmulz:61590480972201025960/675375171340791,-75994828859228936809,-11049721719852020118/20660972971879:-4680558060840013232552967100229808561640/675375171340791 +qmulz:-27522646268475576522/580129834806571,5567162029085222334,74438237038085866509/799763096356799:-153223031245801313480018162391200442348/580129834806571 +qmulz:24148248964829892922/23286035365313,49985702383172830448,7055168644844378885/36672697526553:1207067185830748414507857319763501289056/23286035365313 +qmulz:52980189869726618341/71466611837586,38839808746354627533,32063023501001399398/95171990625945:22126241310599319846248909165943025621/768458191802 +qmulz:-80505026028619928191/8017291718590,-1533155918930949021,-3916532593760914985/326976214133:123426757159468755445689924468501751011/8017291718590 +qmulz:17292391457368334407/1571629061585,-63370707239731364623,43143296273586046143/3465594785525:-1095831076519720312454034284738713483561/1571629061585 +qmulz:-45604879788200428008/529616356051,53301018012216428706,-91229775748273485595/717004201262:-2430786519035835963440363052798417597648/529616356051 +qmulz:-50447424829663619798/988121155093,6780140438275382263,16659035028087001517/899562317168:-342040625094459896541992348672744842874/988121155093 +qmulz:3593845345146253521/41915442602,-63858823181329772213,3118916835826556491/676191095:-229498734436739670514786299133279211973/41915442602 +qmulz:16886813553311884569/11104775518,-56529259575299150290,73272925971647951646/32053123633:-477299533377423659452543589452131437505/5552387759 +qmulz:-36701646710377438096/4191403967,41311697381328283293,85676309288704030215/204223664:-1516207322295535412352618149227058530128/4191403967 +qmulz:-31991568945242380121/3326501360,49756427012706630969,=1:-1591786165245924544503303159456768567249/3326501360 +qmulz:25027541823211097487/727783012,72744111549984214188,27646550684503944351/772714058:455151573552390843680552331807189136389/181945753 +qmulz:-10660456145991522967/70536419,85257294987559072920,-49523716090045547608/476186017:-908881654340736383544975893469407753640/70536419 +qmulz:33128477737669316703/79965173,30163481878837698924,41486580218368730746/24538333:999270237913666562482186749103918327572/79965173 +qmulz:-88082268340996623207/91130108,-98498682060501497133,55248370490574572505/10033543:8675987344487603057841057039320991765531/91130108 +qmulz:-44828402098358201492/3408511,-69899774554986777317,53529539851460359205/7667246:3133495200335534468175721510741221156964/3408511 +qmulz:97775247222108446692/6123089,-93552521078990120186,-42751923423887600316/1557173:-9147120876749770652720919372526854124712/6123089 +qmulz:36516268542348216758/743177,-24090657731418051536,13560217582155473423/145359:-879700927082258851088293609160542840288/743177 +qmulz:13823011732367751421/140456,92159940210798638916,-70795417829842533145/263179:318481983697045021949324000379556224909/35114 +qmulz:21697263555618348560/7063,34463551544345103980,99869086375772085/122:747764760920293478397871020089083268800/7063 +qmulz:-40668672455972057307/50141,18865137997582967131,=1:-26455866140014285075027032694601012973/1729 +qmulz:-15581921553193083728/2673,-55246769898174604433,-17101679935689176965/8667:860850834620665736463709777467848966224/2673 +qmulz:5779320031390413993/7,19217000507739754005,25876817036248520828/8953:111061195977620116757818678920929791965/7 +qmulz:2423549793740192960/491,98696549719389277261,-8414536430516573180/273:239196002715294582270898075501080282560/491 +qmulz:27706287293558914219/676,32022217504768731686,-38742274862382707994/961:443608378981976875151437105221950621617/338 +qmulz:64017926203955613359/38,64555971256483309833,70053608548103954878/35:4132739403922228262726093720335950859047/38 +qmulz:53804889371534152691/9,-61739634189995994475,-2917407728537843404/21:-3321894187431722069404444190953042382225/9 +qmulz:-63773122944071670311,68924540068336860054,-11050684739856731468:-4395533167641640581052894142988833656794 +qmulz:91952574331161593349/4,-53703503362679036569,87690617237600059250:-4938175384800530690367847777470278179581/4 Index: contrib/isl/imath/tests/qsub.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qsub.t @@ -0,0 +1,803 @@ +## Rational subtraction tests +## Generated and verified in PLT Scheme (see imath-test.scm) + +qsub:1/6908363373906559980,-3/3282386453454754261,=2:24007476575174434201/22675918354053873847004295306757074780 +qsub:1/38717857456042735841,4/21180041959354743117,=1:-133691387864816200247/820045845495301036647051443116443956397 +qsub:5/43729125372682174,-9/5619593033754393704,0:14245763648563054043/122869944158248625198135913829316248 +qsub:-2/2974810045372038215,=1,-4/6399510259263906921:0 +qsub:5/554668526872261904,=1,-1/110568531382495635:0 +qsub:3/342789991526278043,-4/498606462885016907,-3/85472740226188603:2866979354760162893/170917305187302413099656668837873001 +qsub:1/3516821512087322,0,4/43427709377638547:1/3516821512087322 +qsub:-8/99244619430310225,9/68745482383862908,2/20174595569499161:-1443165433943695289/6822619236739570045025636310634300 +qsub:1/4158186027003720,3/1924897427288305,2/873983495405445:-2109932130744571/1600816317113127793988749498920 +qsub:7/3877179943979588,0,-3/8937193062762751:7/3877179943979588 +qsub:3/6941436021947,0,-5/715763583943883:3/6941436021947 +qsub:3/164894601106681,5/983718669019872,=2:2126683001526211/162209897529226945840780964832 +qsub:3/97536769945753,-8/56666447486451,-3/355123038725:950293502025377/5527062252129064526472492603 +qsub:0,1/69397821325107,7/899954591994:-1/69397821325107 +qsub:0,1/881101320631,1/1676161462807:-1/881101320631 +qsub:9/5714833944922,-5/2130613532867,=1:47749691520413/12176102541138516914751374 +qsub:1/416320154010,9/647850043316,8/147151224525:-1549515671387/134856514904351145548580 +qsub:1/437091275186,9/260061434048,2/56787440467:-1836880021313/56835291917370078966464 +qsub:1/40450640622,7/70939336904,8/60816634845:-106107573725/1434770811533343057144 +qsub:0,1/44837423526,-1/89874392823:-1/44837423526 +qsub:1/320712007,1/384804019,1/5470204:64092012/123411269235156133 +qsub:-5/9120926808,1/893326726,=2:-6793780219/4073983841738135304 +qsub:3/355507838,=1,-1/715596526:0 +qsub:4/397576755,2/95841397,-3/206755309:-411787922/38104311613926735 +qsub:0,-6/63950497,-1/12602985:6/63950497 +qsub:5/57474807,-3/9692846,8/51541573:220888651/557094453130722 +qsub:-5/7525009,-7/6073612,-1/1008717:22307003/45703984962508 +qsub:3/1999328,6/812029,-6/2808949:-9559881/1623512316512 +qsub:0,7/738513,=2:-7/738513 +qsub:7/320723,=1,9/571685:0 +qsub:7/14415,=1,-5/47022:0 +qsub:-1/22106,3/90671,=1:-22427/286339018 +qsub:3/1135,-9/8459,=2:35592/9600965 +qsub:5/6528,1/1065,=2:-401/2317440 +qsub:3/100,5/979,5/637:2437/97900 +qsub:1/117,=1,-6/601:0 +qsub:5/76,3/55,7/20:47/4180 +qsub:2/5,7/12,8/11:-11/60 +qsub:1/3,=1,=1:0 +qsub:-2,0,1/3:-2 +qsub:-27/133467566250814981,83/42563959651039965219,91/6397136498252123976:-1160304718576896704336/5680908104622192257664942460644145839 +qsub:45/40427972021325393238,64/9751620923778714977,-18/31750379913563777419:-2148567267794782993267/394238257869097174193626565778845125526 +qsub:2/843174797904089739,59/3829064789486601609,=1:-14029727832456030461/1076190310012343744009826655225930017 +qsub:21/135302160124707707,=1,-91/6243239679870796216:0 +qsub:33/269586386932708513,71/663560078654965882,82/347777995721589109:2756849123391569683/178886764117376127330118719865953466 +qsub:-49/381369757179978313,-79/502081482360917424,66/15964802517749773:5526218181533332951/191478693012546642471803143103825712 +qsub:50/84007949326343527,-55/90680207033049248,=2:9154447564601356385/7617858237334741132727849157017696 +qsub:7/63509973628647649,31/6358426332168578,-2/8606093719923861:-1924300198162897073/403823488675725185285863631373122 +qsub:-61/3288737806026908,52/891085361745265,=1:-225370572979860381/2930546117568816471902431590620 +qsub:-68/686724622342265,-2/87939998369281,-97/6330897213879162:-4606470644426578/60390562168923894678643961465 +qsub:53/74615069808694,19/206431401793345,8/335314245039321:9523177968682099/15402893455516996957672341430 +qsub:-41/794425111656850,40/355792921374903,84/720131909879285:-46364514242645023/282650831289974168794338035550 +qsub:-19/9948614096197,=1,-17/6019916154851:0 +qsub:26/86905243242955,5/1105886678309,85/28690254896344:-405773162578741/96107350777587172015563095 +qsub:29/1328659476658,-75/8718935424058,23/3978732114658:88124647011758/2896124044385949895659541 +qsub:89/3664660122749,39/3752130456923,31/2507346317004:191017865878936/13750282860837702636841327 +qsub:-1/111730970852,-4/53644158721,5/525620687366:393279724687/5993713934436112600292 +qsub:9/134376727834,-63/680315135834,-13/19845761250:12619870308/79081766305636815401 +qsub:53/83663624339,-83/23745430735,39/22448823287:8202588649092/1986628796780784659165 +qsub:94/82386633297,59/60658096185,-7/3139891864:280349892289/1665805442295916557315 +qsub:-56/4452532283,=1,-33/2287829573:0 +qsub:5/4288753327,-1/207457757,-40/1852400711:5326042112/889735145545707539 +qsub:31/984155769,43/889343448,-34/317681033:-4916350393/291750828323850504 +qsub:91/918406649,64/20465291,4/3347977:-56915684055/18795459328119859 +qsub:41/61159865,47/95152545,=2:205348138/1163903361321285 +qsub:76/19895571,=1,=1:0 +qsub:1/1255098,=1,83/1479054:0 +qsub:91/7916464,-7/427858,=1:47175163/1693561227056 +qsub:25/630098,19/359620,-70/654341:-1490681/113297921380 +qsub:1/23261,6/84073,16/99379:-55493/1955622053 +qsub:87/25076,=1,7/10664:0 +qsub:88/76661,-54/49307,=1:8478710/3779923927 +qsub:86/1213,99/1546,=1:12869/1875298 +qsub:40/4409,47/6632,=1:58057/29240488 +qsub:47/221,-20/453,32/67:25711/100113 +qsub:88/281,27/221,3/160:11861/62101 +qsub:11/76,=1,0:0 +qsub:12/11,34/37,-91/30:70/407 +qsub:-21/2,9,-75/4:-39/2 +qsub:-78/7,19,=2:-211/7 +qsub:716/63229225130372968755,323/1041977709013285590,-85/5331036743812256792:-87453260788697584113/292815302862361288266503618244274402 +qsub:28/28432306149803878485,51/36062569591582234426,-327/8530238148665402747:-440295665075695238807/1025342019176473906318007480837287724610 +qsub:35/2651717833003975527,94/1600682896707796861,=2:-193237574917600809403/4244559382184525484529422270531420747 +qsub:386/5424883893029166991,-201/2832569452810712705,43/716839232710423233:2183773471283797669321/15366360400439276458941965547170320655 +qsub:971/506137779607436980,-690/134579589961574473,267/104999489601941375:479911849781820329483/68115814843630618803212580924211540 +qsub:846/926665120742753771,-693/971167451265042566,=1:1463786592444954374139/899947003487953107927067006372016386 +qsub:-160/248883036705679,=1,950/1477253685625391:0 +qsub:306/15329555212551109,173/93038341559131937,683/17162719883913218:25817719465323030865/1426236393814901458412317286668133 +qsub:-625/3476582462880142,-872/8679903101365753,437/9209000641481251:-2393359530722111801/30176398901707132402666142576926 +qsub:4/92742256929161,-206/1677519242207209,-29/1920847318304748:25814981896236002/155576920564392438731996521649 +qsub:105/440859258236711,23/114084068799213,859/777590483782957:1839064284473012/50295017947446948173484508443 +qsub:234/109710309040703,435/19164872307439,=2:-43239404312765079/2102584063574743486180689617 +qsub:40/98720052152257,200/37673731641681,195/18309401204:-18237061164784160/3719152752436883045979424017 +qsub:101/8139505456847,-896/64811418546951,=1:13838950162576963/527532894928902528173923497 +qsub:339/2503418324141,=1,203/710577119901:0 +qsub:-210/2286964112149,579/5338514331377,-895/8857700286753:-2445240230523441/12208990688052313177599173 +qsub:223/305810995184,29/35011322751,41/153998316063:-1060993886863/10706847453191530631184 +qsub:212/157864593381,817/922433484280,301/424913103878:6052775079553/13238144265171023231880 +qsub:39/74199525578,=1,86/3093865155:0 +qsub:-285/57499506881,767/82446691329,5/8259783887:-67599428806492/4740644095387518534849 +qsub:419/3764128897,129/517942151,-247/7249378910:-268554866444/1949601017553437447 +qsub:245/1908967167,757/2819581996,-985/2094042342:-754290556399/5382489455028325332 +qsub:-295/48205876,431/527424726,140/594985499:-88183513363/12712485470444988 +qsub:961/845688743,-405/870406786,187/421915568:1178964862261/736093220751009998 +qsub:407/45012097,=1,=2:0 +qsub:-58/619321,49/12338458,193/39820887:-745977293/7641466147018 +qsub:575/7245689,-62/7853229,=2:4964839393/56902054979781 +qsub:95/498463,=1,31/397052:0 +qsub:194/160465,199/12089,-11/7277:-29587269/1939861385 +qsub:266/45609,908/59061,-571/590454:-8567582/897904383 +qsub:131/55938,=1,55/8836:0 +qsub:199/46692,=1,964/70603:0 +qsub:382/8669,-217/474,467/5123:2062241/4109106 +qsub:147/745,528/8207,-88/5227:813069/6114215 +qsub:396/775,=1,-877/724:0 +qsub:6/551,=1,-435/346:0 +qsub:55/24,277/11,54/5:-6043/264 +qsub:10,-123/13,556/9:253/13 +qsub:108,-709/4,-92:1141/4 +qsub:181/9,=1,-941:0 +qsub:5864/87029719866427538623,7169/77056696318482378212,9879/50543130835616368106:-172055594510838358553119/6706222694429899607884755085022523682076 +qsub:5653/86895502758062177839,5653/8154794595245621549,-1891/10149086543140986167:-445121223244401992707370/708614976242596448503974984564128652611 +qsub:661/363701500997277796,479/2983031197662645683,=2:1797570602677312732179/1084932924111611507079868138271154668 +qsub:-667/1895442338469738028,=1,-1283/8749436718472928966:0 +qsub:-9697/818740708549198026,3503/102582377391327177,-1163/20328789690713125:-1287596671870513440149/27996122783345481707441743709517534 +qsub:5593/36797958092515142,-896/400288681159053633,1503/320767765005962056:2271785564173480536601/14729806114199011085303985442610886 +qsub:6797/6164537725975597,-25/1227246984675396,-8333/22072906026109818:8495711197988056537/7565410336121273997822462311412 +qsub:5972/68776879303523725,3471/59251132058857634,=2:115123212592966940773/4075107958209196684815674316366650 +qsub:-6611/9413167004921254,=1,-6256/7532100811974283:0 +qsub:1837/782359177742283,274/89188711189557,2191/8972155631565142:-16842250748723111/23259202250051923207502312877 +qsub:553/12771753856843,7076/381142689332759,4681/186762282268761:120398976909994659/4867860612493178112476219837 +qsub:3079/80223061021791,-3585/408207816163306,=2:1544471539729939909/32747680545640939721680601046 +qsub:-9557/15580233019419,6164/45700338424117,-8859/38230373237191:-532794690650984885/712021921714050551118928023 +qsub:-6948/27781302080773,=1,=1:0 +qsub:965/554586285674,=1,1991/3124819638593:0 +qsub:745/38448222313,1985/5666404010804,403/1187780069839:4145151266757675/217863161122667045869652 +qsub:-859/409102304936,=1,4163/697719670590:0 +qsub:958/328712574179,-6903/92390217229,942/905293648915:2357612727663019/30369826134301586329991 +qsub:151/12267425536,=1,=1:0 +qsub:8671/21057436708,2207/65025757482,2889/90207961763:36954612879419/97805412326212317804 +qsub:-563/827856356,2261/803220213,9777/7547919848:-2323996200835/664950958599723828 +qsub:75/325694386,7497/1661300549,1948/1110250407:-2317133270667/541076262268017914 +qsub:3501/918304436,961/56965645,=2:-683053839851/52311804503101220 +qsub:1123/310344294,2131/431751558,2307/53942272:-4902408080/3721989790303057 +qsub:1405/9784159,2196/25867783,=1:14858221951/253094501849497 +qsub:794/7899253,-2407/48403717,=1:57446053269/382353206723401 +qsub:1229/5474993,4511/2921328,-7447/1108510:-21107381311/15994250350704 +qsub:-7372/331741,-1691/1178944,5486/4648811:-8130201137/391104061504 +qsub:5538/47579,1604/905061,-3007/385287:4935911102/43061897319 +qsub:6299/305054,917/272126,5357/926074:358596789/20753281201 +qsub:-4585/61734,=1,3775/46277:0 +qsub:419/11735,-8692/17091,1813/23231:109161749/200562885 +qsub:-1997/1968,4543/2391,=2:-1523939/522832 +qsub:2071/1736,755/3768,4076/8723:405803/408828 +qsub:838/393,-953/227,-1542/517:564755/89211 +qsub:30/29,5248/27,=2:-151382/783 +qsub:391/83,-375/8,1924/15:34253/664 +qsub:3263/21,607/4,-2267/41:305/84 +qsub:9453,3109/2,6826/5:15797/2 +qsub:-3878,309,8605/9:-4187 +qsub:11222/48066783055662674131,=1,=1:0 +qsub:44095/11229138978726519749,=1,=1:0 +qsub:32172/9931355060831305057,-22127/1443489042124973960,7360/8565719299009119553:266191022894258949237359/14335802203762393030456814478941315720 +qsub:64044/4464944802393435647,12647/913738015734848205,80458/8255357897052863503:2051280563852837813411/4079789804104601810582916593980963635 +qsub:41455/753918793466056957,=1,38552/179247636782332451:0 +qsub:70832/329222465952924851,20242/279519391122527087,98212/275893153651362115:13134796356171733792442/92024063227018458748454302122939037 +qsub:16550/9390796490643017,=1,=1:0 +qsub:-52475/54547572128706592,17578/797685580288227,7736/4761258128626551:-1000695773704029186001/43511811726801235561284074892384 +qsub:-20996/6762826792669,-44673/3665405594824492,-89646/5844908573159699:-76656740107626131795/24788503162677927378327249148 +qsub:45185/5494693252958359,32663/2723960065506187,40281/8753885671043431:-56391030161481820422/14967324993264855317568567867133 +qsub:12788/20397625645595,85276/411854703134143,=2:3527370019125661464/8400858054907910680262050085 +qsub:5182/89854258440697,64615/978522088368546,=2:-735231447219831283/87924376618197880146621116562 +qsub:14899/24106539570023,26806/37583148137177,60169/20330813693322:-86248575618236415/905999647734893551001045071 +qsub:77/5504614030045,39585/32999174301133,41462/80693310429705:-215359209958144084/181647717837917119539540985 +qsub:82526/6888246953501,26067/1462753317193,18855/1955140329926:-58840753082241049/10075806080878164174842693 +qsub:48233/7425592622352,-67581/3978085226579,41398/5449697074565:693703959744755419/29539640309572506699893808 +qsub:5505/559716521882,37907/205803582655,=2:-20084225472465199/115191665474511303156710 +qsub:21476/65447686805,89325/499062486437,-40113/803762193086:4871751334864387/32662485308453336363785 +qsub:21526/16385258133,59161/53875727711,=1:190360658300573/882767705647956223563 +qsub:-19280/22598967893,14123/12257869757,=2:-555496952467799/277015205075018712001 +qsub:10456/7458705583,-25903/4591932494,70435/2217009577:241216096873713/34249872529756914002 +qsub:19521/861174313,=1,-5154/2978985245:0 +qsub:682/74110691,2034/18404407,13571/194261092:-138189339920/1363963320215237 +qsub:17065/678911302,47417/43292069,6893/55518891:-31453158049449/29391474931063838 +qsub:66870/71491241,=1,54717/26772383:0 +qsub:61950/53770049,38657/31651038,=2:-117806980093/1701877864160862 +qsub:125/24174,61922/4089943,14863/1071502:-985659553/98870282082 +qsub:10528/5066181,69178/5064619,8499/4855615:-297147960386/25658276550039 +qsub:73667/793622,-17081/241311,14485/728923:31332514819/191509718442 +qsub:-88059/511891,4080/46861,49511/313693:-6215048079/23987724151 +qsub:96249/64877,25429/18718,15172/33979:151831549/1214367686 +qsub:-54470/35523,46889/71763,-69316/98395:-1858189519/849745683 +qsub:44983/9496,84144/9341,30612/1481:-378845221/88702136 +qsub:43297/8081,24282/8963,-12747/9001:191848169/72430003 +qsub:-14149/568,-11037/95,10139/463:4924861/53960 +qsub:32022/65,=1,=2:0 +qsub:-5464/11,57106/13,-42349/21:-699198/143 +qsub:9122/11,30683,21590/69:-328391/11 +qsub:80394,-42819/2,78542:203607/2 +qsub:78738,81991/5,-92741/4:311699/5 +qsub:519349/84038265230060350539,362530/8834704951888139441,101653/2801162463496519815:-25878097111795625550359761/742453277976103030839734354712971508699 +qsub:-45313/4045263795932519300,=1,-897976/3871830745560558349:0 +qsub:-219497/3880705578320077638,=1,1955/195812018697132227:0 +qsub:-694177/1567385155785412134,749667/2535436916491658333,-965299/416081746175083596:-2935058919961612464886319/3974006186339362871680339779520412622 +qsub:26135/62576945582816088,732203/950441429248291026,=2:-1165513362953922339853/3304206755429125252534073692157016 +qsub:344416/442049470250620209,200643/69700793670676003,61742/228330350355985637:-64688063306615644345139/30811198918170109145079107043144627 +qsub:497397/42178943629236355,-221769/8144580724357867,=2:13405072168265547184194/343529811256455471792784946654785 +qsub:48033/18607268489677754,110044/5810062497436207,44420/6136363607606977:-1768543521738745430345/108109392831603170896668602039078 +qsub:556572/2349911949088169,-916879/8313100022391424,574574/9350618406931231:6781423623630450943079/19535053076582732528599605462656 +qsub:284777/1927882721172702,160787/3581064945969006,754048/423838688960001:19717401473028344033/191774256464747287423446257617 +qsub:892952/185949909151557,=1,175057/59061216301442:0 +qsub:-661714/491200735750687,450275/303031578402964,15122/4784925303203:-421695649161479509221/148849334267227909475125836268 +qsub:187069/55339769759630,621163/52226505565130,637525/3333974030852:-1230252861681887286/144510139666216453870485095 +qsub:219295/84834684101354,903655/27591730927967,=2:-70610557827760525605/2340735777083639503901167318 +qsub:-81292/3037742698087,279570/7725479008867,-183321/5178790607504:-1477281365692998754/23468017448410123176937429 +qsub:17070/729776002573,=1,494590/5887202393519:0 +qsub:480492/747354949451,=1,=2:0 +qsub:-199046/37296461289,419244/37303053961,-158450/158465916423:-23061341295366722/1391271908017914615729 +qsub:189316/25281354931,=1,=2:0 +qsub:-322219/71926874588,364328/31410801333,564494/88472961545:-36326131359614791/2259280768187274225804 +qsub:865470/7987112681,-75379/665073758,-53389/213996667:1177661952117359/5312019046322125198 +qsub:508019/5416093157,978840/4026946153,=1:-3255723468096973/21810315502870775021 +qsub:-355411/591634303,88/18167855,-400943/223386928:-6509119332069/10748726229930065 +qsub:-448810/805205621,80689/395020417,609682/664304967:-22023668155149/28915696379833087 +qsub:-295343/11433941,-409495/43207522,-681896/44977613:-8078897500251/494032257304202 +qsub:24193/2785136,19643/9724857,=2:180565038953/27085049325552 +qsub:260123/1810064,259343/3327309,989234/353681:396082171055/6022642237776 +qsub:81657/9557416,=1,74075/783308:0 +qsub:-379579/856742,338617/650312,4129/163380:-268476092231/278574801752 +qsub:625321/775536,-97485/252179,=2:233295951419/195573892944 +qsub:947687/23575,-30577/320,-279954/24839:204822523/1508800 +qsub:259621/46980,191999/83022,85242/3763:2089023607/650062260 +qsub:-109983/2035,269459/7712,=2:-1396537961/15693920 +qsub:495239/4609,169141/85,150340/2337:-737475554/391765 +qsub:181604/763,478129/150,491042/65:-337571827/114450 +qsub:88196/477,143431/288,-238297/503:-4779571/15264 +qsub:-570,200993/64,457558/27:-237473/64 +qsub:404456/75,=1,-923061/28:0 +qsub:-139593/4,318475/9,155531/3:-2530237/36 +qsub:-14344,290960/3,=2:-333992/3 +qsub:3264013/82557280791246853782,1806333/5633889739728044851,-2296597/13263726327210302219:-130736851332456348274354343/465118617189652853731071620663934976482 +qsub:-2980063/1992165262437351098,7376362/30250769500070022259,7703450/29762987155235234457:-104844131048250074763167793/60264532160038812168147102169858090382 +qsub:4464355/431626495996272004,3629338/7179109931450482327,3949813/156748150199903165:30483576874294500186500733/3098694064084008191204928519686873308 +qsub:-3555443/3617243579662686774,303530/2167413807252149777,2777975/533604037161157073:-8804058192833020476098431/7840063678755098878650516823284949398 +qsub:-5552437/989682869077264596,=1,326173/620111908036849741:0 +qsub:4895607/926011931053273421,-1175537/233388199725215284,5091515/239597642395083213:2231138191686733898359465/216120257512593662347946882140166564 +qsub:-2773250/45398131003067227,=1,2736089/95411568076119212:0 +qsub:4006296/68939728562838647,2292964/17013091088520595,5733592/97158552976704111:-89916836988785049713588/1172877881657458911248848921434965 +qsub:515144/49193197792111,=1,1856594/2763661324543529:0 +qsub:8325234/9817785169298149,775935/6180815223492473,=2:43838769910997775719367/60681916035376625680601994332477 +qsub:8627988/156641134252337,=1,3184877/121316717056413:0 +qsub:-3680933/800181047302935,-234725/6902800483321,1839349/73481955705762:162413750236709199382/5523490120067003681501847135 +qsub:1566629/16292772606875,7730144/88872981722417,=1:13285512072409282293/1447987282098298252715816875 +qsub:-7275809/32705732310204,529237/33225169211346,1246554/16046220459869:-14391614934727197959/60369638343750779183798588 +qsub:672357/665582539507,3252537/4040790284267,=1:552021796858428060/2689479459017642288036369 +qsub:-9287113/8904358895491,-1605430/1566913557651,9964765/2264645576736:-256778369548735433/13952360675535131712451641 +qsub:-7651618/4395153917,-1710285/172432083914,2275814/176521974301:-1311867471236936507/757865549031089791138 +qsub:1899605/130650302531,-4840329/426407852458,-3076004/154973753433:206056705252578827/7958616417890244567314 +qsub:2052129/29055355967,2964502/48925195457,=2:14266151553094519/1421538969758186241919 +qsub:2602385/95672384206,3573881/34551770887,7452346/64314906595:-252004705858757991/3305650299298749410722 +qsub:4133338/19957331,8985416/288073487,-848120/288429411:1011380169324910/5749177932383197 +qsub:-1320449/3975283846,-7547086/2795237793,1985723/1567287621:26310840111643699/11111863644241591878 +qsub:3012/50622749,=1,-3880764/539469199:0 +qsub:3415313/456078745,973889/57988958,2014841/282103745:-246119630775451/26447531188497710 +qsub:2670463/29405389,-1058573/52085339,8775931/27268718:170219721491854/1531589654491871 +qsub:8583563/83502235,=1,=1:0 +qsub:-2291635/5535573,5441924/9510935,4978191/9285940:-51919759091177/52648474990755 +qsub:-4162723/8479109,344312/1648925,7433795/4104773:-9783477000783/13981414807825 +qsub:8751329/789348,=1,=2:0 +qsub:8924261/337441,670861/129305,9868269/414227:927575561904/43632808505 +qsub:2681459/27003,=1,4549337/93154:0 +qsub:8680180/14441,4554745/21934,4059413/27440:124615995575/316748894 +qsub:-4518181/5562,-2276489/226,3678862/4781:2910180728/314253 +qsub:210295/1363,9437631/8144,1068488/1033:-11150848573/11100272 +qsub:5745218/207,-7575883/59,=1:1907175643/12213 +qsub:379339/704,=1,-7001184/173:0 +qsub:6487539/2,639662/15,=1:96033761/30 +qsub:402577,2061668/19,=2:5587295/19 +qsub:-3105019/2,3111189,867043/4:-9327397/2 +qsub:1261450/7,4029231,=1:-26943167/7 +qsub:56324553/19397300916635452498,-35924092/46902696457421385061,84175915/39224029534660703473:3338603835139839372201484549/909785716986214223068528185651632332378 +qsub:71555823/5836071212068629344,=1,=2:0 +qsub:77442257/5545018942084673068,42879535/9528293896880000587,=1:500124750930929791835741479/52834570143949387832940624231543090916 +qsub:1882546/587096528196767501,600949/3758491116151436011,-57408520/7215298889224654953:6722717345223102023805557/2206597085550901708728088609445878511 +qsub:18533295/259544696596588724,29260803/65551904123652131,8066314/468460265894896593:-6379593459872191703783727/17013649067101965587047139053170844 +qsub:32814976/324705085482999809,15878615/126957830524485142,48012589/448457761496522203:-20198956719461136022407/841303126799778581810770681823222 +qsub:73425587/76876862799514627,=1,=2:0 +qsub:42901263/91461268846245118,59358212/33469972365725591,25272929/7921365826117970:-3993073298899687352887583/3061206140818023006999579911414738 +qsub:-63644711/8497399665364222,7797817/1098486658784562,56710153/9438426287422742:-34043508375517625313739/2333570041690749863451890185191 +qsub:25665970/5646791945789527,18692206/1353307528791823,8000643/4532947645247332:-70817047855093605963252/7641846053757994531550156637721 +qsub:-29275899/499819621292276,8512344/446435883937597,42654021/421680780818527:-17324448402522389929647/223137414440972214604482100772 +qsub:10506641/183030842318251,56266904/341432867278395,19138129/13903991433546:-6711266271665423143709/62492745293100236702806487145 +qsub:40020635/13147436598409,=1,95925753/47588135567153:0 +qsub:64062683/28830327884364,35024477/22435119389260,-3892716/40203147434419:53435848201618925869/80851481014652251447941330 +qsub:687674/747723187903,75114792/959745497435,-6008972/779187819521:-55505079707707644986/717623962917648709528805 +qsub:11227721/638144654215,83818613/2696629423889,5802172/903741356827:-23211396997849476826/1720839651253640565542135 +qsub:68154693/605106523822,7149707/547148784630,-89487120/164245654829:8241105773166237109/82770824770222860613965 +qsub:5295524/207408901727,=1,-20716229/60404143771:0 +qsub:-49715976/27289320239,1751391/3004904467,-59390244/46731089623:-197186028226367241/82001800287564607613 +qsub:78299509/99826075029,4177685/5327015769,=1:20274296809852/177258358612286710767 +qsub:-1671167/695155932,-66109555/7854377639,8291158/4963791901:32830472604295547/5460017207919004548 +qsub:35734579/4659787581,=1,97009779/704152619:0 +qsub:30397277/925127047,-10856719/255060817,82870995/232582799:17796998694774102/235963660436617399 +qsub:5543155/496322152,-87192627/129840895,=1:43995360477497029/64442912424006040 +qsub:4832663/6516999,1014585/45500272,66517292/12541481:213275431553921/296525227123728 +qsub:-61572274/59677033,88452583/75989018,9276799/22909073:-9957404351913171/4534799134823594 +qsub:10222701/4964078,=1,44891997/7795153:0 +qsub:-12931066/33763,=1,-11768212/629261:0 +qsub:40097296/352421,81636923/466815,-2827835/59378:-10052546808343/164515409115 +qsub:-58131798/713399,-10445579/899533,=1:-44839605037313/641725942667 +qsub:82683100/20953,11064248/17087,1257553/185:1180976941356/358023911 +qsub:-80145609/17039,35705967/4424,=1:-962958145929/75380536 +qsub:24043257/7198,56987892/9335,-75350352/8581:-185755042521/67193330 +qsub:14613190/1321,24976151/4199,-77272282/6003:28367289339/5546879 +qsub:-95371537/443,32446316/271,28275075/223:-40219404515/120053 +qsub:94947713/221,57161945/491,2069553/455:33986537238/108511 +qsub:-18909223/59,-948326/3,-48280688/79:-776435/177 +qsub:88798812/19,23507525/86,=2:7190054857/1634 +qsub:-47127907/7,27516609/8,38296261/5:-569639519/56 +qsub:31326068/9,51645326/9,=1:-6773086/3 +qsub:898471353/97040476457400255673,774658681/12204618595061363031,=2:-64207747314147492788222196370/1184342003445601583509560261503270224863 +qsub:249093288/12417260530710049873,-801966629/44332144897015616603,=2:21001068305718331000060348781/550483793071430964691988116237976841419 +qsub:-134206127/1610240404875467236,97309922/1581131192036203833,53593907/846433764211142925:-368889861761752296658200383/2546001330825606997121589113609115588 +qsub:421338764/3148326051373083753,429845640/199253189241064703,=1:-1269341134003247764575839828/627314006506815051070753494111070359 +qsub:52740675/795085501889262583,149708345/329574924655249317,2466699/30866271646478867:-101648930631943883299486160/262040244379634804277810209144405811 +qsub:-191594029/598205858083829268,446816852/164644010257658459,56048321/893326266268239982:-298833267632957457898965647/98491011434545366397536822011978012 +qsub:-575491297/25955098472036838,-138975931/6423674226330072,-340643144/90343407636590953:-4979702092675981002067/9262616505371226069222196177352 +qsub:-473218836/46012936562560027,926673527/60598178499774699,=1:-71315169705438365692335593/2788300143116822172490338163356873 +qsub:-16401255/53884896854597,845057173/2931801378584781,=2:-93621040622862865174436/157979814883206214102194088257 +qsub:-78818865/905572899138638,481887257/926039606509552,=1:-254686715554792714417223/419298185592029277399259635088 +qsub:116637517/435071997593711,431546961/511014413627938,-757699852/228015168261633:-128150546020991644612325/222328061736285879181642697918 +qsub:-108955903/383831042493702,422517039/842122710676085,337667995/131589026243929:-253929395929242726868133/323232837946423896536774516670 +qsub:-838736295/92052976509482,-126995685/98224611661102,=1:-1039620824328469286940/132968645145476678498140723 +qsub:692740952/65411481215877,935265461/38090055601935,-384913949/18100942097057:-11596852584880885994059/830508985505893916304640665 +qsub:-860091341/514295231452,256640967/7499412024638,-53504958/4042771540931:-3291084285252876276821/1928455921482556068257188 +qsub:563680440/4169101815059,=1,-402824439/859095166759:0 +qsub:987037827/249183535720,-9882433/691842226,729392866/51288203029:1572707021916944831/86197846017537656360 +qsub:427594973/45174550465,-168845346/330313786895,27534398/79447419565:5954721095702106589/596871073414937326247 +qsub:242570638/16753352417,33473267/19130627213,798544080/26148870871:4079739009798235555/320502139657639523821 +qsub:-376284203/51060506886,29964175/4314022267,946743721/88569137724:-3153284394383157251/220276163670510830562 +qsub:74562538/3217746607,101790049/9743999086,-125780219/323630553:399002717325726525/31353719997587601202 +qsub:42296349/1360874,206369290/316181321,=1:13092472899137569/430282939034554 +qsub:140753986/202352937,938572056/619643731,-19975553/199697682:-102705487079566706/125386728861487947 +qsub:285566114/446058601,342294325/851420566,454403609/475658768:90453534672561199/379783466532588166 +qsub:-161678013/7988168,=1,=2:0 +qsub:4509787/2436277,-428747855/91437693,820266458/82427847:1456913057137226/222767548388961 +qsub:234853231/269701,164588489/2987771,26310281/83858:657297992766312/805804826471 +qsub:-31992898/7754101,-108145397/2546307,471535535/4631202:757106590895411/19744321655007 +qsub:-668796933/155882,935009291/130380,48837623/940728:-2840839785661/247852380 +qsub:456817877/484064,62463895/102249,201875360/879883:2353235462299/7070722848 +qsub:174324995/23089,=1,-75895555/10708:0 +qsub:-40050163/4536,-337645492/6227,218198970/84373:1282167586711/28245672 +qsub:-486371763/6677,832463275/2822,668314177/8066:-6930898402361/18842494 +qsub:323293648/4923,451897472/6255,1266843/26:-7499610608/1140495 +qsub:-867092722/717,317941119/130,-414616612/433:-340685836183/93210 +qsub:817008963/673,332237585/116,450682823/188:-128822854997/78068 +qsub:364631942/71,-521194704/91,393312056/29:70186330706/6461 +qsub:-366929570/43,-318888401/38,12434704/63:-231122417/1634 +qsub:-960895081/4,-86364312,369915274/3:-615437833/4 +qsub:-88689682,-50232394/7,220772295/2:-570595380/7 +qsub:5045827429/82586019977510276867,=1,=1:0 +qsub:1503080467/4197901399132742687,-5426267647/98427189918387234069,3137956632/34196804706756691007:170722923135437211172114777712/413187638271101955385621594687817003403 +qsub:1357458555/213194631658339198,5860802023/9743688404730714679,5343163284/4333989766915232599:1711023093391439556544861613/296757437205742197184000936677098206 +qsub:-4868419043/1874304123005359675,-6816693713/4442416679029074571,5495574701/476000389079390237:-1264426975083621632892461754/1189491413944567430701990198321617775 +qsub:-1647705544/574150473752043335,=1,1879152786/115463808794482409:0 +qsub:-6055562447/487155696631523136,2938185647/317996041759500124,-4728956063/923230126390049652:-839249691117625070582468105/38728395812354051261713195025217216 +qsub:1426529236/11670702563243101,9841949531/91619079682399779,1403083816/16150846549726251:15834830123605943657503213/1069259028091357016655804645674679 +qsub:6837809671/96275996695534461,3411015807/98409047856427193,96187735/946145664954649:344503392583431867018558476/9474429166236077065902521068997973 +qsub:-1004764769/8655312988255579,2879315998/2504870158905897,-1660768037/5076443781115095:-27438186441369551619395635/21680435220272026384233246249363 +qsub:-1613849677/5578341227875998,-681199447/9468113018720909,=2:-11480148177455803120623287/52816365202520317549788821842182 +qsub:7085065306/241255838198475,9871968965/122428691848806,9976645636/596673705145837:-504751623414488774067913/9845545557175498481373256950 +qsub:277829246/34194391207887,945644619/248861822737406,507960871/53401800544381:36805350523599913065823/8509678523390688833157121122 +qsub:8778198607/68845960402604,6712013093/80288466242958,-1204808691/92342273421469:121346557454831419932667/2763768283874247206479931316 +qsub:576607227/41894800028798,=1,=2:0 +qsub:-8197300862/1066469371293,2407397879/7628604144700,=1:-65101379433675314418947/8135672666041382998097100 +qsub:433828061/8105976668621,12288275/146073601224,-3529694919/6043133675158:-36237643265303572111/1184069203423191947992104 +qsub:2306893742/244897997045,=1,9806514683/82914371649:0 +qsub:-6917120851/658194979071,-9884712310/347680431211,2627577543/430392157826:4101120451789026783449/228841514144320400184981 +qsub:4348960295/47252752559,7472787551/90699413377,-104990832/2615837561:41338366482986273206/4285796937549835581743 +qsub:92405095/21190566348,1628334368/828240675,-4846323983/71007937340:-11476264601192136313/5850296325233268300 +qsub:8741146531/1488923836,4234232059/588146433,=1:-1163374887262484401/875705243152076988 +qsub:-7225160297/450834154,-10918713/11024261,3391394031/6088513222:-74729524142841715/4970113381410194 +qsub:2938592113/331333420,3934937063/187151085,=1:-13705735495420961/1127443800904740 +qsub:-2273685624/814502443,3041871576/168756109,=1:-2861310168939737184/137452263051674287 +qsub:3296666020/58254199,2646013137/43895953,=2:-9431079168795203/2557123581356647 +qsub:531031879/25049980,=1,=2:0 +qsub:5011008152/8879109,=1,8455979085/128459:0 +qsub:6770210010/3190157,-4380377540/4239579,3903233564/5705791:42676932255859570/13524922623903 +qsub:7663675612/749679,8111469146/393203,=1:-3067617836238898/294776031837 +qsub:4928169857/385836,=1,959097302/535523:0 +qsub:-1033483668/35795,-5074071593/2166,2441844767/6292:179387867046547/77531970 +qsub:-7344953203/83791,4312882738/17085,2299543269/590:-486869282973013/1431569235 +qsub:1418881373/3187,-364599262/733,=2:2202017894403/2336071 +qsub:-9933599930/2319,-676583006/3991,152888566/817:-38076001329716/9255129 +qsub:3939072211/317,-1768855994/157,3228818149/267:1179161687225/49769 +qsub:1276721019/328,1232959715/379,-1601655315/2:79466479681/124312 +qsub:3256070519/2,1845522973/18,5526750176/99:13729555849/9 +qsub:5966979829/5,27542839/7,-425197375/6:41631144608/35 +qsub:3307015390,1197592867/2,1660312324:5416437913/2 +qsub:5489019241/5,-3873449097/4,-9097250437/8:41323322449/20 +qsub:-36147389137/7366455075149766236,36459659324/31660854497077511625,17927437097/85118037223370314774:-21090084632556843838855432867/3481018840202610972909309235691380500 +qsub:-43262536631/6771439507252414257,9845873437/16005003509293583369,35333513871/31102122701082443005:-759087786974806113821731281148/108376913076544103155525491523953691833 +qsub:1879439977/100949624469036789,38241797291/3160034691975528111,7272414554/1249028818965241647:692866817752736748847051616/106334771821352635019895345254225193 +qsub:-23480972450/1429132014458260453,=1,17730739651/3229879048891135949:0 +qsub:87672655831/185695396976817387,=1,=2:0 +qsub:19335279285/86985857831839459,35182894985/296532209461553487,7819401698/300283568935056049:2673118785659508665734403680/25794108614783931312606692925643533 +qsub:105573770/9591706978551267,-91012289917/82779886875572184,-95699623013/92086977963850524:293900867022815896407896173/264666806209370051637912001052376 +qsub:81888799513/62677875753838689,42525624315/5887466452325273,7440075611/13710507286638085:-2183298237216013854166130986/369013890803736912387239799887097 +qsub:45845595582/1944435405423019,3957631182/8503827262812577,=2:382167667398204481110256356/16535142811414295102976398509963 +qsub:70073122775/9889502421893828,49758775289/4581689842004485,97971868835/5554125313499619:-171036213915285631762370417/45310632788869704568457369818580 +qsub:35007906083/96744217462517,41582054123/195125002566641,4259598485/79647205603988:2808094477684438458969612/18877215680681304677212095397 +qsub:53616094879/804153146230066,-40630189441/409120361012696,=1:27304165381945598904758445/164497712747569959659181458968 +qsub:49936923088/1008159757073,=1,=2:0 +qsub:-54774651067/87557778501674,14552025462/34442391625465,32721932085/17018898896738:-3160713005350324584244543/3015699297010375993083528410 +qsub:36944437609/1522384186532,-31109095589/1913990492988,-90340980434/4550319003301:7379456095901269524565/182114303731094876877351 +qsub:37427798265/3644867199671,17190258551/4857734158151,15531453562/538438754347:119158084549871401271294/17705795897765998009168321 +qsub:-1297758412/359023140343,-13169443469/334495854946,62942721054/868305110777:4294040141274688464115/120091752274429528686478 +qsub:64548705326/965177946721,99400187824/233208667431,-40288901926/927917471935:-80885551634177312487598/225087862788593125943751 +qsub:22792905511/831110170,=1,2899870693/1104812470:0 +qsub:-4225625539/18480348712,12201952952/28791900419,=1:-347160135247248998665/532084359824298910328 +qsub:-2659312874/1644066659,16956954950/4918000213,27389168623/355474397:-40956865552225654212/8085520179148198367 +qsub:47019333517/2453731385,25608075613/4795411666,-79908243099/4320471629:162641721633895395317/11766652108859337410 +qsub:79879022561/451475806,-74196589329/217100545,-15269666465/326484577:50839744301821669919/98015643536914270 +qsub:-96216336903/275984570,5409672454/132808555,14083109727/56233823:-2854267759507727989/7330622388799270 +qsub:63979921573/4858216,31476961600/87404319,9515612291/12422366:5439199596284968187/424629061034904 +qsub:82582224886/74464385,=1,10918064727/56241685:0 +qsub:-46341807304/5147537,9784020329/2675947,44710947790/4319699:-174371826881996561/13774536192539 +qsub:-18674665469/1251399,-11269265668/7443487,57599246809/9830290:-124902281860180871/9314772188313 +qsub:58536600266/32903,83073082013/333030,-39859237469/373423:16761090369112241/10957686090 +qsub:35519852107/330820,53390770345/780257,35509809151/171706:10051878599918599/258124620740 +qsub:-63435900802/6951,=1,62381742036/76259:0 +qsub:-81473653859/71229,11757463559/6248,38764522219/56443:-1346519761155043/445038792 +qsub:44117486351/5857,-2571472421/106,=1:19737567523003/620842 +qsub:32241620201/9076,32252415098/1479,=2:-245037563152169/13423404 +qsub:-3547397518/617,24052413914/841,76689146655/466:-17823700697576/518897 +qsub:-7334508913/948,39473373047/321,1323910388:-13258378336543/101436 +qsub:-3196198423/2,-20901693416/31,16678712262:-57278764281/62 +qsub:-62722671643/56,=1,=2:0 +qsub:-24012149879/4,-24290006742/7,57308122924/5:-70925022185/28 +qsub:6872078720/7,-32246825481/8,58358089888:280704408127/56 +qsub:-959881635801/62932017065985873602,-493229779705/99840110881639578512,-80856942953/6609275501579816959:-32397372018886953016823147330351/3141569780936631939917776357106693620112 +qsub:-332008736903/30374537863168416351,682789260493/54319888411218401110,959961568525/17615592824200222523:-38774085785529920230015532683373/1649941507269636595870960818509000549610 +qsub:113948825097/9684396113323745389,=1,10627090663/610867879165779530:0 +qsub:163071738121/654459680340198322,272886493781/4350646667188036069,-795490699161/9312605941419401831:530874306479618083947510650867/2847322827081031281338460249149276218 +qsub:76846819557/104316101165717458,371275948758/843864366174376699,-256575092889/873170706343972834:26118233246947241582284285179/88028640591990321004129490292711142 +qsub:389764163769/207967463890639277,143006030005/867552974642992847,452774579891/377044461928347543:28036405300529641258282732178/16402071993389391564815603942568329 +qsub:580979558458/78741205846222619,33032926279/1750557646838547,12997506366/8714829535529515:-1584014239122301048375024175/137841020015393107847327312494593 +qsub:224741963637/14683522164236398,-960061639375/75273715504183749,=2:31014248993459091498049306363/1105283269990107068967870865896102 +qsub:807804997047/7249998154317344,9105704912/112491433689913,26073756553/3602151159257410:24854798453934594011093183/815562686628381139953493751072 +qsub:191337323199/6659274625984151,83413589251/1210878215905176,-306099086431/1081677916528086:-323787801810171460500982877/8063570578334296950020294865576 +qsub:-331867978975/508606776667332,85749318495/2137585782677,377450159524/218818801378045:-44322080754745095885121415/1087190614777265014877407764 +qsub:262259669890/904860545418883,782901326213/392394092067508,308978360414/335667028727945:-605507375993851106638145959/355061932167352680139373953564 +qsub:815877865693/66519087957156,-546996067745/51276831144013,29432156288/2425613695755:216679532121401094151189/9448443326960766943517748 +qsub:-562619974684/10325037296475,556872690819/57561686137409,595241901749/85716594322193:-38135085699491971638916781/594326556216735906721333275 +qsub:569774646278/5879076793409,-721915496161/392079169147,-50551273318/7061973297467:4467593410196183185587715/2305063544511209685752123 +qsub:-558695968419/8022121294387,-777164712527/4870971993346,733030717073/7075271044115:3513117174644727699545975/39075528152183639071148902 +qsub:230578421654/363657556093,=1,36043149487/191906623355:0 +qsub:-442745155107/891737442305,209381515609/66199123967,267993885312/121209167453:-216022678603831030588214/59032237489164205223935 +qsub:191691349919/14156267513,63217315803/9723609341,-128345831172/10660892885:969010566700217585440/137650015023101638933 +qsub:4645100745/1355591564,-122150924616/84421443943,321940027501/7149085070:557732875097854576959/114440997229829696852 +qsub:444175516387/7975146669,-45314342690/1470525299,290828709372/1185708607:1014559863205550574323/11727654940000079031 +qsub:789307912523/3728805469,=1,424506863658/9402774203:0 +qsub:-502776486811/539515375,235504157527/997755438,=2:-628706087676449005843/538304399290859250 +qsub:5577709792/27083659,72210181067/64923595,840185174073/737144356:-1593590948783541913/1758368508034105 +qsub:185204908129/17512100,=1,397024789371/90565963:0 +qsub:-59165606754/7623599,=1,410439347980/15967881:0 +qsub:821602843151/5722683,192153300265/868108,739244189764/864319:-386392423858282687/4967906893764 +qsub:-321094052171/8002674,=1,63324198409/402344:0 +qsub:-787087016971/706048,314711556301/97333,461259945208/201559:-298811005526046791/68721769984 +qsub:264872646016/44135,-306557419723/722285,-978795728169/729376:40968690169428233/6375609695 +qsub:165112253012/26681,68785586791/12017,-119718397615/15426:148885703274533/320625577 +qsub:17528604773/6611,-99181928610/39343,-52006507697/18356:1345319627624849/260096573 +qsub:871912524148/5723,182323508186/1091,203321662049/9639:-92180873503010/6243793 +qsub:3526953029/731,=1,-108468202939/365:0 +qsub:313486413069/844,-262666586523/625,-366626397895/982:417619607193537/527500 +qsub:-428607477029/682,=1,=2:0 +qsub:90255143123/14,=1,347531313509/64:0 +qsub:32303888109/19,818375118441/16,4032541865:-15032265040635/304 +qsub:292300807915/3,141298658917/2,331142787887/2:160705639079/6 +qsub:-319866639686/9,263653231334,940025135092/3:-2692745721692/9 +qsub:8034198041699/17592454670005017397,=1,=1:0 +qsub:640259140119/57494394354649546144,-8575402433581/98527174739603547922,8981144595803/52261736819163067566:278060246721630225656578041972191/2832380119564115796138164460514727156384 +qsub:1236159983468/2961715085662590789,914344518503/2225413786553289931,-5038738670790/9117790154416123369:42939515651941188118242991841/6591041583476387621705131100927045559 +qsub:544927281821/225573104564678752,1983999095212/528108855513999917,=2:-159755912219641308519411726567/119127154086392326185226159659663584 +qsub:236180252739/93711559633857505,=1,-875119448860/197150931692089343:0 +qsub:3448258604904/101878636218756661,-9369719313239/333311169679336117,-325685803073/239541171961239254:2103917334342722557318697252747/33957287403409359538552421651625337 +qsub:-7939222138274/86505941453702773,-7521663898635/32404928066636033,=2:393398694553935776247333587813/2803218810143866461870349953819509 +qsub:31222491771/28663266692274319,3403082415831/7352452962268472,-4014317624213/42643848690867324:-97313896958642034025767600177/210745320099903543783491148970568 +qsub:-294177603665/4628696580309847,=1,=2:0 +qsub:-9743813636414/8886484266786635,-857487733127/2872659401368146,=1:-20370606598428196700274910799/25527842574094742730786067528710 +qsub:-255869133971/251203098733934,=1,51860449406/2731920492095:0 +qsub:-2551627469690/620119144262383,795142214972/32216229353871,3950813535806/548061345549077:-575286725704502987095668266/19977900578283148512980734593 +qsub:195247370817/63337336480054,1748779495123/30608951696454,-5591675662514/14668720736915:-26196679492456802179448431/484672368225006676058382129 +qsub:-5602181260057/40083459443536,117096388229/5768970730471,2776946949919/9603782260822:-37012448044623646265634591/231240304305780581099185456 +qsub:1645392691271/1862974141789,-9156882237455/3971219830691,81994652595/616265197207:23593250912635096190105256/7398279855937023607846199 +qsub:-5034167196133/6608304488230,=1,=1:0 +qsub:-2111179317912/94974899629,-2734989223771/337151252491,341842794161/202199642400:-452031424253078525037833/32020906365124361225839 +qsub:-3760876499263/10213162407,9612839350222/220968981509,-431780312153/723158370431:-929214539099496136632221/2256792095060796932163 +qsub:3321533964667/20955327844,-462499260819/4621872673,-7406461174035/83827773626:2276684609255051253557/8804805192358146092 +qsub:532057790509/3873792604,5011839386945/38790613612,6678622123429/35927572362:76501363831601540858/9391674507174207853 +qsub:556360173467/244347911,=1,3477739385301/4086080128:0 +qsub:377956900679/9728280520,=1,1041480439146/9369959143:0 +qsub:1811463975309/425739298,=1,7893909438664/413369383:0 +qsub:-8501443522317/437865641,543359387910/555098507,-9540116747492/861158281:-4957057013263567681029/243058563585697987 +qsub:8568564545305/64448189,=1,8670374182673/15999622:0 +qsub:2886469384143/37100146,706817551959/70885648,2821141489561/36201922:89193109177047996825/1314933945052304 +qsub:-5397172720924/583973,=1,5493925869599/2184027:0 +qsub:632128111787/9181877,8269779184000/4428251,-5293123430135/8227357:-533816593733572799/296785810271 +qsub:7690264089163/217441,-454719683537/54069,3844686753380/33269:514679591744923064/11756817429 +qsub:194395407442/487085,7382213747658/754049,=1:-3449181920691764272/367285957165 +qsub:-6820161889575/40973,1260560268388/12497,3951119679544/19667:-136880499010680299/512039581 +qsub:7733127302799/541,-6375441080647/51092,=2:398550053779236535/27640772 +qsub:8552562777105/6802,4122196848132/6401,6588275470270/5237:26705771375255241/43539602 +qsub:892706337045/1181,7525927198633/6084,3376981309819/6148:-3456894667003793/7185204 +qsub:-6525943779397/22,1169543393537/155,=1:-1037251240464349/3410 +qsub:5679159008921/101,2475493569771/410,-6099782991203/439:2078430343110739/41410 +qsub:3105196603053/35,-1561253366581/11,1543062844359/70:88801030463918/385 +qsub:4851198644302/41,5582000284949/83,1538859614246/61:173787475794157/3403 +qsub:7388598539023,1819068317039/2,-1736481275601/2:12958128761007/2 +qsub:-3766516642396/3,-2830365650207/3,2537215743415/9:-936150992189/3 +qsub:-3499529401917/34680274552088347393,49898319429097/81175729919276761270,=2:-2014564271063470770932585857648711/2815196600566690542230200403343687869110 +qsub:85499989069177/86185277165079792548,-54755717014977/95062349548332003740,=2:802935405911321108881332428232086/512060933986668223303815291051772508095 +qsub:10480741720249/6956596051054816346,=1,59792433694419/619860836842181132:0 +qsub:5440922563791/8096299805235361768,21427106892442/4734770642360508925,=2:-147718760937640942166837597622781/38334122629577497138638724698967779400 +qsub:36141945949905/51170764877853868,68289830259221/944862420318148725,=2:30654723677491802840116592104297/48349332752019923728004548840518300 +qsub:-65660705848034/432686937944828595,-14162742932711/370354589759953089,=2:-6063236635081033520164429735327/53415864465682424679265419115259985 +qsub:-10234488359092/9219723369459949,11490568299383/78007645593504592,=1:-904308201825094205011706861931/719208913074983700054297291585808 +qsub:8824638624671/49117783640687736,71425056890483/80617302142742478,31478624534929/82599814978820418:-466136988760823218273617123625/659957200723862808591316843474968 +qsub:2271907634573/5997198598392443,=1,=1:0 +qsub:87118386941689/6769664747763328,-92703763358616/5951838412401733,72544030367331/9826030071433516:1146087960619838557486271181085/40291950684819664403468341047424 +qsub:-38735368831/390121272239902,18518285294580/100122679213001,-3887528092655/74244322705899:-7228255307730681475045702991/39059986994643540045829365902 +qsub:33507643620217/383472784483096,94120308754159/452308027073903,8479974951625/419952955125076:-271906502553380052184822069/2252569072546560464977223944 +qsub:10914633574213/46775840995232,=1,=1:0 +qsub:16227980458171/44733418409925,=1,14382677933809/3568384653206:0 +qsub:19887329250905/3446066449222,-41404484338255/2669125822468,50077337796229/2478834856350:97882194184456020343960575/4598992472779525554359948 +qsub:-23925661872806/841256858717,91800998586059/100553852929,76785865874845/4626636784081:-79634037182778870157375077/84591618446941749632093 +qsub:29336106782491/175641800187,14997313674741/788809675295,41848999082110/169597375583:20506449693715551470283278/138547951373736740280165 +qsub:-6749631331552/100780901939,22080836367893/122987967423,28833497035036/165078850509:-3055450043045906849075023/12394838284534289533197 +qsub:25051511362687/10396488145,38509696040707/88706839049,-60514064785671/63433114810:1821874788029306610246148/922239600553351574105 +qsub:48606586904983/42071764992,29823112345620/42059865901,-21691164849293/4231585639:789675553193949088149643/1769532793781906337792 +qsub:-77589654827242/9817530799,8253947272810/520292243,=1:-1178666768036851921932/49592088544983419 +qsub:-13743493332261/1526967682,37506929991611/658645334,86046505206712/7222464595:-16580989426095086858969/251432534729523947 +qsub:-51679389983753/476057441,=1,66423598858706/714202649:0 +qsub:-27413822608864/942542701,-17319180355605/124314974,69101034128319/135803866:12916118386616536859569/117172171368704774 +qsub:16033466371942/6275041,3173224097293/838266,29304504765697/93980195:-6471801590959231441/5260153518906 +qsub:-14788927543191/5343139,16116445186754/71171839,-4194013841977/34472148:-1138667576905362979055/380281028662621 +qsub:-11863377566581/698789,=1,-4578191177718/4105669:0 +qsub:11442715386293/9531887,=1,35378701532975/8123906:0 +qsub:-15768066912479/362615,92363606714861/652333,67857319926071/827985:-3979859967466135002/21504157345 +qsub:-846557698591/239267,-53144962049294/166663,=2:1796392255561165095/5696708003 +qsub:27268730445959/36577,-13465608951811/44542,=1:1707135370154296725/1629212734 +qsub:-9770756513988/9073,7801336502379/467,4503088681454/9263:-75344469378117063/4237091 +qsub:-7026119147779/830,7101024857299/2048,=1:-10141671323104781/849920 +qsub:21638871622139/2468,-42476176597401/7406,-16930478429705/1639:132544343537973551/9139004 +qsub:24211191920307/215,-80284684935585/301,32429769785659/56:13276785305118/35 +qsub:28102057542845/404,10141824152597/778,49924151629427/38:8883051905342111/157156 +qsub:69683068555423/53,19160487574994/75,34686281737182/41:4210724300182043/3975 +qsub:4481580939807,28880719200344/47,12531106213795/71:181753584970585/47 +qsub:-4015047513343,-99632851064851/5,84319873837035/7:79557613498136/5 +qsub:54919395403009,=1,-97138101140295:0 +qsub:210307390461968/47213629337306710429,115035466737199/13799438784982683745,53333082063959/13664786811438045265:-2529117926464810402732988541238211/651521587857026504089626304754000276605 +qsub:-297705233604298/34583872960377931369,77978617195104/5299999273198438663,74378398780959/5075493209379777979:-4274640112431569633737006160990950/183294501554390171572563143412570119647 +qsub:504589485072677/8294597886664545269,246812476335976/1300669888373460411,681100309448968/2603298518001254955:-1390905895394928956894286988007297/10788533707350714724434632367288845559 +qsub:-78507045905186/4052782705070927105,-26333160825061/378849069158294234,245855933356429/7915638278155738995:76980257498111295165827733680881/1535392955316954446563765566755812570 +qsub:158467575315099/42867668947782517,394831131302747/679471751533163594,-48561231318802/281924646264500261:90748750733599226955741824631607/29127370104093594835779192094086098 +qsub:113675246712051/200230549051637699,388686281013415/708939569436428256,=1:2762013003465965719694013380971/141951359232687658393740425918422944 +qsub:73765282645495/1035056942801718,922427291192222/42055305183418997,-56658710176289/49777804321460907:2147456701619161856688029631119/43529635611742911300567485436846 +qsub:11558926182346/2193559666056113,-471907499361325/65178860043302296,906292398921179/61879479804047118:1788554888598395874379208496141/142973718470504311324402957735448 +qsub:272316495707495/5727398323662772,165581996805511/2159650095677579,=2:-360245704923343561937821381887/12369176337681911126512437388988 +qsub:-342373342517849/1018510666353060,=1,349084421810221/2519615499139835:0 +qsub:107181823655878/330213883798891,603343425900400/335568866158937,=2:-163265492894049375913454174714/110809498576332828976950338867 +qsub:186420967060580/27505382732689,107841057765734/938888436801099,150317703871619/56186192325509:172062280782312586790437698694/25824485797510315886178425211 +qsub:277369102524627/35009202732584,-58922735852011/29409493631158,-114354072702623/27524533096262:5110061429589788410990577245/514801462397924199102126136 +qsub:-208415718182346/82232835696833,-149287320962885/17528744477017,144393102539827/5550994994610:8623053867348966063892901323/1441438364550307853348187161 +qsub:885772499510025/2385708677677,1981679910892/945475145135,-927158264975185/51617668049:832748171571039374752920491/2255628258276490509651395 +qsub:199709343421874/120107420805,250421330523511/911998437151,-85756219123893/3387032230561:152057148961466103844594619/109537780064397502326555 +qsub:229005499534863/114476975336,=1,7933977177406/971528526457:0 +qsub:913313238746453/105012167131,998890143666531/308838539768,-340536941048242/129794732609:177170708293018948806450343/32431804354611205965608 +qsub:202747896046111/4130383286,-326610886734874/924106823,400325691919789/22798999151:1536388861680468580631317/3816915376197760378 +qsub:311867860118047/14615054044,78891545894795/49519747784,=2:3572653392028586160839217/180933447527102309624 +qsub:-187714403734023/740833429,506207386211644/6706938891,-756195691891397/5384742450:-1634004388516894022835769/4968724536712987239 +qsub:509320078163086/994171477,-149792211533821/1161942848,919509848550973/7287718870:740719966348074014332545/1155170437385746496 +qsub:744782913412383/35221159,-843622816486697/241699112,=2:209726742160051637325719/8512922853910808 +qsub:110124296861427/126487978,781814771935103/735468241,103648920994391/217349966:-17897246768566789251827/93027890687306698 +qsub:55559598357120/4133243,136581368630879/43479449,-46084945523102/26713943:1851176737404882616283/179711128223107 +qsub:245122390741101/24043876,-76258811060014/21938089,448115170340604/6879827:7211074221005454870253/527476691592964 +qsub:100716567078550/981447,=1,-106552246729921/451809:0 +qsub:-896329574019135/7303813,-344467277086635/1213327,261333607789282/121043:1428383703404051827110/8861913515851 +qsub:76900938369059/75326,993229733624034/890555,-908067780499933/8580:-6331507745706647339/67081945930 +qsub:995595550040069/769920,-34334285476045/592726,=2:308275010533383252247/228175800960 +qsub:10750797928613/490,364135307090702/81553,469882435848719/39098:698333522997732009/39960970 +qsub:318012047587094/63457,344774587461563/88455,=2:6251394672767996479/5613088935 +qsub:-161244027390189/3742,967621707258700/3013,=2:-4106668683088694857/11274646 +qsub:707755729590189/3985,-311896862542891/2746,890911807982825/5104:3186406230688079629/10942810 +qsub:-62494041004924/7,-6009036767325/88,277826134449449/209:-5457412351062037/616 +qsub:313000944443410/187,-424215294038191/492,-69562914630308/101:233324724651299437/92004 +qsub:-214477481502137/44,812058199759953/13,-233671238320360/3:-38518768048965713/572 +qsub:54243114068304/29,862438291931992/63,26733981451778:-21593394279724616/1827 +qsub:266687619713649/8,-362755079043871/2,389177566612001/4:1717707935889133/8 +qsub:653323126774499/9,703678334484790/3,-319996079506951/4:-1457711876679871/9 +qsub:2559305963434670/8990269372406324049,=1,4982250095086138/44081334052072166999:0 +qsub:-1992239658448600/48178503938440461483,=1,-140689209800518/56784446808413335831:0 +qsub:939937733606495/990699059564945896,1384063287837877/148639317667949967,1401228942153371/4899174789530501904:-1231478494265723021017590198267127/147256832228013279266729677589985432 +qsub:2427308943763117/3926876732707845738,-3053828283650605/3709355702828503657,-6851889315460370/7456794982130606687:20995759505827045845208479606590359/14566182602774409222023359782524863866 +qsub:1132187368153827/166386612794510246,3559319078115267/192456340011573829,-9701789017274666/34504738221262233:-374326408180256253543105561132099/32022158525354344242032513725951934 +qsub:1011380512372054/229809286711122957,=1,785057330967873/261864117017722910:0 +qsub:-6373636813888041/82626527312705989,2824358117452821/9660944401937999,8376921479245765/84777299790282297:-294942254029695997688528161214928/798250286493264100581508493976011 +qsub:-9564803757424938/80601591821040757,-5966553227630720/32402706800195057,3062333169701829/13649400405257704:170988156078760300221549229123574/2611709747406183624616884346938149 +qsub:-6645498550927964/1641651956201489,-2448344965334987/7285796471405420,97763428336761/717874275284599:-44398419591282543726427305969237/11960742029768613657228526670380 +qsub:9428078639060/796311207574343,487570664734529/270542984787885,=2:-385707284276751727768550801347/215436410917207812839223234555 +qsub:-8945032146859492/173832543857525,=1,3904355716222363/11348996463718:0 +qsub:-314682518932207/411979868553284,2079866721697896/66512597834021,4675528081388171/426553668427461:-877793570440583492839563904811/27401851312797413669226474964 +qsub:-8416034028506899/32609965027765,-2867068576526460/10471107007973,=2:5369813117494012224678656173/341462433331984537021370345 +qsub:2553878719400981/21754385300349,84746758238377/1863679896278,-358102168359771/6286290072209:2915998795206632613088155145/40543210540146072197201022 +qsub:4236427671394109/2859515833221,=1,=2:0 +qsub:5583901594900219/6147672416839,1662784468995713/977705344691,6565243303664406/3132796116919:-4762843781630684936693623878/6010612179352927527651749 +qsub:5880633088314980/144288094133,445227880160405/385441741948,=1:129552963472585426795492775/3271450255587089340652 +qsub:7123796066897691/646623152591,1738054940928918/811478311493,-465948486952257/36744411995:4656939438506791528261936125/524720664036825168028363 +qsub:-2868399842871272/39606511493,-7967653324405171/45882725248,-4382209264799369/87703483877:183960951073424117991854847/1817254684865073275264 +qsub:2456186256319560/3308343473,=1,3527461933566325/44562489087:0 +qsub:674305784927060/4912146059,-9009832420557345/1095083558,555087666246961/159683002:44996033995029100460532835/5379210383705397922 +qsub:9556395264243127/5642678959,2704206989021393/1653137405,3456993987111567/2767730221:539062590553413975895548/9328123651529361395 +qsub:1913172323114056/317852309,1923331312586217/68059942,5111100924241691/235015288:-481124901330381924280301/21633009715106078 +qsub:7396974207537751/994805053,=1,=1:0 +qsub:284214608834666/15371405,8605121290252485/36320753,7299109191726065/1345108:-17421416545731139652561/79757286323995 +qsub:7309254006136367/43026806,=1,=2:0 +qsub:3445238551293254/7474347,=1,-935490243888754/754065:0 +qsub:-4928287873457776/7482701,5635600141645415/1697376,-9526446027760/22031:-50534668372988554461691/12700957092576 +qsub:-8478337945368580/589969,6645220551921478/525883,=1:-8379087917520827410322/310254667627 +qsub:1719300936213092/194297,902706986884743/48626,2385654314953825/180074:-91790532106447099079/9447885922 +qsub:-2129417266022053/3839,6573034386134051/14296,9786617326073399/94956:-55676028243419891477/54882344 +qsub:-2187293709879460/39491,3573469347555406/99807,4017132988613391/36830:-21142770665073517798/231851661 +qsub:4464053162985503/909,4551500989123885/3361,84727686825382/35:10866368281680664118/3055149 +qsub:2535331877045977/3627,6763176539554039/4483,3870940332291032/173:-13164148504165384562/16259841 +qsub:2507736196654456/51,3033138651383092/821,=2:1904161346232770684/41871 +qsub:684175263169205/133,=1,2378871296865361/491:0 +qsub:-646739283957087/8,=1,1100407856892355/16:0 +qsub:4793571136533963/92,-5722502959595165/61,4757322618112904/15:818878111611326923/5612 +qsub:-7552421230993378,4948198001592823/4,5729503250754923/5:-35157882925566335/4 +qsub:-2755491483441304,=1,-7933615614234907/9:0 +qsub:321721693263421/1424970458268329442,4783029016817033/9976530684162778611,-1284537047056835/71620015235724957994:-400667633933462179077276150388595/1579584611215498321716283384428796118 +qsub:-47606652409415837/99944870827944430499,23322967894703462/17256392723432667009,17445922268336980/1262651123373099837:-3152530103785264263460897588705709071/1724687941699758103837340929139210707491 +qsub:-35800247390542268/3022381832969706807,27658822050080425/3538855927509428196,7414524545924163/4386817849214572582:-70095812989943154324914458022980501/3565257954933885823399042050112976724 +qsub:11270912894283697/4254771338147418239,21165198074272866/1790561357737218389,=2:-69871817037702583386330221699898841/7618429144094642739542804241664796971 +qsub:-22475320938058069/200115960226568483,15533995839026021/419448235219902685,-7677187468882297/691145254573545404:-12535834196951596319645500834511408/83938286356370387266153122748076855 +qsub:6144083459003009/341129592319435505,=1,28739569462221666/606069168271474349:0 +qsub:22546360696472435/24894286772021269,84274062567114482/52430302346827669,-1685672888973312/2330511345390725:-915830172852329009982850908113643/1305214982165707736650909145691961 +qsub:4376832304770209/939333180215946,3715739686394692/26867721681796733,88210818404099477/4648321047973775:114105194635987182911079063768565/25237742452519050348798217304418 +qsub:9647062281850006/4819913902499121,26298077512843496/1999760481189285,=2:-35820885167446167638178828727102/3212891114984188905357249039495 +qsub:-59102942672072861/9022665222289159,37341501938137229/6463207427444592,843867142853825/330321510152954:-718914448947247239109480525418123/58315356880045303166891874778128 +qsub:-48186053317977182/524586203313577,=1,-88203767474302754/222044585954625:0 +qsub:2980158547616795/16459590834659,=1,55614737163455091/802181444522069:0 +qsub:27674141753240653/30123979153216,-69911536707649590/61364291872711,15121999849118525/43270921417874:3804217786223168944052276101723/1848536649125408180638288576 +qsub:-8139585494164199/22694171735055,16416172833245775/23356807697711,-82721251840807344/24795330336689:-562666178636295181890388591114/530063405074508024821959105 +qsub:40963317287207743/9100834089657,-89978521261181858/4614790398485,=2:1007916716937791923695301312061/41998441775154099246969645 +qsub:-22418658716107103/2534171344870,-19948846211000086/637313996471,34428844071591534/7978524432977:36266069449253256094105625307/1615062867541388503953770 +qsub:8499094378194009/144881993257,18142016047956879/328774983548,51933573865337015/728907876721:165838167635160267022399029/47633574949471621935836 +qsub:10952289218891361/410721990889,11230753555935868/494713123343,3356713875262630/76566376963:805523747555915071545833171/203189558938352379221927 +qsub:-48383763418441148/36254620229,7147640525044487/65513778698,-83702869612157193/80045858746:-3428938161941039381724192827/2375177166462740081842 +qsub:-35618330302934381/40720985765,-70406046479991145/43883735712,=1:1303938222964954498988736653/1786988977243374139680 +qsub:19345365507179985/787013497,20346629715849781/1124536845,=1:5741504087980952707553168/885025674888796965 +qsub:25916947948395837/4727212922,65968479175889910/4243635367,38561855794849199/1001864541:-201864970286444028592649841/20060567943138612374 +qsub:-83872784258426507/338189336,72676607354297993/258443836,-31045469397994216/211178075:-11563714420907729197990875/21850737322533224 +qsub:29002323373127602/104867985,31657958092331122/399470525,25010437022653087/448628233:1653133413945169069200376/8378333804728425 +qsub:17927870354086417/3556758,1245879275137696/8208269,-3178672357614557/3197484:142725491384586358632605/29194826431902 +qsub:-62585597691019581/32367872,61984767454961662/87347591,-3097688625515242/23912601:-7473016208537687574702635/2827255644996352 +qsub:-64134232347614188/1287231,5681700507230407/3441090,-22197438767027251/8198005:-1333364483126750936947/25903378490 +qsub:80521535865700778/4914387,29629877920205801/5735623,-31675469441529533/5832635:316228486243991867655707/28187071108101 +qsub:-12089212581249183/367213,39065393509910584/485831,61520933914433223/513745:-20218634584515667108465/178403459003 +qsub:35626200118349978/22677,3226283532016027/401890,70294093126508565/985048:14244651133908145214141/9113659530 +qsub:-42445465189342283/64064,52962797531106583/66292,30509808145126571/40195:-1551700859841172689487/1061732672 +qsub:94842682855165703/29546,-21781294090030679/19071,-98420376085320606/98821:2452294919914911563647/563471766 +qsub:21298039427969457/4529,41390344046065517/4944,-47466303948648638/1437:-82159361252749731085/22391376 +qsub:91816424325919179/1700,99837657326420362/9975,=2:5969158521569033561/135660 +qsub:84285557657486063/501,22158640591353121/907,1409871428669941/18:65345521859071945520/454407 +qsub:-74339750859264619/932,17864819649304693/421,6794209676711141/199:-47947047024902378475/392372 +qsub:-78194010431589383/58,62126554703583997/90,93510406253215651/10:-2660200277912729074/1305 +qsub:71106157246341874/49,-1886317442316576/19,=1:1443446542354007830/931 +qsub:-39663070419423940/7,33868806617110099/6,-19327938437654750:-475060068836314333/42 +qsub:52313046276155719/7,90139156444699943/4,49168703277366491/5:-421721910008276725/28 +qsub:31764659627457502/35459829258840257855,125864014273474351/30437232401502771513,-438810788001077539/21929003917091975594:-3496288128734077196451731372945036579/1079299064068928704074589544922068484615 +qsub:40163813719117127/12253004736518941871,-39840230360733540/9868332108049144213,=1:884512383820142074541633838441289391/120916720061468118490436389825843042523 +qsub:616147121341955963/2895479716224140287,529082239113522161/2438652913112833925,=2:-29377919201006207047359381264955432/7061070044829121412952661959332836475 +qsub:150980224993479452/371034742997570395,=1,97628589854512901/1461818398649717323:0 +qsub:828501131055695330/861555563679753833,-968363844399576751/400987885360876602,4318808141772773/272140134925135118:1166518174369888540148356746507605243/345473343600842551070257384449515466 +qsub:997737191667232852/878873090216825721,-215309181373978527/178339642478000642,44112408043295555/167730641087926307:367165539635142230228004432374783951/156737912692804302819698495840112882 +qsub:-874288368924506038/33067894686016771,172933382638695999/15746943377378890,=1:-19485912325748182437244211303337049/520718265229834381226960561364190 +qsub:113445092902670316/24432013651972039,789628644660942395/81838347379866874,-253719530063131225/7192012672525274:-10008058904834319340307600738181221/1999475620439737613479475390336086 +qsub:469761512155527237/7409272817081662,644368433953482322/2796535736601265,-743279324916258749/3941987500967613:-3460596665454235362140115831224359/20720296215197195433635837502430 +qsub:8261654401496347/568538524395616,-778532546601001661/1096269337597285,-306562427101658699/2779592495957628:451682743636680727605399921736071/623271351537719810570227502560 +qsub:461974279165354118/107945644045613,=1,-4203580865175374/431296441354377:0 +qsub:999567545272721386/528172429856767,-306849659405574946/410631585483429,58620020684173871/34198792094556:572523536122080656350523300672176/216884282280719425778922014043 +qsub:838953299025019215/26401444256374,855300290662954227/88914568043701,-233880940259636371/26804240414928:52014007245249037196988469721817/2347473011785344971879800174 +qsub:-84648269690239765/7748568048141,86620759660993385/4650491023414,740584294215236889/18424376078527:-1064842868956861583564451404995/36034646152192259510173374 +qsub:144119271324804795/7593869059598,-862271465889805512/4817698847465,30615084012712336/133690674221:7242299853153814002244162498851/36584974216225407996219070 +qsub:-514146414782774671/7780370709815,270344156048491787/2722967818331,219882280138478/11635197457:-3503381894653098523553024083506/21185699057511364438618765 +qsub:27542214966861168/383672867,287936038111037884/394023185191,231925740783907885/236839247989:10741798023203186757550669660/151176005126702912597 +qsub:-202417103371781662/185891935843,-75016780652064931/26395556610,539072986943728448/794028543247:8602102465239973123041336013/4906721115886394572230 +qsub:146159764562795268/26252940211,5977449519968967/15598248256,=2:2122910667826975950339620571/409499878861103022016 +qsub:92905251016109811/18087473051,861913285707088178/49029015865,575397421398561364/35847357407:-11034780301515165605154539563/886811003175238954115 +qsub:43007028131858062/2453663475,=1,=1:0 +qsub:-99491213767410734/5448033345,607696219524202834/7914352487,932551377887323725/7825731284:-4098157802713052856358895188/43117656253259679015 +qsub:-693848599167966481/337019784,451296938813827771/190206672,138269118881809795/286360117:-11836276239937430206424279/2670975479699952 +qsub:885539919667431975/906601532,=1,679476927167924457/542648272:0 +qsub:-4563620543259161/50948374,877797754583710364/85678397,871721618807362291/51516582:-45113371989553804002793053/4365175014076478 +qsub:267267974303681854/59860387,643485159739694623/65130620,-346322759520229537/79392976:-21111941818232071960829621/3898744118749940 +qsub:-292697070229916239/6469138,451527711321523043/1713209,-690729392819742293/7199521:-3422446330354619505247885/11082985443842 +qsub:109167064549424855/933921,-974615071639008317/9073576,-141072367242930847/2470173:1900749139206286464552437/8474003171496 +qsub:-442186452566118477/433250,243224124572764479/694402,188939975597921698/84623:-103108002251492003298126/75212416625 +qsub:504154364259376845/839918,-816470041468996533/562156,932823927594899937/948502:484590642542575439841057/236082471604 +qsub:58385990303797466/4715,23346464312197309/7769,-83189886883209658/1309:343522179438192201419/36630835 +qsub:-31667255028373761/6166,=1,=2:0 +qsub:264267843061809424/1507,=1,780372905769447077/8088:0 +qsub:942357538510813910/7893,-485153351303873623/1639,-20022501530390273/127:5373839407460698504829/12936627 +qsub:-42475017998288473/153,147697152269679268/85,=2:-1541649460418555777/765 +qsub:75774035481832811/18,340160682114414248/343,=1:19867601892209197709/6174 +qsub:74102130227248217,144497961842228027/6,-998137158213905035/43:300114819521261275/6 +qsub:821735055204387778/45,=1,=2:0 +qsub:-57815587457821904,51008807915322849,-147281045102225347/3:-108824395373144753 +qsub:454222567912329981,22540753838160371,18269107333524567:431681814074169610 +qsub:3210043239752875243/72149763518252375009,3261470914498557412/93230677190142956657,-4064987413615246181/33645849737189283754:63960149849071755625510420647536825943/6726571311915340136410812262723596984913 +qsub:9804073501780182793/38766744515505567422,=1,=2:0 +qsub:257063569033647893/47627381308050634,=1,=2:0 +qsub:1552551009049725266/1621244061592046727,8268958120903544781/425547204494853721,213262382085564484/2263543462839420049:-12745315507331426593439792125381167001/689915878214377929840178814861821167 +qsub:2934623879325117949/357068238595800494,9728045374534083071/521016049535609725,-804894226755345532/55644798067314489:-1944589886386070523678697500282383049/186038283087822502456659294746204150 +qsub:-3413740827484155595/35201790823660144,=1,=2:0 +qsub:5742873913112182553/61766168241911339,3984407637182474330/61987278332263327,448424158078834703/1851056518481567:109883531216609955256617440787705961/3828716662328761978044444335164853 +qsub:-5538305489874918085/47200167153328601,2292592129732611685/3752960621013977,-7047966941457980339/13001528931023405:-128995774148430971478100961252376730/177140368631719625362323294856177 +qsub:2647084994940083287/8257587043096855,8517457859612680059/8568918876347054,4335833152174662442/3522517188924281:-47650993081224012631875300587027947/70758593486671494919389915915170 +qsub:-2174815554300743477/1055854216058324,1106694427573230889/1439497035446960,1663682898924590039/6228481982913678:-1074787130075326655568302535462489/379974753470032846369692123760 +qsub:-673256166894368145/58357219332101,=1,-9850462360230406692/697272419401589:0 +qsub:-7350812074670262181/353785488987714,-9161255025310493969/644044224968076,1118265777181240006/160586465643975:-82951609813686583656885009057605/12658527836669113872289234348 +qsub:7934622905365481543/24281747034726,=1,=1:0 +qsub:-4406459203030692110/40412972154809,-328394051086803323/17512120371320,3271184521881465212/24850026200233:-63895064332408368266126902654893/707716832937818605603677880 +qsub:460352415792245815/1067976849408,-3006172239763431339/8488209165760,=2:111220155509497494992102376433/141643920030694887966720 +qsub:-8685801779232576472/5545683151339,-9379688590927802729/4661614228739,-1045039004738707304/2306882972179:11526923821437860566165526575323/25851835486360019500131521 +qsub:-1099655652591638878/2758191281,1569957311481795188/313204152767,4679104365556960009/172279461301:-348746959573478031289777831254/863876963334931424527 +qsub:7376706437670791929/273943068790,6472278838608399241/616870830740,-2499089563512667949/302238168048:277743910121812542672687030907/16898748841995226660460 +qsub:6865154371318865863/58818463172,7515040679922839317/98572518047,3436930220114417551/26193376471:234692409694146480303501596037/5797884022518774865084 +qsub:1254860182105767734/5016375113,=1,2599681765080769493/46385850085:0 +qsub:4216394462161257127/7652601313,154087255858661733/228011378,=1:-31111774998800660662723489/249268595808819902 +qsub:-8218805797153900006/3225230965,162240217381132332/3267619919,470501772660009028/17345893:-27379195706038716372068879894/10538828944609591835 +qsub:2993035686422028942/288390385,572871629063315065/300592553,-6417147951768049106/301422311:734473568540558494144018901/86688002087802905 +qsub:-413167836327757837/385147459,=1,4223408874712268336/273008947:0 +qsub:3297442160967679169/69599199,9036377343550866545/45162311,=1:-480004516594753739709297896/3143260670588889 +qsub:368876976532110737/16510688,6518851187565474853/50791699,-1104665290033392205/7386446:-88894829716274002481356701/838605895178912 +qsub:-2062139936169240279/2037445,=1,252666902590280893/289459:0 +qsub:7094134562467803247/3012150,=1,9333233846214751643/9878490:0 +qsub:6076762026375939088/714143,-1173122156103211995/424924,=2:3419939003221785664774597/303456500132 +qsub:-5491034419852196360/519619,715863173404931/44,-3750063252517296119/253359:-613581620774993481129/22863236 +qsub:-5533397069224776206/61493,=1,1084791347634995311/940:0 +qsub:2610588148432509992/29651,=1,-1360998239306614670/89179:0 +qsub:3100610288438845270/1619,9307237399334731519/4955,9392825838002497590/8501:295106629691547983589/8022145 +qsub:3368071818378567709/3813,-3776828995456884473/1454,=2:19298225383599537944435/5544102 +qsub:1898435934717526073/873,4308565906715352586/295,=1:-3201339435820832616043/257535 +qsub:1300690053258900179/243,4943814111367222345/439,=2:-630343895681577851254/106677 +qsub:251833946462887840,-869006720570670337/8,-725021352968265541/99:2883678292273773057/8 +qsub:626008792964496823,3012267373701938935/3,-1881182483045937043/16:-1134240994808448466/3 +qsub:8909701403779037643/2,4263103087268485691/6,-4865092756990722784/5:11233000562034313619/3 +qsub:1563790691172262117/4,4953143499970208620,6661387731632814693/7:-18248783308708572363/4 +qsub:-5421505027803143917/29277316475549977927,-24881453522128465658/13193126736034804489,=2:656935586207185980835950093591652887553/386259346752930686132136354247710514303 +qsub:43002545629357992251/65752963968398524190,31308403854434073804/48746580693008293241,1726565764440537923/12956415087885593469:37606709977597341370212061004874356731/3205232163890005466586601709015151999790 +qsub:-59751660477015957831/4286192839388269021,11974517458086843067/1241046631081301617,=2:-125479687920496057578907990371068840134/5319365183487609778049805813238306957 +qsub:-49461165347668030699/208457055709777407,52105901053159218571/6869817428870197111,-36441364311401291685/8657876687713166642:-350651018476287040134985140793799735986/1432061914485994468255463550024471177 +qsub:-7581437680655861221/49307213191711325,-32918301279907528476/380204896359543505,-62274249636519514774/637143890847264601:-251878005702543064394570301716545781/3749368776266504127275465347738825 +qsub:88463778015782255603/611086942952818386,28997739596524666645/367897090074176869,-81867305184567355447/440111079789875727:14825426466392080175430281904511312037/224817108094666407622918422599113434 +qsub:27845231969167468634/7852896265044091,=1,16619399537337723559/18069459979251540:0 +qsub:-37414950961700930/7204075375675961,-11821234740040951665/4482466888001314,-23524535630982071810/37803027645100347:84993354822012222699375201588403045/32292029330133121955123006212754 +qsub:61321523796737027359/5452182446309742,=1,48591916429664483052/1740855337030687:0 +qsub:5363425484789562617/1756465539350314,-40936806728242699939/5412202567319265,-3599607803259833000/278745158021617:100932035487606021271304492855347351/9506347301479586913476715999210 +qsub:33564895484794792189/136772489172128,4571443108763064643/186748602496254,=2:2821474835811978960085724681544851/12771035606414468103340604256 +qsub:-94258077286598647991/474232208430175,98462449436025151993/228502005075011,=1:-68232224497993790090895883442041676/108363010497445522187430856925 +qsub:34061962820425097482/24899834941843,1855142409964422527/902056706202,14293533188899209595/42267239349684:-15466917813159310212214440113897/22461063092612364807410286 +qsub:-73929207028429916638/21372812626357,-66185303844781311744/59463089468249,-6818430024504790355/20557416897032:-2981492954155214407839662609790254/1270893469389188176252038893 +qsub:57077240876377553179/935097318175,=1,42604601978623894017/8385603091453:0 +qsub:7077386151750173156/1231852917417,40471318485412028642/1706097941603,38461201962265231448/5304200381911:-37779997802536821420601638448646/2101661726762794047599451 +qsub:-37489576712437584437/499625554669,60955914069456492767/885230799387,50229679483949978567/539847952020:-63642060339139483486584581919242/442283929153812140187903 +qsub:3147094074418762156/310106471081,=1,-3700969786876628910/15570398827:0 +qsub:12329606272247487589/40674617665,-77828250896400397795/50092227757,-22437013421232931285/13509778618:343931981299121509240432077868/185225655636734138855 +qsub:49832350382626108453/8964749413,=1,2620089939108140247/2413101797:0 +qsub:50952962315511975411/6309290837,-16012147625149581763/1214855186,49964518797252328078/9043690267:162925766803109858544836037077/7664874693311730682 +qsub:348630015993655559/4656837405,26166625137687604221/1177967663,47073618836385117951/1978562296:-121443043818605211479526497888/5485603874938834515 +qsub:17078935151701402183/29370735,-53438577236731723122/493863599,27771088952431040471/715856601:10004194671903945161352471287/14505136892375265 +qsub:-82659381362807119713/632881567,29388144547912909553/176840848,11667678020670746965/17707269:-33216770068059835487916346175/111919312991848816 +qsub:21029165726302721351/47748016,59722770221895701365/6011409,7537524523228744530/7443449:-2725228872009811783253348281/287032853114544 +qsub:-1377712971222794171/46200083,67781278282353575281/46204616,=1:-3195157381284400868447041659/2134657094183128 +qsub:99498503205328073847/8536940,67748617769009531540/8445211,-11519205096064985138/4045881:261919968776203677676409117/72096259594340 +qsub:4104972121385207947/636151,13294784517447053191/977547,13689829596826434020/1075639:-4444687283214714461541832/621867501597 +qsub:82730974983634629799/122118,-16204666767231941581/177953,=2:16701106687543563518610005/21731264454 +qsub:-10650367180325946520/50547,1632386827276484871/118112,-75101239763743917691/649672:-1340448425361002676144677/5970207264 +qsub:77412383597894642193/47240,80267467079572070186/72803,-25049349718395484959/22130:1844018618238539039990339/3439213720 +qsub:35230904033764128322/11419,95208581964982041789/24788,1540889192878250023/4339:-213883148269184722342855/283054172 +qsub:-83663795012357893939/1322,-18656774262532233660/4619,54887210177965383636/8713:-361778813587013499205721/6106318 +qsub:39695783291112421139/8771,=1,27510059665458841174/5277:0 +qsub:19248997287659952171/173,73630829417088216857/778,-16684093916667265360/351:2237586400643181272777/134594 +qsub:88156024379250020383/629,-6327178680410193049/304,=1:30779226801270017624253/191216 +qsub:-11930537715494417409/2,80328608387065532851/43,41042034234564284791/75:-673670338540391014289/86 +qsub:36406323599126203370/21,48085922416521160270/63,=1:61133048380857449840/63 +qsub:-13809041632683030117/5,28242141662062188361/7,=2:-237873999739092152624/35 +qsub:7450923073218275163/2,73871343095222710643/8,-1203953812110244763/4:-44067650802349609991/8 Index: contrib/isl/imath/tests/qsubz.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qsubz.t @@ -0,0 +1,800 @@ +qsubz:1/89666066690010668869,8,0:-717328533520085350951/89666066690010668869 +qsubz:-7/92370362169890168582,0,3/10759595446182824504:-7/92370362169890168582 +qsubz:0,-6,=1:6 +qsubz:6/6514124205427226147,7,1/7791165451225637150:-45598869437990583023/6514124205427226147 +qsubz:8/927453510429432507,1,-7/939604332333807555:-927453510429432499/927453510429432507 +qsubz:6/791634116823984509,1,3/166448493180216857:-791634116823984503/791634116823984509 +qsubz:9/28379125138664429,2,2/1928364957970427:-56758250277328849/28379125138664429 +qsubz:1/4792771676887137,4,1/7102881482139131:-19171086707548547/4792771676887137 +qsubz:1/6412666850016412,5,2/3998647479596483:-32063334250082059/6412666850016412 +qsubz:1/2202724091118898,7,8/2921444666229659:-15419068637832285/2202724091118898 +qsubz:0,-5,=1:5 +qsubz:1/52166421933102,8,-4/458542817737975:-417331375464815/52166421933102 +qsubz:3/70257684761911,9,2/38216141537789:-632319162857196/70257684761911 +qsubz:0,8,5/16844906665344:-8 +qsubz:1/888589420311,-7,=1:6220125942178/888589420311 +qsubz:-3/9029660826470,1,2/1660505018071:-9029660826473/9029660826470 +qsubz:4/175194964803,2,0:-350389929602/175194964803 +qsubz:0,3,1/28737296870:-3 +qsubz:-1/7337600358,1,4/48392570781:-7337600359/7337600358 +qsubz:1/627219895,8,7/75038497999:-5017759159/627219895 +qsubz:5/6927289812,4,-1/1790030470:-27709159243/6927289812 +qsubz:-4/2649530011,3,-8/6194440675:-7948590037/2649530011 +qsubz:6/83079221,8,=1:-664633762/83079221 +qsubz:-6/331542793,3,2/296815681:-994628385/331542793 +qsubz:8/66065289,2,-1/4328527:-132130570/66065289 +qsubz:1/2350655,7,=1:-16454584/2350655 +qsubz:2/3582747,9,1/2075528:-32244721/3582747 +qsubz:-1/1935616,2,8/4881029:-3871233/1935616 +qsubz:-8/465389,-4,1/262387:1861548/465389 +qsubz:2/240549,5,1/4804:-1202743/240549 +qsubz:3/48194,9,0:-433743/48194 +qsubz:4/27421,0,5/29029:4/27421 +qsubz:4/373,8,3/1025:-2980/373 +qsubz:3/1183,0,-1/3894:3/1183 +qsubz:1/106,3,9/871:-317/106 +qsubz:1/371,2,=1:-741/371 +qsubz:-3/56,5,0:-283/56 +qsubz:-5/91,4,-1/34:-369/91 +qsubz:8,4,9/4:4 +qsubz:4/7,9,=1:-59/7 +qsubz:67/67063488163100893306,-90,=1:6035713934679080397607/67063488163100893306 +qsubz:93/14983550478036855485,-67,69/28718649239616874679:1003897882028469317588/14983550478036855485 +qsubz:-8/1154267369681644285,87,7/1422761935805056072:-100421261162303052803/1154267369681644285 +qsubz:37/9228347282193695562,-68,32/723121468170916937:627527615189171298253/9228347282193695562 +qsubz:70/67740456883245887,-44,=1:2980580102862819098/67740456883245887 +qsubz:-4/290534225323804529,3,14/82856366067157729:-871602675971413591/290534225323804529 +qsubz:46/92984464090082831,31,37/3777138432527707:-2882518386792567715/92984464090082831 +qsubz:-1/30135296523120697,19,39/50227831157182621:-572570633939293244/30135296523120697 +qsubz:5/1204201678805616,27,-95/8641770984922113:-32513445327751627/1204201678805616 +qsubz:13/221269253819147,-51,85/902323678584334:11284731944776510/221269253819147 +qsubz:16/197386558463723,66,11/188936591024340:-13027512858605702/197386558463723 +qsubz:-33/364958822489692,-68,29/670095439482948:24817199929299023/364958822489692 +qsubz:2/69405413649461,25,14/58807481541667:-1735135341236523/69405413649461 +qsubz:4/151019996133,86,-7/15591256924134:-12987719667434/151019996133 +qsubz:-20/2213441952101,68,-5/766058099692:-150514052742888/2213441952101 +qsubz:47/3397682774754,62,-27/825236302529:-210656332034701/3397682774754 +qsubz:-8/300999779133,-8,52/319011801871:2407998233056/300999779133 +qsubz:78/930349215041,-94,-16/849840150359:87452826213932/930349215041 +qsubz:-62/78781195345,97,63/94454224597:-7641775948527/78781195345 +qsubz:84/67865566651,10,40/38840532741:-678655666426/67865566651 +qsubz:97/9037713489,26,=1:-234980550617/9037713489 +qsubz:55/8758626548,-31,-23/3424652585:271517423043/8758626548 +qsubz:96/712280131,76,-47/143760491:-54133289860/712280131 +qsubz:-34/979750323,86,18/751431151:-84258527812/979750323 +qsubz:0,40,49/28166996:-40 +qsubz:11/655774,-79,-5/2552876:51806157/655774 +qsubz:38/4762681,-34,-38/4640209:161931192/4762681 +qsubz:10/759353,91,-79/8482283:-69101113/759353 +qsubz:52/658491,60,-10/24871:-39509408/658491 +qsubz:47/356452,48,-52/327287:-17109649/356452 +qsubz:-23/1045,-17,40/36411:17742/1045 +qsubz:29/57207,74,-19/15711:-4233289/57207 +qsubz:71/6841,24,27/3695:-164113/6841 +qsubz:41/2,-28,-8/503:97/2 +qsubz:1/992,69,-79/335:-68447/992 +qsubz:-80/873,58,55/97:-50714/873 +qsubz:-80/59,25,-24/29:-1555/59 +qsubz:31/53,4,83/16:-181/53 +qsubz:52/5,87,55/4:-383/5 +qsubz:64/3,-44,86/7:196/3 +qsubz:217/14857025609834400288,407,-29/32222540400290548019:-6046809423202600916999/14857025609834400288 +qsubz:-2/3173544479029088453,617,=1:-1958076943560947575503/3173544479029088453 +qsubz:599/8002882171639730594,194,994/7112031035139432061:-1552559141298107734637/8002882171639730594 +qsubz:226/1547262749305138445,841,=1:-1301247972165621432019/1547262749305138445 +qsubz:-21/33650083175862080,-295,-192/250269714000112853:9926774536879313579/33650083175862080 +qsubz:371/195117884451651598,98,-31/6936245079767325:-19121552676261856233/195117884451651598 +qsubz:490/84964164487466941,-621,85/1727659786593371:52762746146716970851/84964164487466941 +qsubz:73/2114768125726396,264,371/90346751835547482:-558298785191768471/2114768125726396 +qsubz:-67/754047118019190,473,=1:-356664286823076937/754047118019190 +qsubz:428/1757703052948383,545,-929/6392239532410133:-957948163856868307/1757703052948383 +qsubz:-187/146639276395956,379,49/117345807572527:-55576285754067511/146639276395956 +qsubz:574/304011640895343,117,31/939392861513114:-35569361984754557/304011640895343 +qsubz:281/28071632904233,839,-779/61474591794274:-23552100006651206/28071632904233 +qsubz:-451/21089251676176,966,-402/36593676777599:-20372217119186467/21089251676176 +qsubz:447/699261969911,217,305/9706389468401:-151739847470240/699261969911 +qsubz:921/4456064406581,-752,-25/13909101793:3350960433749833/4456064406581 +qsubz:57/94353144617,914,944/766019154987:-86238774179881/94353144617 +qsubz:317/388136152543,159,423/224732026858:-61713648254020/388136152543 +qsubz:545/36819534187,-885,=1:32585287756040/36819534187 +qsubz:260/75651626533,-80,142/23885409609:6052130122900/75651626533 +qsubz:308/2920452939,386,176/748052249:-1127294834146/2920452939 +qsubz:956/2320741999,604,=1:-1401728166440/2320741999 +qsubz:229/136668710,-720,=1:98401471429/136668710 +qsubz:697/821017209,-389,877/710813436:319375694998/821017209 +qsubz:70/9998911,-414,409/41910723:4139549224/9998911 +qsubz:-137/4902402,-780,0:3823873423/4902402 +qsubz:98/339603,579,751/7297217:-196630039/339603 +qsubz:843/8995763,-683,=1:6144106972/8995763 +qsubz:-68/25519,874,97/240532:-22303674/25519 +qsubz:-407/183461,-958,53/66366:175755231/183461 +qsubz:353/72580,466,747/59113:-33821927/72580 +qsubz:83/41954,447,884/15765:-18753355/41954 +qsubz:-931/5272,773,5/391:-4076187/5272 +qsubz:81/167,110,19/123:-18289/167 +qsubz:456/823,345,870/7:-283479/823 +qsubz:688/747,879,678/181:-655925/747 +qsubz:-849/62,395,=1:-25339/62 +qsubz:-433/39,676,=1:-26797/39 +qsubz:220,191,-109/5:29 +qsubz:32/3,-877,655/2:2663/3 +qsubz:4482/942383524654707545,4232,9844/42644717112858614311:-3988167076338722325958/942383524654707545 +qsubz:1875/2912377751134048423,-2847,=1:8291539457478635862156/2912377751134048423 +qsubz:3804/6718901259124469983,-7372,7774/3759543365401515053:49531740082265592718480/6718901259124469983 +qsubz:9425/3546445994609032698,-6247,9653/7954521365876236362:22154648128322627273831/3546445994609032698 +qsubz:-5435/351267797941464751,7271,4323/405081904237732000:-2554068158832390209956/351267797941464751 +qsubz:4747/334289067072715219,-9265,1271/365223131014466030:3097188206428706508782/334289067072715219 +qsubz:593/11020543433206946,-9783,1692/92769627960132841:107813976407063553311/11020543433206946 +qsubz:58/71759187206685567,2562,=1:-183847037623528422596/71759187206685567 +qsubz:8176/5868555722851603,4639,749/1128170091785729:-27224229998308578141/5868555722851603 +qsubz:1048/2494671804723743,258,-9823/9523787627049892:-643625325618724646/2494671804723743 +qsubz:4016/437682693132675,-5554,9263/342594970246293:2430889677658880966/437682693132675 +qsubz:-449/124840348021110,-2661,=1:332200166084173261/124840348021110 +qsubz:3767/38680047773174,-361,3480/41604972731513:13963497246119581/38680047773174 +qsubz:8637/56843071105219,5929,9928/45360343092035:-337022568582834814/56843071105219 +qsubz:42/1232757862481,3179,4357/5496968152610:-3918937244827057/1232757862481 +qsubz:546/1614496289405,1603,2191/3651782433017:-2588037551915669/1614496289405 +qsubz:809/91979873066,4972,-4804/368689337963:-457323928883343/91979873066 +qsubz:-3210/152298659683,-4089,541/44970493080:622749219440577/152298659683 +qsubz:7246/21217273455,2308,=1:-48969467126894/21217273455 +qsubz:2397/86866068995,7381,-2866/3975744919:-641158455249698/86866068995 +qsubz:3087/4683188920,6673,9169/306325723:-31250919660073/4683188920 +qsubz:990/4768458857,4306,4877/2755124455:-20532983837252/4768458857 +qsubz:-3658/338788855,2880,5674/71884221:-975711906058/338788855 +qsubz:-9886/839837613,-2330,4083/690099413:1956821628404/839837613 +qsubz:7337/91119486,5300,9061/80090081:-482933268463/91119486 +qsubz:6273/50364475,-837,-1696/28323419:42155071848/50364475 +qsubz:648/537779,-5873,8567/8273739:3158376715/537779 +qsubz:3179/1733392,4267,1178/6835527:-7396380485/1733392 +qsubz:2567/620512,4677,7019/800989:-2902132057/620512 +qsubz:8643/360838,5106,-8302/971695:-1842430185/360838 +qsubz:-2586/31991,-5074,2570/21109:162319748/31991 +qsubz:2023/2705,2980,317/96960:-8058877/2705 +qsubz:-1301/5346,4188,-7061/2853:-22390349/5346 +qsubz:-6732/8017,9992,31/59:-80112596/8017 +qsubz:-3890/853,2695,962/263:-2302725/853 +qsubz:2329/43,7457,=1:-318322/43 +qsubz:1601/82,2574,301/13:-209467/82 +qsubz:-1347/20,4147,-355:-84287/20 +qsubz:1381,-456,5461/3:1837 +qsubz:1267,3358,=1:-2091 +qsubz:12513/10252103968497865097,4751,58924/7482016308047316835:-48707745954333357063334/10252103968497865097 +qsubz:-8397/12043175373779318638,32237,-75596/84316290023168074765:-388235844524523894941603/12043175373779318638 +qsubz:2207/1864898564933133421,-268,=1:499792815402079759035/1864898564933133421 +qsubz:93903/5738092942308156928,-98800,=1:566923582700045904580303/5738092942308156928 +qsubz:-22733/84967665346179535,83373,37597/787951056254403061:-7084009162907026394288/84967665346179535 +qsubz:-86661/144430519608110792,44749,-90279/140207959688288608:-6463121321943349917869/144430519608110792 +qsubz:483/360261339188405,529,=1:-190578248430665762/360261339188405 +qsubz:-38143/29201842630357283,93563,=1:-2732212002024118507472/29201842630357283 +qsubz:62857/8632026056772207,-87080,-91675/4159937477960427:751676829023723848417/8632026056772207 +qsubz:23972/3672679577284837,52253,85704/3937432008899357:-191908525951864563789/3672679577284837 +qsubz:-14599/133661353793289,51189,99045/961552885468912:-6841991039324685220/133661353793289 +qsubz:62703/884965957527142,86064,=1:-76163710168615886385/884965957527142 +qsubz:64258/63053331939447,29993,33125/6340027354888:-1891158584859769613/63053331939447 +qsubz:20336/70880915457155,41846,79118/19214581682805:-2966082788220087794/70880915457155 +qsubz:36038/5027873766967,8156,18212/2385080863253:-41007338443346814/5027873766967 +qsubz:5053/326394695366,-96066,48835/616131440759:31355432805035209/326394695366 +qsubz:-42352/85957538425,63707,=1:-5476096900483827/85957538425 +qsubz:98097/378312685672,74927,-87935/235046263733:-28345834599247847/378312685672 +qsubz:547/343462127,45098,71335/96241407069:-15489455002899/343462127 +qsubz:-60477/84209971088,13484,11423/1932234184:-1135487250211069/84209971088 +qsubz:78087/178203607,2768,99674/645255053:-493267506089/178203607 +qsubz:5795/9287277564,55525,94160/3355805697:-515676086735305/9287277564 +qsubz:18925/113809474,-82623,=1:9403280189227/113809474 +qsubz:24851/454133872,99932,41237/85240886:-45382506071853/454133872 +qsubz:32911/22337158,43967,9767/5792458:-982097792875/22337158 +qsubz:4426/88473719,34001,302/1024805:-3008194915293/88473719 +qsubz:19589/4824560,27427,-56021/4154865:-132323187531/4824560 +qsubz:54075/7773166,56830,-399/153359:-441748969705/7773166 +qsubz:18078/738403,66012,86419/302521:-48743440758/738403 +qsubz:2510/112811,-47375,17956/599429:5344423635/112811 +qsubz:-69109/5420,2635,=1:-14350809/5420 +qsubz:696/5261,-27292,12449/12093:143583908/5261 +qsubz:6568/1031,5374,=1:-5534026/1031 +qsubz:307/167,87414,=1:-14597831/167 +qsubz:14308/171,-77499,92955/236:13266637/171 +qsubz:-3325/3,-32369,-9967/90:93782/3 +qsubz:62901/65,-51444,-55475/13:3406761/65 +qsubz:94982/85,74494,1763/15:-6237008/85 +qsubz:-15489,36907,29337/5:-52396 +qsubz:-44489/6,51924,=1:-356033/6 +qsubz:866110/92140247631008473461,992450,-12311/75887274686890544356:-91444588761394359485503340/92140247631008473461 +qsubz:286002/21377811703132112171,-707482,=1:15124416979355312983249424/21377811703132112171 +qsubz:205249/6361297615099533875,893207,=1:-5681955558890209353681876/6361297615099533875 +qsubz:602071/8282499324515240138,143540,=1:-1188869953040917568806449/8282499324515240138 +qsubz:-157822/195585936483662037,948292,47401/94049003322925483:-185472578879964840548626/195585936483662037 +qsubz:-485225/770852827673995413,462391,451203/793998272131521284:-356435409841006413497708/770852827673995413 +qsubz:832061/32966123055937780,297720,-38054/4240951695865905:-9814674156213795029539/32966123055937780 +qsubz:378475/97089199745880654,-144939,804700/47910921928599697:14072011521968196488581/97089199745880654 +qsubz:168809/1173744791921052,993504,123481/4027191055766810:-1166120145752732677399/1173744791921052 +qsubz:984079/7930167991939240,207285,19678/312910315596939:-1643804872209124379321/7930167991939240 +qsubz:268867/66218854685878,-341636,=1:22622744639464885275/66218854685878 +qsubz:-265818/703448681374513,-608432,516434/935917451239689:428000688106057427798/703448681374513 +qsubz:30312/17555819170721,-807531,837647/26238515163476:14176868210751530163/17555819170721 +qsubz:273401/67808858597950,255506,47585/13599555299396:-17325570224927539299/67808858597950 +qsubz:861384/410255576291,400497,402375/1586446068433:-164306127536955243/410255576291 +qsubz:76471/2810776113738,700348,=1:-1968521429704104353/2810776113738 +qsubz:46697/205225703,-877191,-693829/982561781845:180022139686970/205225703 +qsubz:694597/894706887191,189537,-5500/6992098541:-169580059276825970/894706887191 +qsubz:190839/96993581741,-48652,-262577/87880831891:4718931739053971/96993581741 +qsubz:926735/37595457632,309200,228538/46784730005:-11624515498887665/37595457632 +qsubz:-289777/2914954976,-922880,-785617/9421248912:2690153647961103/2914954976 +qsubz:146291/1692030840,816085,-21414/520023815:-1380840987915109/1692030840 +qsubz:149175/195113702,21897,=1:-4272404583519/195113702 +qsubz:-798035/275024051,342,=1:-94059023477/275024051 +qsubz:84407/78878758,-202254,414137/15080286:15953544404939/78878758 +qsubz:99099/5326786,776103,-250532/35421237:-4134134495859/5326786 +qsubz:820103/1983152,83528,386969/1852538:-165647900153/1983152 +qsubz:-277421/4047779,-724923,-962247/9651313:2934327818596/4047779 +qsubz:300716/83775,791615,597967/22363:-66317245909/83775 +qsubz:913987/585082,571734,-207060/17131:-334510358201/585082 +qsubz:286582/40727,479108,247602/7559:-19512344934/40727 +qsubz:969635/90993,547019,-27576/16163:-49773930232/90993 +qsubz:484543/4803,-13377,17384/831:64734274/4803 +qsubz:3392/77,159299,=1:-12262631/77 +qsubz:272609/60,-479733,5158/5:29056589/60 +qsubz:-63573/145,944778,245967/77:-137056383/145 +qsubz:684504/71,664239,-229408/35:-46476465/71 +qsubz:-86273,-276646,-115497/7:190373 +qsubz:355634/9,348514,373603/7:-2780992/9 +qsubz:-35219/3,752707,462886/5:-2293340/3 +qsubz:6360943/76846663141823723315,-4919575,2604527/5657014356260399834:378052922825937443633752068/76846663141823723315 +qsubz:183663/3383815743880203737,3975537,7064811/78463982107211848135:-13452484690978273523798106/3383815743880203737 +qsubz:4452901/2427919735747339403,2077568,=1:-5044168349557128424359003/2427919735747339403 +qsubz:8188529/976933204663543185,-1819612,=1:1777639382404239150132749/976933204663543185 +qsubz:5989009/760314382917671424,-4531658,4299344/201823238781745367:3445484755863929055930001/760314382917671424 +qsubz:893159/325858362948738303,4913385,=1:-1601067592636886545992496/325858362948738303 +qsubz:-1545535/21298499245651851,4547022,64678/4463799054157215:-96844744636962372383257/21298499245651851 +qsubz:297441/54069528036684176,-4566133,1740182/82453971200884283:246888656262728826908849/54069528036684176 +qsubz:6314549/8139443267727551,7518036,2558291/3365437156048481:-61192627506733360295287/8139443267727551 +qsubz:-372197/9493061230738691,8349035,2681821/7376683826021902:-79257900472580407385382/9493061230738691 +qsubz:2058974/610730967434339,-3873084,=1:2365412338274461490450/610730967434339 +qsubz:1047887/255819069867599,4832574,-2588613/40555255514690:-1236264585746341321939/255819069867599 +qsubz:2862299/15444378077100,3725846,-3488340/75081425094083:-57543374281047864301/15444378077100 +qsubz:189642/13804468201471,-9916920,=1:136897806796531978962/13804468201471 +qsubz:9152299/2631833515647,7403594,-1874909/1403676750221:-19485026825433883019/2631833515647 +qsubz:9157819/3680087499503,6393090,2353381/629919919878:-23527130592188476451/3680087499503 +qsubz:-9202064/585608331143,7948050,3400424/545300178161:-4654444296350323214/585608331143 +qsubz:4941532/944567169683,3506737,-5183542/977397734325:-3312348642907712839/944567169683 +qsubz:-1132569/74601321698,9858377,-2217591/82351435039:-735447953998296715/74601321698 +qsubz:-6722621/70207951128,-2574827,4755161/88553923140:180773328172332235/70207951128 +qsubz:-131623/1102596343,4262329,6139281/2146761991:-4699628368194470/1102596343 +qsubz:-1537871/2076518121,-611135,3524466/1036431631:1269032900339464/2076518121 +qsubz:1873496/94557071,9574995,=1:-905383480166149/94557071 +qsubz:6133681/175761766,-4032589,-1323487/51867812:708774970325855/175761766 +qsubz:33618/108073,9301994,=1:-1005294363944/108073 +qsubz:99693/1649666,4815171,3560665/23554903:-7943423783193/1649666 +qsubz:-1476863/6094467,1954168,6826155/1513109:-11909613865319/6094467 +qsubz:9947161/5499663,-7436262,=1:40896944926867/5499663 +qsubz:-3188500/101159,-1362013,1715658/206461:137776684567/101159 +qsubz:1661723/438801,3554863,397247/83229:-1559875777540/438801 +qsubz:6730319/39072,-7285917,-785583/26039:284682079343/39072 +qsubz:881050/8251,9977014,5611562/26365:-82319461464/8251 +qsubz:-697786/267,9879500,=1:-2638524286/267 +qsubz:1563831/1594,3690522,330707/648:-5881128237/1594 +qsubz:2617466/799,4838440,1742596/21:-3863296094/799 +qsubz:-5575739/795,5654259,241335/887:-4500711644/795 +qsubz:3099833/23,1330008,2467779/32:-27490351/23 +qsubz:-119153/20,-5081644,-9942949/35:101513727/20 +qsubz:4981844/3,7468100,=1:-17422456/3 +qsubz:4124549/2,8822966,-327579:-13521383/2 +qsubz:1379187/4947079973483919932,39455371,85787924/46398781838625356921:-195188875720478223449975585/4947079973483919932 +qsubz:10309279/3518090035798479574,41783212,55881853/31567898190111952667:-146997101800855461307802409/3518090035798479574 +qsubz:7964765/7203559539360591689,17787685,-3457138/299200161568971109:-128134647964891306369585200/7203559539360591689 +qsubz:3870874/16190098037406359,32189441,=1:-521150205559307782184445/16190098037406359 +qsubz:57899009/680974553755525868,95258028,91102702/899472329944903875:-64868293108931388230769295/680974553755525868 +qsubz:36574505/725775689525814263,59424702,7088419/54125181064287425:-43129004068916033849550121/725775689525814263 +qsubz:-1339365/1352359843453361,37294708,32650165/49041162900322251:-50435865472518811452953/1352359843453361 +qsubz:64855889/55163734975059261,-50495551,10273592/5300232731771161:2785523192783588706703700/55163734975059261 +qsubz:87062294/350231041000041,87531372,18935971/2964729931492256:-30656203535721753723958/350231041000041 +qsubz:28654577/4766700414359347,-75710062,18946345/966631458761659:360887183906571880304091/4766700414359347 +qsubz:98899630/25197967410013,-94124519,=1:2371746562245248308377/25197967410013 +qsubz:-60951681/826245104735740,90114845,-46517310/138373690437397:-74456949545270037011981/826245104735740 +qsubz:3673134/7692444132233,98053795,-43749749/38563121801152:-754273339990923801101/7692444132233 +qsubz:-16042613/18604599439295,32614949,=1:-606788061878051063568/18604599439295 +qsubz:-18542903/4333580495789,95232673,8705127/3818163979847:-412698454274670256900/4333580495789 +qsubz:93847183/260167494778,70420110,50108689/4318919693752:-18321023600597338397/260167494778 +qsubz:63160383/511521681755,93405210,-8686231/33289600401:-47778790103815783167/511521681755 +qsubz:10995233/136483986795,-35714136,1540987/281295347273:4874407666229829353/136483986795 +qsubz:11840157/22134680227,-12663935,50115473/42408027975:280312151652353402/22134680227 +qsubz:2165532/84739740289,74114119,81643079/62400874960:-6280411195805874859/84739740289 +qsubz:9910853/253156711,83607638,59919120/1185300817:-21165834640647765/253156711 +qsubz:58968716/943992033,-17638483,-40257956/5469268719:16650587485174655/943992033 +qsubz:85910396/690654879,-56543102,-38201318/528835655:39051769356005054/690654879 +qsubz:4001435/163786307,-76984433,46803523/742917958:12608995981560366/163786307 +qsubz:90944610/52515871,87539015,32701282/49688015:-4597187528262455/52515871 +qsubz:46996626/49950215,-40784808,14253005/11778372:2037209975330346/49950215 +qsubz:16216866/657419,8499426,=1:-5587667924628/657419 +qsubz:26087801/6436061,-9418424,-60061709/1990672:60617577475665/6436061 +qsubz:48316307/459047,-25148975,-96687866/162915:11544609843132/459047 +qsubz:82175177/512872,74792479,9314575/111969:-38358886114511/512872 +qsubz:93244651/92781,94189756,-7781135/31498:-8738926506785/92781 +qsubz:65538455/49692,48926272,-470122/28003:-2431178769769/49692 +qsubz:-12968804/1131,-21968160,-33199358/3561:24833020156/1131 +qsubz:-10642810/4567,43054752,29068797/4090:-196641695194/4567 +qsubz:-16504669/331,19366230,-37110959/378:-6426726799/331 +qsubz:120055/122,35383126,21063457/242:-4316621317/122 +qsubz:-6229424/5,84957981,45357911/68:-431019329/5 +qsubz:13067352,40056104,=1:-26988752 +qsubz:-9746025,-39734152,-1201754/9:29988127 +qsubz:26013/7,93156445,90743757/8:-652069102/7 +qsubz:865257379/90357408174523899396,294967632,443698369/37895023238390231028:-26652510722896757331379092893/90357408174523899396 +qsubz:344980185/77047998342627739241,546105928,895790581/53691868371888449511:-42076368635443183496403340463/77047998342627739241 +qsubz:-701770897/9142934914307305747,-480401371,=1:4392278467796997195473208240/9142934914307305747 +qsubz:171005591/1827355652621001622,996389504,-95300137/8222844065780808107:-1820757992346636105956769897/1827355652621001622 +qsubz:-913921523/880602809205096206,-38929444,=1:34281377747192476352167941/880602809205096206 +qsubz:298448428/179100960271183235,-314975674,481319159/261547773510673260:56412445675463162520073818/179100960271183235 +qsubz:48498841/75668495862610916,840770177,14203580/1565428657566429:-63619814659731147478953291/75668495862610916 +qsubz:425310066/60222413302772033,-201447801,=1:12131672730756573677459499/60222413302772033 +qsubz:-940057/1889686623104801,252375598,-199312501/752380091448134:-476910791538674769986055/1889686623104801 +qsubz:-138260663/718501375621144,583863337,699241429/9216930315103608:-419506610809251721858191/718501375621144 +qsubz:-341109904/135846371828305,-320703571,357847807/48145438729245:43566416552730871267251/135846371828305 +qsubz:763032333/814687008627806,672611909,-202445947/307017891884461:-547968184110647301109321/814687008627806 +qsubz:624917837/39308871863154,192138767,126397892/82282223854417:-7552758171946777373281/39308871863154 +qsubz:330847639/89408290233165,395051236,734130441/60162275528191:-35320855565258230594301/89408290233165 +qsubz:241863323/8941917277532,727547638,36393496/593234672785:-6505670794459555206093/8941917277532 +qsubz:-844311241/3424218332208,394767882,35903300/424665745313:-1351771418512168854697/3424218332208 +qsubz:-38997799/537796116092,500842415,30021710/666347170909:-269351105561176639979/537796116092 +qsubz:152248609/304406597856,-602339321,39788505/63196175173:183356063460655344385/304406597856 +qsubz:-585718840/1597344893,-966455736,981830119/83198283632:1543763133624437408/1597344893 +qsubz:781348015/38619662873,624508546,-83818298/66343651279:-24118309507046064643/38619662873 +qsubz:26891135/250398333,-399834495,887194659/4297219804:100117891050787970/250398333 +qsubz:366957713/4214088144,750168389,303961849/7723958136:-3161275713721522303/4214088144 +qsubz:-382233523/802407598,539224619,643293638/180492853:-432677931696488685/802407598 +qsubz:504657599/972138678,943952223,=1:-917652465657723595/972138678 +qsubz:-408988345/21433274,760561192,417030670/7339543:-16301316830890953/21433274 +qsubz:410157974/58771605,-898139207,117071195/99665253:52785083118975209/58771605 +qsubz:-181359243/8378299,999308019,-685030111/5629257:-8372501557638924/8378299 +qsubz:367963568/2283391,533036363,91720099/586329:-1217130065983365/2283391 +qsubz:44939447/196951,46409799,-103285387/76069:-9140411383402/196951 +qsubz:814899293/55934,-36864186,292213674/137551:2062776279017/55934 +qsubz:151776179/86747,-807563906,322468120/95761:70053897929961/86747 +qsubz:-425405259/29272,662984675,715664474/9319:-19407312811859/29272 +qsubz:24777055/3654,967458144,-290540261/2806:-3535067281121/3654 +qsubz:366485985/1627,409846678,116744107/387:-666454059121/1627 +qsubz:87840767/198,-135713419,331986209/900:26959097729/198 +qsubz:606872603/617,110773818,-2999504/3:-67740573103/617 +qsubz:-126522338/7,345173453,=1:-2542736509/7 +qsubz:-107170432/13,706985358,-54309695/7:-9297980086/13 +qsubz:813855667/3,475384819,895215002:-612298790/3 +qsubz:464635413/2,211174932,343207577/7:42285549/2 +qsubz:-1073292494/4835121375628045513,2251773912,5366939142/90030076701246336647:-10887600174992785502795349350/4835121375628045513 +qsubz:9937723759/16929248820944777341,3536220517,5346758168/36993790254509343525:-59865557018022980947303181538/16929248820944777341 +qsubz:1854788341/3248262723951959327,-8297282960,=1:26951754949049775984384956261/3248262723951959327 +qsubz:-906823037/71927651067601606,2683555089,2600732775/4128402288016064626:-193021814062278573712695971/71927651067601606 +qsubz:6194391639/613753365565872866,-6823117729,-5801950686/463111032618663091:4187711469825925275559032953/613753365565872866 +qsubz:7222246398/974438771703442207,-2981326784,144559659/180449736371193901:2905120409447533563947418686/974438771703442207 +qsubz:598767509/618842078099439,467678172,4281762740/40185499542661501:-289418931842226266977999/618842078099439 +qsubz:9493241893/56354383572502234,5379218555,=1:-303142545768791195418509977/56354383572502234 +qsubz:7562126681/5274644967533227,5051748469,-1293127915/1893065732128434:-26646179639254526641752782/5274644967533227 +qsubz:7565520398/6835621275673391,7146311176,-1198943513/715334747317684:-48849476717248123463597418/6835621275673391 +qsubz:8495334411/471195956506405,6785264959,2168272913/863558614872658:-3197189412505389410227984/471195956506405 +qsubz:329831990/194008083833657,4410191432,4944067900/100050586251673:-855612789061931484794834/194008083833657 +qsubz:3921639067/5566583240720,-1672367274,6936260591/2578150592889:9309371639780913836347/5566583240720 +qsubz:2380554367/10517458627732,-7041942370,3279856951/33783400334050:74063337535350408359207/10517458627732 +qsubz:3445818365/3619763010066,895311547,-53891527/6375878985703:-3240815620312121213737/3619763010066 +qsubz:9680947669/4195349234903,9847517105,1869006639/80865949846:-41313773352146274568146/4195349234903 +qsubz:-6058980583/155496366963,4042446763,9119016077/744819499043:-628585785293898471352/155496366963 +qsubz:-1977545176/405611601655,-4869751414,5820473357/314742970445:1975227670692263444994/405611601655 +qsubz:-2162676941/6345800531,1286256621,-697595567/9987397219:-8162327950706742692/6345800531 +qsubz:3392475437/45282237869,6472179727,-5979122928/2366853503:-293074781925541006326/45282237869 +qsubz:4416785424/2111265383,-3271176628,821511083/7068316944:6906321980791853948/2111265383 +qsubz:4093300065/635906036,5062025739,285565567/61253547:-3218972717724160539/635906036 +qsubz:7916328811/940173619,5412477560,6775158536/668079907:-5088668607425160829/940173619 +qsubz:3127361256/855850901,-4692272984,2575948861/541199820:4015886064221719840/855850901 +qsubz:283244715/13702009,963515826,-1674038966/12371545:-13202102236249719/13702009 +qsubz:540577841/30024966,5801262858,9382566733/31524563:-174182719527934987/30024966 +qsubz:7954787149/971554,327753005,4739437825/5416433:-318421788232621/971554 +qsubz:1560609006/1064401,1688715477,-368001807/3080264:-1797468881825271/1064401 +qsubz:-4972657594/362819,8090532645,-203495293/57308:-2935403936383849/362819 +qsubz:1444526623/179543,2853408565,726160202/41635:-512308089459172/179543 +qsubz:4218657381/36913,7674015126,1050342199/14146:-283266701688657/36913 +qsubz:9320467151/38863,-4055403274,308167507/16643:157614457904613/38863 +qsubz:7827452709/3047,-9072276043,5468639/133:27651052555730/3047 +qsubz:778524864/3065,1683932125,1339853306/655:-5160473438261/3065 +qsubz:3472788866/281,6153287472,-7044029756/603:-1725600990766/281 +qsubz:-5843681042/587,6535907369,6873433701/140:-3842421306645/587 +qsubz:1706274151/40,475391167,=1:-17309372529/40 +qsubz:-7106248861/76,-7953014416,1126059826/93:597322846755/76 +qsubz:8857605738,-2247650088,7100250512/3:11105255826 +qsubz:1839886389/7,1649369168,688187521:-9705697787/7 +qsubz:21420789821/10134187221769337622,-67300091654,97875160505/23312037706226247093:682031728863872046028891196609/10134187221769337622 +qsubz:19184556071/53765794610868208511,60577023217,74452356089/4734788160637873210:-3256971788423016947478859443816/53765794610868208511 +qsubz:-7679928117/2767247253219016337,55513625448,18687044299/6286371666239502248:-153619927537207285250890872093/2767247253219016337 +qsubz:38618312951/8137064142866736162,91272025410,=1:-742686325210532613183211563469/8137064142866736162 +qsubz:-70329305757/733471856768781955,17530726893,-36062653409/460161038303613091:-12858294804715129971700921572/733471856768781955 +qsubz:-92664480037/251152784368324677,58676410442,-81532606580/860207074670537961:-14736743859246940544233557271/251152784368324677 +qsubz:38165401669/68739156230002569,44174230933,-23746763849/25990052797565342:-3036499361443699108023865208/68739156230002569 +qsubz:9045716812/13158209333079373,-79399582136,-87223831269/2510586287796491:1044756322704517467366597540/13158209333079373 +qsubz:52939174938/4974456626264035,87493688728,43147212680/2387939387259719:-435233559649282454892122542/4974456626264035 +qsubz:81367771694/850281974804851,92502648537,-69900752953/1391561070523707:-78653334672719339847881293/850281974804851 +qsubz:-85053146313/639164379192017,54673455287,13200170243/100963367078830:-34945325106797939689990192/639164379192017 +qsubz:20156443510/20773119248737,37480014907,20271435745/312278412786689:-778576819107531244478949/20773119248737 +qsubz:-10838886733/6871945259460,92773868860,6711171275/80361105218191:-637536948314251553302333/6871945259460 +qsubz:97173191102/49466168642747,17726036129,12845931025/12225527003766:-876839092524443042615261/49466168642747 +qsubz:95109045/199572919304,-36806647761,19117093237/4980142825265:7345610143456900387389/199572919304 +qsubz:-19508332357/8876460386507,29224737608,43187977743/4349125197230:-259412225683492846987613/8876460386507 +qsubz:12109709171/148689816535,84702134869,23340728701/21524306891:-12594344893782326549744/148689816535 +qsubz:70406287853/869355596938,33776459373,55742597576/52660518145:-29363754000596113912021/869355596938 +qsubz:585222646/31985233215,-81118619,8164685068/93850613725:2594597947378952731/31985233215 +qsubz:46451898407/8549297194,35096580302,=1:-300051095448432374181/8549297194 +qsubz:60939385/27011903,-54212225249,34047977198/2734124659:1464375369901078232/27011903 +qsubz:27241414109/5032121410,-80524782294,=1:405210481044467728649/5032121410 +qsubz:-1517062448/92397599,82706710904,32781270955/804186901:-7641901510233781944/92397599 +qsubz:-72090700936/254068779,44740138239,=1:-11367072366764641117/254068779 +qsubz:-32335979955/7707637,-5502717532,2999795591/1166575:42412916914211929/7707637 +qsubz:-24159394717/30439725,42916822470,3512473831/6138983:-1306376298020015467/30439725 +qsubz:-83277071349/5625575,91497956206,=1:-514728698260639799/5625575 +qsubz:38672562477/8826391,24030139693,-6160335294/93847:-212099370042475486/8826391 +qsubz:-3384269055/64964,9103457689,30554917387/326314:-591400409577251/64964 +qsubz:-59571884431/32240,-81755116216,408787901/1755:2635725374919409/32240 +qsubz:48229096314/54161,27903967566,=1:-1511258558245812/54161 +qsubz:20045879099/62217,-64596206712,-66029045734/75381:4019002238879603/62217 +qsubz:23489616563/872,29670916860,-5971297606/557:-25849549885357/872 +qsubz:83219508219/5974,15772230677,582785677/54:-94140086556179/5974 +qsubz:6729510238/31,24272198233,=1:-745708634985/31 +qsubz:16173563552/113,27486903185,=1:-3089846496353/113 +qsubz:-47472904273/69,7141425373,6439404343/56:-540231255010/69 +qsubz:51824444351/61,-52527701227,=1:3256014219198/61 +qsubz:-28091556651/2,5950022569,-3627844227:-39991601789/2 +qsubz:54841455404,-4522114796,-49302775324/7:59363570200 +qsubz:582044754139/56293289312589333700,543100653961,-293376120510/22101874091130677947:-30572922239283039282121211031561/56293289312589333700 +qsubz:863378183609/36104436361383843452,7988014019,=1:-288402743802827490871299169979/36104436361383843452 +qsubz:310042961637/3290967571160173688,-218205349633,481594120353/6095463672099458281:718106729495870507345090018141/3290967571160173688 +qsubz:332189704537/4416708145100434021,836207829003,9340261402/4185349277685404729:-3693285929354301043761262006526/4416708145100434021 +qsubz:-249460520992/202110419372893751,428458525044,-44611263972/42616655580362771:-86595932180534340237045121036/202110419372893751 +qsubz:122311231452/75027142810316983,377180651007,-741450514659/647861091739096129:-28298786568390519041656920429/75027142810316983 +qsubz:13278459816/99368908017329513,705837543053,20559860194/117508700464855:-70138305890811416988946563373/99368908017329513 +qsubz:973128819452/9328598030058051,-470123313629,-372304176079/29720264187522870:4385591417403853652478296531/9328598030058051 +qsubz:-43724262678/1538974313385071,155441438418,321158859675/1414718865236666:-239220380960929390691320356/1538974313385071 +qsubz:297720090859/6268772602498826,-683800722712,195404651967/567524423173634:4286591236105882613651626971/6268772602498826 +qsubz:-478151981509/569806807788948,393132978368,429377458060/939853885300617:-224009847440432106145458373/569806807788948 +qsubz:646410569317/333338235834566,-549506177325,=1:183171419729712340170985267/333338235834566 +qsubz:51236525512/4913829572565,518862556472,849462110245/92311588868614:-2549602174088739697865168/4913829572565 +qsubz:170018414037/33080905332140,27360261367,430903523746/37958380653475:-905102216144164327021343/33080905332140 +qsubz:389185485712/9793322203883,-659024335733,59021105873/481883158776:6454037660033622853736951/9793322203883 +qsubz:909632962214/4281741824583,12584416260,=1:-53883221437494739957366/4281741824583 +qsubz:-433649087373/555105608969,522178231717,636663919751/434542406633:-289864065308054524557146/555105608969 +qsubz:226289850773/240939721173,-779455912091,325469197331/306494129848:187801890126078229253516/240939721173 +qsubz:-28728778059/3012978130,-106991553027,613396487281/79642465446:322363209336357521451/3012978130 +qsubz:78754526716/14242413985,431207764296,152553713159/10855948650:-6141439492571179552844/14242413985 +qsubz:387141036389/5539390134,145933365862,=1:-808381846690234169119/5539390134 +qsubz:205234713289/2404538676,831396150355,445862618338/245594955:-1999124198400873916691/2404538676 +qsubz:406556133145/882230806,-177285397339,-907530046754/970980799:156406639392972358379/882230806 +qsubz:-437068913804/579574371,60088259224,=1:-34825615481303661908/579574371 +qsubz:30508378793/3569747,-780792504756,198433507438/97598395:2787231731983595525/3569747 +qsubz:196609293534/8130889,426393278342,-296591563367/98318012:-3466956219935612504/8130889 +qsubz:-103665512384/3219407,343041471685,327414529149/276949:-1104390218898503179/3219407 +qsubz:15404741180/341451,869230362129,339893658990/5534429:-296799560974567999/341451 +qsubz:-209751243565/196919,-569752205869,-11109223799/401194:112194824876274046/196919 +qsubz:-83409156386/117227,525814065374,791933892737/764822:-61639688850754284/117227 +qsubz:-104685303052/62283,-731959248807,114243681256/7429:45588513208143329/62283 +qsubz:895224938428/69119,-716278812153,-90243582193/10681:49509370442141635/69119 +qsubz:42133988649/3631,-445162819995,-954951120397/5875:1616428333390494/3631 +qsubz:112664025666/277,503116531409,247371933467/111:-139250615174627/277 +qsubz:284809115647/66,672615493530,554002682515/271:-44107813457333/66 +qsubz:5127131051/6,-212712172623,=1:1281400166789/6 +qsubz:171390839296/35,-82337476599,417661388196/89:3053202520261/35 +qsubz:191091147431/39,-920358211719,-25819031162/73:36085061404472/39 +qsubz:807118523227/5,346448150075,80611631468:-925122227148/5 +qsubz:418694152501/6,739403431228,-129305925739/8:-4017726434867/6 +qsubz:126259912535/19744860018986912314,1555457055296,-3487093339153/28692815598057427812:-30712281822365105276971541402409/19744860018986912314 +qsubz:-968360818288/10957042492839702615,-2258597022367,3154775409189/49421866618340899520:24747543548276443243508422571417/10957042492839702615 +qsubz:1890330468609/2410198493801717930,9205721307529,=1:-22187615629764777182735712826361/2410198493801717930 +qsubz:1034477250607/615640323458489068,9353407953800,1425836114708/170749360405788367:-5758335098116636371727071807793/615640323458489068 +qsubz:262340294343/741793310935990,-2150652932535,=1:1595339959499334241513728993/741793310935990 +qsubz:5309424088963/684908358112044502,3522078056131,-8179152756076/644669401491648789:-2412300698567144519392901852799/684908358112044502 +qsubz:3588674603747/1545966035679074,3212946088828,=1:-4967105527796005520630181525/1545966035679074 +qsubz:-4534453995828/32270512908519613,6589946455938,-9801838977275/38162912829764278:-212660952172800308629967307822/32270512908519613 +qsubz:2685068067884/3336975215402057,-7595365246836,-8811372244318/6683370423107785:25345545580617861619855209536/3336975215402057 +qsubz:543922202681/1166407376560219,-6302819775757,4908003544930/9587540580797447:7351655479572590719509013464/1166407376560219 +qsubz:1156846910145/409653034339684,9351664480220,1708516236439/66993814409903:-3830937730448765627932140335/409653034339684 +qsubz:9324441180811/420640541106436,1370697368460,-1313111911158/152906436709229:-576570882762172957528227749/420640541106436 +qsubz:-3788617052905/39205078029262,1228798560487,=1:-48175143446141445080023499/39205078029262 +qsubz:-7794396369241/56330672452520,-7704693024950,871554050776/21153823483007:434010539135666159654004759/56330672452520 +qsubz:4137136201806/8737070701967,-9979643114697,6058666158875/9867656564998:87192847473509993220710805/8737070701967 +qsubz:2641531019871/5593201879555,-4265291606149,1130816894271/2795283200510:23856637028365393126403566/5593201879555 +qsubz:8014147074772/512942258297,-8116516720099,876859202116/274307119021:4163304415920954656486175/512942258297 +qsubz:7059941701479/197648480521,8708557606758,=1:-1721233178498254999259439/197648480521 +qsubz:3755712200003/217202180,2401179822277,3189798795928/5096167231:-521541488214864763857/217202180 +qsubz:5560957786655/41651212441,8862436005090,=1:-369131204787209989538035/41651212441 +qsubz:-9615360976410/8344722377,6598017106271,700561666213/7396251362:-55058621000143761702577/8344722377 +qsubz:-1589748773573/2251431553,1769925300090,9628158560519/9021450241:-3984865668665368513343/2251431553 +qsubz:4945046252645/140767167,-3087509026163,3397834417837/518301300:434619903644940642866/140767167 +qsubz:1602058825487/99985791,6831864885925,3194690165276/457014865:-683089413022277066188/99985791 +qsubz:4764685272484/38991805,2571787873727,410456342572/677513:-100278646509042534751/38991805 +qsubz:4983758675551/20456287,-100153673261,=1:2048777268089917458/20456287 +qsubz:5694289753177/6317218,3418777293359,4923010338011/2845899:-21597155761309002085/6317218 +qsubz:329203322035/1858873,-4317791382401,5975893406151/9192155:8026226149581216108/1858873 +qsubz:4335665925075/55982,1656849962526,181594437680/67803:-92749438936205457/55982 +qsubz:9709390247427/166663,5132356269680,-3016218694867/745383:-855364183583430413/166663 +qsubz:-4359941557652/86109,1888975613916,3532475125997/7807:-162662161080250496/86109 +qsubz:75022830289/2220,1146635653662,6798944526217/46106:-2545456128299351/2220 +qsubz:4100868613295/1849,7054226490020,=1:-13039163911433685/1849 +qsubz:8649747700020/5381,3828262903125,2064106492493/761:-20591232934015605/5381 +qsubz:8502529839374/915,3194584992739,=1:-2914542738516811/915 +qsubz:9574702992505/246,5116051092239,5492259470317/599:-1248973865698289/246 +qsubz:-2543724436678/17,5669830231740,2153080048221/11:-98930838376258/17 +qsubz:1139363340091/4,4576282403250,1187287585095/19:-17165766272909/4 +qsubz:801445681414,5625028722145,=1:-4823583040731 +qsubz:287567579499,-5591174678442,-4382414917357/2:5878742257941 +qsubz:-715733231768/486064740545382237,89623634634077,58742041670676/35324168704538737315:-43562888715146770490499323922017/486064740545382237 +qsubz:-75727619487742/10388202751580825775,96108515478673,48660513204241/1818946673143737333:-998394744945899243492150360684317/10388202751580825775 +qsubz:-96029325769707/9893650986371005511,-74226005177085,-46687636878977/2387058458323178030:734366189334646371739993740145728/9893650986371005511 +qsubz:35783358055412/1552476032897596751,43490497059466,-1079321111837/5800379511336485288:-67517954343624372543080377339554/1552476032897596751 +qsubz:57789813906856/971696921385158133,2391642623404,863087819839/4775785527716489:-2323951774215189888927692837876/971696921385158133 +qsubz:-77070689378461/283257676299534021,-94811904810524,3607206487153/28906915118888592:26856199842161639591718807458543/283257676299534021 +qsubz:34509538492008/72304248340579153,-41953401106124,=1:3033409132309117863454513524980/72304248340579153 +qsubz:1340089579409/19730355565997710,37067446196524,342940118101/16746159833490834:-731353893380907947460704380631/19730355565997710 +qsubz:3919216713549/2250316629207754,-29394351385551,2872931002859/32162204014599:66146597727681403624549476003/2250316629207754 +qsubz:13914230734213/7377733041063051,68650193198811,-10400363504789/7533498628147940:-506482798638229846031398498148/7377733041063051 +qsubz:8362337855011/33881947681545,3976758804466,=1:-134740333755032092353924959/33881947681545 +qsubz:-79790637400646/303532319009043,-60289205709726,=1:18299722420286289131189651572/303532319009043 +qsubz:49164617138338/49329628036955,77336493302650,8067608439485/33220679284796:-3814980448302136859582292412/49329628036955 +qsubz:-22432972371586/38951076862109,-92458433570223,-31701633786722/95207688313893:3601355552543932683767008721/38951076862109 +qsubz:-4621525773709/140347977321,34467754323165,49739152325557/4329768753107:-4837479602057982650714674/140347977321 +qsubz:-43517481518770/3452004002879,30104767625988,21895741020071/133893785957:-103921778350696223428738222/3452004002879 +qsubz:52840510018437/757153700674,-23243061688718,81530288553473/77422952760:17598570172659746044814369/757153700674 +qsubz:66795802116211/748770475694,13193952800144,=1:-9879242314381210389583725/748770475694 +qsubz:40654512282679/28351746821,-94129569333945,4668047575488/16185258151:2668737718166428753421524/28351746821 +qsubz:-8794421645897/53319870337,-20198498303046,44580016832223/49670829584:1076981310511732830500605/53319870337 +qsubz:33181476617649/4377168145,45758335183370,79624732407833/456222057:-200291927099698421131001/4377168145 +qsubz:28405759396583/2581458592,80820518399572,-54287042127266/4414416479:-208634821604063469126041/2581458592 +qsubz:20477840610563/180143060,-48654124735301,-16777846576721/391089816:8764702931916652771623/180143060 +qsubz:19988889540450/80587711,60651285384749,-44648119713661/448244778:-4887748238375786679089/80587711 +qsubz:-52456127766149/43656429,6722399471849,16794509454023/64472294:-293476007708541133370/43656429 +qsubz:79338612639523/4449964,42881321722350,24368081230145/16600353:-190820258598262855877/4449964 +qsubz:-36687850855147/3594342,40016343462709,59189303240521/1278571:-143832460682291247625/3594342 +qsubz:-30566194381329/2595937,67081788792968,-67923038242759/8884794:-174140128120045352345/2595937 +qsubz:-6295335911933/438252,-44734738625819,76501444579927/371738:19605082376906516455/438252 +qsubz:27767502414109/413061,97215608337806,34631303453755/296748:-40155948628120070057/413061 +qsubz:37136350760161/3002,-92175327996582,76466821875271/29733:276747470996499325/3002 +qsubz:2935626294482/5109,20674608574976,-2365106865080/11931:-105623639583257902/5109 +qsubz:52812699008901/2884,84249241650178,6737583755031/134:-242922000220104451/2884 +qsubz:-65470998619593/2326,32262904613011,=1:-75108987128483179/2326 +qsubz:78999075171323/661,-10593407332566,=1:7081241321997449/661 +qsubz:1731396778013/5,56049768012708,=1:-278517443285527/5 +qsubz:-8277249758540/11,59885952775145,-25291842793412/45:-667022730285135/11 +qsubz:-42440035424938/57,-39767184220346,-904504982593/8:2224289465134784/57 +qsubz:22865720041019/4,40904975798004,8075381981923/3:-140754183150997/4 +qsubz:-21922184931013/2,-85282941031136,34448564580295/4:148643697131259/2 +qsubz:-246867251356781/34913747863834817207,99725282227818,=1:-3481783359351804958476515011821107/34913747863834817207 +qsubz:-305181664167009/90807051195363677740,-556419009100301,=1:50526769445444561004327150236832731/90807051195363677740 +qsubz:338648296555449/4263692604904527856,496604482821540,809299601354051/8236031413566206038:-2117368860968637737678068110262791/4263692604904527856 +qsubz:-229143629870713/5276801568796926466,-709348348254893,403852851463129/9918468826070875579:3743090476894927918180789515827425/5276801568796926466 +qsubz:541314787008921/969761679678247393,-625023945769056,-10730423739323/107949110676011946:606124271488125555126774399079929/969761679678247393 +qsubz:269697710637581/986639032055630686,-647511576454662,81783586137827/121738862044573311:638860195038043221027996005595713/986639032055630686 +qsubz:-688966709079205/74860741099180639,648207519211481,879845264372555/41946111313649477:-48525295274232840016387170795564/74860741099180639 +qsubz:166710353298975/16970305651247011,-698094548558201,213765522314/321157776265937:11846877862501969531938114086186/16970305651247011 +qsubz:49899180545856/2876267857739683,557467828819843,18059812167469/275257158459484:-1603426797758442090812218383913/2876267857739683 +qsubz:6692317961394/141734941248049,-441438992382050,647025798139055/12642657149192:62567329649867813522743081844/141734941248049 +qsubz:479537992567656/157885618980541,477496194629370,723421646353653/802564393977836:-75389782249910480040744521514/157885618980541 +qsubz:908470734681149/429897226733416,29178161829135,=1:-12543610851523044744852194011/429897226733416 +qsubz:77188802685248/7318291809111,-463455255292264,-108058346785819/1176426648669:3391700798694900254405702552/7318291809111 +qsubz:171404401104613/33934604643401,855275555777772,36574880343413/903775150870:-29023437846483581280861177959/33934604643401 +qsubz:-541340901900380/6622210685537,359991433354457,757631862823376/2232325778223:-2383939116662207278386288789/6622210685537 +qsubz:692469292076099/5877109446415,650562123345311,-533032945119773/2302096119676:-3823424800591835209803933966/5877109446415 +qsubz:-95311828811477/314989654006,189810882360044,-28308634395237/5347103791:-59788464161259140107747741/314989654006 +qsubz:698022114495799/176594100926,695874989112564,-126581470685793/77926271237:-122887418058525256076138465/176594100926 +qsubz:842269707991031/20902452297,641480824512781,-207378748871278/20625232021:-13408522332976363411316926/20902452297 +qsubz:90008215456199/31308617602,-364998910104603,7226822032963/10002572848:11427611301701797362478205/31308617602 +qsubz:-351501780974067/3968320430,622136787208291,55114547224579/2370456759:-2468838123284725621659197/3968320430 +qsubz:344449638260631/4282977544,558958638427895,637819877664383/3604552102:-2394007296067040109929249/4282977544 +qsubz:210466623353876/42415731,582912199285926,-497147675534948/306590031:-24724646831063605948030/42415731 +qsubz:159664413249106/959545307,-279292307566119,-653584191266708/745665815:267993623165934491902639/959545307 +qsubz:-392198737412127/18608647,672422899635821,-569033599510242/82909327:-12512880766238158956314/18608647 +qsubz:39300503655213/2721430,511724197547707,59370211633018/15974095:-1392621543631752605797/2721430 +qsubz:87754948235651/938752,383351463740417,375522385390265/6961414:-359871865534295703933/938752 +qsubz:41618261156437/401439,-114295722812862,220994573438802/7353641:45882802288533664855/401439 +qsubz:583595357599684/369917,-921858234302871,506477458084177/879257:341011616053972731391/369917 +qsubz:45271960096970/353353,134033050982156,449578874064836/569165:-47360935391737672098/353353 +qsubz:226890272517543/20945,-473968771427454,474551299506991/45887:9927502807820541573/20945 +qsubz:-684400875331106/63053,771762142119055,263139740728045/52269:-48662602747908106021/63053 +qsubz:34178215463647/1460,-574309051342644,-63579349430280/3001:838525393175723887/1460 +qsubz:304677119786896/7379,953072503508023,=1:-7032417326265914821/7379 +qsubz:690712418406353/551,-878220570482942,945308150006353/640:484590246754507395/551 +qsubz:563742800297603/343,-370471036590769,=1:127635308350931370/343 +qsubz:21771882327450/17,838540815832625,=1:-14233421986827175/17 +qsubz:-70429366835830/23,421029379926378,193588248726221/68:-9754105105142524/23 +qsubz:579884703987868/9,158994766699977,-448423246325295:-851068196311925/9 +qsubz:211206174985053/5,-931363857001162,111347832442520/3:4868025459990863/5 +qsubz:-1832545914230682/30139417405441315141,-2206272301963151,1860280227521645/86203654952388608222:66495761818931270288235871646138609/30139417405441315141 +qsubz:-2244126580089402/15802353325367691233,4284202352680604,9672828494536963/16956491871832558298:-67700479294430428930131058720034134/15802353325367691233 +qsubz:-2873054508761746/4018888696438887255,6328415852872821,1498506651106845/518044831134554573:-25433198937475240507570306781558101/4018888696438887255 +qsubz:7896973515418738/171152447613110907,28172470782975,2496184225627819/8379223243264936533:-4821787329815018407032286989587/171152447613110907 +qsubz:6171557047136737/153596772628473013,1680648096723096,-1368752415341766/146474119282103663:-258142123580853290414834522671511/153596772628473013 +qsubz:6110188097149881/174980302833168079,1110459252556,-1094629510180661/186263856652338951:-194308496296136243983761210043/174980302833168079 +qsubz:-3332313275107576/6438318281683471,7900787008515747,=1:-50867781436614198716281448225413/6438318281683471 +qsubz:-7156623476138575/60768468431925828,4848185091878538,2590883047783370/29043794443881857:-294616782707954363603301077218039/60768468431925828 +qsubz:6244864610487455/4441450329956024,4695453677641407,8682107496188525/1108836802236426:-20854624285853647226021740998313/4441450329956024 +qsubz:1214388452257501/8099557799286469,-7732646369856166,439856662355753/161507957350071:62631016214092712520853412275355/8099557799286469 +qsubz:152270808963307/225936249720782,5032164593494515,-3042221834459135/169235048654169:-1136948396231854028931589547423/225936249720782 +qsubz:2643724012201914/307126445994791,-693785933640383,=1:213080008080151385664497446867/307126445994791 +qsubz:-4268051553498140/95366069343373,-8287002357898623,-3054534942105489/17777545496443:790298841512051368610157377239/95366069343373 +qsubz:3485602780203412/25700401711199,7457017497637979,428269713159377/10715443614396:-191648345256732514829431823409/25700401711199 +qsubz:-8234491447936746/4919684964695,4149505619200689,=1:-20414260405707280268532611601/4919684964695 +qsubz:810546492778734/1537255953059,9694022516419974,9086115085796596/3823340626845:-14902193822453782061581221732/1537255953059 +qsubz:-5877831901958825/989824365981,-7295262013116067,170001713972327/26272141179:7221028096792006892537357902/989824365981 +qsubz:413656776972827/989269893760,7369973639327299,-436236958984308/162577127395:-7290893039190903982820781413/989269893760 +qsubz:3878951355242185/83694892558,3450947753988635,2108640605094263/15564008636:-288826701489471270922836145/83694892558 +qsubz:-2535073297478552/40453071523,4908538742513000,7101922105535221/34207081432:-198565468826829943054777552/40453071523 +qsubz:-2382309885993389/696509530,-1466852366874503,-2309936099592793/3712437025:1021676650248837767520201/696509530 +qsubz:7607952043533620/5686913259,6298086275997422,4940928909130479/2342224064:-35816670341687720578084678/5686913259 +qsubz:2927215245836138/37741447,-962144281698956,=1:36312720341309463665470/37741447 +qsubz:4910061305028263/340473560,8119898610953665,=1:-2764610782000388012569137/340473560 +qsubz:4067805811057167/37177673,5330125030512986,-1997223198941339/66900704:-198161641365721004704411/37177673 +qsubz:7759637046791302/19652141,-310036804999994,=1:6092894766686433878456/19652141 +qsubz:3919065179535201/3669449,-9390389769263598,2882022398896797/3976985:34457560267499719952703/3669449 +qsubz:716031381446830/216733,7947765435310961,=1:-1722542330059869063583/216733 +qsubz:4054967994410335/373802,525724563764829,3503712661359490/252721:-196512838416426199523/373802 +qsubz:9078916136353979/203034,-9146320842030949,-2957406411653994/351673:1857023184757048053245/203034 +qsubz:6377608393262961/38293,5049392078825515,=1:-193349993266072182934/38293 +qsubz:6441803794276323/46595,-7945891506343445,444633258633711/77876:370245256541867096098/46595 +qsubz:-31739640835113/134,9187216015631531,4944420675707143/1828:-1231118685735460267/134 +qsubz:9380863138336115/5303,6462848225018826,-6700633266931069/6325:-34263103274136498163/5303 +qsubz:-3097631232518591/9,-8171290453822216,-9196963695173/266:70443982851881353/9 +qsubz:1093336426937324/7,1050221975761222,4629256617357701/951:-6258217403391230/7 +qsubz:-347597167946897/2,7674954857028324,305176137974688:-15697506882003545/2 +qsubz:2328475415769504/79,272925582329873,-6102549509203995/38:-19232645588290463/79 +qsubz:2308509394585516,-3830045206470274,7003553193110811/4:6138554601055790 +qsubz:1732760946956491,1777160492223769,3345447948158671/5:-44399545267278 +qsubz:60622144360049674/33802404082907624055,-69039399995425550,51265382108255056/56157062688150984537:2333697696286865212886332363501654924/33802404082907624055 +qsubz:36134312588149621/46726106282722203568,88368419250610983,16599233636304207/89218481321406581495:-4129112149940203572739672031514437723/46726106282722203568 +qsubz:20529608710739058/363448886403849905,-38414609254761218,-28483290600430736/9731878244397435811:13961746955281991196780195397723348/363448886403849905 +qsubz:-21301556721438976/6513242985788039333,10185328317205357,19471190728639913/1019778013146869138:-66339518219986085639448723675745857/6513242985788039333 +qsubz:44545192250412223/556091898773307973,-68210916338593275,48338123621716519/630903301445119154:37931537983795590439601289412093798/556091898773307973 +qsubz:8756185550667068/221237800002764551,37082500190782117,-49571575251913483/428549478410686743:-8204050760810732298651341341667399/221237800002764551 +qsubz:1266875902956333/74065487263129243,82179201358611673,-22809095236679413/11512992706379829:-6086642591520386247198936144497206/74065487263129243 +qsubz:-3290636228641958/39922728219039171,27776924787657947,38458678927210417/47863542399556842:-1108930619058360556827999971083895/39922728219039171 +qsubz:-42130079299808296/8434875921605067,-11019950142983699,-23447400609379164/121422770092321:92951912118341475833697196994537/8434875921605067 +qsubz:4099885603797749/2435210469429361,74350793422542339,86927824732188143/8409742118553639:-181059830552954771443357588417630/2435210469429361 +qsubz:67669333773707083/272613019755061,-93798347274264096,-45708312696783257/349531962793823:25570650698471097774452720296939/272613019755061 +qsubz:90957430568123489/391120597363954,6192418291726731,47258016849281278/236338757046761:-2421982341387543639094949530885/391120597363954 +qsubz:9680926001959435/35332948152676,87479517830701337,69091152204102197/219079971218:-3090909267933256327145631368377/35332948152676 +qsubz:-2401057520785223/6794448427129,78594993607525862,9822515380715691/6307070974391:-534009630696870303660610695421/6794448427129 +qsubz:-35669437330800467/9924679089374,82178011946947185,7494777953306900/464563380743:-815590396776229150262403512657/9924679089374 +qsubz:11660103886719350/702376882271,76866897184391316,33851103741574544/1043053682715:-53989531594206620633040039286/702376882271 +qsubz:46821131628705451/862314840987,-23194527064543517,=1:20000984917477331879225436730/862314840987 +qsubz:161045881718771/27075945293,-43271044257960465,=1:1171604427099680375978560016/27075945293 +qsubz:-60112156053007651/36372620700,39791023371344653,1476360991693221/6530487026:-1447303800410866468595124751/36372620700 +qsubz:93025606850655363/57750297227,70375311017089745,-20809770167586319/6537747728:-4064195128586474843432981752/57750297227 +qsubz:66318318188267865/1763416382,-8494345308336372,25978643271663860/9056806641:14979067737403517739513969/1763416382 +qsubz:39872461457095153/7697794394,16021018477534333,-29038307872337798/2023268917:-123326506182661742052834049/7697794394 +qsubz:-10578481873157050/399979569,-74955252966976839,7152087282045522/102539471:29980569765438885423045341/399979569 +qsubz:78420049286413657/598935089,57793609900514480,71630428375584251/480499416:-34614620810975871938175063/598935089 +qsubz:-27519033180387711/13885085,57110868026002395,=1:-792989284483858645166286/13885085 +qsubz:112418468340001/301745,54405933003593985,=1:-16416718141750998663824/301745 +qsubz:9174319448294783/1062136,97028070754069006,=1:-103056997784124389462033/1062136 +qsubz:-11682605623507087/1833691,7208465426749752,42708279458013085/2810354:-13218109859447803001719/1833691 +qsubz:2812356728656513/534935,68388753901027584,97245878303468343/140699:-36583535255689461990527/534935 +qsubz:31551448030819707/330632,-80750562495416306,5621444274957506/269077:26698751530432514905099/330632 +qsubz:-33849467579218205/69497,60936973306267634,=1:-4234970683333260978303/69497 +qsubz:-10824831395257468/25447,96813598240824230,25910641834610055/22417:-2463626459265649438278/25447 +qsubz:4701573695056803/1438,20730190652622936,22128237033227327/2325:-29805312584776725165/1438 +qsubz:19342403188073667/1838,77710503528688069,-29951149360890159/1909:-142812563082540597155/1838 +qsubz:20926018629804348/149,51657522271692972,=1:-7676044799852448480/149 +qsubz:13573480210796164/447,33824716809070641,1445132915921588/9:-15106074933443780363/447 +qsubz:-42143315976323015/51,33391903738170435,=1:-1745130406623015200/51 +qsubz:-28698219386640759/13,83268075330816132,-49006503722648020/31:-1111183198687250475/13 +qsubz:12975981398542545,18975161321245933,550313867201012:-5999179922703388 +qsubz:-4164064005006797/3,12081203464497637,84626976109311453/4:-40407674398499708/3 +qsubz:-477106876207656134/7877944473247978593,-803086328922597207,311162678588479799/34146563555720051689:6326669506476782929117540896089933617/7877944473247978593 +qsubz:-465449358463997555/82259489098814668274,78609606376504442,23623692298759933/1909856158146778290:-6466386058790179182859588942381470663/82259489098814668274 +qsubz:55657155637787468/352243932662032145,931147756136809511,-706077458182178492/4890139950764490669:-327991147511056658341169010385943627/352243932662032145 +qsubz:-338412710404804019/9240924616405735378,180507301532576790,354994699428236406/1584136814505879965:-1668054366173361583178755373609480639/9240924616405735378 +qsubz:-278052766531165423/213589938382221126,-717335569765330249,327115671099490325/973040503527761492:153215660145552371350937879003474951/213589938382221126 +qsubz:319790079757993429/85843803189992002,129266654884522405,=1:-11096741280935559317469625781811381/85843803189992002 +qsubz:647723610543155092/95934901226294863,10437868520469255,655999718116549702/60165561163831581:-1001355885524269831096747212781973/95934901226294863 +qsubz:-490792959368504510/8839690905932849,780493070335457531,=1:-6899317495987951906756776145840329/8839690905932849 +qsubz:200230806231530877/534053235743650,574182776580143425,=1:-306644169740898654458247301470373/534053235743650 +qsubz:-415400268260899058/3432173800064079,-969417138049457063,=1:3327208102546448501242352298240919/3432173800064079 +qsubz:610500835640448509/244349286982576,-726909463539500534,141143959595247333/41552246570044:177619809116764391827142641144093/244349286982576 +qsubz:136794096998673790/125947220203517,501933222844173130,=1:-63217094145015905841679184224420/125947220203517 +qsubz:37195166234504707/4122583546869,350304198433672874,288669113811749979/50036393133086:-1444158324861755915971558426799/4122583546869 +qsubz:-220618681215838560/14377665800771,8868226871326041,=1:-127504402201563441934106016171/14377665800771 +qsubz:-178245325407305280/431875286797,92993296137381601,775757861791511902/3521879350061:-40161506439708276569913327277/431875286797 +qsubz:479413403799611117/2544433559696,571317426935469616,=1:-1453679234333296934118530585619/2544433559696 +qsubz:78548226516829117/75731440956,475186597103136792,372968862509778142/473438190991:-35986565721520216379222424035/75731440956 +qsubz:356871544245112943/457036865155,380199263690323829,=1:-173765079610907947968711165552/457036865155 +qsubz:164087683390841152/9866781011,414256053008139562,142080480091212971/28353008652:-4087373757348433175388616030/9866781011 +qsubz:-926767597190934385/71130390483,424803581672574937,997220370520185575/14320267108:-30216444643874005118080058956/71130390483 +qsubz:-508670075791922879/7201821098,217937729927638852,137262476496651971/1332969124:-1569548541951765573450022375/7201821098 +qsubz:708541217086167290/1270367493,137055529956144222,612951099738164089/8319475532:-174110889283632118162408156/1270367493 +qsubz:478290371375801493/32509979,-621018688752149419,=1:20189305008230285192353694/32509979 +qsubz:202407674710634402/98360799,438420143767171363,805524032483129161/407774601:-43123355436226170523964635/98360799 +qsubz:750240893218756098/12726925,682819412842796873,556437922516174385/42980509:-8690190705553419374149427/12726925 +qsubz:239662400690312894/37085945,-617903896056362368,=1:22915550144094372370030654/37085945 +qsubz:547526163264525237/6384643,925215752491576731,243367286469210971/2199851:-5907171730108914670016796/6384643 +qsubz:488339838572246377/8987524,833735135695423197,67144546497217911/577715:-7493214053366034100947851/8987524 +qsubz:54158926298615969/463896,903750262214101670,-323417221290610907/56479:-419246077481146609690351/463896 +qsubz:899979201562416758/19011,36874785972814972,333938930051256853/431121:-700126576927623015934/19011 +qsubz:251495623875326929/9839,122446851891915382,980630311370393757/34454:-1204503080140680116569/9839 +qsubz:586639670688982327/24017,-796132898656953871,-681706178572361176/45543:19121310466714750102134/24017 +qsubz:-102851779508569447/3820,-939797330665416187,=1:3589922951362381264893/3820 +qsubz:197733827323726961/1063,970508998896485514,-112039443168568153/1485:-1031453331999640374421/1063 +qsubz:798475189524604680/239,365694081282229859,=1:-86602410236928331621/239 +qsubz:142434970975405303/27,565787783866093670,80082655399847437/326:-15133835193409123787/27 +qsubz:814435903223223400/23,934520995176210672,824076522724149791/98:-20679546985829622056/23 +qsubz:-342004432352715490/61,708047941844384558,-893520674572963797/68:-43532928884860173528/61 +qsubz:188506043793261871/2,173381870849138370,457155699541150681/8:-158257697905014869/2 +qsubz:-195061562764744895,-579261672564430749,572618332809556695/7:384200109799685854 +qsubz:-5211865465872518894/11421997512267397151,9216468347981324231,-3730577014383987231/46090107429011417798:-105270478542533892972691061438449184775/11421997512267397151 +qsubz:443443414160163915/4491468994021274354,932514129347471790,=1:-4188358298450913632328975749705309745/4491468994021274354 +qsubz:275361187224379309/346698790548066715,-9688017663470973747,1805402917593442446/2385740059851766675:3358824006733693814162539396593910414/346698790548066715 +qsubz:1927916840762649449/644266943246233650,1019481372573774207,=1:-656818147604580167864072677502816101/644266943246233650 +qsubz:3969083678872801204/896572266795201101,6807779792226215707,=1:-6103666560158821383204536354397092203/896572266795201101 +qsubz:-865341312927331777/288496053508154740,8626492255839507491,1039454095259162685/156542247725866016:-2488708971428357042860912746744489117/288496053508154740 +qsubz:2279766799414118849/27989015333357246,61102716510638539,8643998670150313515/44107462445321072:-1710204869326040746987478648384745/27989015333357246 +qsubz:-9598524755027771179/55399943240765642,-815430339648713125,884311989519445007/53819690104622587:45174794533336946781627589986680071/55399943240765642 +qsubz:-2021737476156144347/2495236846065565,3202240405398277170,3178930774678872133/7381295168863952:-7990348249509715413422020018795397/2495236846065565 +qsubz:68053119707871158/578630692788811,737684984689589161,-7410529972742470086/9627432535163773:-426847173750840343829989219806413/578630692788811 +qsubz:2141868292014076693/328873136022248,-6454969195161975215,2185675198776140021/319490487602131:2122865962139927113433579878660013/328873136022248 +qsubz:6904094780152376715/105515417760572,9013725078444379686,=1:-951086967230996440142437656163677/105515417760572 +qsubz:986043406552959943/14107596810979,2995890298668631332,8819951421573670481/67954939364565:-42264812423539521185379288034085/14107596810979 +qsubz:-4371503587867387026/10407970809659,7789426111500215458,1611857228024591370/10701042327247:-81072119592494224995141074895848/10407970809659 +qsubz:128834428582928630/134708403993,8492912687875656470,-1262307966262698384/1518482758745:-1144066713435500610282261356080/134708403993 +qsubz:9450827094775890930/2700687301223,-6757147386255266788,6002877009556405644/1405277037833:18248942138561235652948359572654/2700687301223 +qsubz:-8388250355830908541/266466413258,2862142690442542385,=1:-762664896963214716421421848871/266466413258 +qsubz:-5619275429133115259/41783227722,-2163358989032247609,=1:90392121277550826819203901439/41783227722 +qsubz:9606560958482546016/29644869859,-7459227243081357178,9905446256945526764/20720077985:221127820879460752649388043918/29644869859 +qsubz:4930763186584321169/47984083979,6662837494722716160,551152931619292049/65568759475:-319710153880274018353836079471/47984083979 +qsubz:6701839224687506932/985583379,457687991137105386,3188171598044228633/792087660:-451089670130791153925472362/985583379 +qsubz:4977850203493279051/6143184950,3544412937261195005,5139590551055599222/1513126297:-21773984207790417170237895699/6143184950 +qsubz:2743230165777443647/888694730,494148490776673118,9757565623145649909/510318983:-439147156847452841121824493/888694730 +qsubz:-2143911698311688420/449171481,-6870034167785299997,639958345512727336/149888949:3085823419520813991370097137/449171481 +qsubz:-8533723636383149797/39725880,2768513107473221737,3141886070022952860/42371633:-109981628019631946320603357/39725880 +qsubz:-5314262731256470963/63761165,5833696012508623470,-7880529150937062671/68519301:-371963259327667136250013513/63761165 +qsubz:1681639872255718298/1514077,5997071385278801708,-6427612516373280573/8782472:-9080026170168899997925218/1514077 +qsubz:6099083259404780614/4192479,-5164344556388094262,-681054291106360636/3826929:21651412200504660448236112/4192479 +qsubz:8734142975627530613/432795,8347557484528703322,=1:-3612772407373624526714377/432795 +qsubz:9737081301281728277/751482,-1055406353334667048,=1:793128614297943544293413/751482 +qsubz:7681560095018293619/96421,-1078017997145375078,=1:103951254862849228689457/96421 +qsubz:9092804880201392539/52889,4169259379769360400,-5597148679483744113/49247:-220498866531741500803061/52889 +qsubz:-4754156917842901869/1537,-7603757415178737028,=1:11682220990211875910167/1537 +qsubz:-1492184829986224781/167,-4909822866544288080,-7885239837871971805/6814:818448233882909884579/167 +qsubz:-3561671662616934523/234,-1643132577230822696,=1:380931351409395576341/234 +qsubz:2224799941584138562/239,4895333498642631574,97344947199515758/161:-1167759906234004807624/239 +qsubz:7083599259933004607/80,7011559617335986001,1255271091090021783/31:-553841170126945875473/80 +qsubz:958854888905624023/33,5357637989296291879,-6913737981438705455/54:-175843198757872007984/33 +qsubz:-3476077523929127472,9908984532191635107,-6771898413854964869/5:-13385062056120762579 +qsubz:9188473183063801985/2,3589464423036032766,-2241566641820695587/2:2009544336991736453/2 +qsubz:41509521914914232161/2172094934845501331,95015472716989623433,=1:-206382627020524085395686379432876057162/2172094934845501331 +qsubz:-570614734467915216/612897350622429103,-29603844723095151643,717827408667935931/776625266995427534:18144117999022796755619629936333551013/612897350622429103 +qsubz:-27042524847598213145/9016861265984956672,61942065399081471006,-85599646530160700355/3483722943530240888:-558523010232084733112550144976532465177/9016861265984956672 +qsubz:26949534603425444509/3315837931819363899,1606604827685202950,-71919839549756914182/3712334721902834665:-5327241229082708837857932880292857541/3315837931819363899 +qsubz:41438250760107242789/99249508352697542,73974969596388490897,=1:-7341979362847306203122430732354032385/99249508352697542 +qsubz:87351178611540281996/61845876966812939,-91007621652632243823,19408679396333792502/44151394776784993:5628446171770955073811619296219507793/61845876966812939 +qsubz:4405917364991104531/771908998098153,64506590711703018448,53841168466232317214/53456487025575297:-49793217806998294835979616482622013/771908998098153 +qsubz:-9365617946363817493/26374061478484340,43990273202897382222,83764348600369483135/35424906140909763:-1160202169908537784737001508585220973/26374061478484340 +qsubz:-23473112900467700871/4618168111280368,15106111862258441004,38672462198241424645/4699633736186089:-69762564087716050528958198499110343/4618168111280368 +qsubz:-22186709781123392335/603508867935672,76634878648225439420,-26972666418343859759/2836755066733443:-46249828857378158866193511616382575/603508867935672 +qsubz:23848664713951836051/633837930342658,61700049658138946296,-28353020445764265473/310114901939234:-39107831777353989139731668388058717/633837930342658 +qsubz:2630510857358657218/37381246359883,-12240046954756473381,48743251697811443023/762346209014900:457548210672290050277093994431641/37381246359883 +qsubz:22881875543808933841/18718381442116,7150358297276988453,14651206458917400377/15752969059626:-133843134056206859479223810952707/18718381442116 +qsubz:1082979078922829695/1046984148841,-43275384717956071867,=1:45308641834697139731977743585842/1046984148841 +qsubz:21755828016468111169/5500110518439,18412344180922250307,63875503932039462805/8260608840523:-101269927898587827121167828799604/5500110518439 +qsubz:69011314837775177660/2882678720201,32263646636145101120,=1:-93005727594031047489899556547460/2882678720201 +qsubz:97885536037352108896/150601844165,4452732237850850724,=1:-670589686495399999211173316564/150601844165 +qsubz:22138505699176485607/252116416049,61532865941590224682,27472490489762575799/708864811:-15513445630395164712899324235811/252116416049 +qsubz:89674388203290664536/67784290823,-72266756979360926584,=1:4898550872013740444455898603168/67784290823 +qsubz:35131532657379157626/53215163647,19053685252752801749,28163327184395823897/32686497356:-1013944978768539369653403660977/53215163647 +qsubz:83869306682999924931/5573344090,99595425285705819332,=1:-555079574823255782969610022949/5573344090 +qsubz:-22687176270238560014/37602313,49747019891864444660,1536837876444207726/641869829:-1870603035478289271915058594/37602313 +qsubz:49755871830274632905/374641781,42438577123950343113,31092478152506184877/7732186:-15899264067066742469140771348/374641781 +qsubz:10982404440168695175/15660421,60671432520545031046,-27453714136445367576/288574235:-950140164962421895469735191/15660421 +qsubz:6775869043981190441/18805965,64780757548781992084,=1:-1218264652360010891780790619/18805965 +qsubz:44672679637496213080/48849753,95859623215842468974,18456416171029545998/4876557:-4682718872094290658793850342/48849753 +qsubz:-42152529057348698335/3235744,59925250634539284363,-3628407662598980249/15331:-193902812341735739490569407/3235744 +qsubz:52085283917127896710/9866863,38283604142633656357,4824692675957093036/5558115:-377739025136314829335701381/9866863 +qsubz:23591689782602478979/107299,69997830527239555546,79585026335134005520/792209:-7510673626052494468051275/107299 +qsubz:75522219291754027577/523942,98517292436821748408,-78467100165240534481/769278:-51617271711713968750356759/523942 +qsubz:-85486382965188732358/90271,23243020426810978176,=1:-2098256183331618999658054/90271 +qsubz:983479060786951655/34946,98005836915865207790,=1:-3424910993382764764477685/34946 +qsubz:35301842348289418558/1435,49016933196656116973,=1:-70303997294853238437697/1435 +qsubz:2632750748212302453/790,20382032741788103576,=1:-16099173115264389522587/790 +qsubz:-18891606196309322941/371,15238007397425687662,=1:-5672192350641239445543/371 +qsubz:22866847672127230662/17,21730312190117757012,30995020678487656037/5:-346548459559874638542/17 +qsubz:1126858518170848635,-611735474764215689,1160987006014179401/33:1738593992935064324 +qsubz:7067907915086579691/25,-28626674589646474416,=1:722734772656248440091/25 +qsubz:60995824276572751408/5,-94170815171282976513,=1:531849900132987633973/5 +qsubz:-26266792979830841992/9,26748623877696285585,-25180055821630578113/8:-267004407879097412257/9 Index: contrib/isl/imath/tests/qtodec.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/qtodec.t @@ -0,0 +1,1303 @@ +qtodec:3/29668193161647153598,10,8,0:0.00000000 +qtodec:1/2552439818325226004,8,24,0:0.000000000000000000003472 +qtodec:2/2729838301109816701,10,17,0:0.00000000000000000 +qtodec:-2/8398891633027131961,8,2,0:0.00 +qtodec:1/30929359245686845,10,17,0:0.00000000000000003 +qtodec:1/93965811021736277,4,4,0:0.0000 +qtodec:0,2,5,0:0.00000 +qtodec:6/83909376915228431,16,18,0:0.00000000000005270C +qtodec:-3/7079577697657177,33,15,0:-0.0000000000LDPIW +qtodec:-6/9174315766316507,8,5,0:0.00000 +qtodec:9/479356093905517,16,19,0:0.00000000000548E50ED +qtodec:7/272231567064361,2,0,0:0 +qtodec:5/47376768449307,10,11,0:0.00000000000 +qtodec:1/12288137207534,10,19,0:0.0000000000000813792 +qtodec:3/2308297858255,16,3,0:0.000 +qtodec:3/7879579455704,4,19,0:0.0000000000000000000 +qtodec:1/716028119691,8,6,0:0.000000 +qtodec:-7/176165656001,10,2,0:0.00 +qtodec:-2/79472074107,16,21,0:-0.000000001BAB9EA7B105E +qtodec:7/39648256931,10,3,0:0.000 +qtodec:4/9367226433,10,11,0:0.00000000042 +qtodec:4/5861792533,21,10,0:0.00000014H0 +qtodec:3/243862471,8,3,0:0.000 +qtodec:-5/892143793,16,23,0:-0.0000001812303B762B937DA +qtodec:-2/12767069,11,15,0:-0.00000030641A338 +qtodec:-1/10048225,25,3,0:0.000 +qtodec:-9/1466150,8,1,0:0.0 +qtodec:0,20,1,0:0.0 +qtodec:4/16203,10,13,0:0.0002468678639 +qtodec:5/580616,2,22,0:0.0000000000000000100100 +qtodec:-4/49429,10,8,0:-0.00008092 +qtodec:-5/74444,2,7,0:0.0000000 +qtodec:-2/437,10,9,0:-0.004576659 +qtodec:-6/2737,4,17,0:-0.00002033222223022 +qtodec:2/295,16,18,0:0.01BC4FD65883E7B3A2 +qtodec:-1/41,13,18,0:-0.04177C08322B136459 +qtodec:0,8,11,0:0.00000000000 +qtodec:1/90,8,11,0:0.00554055405 +qtodec:3,16,7,0:3.0000000 +qtodec:1/5,10,16,0:0.2000000000000000 +qtodec:27/28225889819425315955,10,14,0:0.00000000000000 +qtodec:97/39183286035001818490,16,11,0:0.00000000000 +qtodec:-35/3702072548595294917,10,20,0:-0.00000000000000000945 +qtodec:37/8652786483007175262,16,10,0:0.0000000000 +qtodec:41/181598573551235020,23,14,0:0.000000000004LI +qtodec:15/600082766020339676,16,13,0:0.0000000000000 +qtodec:-9/2722110669597035,16,10,0:0.0000000000 +qtodec:57/47186773574985517,4,12,0:0.000000000000 +qtodec:0,8,15,0:0.000000000000000 +qtodec:38/8249095374399173,10,12,0:0.000000000000 +qtodec:86/135104489739753,30,7,0:0.0000000 +qtodec:-23/99519784680918,16,16,0:-0.0000000000410D37 +qtodec:17/35672209854079,10,3,0:0.000 +qtodec:56/46540343251387,8,11,0:0.00000000000 +qtodec:0,16,1,0:0.0 +qtodec:-59/6929353087150,8,13,0:-0.0000000000004 +qtodec:79/932785444169,16,2,0:0.00 +qtodec:-39/53188416323,8,10,0:0.0000000000 +qtodec:70/56574330991,10,12,0:0.000000001237 +qtodec:-83/19562860498,22,23,0:-0.000000ACI2EFKHH9BB0IH2B +qtodec:13/307883133,16,18,0:0.000000B55992EED238 +qtodec:11/573365410,10,14,0:0.00000001918497 +qtodec:-89/983323622,8,20,0:-0.00000001411360322773 +qtodec:-27/872316667,10,14,0:-0.00000003095206 +qtodec:23/38939829,18,17,0:0.0000121AHFG008FEF +qtodec:10/15277977,33,22,0:0.0000PKABC0QM81FH6PKCEH +qtodec:10/731501,8,10,0:0.0000034526 +qtodec:6/1029065,10,15,0:0.000005830535486 +qtodec:49/332590,16,17,0:0.0009A7C345BF4128D +qtodec:50/776461,8,1,0:0.0 +qtodec:2/479,10,16,0:0.0041753653444676 +qtodec:43/1929,16,15,0:0.05B4E2ABBA75950 +qtodec:-3/4439,2,0,0:0 +qtodec:-77/3511,16,1,0:0.0 +qtodec:-3/73,2,22,0:-0.0000101010000101010000 +qtodec:-11/574,4,21,0:-0.001032133222211322030 +qtodec:85/7,30,12,0:C.48H48H48H48H +qtodec:17/4,8,21,0:4.200000000000000000000 +qtodec:-61/8,16,1,0:-7.A +qtodec:81/2,16,0,0:28 +qtodec:-223/7523256159150326952,19,11,0:0.00000000000 +qtodec:492/63927532590023633933,10,7,0:0.0000000 +qtodec:-488/4671427241940113665,10,11,0:0.00000000000 +qtodec:869/1536545359977443591,16,13,0:0.0000000000002 +qtodec:255/990950541390055304,35,10,0:0.0000000000 +qtodec:314/865017777698304039,10,21,0:0.000000000000000362998 +qtodec:397/94739791379991670,4,10,0:0.0000000000 +qtodec:197/49947954439637722,10,12,0:0.000000000000 +qtodec:4/2294468349351839,10,1,0:0.0 +qtodec:465/3028494196809779,11,17,0:0.00000000000053342 +qtodec:441/948226064615029,10,9,0:0.000000000 +qtodec:415/205250226057042,8,4,0:0.0000 +qtodec:-7/17462466865516,16,18,0:-0.000000000070D4FD1C +qtodec:608/28239839509857,8,12,0:0.000000000001 +qtodec:-223/866713738143,10,22,0:-0.0000000002572937178517 +qtodec:563/7786288255956,8,1,0:0.0 +qtodec:-919/714101559956,4,11,0:0.00000000000 +qtodec:-835/607709250842,10,7,0:0.0000000 +qtodec:-734/88891360337,16,6,0:0.000000 +qtodec:41/3074329077,10,10,0:0.0000000133 +qtodec:-34/7345250185,8,9,0:0.000000000 +qtodec:142/2351029685,16,14,0:0.00000103697A0A +qtodec:34/31175165,8,8,0:0.00000022 +qtodec:-96/319314395,16,17,0:-0.0000050B41B8D426F +qtodec:948/10607737,16,12,0:0.0005DB5BC777 +qtodec:47/24044059,35,24,0:0.0002WNBVR50LE0WRKG58RQLQ +qtodec:535/6095688,10,7,0:0.0000877 +qtodec:486/1456495,10,6,0:0.000333 +qtodec:373/978875,8,11,0:0.00014370747 +qtodec:6/6211,16,7,0:0.003F4F4 +qtodec:685/2168,4,0,0:0 +qtodec:-88/41285,4,1,0:0.0 +qtodec:168/2015,8,2,0:0.05 +qtodec:-257/2002,16,21,0:-0.20DCF6899725153A0DCF6 +qtodec:89/871,5,6,0:0.022341 +qtodec:499/295,2,3,0:1.101 +qtodec:587/48,4,5,0:30.03222 +qtodec:155/24,10,16,0:6.4583333333333333 +qtodec:199/9,4,16,0:112.0130130130130130 +qtodec:-106,8,2,0:-152.00 +qtodec:-2933/29115963383147957058,10,2,0:0.00 +qtodec:1529/24516687344881033558,4,16,0:0.0000000000000000 +qtodec:-8335/3596290216553914092,10,2,0:0.00 +qtodec:1923/868496977516837484,10,2,0:0.00 +qtodec:9839/964058578172332209,2,23,0:0.00000000000000000000000 +qtodec:6976/372390689442127831,4,16,0:0.0000000000000000 +qtodec:-5619/82130008401991793,16,19,0:-0.00000000001341E2F2A +qtodec:-793/7362155502859746,10,10,0:0.0000000000 +qtodec:-4999/903131924743945,8,11,0:0.00000000000 +qtodec:-9413/1178970988260896,10,8,0:0.00000000 +qtodec:7323/311224385698598,10,22,0:0.0000000000235296472143 +qtodec:-9700/190189472805017,22,7,0:0.0000000 +qtodec:2239/31441940161082,16,18,0:0.000000004E4C01D373 +qtodec:7871/77670518853986,15,19,0:0.000000003D68421BBCA +qtodec:2122/2157192364211,16,24,0:0.00000004399300DABE38D2A1 +qtodec:28/69260597489,10,18,0:0.000000000404270263 +qtodec:4611/328096450714,4,18,0:0.000000000000033011 +qtodec:-8445/771625180456,16,17,0:-0.0000002F0187FDD06 +qtodec:6104/31076369717,6,7,0:0.0000000 +qtodec:-5146/99207462261,16,19,0:-0.000000DEC8E01BF79F7 +qtodec:6599/8951560744,10,14,0:0.00000073718988 +qtodec:9817/9012958484,4,15,0:0.000000000102101 +qtodec:103/2508067,10,1,0:0.0 +qtodec:160/346307341,4,15,0:0.000000000013300 +qtodec:-6972/39670075,8,20,0:-0.00005604455467641370 +qtodec:-4197/45941168,2,7,0:0.0000000 +qtodec:-4076/9631149,16,5,0:-0.001BB +qtodec:-6082/452297,16,8,0:-0.037141D2 +qtodec:3422/343607,10,20,0:0.00995905205656462179 +qtodec:2255/505667,2,4,0:0.0000 +qtodec:393/6293,16,1,0:0.0 +qtodec:235/511,8,6,0:0.353353 +qtodec:1809/3322,8,10,0:0.4266367156 +qtodec:-751/3630,10,5,0:-0.20688 +qtodec:1444/297,16,14,0:4.DCA8F158C7F91A +qtodec:-175/18,10,10,0:-9.7222222222 +qtodec:-1745/2,10,10,0:-872.5000000000 +qtodec:-7930/67,2,18,0:-1110110.010110111011001110 +qtodec:3077/4,2,21,0:1100000001.010000000000000000000 +qtodec:-3053/2,2,20,0:-10111110110.10000000000000000000 +qtodec:21182/2833372713644414301,16,20,0:0.0000000000021AB1F123 +qtodec:45387/14250357568649348800,10,19,0:0.0000000000000031849 +qtodec:-13863/3176447931757610564,16,21,0:-0.0000000000013A7B4A19F +qtodec:51053/6071062782227045417,4,2,0:0.00 +qtodec:48153/204469188404773127,26,12,0:0.000000001769 +qtodec:-35643/103256682364442069,8,14,0:-0.00000000000001 +qtodec:54071/11780111475151984,4,10,0:0.0000000000 +qtodec:40181/97271345682485899,16,15,0:0.00000000007445A +qtodec:63074/426635952224589,27,6,0:0.000000 +qtodec:37487/5041371975161711,10,7,0:0.0000000 +qtodec:33690/403332722546693,29,23,0:0.0000001CMM80DDDLOISN2P1 +qtodec:-32096/929352974579813,10,23,0:-0.00000000003453585545848 +qtodec:27697/5399115155752,8,13,0:0.0000000005404 +qtodec:43081/77103958462682,2,0,0:0 +qtodec:76092/2192729147447,10,15,0:0.000000034701960 +qtodec:40520/1057974855979,4,10,0:0.0000000000 +qtodec:-93832/180749201941,4,21,0:-0.000000000020231122031 +qtodec:15613/112650436297,10,22,0:0.0000001385968888645643 +qtodec:-15981/2114647337,8,16,0:-0.0000017662447224 +qtodec:-2956/48741428353,8,24,0:-0.000000010107463123137573 +qtodec:36488/7263916629,10,6,0:0.000005 +qtodec:17486/4731824201,33,11,0:0.0004CKGBDNA +qtodec:87479/200379782,2,0,0:0 +qtodec:-21070/435273677,4,21,0:-0.000000030230013321132 +qtodec:-22652/26779223,16,7,0:-0.00376F8 +qtodec:88608/32268761,16,23,0:0.00B3F52FA37144F68F26E67 +qtodec:31998/3038585,4,10,0:0.0002230202 +qtodec:-8472/444571,10,14,0:-0.01905657364065 +qtodec:34267/677762,10,24,0:0.050559045800738312268908 +qtodec:-92699/231514,16,22,0:-0.6680D6DAC04F671A8CA61A +qtodec:36031/70412,4,3,0:0.200 +qtodec:98/63775,8,24,0:0.000622645765407600507635 +qtodec:-65898/3023,10,11,0:-21.79887528944 +qtodec:7561/977,16,22,0:7.BD2EE71B83467C335B7281 +qtodec:-37137/52,10,8,0:-714.17307692 +qtodec:-88738/631,21,8,0:-6E.D536IE1D +qtodec:67918/13,10,20,0:5224.46153846153846153846 +qtodec:-20668/21,8,20,0:-1730.14141414141414141414 +qtodec:-72712/5,16,11,0:-38CE.66666666666 +qtodec:45492,2,7,0:1011000110110100.0000000 +qtodec:296304/46496256563281536829,23,10,0:0.0000000000 +qtodec:-319725/3061659936699002531,4,23,0:-0.00000000000000000000013 +qtodec:-702855/9285437245836392212,10,4,0:0.0000 +qtodec:-199215/2284481803901388209,12,10,0:0.0000000000 +qtodec:199669/333012758422549802,8,4,0:0.0000 +qtodec:486363/473044697601679021,10,17,0:0.00000000000102815 +qtodec:-825841/23059317823282264,7,9,0:0.000000000 +qtodec:117332/24561684169423891,10,11,0:0.00000000000 +qtodec:-281263/409628091879471,10,19,0:-0.0000000006866301544 +qtodec:63007/1228412979569096,10,9,0:0.000000000 +qtodec:102915/195471522013601,2,19,0:0.0000000000000000000 +qtodec:-93162/25115626353389,4,5,0:0.00000 +qtodec:338038/29004229856357,16,17,0:0.000000320E91B972B +qtodec:439672/13350641833293,27,21,0:0.00000CKD439M189BCG4PN +qtodec:-1085/288156538958,28,0,0:0 +qtodec:15999/3935036028619,11,22,0:0.0000000096501919328434 +qtodec:958486/806510801671,16,0,0:0 +qtodec:24222/167944894493,10,15,0:0.000000144225878 +qtodec:90199/33724326940,16,16,0:0.00002CDF4F08A894 +qtodec:798735/74124476497,10,20,0:0.00001077559043580330 +qtodec:276215/643447444,10,5,0:0.00042 +qtodec:-877491/8506905787,2,17,0:-0.00000000000001101 +qtodec:622736/862215415,2,9,0:0.000000000 +qtodec:48302/90081849,18,8,0:0.00325372 +qtodec:996595/91668012,16,21,0:0.02C87E4CDFA1A8C2484B9 +qtodec:10754/13902389,4,9,0:0.000003022 +qtodec:424209/505345,31,11,0:0.Q0LRENN7438 +qtodec:198628/7370669,10,13,0:0.0269484357525 +qtodec:906593/696606,10,19,0:1.3014429964714630652 +qtodec:63392/486251,16,14,0:0.215FDAEB4E8BAF +qtodec:775986/96101,8,4,0:10.0461 +qtodec:985049/21250,17,1,0:2C.6 +qtodec:-284525/1208,10,4,0:-235.5339 +qtodec:933244/2529,10,20,0:369.01700276789244760775 +qtodec:719857/48,8,6,0:35225.012525 +qtodec:-26991/715,32,2,0:-15.NV +qtodec:-59177/2,10,20,0:-29588.50000000000000000000 +qtodec:833931/65,8,0,0:31035 +qtodec:283969/4,10,9,0:70992.250000000 +qtodec:692243/9,13,10,0:29017.B72B72B72B +qtodec:2220425/82098663244722404628,2,19,0:0.0000000000000000000 +qtodec:1332706/24886222077598879681,30,8,0:0.00000000 +qtodec:3722825/2026604562916823564,27,7,0:0.0000000 +qtodec:293817/19154085506889290,8,22,0:0.0000000000010335564623 +qtodec:-2328299/361670841450282499,10,4,0:0.0000 +qtodec:6148084/561670125531460687,33,17,0:0.0000000FD0POOHRUD +qtodec:-6433247/6864670391549153,16,4,0:0.0000 +qtodec:5175613/4620647601293887,16,8,0:0.00000004 +qtodec:2667155/2429659044108081,17,20,0:0.00000007B30FD7461E0A +qtodec:681343/9032805224095139,10,9,0:0.000000000 +qtodec:5863994/174238841171323,10,15,0:0.000000033654918 +qtodec:8643703/353914077710020,10,10,0:0.0000000244 +qtodec:5346661/34799692977081,10,0,0:0 +qtodec:5106120/19563121357247,2,24,0:0.000000000000000000000100 +qtodec:6183913/2383366879745,2,8,0:0.00000000 +qtodec:518571/148387088269,4,4,0:0.0000 +qtodec:-3361270/733528692901,16,24,0:-0.00004CE0F4509B06F00B6586 +qtodec:1562255/21178801269,10,21,0:0.000073765034203645702 +qtodec:3467363/42461659020,10,21,0:0.000081658679383366213 +qtodec:-9936449/10071886359,4,11,0:-0.00001000221 +qtodec:-3336987/9840159415,10,18,0:-0.000339119201149649 +qtodec:2604333/1086112640,15,22,0:0.00815CEC195D2CA7051D65 +qtodec:7503718/882484091,10,16,0:0.0085029498849061 +qtodec:4474267/384881278,10,10,0:0.0116250575 +qtodec:712293/1045276,8,2,0:0.53 +qtodec:-272327/2700287,10,16,0:-0.1008511317500695 +qtodec:3101476/3471127,16,21,0:0.E4BCDE9EB583017073130 +qtodec:3127691/6558689,10,20,0:0.47687746743289703170 +qtodec:41313/916,16,17,0:2D.19FDC3A2189808F17 +qtodec:590136/11795,16,10,0:32.0860B6A96C +qtodec:3688335/27739,16,21,0:84.F736CF72645AD9608B190 +qtodec:430927/16465,10,14,0:26.17230488915882 +qtodec:6193621/6249,10,24,0:991.137942070731317010721715 +qtodec:6881703/4802,4,1,0:112121.0 +qtodec:-3142168/979,10,7,0:-3209.5689479 +qtodec:-3176297/326,10,20,0:-9743.24233128834355828220 +qtodec:6271672/3,10,7,0:2090557.3333333 +qtodec:-2915894/79,10,18,0:-36910.050632911392405063 +qtodec:654753,16,2,0:9FDA1.00 +qtodec:-6358267/9,4,15,0:-2230132222.013013013013013 +qtodec:-18678516/29688438786197957,16,22,0:-0.00000002B3C24F9A0699C5 +qtodec:-5100140/10011896485948009711,16,1,0:0.0 +qtodec:-63971979/5765059347475183331,16,20,0:-0.000000000C3363110E8A +qtodec:49592178/2236069654488181723,16,23,0:0.000000001862A177C1DD31F +qtodec:70399774/240687813855844671,2,14,0:0.00000000000000 +qtodec:45825874/963387555556851547,16,15,0:0.00000000344D0AD +qtodec:-7101885/38297123998463233,35,6,0:0.000000 +qtodec:45706162/20208127584234763,8,23,0:0.00000000023333300051317 +qtodec:-4603037/752013415132706,10,9,0:-0.000000006 +qtodec:-33461502/9204850740162821,16,15,0:-0.0000000F9CF2B5A +qtodec:17754722/53304375179261,16,15,0:0.000005969369127 +qtodec:-38722845/596630162922919,22,24,0:-0.0000077JCJJ5DGKGF1H14836 +qtodec:68992640/66560021807813,8,5,0:0.00000 +qtodec:14264823/17373344136937,10,2,0:0.00 +qtodec:12383615/9923197741689,16,17,0:0.000014EFE3254D306 +qtodec:-67431335/7690429580523,16,6,0:-0.000093 +qtodec:4367596/64156078187,16,15,0:0.000476275848D8E +qtodec:20810847/488563827005,16,17,0:0.0002CAA4454B3E427 +qtodec:-22478409/38544781642,10,5,0:-0.00058 +qtodec:36702575/69781180501,24,3,0:0.007 +qtodec:65365649/26951426,16,8,0:2.6CE15346 +qtodec:13356174/2840415263,29,12,0:0.03RJM9IFG27A +qtodec:47208715/178421993,10,21,0:0.264590223470937240343 +qtodec:7539463/119654423,24,13,0:0.1C717ALE7IC94 +qtodec:-43582754/39677013,2,15,0:-1.000110010011001 +qtodec:-57528557/8850837,5,6,0:-11.222214 +qtodec:47234381/8936103,10,1,0:5.2 +qtodec:33301301/106817,4,20,0:10313.30022203221331330110 +qtodec:81045865/711846,16,16,0:71.DA63F30882704AB2 +qtodec:91094596/828431,4,13,0:1231.3311313002012 +qtodec:40293131/48303,8,20,0:1502.13126064102265372300 +qtodec:-181649/70,8,6,0:-5042.770537 +qtodec:45546885/4774,10,1,0:9540.6 +qtodec:828359/734,31,12,0:15C.H5QUJ6M5B8HO +qtodec:-59718139/406,16,16,0:-23E91.032717F5E94CED15 +qtodec:2679103/162,4,10,0:10002121.2230033303 +qtodec:12366443/53,8,10,0:707561.0717545336 +qtodec:34041109/25,4,7,0:11030123230.1130022 +qtodec:-42857879/3,4,13,0:-312133302013.2222222222222 +qtodec:-16602037/6,10,15,0:-2767006.166666666666666 +qtodec:201634836/47285863779715310669,8,2,0:0.00 +qtodec:744820415/27255853323214067023,2,1,0:0.0 +qtodec:-625328361/8980450114346406298,4,0,0:0 +qtodec:403756951/6617643244507173155,16,12,0:0.000000004315 +qtodec:-426683165/783310053429126211,16,23,0:-0.0000000256EC83CE37DE9A6 +qtodec:787333919/76979591766305433,10,11,0:0.00000001022 +qtodec:661348691/70208895966253883,16,20,0:0.000000287519ABAB23C0 +qtodec:280056103/19236376368074700,8,12,0:0.000000001750 +qtodec:7656653/5938020515370151,16,3,0:0.000 +qtodec:-208421697/1757008688014187,8,19,0:-0.0000000177275547023 +qtodec:246570074/100899135942843,34,13,0:0.0003912R3IHWN +qtodec:113230062/65743402595005,10,7,0:0.0000017 +qtodec:70543944/10849645138255,10,19,0:0.0000065019586448286 +qtodec:642672567/24971850717497,10,5,0:0.00002 +qtodec:-314721695/752512751681,8,6,0:-0.000155 +qtodec:-163807291/5886020608,8,4,0:-0.0161 +qtodec:438467533/52265645624,20,6,0:0.037259 +qtodec:498074863/824377038073,16,4,0:0.0027 +qtodec:-27700104/49948246387,10,14,0:-0.00055457610634 +qtodec:141171374/99253478457,4,5,0:0.00001 +qtodec:-361755751/3656937423,4,14,0:-0.01211103001233 +qtodec:22816939/611768152,4,22,0:0.0021203010123303032113 +qtodec:-53856232/403256995,4,11,0:-0.02020300202 +qtodec:449484375/227346169,10,2,0:1.97 +qtodec:217806981/3021451,16,19,0:48.163DE229590DF0963DD +qtodec:250860083/22259097,10,17,0:11.27000268699130068 +qtodec:431639694/8164765,22,23,0:28.J14GK2EE5A85EIDALF8872L +qtodec:-39808798/57615,8,20,0:-1262.74366630432236034771 +qtodec:7210334/8793,8,10,0:1464.0042361134 +qtodec:-90699159/75166,16,16,0:-4B6.A6C208F34F5CA17D +qtodec:-190010/41897,2,13,0:-100.1000100100000 +qtodec:-37292046/12725,4,21,0:-231302.213031123013102122123 +qtodec:-827038151/3021,16,21,0:-42D63.0AD8C3EB52CA876A2DEDD +qtodec:-263139079/9216,2,19,0:-110111110001000.0110101011011100011 +qtodec:859020523/138,8,13,0:27575622.3140355346016 +qtodec:-50892458/33,4,12,0:-11320200303.230212302123 +qtodec:207612373/7,10,7,0:29658910.4285714 +qtodec:35998064/9,10,13,0:3999784.8888888888888 +qtodec:424044905/4,10,2,0:106011226.25 +qtodec:493019,10,13,0:493019.0000000000000 +qtodec:-4042513085/15637696512520985642,10,22,0:-0.0000000002585107775792 +qtodec:6403629722/13409004049280473687,10,14,0:0.00000000047756 +qtodec:4310949661/9182204608528567055,2,12,0:0.000000000000 +qtodec:-6207213301/7937357727791570577,26,7,0:-0.0000006 +qtodec:-5492618011/924682356235504554,10,14,0:-0.00000000594000 +qtodec:8192041323/632108923605970228,7,1,0:0.0 +qtodec:-186147758/5553753716846915,31,20,0:-0.00000TN4N56ODGNH7IPI +qtodec:5752674759/45700966145683610,31,19,0:0.00003IM5RCTBI6HUEBC +qtodec:1348886735/4229222108363968,4,20,0:0.00000000001111213123 +qtodec:-991251339/2657176318638922,10,1,0:0.0 +qtodec:8018307442/898724497172469,16,0,0:0 +qtodec:2014050707/340069109236288,16,18,0:0.0000635CD5D59A22E0 +qtodec:4505135732/39991791916081,10,7,0:0.0001126 +qtodec:6453084395/58624215198992,10,17,0:0.00011007540780027 +qtodec:-1804902629/2765243734591,10,16,0:-0.0006527101413962 +qtodec:2151190453/5551909474614,16,4,0:0.0019 +qtodec:725818559/82908634105,4,2,0:0.00 +qtodec:3396663851/192565119374,8,0,0:0 +qtodec:411464751/68497491776,8,15,0:0.003046546407536 +qtodec:331510163/2781814914,8,21,0:0.075007644307123546602 +qtodec:6307596319/2688917842,16,11,0:2.5884B649AE6 +qtodec:-9200062729/3512239660,4,3,0:-2.213 +qtodec:2884984405/325651823,3,8,0:22.21201202 +qtodec:1305611221/700300760,10,8,0:1.86435785 +qtodec:1587226477/40056887,4,16,0:213.2133310223222233 +qtodec:34378367/11734676,30,22,0:2.RQK7MSK4KA6QIJ9KADGNRK +qtodec:7518884673/9949274,7,15,0:2126.502424542621013 +qtodec:3931084199/1830484,10,10,0:2147.5654520880 +qtodec:-2575482611/282998,22,10,0:-IHE.FD9E9AGG86 +qtodec:-1417727301/197914,10,14,0:-7163.35024808755317 +qtodec:3672290/691,8,14,0:12302.35211047212436 +qtodec:8228518089/35371,30,13,0:8IEE.HL4JRHM3K3LL1 +qtodec:410532666/2941,16,24,0:22145.7B57D42113C25F3A3BB688A9 +qtodec:8394604490/1573,8,21,0:24267154.265477753126202662152 +qtodec:7379334711/332,31,2,0:O22T4.O5 +qtodec:-2823493053/70,2,0,0:-10011001110111100011111111 +qtodec:2377080339/46,8,24,0:305101013.426205441310262054413102 +qtodec:419615836/45,10,23,0:9324796.35555555555555555555555 +qtodec:8359035220,4,24,0:13302033030011110.000000000000000000000000 +qtodec:2211961894/3,8,5,0:5374517267.25252 +qtodec:3722836622/14480498279571705649,16,0,0:0 +qtodec:65111863307/11533490001438870777,10,19,0:0.0000000056454605933 +qtodec:5949898539/1696780621152707101,8,11,0:0.00000000036 +qtodec:56815400197/1686789806569317842,10,11,0:0.00000003368 +qtodec:90925627747/25695775444577271,16,1,0:0.0 +qtodec:-27535487045/285845335283069982,10,8,0:-0.00000009 +qtodec:15775413556/25311693641355547,8,4,0:0.0000 +qtodec:-2057810676/17252279485169683,8,10,0:-0.0000000200 +qtodec:85387309833/8636897486832992,10,20,0:0.00000988634054800042 +qtodec:716266208/466095180147391,16,22,0:0.000019C83D60B83CEE8EE7 +qtodec:43248451649/397132885993682,8,6,0:0.000034 +qtodec:-45534175087/316387723492611,10,5,0:-0.00014 +qtodec:-47173726353/7171454234480,10,11,0:-0.00657798611 +qtodec:297529128/678060165163,8,5,0:0.00016 +qtodec:-6512811254/5361725734445,8,6,0:-0.000476 +qtodec:-20777019927/2016234688361,4,22,0:-0.0002220311123210221201 +qtodec:-947693138/3599271747,2,24,0:-0.010000110110011110110111 +qtodec:22262357967/226160142878,10,16,0:0.0984362570862418 +qtodec:82037055923/64093321236,4,17,0:1.10132223220113313 +qtodec:16205375896/9742150071,10,22,0:1.6634290970572752532996 +qtodec:97719092318/5262332763,10,12,0:18.569538780419 +qtodec:-49761904323/530474551,8,19,0:-135.6346771114202260241 +qtodec:33397252622/403519053,16,11,0:52.C3D6BF6B7B6 +qtodec:695492668/55458573,16,23,0:C.8A6F439434C6E70775E0AAB +qtodec:75005050378/73364577,7,5,0:2660.23445 +qtodec:29030528543/40315167,10,15,0:720.089502370162574 +qtodec:31369038993/5743048,2,5,0:1010101010110.00010 +qtodec:39339254427/4936337,16,16,0:1F21.52312B564042C6B3 +qtodec:37009536016/100485,30,9,0:DJ6T.1P2MILPAG +qtodec:1551216144/205609,10,8,0:7544.49534796 +qtodec:99143355445/6654,10,8,0:14899812.96137661 +qtodec:893556747/43649,4,15,0:10333313.122133133133000 +qtodec:-32107553839/5925,26,21,0:-BM86O.B3HIL8OGDBF29CN87DEB6 +qtodec:40475869854/7411,10,21,0:5461593.557414653892861961948 +qtodec:-21388883933/385,16,0,0:-34FB5D6 +qtodec:23566612035/406,4,14,0:3131123112102.13031203220002 +qtodec:-94254132457/78,8,23,0:-11001501411.43220322032203220322032 +qtodec:55429871241/94,2,1,0:100011001001011100101101111001.0 +qtodec:81069744134/9,10,14,0:9007749348.22222222222222 +qtodec:-63777906131/8,16,5,0:-1DB2EB3BA.60000 +qtodec:22636846283/8589275715769980395,16,4,0:0.0000 +qtodec:451030208027/11667920285394363609,2,13,0:0.0000000000000 +qtodec:-396336330142/9218513566402258373,8,6,0:0.000000 +qtodec:-812297708247/6583818474797492140,10,17,0:-0.00000012337790164 +qtodec:65812963138/110962035363701723,4,16,0:0.0000000000213303 +qtodec:-367081998292/90608900002645629,8,22,0:-0.0000010376016446422266 +qtodec:765068976289/27117928920114978,4,23,0:0.00000001312111101312131 +qtodec:466163950691/74887899881824511,21,19,0:0.000148I9D04GG13GACA +qtodec:2881317737/21976075689165,4,1,0:0.0 +qtodec:17255779745/25462798741843,16,23,0:0.002C69AEC9C156BD44A08C5 +qtodec:53125954797/33441637786834,2,13,0:0.0000000001101 +qtodec:43895010407/151886174379178,10,1,0:0.0 +qtodec:-251294209230/63991299908567,16,24,0:-0.01015C39B4D2F68935F6E4BE +qtodec:955590711151/37535044163376,10,6,0:0.025458 +qtodec:174878212849/3669903179355,7,21,0:0.022226131634650361136 +qtodec:-157330267554/4348224760679,3,12,0:-0.000222101011 +qtodec:459430618651/21414547740,10,19,0:21.4541359560367722246 +qtodec:34869089840/299703846887,10,8,0:0.11634515 +qtodec:745844090051/5002251143,3,7,0:12112.0022020 +qtodec:466911780262/26884443459,2,21,0:10001.010111100000101100111 +qtodec:815254747041/5076712349,10,16,0:160.5871459708736789 +qtodec:-481092000475/9125040392,10,17,0:-52.72217763515626967 +qtodec:148261988694/154485473,10,2,0:959.71 +qtodec:87399306218/237779763,8,23,0:557.44064516575231734633261 +qtodec:554983007393/9392637,10,12,0:59087.028210820880 +qtodec:-959429967314/73223417,10,23,0:-13102.77513154022844904929798 +qtodec:594089636023/951818,10,18,0:624163.060609276143128203 +qtodec:271932654628/1030467,10,22,0:263892.6376371101646146844100 +qtodec:381378480415/45628,10,8,0:8358430.79720785 +qtodec:157468278507/203998,4,1,0:2330131012.3 +qtodec:-195533395495/7408,16,4,0:-192C110.CCD2 +qtodec:-101137757753/54175,4,16,0:-13013301313.1210302022313232 +qtodec:236424674428/8301,10,2,0:28481469.03 +qtodec:44997066682/681,8,22,0:374034553.6221666243714700060074 +qtodec:49672355883/11,10,17,0:4515668716.63636363636363636 +qtodec:-156344022343/116,10,21,0:-1347793296.060344827586206896551 +qtodec:-282780023728/5,2,11,0:-110100101011000000000010010110001001.10011001100 +qtodec:638682849990/23,16,9,0:677268F6C.C8590B216 +qtodec:535560667707,16,18,0:7CB1E7423B.000000000000000000 +qtodec:-401907828437/3,16,9,0:-1F3130ECF1.AAAAAAAAA +qtodec:3218700909539/29338078141536091560,8,23,0:0.00000001656320570000741 +qtodec:5439189996708/94348764673867659923,16,4,0:0.0000 +qtodec:1740848648701/1119578055730924485,31,18,0:0.0001DFUO0I3QPKUBB3 +qtodec:7295053757088/1450625657591198545,8,7,0:0.0000012 +qtodec:-1032855428030/265721276914642799,10,4,0:0.0000 +qtodec:9675459200429/511269589228603602,16,0,0:0 +qtodec:-6223725941437/56926625845778373,8,5,0:-0.00003 +qtodec:-2879348418643/47766734102586734,8,12,0:-0.000017632436 +qtodec:2520416264460/3387623665183741,4,12,0:0.000003003002 +qtodec:-3355498216855/9089973231071546,8,11,0:-0.00014061140 +qtodec:76270631539/39479824809239,10,8,0:0.00193188 +qtodec:3364353901017/768729606000529,10,2,0:0.00 +qtodec:-9452026777809/99657509107327,8,9,0:-0.060437046 +qtodec:-4815297415205/21430300809226,10,10,0:-0.2246957454 +qtodec:-6342167555982/3875920251233,7,17,0:-1.43115201521246450 +qtodec:8934479736203/3867754877020,10,18,0:2.309991201688244985 +qtodec:-3753600089937/143741616224,10,19,0:-26.1135236164839743412 +qtodec:2897856603605/615018645051,2,9,0:100.101101100 +qtodec:435938574533/2644597999,10,15,0:164.841149655955706 +qtodec:826020960749/10601806559,16,12,0:4D.E9C93E2C5870 +qtodec:9761146029167/8021480002,24,3,0:22G.L0D +qtodec:2245343058343/784476985,4,9,0:230232.031313033 +qtodec:1072296751915/36801933,10,3,0:29136.968 +qtodec:-807541874983/131278078,8,7,0:-14007.3045040 +qtodec:-435413761289/43289060,7,10,0:-41216.2001345166 +qtodec:4073307919652/31662917,8,7,0:373206.0046555 +qtodec:-1321397617831/1964025,23,21,0:-296J4.IG8A9IBJ59J61E8CGB7GI +qtodec:2696371910638/7287271,16,17,0:5A55B.3403DE272E3931399 +qtodec:5257481019409/238632,10,21,0:22031751.900034362533105367260 +qtodec:1568947440315/909929,10,13,0:1724252.5958783597401 +qtodec:766431707621/1221,2,20,0:100101011010100001000100100100.00111111111100101001 +qtodec:-431144146277/82280,4,20,0:-103333102122.32023132113312320331 +qtodec:384242556775/153,4,15,0:2111230030021023.331322021030331 +qtodec:2640838852687/18,16,18,0:2228CAD559.B8E38E38E38E38E38E +qtodec:7610182808651/115,8,1,0:755027404533.7 +qtodec:-9118836627837/914,8,15,0:-112252512015.670667132577121 +qtodec:1898758084737/34,4,17,0:310000222322313211.22310231023102310 +qtodec:3941772625972/27,16,22,0:21FDC6B473.B425ED097B425ED097B425 +qtodec:7305852397411/8,4,6,0:31102200311321103230.120000 +qtodec:7715401636819/8,28,19,0:2FD9CJPF6.AE00000000000000000 +qtodec:-6377466965229/5272197654656004845,2,11,0:0.00000000000 +qtodec:95367642815004/58794630553530738613,16,8,0:0.00001B36 +qtodec:89910282347329/7828383835585298780,10,8,0:0.00001148 +qtodec:2038526394593/1990816553437773794,10,2,0:0.00 +qtodec:28272663625994/160960199502197837,35,1,0:0.0 +qtodec:-59069158030644/424215731327050267,16,3,0:0.000 +qtodec:75400206290854/49799134304108783,16,11,0:0.00633A28CE3 +qtodec:-37669923041786/75586822083192129,4,11,0:-0.00000200222 +qtodec:7496638266025/6034056131446777,8,8,0:0.00050553 +qtodec:24694543702374/3151507628740733,6,3,0:0.001 +qtodec:36765006277527/993625421845964,16,6,0:0.0978E3 +qtodec:24118383293179/139876602800164,8,3,0:0.130 +qtodec:84628426174922/74981426674997,16,16,0:1.20EFC3CE6BC695C0 +qtodec:75123320783542/76127954130971,2,8,0:0.11111100 +qtodec:72843089406231/6513652706969,16,20,0:B.2EE2417719BC9EBF6400 +qtodec:30025878059676/8095500354281,16,3,0:3.B57 +qtodec:40392627698767/335455107355,16,17,0:78.69533006D036F2932 +qtodec:19166212064859/56607758681,10,2,0:338.57 +qtodec:32912615723976/61714756253,32,24,0:GL.9LEN5HK85GIITU1DGPP794DF +qtodec:41214369996242/38676773967,3,1,0:1110110.1 +qtodec:90080254229318/6760666411,2,10,0:11010000001100.0010101011 +qtodec:82429041024490/7102488371,16,5,0:2D55.A816C +qtodec:57660654095256/202993813,8,10,0:1052623.2234624203 +qtodec:2309226834537/34009046,4,0,0:100210330 +qtodec:5980018582499/10018234,4,16,0:2101232301.1302033232010302 +qtodec:6907402092405/8167279,10,18,0:845740.924536188858002769 +qtodec:687627440189/2492032,4,3,0:1003113122.122 +qtodec:-26205406708751/2529448,16,19,0:-9E1540.A7F1ECC11AC5EB38F15 +qtodec:7987206144352/958979,16,4,0:7F16A0.7EAA +qtodec:9349896502895/60416,10,12,0:154758615.315396583686 +qtodec:10860759301327/48735,10,2,0:222853376.45 +qtodec:3148381751581/5818,19,7,0:B9A7BD1.66HDG7A +qtodec:61935911504963/4361,10,20,0:14202226898.63861499656042192157 +qtodec:-69993147865828/9859,4,19,0:-12213022013333300.0110131201200023123 +qtodec:86935769322811/926,16,10,0:15DBDEBA5B.04B3250B9C +qtodec:-64121171058167/770,20,5,0:-351341067.9FGHD +qtodec:9446426763225/4,16,18,0:225DABA57F6.400000000000000000 +qtodec:-15324302869615/24,8,5,0:-11225224260057.22525 +qtodec:-4671160833472/3,8,5,0:-26520750116225.25252 +qtodec:55245335112604/3,10,5,0:18415111704201.33333 +qtodec:566728086891451/10568813125939255124,3,12,0:0.000000001001 +qtodec:739540223328929/6053203450796243551,10,17,0:0.00012217336313578 +qtodec:-267044400853535/2379289330009370147,16,14,0:-0.00075B066EC680 +qtodec:-843852024858729/4271893173695550305,10,6,0:-0.000197 +qtodec:197347580645443/108172371955754181,16,12,0:0.0077900729BF +qtodec:-471123271600944/654989858032575515,10,23,0:-0.00071928330770812175815 +qtodec:-163920861540435/9535143268783618,16,17,0:-0.0466A503DF678948D +qtodec:-245368226573823/3254547830228791,16,1,0:-0.1 +qtodec:369028112478579/2538185191154003,16,21,0:0.253850793AFB1044E30DD +qtodec:626129443248141/7910783804367593,16,19,0:0.1443195BA445886AF1D +qtodec:-157750576827642/153140053336643,8,8,0:-1.01732420 +qtodec:275996140907183/409619916609098,16,20,0:0.AC7D3C447ED47543D31A +qtodec:355251513430543/14307219099290,10,15,0:24.830228080324321 +qtodec:937664836189255/79009750870091,30,11,0:B.Q0S5AR173F3 +qtodec:349923951151518/2085182381581,10,14,0:167.81455389346000 +qtodec:942533795406013/1253026069985,8,12,0:1360.151377610176 +qtodec:168503932887067/490675611980,16,3,0:157.697 +qtodec:-677938451596593/682092667400,2,8,0:-1111100001.11101000 +qtodec:803603551114720/23581903161,2,0,0:1000010100011101 +qtodec:112615275542863/25757128420,16,2,0:1114.32 +qtodec:579802064583250/5360830521,16,9,0:1A67B.44BEE11BF +qtodec:273379089201067/1016082892,2,13,0:1000001101011111011.1111010010100 +qtodec:975288121833827/137728947,2,4,0:11011000000110011111101.1100 +qtodec:-99770800296007/18724410,33,20,0:-4G8U3.H9T203QQF1ID7D4MF4GL +qtodec:-991804729064264/26457723,2,18,0:-10001110111111111100111101.110010101110011101 +qtodec:-62591002485079/97559203,16,0,0:-9CA21 +qtodec:688513532701121/5610689,10,13,0:122714613.6064788121387 +qtodec:553695114091357/8948070,4,23,0:3230003012333.20320221111300131301211 +qtodec:394354539297348/400625,10,16,0:984348304.0183413416536661 +qtodec:950552587873347/888277,16,0,0:3FC88E89 +qtodec:350686839911665/16413,4,22,0:103321202113333012.3231220011031122032301 +qtodec:903828738534/25,16,20,0:86AE54865.5C28F5C28F5C28F5C28F +qtodec:541050473343191/7988,10,3,0:67732908530.694 +qtodec:247693604041126/753,10,20,0:328942369244.52324037184594953519 +qtodec:669870599648747/481,8,6,0:24210111252064.072426 +qtodec:754104756872751/751,10,4,0:1004134163612.1850 +qtodec:400809404312086/31,29,15,0:POFCDO4JM.ES1P7E0R3LES1P7 +qtodec:691618327861484/41,2,13,0:11110101011110001111001111001110010010000010.1010001001010 +qtodec:-210072315488840,8,7,0:-5760750557365110.0000000 +qtodec:-81144130253573,10,3,0:-81144130253573.000 +qtodec:5170809372187007/11283707234075047947,10,10,0:0.0004582544 +qtodec:1639188787409323/46524006641110741684,10,3,0:0.000 +qtodec:5309238096936419/7635150210858603024,16,9,0:0.002D92563 +qtodec:6245068701898179/9732919709002668103,9,8,0:0.00041788 +qtodec:-4005803274360553/523443601614052653,8,16,0:-0.0037261037222672 +qtodec:910033404367986/51511134209314135,10,14,0:0.01766673202477 +qtodec:-8946453122467272/16357932122088269,4,1,0:-0.2 +qtodec:1439256442170292/18860267700460975,16,18,0:0.13892784AB4AC9534F +qtodec:176342308920979/1166455373773242,19,16,0:0.2GAHC9H4CGC0CEHD +qtodec:9127798257300245/3295488783649008,2,3,0:10.110 +qtodec:2823851681807332/216293042654769,35,9,0:D.1X72DBVCV +qtodec:1528606788714955/776202467853779,8,1,0:1.7 +qtodec:-2245234784303738/7968662735081,2,19,0:-100011001.1100001000001110110 +qtodec:-128444956522416/7394678196655,16,17,0:-11.5EB2F81C36E711FA5 +qtodec:9112358352966977/2361812921250,16,7,0:F12.3478F81 +qtodec:2905352187696283/1380663976291,16,7,0:838.50B0C57 +qtodec:8510056286946796/21028769443,10,6,0:404686.365981 +qtodec:-327110149217475/8556403273,16,0,0:-9555 +qtodec:-9974695312898971/92239807984,10,5,0:-108138.72590 +qtodec:1221192643750202/2497860115,8,18,0:1672677.417113245412637252 +qtodec:-4419213285773803/8210131295,10,24,0:-538263.412238622792937929502380 +qtodec:3449812953293071/3716759862,3,8,0:1202011012221.11200111 +qtodec:-1747118140195518/581874449,30,24,0:-3L65I.ROIQ9PQN4D3L479OTM4HQTTO +qtodec:2932615081988594/424849503,10,16,0:6902715.1056561174793230 +qtodec:205249461865499/1394293,8,8,0:1061431264.50247217 +qtodec:200178651506113/94362405,10,18,0:2121381.407204627732834914 +qtodec:4983485895963716/3124575,16,4,0:5F10BCAD.83B3 +qtodec:-2126394804343852/5400439,16,12,0:-177811A5.9FF614B5F0EB +qtodec:-4331181325256657/303608,28,15,0:-11GP6OLI.GLNOMIO8LGAFBFB +qtodec:5081378901139473/111776,10,6,0:45460375224.909399 +qtodec:2920920792505487/41003,10,4,0:71236758103.1994 +qtodec:7658747612532673/37587,8,3,0:2756104626662.525 +qtodec:4821921280150899/6211,10,2,0:776351840307.66 +qtodec:971865299978799/70,10,4,0:13883789999697.1285 +qtodec:-7430593251383/46,8,3,0:-2263415567573.502 +qtodec:2823536151388589/214,8,16,0:277777522736567.1720114437064505 +qtodec:4578540213882646/39,9,17,0:511604860453776.84754754754754754 +qtodec:-9927408845436128/93,7,7,0:-31325111416165136.1335226 +qtodec:407609585094280/3,2,13,0:11110111001001010101010110101111001101000101101.0101010101010 +qtodec:253188219226631/3,10,12,0:84396073075543.666666666666 +qtodec:-68930748060360886/37490536052536135645,16,16,0:-0.00787EE12917A18A +qtodec:-27942742835596649/47682255502975144563,10,22,0:-0.0005860197371295314577 +qtodec:-889817670509617/3535523156098154639,2,8,0:0.00000000 +qtodec:15158188532341466/3995083585765893961,16,13,0:0.00F8A84A7CDC0 +qtodec:-59804365023342061/621117898115362242,8,8,0:-0.06123043 +qtodec:-81485939236590623/615428154300888948,34,11,0:-0.4H21W6LIJ50 +qtodec:36074584319124862/92634714729867147,10,20,0:0.38942835225781451191 +qtodec:27642416496412871/152889510367347,4,19,0:2310.3030302130330102330 +qtodec:-33829733020352429/4052703927980325,10,17,0:-8.34744743794091070 +qtodec:-66100320694014641/8124063954599958,16,10,0:-8.22E8955406 +qtodec:58590194428080104/702027678864689,16,14,0:53.7561E129C90D18 +qtodec:31662226155385957/171148946506769,28,12,0:6G.RQDMHIG61C7H +qtodec:80426773270148529/88072832508602,10,6,0:913.184815 +qtodec:6986828640027445/26266703980128,4,16,0:10021.3332320200120130 +qtodec:-1329127236657015/571179194743,14,21,0:-BC2.DB9808DAB68A65CB41223 +qtodec:30790043632436089/2944082517781,10,21,0:10458.281466799040529212839 +qtodec:37527850657958435/230664339986,8,17,0:475606.50517543663044013 +qtodec:1274159114112977/691969514703,25,20,0:2NG.8JHABOIBBB9OE6722AG6 +qtodec:-8727012566649617/7034024865,10,9,0:-1240685.487205711 +qtodec:17256266960825731/63664944830,16,1,0:422C8.2 +qtodec:50744507398196374/8821405641,10,16,0:5752428.7469954669551965 +qtodec:47177149363508061/3993510814,4,7,0:231010021030.1003113 +qtodec:60964430640468696/20931833,8,19,0:25546310107.6643376221343113763 +qtodec:28046052697862828/808622915,4,7,0:2010103231022.1202200 +qtodec:15333390554164126/4607479,16,11,0:C65C4208.702AED37B48 +qtodec:36857302943990537/94956649,10,23,0:388148732.41778505684209643918668 +qtodec:8496754449568199/55962,10,8,0:151830786061.40236231 +qtodec:-40689989695341081/5616818,2,13,0:-110101111110010110111001100010011.0001001001010 +qtodec:23163002269331293/193866,16,4,0:1BD187A9C2.1156 +qtodec:34444442500613215/206713,8,13,0:2331370253516.7722402424374 +qtodec:62933776312076227/59883,16,14,0:F4B13D77CA.C8A382A3CADEC9 +qtodec:-18647677587711109/26916,18,2,0:-38FB804D22.HC +qtodec:17817200142697406/9583,10,24,0:1859250771438.735886465616195345925075 +qtodec:-11671994921731151/3051,10,14,0:-3825629276214.73320222877745 +qtodec:-25084790823695601/724,4,9,0:-13320023333333312130211.012303213 +qtodec:55617132227847436/639,34,15,0:1EP48NP5TQ.OG5WKWQDA955GBD +qtodec:-7818552938767891/33,10,5,0:-236925846629330.03030 +qtodec:38873447567837132/65,4,8,0:2013332310102332133330202.22111222 +qtodec:95354368608906933/5,8,15,0:1036015571557436212.463146314631463 +qtodec:-40993349533336479,5,21,0:-320441040014321013231404.000000000000000000000 +qtodec:135033976497795375/40316057739120473824,25,19,0:0.02288KK6H25D8FAK52C +qtodec:-968873270873936405/81604197111822403467,33,1,0:0.0 +qtodec:-582538953962125016/4568729267973575005,4,6,0:-0.020022 +qtodec:6393160063269118/92227912540813733,10,19,0:0.0693191452255839024 +qtodec:474281688207585819/814291209842309920,10,3,0:0.582 +qtodec:40690442908425581/187118373843998614,8,12,0:0.157255306433 +qtodec:-268184957010686822/58138937651604387,10,18,0:-4.612828645369753495 +qtodec:244145735027212276/20118199473446397,10,18,0:12.135565876531608828 +qtodec:185382924301762910/5186767786834931,8,19,0:43.5735167671261201162 +qtodec:433898808529646925/9828786248752108,10,7,0:44.1457162 +qtodec:245241871711849034/3863301881929,10,23,0:63479.86235789484292426582206 +qtodec:-347923793289428653/116335863891625,16,5,0:-BAE.AF130 +qtodec:-101194595933896924/47243525609381,2,20,0:-100001011101.11111010011000101111 +qtodec:472198009745101481/5392622647777,4,6,0:111120023.231000 +qtodec:192703964184690803/5888450417178,10,2,0:32725.75 +qtodec:351370652185299362/4111024159547,10,9,0:85470.344748355 +qtodec:966591837542629967/302542852166,8,20,0:14140014.25030572653613126432 +qtodec:849532369021753832/344987961049,10,3,0:2462498.593 +qtodec:232084364697362395/63954852178,10,0,0:3628878 +qtodec:-15233960541477728/29236841251,2,10,0:-1111111001101011101.1001001000 +qtodec:-204455585309689977/2573797241,24,8,0:-9NA80J.I46J0E07 +qtodec:-208654616780822858/3143953651,16,20,0:-3F4ADE6.A4B10A1959FE7A9D8B74 +qtodec:61432060563100995/654186158,10,20,0:93906084.39486577305415869101 +qtodec:-215408951941727837/842697775,16,20,0:-F3C6CE3.6A4AABDAB1F876EE1689 +qtodec:1494042204388242/341149,2,14,0:100000101000010001111101010110000.01010101100110 +qtodec:252329963368832243/44580470,35,4,0:32QT0LR.50QV +qtodec:168671981609579290/315937,10,17,0:533878531509.69747133130972314 +qtodec:97357880572782372/2370407,5,16,0:1133103442034142.2141330201310323 +qtodec:438158095794943133/660884,8,17,0:11513512103507.35524017602321151 +qtodec:7850289549554440/306739,21,4,0:E4890EGI.6AGB +qtodec:119806400157154998/22543,8,20,0:115254513702023.51671000734614004504 +qtodec:842337451434634867/22911,16,20,0:21702A953033.D41940A3C2E70126A09C +qtodec:-191741119725912979/977,10,12,0:-196254984366338.770726714431 +qtodec:679872291852418397/4361,16,19,0:8DC9E4228BBD.64F7B9167BA06ED4626 +qtodec:-520912901611533563/280,2,4,0:-110100111000000011011100001000100011100110111100111.0100 +qtodec:39729892807989997/54,8,8,0:24722320713461336.35502275 +qtodec:970713517442043449/37,10,14,0:26235500471406579.70270270270270 +qtodec:29117381123938587/8,16,12,0:CEE4352D5D323.600000000000 +qtodec:363588332502803888/3,35,2,0:18WP2QFWYK2H.NB +qtodec:797307393945548281/8,10,23,0:99663424243193535.12500000000000000000000 +qtodec:962196352783334317/9197391367410673270,24,6,0:0.2C653F +qtodec:-1712459327217296767/24201664403827655252,2,12,0:-0.000100100001 +qtodec:-6257340861519758901/171587352958408768,11,22,0:-33.516097715A478605011696 +qtodec:417344045124814390/1985525411662453127,16,6,0:0.35CF39 +qtodec:4903347687958413477/936909515551143478,8,9,0:5.167443402 +qtodec:6815391545417096283/459992327223804545,16,7,0:E.D0FA110 +qtodec:104292470919702350/405232099156473,10,0,0:257 +qtodec:1273295935414124869/12782736302053151,34,23,0:2V.KPSOK4L6RBMXDCVRWQAD0GN +qtodec:4109078480849408360/435043171158277,10,19,0:9445.2200454249798277382 +qtodec:6514718679505732082/7354769508455189,8,8,0:1565.62007631 +qtodec:9866917402610085742/359433106924021,16,16,0:6B3B.54E315BF403F00E2 +qtodec:-1457774896854499915/466537799128293,21,21,0:-71G.DKGG5JHK6IED1DCB8C949 +qtodec:3562469801994530303/39520702664299,10,5,0:90141.86393 +qtodec:-1121788856677512277/4346264061083,10,15,0:-258104.165074127011561 +qtodec:-9277969991539582813/2921352796605,8,5,0:-14072753.47761 +qtodec:9405317682640021543/7885054834345,8,24,0:4431543.050247665143116233543566 +qtodec:6327008262496741021/191631004675,10,9,0:33016621.048494437 +qtodec:932916830728130561/490000068712,16,15,0:1D0D27.A1E90D8F3EB7E02 +qtodec:529997294498903710/61063223157,27,15,0:G8Q0A.BEM6E6H7QAPGMP1 +qtodec:-378316587720990944/3926689661,16,23,0:-5BE1B54.8DB9C3FC5575501C10951F3 +qtodec:-3320019367427260995/7860304231,16,6,0:-192CF9F4.E51A76 +qtodec:2546767615570206397/876018632,2,5,0:10101101010010000111010111011100.11111 +qtodec:4651229211968910861/560332411,10,14,0:8300839145.94208768873089 +qtodec:5163696080111021129/746361687,8,10,0:63427744254.2545124347 +qtodec:-9950518479492602835/4241804,8,1,0:-42105571761136.6 +qtodec:420714617814952557/20658446,10,21,0:20365259701.284044162857167475230 +qtodec:6389761026090454423/1077366,10,3,0:5930910225578.359 +qtodec:-3097681303678311991/1783890,4,6,0:-121101032000121021210.120323 +qtodec:821760264557780373/82357,2,1,0:10010001001100110000101011011100100010101100.1 +qtodec:6406014444168904793/598448,10,17,0:10704379401667.15369255139962035 +qtodec:1412628290169413175/3619,16,24,0:16302549B006E.CA617A05CCED655E02B02315 +qtodec:2486326722603345473/4212,10,22,0:590295993020737.2917853751187084520417 +qtodec:2663530739497419216/4037,16,2,0:25810EFFC7428.72 +qtodec:-214922836739795459/270,10,12,0:-796010506443686.885185185185 +qtodec:6226184158746697831/799,16,18,0:1BAF35FD2D429A.8FDC1D7A12954E7F84 +qtodec:-2407322554685617466/195,16,13,0:-2BDBEF138C3CFD.ABFABFABFABFA +qtodec:858459865910732119/11,24,16,0:236L1CMG4BGII.248HALJF6D248HAL +qtodec:2546836315293994167/4,8,10,0:43260270424442471455.6000000000 +qtodec:1687480025170556035,8,1,0:135531042215166732203.0 +qtodec:8502691839655002109/6,10,23,0:1417115306609167018.16666666666666666666666 +qtodec:13139171374879806857/10977381074509304689,10,0,0:1 +qtodec:25010427150343850302/67656897694844048439,16,9,0:0.5EA2677CC +qtodec:34472195313108788669/434602033270864170,16,10,0:4F.51A97A0B8E +qtodec:-83602382263216798102/7417291363069673277,2,14,0:-1011.01000101011100 +qtodec:255840050198896639/1315714580972021,2,17,0:11000010.01110011000100101 +qtodec:28302759431751782745/592140283405467652,16,17,0:2F.CC21AE72A26F651F8 +qtodec:3937631720009717237/36823618427527354,20,8,0:56.ICHH37AC +qtodec:22545518158553313659/62467059813338995,16,15,0:168.EB237A73BBA8622 +qtodec:-48446768942686919883/3741466474083086,4,11,0:-3022110.21222310212 +qtodec:7169357010298918984/1220646708315151,10,7,0:5873.4087115 +qtodec:46778564443315773088/210614351846423,4,12,0:312032121.103121102132 +qtodec:30982166662165412803/52147001878280,2,11,0:10010001000011010011.01001111111 +qtodec:80598339985947052706/2958216824641,16,15,0:19FBC0E.4F4E111B987AE60 +qtodec:44066815386005295782/52340788103663,10,7,0:841921.1284845 +qtodec:2228125575854677152/794184699731,16,5,0:2ACF2E.DEE87 +qtodec:-31021849545265661608/4106419586427,27,24,0:-E5LLB.8KKG3308C79II4HIF7HO8DM2 +qtodec:77877994428662842064/93387431541,16,12,0:31B4AA89.4008C5AB084B +qtodec:-659373254181263916/165391612333,10,10,0:-3986739.3810375323 +qtodec:98882644692855550886/8432909589,10,7,0:11725803964.7240371 +qtodec:69505961999667187147/91220437346,10,11,0:761956026.76218709506 +qtodec:10734338306931222346/1274484573,10,24,0:8422493715.764437382483718773110641 +qtodec:61367391524217084335/6370835564,14,13,0:6754326B1.A46C4BC7937B9 +qtodec:44577580152302734007/198070854,8,10,0:3214643014233.3071243700 +qtodec:-56791209452014782584/235059441,16,12,0:-3840B28498.8ADFAA158075 +qtodec:16511384744316378091/2678129,8,6,0:131556651335325.270744 +qtodec:88298173378026931716/10792589,10,12,0:8181370881261.848451377144 +qtodec:-42234235979751132649/8018900,24,5,0:-1NK84K6EHI.JE0IE +qtodec:18531075354063777193/5038119,16,19,0:35864383BFF.AB3590FFE1BAF5F6E6B +qtodec:36664397392769922711/807520,4,10,0:22110231133201221212231.0003203003 +qtodec:-42507384945776962084/555657,10,23,0:-76499324125813.15826850017186861679057 +qtodec:486858786170940568/88643,8,18,0:117731165754015.026354742305726672 +qtodec:893199977657440169/88569,10,0,0:10084792395278 +qtodec:45981109152253249913/3272,16,8,0:31ED0B3350005A.DF87D2EF +qtodec:10005656828299907515/97,4,10,0:11232131312011100201311102202.3222320233 +qtodec:5497769811530428529/891,4,11,0:111322332031222203312210312.12320022322 +qtodec:19676898338016110283/235,4,18,0:10221132111123222120031323300.201133313102033302 +qtodec:92885714512301641859/8,10,19,0:11610714314037705232.3750000000000000000 +qtodec:46299019950017172226/55,2,14,0:101110101110101011001111100001001000001011000011010010110101.10010000010010 +qtodec:86031296735581415137/3,8,6,0:3067714130270613633640.252525 +qtodec:-74317122139160378225/9,4,6,0:-13022120120211002233111020312313.032032 +qtodec:68655/564493455483553,10,10,0:0.0000000001 +qtodec:744/11213190182777,8,17,0:0.00000000000443637 +qtodec:1969/316819189359038,10,8,0:0.00000000 +qtodec:-28439/301147910327855,8,17,0:-0.00000000000637251 +qtodec:47926/42794221756379,10,6,0:0.000000 +qtodec:8609/54631358200256,4,0,0:0 +qtodec:52489/82632930569226,2,8,0:0.00000000 +qtodec:10307/11184215134882,16,14,0:0.00000003F545F5 +qtodec:-31349/9533318763438,2,5,0:0.00000 +qtodec:-26472/3296480616721,8,0,0:0 +qtodec:57256/806743900853,16,15,0:0.00000130D23A739 +qtodec:40722/3682812606167,2,7,0:0.0000000 +qtodec:37969/34007088009,10,0,0:0 +qtodec:78781/962690517003,10,15,0:0.000000081834191 +qtodec:7283/142340577595,16,9,0:0.000000DBC +qtodec:76855/907629934047,4,2,0:0.00 +qtodec:15363/69482486347,8,4,0:0.0000 +qtodec:-289/869154128,10,24,0:-0.000000332507193706845053 +qtodec:-21217/25103660786,19,1,0:0.0 +qtodec:13692/5736313747,32,11,0:0.0002G2T6T27 +qtodec:1355/477699881,10,14,0:0.00000283650897 +qtodec:18475/503078099,16,14,0:0.00026820095C41 +qtodec:62593/8927182523,8,24,0:0.000001655043044264105063 +qtodec:-82180/4421221347,16,9,0:-0.000137D93 +qtodec:-24674/17452297,12,7,0:-0.0025396 +qtodec:-11477/47606496,21,11,0:-0.0024ICB8BA6 +qtodec:-21973/418977883,8,17,0:-0.00001557675043667 +qtodec:-41725/131769957,22,2,0:0.00 +qtodec:3199/70769667,10,10,0:0.0000452029 +qtodec:34338/94122911,2,20,0:0.00000000000101111110 +qtodec:-13736/2772531,10,23,0:-0.00495431791384839339938 +qtodec:-5183/49753414,2,20,0:-0.00000000000001101101 +qtodec:-51566/4144321,10,12,0:-0.012442568999 +qtodec:-96027/1859756,4,4,0:-0.0031 +qtodec:12379/2809096,16,6,0:0.0120CD +qtodec:-24031/9122052,17,11,0:-0.00CG07B319C +qtodec:12305/38714,8,11,0:0.24257063763 +qtodec:88995/335867,8,14,0:0.20752442752633 +qtodec:81953/624954,16,1,0:0.2 +qtodec:1944/4277,33,16,0:0.EWW7Q5DG2C5HIGRA +qtodec:54911/82297,10,10,0:0.6672296681 +qtodec:29583/27671,16,14,0:1.11B0618C693572 +qtodec:-75887/60475,10,16,0:-1.2548491112029764 +qtodec:17652/15565,16,2,0:1.22 +qtodec:87767/115652505214716,4,18,0:0.000000000000000310 +qtodec:12897/583646546551346,16,2,0:0.00 +qtodec:-19825/432539042784217,16,19,0:-0.00000000326520AEFDE +qtodec:736440/839968528505573,4,18,0:0.000000000000000330 +qtodec:703589/85878714909896,8,18,0:0.000000001063003223 +qtodec:608123/89966921812529,10,15,0:0.000000006759406 +qtodec:919819/82768941199286,8,23,0:0.00000000137353716263317 +qtodec:-38153/35848949843701,16,23,0:-0.00000004922DAC4A09FC403 +qtodec:209877/1638057441965,10,0,0:0 +qtodec:751856/1582376330691,8,10,0:0.0000000776 +qtodec:212627/2270529591527,16,5,0:0.00000 +qtodec:-342197/1695850530890,8,19,0:-0.0000000330524323052 +qtodec:360157/727872304477,16,10,0:0.0000084D2F +qtodec:-840347/766875155324,8,7,0:-0.0000002 +qtodec:441366/320303145713,10,14,0:0.00000137796336 +qtodec:-397333/170752574257,20,0,0:0 +qtodec:377646/38251209193,16,16,0:0.0000A5A34AEE4273 +qtodec:492455/93020377059,10,14,0:0.00000529405508 +qtodec:-329137/677535547,8,1,0:0.0 +qtodec:-906246/51378477563,10,1,0:0.0 +qtodec:860093/6194527744,19,3,0:0.000 +qtodec:31316/103976957,23,3,0:0.003 +qtodec:243505/1499845166,8,7,0:0.0000524 +qtodec:482241/2737367521,10,17,0:0.00017616962147042 +qtodec:567088/116192713,16,14,0:0.013FDA91B97CF9 +qtodec:694040/908350707,8,9,0:0.000310227 +qtodec:288216/7323035,10,14,0:0.03935745220390 +qtodec:991400/605403489,16,24,0:0.006B522057B40442574209DF +qtodec:-461143/35204521,2,16,0:-0.0000001101011010 +qtodec:-117710/43583043,16,20,0:-0.00B1004216172B6035A9 +qtodec:-3056/22397223,2,15,0:-0.000000000000100 +qtodec:-102033/8495267,4,1,0:0.0 +qtodec:110927/145078,27,19,0:0.KHAI30C2MDG85E9MMC2 +qtodec:106035/1516586,8,11,0:0.04363023014 +qtodec:-78219/7511632,16,22,0:-0.02AA6DFD6E8394C7FBAF89 +qtodec:64866/256723,16,1,0:0.4 +qtodec:-384383/794667,30,8,0:-0.EF9TIJGJ +qtodec:105023/359600,10,13,0:0.2920550611790 +qtodec:-335084/614183,10,5,0:-0.54557 +qtodec:173356/199035,16,23,0:0.DEF8B56028757A16842DA12 +qtodec:381414/97673,27,20,0:3.OBK85563P4LQHMP877N1 +qtodec:740226/15361,10,10,0:48.1886595924 +qtodec:791292/78311,4,2,0:22.01 +qtodec:284139/12334,10,12,0:23.037052051240 +qtodec:823655/378760563881187,10,4,0:0.0000 +qtodec:4866313/111569112800605,19,9,0:0.0000020IE +qtodec:1858787/249890994746724,10,5,0:0.00000 +qtodec:7273440/805769398706737,8,22,0:0.0000000011542366515000 +qtodec:-9119403/7773223229000,16,5,0:-0.00001 +qtodec:2054927/69883023343346,8,17,0:0.00000000374455467 +qtodec:-3095106/23726483413861,10,19,0:-0.0000001304494200009 +qtodec:1124235/18821267939248,8,16,0:0.0000000100106064 +qtodec:-825697/8046469218859,4,4,0:0.0000 +qtodec:-8466329/522547357251,10,5,0:-0.00001 +qtodec:-451191/4499178998474,16,11,0:-0.000001AEB64 +qtodec:359287/900902946089,10,1,0:0.0 +qtodec:-1567363/85934054431,8,3,0:0.000 +qtodec:508948/70232110139,16,17,0:0.00007994276FF3FFE +qtodec:2394568/624074713719,8,1,0:0.0 +qtodec:-4216998/945198033841,16,12,0:-0.00004AD9FB9A +qtodec:8302337/6722959869,16,14,0:0.0050EE9167ED89 +qtodec:429445/95937769192,35,7,0:0.0006P3L +qtodec:331857/43689514733,10,16,0:0.0000075958042113 +qtodec:159145/7758156704,10,4,0:0.0000 +qtodec:2901825/9825452368,8,1,0:0.0 +qtodec:9606613/3849003924,16,22,0:0.00A391BF8D5B12DB0C8967 +qtodec:581921/247249935,4,17,0:0.00002122033212230 +qtodec:-7077467/7969534729,4,23,0:-0.00000322030310031021011 +qtodec:7654151/567131838,8,0,0:0 +qtodec:-157427/61065933,16,22,0:-0.00A8F3651849629E3984C9 +qtodec:9393952/205343869,19,20,0:0.0G9EG2BH71D114B92E89 +qtodec:1582726/158038579,2,13,0:0.0000001010010 +qtodec:2124277/82841119,4,6,0:0.001221 +qtodec:3083421/3981011,10,22,0:0.7745321477383508862447 +qtodec:3235080/17333887,4,3,0:0.023 +qtodec:-1229849/73704028,8,18,0:-0.010426157756241450 +qtodec:-1583401/1441424,10,15,0:-1.098497735572600 +qtodec:7626667/3243668,4,4,0:2.1121 +qtodec:-1121161/1274083,10,0,0:0 +qtodec:562341/836315,10,1,0:0.6 +qtodec:7101809/698134,2,17,0:1010.00101100001011001 +qtodec:3520373/805634,4,1,0:10.1 +qtodec:-6935257/276974,16,22,0:-19.0A14C076A97C6E6EAC313C +qtodec:-944696/960767,10,0,0:0 +qtodec:-1179024/57377,8,10,0:-24.4307440501 +qtodec:-6460475/3693,10,9,0:-1749.383969672 +qtodec:4614415/37109,10,2,0:124.34 +qtodec:-257431/24801,26,10,0:-A.9MKCFG90C1 +qtodec:79010339/389043341388123,16,19,0:0.00000368427AA7D37AB +qtodec:77290549/450505435559884,29,11,0:0.00003F1D92R +qtodec:1533996/23992454790335,16,3,0:0.000 +qtodec:20673781/414667535279553,10,20,0:0.00000004985628061300 +qtodec:1613195/541735894212,4,23,0:0.00000000030133112221312 +qtodec:-63576657/214144111954,16,16,0:-0.001374F10A12653D +qtodec:80261049/89465234336497,10,11,0:0.00000089711 +qtodec:-92707227/46577185021877,16,2,0:0.00 +qtodec:20180088/9052096932529,10,11,0:0.00000222932 +qtodec:5958725/9682403484536,4,2,0:0.00 +qtodec:6585917/42481037484,10,19,0:0.0001550319245964863 +qtodec:47989819/1900947593758,4,15,0:0.000000012213202 +qtodec:-54873667/162032680162,8,4,0:-0.0001 +qtodec:-52980833/419098674300,26,15,0:-0.0025JPO9FCEKGE3 +qtodec:-60842116/680762626237,16,5,0:-0.0005D +qtodec:-45311824/640856069947,16,19,0:-0.0004A23C4D9E3DCA928 +qtodec:46200845/79924033279,10,24,0:0.000578059478539094811289 +qtodec:98460259/75913335170,2,10,0:0.0000000001 +qtodec:24809941/19096691737,16,18,0:0.005524895A3969F3B0 +qtodec:10882277/3259863295,31,11,0:0.036DTIINPNJ +qtodec:4972596/3972114529,8,24,0:0.000510127773454276673616 +qtodec:-14213132/6879138065,10,24,0:-0.002066121055530813801161 +qtodec:10551615/4849980697,16,18,0:0.008E94803047CFE692 +qtodec:-10819947/251762996,10,4,0:-0.0429 +qtodec:-5411766/234581185,10,2,0:-0.02 +qtodec:-14769835/347988511,2,7,0:-0.0000101 +qtodec:50123417/964435923,2,23,0:0.00001101010011100000010 +qtodec:-16460359/132357561,2,23,0:-0.00011111110101100011110 +qtodec:3791364/16604819,16,22,0:0.3A73C74220AF142E9A1AF8 +qtodec:37528863/53944966,10,17,0:0.69568795353397757 +qtodec:-124027/319601,16,3,0:-0.635 +qtodec:4793306/12338915,4,12,0:0.120313023033 +qtodec:26259994/812687,4,17,0:200.11000003221312333 +qtodec:-46562347/4867601,8,15,0:-11.441530754510376 +qtodec:17565101/2286550,4,6,0:13.223221 +qtodec:63309560/2167187,16,1,0:1D.3 +qtodec:272611/47935,7,17,0:5.45445020052652515 +qtodec:22106/1745,10,15,0:12.668194842406876 +qtodec:92712989/247904,12,7,0:271.BA24145 +qtodec:-26831343/493699,10,1,0:-54.3 +qtodec:82814925/36226,8,4,0:4356.0402 +qtodec:5223041/7597,2,6,0:1010101111.100000 +qtodec:1284647/982,10,12,0:1308.194501018329 +qtodec:1433947/3182,4,8,0:13002.22102233 +qtodec:-344137/2854599874650,4,20,0:-0.00000000000200113013 +qtodec:165197798/175803438592331,10,11,0:0.00000093967 +qtodec:-477975899/343848834437535,8,4,0:0.0000 +qtodec:-179094377/38000927193456,8,12,0:-0.000001170433 +qtodec:128908614/5526392874913,10,7,0:0.0000233 +qtodec:78808036/21436353240389,15,20,0:0.00002BD2221322244863 +qtodec:141778616/4804415363543,2,7,0:0.0000000 +qtodec:-525236484/20786529543401,4,20,0:-0.00000001221332312331 +qtodec:-330972359/2306003612051,16,0,0:0 +qtodec:72312481/6690636866,16,10,0:0.02C4505872 +qtodec:52490699/28938790787,4,14,0:0.00001312313312 +qtodec:-282868783/8254983317343,10,11,0:-0.00003426642 +qtodec:822417609/530339299663,10,5,0:0.00155 +qtodec:-481554202/25544143895,16,17,0:-0.04D3797320111700E +qtodec:35278143/42465228617,4,10,0:0.0000031213 +qtodec:369827999/465038226115,8,12,0:0.000320362366 +qtodec:-505275021/38032954912,10,1,0:0.0 +qtodec:254690907/68730592706,16,17,0:0.00F2DA573347E3502 +qtodec:-106083040/46269280369,10,12,0:-0.002292731573 +qtodec:-60406265/22643434934,34,12,0:-0.032SWS7SG010 +qtodec:319918396/6184401717,10,9,0:0.051729886 +qtodec:-140330623/1088869052,8,5,0:-0.10177 +qtodec:-409230877/2046172793,16,9,0:-0.333315036 +qtodec:314851793/5236274560,2,24,0:0.000011110110010010011100 +qtodec:128553221/836175814,6,6,0:0.053112 +qtodec:-122961428/611026759,4,19,0:-0.0303201010230121103 +qtodec:-446255647/346867903,10,24,0:-1.286529088279465281052539 +qtodec:-260572769/470364896,28,6,0:-0.FE8R4F +qtodec:280776256/10072775,8,5,0:33.67770 +qtodec:369274812/9412439,10,11,0:39.23263800169 +qtodec:-316593321/24342910,28,8,0:-D.04A53L0J +qtodec:152179493/70796663,10,7,0:2.1495291 +qtodec:-600553760/2862917,10,22,0:-209.7698815578656314521168 +qtodec:68116207/854536,10,8,0:79.71133691 +qtodec:831793089/4921439,2,17,0:10101001.00000011101000101 +qtodec:-430839925/3981974,4,0,0:-1230 +qtodec:665664377/410666,16,9,0:654.F04907A9E +qtodec:427424299/163630,7,24,0:10421.065444130504402406531221 +qtodec:-570208971/139948,6,8,0:-30510.23351152 +qtodec:403698908/154223,35,7,0:24R.M2YQLYB +qtodec:211979567/2715,16,13,0:130FD.3046E824F649B +qtodec:691881174/35801,10,17,0:19325.74995111868383564 +qtodec:718421447/46942,16,16,0:3BC8.72F483CD15F4B8DA +qtodec:201501728/17427,10,7,0:11562.6170884 +qtodec:6614235784/345886207819559,10,13,0:0.0000191225774 +qtodec:-2302388421/790735305178466,2,17,0:0.00000000000000000 +qtodec:7147160405/219749646210273,2,19,0:0.0000000000000010001 +qtodec:1993884675/319701400539757,2,9,0:0.000000000 +qtodec:6157645931/53304026168395,16,19,0:0.00079217C9BDFCFA6C0 +qtodec:1746071285/5227857159967,4,16,0:0.0000011132031323 +qtodec:553442690/20934817860993,32,23,0:0.000RN1U6EMOSU5RV9F49PC4 +qtodec:3205641509/24017897955798,10,12,0:0.000133468862 +qtodec:3393272000/255645842301,10,2,0:0.01 +qtodec:9744696047/5669769706461,16,16,0:0.0070A32FE7590818 +qtodec:3865439982/2777396640079,8,22,0:0.0005546553373234167534 +qtodec:4190724699/7966032689051,33,7,0:0.00ITT41 +qtodec:-9506622734/658378266099,10,0,0:0 +qtodec:3974837290/274042666569,10,23,0:0.01450444684313124346213 +qtodec:3060351821/439485280782,8,7,0:0.0034413 +qtodec:-3608767797/392112547931,3,20,0:-0.00002020101100120022 +qtodec:-955758669/13342842196,10,4,0:-0.0716 +qtodec:389442347/27273496087,8,16,0:0.0072371430615551 +qtodec:5632160912/39395530459,10,16,0:0.1429644644044466 +qtodec:2712067031/40703849020,33,24,0:0.26IF0WA1MRBQE0RTIFEMN3WE +qtodec:5097549193/6461069250,2,14,0:0.11001001111110 +qtodec:7958065019/7287746841,24,20,0:1.24NC8DE54L3EKC4A039D +qtodec:8706651840/8110760959,21,20,0:1.1B887AG7I6KF270GDIG0 +qtodec:1270979794/691940283,8,10,0:1.6543531132 +qtodec:-9105312527/329024092,10,18,0:-27.673695478202246661 +qtodec:1056925223/1272276,19,5,0:25D.DIBG8 +qtodec:-7999259177/792682763,16,11,0:-A.17645D7D0D8 +qtodec:7669473418/610724525,16,17,0:C.8ED8889631A0F8E4A +qtodec:1543148811/90789352,12,22,0:14.BB6A362A93B84A069598BB +qtodec:3603627164/30995143,10,11,0:116.26425353159 +qtodec:7737616061/5485940,10,3,0:1410.444 +qtodec:2810821129/39280616,10,16,0:71.5574605296413885 +qtodec:5927485272/2570707,10,23,0:2305.78018887411128533901374 +qtodec:3101097701/525664,2,22,0:1011100001011.0110010000110101010011 +qtodec:2470594099/907464,2,4,0:101010100010.1000 +qtodec:22580764/15141,4,19,0:113103.1131203032310023320 +qtodec:-41037999/6632,16,0,0:-182B +qtodec:1026897985/217757,10,4,0:4715.7978 +qtodec:8539499023/655885,10,21,0:13019.811434931428527866927 +qtodec:-2250794858/346599,4,14,0:-1211131.33013232112020 +qtodec:-9450403358/13649,10,1,0:-692387.9 +qtodec:204008989/1324,27,17,0:7M9N.945Q8MB323LQ00ENA +qtodec:1031368481/24059,10,0,0:42868 +qtodec:1641140120/9907,10,17,0:165654.59977793479358029 +qtodec:10594464181/256539867180682,8,2,0:0.00 +qtodec:-46231449261/99440850943399,10,14,0:-0.00046491405516 +qtodec:27073997033/979290145342336,16,12,0:0.0001CFD50AA2 +qtodec:21909914237/215314847601042,10,18,0:0.000101757563313037 +qtodec:22790213983/20690898775054,16,15,0:0.00482F72209EE2C +qtodec:57162073993/66399138763836,16,24,0:0.00386B443F1EB24EAADD18E5 +qtodec:49004505327/38821416507106,16,17,0:0.0052B9FACDD757940 +qtodec:11768332051/3589682824180,10,12,0:0.003278376566 +qtodec:15850186666/2474635965095,10,16,0:0.0064050579113730 +qtodec:46667593003/1864122052703,4,0,0:0 +qtodec:-59759544899/1772867786040,10,1,0:0.0 +qtodec:-56774525477/9339451223280,10,9,0:-0.006079000 +qtodec:88931309073/791190043090,10,23,0:0.11240195683666335508307 +qtodec:-35855044967/97196495706,10,12,0:-0.368892362904 +qtodec:31352585060/666072991803,16,24,0:0.0C0CD4E3E1E55177982A4E95 +qtodec:-4008002633/30236135502,4,15,0:-0.020132330330203 +qtodec:-46826363590/29612569101,16,18,0:-1.94D0183BB64FFD4582 +qtodec:-35128605083/27702402610,16,20,0:-1.44A0480BA20A024C6723 +qtodec:-65659897349/54589663850,16,11,0:-1.33EA0A452B1 +qtodec:86323433001/89177536283,16,5,0:0.F7CE8 +qtodec:12490055427/952518779,2,8,0:1101.00011100 +qtodec:2264332583/1185373888,16,18,0:1.E9049A2BCA80B2A224 +qtodec:-74427879390/4597012537,29,9,0:-G.5F5O0DEKA +qtodec:29951503181/2445822201,8,0,0:14 +qtodec:-31576431431/83020171,10,9,0:-380.346499539 +qtodec:-9447985051/104277227,16,6,0:-5A.9ABFE8 +qtodec:35232385623/566066791,16,1,0:3E.3 +qtodec:-15116306133/99765700,16,7,0:-97.84A01D7 +qtodec:85943946533/13486473,8,4,0:14344.4650 +qtodec:17458384033/41778207,10,15,0:417.882558554990165 +qtodec:47372358000/36962941,16,4,0:501.9E1F +qtodec:-19944419571/15407785,16,5,0:-50E.7014B +qtodec:5577496827/9366839,16,9,0:253.738AF7ED4 +qtodec:2073882842/2445003,16,16,0:350.367A18E86AC9C78B +qtodec:-43839972997/4451064,10,3,0:-9849.324 +qtodec:26005540769/1779488,24,3,0:118M.199 +qtodec:1651522055/135313,16,9,0:2FAD.32DF9AD5F +qtodec:76197886466/518409,27,11,0:7CGN.30FE7G874BA +qtodec:765108336/7387,10,5,0:103574.97441 +qtodec:23901412931/455042,5,21,0:3140100.331040440011320300133 +qtodec:-30812270737/28228,2,4,0:-100001010011111011101.1110 +qtodec:-40336960322/42873,30,15,0:-14PBH.IOF1RIL9A5ETT1J +qtodec:8218880614/47365,10,15,0:173522.234012456455188 +qtodec:4420970446/22233,4,11,0:300202333.03222222132 +qtodec:614430785631/133706995251806,16,5,0:0.012D2 +qtodec:599123774551/302548464679822,4,8,0:0.00002001 +qtodec:281790013817/560893551217888,8,11,0:0.00020354622 +qtodec:-206717407741/550231026879086,8,23,0:-0.00014237041720054527517 +qtodec:666962690207/14069382615292,10,18,0:0.047405256395691365 +qtodec:931917525705/93596193043406,11,24,0:0.0122860711573932A1A861A6 +qtodec:-113538101447/619757160013,16,16,0:-0.2EE60BCB5C2D54A9 +qtodec:728394383355/38080601690192,4,13,0:0.0010321120312 +qtodec:189773534962/4102482488695,8,2,0:0.02 +qtodec:10973390446/485105217927,4,22,0:0.0011302213131130210013 +qtodec:-115610427903/163642536352,4,24,0:-0.231031233321010131133112 +qtodec:-24720050891/3267467595011,10,13,0:-0.0075655075902 +qtodec:406509460181/819769573976,8,3,0:0.375 +qtodec:819367776495/157261270951,2,4,0:101.0011 +qtodec:-256014045305/291786063426,4,1,0:-0.3 +qtodec:10334656186/19273767409,16,24,0:0.89449D46C54D81A73E4D1527 +qtodec:-186869912318/39153869757,16,24,0:-4.C5D010D70DDE0283131D1DFB +qtodec:217180119685/68726204146,10,3,0:3.160 +qtodec:129836079717/94890868831,16,19,0:1.5E46C53EB0621ACB13D +qtodec:810979911896/61650722121,8,1,0:15.1 +qtodec:45011863358/4039593361,16,18,0:B.248624FAE640A4ACF0 +qtodec:-215420752673/1003997587,8,4,0:-326.4402 +qtodec:784586911285/4052339642,10,20,0:193.61331492386293912725 +qtodec:25138297055/497924358,10,20,0:50.48617656700377771034 +qtodec:66808621591/367038485,10,13,0:182.0207534667652 +qtodec:657202139395/116949531,10,10,0:5619.5363399533 +qtodec:-50242217502/259433627,8,15,0:-301.522407370214770 +qtodec:-805222832932/648093307,8,3,0:-2332.345 +qtodec:176740416233/55550964,23,7,0:607.DD7LBL1 +qtodec:15978966044/90531185,16,14,0:B0.809963ADB03146 +qtodec:-22930906857/3466300,10,13,0:-6615.3843744049851 +qtodec:428950257809/90217188,4,20,0:1022102.22033130022220202132 +qtodec:-729269681423/3415862,4,17,0:-310013313.01003010133211323 +qtodec:716760678407/8104084,4,6,0:111211330.120101 +qtodec:-56519730643/958996,4,4,0:-32120320.1123 +qtodec:75679919054/101713,10,8,0:744053.55317412 +qtodec:899780170392/784091,16,20,0:118299.976D24C16D10DCEF0726 +qtodec:654179133521/312025,10,22,0:2096559.9984648665972277862350 +qtodec:157095035973/829990,4,19,0:232031121.1220131333300101012 +qtodec:-118896971485/312696,8,8,0:-1346507.64746463 +qtodec:291032078135/26972,8,11,0:51122413.51356143360 +qtodec:-125244286687/10654,16,7,0:-B3605B.AA6F343 +qtodec:-254071356292/52021,2,8,0:-10010101000011000101111.00111010 +qtodec:-411717868922/67827,4,7,0:-113021331211.2202322 +qtodec:-3022414154367/90907778612482,16,11,0:-0.0882E0B2B5C +qtodec:-17701275548/653297673253,17,7,0:-0.07E206F +qtodec:8979713291953/175380602612246,8,24,0:0.032156070756223520303273 +qtodec:-5326013448559/12787683829043,4,24,0:-0.122221331303312310031302 +qtodec:857488611960/30586540342757,10,7,0:0.0280348 +qtodec:5738645734057/90951057139915,10,6,0:0.063095 +qtodec:2150180745771/75085058005357,10,10,0:0.0286365996 +qtodec:9211573654621/31326323574601,10,1,0:0.2 +qtodec:-2622066957883/1546353871091,10,6,0:-1.695644 +qtodec:224011912746/207690732319,10,17,0:1.07858405738553459 +qtodec:9555205925617/1205795142091,2,20,0:111.11101100101001011010 +qtodec:-8730617437121/6055175866493,10,24,0:-1.441843743207007133126749 +qtodec:-4064904713342/494211830517,10,24,0:-8.225025105306892432251847 +qtodec:7676618287424/780404569679,35,3,0:9.T9Y +qtodec:-4358217891649/583281222878,17,13,0:-7.80676F3C2CC10 +qtodec:4328191663159/246276445006,26,9,0:H.EO9M9D2J7 +qtodec:737625000181/4792760124,17,17,0:90.F646D65A829FCC044 +qtodec:-71443761268/988984303,10,8,0:-72.23953004 +qtodec:381451888319/69461063050,16,1,0:5.7 +qtodec:201128820701/3339261143,16,3,0:3C.3B4 +qtodec:4042648911199/1793950960,10,7,0:2253.4890871 +qtodec:5673741769200/852342691,10,0,0:6656 +qtodec:-8389684341647/9150651656,10,15,0:-916.840095879505961 +qtodec:1372726881895/1560653491,16,19,0:36F.95ACC431C89A521C30D +qtodec:328988903869/101330533,4,1,0:302232.2 +qtodec:6568406520821/800160752,8,17,0:20020.66750526036730745 +qtodec:501238490585/5971867,8,0,0:243735 +qtodec:6266930625937/691212664,8,23,0:21552.44562064316534547754507 +qtodec:4565491072367/11630659,16,17,0:5FD5B.541017CCD8963842F +qtodec:-1162420020152/24630125,4,22,0:-23201123.0031031110222320020123 +qtodec:5113275296450/89201439,15,21,0:11EB7.BC9038ED2071A71B54669 +qtodec:3315661534768/61059429,10,14,0:54302.20342820434825 +qtodec:1733402780098/4797927,4,12,0:1120031001.212321010002 +qtodec:3283980196433/2438910,18,5,0:CEFF5.0A1C8 +qtodec:8489184557941/8439595,35,7,0:NG4A.SQX37QV +qtodec:3788804069259/3461851,10,3,0:1094444.581 +qtodec:-3096145670549/510543,7,24,0:-102355342.020600564131455624420322 +qtodec:-3078702213873/276616,10,22,0:-11129877.5698911125892934609711 +qtodec:1748608098871/9819,8,9,0:1247254444.540514032 +qtodec:8487930264661/21627,15,11,0:246C724D.08EEC2CE9E2 +qtodec:740911632886/11719,16,19,0:3C4B546.94752D05B3962EF76A3 +qtodec:563687406299/41136,8,8,0:64213553.32002623 +qtodec:1780375881783/26804,33,7,0:1N09JI.51C9U8J +qtodec:-3247679347711/26264,2,20,0:-111010111101101010000000000.10010101101101001111 +qtodec:21406766924698/763359226461945,8,7,0:0.0162672 +qtodec:24260209610958/200034339782053,10,24,0:0.121280224372428559322852 +qtodec:1814902384527/227339212768685,4,12,0:0.000200230300 +qtodec:31173219462521/203933404240669,8,6,0:0.116207 +qtodec:18030863259117/23714043196153,16,11,0:0.C2A5FEBA219 +qtodec:12974701069361/70664067852975,10,2,0:0.18 +qtodec:25696621276083/44253078013283,8,4,0:0.4512 +qtodec:9021988651073/35238715595793,10,6,0:0.256024 +qtodec:8048554533578/701038746989,16,11,0:B.7B1C260E450 +qtodec:-23885228112881/6921647732686,10,20,0:-3.45080088373872630271 +qtodec:33478283623865/8474518157089,8,1,0:3.7 +qtodec:-25807603431943/2948804373766,8,19,0:-10.6007565676256043474 +qtodec:89076698620825/964761424737,10,3,0:92.330 +qtodec:76836733524587/591287975017,16,14,0:81.F2B4FA0C640A59 +qtodec:2301284879441/92761811708,8,7,0:30.6357611 +qtodec:-22162325445043/7119385698,10,7,0:-3112.9547386 +qtodec:-88830049403167/77327410704,10,12,0:-1148.752409972677 +qtodec:40330389045243/30915263495,8,10,0:2430.4275130461 +qtodec:-97356183980680/88686324821,8,0,0:-2111 +qtodec:-61508444809/21872771653,4,5,0:-2.30333 +qtodec:-76008039360448/2365100065,2,20,0:-111110110001001.01011000100110100100 +qtodec:4553948402077/3181382511,10,21,0:1431.436926031746831338509 +qtodec:43200901021147/9612178431,4,1,0:1012032.1 +qtodec:98112477878099/2403895417,10,22,0:40813.9543776579361896591194 +qtodec:88141431773341/441452695,10,20,0:199662.23509710593113493168 +qtodec:-74737428452597/886243587,8,21,0:-244552.444607747231253546632 +qtodec:42004523099961/727188967,16,7,0:E1A2.DF30844 +qtodec:535967733905/65519711,9,19,0:12188.2235053083367133015 +qtodec:29508211302267/62743787,22,5,0:203F2.KH16G +qtodec:20444506756589/73095694,10,8,0:279695.09061079 +qtodec:60358251477113/17276777,2,9,0:1101010100111011100101.111110110 +qtodec:7675515321823/53051166,16,2,0:23529.5E +qtodec:68145812098865/9201386,6,15,0:422423113.430414512210252 +qtodec:9010952293583/1041530,10,5,0:8651649.29822 +qtodec:64799577298519/4451432,10,22,0:14557018.3479201749010206153884 +qtodec:4766086981551/1109401,4,20,0:100120312122.12111220122321000303 +qtodec:-14985202309069/259277,7,5,0:-1301154532.10024 +qtodec:77527740569441/65903,10,5,0:1176391675.18081 +qtodec:-34544219638590/487433,16,10,0:-43962AD.C208E5DFB8 +qtodec:89606198611077/718691,4,14,0:13123213120300.10302120010032 +qtodec:-20900481598325/19479,8,1,0:-7775046350.6 +qtodec:8694579108687/6527,2,14,0:1001111011001100010010100100000.10100101000000 +qtodec:11008512080877/36688,10,4,0:300057568.7112 +qtodec:-26629103193937/3238,16,24,0:-1EA2F4C19.E0C5562D391507BF7C71372F +qtodec:320315168187847/67090457824132,16,10,0:4.C63D998DFE +qtodec:37992496059712/933307870572061,2,15,0:0.000010100110101 +qtodec:-642835243415327/563880960452415,8,2,0:-1.10 +qtodec:-996741207812269/744724604059786,10,19,0:-1.3384024139643589286 +qtodec:865729136060421/18601273799867,4,24,0:232.202221202012312012111231 +qtodec:-190792427336021/12399475938971,8,11,0:-17.30615536546 +qtodec:353117587688196/41602134470867,4,12,0:20.133032231321 +qtodec:223068576005855/34076492509692,15,12,0:6.82D1EA2D84C4 +qtodec:219205101136492/2395575765723,4,5,0:1123.20010 +qtodec:456340378396493/4330214900946,16,21,0:69.6299AAE57B6C08183D61A +qtodec:3571581360820/3092454154269,2,22,0:1.0010011110101001110001 +qtodec:847831462081399/7150211415400,10,5,0:118.57432 +qtodec:-898578802522565/555835047564,16,16,0:-650.A0E8207F331CE070 +qtodec:663661151253796/453138066205,10,19,0:1464.5892736664396649880 +qtodec:271225450200625/257749526519,34,21,0:UW.9L5RX9FJI38PG83BX6NV9 +qtodec:-165514406278015/4322124123,22,8,0:-3D2E.F462JIGL +qtodec:969134788868309/87912888352,10,13,0:11023.8078515624311 +qtodec:349857780160166/918601801,10,19,0:380859.0183247049828067994 +qtodec:583417315283519/55625636618,23,7,0:JJ0.6AGDG5C +qtodec:5198673145663/2582846448,2,16,0:11111011100.1100010011011010 +qtodec:25224504315989/2747113245,10,16,0:9182.1858315815444295 +qtodec:-354734288655699/8606733226,10,5,0:-41215.90379 +qtodec:294622457238131/4699248277,10,15,0:62695.656809649983088 +qtodec:84851645314450/3149545649,8,5,0:64474.72505 +qtodec:162782722239884/940443795,10,5,0:173091.38845 +qtodec:-503919081966818/49953093,10,12,0:-10087845.450667449160 +qtodec:696741265176479/547456417,10,10,0:1272688.0963320208 +qtodec:123373090223114/171645417,10,19,0:718767.1676844945997014298 +qtodec:530906534529992/21770787,10,10,0:24386189.3706457189 +qtodec:25200685975741/10321244,4,3,0:21110012200.213 +qtodec:-58528486417214/9145779,16,23,0:-61A614.0F20EFF0ECB8777D9D089D6 +qtodec:-202870643410118/39728965,4,0,0:-103132222332 +qtodec:226786253503/4854200,10,10,0:46719.5940634914 +qtodec:947663833947325/1199459,8,24,0:5705715226.174676743125024435532213 +qtodec:58508575771048/1950595,10,12,0:29995245.435904429161 +qtodec:-162029920997164/5378993,10,23,0:-30122723.89965259296675046797792 +qtodec:-638908439370581/780673,2,13,0:-110000110001111110011101001101.0011111111011 +qtodec:54048561476435/260446,16,13,0:C5E8D1C.AADE1542405BB +qtodec:311253898901698/112463,16,23,0:A4F666A8.42F6DD7D2BF402286E84E52 +qtodec:-364014082098529/378836,16,13,0:-3945CA63.2A9FE228A057C +qtodec:662955978899037/29150,8,10,0:251345254234.0616507470 +qtodec:380819161094198/155,16,19,0:23C0A857C06.F4704F4704F4704F470 +qtodec:19950100398461/41364,3,22,0:1020121112200021201.1102012021021112012001 +qtodec:843068174103353/67398,8,22,0:135145224047.7022451545330470767051 + +# Writing decimal fractions, with rounding +qtodec:@0.001,10,1,0:0.0 +qtodec:@-3.5,10,0,0:-3 +qtodec:@12.001,10,2,0:12.00 +qtodec:@0.001,10,1,2:0.1 +qtodec:@-3.2,10,0,2:-4 +qtodec:@12.001,10,2,2:12.01 +qtodec:@0.001,10,1,3:0.0 +qtodec:@0.051,10,1,3:0.1 +qtodec:@0.050,10,1,3:0.0 +qtodec:@-3.5,10,0,3:-3 +qtodec:@12.001,10,2,3:12.00 +qtodec:@0.001,10,1,1:0.0 +qtodec:@0.051,10,1,1:0.1 +qtodec:@0.050,10,1,1:0.1 +qtodec:@-3.5,10,0,1:-4 +qtodec:@12.002,10,2,1:12.00 +qtodec:@12.005,10,2,1:12.01 Index: contrib/isl/imath/tests/root.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/root.t @@ -0,0 +1,44 @@ +# Root-finding tests + +# Square root tests +sqrt:0,0:0 +sqrt:0,=1:0 +sqrt:1,0:1 +sqrt:1,=1:1 +sqrt:1,5:1 +sqrt:256,=1:16 +sqrt:257,=1:16 +sqrt:-1,0:$MP_UNDEF +sqrt:-1,=1:$MP_UNDEF +sqrt:-1029384298,66883:$MP_UNDEF +sqrt:394820398429038402938402,=1:628347354915 +sqrt:394820398429038402938402,-5839823984:628347354915 +sqrt:17179869183,0:131071 +sqrt:4295098369,=1:65537 +sqrt:26965706504352387672564992041751053514175649974280741932736827760729,=1:5192851481060515336695158019653723 + +# More general roots +root:0,1,0:0 +root:0,1,=1:0 +root:0,5,0:0 +root:0,5,=1:0 +root:-1,5,0:-1 +root:-1,4,0:$MP_UNDEF +root:-1,3,=1:-1 +root:-8,3,0:-2 +root:-8,3,=1:-2 +root:17,2,0:4 +root:17,3,0:2 +root:29,2,0:5 +root:29,3,0:3 +root:50,5,=1:2 +root:4295098369,2,0:65537 +root:4295098369,2,43:65537 +root:4295098369,2,=1:65537 +root:-4295098369,2,=1:$MP_UNDEF +root:-4295098369,4,65537:$MP_UNDEF +root:-281487861809153,3,0:-65537 +root:-281487861809153,3,=1:-65537 +root:-281487861809153,3,8349283:-65537 +root:-19991036671350700657170189502736817905009200157042372341654483623953031910930270960998207372480741818129399253027601458115528449927512127290460743651463958852225556661727551760552841554362323271980596910944452290359774556447658518439936535499843549082781717193598437061923,7,=1:-571823748273487384719287348728374273472 +root:26965706504352387672564992041751053514175649974280741932736827760729,2,=1:5192851481060515336695158019653723 Index: contrib/isl/imath/tests/set.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/set.t @@ -0,0 +1,12 @@ +#Unsigned integer assignment. Assumes sizeof(long) == 8. +setu:0,0:0 +setu:0,18446744073709551615:18446744073709551615 +setu:0,567:567 + +#Signed integer assignment. Assumes sizeof(long) == 8. +setv:0,0:0 +setv:0,-1:-1 +setv:0,9223372036854775807:9223372036854775807 +setv:0,-9223372036854775808:-9223372036854775808 +setv:0,4324:4324 + Index: contrib/isl/imath/tests/sqr.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/sqr.t @@ -0,0 +1,755 @@ +# Squaring tests + +sqr:0,0:0 +sqr:495,0:245025 +sqr:702,0:492804 +sqr:23080,0:532686400 +sqr:-485,0:235225 +sqr:31727877,0:1006658178927129 +sqr:-8234442,0:67806035051364 +sqr:80,0:6400 +sqr:75029676,0:5629452280664976 +sqr:-8153,0:66471409 +sqr:5729957,0:32832407221849 +sqr:641,0:410881 +sqr:-82,0:6724 +sqr:7356,0:54110736 +sqr:0,=1:0 +sqr:7761224,0:60236597978176 +sqr:928319,0:861776165761 +sqr:912,0:831744 +sqr:334190449,0:111683256202821601 +sqr:#xAC46D3FD,0:#x73EF407495E70809 +sqr:-180,0:32400 +sqr:8965915,0:80387631787225 +sqr:1771,0:3136441 +sqr:131,0:17161 +sqr:2518088106,0:6340767709578667236 +sqr:31019,0:962178361 +sqr:460877681,0:212408236843937761 +sqr:2,0:4 +sqr:2,=1:4 +sqr:-43189,0:1865289721 +sqr:400,0:160000 +sqr:400,=1:160000 +sqr:16978,0:288252484 +sqr:32,0:1024 +sqr:4185,0:17514225 +sqr:246082426,0:60556560386045476 +sqr:5024,0:25240576 +sqr:4283818927,0:18351104599323431329 +sqr:79803747,0:6368638035240009 +sqr:27,0:729 +sqr:-294872579,0:86949837846111241 +sqr:5431,0:29495761 +sqr:-64,0:4096 +sqr:-27347593472,0:747890868709777014784 +sqr:-93,0:8649 +sqr:5941698,0:35303775123204 +sqr:68188,0:4649603344 +sqr:-10073,0:101465329 +sqr:712007,0:506953968049 +sqr:74981,0:5622150361 +sqr:590060947429,0:348171921680809101710041 +sqr:3375362,0:11393068631044 +sqr:6288,0:39538944 +sqr:-14938,0:223143844 +sqr:818,0:669124 +sqr:-61517636,0:3784419539028496 +sqr:-485757743,0:235960584884454049 +sqr:52047149,0:2708905719028201 +sqr:880295,0:774919287025 +sqr:23268913856,0:541442352037948788736 +sqr:8611582804,0:74159358390148502416 +sqr:-35440071,0:1255998632485041 +sqr:-123,0:15129 +sqr:-198239315,0:39298826011669225 +sqr:-18792,0:353139264 +sqr:42334,0:1792167556 +sqr:8871716,0:78707344784656 +sqr:-742998638,0:552046976069855044 +sqr:599309793653,0:359172228768401439084409 +sqr:92330620850,0:8524943546546454722500 +sqr:-21253,0:451690009 +sqr:-8591240,0:73809404737600 +sqr:-4406721416023,0:19419193638435754241136529 +sqr:7093605833487,0:50319243720880795970579169 +sqr:540053945630,0:291658264190530996096900 +sqr:6679643648234,0:44617639267392821131318756 +sqr:521589,0:272055084921 +sqr:13144286787,0:172772275138902783369 +sqr:-47469,0:2253305961 +sqr:480758624,0:231128854550373376 +sqr:-8238434,0:67871794772356 +sqr:-867204631,0:752043872027846161 +sqr:84079798766,0:7069412560531055122756 +sqr:14048677,0:197365325450329 +sqr:647598376181,0:419383656832267988144761 +sqr:89538606,0:8017161964423236 +sqr:8775965118,0:77017563752352753924 +sqr:135957585,0:18484464919032225 +sqr:76500157735,0:5852274133479880330225 +sqr:821777330800,0:675317981416772628640000 +sqr:38741,0:1500865081 +sqr:262422499893,0:68865568450091585011449 +sqr:-114911750278913,0:13204710352163261933292461569 +sqr:645965,0:417270781225 +sqr:-846535490921,0:716622337388858473428241 +sqr:56965538331,0:3245072557340630265561 +sqr:-744309142053,0:553996098943672933054809 +sqr:8398405793,0:70533219863895958849 +sqr:14899711014997,0:222001388330422931958910009 +sqr:4321091217,0:18671829305634541089 +sqr:818709681211,0:670285542108617246426521 +sqr:557620246567,0:310940339381441875285489 +sqr:666538614295667,0:444273724347187940858494974889 +sqr:-169058708804,0:28580847022475667110416 +sqr:-796502,0:634415436004 +sqr:-5416597755634,0:29339531246339285978741956 +sqr:922525,0:851052375625 +sqr:2993210,0:8959306104100 +sqr:1714169182508836,0:2938375986263011104043218074896 +sqr:-27353337,0:748205045035569 +sqr:9130672606905,0:83369182254485348653679025 +sqr:1596656380704,0:2549311598042796583535616 +sqr:-9683496758810,0:93770109477883775312616100 +sqr:909229240,0:826697810870977600 +sqr:333499398389171,0:111221848725938992589570067241 +sqr:-307250046,0:94402590767002116 +sqr:3035000042541,0:9211225258223871809736681 +sqr:-2721781933,0:7408096890805216489 +sqr:48792067992331,0:2380665898968251261074813561 +sqr:9234221,0:85270837476841 +sqr:8101724703211,0:65637943166619366033710521 +sqr:8164095821,0:66652460574469664041 +sqr:804766485,0:647649095379255225 +sqr:6183556496806,0:38236370949191691088201636 +sqr:48857539680655569,0:2387059183646833479261385610713761 +sqr:7026205978661388,0:49367570454577033123192362086544 +sqr:644316320534354,0:415143520906928406000094197316 +sqr:-2418657837,0:5849905732481518569 +sqr:-689024588558,0:474754883637521184519364 +sqr:7595432034404,0:57690587789250486239635216 +sqr:51477603372463937,0:2649943648972710500135406365539969 +sqr:-4859149914716259,0:23611337893687027113016478955081 +sqr:-596229664,0:355489812233552896 +sqr:539807450614764,0:291392083739210874761534775696 +sqr:-1566967626957,0:2455387543931251913079849 +sqr:65611170065548,0:4304825637370261946616540304 +sqr:30495282,0:929962224259524 +sqr:24673048425668,0:608759318615358173321246224 +sqr:-417870989,0:174616163447838121 +sqr:973135796,0:946993277456553616 +sqr:61834268876013338,0:3823476807431111794332536353902244 +sqr:82806890204302,0:6856981065307326523299307204 +sqr:1316959192994,0:1734381516011407738684036 +sqr:80328462383346,0:6452661868872633334658155716 +sqr:42624480104111,0:1816846304145754485399100321 +sqr:-375979141,0:141360314467097881 +sqr:9920379080,0:98413921090901646400 +sqr:80353168236771535,0:6456631645686909915006519786256225 +sqr:21921266256,0:480541914266444257536 +sqr:51036336390,0:2604707632113238232100 +sqr:7536279247897084,0:56795504902284238073836255703056 +sqr:4057492473172,0:16463245169847433139741584 +sqr:270453549401790,0:73145122384026464066855204100 +sqr:-97595328880030,0:9524848219201217774132800900 +sqr:2730620091663,0:7456286084993650522105569 +sqr:596640915610381483,0:355980382180394358404919444789279289 +sqr:907362117785845,0:823306012792813655285282364025 +sqr:3529407863794686,0:12456719869015768803663561838596 +sqr:5637629105915,0:31782861935859962287987225 +sqr:701177821774260333,0:491650337748096387958827849257270889 +sqr:388674994544,0:151068251383778429767936 +sqr:9003508844276352939,0:81063171508962508596780155978893937721 +sqr:5782278255807599,0:33434741827585369298571706144801 +sqr:54932190594257,0:3017545563483777218801382049 +sqr:2330326791,0:5430422952852357681 +sqr:2344523846,0:5496792064462631716 +sqr:734348606390121,0:539267875707112861194846394641 +sqr:1667343410703,0:2780034049214712934954209 +sqr:47416690990247089326,0:2248342584464579496535799798615023134276 +sqr:2992718026488505861,0:8956361186069257268281338748231351321 +sqr:36345508239,0:1320995969151216881121 +sqr:9136952501974852622,0:83483901023344519207328952878620274884 +sqr:-68684476889,0:4717557365515575118321 +sqr:3324362191672831934,0:11051383981423794566026717599410180356 +sqr:3950591846438354580,0:15607175937145207775001664097806976400 +sqr:452699498737223,0:204936836156932968571605751729 +sqr:16407472075973,0:269205139923833746283896729 +sqr:-42791759402,0:1831134672718655397604 +sqr:-969620447288,0:940163811798981186554944 +sqr:-7324554153015094663,0:53649093540450670762129798726851083569 +sqr:1246969904304174,0:1554933942240360863251113822276 +sqr:527095728932983463,0:277829907459393180154350270231472369 +sqr:133034527166,0:17698185418281191991556 +sqr:5806610887494202860,0:33716729998766214183769310106832179600 +sqr:604840631315943,0:365832189290668488059885979249 +sqr:7106121629098296578,0:50496964607538628518974633341246510084 +sqr:81378228896850,0:6622416138388112367939922500 +sqr:-18768741494576,0:352265657290218942237419776 +sqr:81188620065937,0:6591592028211068078227687969 +sqr:8219251025608152,0:67556087421960658524081448855104 +sqr:20867876779389,0:435468281279762622975213321 +sqr:27156769177930279482,0:737490112183384027655411672542630188324 +sqr:40320990680365371419,0:1625782289446111137560608246113822073561 +sqr:231848755308011786,0:53753845337874323313724120314909796 +sqr:841695784516,0:708451793672004705354256 +sqr:1766836913116,0:3121712677549275732829456 +sqr:664177322904,0:441131516259924282993216 +sqr:5979213918247228581465,0:35750999080161375874506971631233196141546225 +sqr:1758746127509067,0:3093187941028139358526167210489 +sqr:135179542401621982047,0:18273508683911915341791581411360790310209 +sqr:112047175441308,0:12554569524375254604552750864 +sqr:70541788345164680600,0:4976143902934011567084482333700016360000 +sqr:1492832267100,0:2228548177694925742410000 +sqr:3521705164411,0:12402407265039108540976921 +sqr:-473191108111249626,0:223909824795552331595427695285139876 +sqr:855883713881684,0:732536931687904321002750675856 +sqr:16916839558930925199,0:286179460662610259828831065810133189601 +sqr:296829185936965,0:88107565624001340524953411225 +sqr:7414275234516727336390,0:54971477253168072142121335070692704218232100 +sqr:90237037450605,0:8142722927861889317814866025 +sqr:60553464627047020812,0:3666722078339034795281351845204761139344 +sqr:4439551436109999,0:19709616953866354532829227780001 +sqr:5735204172472,0:32892566899940238322590784 +sqr:-477556465681133,0:228060177913855160813632163689 +sqr:6136903544018042,0:37661585108581203963482021513764 +sqr:7355012443029717610726,0:54096208037121975042332803663623262070247076 +sqr:2615297272121929464,0:6839779821568405573166111210191327296 +sqr:1236583510060121661932,0:1529138777352611011481426496873465697972624 +sqr:259304999298782298,0:67239082661341488057486265598160804 +sqr:67283385405374162098001,0:4527053951608116799312629323426390509928196001 +sqr:301048056239861279998,0:90629932165798680163672601418278954880004 +sqr:513985608867175879,0:264181206122561507573492869119422641 +sqr:8456087728243890247050,0:71505419667756916634176268857406110033702500 +sqr:978607251971625,0:957672153611455542449805140625 +sqr:190320200462916,0:36221778704244531620691223056 +sqr:213818886286553,0:45718516132821882562028621809 +sqr:-862217602106683,0:743419193382598324879713262489 +sqr:318640018205323583652,0:101531461201888944823553345475699841657104 +sqr:-500900129006539730,0:250900939238768144201293108068472900 +sqr:820114087330800098,0:672587116238431209810989756836809604 +sqr:55403047897851377414057,0:3069497716371613929908572787677424384421199249 +sqr:4810813844423644764918,0:23143929845698208536190754736426427483546724 +sqr:9103047106745502875,0:82865466627627670814122634036633265625 +sqr:963951698125641,0:929202876319306914592621660881 +sqr:539175052498265418,0:290709737236507269568171898774714724 +sqr:-50157204922004988220,0:2515745205588001416429472062562338768400 +sqr:11026905984136936161244,0:121592655582994972607713656480448242767627536 +sqr:3502071722216797290044,0:12264506347550524601785650136506422261521936 +sqr:-40351577732954785,0:1628249825538692426114606854396225 +sqr:-95254896582422725495010,0:9073495322928048629343683310955771449534900100 +sqr:60457070221477869,0:3655057339764706108220106456781161 +sqr:93325659970487089,0:8709678808926976205678491915693921 +sqr:413237232385124613101743,0:170765010229317482334791391007519236011269638049 +sqr:951114415591592288075347,0:904618631546136131332571710964234352253549170409 +sqr:401010074180215687828,0:160809079594022088656212052683319147357584 +sqr:52476554710721850732027,0:2753788794307383662963857897873667915763528729 +sqr:5258576802493280623,0:27652629987720455286211141065027268129 +sqr:6054103219841182396749,0:36652165796491372073556099894662392045769001 +sqr:956352502346019997280,0:914610108743494184401252227637651207398400 +sqr:-26892207599979464777,0:723190829600393285039943832095383659729 +sqr:764634776535170557034248,0:584666341486990214285762412733243291473444925504 +sqr:8999350031831592,0:80988300995427275943650249254464 +sqr:7641437781743263624,0:58391571372253409436905597502761613376 +sqr:27231085935730852312965,0:741532041239158628505821004397916290307091225 +sqr:54460324605443402457738,0:2965926956130264089583329153826508098876076644 +sqr:360110851757167625249,0:129679825553272757329435766523210102312001 +sqr:5646907739554115833792819,0:31887567019036174101601259024712393010835015966761 +sqr:8713094333529031952536,0:75918012864975725504514567963780052556831296 +sqr:6067775047370385059161755,0:36817894025490678648663816543505226751463254680025 +sqr:-39161602370641311011,0:1533631100236219150516980671952829842121 +sqr:7592562487471228106393,0:57647005126155282856061129287036732527470449 +sqr:-117854390966306661620,0:13889657470039065250071587891189181024400 +sqr:-5296482668083754900244441,0:28052728653311610979016516323012132263081551402481 +sqr:4890037916081745315,0:23912470820717098435617409376524449225 +sqr:878103465304676151,0:771065695780080592884753986988174801 +sqr:410286152523309284403,0:168334726952380209481013581654379939066409 +sqr:1320575015715850,0:1743918372132917474487941222500 +sqr:1130593146191972580760544,0:1278240862216263084092458499026711588345467175936 +sqr:9152293784326972307,0:83764481514630131881899390265544902249 +sqr:-30945617243677794421601,0:957631226592208454530069639810039434135403201 +sqr:637512608176985502983848,0:406422325584622643202173308977613669311348887104 +sqr:953752290145863389507,0:909643430958479183560202570458470797703049 +sqr:71232551174252547137921372,0:5074076346792507932127726514013453732491272854362384 +sqr:89641379812972941263,0:8035576974773672749927646579813248035169 +sqr:570533510213359628,0:325508486276377734955790890860298384 +sqr:156037452082545281465,0:24347686452412614795656577852136072546225 +sqr:820946717694830576249,0:673953513293915850368458978756517402910001 +sqr:897982009226057242719944960,0:806371688893666754984415476086593388617121385429401600 +sqr:30047225710589062348346,0:902835772903084382776376808801558904248935716 +sqr:91332956688159987977447,0:8341708977401308279373560739783999581780637809 +sqr:779547769133542092868254,0:607694724361082242143909923818285375848601008516 +sqr:70223199028646964984,0:4931297681816964046455576234794522120256 +sqr:-7130588717194686908,0:50845295453784170628102737064146600464 +sqr:7862855876206371917242,0:61824502529993072660297880196210138896886564 +sqr:99635166626419149819259,0:9927166428674308348042432184271252852367309081 +sqr:9143110466763720332929390,0:83596469007444295894790689042921258303578725772100 +sqr:624603802062355481979,0:390129909550750146243139974448833393756441 +sqr:57467188276773877127351,0:3302477728438176937336538778081989035872277201 +sqr:56666158509765775413,0:3211053520253900204952292290417155320569 +sqr:1669285813108053464947655816,0:2786515125843815201176904833798671100095144793598625856 +sqr:-3894381579633443035,0:15166207887788271015100954608590011225 +sqr:260571571745997869095,0:67897544002179714981985817184280756119025 +sqr:53560277137779384583336,0:2868703287075733025329170304306805830328888896 +sqr:532633647890554999729943,0:283698602865199724513575317928240776802930783249 +sqr:-8109683324597705697831,0:65766963625258096837076939441707642678104561 +sqr:71512764950951349786,0:5114075550930015809763806667815322245796 +sqr:-3230261313024043132,0:10434588150419815167286482704196369424 +sqr:3876597618180653484531214,0:15028009093283915659666843759569773575981340313796 +sqr:2022902748890635933130119,0:4092135531469291257986156298716581802948984954161 +sqr:-9239803654422657921335,0:85373971572282304128064994834647223048182225 +sqr:40891548247525081118,0:1672118718079671532749847110472480129924 +sqr:165164019691356860628567608,0:27279153400606916807248493439181759924278997826841664 +sqr:236044194969218596813550,0:55716861978666481928715444466626794213463602500 +sqr:-9327691800876445934166044473,0:87005834332137675107296063213991033162475616331013847729 +sqr:-1141008979009187167080443,0:1301901490179587721260801760634357975556433076249 +sqr:80240901025439711368171436,0:6438602197374411723371216408703542996140198286302096 +sqr:48396694980176876386,0:2342240085004277665404844769815924420996 +sqr:8287110859147430899223483,0:68676206391799270292835857144249638800252378651289 +sqr:979738309307210018577,0:959887154724150329311355128100080685104929 +sqr:79997549118990663707588,0:6399607865045323915139363453196300002368777744 +sqr:404720558142791950357,0:163798730183413039673176219498755952427449 +sqr:39783276700470626124196,0:1582709105026208988642497555015175748816646416 +sqr:68076977401073761586383174,0:4634474852066307646499543932220927310440054750314276 +sqr:8780946490021005951868,0:77105021260612224378649288336653880732689424 +sqr:2293326364302719333015,0:5259345813205928950683229209501046468990225 +sqr:-85950587462318432622522110756,0:7387503485117650543389782822459944191622287564105530891536 +sqr:-45213570780978740239083451,0:2044266982766574490551025400685924690824376542069401 +sqr:-252288475394454050742693,0:63649474816858046994487266873669024064892892249 +sqr:13343208905111714280686404,0:178041223885452552994753470810964520657769390451216 +sqr:2532670767542782527921078886,0:6414421216765747171902768427962647904467236158235000996 +sqr:90594811403510761816916775742,0:8207419853237683569360118704220290897994537812705119650564 +sqr:8205141011719296761924,0:67324339022197964842201619162042351536181776 +sqr:9720036859316498875611356,0:94479116546471347354649044496204860597822756158736 +sqr:283132666802141375993924892,0:80164107010492409231567496032871329019099690937211664 +sqr:35478297544662423863733,0:1258709596667599773811969774518746956152695289 +sqr:32285080416677631255843925,0:1042326417511341492231091561259042214939463959405625 +sqr:-34268147969999862649888,0:1174305965293805707432076575873585053266412544 +sqr:700904064615551520403894,0:491266507794601220883840126321977531400890363236 +sqr:911134642830965648237534581154,0:830166337366711341532911911675565532094507072828006211971716 +sqr:51391198660039915856968,0:2641055299715688443070254859801397489834153024 +sqr:66416349272456975065639625734,0:4411131450680996161120441843876023071544149766499595038756 +sqr:806758926584205263840,0:650859965623299098779505861978364011545600 +sqr:477799154735707308352114224,0:228292032266156375585779864239845871819082410743122176 +sqr:-1654950158079442331247637936451,0:2738860025727171161306644564106812249408719162131709514475401 +sqr:942376212580429636273132640938,0:888072926037435108264123633745578188505325516681766433519844 +sqr:-173744882442406814125820238,0:30187284174925763628296929994001889276434196290376644 +sqr:2808504238232363752504253,0:7887696056169149811385548240526285742328783088009 +sqr:807298846393541075908135,0:651731427388342229023346153451352474114959178225 +sqr:26937190640553605997330,0:725612239605528790179357561582679743967128900 +sqr:62574675969704339348702583,0:3915590072713493701996057357474786632808765390871889 +sqr:804162708867230857991464,0:646677662332682695199247623301634798792296863296 +sqr:-386730036170782490733,0:149560120876654733607852171916967230877289 +sqr:-434273419527492647189701,0:188593402908101632063112882554636374293080469401 +sqr:869166535411038930671123943286,0:755450466278428791412005047210119303561723595211750144477796 +sqr:10449922204455770677506,0:109200874079177753861811872396922278254380036 +sqr:-90720321424101605506013285,0:8230176719292308756103957083707087895694294596491225 +sqr:618017451906480640476197978670,0:381945570860979111437601753456109637509740412489393774968900 +sqr:600218595859234657114146,0:360262362815231263075003129475804047328873309316 +sqr:-1271084021549941372472074416151,0:1615654589839571823374561631341349734773214052728307529654801 +sqr:-1550867554578739621065776,0:2405190171845039917385273345455165995626118482176 +sqr:6043648591268889505332580,0:36525688294746432641148169772867559568256409456400 +sqr:4436117400241675705710942,0:19679137588726963606581585499912481843633658527364 +sqr:963653222408138267064741,0:928627533057588796323445139533613848091885397081 +sqr:79810459027918017737526,0:6369709370246980620783598883260816355828600676 +sqr:902803003175340266413761,0:815053262542413447161071151674614683772050165121 +sqr:41752360733446165868795969,0:1743259626815817253890642356111049015824205750648961 +sqr:18433679660798345484293758,0:339800545836930605431594748131416795001464037762564 +sqr:-8099616466845982700651861415703,0:65603786910002599981017618042158396492585415981482319374984209 +sqr:53861499928450854325903869409643,0:2901061174542511385668622771108001926502370466421638385341387449 +sqr:-9539042911647353522749973,0:90993339670249619985617080925599605810472271500729 +sqr:-9953723302036330682964697708913,0:99076607573501034335207891975711363757759935206913991279641569 +sqr:819405964225846194717255113,0:671426134208888733847054770271652175310634741124642769 +sqr:802401078039205223147440807946,0:643847490038478710635011163996163360107384995763769256738916 +sqr:519449268240923314088505,0:269827542276030702352860062200068431818973135025 +sqr:-4555091246368490325696260,0:20748856262742846629765230682011655772853777987600 +sqr:92030015548432048748093276815,0:8469523761844644646313223067398164807006285055804216544225 +sqr:69892106365908429041254342845691,0:4884906532263457551578632249701418592382287262507816195837267481 +sqr:910047959446947352191893618610,0:828187288493552732485135863553654427423698002303240138332100 +sqr:248378228391386474704886916939167,0:61691744338843742253916643321386052988120454926320117359978653889 +sqr:44668713115713790179611935799452,0:1995293931413941180740289260931549563994989167786466958363500304 +sqr:554146318830994817582767590433,0:307078142673942561571697027825775135058421635981084833127489 +sqr:913107312130554773072541881000511,0:833764963466286379835121944707623846292155777477098298802382261121 +sqr:81108023466385198143279886584,0:6578511470623691973244557720131367432321893163523903189056 +sqr:-4943833529340426042939004,0:24441489965830613211569173244841340595166064512016 +sqr:51140730159890637422105920403,0:2615374281286747861428645748709966547587341461263771682409 +sqr:-607843803842581788311388679398,0:369474089869819046801414956186873945785214116905230429642404 +sqr:122000635477119336893648,0:14884155056820949371250828570794377554062747904 +sqr:5316396721948668528754688,0:28264074105146548353074606970605680292688081977344 +sqr:3871007685189086282275603,0:14984700498792968128669630624162919017232049013609 +sqr:7594454675984973208305706419,0:57675741825590024399104214106984154178550700718617803561 +sqr:28214522979760017572876300,0:796059306975406100990301973660076181981455101690000 +sqr:-8758954355837792555434977,0:76719281407649839529729437792891939009581674990529 +sqr:192247354570382237619981,0:36959045339310268227417106552924468739370440361 +sqr:17921008488602803526064091292,0:321162545248573740358745190642913074581611098877710229264 +sqr:2786656582338594569854846808207651,0:7765454907891016297545581568122273298720717571197646453099134937801 +sqr:-8119878340729712848165819773762372,0:65932424268251514701015178259411842162406168492081516233544323066384 +sqr:-79010392379176306659400405,0:6242642103911401396317544499881175920416754114164025 +sqr:502548653639979591878843903680232,0:252555149275356173101979364004936274487595147326132901113707573824 +sqr:370095553656392383016573,0:136970718836231613385863745681913470927192664329 +sqr:3308233251214375641713788330957879,0:10944407244440438253289991279061494519953582690662512604421672178641 +sqr:-183583169171890388291350537,0:33702780003194925435879559331574763782761847410188369 +sqr:20022240072762280694432559381,0:400890097531327699316940227336660015830476888446091103161 +sqr:991600160459479600853539507705,0:983270878223265691657333328413726449497510327213293754367025 +sqr:-886802930484090401215003053,0:786419437515170472599024051267193209332214818799320809 +sqr:-4021243178549426619810076170246,0:16170396701030295777747606521080114147933679758148426375700516 +sqr:-437190641321459296906356238626351,0:191135656859068873243134481446335599971533230314698916447391575201 +sqr:4949096192729469662233605922109588,0:24493553124889331919611856555201632265117322697483182895572281529744 +sqr:-222922740889004859161836432272026,0:49694548405466398945671001441165552874782078359206058576462144676 +sqr:6633207453537081635390578639208521,0:43999441121659895022772886274234937490050952802629650017809319007441 +sqr:-388419057976394528897376766008911,0:150869364599269734301902942514512041010013259450627804723731405921 +sqr:1587145903911990027117983209,0:2519032120304607880066057705136945202936833323605937681 +sqr:9341556580305242597961446590124642,0:87264679343044178399059265004205078308505980101212849351757095628164 +sqr:-98589396724476958519746033,0:9719869146496308037624494359753950110951166819237089 +sqr:68949788143317567890727634506437,0:4754073285008375866022480396033956238363312230990817816594434969 +sqr:15348440724699030968793800,0:235574632679599714954032510452755198589426918440000 +sqr:19579760235445809588453948,0:383367010877544944929983398547473038485912916786704 +sqr:72079227800301785573175211637474,0:5195415080287797782151390372393575616172253417843110320401100676 +sqr:6817374173872891802717574,0:46476590626589093993102340500884140128371608445476 +sqr:27365680739830168291453603457,0:748880482354311826968810008262872424540584520070202350849 +sqr:267264590007941098022378239,0:71430361072112848614264522780315039578433629580741121 +sqr:6823763963460016478347085218,0:46563754629015553103873634993707652191220912556554107524 +sqr:8549091706180068110128584180,0:73086969000676828009663171737806902080553533491346272400 +sqr:-68363462105740373654914242951,0:4673562951083000043628088543159794818215387066081453188401 +sqr:63674293081366378395048823165,0:4054415599411742243170904564153062594260665424051440617225 +sqr:12314822493559883827822938851812,0:151654853047888474961995203087973689051788205242869652895683344 +sqr:360322042567152808702152365098795,0:129831974359765080636852128393794927791043507146551510810110452025 +sqr:2648892181207467563739706353,0:7016629787662055175845497345399540904332220966668560609 +sqr:1931728450461383908845059474429384,0:3731574806321939346389291168735723327873036035228210710552402619456 +sqr:358403207284545478566799458841,0:128452858991848873192347508921766736387368968538450453063281 +sqr:16923832563401191240604105408,0:286416108634038535732613208202327062603817395183974846464 +sqr:-60296919348805772314352496412720,0:3635718482956387921607376827103051300909552440589140468577798400 +sqr:137381863838359684196723188000,0:18873776511701600260921940211907923493005196696883344000000 +sqr:591213095515431378414779198676378,0:349532924308938586251105113436721993590864360832386253227175198884 +sqr:550075895507569886172410506205,0:302583490818454944080300856365310614939073667909864343502025 +sqr:711087936283568776727078639050747961,0:505646053128024768394217620639062509678773141734419309834385513545657521 +sqr:87137753047658080124389033343282625,0:7592988006194645030937734327894136192749543225796276656746210626890625 +sqr:892477052408611488403157406380218433,0:796515289075963457333727567531410316000818421665541198467895652792975489 +sqr:6158563241782182682620279504718154739,0:37927901203030667115475855586796884579475600717657459343120085141148158121 +sqr:163129498185919713569905746566,0:26611233178389983120491164583169402737995471084949820792356 +sqr:-840675253673606619740059054280,0:706734882139182840398643757541187982055463962461807986318400 +sqr:3156757217808506455275677523420556199,0:9965116132186102265018848181467495754138541196082820401622097670517327601 +sqr:993671209419443022612977747577,0:987382472429098591948836324268579783286641834412572329370929 +sqr:-9326822514499666899515267554736938,0:86989618216977889172048813242979601855371201795395107397962381615844 +sqr:-235676703573040466448512193799813867,0:55543508607054784964710322367602777661099488105005836599662883845493689 +sqr:9745324195976053070545476544,0:94971343684676305233934428420617617171065924820054183936 +sqr:42036349610817613966650109709956317,0:1767054688602886165196914277223620205192980370693225930615078048204489 +sqr:6423789221002494265324250049541,0:41265067955867832110408469297659891351326774859357340954310681 +sqr:39820799073224257724368475037593,0:1585696038830097902894340812101752876025276615089993162763233649 +sqr:-248685011975388562625272850484520,0:61844235181199152802863183501684240433880069673516902798759630400 +sqr:7810586566859132079040306752412919266,0:61005262518400323306681848115066990496722484937205544401071870384233978756 +sqr:148248035689146148163507965322876507,0:21977480085690350061040242660528838386718186881517058316005748772521049 +sqr:2174924777531088681854941082964503,0:4730297787918655595183218550423839198281245191521603201754758037009 +sqr:7460214282782494008461541364649578693,0:55654797145031921479620736345863324550380883977276538456407066982399588249 +sqr:910214324198168001046442701640701,0:828490115975527682261108829195991618894759199353089171357299771401 +sqr:-59899876223007500200643117496816827084,0:3587995171531619267909340862365356764690500898711702775194521329813155943056 +sqr:3693325822188682181380816692,0:13640655628845705229325716773595065057160551856905822864 +sqr:-377300624776321473819796906114622586,0:142355761456602529596293103174374647548147320880285674734176169221327396 +sqr:414831269398550325451238357295142,0:172084982070812635693442772673726339898901985136718231410496800164 +sqr:6560318055585225985879353052799903,0:43037772990437520228181479222553604645045752273627418993347756809409 +sqr:81752690538327392490210233502803189412,0:6683502410255525163317352014073423856877240881760773530410353274879548905744 +sqr:218839351597324273539262978455,0:47890661807537314072553854206046627823699636362157794187025 +sqr:-5805326576316957672801693030589753,0:33701816657691969378866024022901213186262873511166214639390988601009 +sqr:657052654171627411520319781527678957,0:431718190353980208506608543148088461575698759507192213967541915660607849 +sqr:850803172144816061232121227544210866,0:723866037731681512526641628957082234808088810211668969221470630672469956 +sqr:96750262807275012100488295035769,0:9360613353276782505243770907131423414773817247651756648989421361 +sqr:1302972096425652715773488728124955290,0:1697736284063860438660129973080040668130028649420585700653556064498984100 +sqr:362539128333737071068563296326856312,0:131434619572985877564322363931711449060712966012688612245083752694241344 +sqr:8647059398106102973445629549035094,0:74771636234375079831388808708994826778243955204442145247786443588836 +sqr:4801679506442312786805559965365951,0:23056126082588092523487649586475214155591493450499364174637350134401 +sqr:-77184374294092760219449891857411639,0:5957427635170607277431236668258878037311657775496943176517416692666321 +sqr:237675308690641513277997273186171423,0:56489552361191733248853882918288952408272576415112822843718756741844929 +sqr:-5002351530431559668603019491716529,0:25023520834010967237231458781580750346527800518094804987246891807841 +sqr:43664655191273703505834328260330,0:1906602112972825584894722514125938669910101850559285284251708900 +sqr:61437334296785487665781722675145481656,0:3774546045494974352232649823192447953130381594535380154723604664512232502336 +sqr:76999761286305362841208123728009,0:5928963238148010105553373748266081481905919994513298364211104081 +sqr:4045969265340624054820554440481625,0:16369867296080949138563301459618249171273665229809612664561962640625 +sqr:-90733797775896931157915560238405881,0:8232622058837358891226618551896739737707140965912018467654084095386161 +sqr:1250789450925599394334826479552697791,0:1564474250546762415577515695203307841292579604239130459928690626176279681 +sqr:5972484542109405765482619578501051194087,0:35670571605735798250313214826049005528483190382247035739054380369668008543763569 +sqr:65678344134099005094717808763640919760,0:4313644888197137191319800821202398871887873211187330220689626491898758457600 +sqr:-62990747469444164811979252597669258024,0:3967834266759286452973199215274493545160660868223522376653578082958688384576 +sqr:-53997255662311143749287788767141410,0:2915703619060992875399948731380693863707266595015584952708102936788100 +sqr:5686190404642301882852816915831698249955,0:32332761317846184821910191091058430280642996317973095727786765956628209657502025 +sqr:4318656996688968372478897431491494622189,0:18650798255050580180132125928030568680914499281769771597690822356558707851151721 +sqr:90772643431688731485119396638690,0:8239672795576503406798366498149929387564332199866630470404916100 +sqr:5194695663243172552311326817796924132,0:26984863033717424374763712982568150984157237537337208924447183760163953424 +sqr:663052304331426874021220834995676750,0:439638358279215120964420211896852784266488221371872739050191190490562500 +sqr:765274211863773061319130051954728,0:585644619343719017714207640892708560609108866025443392573761553984 +sqr:8793390746808666322341142829879636,0:77323720826060274427606858051544436111644164324015870268834247492496 +sqr:-1143404644203622436511911843731903,0:1307374180386412415102092423534367931853000575304412276790140001409 +sqr:1274715157279956414098609764282,0:1624898732199264017780108312111877512545271895107751602975524 +sqr:409119214024402199476926287393039,0:167378531283944613340338055007668151076742941392029630986865655521 +sqr:71377375780409892756507920763626830337332,0:5094729773297844747021699813855551310975623888825070108789795349920431748912878224 +sqr:16711505580703743734170498011402976914,0:279274418773892371081455883621263741224242040916240683397794226501216963396 +sqr:-74453371480687043335744644177229319766278,0:5543304524841182775798580739240538131276183842677571645900572414881617796545973284 +sqr:-6405878501504187329383105565378712287,0:41035279376033532548797887930856354109329109091108165640510577306324770369 +sqr:40950531000192473613267941356844194183,0:1676945989197724793333658733771064889173041987235658694162953328114611037489 +sqr:4307204533471560374295387513178008657555,0:18552010893157962052718908742109438219933838558835235689466967303594533258578025 +sqr:-149484891420637067740168061887375693,0:22345732763039653620332820862877954314918077499338875920118166527230249 +sqr:8343682513737833903327046937516169964,0:69617037890054498842921226973866568012575744383637684564661631967735761296 +sqr:3509188584470681541017936658877926984,0:12314404521379345637100883238194066833159131043160907804892714733235336256 +sqr:843579050130514060756624621185917,0:711625613819100354786465278348435375464052902370772400359479130889 +sqr:31410619716472975493735222400837838865,0:986627030972880827393632528272477830148142517559149626692979125963704488225 +sqr:99785546587226129843537244978723,0:9957155307711476328643044694094129659431472972828141076722710729 +sqr:87088383260454928172097866342477398,0:7584386498919886145615067404165620415719691675067902815356104140850404 +sqr:-21019572728823619340736653333183687,0:441822437702305615250281344482791728824090026904703796170591282913969 +sqr:-213022293683144585643783023194682847,0:45378497606027901635433606485223048786626898394552542573714372916025409 +sqr:821558964589159729952441643882176928965,0:674959132296812211087604639834230395153394804319126838028473912988118655971225 +sqr:93628576598887540441164941175327620645,0:8766310355933751549963656542407355813018943206504806465783388451037030216025 +sqr:808908479404403522256434597056244,0:654332928052344317344932524548899015475902513950134223950499387536 +sqr:2403686005394008280252761408349209,0:5777706412527004403350603444613906227812077284451715581174490925681 +sqr:98761522656704312056591131334972202427,0:9753838357470719156604333998408117019236907401667603138016126272795064690329 +sqr:264921969502430465410895298885047472157,0:70183649925046697616917925839949419303701946877664620425503463543495690232649 +sqr:5734044193381222850292161236386120,0:32879262811648918591058681843423942962076958921730666289037728654400 +sqr:-77343515936181223098604746930499746,0:5982019457370318819325847928980176284218772540166615080618809306064516 +sqr:477530086265353018187224199691826067746,0:228034983288595495261021696621307088152352747277191879096752478920892981520516 +sqr:6380429851450892850108602700855721,0:40709885089285662602074098891157189887680003507622857222825658429841 +sqr:1614017525491513292625779920457654198,0:2605052572593747761378509433651355353858519931761187647033655684947023204 +sqr:5843196999513910258932442804866747074,0:34142951175128363766762829236509048605085738725187936744829961482287561476 +sqr:-16840291081678306354388229172771403474441,0:283595403715653901461439541409615997910511102944454782045143368506083646540262481 +sqr:7474294456536468895568721815784039906712,0:55865077623011788920219279745354529689516076975872074869650077219876961662650944 +sqr:40025018325908445925732334410935532,0:1602002091989306935275241821685425175435487432655654492651387460123024 +sqr:71178821881382993600746091906288293726,0:5066424684421646444739284493107312862767524722848585207267121476784450963076 +sqr:-956534424185242867042536059215467741482912,0:914958104651394134287596545591933348101595618215576678952462132267362996716787999744 +sqr:721829962859255739884681107822513072001361,0:521038495281394520876802923408055786959896312734012309918355263586370064581985852321 +sqr:513339816745878383185851793188104945331,0:263517767456692000522339869140844051045940350138813491305250127423978498699561 +sqr:799894410213938707352908144028526318948,0:639831067491504852234204013807619439299774103064068517022995175896723023826704 +sqr:5059143920618658416911136512212276876813,0:25594937209532730337328341168912486221010349334531467986696362464941481577036969 +sqr:7379242107602262033739052700681405641112,0:54453214082610274166992064235604092051241247993780042359574422852539255744596544 +sqr:4599028230060805133113661583732548660414,0:21151060660896221947440972108717970222629954445507481380394996890598345890651396 +sqr:-610947584794355405122282058915720029,0:373256951366056087824599406569194476559334062938481114234422535511760841 +sqr:151016760305167557688524773300221125,0:22806061893068431731595439152646898640190980000204142970991973896265625 +sqr:-5043972380615273383773350465024144665722,0:25441657376409708308182401188063792057370329788793418956979339486342827121781284 +sqr:-1901326156132477111554066093388015224,0:3615041151993500730555701528108452476651988041641332535522955478055770176 +sqr:186173294979292913545567242624444046622,0:34660495763446811970285555836345743988397392804771376759698280409658509610884 +sqr:134444238155321083315064919179926948671901,0:18075253173164693407381472881519065043651038267940050028398999140418897027746953801 +sqr:182751469381748889650715918274290926706,0:33398099561188301891306676682175702712867585589145527684366524689236264010436 +sqr:-19782833113399238615456499401930538244,0:391360485992605412572841611431223918801790691677441123223853085111546603536 +sqr:-53439814746421546360134168635454563545302138,0:2855813800131853763301018844500573332922284544274015258314229885052800908865809707371044 +sqr:-942658818709448211511437874237821183862608,0:888605648490692349494488804835692227243472617418048028178845602724596399794620561664 +sqr:9834555863623710363291061910128791251884,0:96718489034735503589624960384782834610966324564239408703329883463441847933549456 +sqr:51449832652939146582734700068610837004647986,0:2647085280015443222139677978390743228846577502050643060932244409106773419670167773856196 +sqr:2291742184006479592618233849836236908475350,0:5252082237954788967476725027613349500538682695376657947018844871340710892661557622500 +sqr:35726042449731702718621910342910442871,0:1276350109120031602372605532253019950930377400791207831395379049985354722641 +sqr:314864095665797450690432494576559180549068,0:99139398739440448973186550472760318244168691761448570815799105906596791989955668624 +sqr:-59649935536675658576676397615555554,0:3558114809529561588382641776313422189329463523863391447026516060246916 +sqr:46149412421201088724138934931962583741,0:2129768266822109334168041249232625528680710162397761120741201681200437555081 +sqr:81505683246039956870662440686055779,0:6643176401403798520603430158045363639536746978811045511154051899296841 +sqr:-91299975424257598936582802453683157768592,0:8335685512470041532934583154336766995790602158310653976092333552449139600621662464 +sqr:574823126630437679349613040851854060,0:330421626909192191581312097609382416497762511199933655831540139538483600 +sqr:5848279024202366423130208101566693655407,0:34202367544925383191149561091505226508437583697212620809081729403292547660335649 +sqr:33303836250493780483071804093805232,0:1109145508999703631203582340229800796051766205357661302556477550573824 +sqr:-90097283028670050701146267779856415835245618,0:8117520409148276344113019232317307994477445330168474386622133497011544293514182388201924 +sqr:-14668385513233950758334444245442362205,0:215161533564851632997671384914831185622213282649650113792531204770412462025 +sqr:7590774137730042375112728223871690355920093,0:57619852010031268329372461592010579705963482263927747947299813304373576413452601128649 +sqr:343995691938696340599208107211356310244992,0:118333036072382474528342713640289708614178710132517265632044214980665310259061080064 +sqr:9070182305961666411059354831291359229936,0:82268207063380092355731635277150073589698333812886179476183173042500898918564096 +sqr:-613222418174165442752517769424869180677247339,0:376041734151371031903812645758550041032916828201133265381231649900288825614887998182580921 +sqr:581873090996018714406098523305834447403,0:338576294025261075090661404647983063923320691169652763323293680756298373444409 +sqr:820560888183185727159245513358928235617874576,0:673320171215978629926989442338497570791398876600290863949889599973315463411875711667179776 +sqr:-9626227543559910905998441385452600037,0:92664256720391476419210060982085791459697761624823914410791509283492401369 +sqr:66650014481401668085852877112449263254057605,0:4442224430371052066838460958811706436780164160347132176597571432339519948135496658336025 +sqr:7315583918748836072386922803226766220,0:53517768072256576981304868128894291620776130258551034531987652238533088400 +sqr:70529223458010474926294230806646675385113866,0:4974371361589975054598623878560502789346907784009727387771830847443624158903789785465956 +sqr:401470286946091912268711270125222133422,0:161178391300577378096702751397459234166566519344188262751550714578757169430084 +sqr:4572343757129188862013232461765111042143389,0:20906327433358266822416965557951167365266138697665588057103694409510400778423236405321 +sqr:715210017519130849476306967366881834101790443,0:511525369159715456627844733333364085544303094139050148620796444543726446833386218286136249 +sqr:4527199826692724171566735731879658501804396281,0:20495538270806631774445707083379965566022585863396771217697173872449187877155922938886630961 +sqr:35406064719217317374472447210630089246913,0:1253589418901405255011316475685007527140454016052775693446831108384535391480029569 +sqr:2644657831335048513698968865262623996785,0:6994215044841801912150035078815852976779574670478382280388121561737327690336225 +sqr:228843981090068751940043109460476113233,0:52369567681151744523434257037145251209496783558582439385608973652170637712289 +sqr:-363455548653099175486553836897754887953239,0:132099935846725341876165715863568689720197347788826724804411086993540711366650591121 +sqr:49645456723940808192361707189216800740740233,0:2464671373328679603526959106904136209915438913265444195194837009476455587724892784894289 +sqr:-41972159081040399279897402054342460893529,0:1761662137924162054566224840868772179586183621899204603865834479280728681074073841 +sqr:904449444989445227486671780903374927026028972,0:818028798541715508716549477493246211642182516309001046520574799048903490361447595383376784 +sqr:-4637800501264787734476081456234817427937,0:21509193489531916376293763644814267498077828503138957431543983297006948188075969 +sqr:2819020042629861965107669573484320344278,0:7946874000748868771060776526221076809798728593879130631101816702469560447341284 +sqr:-1419073712851139608844222498035130011907978763,0:2013770202505118633030036333824745381599233534572616361640971080598274677688338220059010169 +sqr:1279435386592185332336335306072373865346150,0:1636954908464294734873238356134567494583629002794863673644038288728942651859319822500 +sqr:7540143721140140666472157286788379305,0:56853767335449087373733223381002849374201673267193998122596274388552283025 +sqr:-5262011646580039205673608048505741906619582985,0:27688766568743975427118675132271563800332472067380214865377259872310937555902021895301510225 +sqr:-7327313385175641658893891579493621423472131,0:53689521444574121181384482122663805719648236391922401719821519793880350881347733681161 +sqr:5706335860903446254669972577013696202625,0:32562268957432675122028129097936933650790091200861535522835758415216345056890625 +sqr:60764795039857320711933375802630887834931,0:3692360316235868846208377282943565982855715966661963445194081550939587924703774761 +sqr:6600882114332387632455874953453879300978,0:43571644687313212152096063287158210620222118112302362027400043627924277911756484 +sqr:-2251822567054969085004683861579459385511998,0:5070704873498030741204798440716913976082340904309541108933200404386498317664601952004 +sqr:2529814352175492857421615283607797166745474847,0:6399960656473108602788181861993114613603433429900229071740736287078399957217499951509673409 +sqr:8879583655989939149712696359705781351087498,0:78847005903723654012446892603376809645393741694579508469156852345582458114307251900004 +sqr:3351414487201377754699699738698168276843,0:11231979065023273817960765077734203806947341396425672066505356077057923890046649 +sqr:493311088492211553497370970192138517368154,0:243355830029370578206188770286494126657338190622766247718762414035192416310773367716 +sqr:82685877720710523061992100323174276509125450,0:6836954374444292844442742416877544049404896861094638922225024615086673653057123837702500 +sqr:647294863666837620786899669173664903756583190,0:418990640529469902225676759601758499930370634181067199099319436360711522177979263390576100 +sqr:216273949195441394151753549195148053993499942,0:46774421100592365260727829266381968975002672686299927792795537237038284660867986754003364 +sqr:3950961225764940372370426740411682156774744080,0:15610094607498000126930368549421600598238504973066689872189952445984103363005501349495046400 +sqr:-64567592264420980155379737156740169852286,0:4168973970824515995743765693939003440464366784937500483094535902887465079059425796 +sqr:-5393776308108858222846593366287251097190,0:29092822861916424670653729347861600362879624868296884894957063675916858825896100 +sqr:4421257035474409230652669129710743041139129999,0:19547513773731961522209166180650357790395010294343310626102311499057900780186531074621740001 +sqr:25745585348235541052001355061838556004714,0:662835164923280565618572665499610627882266313568159091349035783688149905990221796 +sqr:3022361477414863092264903791427345647050163,0:9134668900161353985753195181966102732074420111230027247692488593788588488383438326569 +sqr:16174126083338739712392546466600144029545,0:261602354559738560524227152873205540857880607788363443574217951532138509832907025 +sqr:8536359038962118971924046789322102135506936,0:72869425642070271408155883035265401649238199527773293064559915981755136561073704108096 +sqr:16829452309909947550920920604869233567741,0:283230465051533269305657969245471380416496809799098078990297800266415747635843081 +sqr:355623225691640883087356495814808440781511,0:126467878651327748249114458690580697745795910662947600858514518696687118116439443121 +sqr:-4209401143443034381092730841013060610254,0:17719057986419525309516357045133676283967190690277715809293823866768206889944516 +sqr:918167948787358412274755629955529806721807808,0:843032382180385220097634047295256324836379578514035039013396468142117850016057007689764864 +sqr:938573266314205341044186153980377755729062621,0:880919776239716222375696294047377432376471646919887673869340040964527602792324015339389641 +sqr:-337834833138283209912173119871827704113293618,0:114132374481571659273888147381589921838671732890472824055868207447165729730421587879529924 +sqr:3347677785850637302491730901579246582150171,0:11206946557877825427011369191220138899303204964536294325376558809200796800953595329241 +sqr:4356645141393535940709418390025017847118962,0:18980356888027902768955973980307120610625051788598446346637986213696827755243779957444 +sqr:92826772426011694027779601747722647943499793413,0:8616809679030564963186880963791809918932126468805307429201291100830072265634908592373678188569 +sqr:51010376762258960953864569830757574823681474404,0:2602058537427608996290624274755631383147159000024273704429828958236707279671443068347307155216 +sqr:30382831063227602873284055143189355113414,0:923116423416628149265937489922124060523986868896196859513517045335380028802735396 +sqr:3915054492997401943585003235342851158415,0:15327651683139143984118805637794267152206819518847446899400091861876507425312225 +sqr:-4641090311724785696843174695620414415792,0:21539719281585668471865797038997005291814557178275054719466959614202528658987264 +sqr:-39951447861070793408634234428218891908517431,0:1596118186195858073668911179663982468054349199578643473088622372024243339381964430839761 +sqr:-555198960224555495005823246552894089948692,0:308245885434427554629461691197291076483738765823061906226206596488656320063192510864 +sqr:58589016716833637943477313441669085819261,0:3432672879845411479467663313022248204450828930033468407431125219807738163558586121 +sqr:81263647890474008516998822691088790271345139919,0:6603780468466940774544731497500550809853395908650543188970162129807619747633000977661687326561 +sqr:5560457512376932639583447838381337320337229849,0:30918687746949065998721620382358683435170457483405007324210641546498211977797053331056562801 +sqr:432730426644912729122981083168165400551009,0:187255622144288196428332849203454859775636894202341850981185369067975298080810918081 +sqr:165634868693456077262813338073145431993831748,0:27434909727098436123329108213498577822229788099353666621117280426073913085588319332735504 +sqr:5136036432296350718059822910992767783245508,0:26378870233875426793297045400748869895784309008118709948631066937426759954797802178064 +sqr:52495461812056415175919972939040513752659169,0:2755773510861073404770251585451023468741709259421767644302188340904609910323218679770561 +sqr:644921741309901067265662755007058628663417209308,0:415924052414194952773497338448414267721637881779193538991963654588957862098729012454014681838864 +sqr:77219986751846279294740383367169789369471081163,0:5962926353955314887856712243839730087619098814350842401405209118435169818950049029756133432569 +sqr:-406564763021417498306152266546407011266123,0:165294906530661369246246104614399625280534743301156579253890792930213067047527451129 +sqr:77332635435051704171741918986869908321498,0:5980336503330614478952575573159205861850436194935556182332670256809867467728964004 +sqr:-30133226652964637636178317676292739183072833,0:908011348518938418160952049024705846190373876758216571799570644467898365634836182645889 +sqr:843353980371530518867911928059756715267687917567,0:711245936208503883695472164087598868479574150979252250593440597707343604621646246021356987199489 +sqr:52416664036135192338300928811249602187501,0:2747506668677068472049940358100381783185000537820108447834753651234627284360625001 +sqr:24936864359653987871165102360085320772025101390,0:621847204091781294552778349831227902040956037620708005774854493451595520123946776239779932100 +sqr:2505909981582499443571901125584999220379619248,0:6279584835794802700486852245258742443988754052584342546884836165850470328098083893452085504 +sqr:-73977703479204885730664268429435963708518,0:5472700612057162655101360993309179348039302715439935757192986595911588767665756324 +sqr:-198589249704105435037679342682866043073186,0:39437690098039540617666518382007710264897977029189581552408645429654317451352190596 +sqr:73328039448018528864208189941878255640285587838,0:5377001369290161515275169918004259959150861969199997507466059992543980522974959373053213514244 +sqr:535683488298987839878819855712326543532053,0:286956799636171841961137163658674435700232958301938352313323115244951797648638394809 +sqr:184063216702015429721557935438113110817744644,0:33879267742693091845169539821262585008285349159029510408323623234301679006071982790686736 +sqr:9676294432856266922797489910606089116869045937198,0:93630673951325184339475444014224838280508945273159278657409367399182897368794695514896350160091204 +sqr:-2663749195133384508359036407296314458167292120970,0:7095559774573753778551499428892681382031491295323466926688594859703932221913778622258641113740900 +sqr:56186493557755840121940359083662314213584866639,0:3156922058315738524532619454274852899939633083172653727996908969426171204418780549199415156321 +sqr:144196799982597573891264558388418615203807,0:20792717125221251686070638980516239709909762281452172068877272181455090376147293249 +sqr:450542969038187905714211262451476459135879207294,0:202988966949745545842203931499090333856324212634176893780523587535885897796107342866845822802436 +sqr:467808110665735390128574258585344541690288818,0:218844428404644929675525571476567575876982168069310375514724173646708352135783728255837124 +sqr:43329024140220466727250156222903487498123397,0:1877404332943807955894226235179737256169220753410657867280549089825917543297596638819609 +sqr:-6438501793677256617789281924089504319534108161,0:41454305347185250745373491255204904408762383595512409623526297043091627263730566245646801921 +sqr:-510407326611660928505767463487707749496052517369,0:260515639058862714248740984693664668973511630313643512343292186231469444203704884750122046682161 +sqr:594859310867495622564465375741063919562317268,0:353857599725751795685985263032949412484008176182571404388603629978255638007107293890983824 +sqr:472755285423104075830726552388870346265278901544,0:223497559895480601087050545047908867496351886554740936596802968200467105106203324052391245583936 +sqr:919376689556435886927444595022970417850392,0:845253497299751088037885686267060750171668735078243780695626798158701607430094553664 +sqr:-57876848300975619887354759108579447562241954,0:3349729569254144498438740796585193942967339615854670325521241615639822207154890837738116 +sqr:92443624150723929520372770653993712765851558123728,0:8545823646120308559485384430414356108540247254855261339713154331207835436289869077213927151756617984 +sqr:6356695791313384685269608982290373651589003464257,0:40407581383301297900732576196843555338795405220256471898087562078412738286830831265520747076562049 +sqr:307127491594185711277517789087998032847443,0:94327296092936614738485546027297758808557937399435107006033165112073657182511638249 +sqr:17428956723465902727803305936369912233011708,0:303768532468447295689240001394414945439324062976254537841546907447929084153848065077264 +sqr:72297817711860917755762192038277545133731492273,0:5226974445897470229462257539080517594348715584296818355233250622811936276677931595563458706529 +sqr:67252278294589637192130214244481638653946844,0:4522868935812932439511615502129787436243727493914417949589485803608267599747418777560336 +sqr:233519289964558213430232864885327053119123532000,0:54531258785551418329049006520631935794109261573329320368381923668902676071212807876155024000000 +sqr:-563139419418908049216270219501394613917054555130,0:317126005703464832075631587212216737604993581567807889138062714550857544319576086464682209316900 +sqr:387346925081870204031788982970764929245794451,0:150037640370379968568374859913413077524950740578939448357312222610670070607632870142391401 +sqr:6548128948957570787901878097677042348848668836243860,0:42877992732176180696955854123775448728390486486456039969161855812399796757319019743578067660753387699600 +sqr:3936261343830022028126989725444688680102839,0:15494153366930530895998393269628264395230650631049274762266477014870155078335615859921 +sqr:-6668751893614929632721278392171875150277412,0:44472251818592709753921778491551103916600149753115944646208009229845890958300557417744 +sqr:822791736100600708215338516228167925437093404964,0:676986240995440558720776181683504597370626325184035707987923521578936602522691804063023299841296 +sqr:2255604311982997704851854524113475159961890,0:5087750812236292443500181849614429747419680925075316427764315940109096523306252372100 +sqr:52999724285024877184966735916574085712319285570070,0:2808970774288655729113448519823998478249246548895966709777902921010943548779991866954934924879804900 +sqr:8675455794622195828232781164728362446211729095767700,0:75263533244443835242476547921223757363355239874534465194829970026093679319415889649583007878052363290000 +sqr:9766818189510276491458799796620669154596997230,0:95390737546948795157658200093224007046731125703431784850732659642141281407725292532627672900 +sqr:-9024401376963549724600495802510085357805727790,0:81439820212541612297986698812686168419623022133807410031655461931147272504463139331578284100 +sqr:-164402463040098189805763808555384663595781727680,0:27028169853650851333425988271230481834028482476783289514442582861911248333185010717365678182400 +sqr:8209632913178182128605357625511278362817287,0:67398072569138485304045634372020174804374820709272995681812799898811875361955746040369 +sqr:7849224085998259155678225291216074629306321405059,0:61610318752215206841639102273634107076695214340061949813699902301891202503337597099419319950793481 +sqr:84268602084300522449759528578955949436191540691506,0:7101197297242178356528279504357739226784541729116446371397131837835040302245005109217734596660548036 +sqr:6902994314778717651425565958771304030675588082954,0:47651330509867297636610632795902289548938744057689235679157410009315813482325208267069460785366116 +sqr:50206220922066168700530370919092488455057426610,0:2520664619275314690877903300166053204159444860750414396463078163212160418801872872915536092100 +sqr:96072567275642889243275576425042150057804998,0:9229938182932928965775346621497651355565875548926029234561161694019317264672817793780004 +sqr:-6595062761346074146596020647362793948252580229123,0:43494852826093704554640308679361114439497638530221613744048447331967293266246352267351827177349129 +sqr:8568149081811385177067925203516520860649420,0:73413178688145282880121477119739180696541954507523244741188166930150537554224146336400 +sqr:49248502660946919517092747877001926974328533013,0:2425415014345295812313592875146328669679484501975145885494533043030190389627256319264630858169 +sqr:17904856181876925295665552266562559466201268258,0:320583874893696347362514229991660521224017219129814545000338054375384201139526969367678354564 +sqr:771631948578145161796849085547411200917340758349,0:595415864066505259182407508395039909989724181602136362998216709114978732844986284528318413205801 +sqr:12382670011838180563176688905711438881735913656016,0:153330516622076566768604699870546073103022701784337888662872589882573674742398852825302835572992256 +sqr:79887086905840845071329751273276580577004634220257,0:6381946654301367805599628548194540727819498426580860632249477255744128432673947273772575390389146049 +sqr:-30740506384917649516095908074870705315727017255,0:944978732801162777072483626498071187718358606407147765800812805176218918541578974739067735025 +sqr:2367793261905004127519128277205938124388123643062,0:5606444931122739470452985637552178996115400052104533840285616956995976414363107753679718780735844 +sqr:-7205537163239928136782948117253088856431489639087,0:51919765810831710781135325357956163524444034169223786198198403577770151672808946737583429518193569 +sqr:-87222501875881575403280138643647476695025770484971921,0:7607764833488164940156888723183272524826225411571931628845909517856498792285963403271657878006104158430241 +sqr:768592553397196739913804827364926053433680074,0:590734513137622721905021754614420272988265613837215107708841948464515520527214250584645476 +sqr:72654430008231434800757497564201500782485093291413,0:5278666199821000407130155626386018512614357611234992080780160725379258284115224662271305897739536569 +sqr:5294979779912456291593332485003094781099145296,0:28036810869681764068248622882698671835224328885732252901436697669373532746966430141718927616 +sqr:-225524330077841338311518714864637992502982300827,0:50861223457059131344076452854745359154811942946783092141124606168363630406185633713222724883929 +sqr:76300515665590045878902542341914483141905465924,0:5821768690834952001877892404074353487780621638858283497181488390792314668694315843107525173776 +sqr:1367671021590108635537147568793462718551758852,0:1870524023297331401480243199414359851331324615117918733772848624680091553081397302760357904 +sqr:510148602546875823515395311882287764490427522201,0:260251596680530277967028454013847983210561613833634354975554290871003699196080451660212347884401 +sqr:-431885828352074513804191534183233827345066984060724,0:186525368731357569947997844493090345640360420960321598190276095427440182661892141310259951076519404176 +sqr:-809483217718253905386013436699549868896275873002,0:655263079767498053425256239691815322385021649460858579931313119375600071847578167997497232492004 +sqr:7093947060113745921407567380188169090451326617,0:50324084891696458689525345491512385227204357117921476509864826534231186457831032775212664689 +sqr:-68080232880306501903664558878954222691596262631984,0:4634918109036766536359386931180300421938059628159541879284111014923670444055728559424188487019776256 +sqr:123732084807188820529492594422304230836960515452,0:15309628810733366542785996328670362388267452693830627108998185467309957713222828345677530764304 +sqr:7540117648567179857455046065990308358027888235,0:56853374154234257609895527408355719669136623351747723531173678837172982618421514013651415225 +sqr:-45060593639989118987524402495961714937398249804074054,0:2030457099188227839836890779305097649691764560779479754889468083163520905704358745278334218397976315994916 +sqr:632053029293918960044415400816420531501630472353905348,0:399491031839619579039593812314125996580654591892869493458792928066176249648663979069801773646377507343001104 +sqr:3817746132424122174583264307874535849181410143,0:14575185531639343007201251665616569687900232059519506674273338124182781949884342453983280449 +sqr:-601998309194629269720110854571071245260480241599,0:362401964273192463544703828120443279897492192836031400769571647881320007895533397773473410076801 +sqr:149189674784531010082775561427484020603730152224437164,0:22257559062314127889768903830566720975053523644513943276233173866428033619416786913180630322709896584362896 +sqr:-667952680634617065225948909891271695652859024779524,0:446160783566970739385553579285903168560292605633974252482379900185517391327443619782431132256809666576 +sqr:896442187023978024135817888181355581875489698966,0:803608594676332793793077691071489566065573314613637479558689073204033255413470271487577301469156 +sqr:469876837063508044888529054004029741634188262,0:220784242008806487516585370721594781809415657049495909138954715803166606284395035658580644 +sqr:333460505499634389071621746836449438345651158948851902,0:111195908728071696640013460481101860680028270768188479169081462544951631246428196028946634293924963929017604 +sqr:2786546981347699152350591332346527753272696601615332,0:7764844079257974407678493361975288835463281192151603359405015138569536085295805773150543091151697470224 +sqr:-73071180676220826524286202896313207937408377936310398,0:5339397445416907926684389231894822147916634835106530498340816561362917793316088182837322991485253402918404 +sqr:97268643839279074792000245431060117711471587597076511,0:9461189074332523111016107641208277216000335342535735276099162974736485081225309337128089039686273987933121 +sqr:5373770600769362045085178646946336003315453933096,0:28877410469693110277861132973833648845693365290082720947082539067604050573484907294481735644145216 +sqr:7730022208425583302760731266174266674824479287,0:59753243342752732027570001943282813441979961478227838695136173133534955486934528970692028369 +sqr:186015250092269625466554459097460746814672772260764,0:34601673266889614905648672478996105551510265225901936707632047204975658817888057802926645503613863696 +sqr:4815666699948553139200366699245624686477868625356,0:23190645764993388131257987862178276692328734350163125333215390017611850098020996699531633086126736 +sqr:17081969233179688351760402283975114660908394799,0:291793672883297470081631634308890045217155311366254116499612450017968346005970487790850250401 +sqr:-43332131748563083907399274032132960698499791186721,0:1877673641874828787625525012286653311094511677166880415689214828901799869432475136212839985486731841 +sqr:1898554232540005594761509086534555991176474523590966619,0:3604508173895569638767886256267002152378977439165342675620569566281281336502387804811587491743137018772291161 +sqr:-6445244173897779327967913685216339870247860278566770826,0:41541172461163267894256110942941660309957282870559131430664069420103268562436340311324462473310528425204722276 +sqr:65847514811614176821263497363221055127791917392687769,0:4335895206865748400390819297884493082375490967259923170455114945080901924156961634452124720130029922197361 +sqr:-28264343742850718502716299981680971000837535755872043920,0:798873127214024562941629848748102397995321372847598546364602780290618822199779680422856795951621179798408966400 +sqr:-282181133469986333088832466973840605999043481716,0:79626192086406241151931423646013826941082487042406305406535152992700626621319634719227626304656 +sqr:-434247247729195929964308594117079054346013291477644823,0:188570672160381659752938334784076794251905170787774464494097399065847591192000757928868479498829562938701329 +sqr:9240816951257803833721612536356214330313434983018109831,0:85392697926653572474441387898710779160646698736295404941246735442747843749195839063211719258143563711978848561 +sqr:-553437984914283832199711793939722097864052715723678494,0:306293603145983058628720487059837183281755876058747737586115542682024534807946633420427796579332982678108036 +sqr:6047211011673838976527797824201388483565752195,0:36568761019709335078453798066472987505683172242522836648346989500201360601930015916147318025 +sqr:8955137550631297248650463364979038566397939600995033172,0:80194488550726709893601438825399931426591990165490900865830781031863248149485356041714708909894913413380381584 +sqr:790779058506749058766189248617038335165057845224,0:625331519372820450923822161102637479423295357609393493544855157664620164122653416349989939610176 +sqr:924579527319299462598706457157008969788011018317012,0:854847302337979221303684560755968979733480484179132343486688206396061271407117703550270221776928608144 +sqr:8261040079039720082284754517273813743276045370542446932,0:68244783187500584624392647600687253970401912865126265782976546569564017937607883404257489780392858354036212624 +sqr:81648112117151901296706874493743067927111503972,0:6666414212295007129897504217103504480128611223900886718005747056017651759771665045223771776784 +sqr:7899564578684868309378186947806084222206879072463,0:62403120532812640959186386238692291461262959507356112939970796721050816677313636908195151204886369 +sqr:202875148688606841162017225883717133105073395273,0:41158325955424334103292855054548709570644287446922395354404946376369163111503043012196098744529 +sqr:-447599944273190621944023321274152349834427894265443,0:200345710113363350241573135392171477512633083999735087675041776698945249056665566679475323004543986249 +sqr:279448269247759221729545915827816901286962304397091,0:78091335185568132343602216620236567337871190952067796247538287572338846008514454214870712673009262281 +sqr:263048068751475889817576462013638717456577558094,0:69194286473881186494904734527044427456680242987310636245194242896044320271253317351079944912836 +sqr:4953918586547460893294750792007989508019383275031399,0:24541309362140392785101770879220285481237618136650376029112407574731123149898250836474326855904435897201 +sqr:4471437353356145807877658377771700534452125783017614265,0:19993752004988613946043886485552363304372507758161087249440003657966157279048035653082325835710499252331490225 +sqr:-72098170677932326230814230626869993207419376557699079862,0:5198146215104260669761646225033691215158769193995972929447181676171580708713242869981328524528675902921453939044 +sqr:298429988994779695408244160373799551781709296663708,0:89060458331424330116238562159365179356263870750077166569310858891659319712469121280685043299644309264 +sqr:15631841203855394599569166381728452039734506241667,0:244354459422551272302469662109502580403312226387630490060815637724042398254594605237073781406938889 +sqr:660426807315003637221713949061982205086603339679753,0:436163567820288941746673080355640275297800545472250496547078441144692622864124308034416680452598141009 +sqr:917392439916950305180360768242753564177817712397351776809,0:841608888816775275663208862326623620567046837893704481168518555441621791638059053430461906332510516549269350222481 +sqr:-155846450238268495344369959195559500580543629842832,0:24288116051869098349295047128215656778566742131145679653985424636366108865305515159091137545021780224 +sqr:25472033362764858072900019697941213135876145681845377,0:648824483633806003744793667544511819270248356569452159505562928008016765090401968998670090576448136272129 +sqr:20189277289260360026888777803572924468097073267041778216,0:407606917462644151076725849420885819139012157714254702542998040670975149459822767551525742560834848763332142656 +sqr:325204287745187960673217120597871887240330145314572,0:105757828767855008418740324132756067538697480557296437838517344014269355767453319221651293844835543184 +sqr:-6414722934234222900958263644266120836831440017886,0:41148670322990518384944829118717910442843247950185748761142292129209592995146647048734271999908996 +sqr:312301120272909624627968726242736198455177785970818842,0:97531989723714362934668096275738607603861443157722482847186557044333833343486010148981998218139163982220964 +sqr:9028894954680171974419101406148453477562571298124980366,0:81520944102649064731832317449161331094564889092209138390941931719546194698076589489252890701465890227885493956 +sqr:788806307332790616113150948641884167876975922667808167,0:622215390487992922911688182036473235781447944210433463649952255548713919326836326920237228393877695911899889 +sqr:8462072534820037419699255083511733952413272276484107788809,0:71606671584555613408851055334596052520163369900719944476255980385358955582796459794726778717991205869753539345638481 +sqr:-685942527221288609261737584619270624284127458641912,0:470517150650728264715592414998231622951986855228964433454490078408056889339366486340487414051443015744 +sqr:370058929694186697058774342888571633336040599274254758,0:136943611446407012761130137137417712864012148304763406301401028969847631099408086708759895389055756285638564 +sqr:9704187879914430313664077393665195769441512689418966870566,0:94171262408678125773934398641195191307284789234258975677909176503419014249751224545097316770934552462579867397160356 +sqr:5925798128737745925759715663331423546607679889144875112930,0:35115083462551771236157369162138315687265847656064728641830503311468988183199467328159949805669318527886480253184900 +sqr:33488647002377175259885536134537076443400396426003731,0:1121489478049825766276530922246725189111830952465458275864281151986139799264328218398374227234130825920361 +sqr:2123735232819297700815836330311374814786388785356210060,0:4510251339118036610109622239017828107705345092062097267522409602229318236281318584088873097703239806845203600 +sqr:29872141162702890384989735017623770258183788742075,0:892344817644448391848145835628174663828417858780217507228848289828118687946707014712413510875305625 +sqr:7532139657883258576470960593627865781553593844952,0:56733127825857731552224724505206926449807777229886757388281330093349393178013626920192739015882304 +sqr:845457525713874120263223171268947077567681659698840902652,0:714798427786226119268210281388981030688454506537030966614579539102544522728409887855024503885468326555462140633104 +sqr:521768158545019160169259844676904044401662888508547040917,0:272242011271460250849489239712473973544134037328971616162419516920558472338192391022931027231772869417436872200889 +sqr:8452712498170643941637436558664265704301557216577944354047371344426782440907597751590676094202515006314790319892114058862117560952042968596008623655407033230534186943984081346699704282822823056848387726531379014466368452684024987821414350380272583623832617294363807973375,=1:71448348576730208360402604523024658663907311448489024669693316988935593287322878666163481950176220037593478347105937422686501991894419788796088422137966026262523598150372719976137911322484446114613284904383977643176193557817897027023063420124852033989626806764509137929897881780377071828193979369536094745977623512725964279515528917451111552087757216338484610394583686853163069435510427134801022221259480105632478261997058761512146362996413333996057383868504433356414886358698618132135318758644287722813462338791398132036589335991224708890625 Index: contrib/isl/imath/tests/sub.t =================================================================== --- /dev/null +++ contrib/isl/imath/tests/sub.t @@ -0,0 +1,849 @@ +# Subtraction tests + +sub:0,0,0:0 +sub:0,0,=1:0 +sub:1,=1,=1:0 +sub:1,-1,0:2 +sub:1,-1,=2:2 +sub:1,-1,=1:2 +sub:-1,1,0:-2 +sub:-1,1,=1:-2 + +sub:103427990038,909510006269847,0:-909406578279809 +sub:128593002,-9007199254740992,0:9007199383333994 +sub:-65537,70000,0:-135537 +sub:-1000000,-6543210,0:5543210 +sub:#x29C932F25E6CEF8046FA,#x29C932F25E6CEF8046FA,0:0 +sub:#x800000001,2,0:#x7FFFFFFFF +sub:95031018,=1,=1:0 +sub:#x-176E7F8018D6BA4B550AB36AAAFDC78A9,#x186DAD2485A41B18AAF5EF17922D7E5F1F,=1:#x-19E4951C873186BD60469A4E3CDD5AD7C8 +sub:-628443782411312,-301652218193016,=2:-326791564218296 +sub:950147,37133897,0:-36183750 +sub:649972385,297,0:649972088 +sub:505,9,0:496 +sub:33,-2638,0:2671 +sub:-5,71542573,0:-71542578 +sub:4,475357,0:-475353 +sub:5,775166,0:-775161 +sub:0,20805741,0:-20805741 +sub:1,39,0:-38 +sub:76825770,751287444,0:-674461674 +sub:-5846049,574445,0:-6420494 +sub:501105944,54475,0:501051469 +sub:84350933,594,0:84350339 +sub:1367,-96716998,0:96718365 +sub:49879,-426695,0:476574 +sub:4,2,0:2 +sub:710883222,2440893,0:708442329 +sub:-68,2096377330,0:-2096377398 +sub:-87838,-485655,0:397817 +sub:4683739592,822,0:4683738770 +sub:2849496,766332,0:2083164 +sub:60422837,52,0:60422785 +sub:-13318,250,0:-13568 +sub:1,2001827,0:-2001826 +sub:97481748,62763650,0:34718098 +sub:1643,636255899,0:-636254256 +sub:-400522,-40393280,0:39992758 +sub:45568099,22,0:45568077 +sub:645024401,860182184,0:-215157783 +sub:37244191,-976205,0:38220396 +sub:-27,359887,0:-359914 +sub:27528,8076231,0:-8048703 +sub:7298,58548352177,0:-58548344879 +sub:71847293055,573,0:71847292482 +sub:673824473,27805877,0:646018596 +sub:449,53709067,0:-53708618 +sub:40569,6538078687,0:-6538038118 +sub:-642338,9669221067,0:-9669863405 +sub:209745,-28,0:209773 +sub:2488518646,-1846396,0:2490365042 +sub:581,539581676,0:-539581095 +sub:-86,16372077246,0:-16372077332 +sub:82972869,96,0:82972773 +sub:81666,-224,0:81890 +sub:3353174666,6467525,0:3346707141 +sub:178,76264272942,0:-76264272764 +sub:67786255,18533457,0:49252798 +sub:-59339460,8103,0:-59347563 +sub:427117459,-6532,0:427123991 +sub:-514830072898,10894,0:-514830083792 +sub:4160587,946181096,0:-942020509 +sub:76936,1066849,0:-989913 +sub:-776709551,28397881,0:-805107432 +sub:917,6034390,0:-6033473 +sub:5528,-1297,0:6825 +sub:303,37728739196,0:-37728738893 +sub:920355,13059,0:907296 +sub:55576,-56300,0:111876 +sub:-85278759,67364939177,0:-67450217936 +sub:50472201146,-89468966856,0:139941168002 +sub:7257002442515,-4541182637,0:7261543625152 +sub:56005,-57203,0:113208 +sub:1508,8778323669,0:-8778322161 +sub:7477,1777344,0:-1769867 +sub:619620595216,-271826,0:619620867042 +sub:503021,559324,0:-56303 +sub:46990,601026675862,0:-601026628872 +sub:630276867,92393884,0:537882983 +sub:64847122,-1741761,0:66588883 +sub:-901885041650,6063747686,0:-907948789336 +sub:9090817588683,-74217059906,0:9165034648589 +sub:4643353802,39676050,0:4603677752 +sub:61222313,-991211846100,0:991273068413 +sub:8145673172195,79545920286,0:8066127251909 +sub:4326733518687,315334416,0:4326418184271 +sub:65122622889524,686861271,0:65121936028253 +sub:91927935495,815931,0:91927119564 +sub:360036184139,-929647,0:360037113786 +sub:851769193,5104213614039,0:-5103361844846 +sub:49764,-1370901,0:1420665 +sub:543849288,7706203685,0:-7162354397 +sub:62844,8576091,0:-8513247 +sub:-809058073978,541423856,0:-809599497834 +sub:-2639589,58729,0:-2698318 +sub:-79585473,1798247,0:-81383720 +sub:316852976150,-860129592,0:317713105742 +sub:1273939285186,11601,0:1273939273585 +sub:80537932950,292617381640,0:-212079448690 +sub:5467548,5430035835,0:-5424568287 +sub:-5937877,24003123599412,0:-24003129537289 +sub:684651821908033,41369461672136,0:643282360235897 +sub:1137993337,2322246811872,0:-2321108818535 +sub:7374342836,64650413647,0:-57276070811 +sub:432132,-42261483441184,0:42261483873316 +sub:83231980056423,2783677270377,0:80448302786046 +sub:2587541968775,479202225,0:2587062766550 +sub:-928954175477668,-1742785659277,0:-927211389818391 +sub:6404997096,7343350521970,0:-7336945524874 +sub:727251429810,3193503,0:727248236307 +sub:77165840,-457577668996931,0:457577746162771 +sub:33934095603840,74283623494449,0:-40349527890609 +sub:3846088301735,-44249412464855,0:48095500766590 +sub:24497022452,4724262825964,0:-4699765803512 +sub:463651487662200,-753243402,0:463652240905602 +sub:71713522960,15380043873197,0:-15308330350237 +sub:8294630828927135,31183461626,0:8294599645465509 +sub:6703541383230,44950919818203,0:-38247378434973 +sub:868891910767,8481827,0:868883428940 +sub:6321902376793877,-477388684714663,0:6799291061508540 +sub:-32763637641,66549351522069,0:-66582115159710 +sub:288533359019263,58471469888811,0:230061889130452 +sub:-751498035858161,527076997758,0:-752025112855919 +sub:1940356995569832,103761002,0:1940356891808830 +sub:11785051,32863482880064,0:-32863471095013 +sub:6832388,998030894437455,0:-998030887605067 +sub:-29992855,4391685016,0:-4421677871 +sub:-60108503487,-15310122633,0:-44798380854 +sub:-6477442216968621,60885516917,0:-6477503102485538 +sub:31744989963367,971914401,0:31744018048966 +sub:4773395,-699494329,0:704267724 +sub:158083905091,153315973803,0:4767931288 +sub:9257392592301,778762452,0:9256613829849 +sub:-869525659304,751325704189605,0:-752195229848909 +sub:-49703875573842714,4505925018715,0:-49708381498861429 +sub:-91664099,25339513330017666,0:-25339513421681765 +sub:469453608,-325915913621728,0:325916383075336 +sub:-6329249891,453489665443616,0:-453495994693507 +sub:1555896943,216164615094,0:-214608718151 +sub:7867736225,6515990968510638,0:-6515983100774413 +sub:47191079551,22909405,0:47168170146 +sub:480598620144,-630471272,0:481229091416 +sub:-44964236,4129791840132424,0:-4129791885096660 +sub:2078461471836,9510166882939211,0:-9508088421467375 +sub:3399372328,4480430653,0:-1081058325 +sub:37397829728829741,55828595309,0:37397773900234432 +sub:932684640397258009,-748484093750,0:932685388881351759 +sub:840884486710412,70796060480,0:840813690649932 +sub:2539205,16161203759,0:-16158664554 +sub:713637461058,6441899124,0:707195561934 +sub:-8173074559441,-280676331618304941,0:280668158543745500 +sub:430261608,4233937508,0:-3803675900 +sub:-131645380114748755,77441408953418,0:-131722821523702173 +sub:-31661643391,786373077474234,0:-786404739117625 +sub:278686734235471032,120592814722,0:278686613642656310 +sub:-2931231599090,18746712502644976,0:-18749643734244066 +sub:61029444723255769,-2293742672243933,0:63323187395499702 +sub:816220890520,640524790657208413,0:-640523974436317893 +sub:16665591262,113580566277835849,0:-113580549612244587 +sub:-868305701832,6230551669213729,0:-6231419974915561 +sub:11999732039934306,23827304849399,0:11975904735084907 +sub:91534672684829653,795520608093438312,0:-703985935408608659 +sub:-8985197818103126,141826190572801,0:-9127024008675927 +sub:390870406977082056,3249082110578,0:390867157894971478 +sub:88089340380,339939269745765,0:-339851180405385 +sub:-9559600885723,1043929655718,0:-10603530541441 +sub:7521666468386587380,-6553266884,0:7521666474939854264 +sub:8481985305837,8883976116,0:8473101329721 +sub:8322745787655471,-2367148822664118142,0:2375471568451773613 +sub:-1536130411,5098377844876093,0:-5098379381006504 +sub:-80409580247,-379667394325917,0:379586984745670 +sub:2780978527253898223,-793585194380805771,0:3574563721634703994 +sub:983228849414820623,411233979567,0:983228438180841056 +sub:4312344973,8504030055,0:-4191685082 +sub:6929160648081603523,-9139369237550637,0:6938300017319154160 +sub:40543447104286,922867012966969520,0:-922826469519865234 +sub:-32492268811,-52539511415,0:20047242604 +sub:-837736542959704435,-11698939306808,0:-837724844020397627 +sub:30695570430,6965534034801150,0:-6965503339230720 +sub:743449156492,-892800013061,0:1636249169553 +sub:4650491989907718938,9119100370137466,0:4641372889537581472 +sub:475327493368,391070618301538,0:-390595290808170 +sub:9789197909023,-2250068166694,0:12039266075717 +sub:3951486522961630212,41419130651165087030,0:-37467644128203456818 +sub:36289729721981,609158820292,0:35680570901689 +sub:5238096716643,857369737080,0:4380726979563 +sub:20927421747352,7859500562781,0:13067921184571 +sub:853523362775,-58650620319893709899,0:58650621173417072674 +sub:46324137709977166,3445427404517058,0:42878710305460108 +sub:8903783900,665953140969,0:-657049357069 +sub:8807754569337,1429027872766,0:7378726696571 +sub:-69086569251605,3823065660047,0:-72909634911652 +sub:74058749504331776,4434739153355644691,0:-4360680403851312915 +sub:-52234016526389,-2748494775019,0:-49485521751370 +sub:-6279254893906588798,625713048668,0:-6279255519619637466 +sub:3054225188071649,435737551736,0:3053789450519913 +sub:773765483980477636,76679006788618217,0:697086477191859419 +sub:9779893465932,7787153050157190775,0:-7787143270263724843 +sub:59561782129137,9069749963639028245,0:-9069690401856899108 +sub:-341767412794852361,347062438266855646,0:-688829851061708007 +sub:-9228152928357,640608182261,0:-9868761110618 +sub:-42043060859484,7345135549532130055,0:-7345177592592989539 +sub:19318981939433,264137322793696365561,0:-264137303474714426128 +sub:8745011564822621615,75690236981341546,0:8669321327841280069 +sub:2006412627556,444508404836,0:1561904222720 +sub:-996892139262,3687846060016536,0:-3688842952155798 +sub:591666758481462692,6187092701409,0:591660571388761283 +sub:17253871467666658,521693769674,0:17253349773896984 +sub:-18811272204464,-70402687077401900203,0:70402668266129695739 +sub:45980222925454243960,90960767776830610102,0:-44980544851376366142 +sub:-66394515686754,99465607502696,0:-165860123189450 +sub:-731492671961447493,42337700004380375319,0:-43069192676341822812 +sub:6642648198381310,-567336740547801378,0:573979388746182688 +sub:811917479145896,258859229290245057,0:-258047311811099161 +sub:66015593565297,625461142945341,0:-559445549380044 +sub:30440701155222429,6075207040555619467769,0:-6075176599854464245340 +sub:2751861052219993314121,760255884133587996796,0:1991605168086405317325 +sub:9525855084181563454,4607581127890,0:9525850476600435564 +sub:5557962211148071712,1921710471388746938,0:3636251739759324774 +sub:800293622218736473310,8120868065192,0:800293614097868408118 +sub:-45549550905111,-3937133121943669502489,0:3937133076394118597378 +sub:-81611168134401657674033,-29024094310537521258,0:-81582144040091120152775 +sub:473739545776060,-95651109326027,0:569390655102087 +sub:-9943711197250791783,5192955396843373262,0:-15136666594094165045 +sub:74362674758137703088,991218776208774087,0:73371455981928929001 +sub:8942190838160347,42915360862670,0:8899275477297677 +sub:66210460069722759,8216793402040737008247,0:-8216727191580667285488 +sub:28630228799120059057,-727654086775011,0:28630956453206834068 +sub:-2502191839260572,-609085018990088802,0:606582827150828230 +sub:-707403262721461629,-9548746126714505844843,0:9548038723451784383214 +sub:-42739413943936747053,7248311562458017,0:-42746662255499205070 +sub:46123774937019599821,521218568189626101724,0:-475094793252606501903 +sub:9415554602318087,9000595012272170366,0:-8991179457669852279 +sub:-1951679141829705122,-12285787616979339429,0:10334108475149634307 +sub:-4386967398151873150474,2143436435198250529,0:-4389110834587071401003 +sub:97977437591194303377451,642191000671555391,0:97976795400193631822060 +sub:83261682108887535662635,511317890231125086112,0:82750364218656410576523 +sub:41310833218589671,9897170076989397,0:31413663141600274 +sub:1683930885684182315875,-66190399132485560,0:1683997076083314801435 +sub:83038493375345259207979,58284882728646817780,0:82980208492616612390199 +sub:174833752819190460,58205143986480293592,0:-58030310233661103132 +sub:-51972688295317718162,-53017954844280432,0:-51919670340473437730 +sub:3049073769975215127,-8413940824249555462,0:11463014594224770589 +sub:66856363357316667,-37906703703222242237619,0:37906770559585599554286 +sub:541685788711205,813493512383742701225466,0:-813493511842056912514261 +sub:12039482877604486443159,-27784227929617157318,0:12067267105534103600477 +sub:2031498290041713,-706931410323604521481,0:706933441821894563194 +sub:793163145663267355,488093806957995,0:792675051856309360 +sub:-35932264894813,6608203939349524510555,0:-6608203975281789405368 +sub:6095035696899997995461,49012978744796870,0:6094986683921253198591 +sub:736660687461873,2928166059556503986320,0:-2928165322895816524447 +sub:-80752317921759003744482,-2784356502312865996499584,0:2703604184391106992755102 +sub:-55600025805872206,-7990044978835553,0:-47609980827036653 +sub:20131235857391244,745599894858331816,0:-725468659000940572 +sub:473379993971533482724,53545104197056246737,0:419834889774477235987 +sub:-7901274667808068,7310483319842229,0:-15211757987650297 +sub:611143500250518767744,565842823113937536426566,0:-565231679613687017658822 +sub:8702674605316149,74225958414698686231,0:-74217255740093370082 +sub:847520472084398906,-181833891734712245,0:1029354363819111151 +sub:882552741752125480,4287937154291698619767895,0:-4287936271738956867642415 +sub:1164933678283444,-605787688418745409686,0:605788853352423693130 +sub:8189990356647722508802,5327680305703219926,0:8184662676342019288876 +sub:20126414182234863325418,651586473061170891,0:20125762595761802154527 +sub:-7243913367665451229510,920916193262000838,0:-7244834283858713230348 +sub:241247407616518609790,849820061721310660,0:240397587554797299130 +sub:11610932258446222276,-238310622287414468083,0:249921554545860690359 +sub:333102694750160639,69609722651274194224,0:-69276619956524033585 +sub:489371802875965014118478,96271202587903139,0:489371706604762426215339 +sub:7344620696143243253130,-354550759273217997666,0:7699171455416461250796 +sub:7443029079637089736774,47397475977873627,0:7442981682161111863147 +sub:-552185046973685246703728,5086882342952953836639656,0:-5639067389926639083343384 +sub:34160638466370340264992,6442462400353615432715,0:27718176066016724832277 +sub:224642516163621778782,4567297709761777098,0:220075218453860001684 +sub:396245283577471672779404,-28835207585120519380895,0:425080491162592192160299 +sub:542742994231711454505,1493274706520691229211,0:-950531712288979774706 +sub:-4010437024179449951252946,6148766465731638330749,0:-4016585790645181589583695 +sub:-45993733981177457,-2333654032343500227394581,0:2333653986349766246217124 +sub:-53268979390855780768161,244917458799919371067,0:-53513896849655700139228 +sub:9597472083289623017,283637277496645411,0:9313834805792977606 +sub:-549237729763380362715631,4233347728399082996881,0:-553471077491779445712512 +sub:546810502069383982063,-5966616092961401439222,0:6513426595030785421285 +sub:2693320235570423841,-636227430987384270,0:3329547666557808111 +sub:299001294509600705281,-662976479255032381882,0:961977773764633087163 +sub:-9969627469592910143441654,-4697810125124307023,0:-9969622771782785019134631 +sub:295862851742112486,62089965837017871773124,0:-62089669974166129660638 +sub:35578586721878839413,524399278031861381275,0:-488820691309982541862 +sub:-579419395708175094375,-86888512465827623053,0:-492530883242347471322 +sub:6685264590200748832,2474399060436569565967165,0:-2474392375171979365218333 +sub:411194309664386491791190124,-758109583623796174126,0:411195067773970115587364250 +sub:63387968120454752,367951841292571472228663,0:-367951777904603351773911 +sub:-523269515783595554078,49060669022383177598,0:-572330184805978731676 +sub:13445326521609443648,9751080551639245658806,0:-9737635225117636215158 +sub:789739255835156800013,315101502591672711170806,0:-314311763335837554370793 +sub:73481634769773817391,7522066373372077852,0:65959568396401739539 +sub:59238938099041804756,-284755768386936014001,0:343994706485977818757 +sub:2345748144830635294766296,26772347379722903394664,0:2318975797450912391371632 +sub:-96180432920038812502,7130528324583233658,0:-103310961244622046160 +sub:-6103646636128907863077733278,167360991644513667938,0:-6103646803489899507591401216 +sub:89183651282796860734843567,650591691692940868,0:89183650632205169041902699 +sub:885385723843334016669166462,7959173204532632279022148,0:877426550638801384390144314 +sub:426509712333758537770,3053810150190399695475807,0:-3053383640478065936938037 +sub:-43602818211336693439,37720583430905942376,0:-81323401642242635815 +sub:42082335899892839012828,54006514124159856356378769,0:-53964431788259963517365941 +sub:744007647137500935704813,9607111119925514823029,0:734400536017575420881784 +sub:49316936033792930103965,-3034940638845987540137,0:52351876672638917644102 +sub:83874798574806162505693,464988593797915772,0:83874333586212364589921 +sub:47935017932067725904,525937150680246466817568,0:-525889215662314399091664 +sub:15759732742160839060899,8468547017336608217,0:15751264195143502452682 +sub:68081177675380449585,232838274961715380121771,0:-232770193784039999672186 +sub:198837569846432824894,74142127460226777613642,0:-73943289890380344788748 +sub:1898390184425605471746,-8609726339421831182804422363,0:8609728237812015608409894109 +sub:5010086610580228482335807,750924907754526639102577674,0:-745914821143946410620241867 +sub:3239772657087138659473,26630017052110857873,0:3213142640035027801600 +sub:30931222688688580641792927,47650975868262142324567646743,0:-47620044645573453743925853816 +sub:2618635242932069293276,-37969350588765740201326652600,0:37969353207400983133395945876 +sub:62748041061334975755,-8597227755884238992024742173,0:8597227818632280053359717928 +sub:73666512572900713065,727593598628012630085291831,0:-727593524961500057184578766 +sub:73065402278129705309963059248,-1510259437891597840030938,0:73066912537567596907803090186 +sub:652852443033404198570557,3218208198091308335983,0:649634234835312890234574 +sub:322654125619631317783651175,103982638102588159557510478,0:218671487517043158226140697 +sub:47298054366651393257588577343,25292337944252217030,0:47298054341359055313336360313 +sub:4969650998010954466,-5928799632879538310681042,0:5928804602530536321635508 +sub:94361219162537205953,-573028299187075717448661476,0:573028393548294879985867429 +sub:500487140938346964814,-666190790348527856857515,0:666691277489466203822329 +sub:2397057037367709886558,8469650679664722706535608,0:-8467253622627354996649050 +sub:5916454672457377863577802905,-301691311710205742681455,0:5916756363769088069320484360 +sub:-4732324961421982812667328,-41666595440544717926863264,0:36934270479122735114195936 +sub:7784556296620016124437432,295631109431335676271,0:7784260665510584788761161 +sub:-468243465340943117955484398,-86059014635749889021797574078,0:85590771170408945903842089680 +sub:7581798337258404983887829,286326330291344819121713,0:7295472006967060164766116 +sub:-59661872187286137669680,993451500121394333929486,0:-1053113372308680471599166 +sub:2962196560211918477855182834,429980300074111981923309698661,0:-427018103513900063445454515827 +sub:-117191815514577197960025,-93952901109567063533541898393,0:93952783917751548956343938368 +sub:972649124468069443877962,39940702160872858805890483783,0:-39939729511748390736446605821 +sub:52911349728309634554095814861,640041502135571284090,0:52911349088268132418524530771 +sub:9563434009347863250789850,39324990112287164371797250,0:-29761556102939301121007400 +sub:501256807694158654884,8345102795766270329548488379,0:-8345102294509462635389833495 +sub:73135419149054064613594459638,-376755188742340618890,0:73135419525809253355935078528 +sub:258128605755268399576,116154542754127542403,0:141974063001140857173 +sub:-388289190817020242752560429,683426700586684828499964340,0:-1071715891403705071252524769 +sub:77603273142377289304718668478,7907734025138351381355884534,0:69695539117238937923362783944 +sub:59920022083646756381083767,-676349674131765453090842,0:60596371757778521834174609 +sub:1386456963825362091135,5043324890371013843489776600,0:-5043323503914050018127685465 +sub:22908004694216963557562131,1437848391259187655742912574429,0:-1437825483254493438779355012298 +sub:75830204485394953668558224750,818650518003178932071960,0:75829385834876950489626152790 +sub:8072507208044425938387,2801437782939637080569080,0:-2793365275731592654630693 +sub:996986457053305310363710,4270654800444412431799788016,0:-4269657813987359126489424306 +sub:476227015634465030195295,802516552923254955041235580710,0:-802516076696239320576205385415 +sub:-3862793080955285675336,601225923445782883856004,0:-605088716526738169531340 +sub:34058788843087368388987,788661560182208367542729826,0:-788627501393365280174340839 +sub:75890485056733894277957536421,28898157540847408357479445339,0:46992327515886485920478091082 +sub:836419152310550927547976,-715832228817310323167747520,0:716668647969620874095295496 +sub:71149688455411718068481321,130052491916581090823794037636,0:-129981342228125679105725556315 +sub:3047224655714425540346555,583427698600273187296801675761,0:-583424651375617472871261329206 +sub:-1762508903601801463391,1123979050566438206073605513714,0:-1123979052328947109675406977105 +sub:75571713529690058494700131,154047782298368874362663480,0:-78476068768678815867963349 +sub:8881924107521011726353538,-3145465133030840075856549,0:12027389240551851802210087 +sub:2119385564140685046061904,42628989499638883272827242,0:-40509603935498198226765338 +sub:636137867409083757104434174,876963242090925483645110008648,0:-876327104223516399888005574474 +sub:956392636402263734252628073,47247440520063140522408813223,0:-46291047883660876788156185150 +sub:5565262347877821939981460417240,-985376663560828156502183,0:5565263333254485500809616919423 +sub:-96960327111310542205299575340,754323275128519456665692931,0:-97714650386439061661965268271 +sub:390903876504582680914435276856,409728963505921718859992691123,0:-18825087001339037945557414267 +sub:600683747782519279592349358,3076791699376918600719019341,0:-2476107951594399321126669983 +sub:9867764659515798940712578323,6357991496217721443026258037557,0:-6348123731558205644085545459234 +sub:68114522731034072566854092812686,62725405971469064330284876,0:68114460005628101097789762527810 +sub:907396594886580376638506,-894708410482856602073830977246,0:894709317879451488654207615752 +sub:-30792046454713176872672190485565,-8017250846058869636998077777,0:-30784029203867118003035192407788 +sub:-18821866119770039003181629912,82441485710616151410107,0:-18821948561255749619333040019 +sub:80095770818874409058224,9316123957640218030400143320,0:-9316043861869399155991085096 +sub:-901755584000000420457516562373,-2517773106349772310667656,0:-901753066226894070685205894717 +sub:-883321569482669903165683,-44558935482820169589044365546478,0:44558934599498600106374462380795 +sub:601706200500617282847480732962335,43201582734874942566066864633597,0:558504617765742340281413868328738 +sub:3611141688653897808711895791472,54026584092810638450252354,0:3611087662069804998073445539118 +sub:-9089386632359156927536477163974,604640114580951133123734104973745,0:-613729501213310290051270582137719 +sub:-65911585682039568232806668,921349267715834145888878007323,0:-921415179301516185457110813991 +sub:740180119243741829715055823,420700352624083519085129,0:739759418891117746195970694 +sub:85012296935839090922311415,56044320231947385798897291322,0:-55959307935011546707974979907 +sub:5658315653448747612688000,4877275861716865293755139,0:781039791731882318932861 +sub:53078309233697402718315797802,786142563765269101788772678439,0:-733064254531571699070456880637 +sub:380283779338470154888541799,69789893061880576858724867806,0:-69409609282542106703836326007 +sub:-36819622867396721797461,-487239057841776678372530391049923,0:487239057804957055505133669252462 +sub:432355289983835194025265634880,722175859400496706671386831852299,0:-721743504110512871477361566217419 +sub:406113849743376356851682,-2948843385313638396180656653220,0:2948843791427488139557013504902 +sub:-450089373848778279085231682276,6922355877436261896463320824,0:-457011729726214540981695003100 +sub:-461778533905902103878563791120779,30903051263975616567418133538553,0:-492681585169877720445981924659332 +sub:2225847828886634429718900,-141670429280564340131559528873669,0:141670431506412169018193958592569 +sub:-518005307820181246928833,41493548566098807242410918395372,0:-41493549084104115062592165324205 +sub:1386972819787742372011414030306,6378199700569631039860797133,0:1380594620087172740971553233173 +sub:-9953467574634703627642091359525106,109232097199219102894213900,0:-9953467683866800826861194253739006 +sub:272224578522098768588271712614,-954774545043667358357735233977,0:1226999123565766126946006946591 +sub:-13397521090097970078307026041,-208746646957761968673045385061,0:195349125867663998594738359020 +sub:90242053814362992528569637627538,819378127307812972535514213,0:90241234436235684715597102113325 +sub:475879565794423355160366826570767,-981714991594839343058124009,0:475880547509414949999709884694776 +sub:73272944471878906655000028253254,9316121481273747448232884110081053,0:-9242848536801868541577884081827799 +sub:156124484535009677347773264807041,41067689846332812531537548182,0:156083416845163344535241727258859 +sub:5750622698618635176765494780582,8778936683577810871387349,0:5750613919681951598954623393233 +sub:752423753475915953095080157764850,110028403919321544278497683,0:752423643447512033773535879267167 +sub:986438424059798089328623129,944289987162416305345778315780032,0:-944289000723992245547688987156903 +sub:2940131992853959894009314316599,-6130856644000035009877295436,0:2946262849497959929019191612035 +sub:-60219475207618615852406049263760,245420985013813274904940493371846,0:-305640460221431890757346542635606 +sub:76132456058041997180166479105207,1333701621741713587577000118516444,0:-1257569165683671590396833639411237 +sub:551757239718514829275035933587668,20975678617718960357674898185,0:551736264039897110314678258689483 +sub:827026171479636357807858542315003,657266896495283042560293955528681,0:169759274984353315247564586786322 +sub:62029235723027056966248632640016,4720308399791420006433428083,0:62024515414627265546242199211933 +sub:3370077911228331451226459981542,56700095331827269676453888012958,0:-53330017420598938225227428031416 +sub:3514193210192659422357386965236028,5945062235433978181560378967712895,0:-2430869025241318759202992002476867 +sub:3725417532430237033267313551512,-29139588479237546460280773,0:3725446672018716270813773832285 +sub:86971485372454469574581715701279,76600079495825348746163163766060,0:10371405876629120828418551935219 +sub:52025473585241225053445613599064,64931994025064476703228951534248,0:-12906520439823251649783337935184 +sub:-46094956887492446679275334,4199288643419024266960740601763,0:-4199334738375911759407419877097 +sub:-199531081865328340581624098,61586813654360478634926776,0:-261117895519688819216550874 +sub:2228997256609098057220853694688,77983035307573853597859653028,0:2151014221301524203622994041660 +sub:-998325557636914977245575086,7667612449137815647454849829,0:-8665938006774730624700424915 +sub:746793137925798942820906830,399507178175236915401754759449,0:-398760385037311116458933852619 +sub:634724387005569029859717498,3437595978823543942820525964913,0:-3436961254436538373790666247415 +sub:7141573144886127523784053337066625,-390050969405812623337724114002,0:7141963195855533336407391061180627 +sub:-91403573621251855050085889821,78465471196357080847824505165565,0:-78556874769978332702874591055386 +sub:349658297262594920988266356059043171,796963132566625995186691340562185,0:348861334130028294993079664718480986 +sub:-633893601713106197757857736129298,86189806992731837430692951480,0:-633979791520098929595288429080778 +sub:-43900746259116235552821471377,591055471482916203481396667491207,0:-591099372229175319716949488962584 +sub:2557547273135447028597996609,64663579124550082208338293785,0:-62106031851414635179740297176 +sub:94701712281465414851697898675451825,1024428303725598723580617161,0:94701711257037111126099175094834664 +sub:1405995388343974884472280878660,-220054432405512280858363563,0:1406215442776380396753139242223 +sub:999816594826990228141732119822,984552280063995997341773813089627665,0:-984551280247401170351545671357507843 +sub:5838938294141788996592039893,50902237118539094354421180186316,0:-50896398180244952565424588146423 +sub:599678492538583548148447971111185,73667844355412382811962121530977,0:526010648183171165336485849580208 +sub:6395778081807663524044632168813593,867149393095359006170012722,0:6395777214658270428685625998800871 +sub:939460433716954373684816294933837,474277009046118167849279293527097,0:465183424670836205835537001406740 +sub:7816286294597662244110191807959541,6233835682136551847146227987794,0:7810052458915525692263045579971747 +sub:23281631659668473110100795038996,116520759657498664805703882673,0:23165110900010974445295091156323 +sub:46391396072715161551587488065814,33356982434471244343742063785074041,0:-33310591038398529182190476297008227 +sub:4585954807809352935161825310034011798,-54552397859131970401808336962,0:4585954862361750794293795711842348760 +sub:2422872895287330189582522753,4480479893211606075278003418285,0:-4478057020316318745088420895532 +sub:-13361745527437011657973841351,984220774495913608130872189292612,0:-984234136241441045142530163133963 +sub:-52685529704743149299243245793811,124512071496978690744692284754346701,0:-124564757026683433893991528000140512 +sub:143835388043216256200766869526,498925860575853395417250651462811889,0:-498925716740465352200994450695942363 +sub:371250666979424888145103423650818,1951666913810216016291928636377,0:369299000065614672128811495014441 +sub:14113880586323385101587281089,5086582061966123909499437086680,0:-5072468181379800524397849805591 +sub:457422738047527621626918654730135,17793707850630720090008287485134930,0:-17336285112583192468381368830404795 +sub:75091527004493134510290819264195424,48439881910003416229205500079317137,0:26651645094489718281085319184878287 +sub:-37624201790320133398219479795320611,4305256066030674211442956228314751717,0:-4342880267820994344841175708110072328 +sub:-63359729740153326293762634,354591974904021002246602880500006792,0:-354591974967380731986756206793769426 +sub:9308446708313654525402624748223454,-60317991035211151378177464977415474,0:69626437743524805903580089725638928 +sub:120534458842619000629729516606,567080219552763040041011655657,0:-446545760710144039411282139051 +sub:-8121545527448089591108392261383421226,-250658045580063728305171566063327,0:-8121294869402509527380087089817357899 +sub:196379537181644459409584027643681,1405776248624555617885389492315342,0:-1209396711442911158475805464671661 +sub:249608305407374994198898962694969319,2499313962944780828355872882428,0:249605806093412049418070606822086891 +sub:-86133870952625036607121720129239484192,-2210083521958904762483447549909,0:-86133868742541514648216957645791934283 +sub:-5537761268890338810683747816401,88831072690533799673765398860186343,0:-88836610451802690012576082608002744 +sub:7650066177648379388712028843866717642,918679522282053129239748147974121,0:7649147498126097335582789095718743521 +sub:565791730633833592281012727365648,852047442684103892006895595156346311,0:-851481650953470058414614582428980663 +sub:35625580968671553109914463243195234,991752088396773683576302377308181924,0:-956126507428102130466387914064986690 +sub:6830152102738950636231503454962474,6109835276749854485232715520241,0:6824042267462200781746270739442233 +sub:9645316618209602253070352413137908638,3394079504397347166925767086732227,0:9641922538705204905903426646051176411 +sub:6906473148858285032644642660383154266,-13248476237838956330778312519,0:6906473162106761270483598991161466785 +sub:663679860762267995009788953575,245501799877415862306412167957117435,0:-245501136197555100038417158168163860 +sub:-44512568466689863068389777224796828752,59397617756155227553085552332805471,0:-44571966084446018295942862777129634223 +sub:-9780895042010683622315363216460759418,76907130979153947097579514138695056628,0:-86688026021164630719894877355155816046 +sub:7347847663681638512926883660656747,21689722568710802776572651908345,0:7326157941112927710150311008748402 +sub:3783373250173630571015208086015385375,85650811474649882924710498921920,0:3783287599362155921132283375516463455 +sub:56849910710166566393455502068193,938068347237485972222899422567001939804,0:-938068290387575262056333029111499871611 +sub:504581213153898088538898634074784,298859276817968178012741515281,0:504282353877080120360885892559503 +sub:62457537532467044548168035547098,350956278715084042186918483657291476,0:-350893821177551575142370315621744378 +sub:7253075028419141077788097530219264862,50712428890680046435253055355573928021,0:-43459353862260905357464957825354663159 +sub:908092436379098470271979681591988,-50980440695559153633860322916212052697,0:50981348787995532732330594895893644685 +sub:199609775815884715957098583502038535,126431898613403845101203447550779,0:199483343917271312111997380054487756 +sub:9582359917228621477273022611353,-7814266758202663854720672879571,0:17396626675431285331993695490924 +sub:-8602898145948602715689375495162314,160918011477272833149624669760689743,0:-169520909623221435865314045255852057 +sub:9948567545244824462599097821402,321969130181831095335604501478150,0:-312020562636586270873005403656748 +sub:3108375720921396317913873465866,515757643860608151355730977219,0:2592618077060788166558142488647 +sub:-6959118740348618652311501232880384,314902316795577348140190091299453995580,0:-314909275914317696758842402800686875964 +sub:852431860747366034722063069637910,697844878845085176354494126562269534,0:-696992446984337810319772063492631624 +sub:-695872067848396881315408129801830330160,515796995164989970353676000353939744,0:-696387864843561871285761805802184269904 +sub:763264778536698023696216317523596944856,66658684467328574590928002628720352,0:763198119852230695121625389520968224504 +sub:551406701743303600756051581664966707,-2096778986234403787979394471172513533,0:2648185687977707388735446052837480240 +sub:8980464673485071567470684316357345,706157473742536317728718771566732899996,0:-706148493277862832657151300882416542651 +sub:-8959013916303797315474218091253977724,17317243712015390717561716185598103919,0:-26276257628319188033035934276852081643 +sub:610642046003967779716956199512502965820,-1342047130732031394498227273521440693,0:611984093134699811111454426786024406513 +sub:39048465017221373894786787092323,27171758183377068947756846246554,0:11876706833844304947029940845769 +sub:8851422489276175894252333429720103986615,23971945232205648973518397199417121,0:8851398517330943688603359911322904569494 +sub:-84833640081477194078008827918110,4096265727659744202225819899847459,0:-4181099367741221396303828727765569 +sub:2449552679550251863203300609863059096,-87978393823203322230640767374297,0:2449640657944075066525531250630433393 +sub:-78001817791533007712431842020149120,-517984095203705432252174589659459457366,0:517906093385913899244462157817439308246 +sub:925643199231868890271300730031810,24193296045997277400311155524231,0:901449903185871612870989574507579 +sub:45809177403727955831024802122687486932,47359799236575106780358807894627994236,0:-1550621832847150949334005771940507304 +sub:517605223957091165935716210936350445,862910955378659702358254436657666937,0:-345305731421568536422538225721316492 +sub:72688630642528437745188023003208451686,-6514092119486018712109302075636901,0:72695144734647923763900132305284088587 +sub:9017708871653095110086602388639208564217,9686163604138029584498185971117663,0:9017699185489490972057017890453237446554 +sub:232079069033420026812017177630381923958,-620458583032652195500759259597623123174,0:852537652066072222312776437228005047132 +sub:7890695491854299352485817202277388,703159083088728550533731201284887315751,0:-703151192393236696234378715467685038363 +sub:89820101894310757911847760478077656263,83262600530464963372213698397466309520,0:6557501363845794539634062080611346743 +sub:15643499204310770849595390474553,-167812233465782889797029678386637503251,0:167812249109282094107800527982027977804 +sub:-5489423773440626595521848968440708,53474930188578916210505119684094887079874,0:-53474935678002689651131715205943855520582 +sub:9795002336914579634933717979516686913,261017010939337312979598924346472448676,0:-251222008602422733344665206366955761763 +sub:4331261142314159296760231606251204672243,95924782688351130622315102956854589,0:4331165217531470945629609291148247817654 +sub:-8555084299250330981422502494290977,-783738723298387481257063528884261006006,0:783730168214088230926082106381766715029 +sub:55877969868981220363181591809987047101,-582660368158295495569660057228613506663,0:638538338027276715932841649038600553764 +sub:7431276323200780996119690290385564268160,352432120959308196444383869982649742380,0:7078844202241472799675306420402914525780 +sub:55510991248344199097615219287024885342254,332608825632573500219548085422149375,0:55510658639518566524114999738939463192879 +sub:-407443715077704811283446238871658731249,-40791246123034116937388818513050,0:-407443674286458688249329301482840218199 +sub:92659603513745501543601415394970469662329,6767288283622355176053882537452755648142,0:85892315230123146367547532857517714014187 +sub:47223347378419458293433033085679670112,-62754319264178123190515063783530,0:47223410132738722471556223600743453642 +sub:1267788394862117094544460471276744086901,-665697188010909239862834883890257046539,0:1933485582873026334407295355167001133440 +sub:295345762969445285300883528234566,676193063455453770878866399645739938,0:-675897717692484325593565516117505372 +sub:5505393498870816097766218031623252626,39514445630793756368190395762767,0:5505353984425185304009849841227489859 +sub:42208069897508165365927050240558926,45558978530284359271147071076409531,0:-3350908632776193905220020835850605 +sub:54167453556761503889312836115010425171760,187522719313793483915703839179272166586,0:53979930837447710405397132275831153005174 +sub:362669233317017065848977774618899144317100,22296129083231337516474760065879885,0:362669211020887982617640258144139078437215 +sub:2070398587579928847370215004355097684669,-64067479504146184394486079741662,0:2070398651647408351516399398841177426331 +sub:547456256889894902401571239347850863825110,963930110027673150476898540751636078,0:547455292959784874728420762449310112189032 +sub:1331413985442244763704908202938864787301,-6928236741466387982911397285024730442,0:1338342222183711151687819600223889517743 +sub:2647018820693334945869095350861961405456,68207845515177324917936202808076981,0:2646950612847819768544177414659153328475 +sub:8513268833284045819607290710032375651,877742296072025989690540346672438747497853,0:-877733782803192705644720739381728715122202 +sub:-362723824300008973505657052571345045426697,-3728428407208494550981026382186278817,0:-362720095871601765011106071544962859147880 +sub:29679672086905939495640819132486834971886,805805496484559347056265315535987,0:29679671281100443011081472076221519435899 +sub:85912095665544820943415113062566570378,-2312537069323562328248319672615297,0:85914408202614144505743361382239185675 +sub:-92634213643016881068533819685947190995,874723874226479957426284530510689780,0:-93508937517243361025960104216457880775 +sub:339348983157405555268049494721010874912,538915927881095996244878294700090,0:339348444241477674172053249842716174822 +sub:-786507623206485460799545427617928648802,-66497629708368438568316964408808815,0:-786441125576777092360977110653519839987 +sub:7838773867614617728873367710439469,-20970941234515400392700499346730050,0:28809715102130018121573867057169519 +sub:-14549979612356881205802146600958641293,-4331851795749574278449787125765833575320873,0:4331837245769961921568581323619232616679580 +sub:916100575956975239103806648291021240434945,-6239107263122317258754465996318083039813,0:922339683220097556362561114287339323474758 +sub:92055367791915247552778134001204029114,6493201508072505271272645779402011239988532,0:-6493109452704713356025093001268010035959418 +sub:-6983015937156891828369789959503372656192768,774335279468118483882198373037947794429,0:-6983790272436359946853672157876410603987197 +sub:3000995395281402114598820789701617484765714,21554713637509345916067753026101593,0:3000995373726688477089474873633864458664121 +sub:210513959404424485767273638342023036080,7040631017221420564743196284036319107483,0:-6830117057816996078975922645694296071403 +sub:927299366270769201971090702434342061,292331300721224857352792240371766440,0:634968065549544344618298462062575621 +sub:4878072375408814508188936210997478,1660478705544816285463647361127486,0:3217593669863998222725288849869992 +sub:549522597810758995529412992430729353622069,28161367971601239141551130639124424718,0:549494436442787394290271441300090229197351 +sub:-3158360246238245818023338839988456941,266461438371462069740221467823944724791696,0:-266464596731708307986039491162784713248637 +sub:9007280594321441251173718122758301273400191,5723070952876244917629403533894720814995808,0:3284209641445196333544314588863580458404383 +sub:7884430922306064951790326519656428,-265155882238652982403545634743490030,0:273040313160959047355335961263146458 +sub:4597158820829446940984073371303248589349336,4591368594874737502008341975525406,0:4597158816238078346109335869294906613823930 +sub:187371543407659146021544517634809651432,2502692698036481709764505060551779924246,0:-2315321154628822563742960542916970272814 +sub:-46135001830288779024726983515547650361,28041526428243568730358118145100364532,0:-74176528258532347755085101660648014893 +sub:-9572831631676924773779207132507340476745,6190297632466241073074006835641016273635051,0:-6199870464097917997847786042773523614111796 +sub:47274442119812358441831910654123850,99197173529181174900799490801927162,0:-51922731409368816458967580147803312 +sub:4006521386515878530482447147782028809,9872623466258041127006795769315012678883,0:-9868616944871525248476313322167230650074 +sub:82360906569911962379105787490864998240463,3515099274891762492395251937584744489436,0:78845807295020199886710535553280253751027 +sub:343670280360898716041692324762031485,912832148190967667750082998631524743067,0:-912488477910606769034041306306762711582 +sub:-253140613356453965474749134907880537,-170796125539274882635608256319127725001467,0:170795872398661526181642781569992817120930 +sub:36063566343365723001908493555712611383171,32734135808710310540138548400630432992351,0:3329430534655412461769945155082178390820 +sub:8562448362864558581436509546230412228013,97253910164731217335889068286633868249,0:8465194452699827364100620477943778359764 +sub:458404043113501189736392131389765493,90992739814093306447341282135584737049,0:-90534335770979805257604890004194971556 +sub:93153136351650823472294576193567969076519204,-173058937221894304147436488969103021,0:93153136524709760694188880341004458045622225 +sub:6881134628891939703289843575851421899205356,411386417698245110176551995497774432463572,0:6469748211193694593113291580353647466741784 +sub:4806770024356558662054629453935871253631,-54599892445310777761980324364755187,0:4806824624249003972832391434260236008818 +sub:-659266383152476584352966529996782786154127,435809612191536018491951858809486469615871,0:-1095075995344012602844918388806269255769998 +sub:6935351506572536921188795798274428881775,-576575580669724321453218122448616063259,0:7511927087242261242642013920723044945034 +sub:858138516046706031509684781296126036025,8270111802191391308669991938939548604849,0:-7411973286144685277160307157643422568824 +sub:817937608310793751229857205081702066047,67716404516400692803055765045097508053,0:750221203794393058426801440036604557994 +sub:21505104291973748253849551840337359946735,724706181460445217421835535592570632258046,0:-703201077168471469167985983752233272311311 +sub:708273146228220275650926105350112291281906759,23865262954820244462104344820227603348946351,0:684407883273400031188821760529884687932960408 +sub:6099153001249914941269621426404674818058,2938683952037817006492484814984313285,0:6096214317297877124263128941589690504773 +sub:-31923841914332687245342017699243753384096,-5606132365222969440586408949174817104241599,0:5574208523308636753341066931475573350857503 +sub:72727007176742518045851035107319602707253724,6024790453998465390250582473731871348,0:72727001151952064047385644856737128975382376 +sub:83215407925470185284051090474309060496,291921577188866523931442328192670035753786,0:-291838361780941053746158277102195726693290 +sub:9122506511038509689834545171005820589612113,719752849629179435477077881697561682399792,0:8402753661409330254357467289308258907212321 +sub:-706538117813388518478786341886424717471940980,753933770122593367025588615709647464797283389,0:-1460471887935981885504374957596072182269224369 +sub:-521928555277746411910375390507381642863,6565723095409618237803362642454225982248113,0:-6566245023964895984215273017844733363890976 +sub:24450643550397676433664068681105834123,-3553012684598341625460876864934571794587360,0:3553037135241892023137310529003252900421483 +sub:4697123465198881265199203985357713516731,2536656939218887194502000678986317871877842,0:-2531959815753688313236801475000960158361111 +sub:-434930612814998054601249422118251831669239,-9901632499831703140917838027000240996177,0:-425028980315166351460331584091251590673062 +sub:-24385109664317253785149664202310847974785,96607275813663749523021171230142234086194,0:-120992385477981003308170835432453082060979 +sub:175998623183130570261164123649545173,5736821048759940607107406386900421138480116,0:-5736820872761317423976836125736297488934943 +sub:29899463144003206689099598069297927023037663,99983896248939908245937246988587266778965056,0:-70084433104936701556837648919289339755927393 +sub:-2847961215729667396008072338427848628952207702,-18041421325649266529475871020854283985158140,0:-2829919794404018129478596467406994344967049562 +sub:860655541398867584200967070629696235008,78536431962263231465180358761552384639106,0:-77675776420864363880979391690922688404098 +sub:635054687904331166120357977754969371811679971,-686756348638066683308736393560844813903,0:635055374660679804187041286491362932656493874 +sub:66115475514119620126879119225040664892295317,-87563343403151221453653304787865218792612594,0:153678818917270841580532424012905883684907911 +sub:-95550181030075465859987797705444435041845,-13665284586416167283376541733856225706235,0:-81884896443659298576611255971588209335610 +sub:92616049236912210791574668731523882357,-50096816156035511846343817545380962370926891,0:50096908772084748758554609120049693894809248 +sub:752708246188412062918458739359406381571670,-91802938193508678084864563021449730861494286,0:92555646439697090147783021760809137243065956 +sub:4243612523329014748898840962380294468164,-7391899758560053704137252356014460148281541618,0:7391904002172577033152001254855422528576009782 +sub:7067486379132347032443631353172208490907237,6868653310067531021850169369487996413345,0:7060617725822279501421781183802720494493892 +sub:652556473645101039426795633187084650620590359,66152612457983000774979517275135281517333,0:652490321032643056426020653669809515339073026 +sub:-35248969314647098087083472237063687482719167,25849045865960518844267357563296662714932,0:-35274818360513058605927739594626984145434099 +sub:154806501204449775250550809865383692315599,220408143673773957176222952814246726548300733,0:-220253337172569507400972402004381342855985134 +sub:426192001635333106574725027301522624829,54396270337654281439857103497213765055827390,0:-54395844145652646106750528772186463533202561 +sub:2229896635643148464416291192052339376,44520846864866048574834661782670612999637,0:-44518616968230405426370245491478560660261 +sub:3511182372941029827917330703726647738515,103149425998143931124350359115352011,0:3511079223515031683986206353367532386504 +sub:525626542557810263995696385369141917216429,28217794014403546465377535948401259179623,0:497408748543406717530318849420740658036806 +sub:246690678230593477546220249711651118557673599,7508868156388634892422733339741334130597495770,0:-7262177478158041414876513090029683012039822171 +sub:-52449842456878273278887468997485654278006880781,-8622224358149020156382756933011263673304901,0:-52441220232520124258731086240552643014333575880 +sub:43917648018810264827549426849617327620,237558137782296171751042504067082682085,0:-193640489763485906923493077217465354465 +sub:436885913378194523559098742354033959419293521,-4530060472748984412434685566970122986799899668,0:4966946386127178935993784309324156946219193189 +sub:934641428600528147928021193868692944237063,766500089354618869804173156494044479533434,0:168141339245909278123848037374648464703629 +sub:-9768794865885075606938340182122123503498,43399753693320722515476020420307206331,0:-9812194619578396329453816202542430709829 +sub:4363510431895873679990777251153049456887914686,-513680867120410140612246382388345195337,0:4363510945576740800400917863399431845233110023 +sub:813902461333355602341973794050956320693244,45925401255610697190710944025791579854,0:813856535932099991644783083106930529113390 +sub:469188297775571118958824594174696108861,49387169240595114881040011727698749675,0:419801128534976004077784582446997359186 +sub:2617097578471262472460098378161373440917,626830512279231586849866185531317270325856135,0:-626827895181653115587393725432939108952415218 +sub:5151556733598102144567084692707520491967675549,925683351507641765110930982020390027551182330,0:4225873382090460379456153710687130464416493219 +sub:7961214185889032744958189528184087887568,15082937694452952801156707282245848781046520,0:-15074976480267063768411749092717664693158952 +sub:103879675257649176952122144944531240879704,-22423657059836578389654041651233303849189846,0:22527536735094227566606163796177835090069550 +sub:-377277225308671992459589258065441211400861174609,785048601099920118475775642499967466881441513003,0:-1162325826408592110935364900565408678282302687612 +sub:2735744675788022453896759288099853051599961,8561848816916220633924173923975969846159936,0:-5826104141128198180027414635876116794559975 +sub:-8108322047295156406910661075095138292543118,765970407325610304094444482334627162219563792,0:-774078729372905460501355143409722300512106910 +sub:62171119480646146147373364600786632314820,68234069541303335859784698762591456286309,0:-6062950060657189712411334161804823971489 +sub:522026031606431401123213997569507489607798170076,-717305442128471697055893486214586513387,0:522026032323736843251685694625400975822384683463 +sub:7106849336102271174193475715677967626534,9912977315535152329193899289756117840576705086,0:-9912970208685816226922725096280402162609078552 +sub:5058631248804275381537183819839410866070,50068425216904104076548398574368463679233329,0:-50063366585655299801166861390548624268367259 +sub:377384922290900684378766697765696266656684929965,3450714239029691596858831084813277683453331017,0:373934208051870992781907866680882988973231598948 +sub:4127043375130626839550947340494729073973521,-93626779328435839646986009707952408489178855259,0:93630906371810970273825560655292903218252828780 +sub:8332162922657358325764463012629457809751,18980828259225905732804403805861953606268378,0:-18972496096303248374478639342849324148458627 +sub:6824265591340935169578122399500191463946638,540683715600472521291029118849898014133054,0:6283581875740462648287093280650293449813584 +sub:938521197483583303249511621812565283382055,44983796709641426782128325690649049185212710901,0:-44982858188443943198825076179027236619929328846 +sub:6735919466177663580236501266144291220013606,545280109966768999298146733178996573556068,0:6190639356210894580938354532965294646457538 +sub:141557686844798866713592847624357600454939,63012778579350927253738282115561965895300222,0:-62871220892506128387024689267937608294845283 +sub:2911872274073904179049270098803758998758604373,5178258239494241937818225445947335874009677,0:2906694015834409937111451873357811662884594696 +sub:1408871869925689627762516558570503883504,142730298505138588027696948531422563739,0:1266141571420551039734819610039081319765 +sub:8517606735957047009697093887557000606415498004,67761524001779430467799539453579156328203130,0:8449845211955267579229294348103421450087294874 +sub:4191752928232629208839556407817672130663759960,31120143251696350351062838658625186585417641244,0:-26928390323463721142223282250807514454753881284 +sub:1773460231905714486091498164221417916299907001,-13984788525502795401300137979455088110924764646,0:15758248757408509887391636143676506027224671647 +sub:25958221336257013267259455572234542250872387609,369753082501759921518867762124056653598276202875,0:-343794861165502908251608306551822111347403815266 +sub:2747326205290884717571093710516354517279131,-200370678858880488915468681389496795418066109,0:203118005064171373633039775100013149935345240 +sub:40540925013283891720123827423744878263336,16816649411016376863928894144184888209331,0:23724275602267514856194933279559990054005 +sub:956824713963595631181304277992935834382643,3722011506884112771542173984351354075026431,0:-2765186792920517140360869706358418240643788 +sub:33786382660255444220666312795011817615453429904,735670904381689507641600295585249267679379526941,0:-701884521721434063420933982790237450063926097037 +sub:2877930508524945640926303283416511321376944980965,-43009247946073345794766337066700378436417844073,0:2920939756471018986721069620483211699813362825038 +sub:850600786011638919961278503128401557972292751560,899851210392294397522137472190488479511758393106,0:-49250424380655477560858969062086921539465641546 +sub:2462694975979744365735428888726732845981,9408686710098328540592679577780711010523157567,0:-9408684247403352560848313842351822283790311586 +sub:-2041867610696880800533651474257712171578353,-2951979315678021415040184889765351233307860,0:910111704981140614506533415507639061729507 +sub:-129073103525919620980862298218649200450487,-4680531750102980987058307458952588397482469573,0:4680402676999455067437326596654369748282019086 +sub:560697897202574381605152953497173580884569831607,-4417286348361216883592573456612155389663357,0:560702314488922742822036546070630193039959494964 +sub:17697094196983519858381804010054585256525242,1131229531263856806842311520174862769452765002,0:-1113532437066873286983929716164808184196239760 +sub:804944662083760414801916105180787524533460301166,561420687759659377688505547923187467868090247,0:804383241396000755424227599632864337065592210919 +sub:-1028404789696953408936491711523277627418563936203,-464819589190508369472777448816708894892918349,0:-1027939970107762900567018934074460918523671017854 +sub:3239904738301933363048789064790365041923795,-9362725662858815747997680077547152674652685944821,0:9362728902763554049931043126336217465017727868616 +sub:761535872788271240805547447218654406655,107117430857728547131949784152272910306695,0:-106355894984940275891144236705054255900040 +sub:-706599751963833313886288562747297926395913585,8278362817238299934703728858793740479430872564850,0:-8279069416990263768017615147356487777357268478435 +sub:463035181445197130733843489204182896424351860,455471771631505836436066499095031596509414,0:462579709673565624897407422705087864827842446 +sub:2824978869446515961236880620253514087311655553702,84452147844444783212562643686865477267414258,0:2824894417298671516453668057609827221834388139444 +sub:95172190180193659817200533401819150201616611288,4253516641549024667802049662408505566309488148712,0:-4158344451368831007984849129006686416107871537424 +sub:-413667190552706011487044934212907016404257969614,33510901758543302257900826215150539862667792900853,0:-33924568949096008269387871149363446879072050870467 +sub:1802858236899130718560292083677283004676939126204,-9591029147984982245013613101603852129053721197,0:1812449266047115700805305696778886856805992847401 +sub:5057939642669588382714715374719737582363077336,6279587642602985268062149755325894048022192320,0:-1221647999933396885347434380606156465659114984 +sub:20062487148514066658598386877620234236424,92694212932494347668352880363113439277308854,0:-92674150445345833601694281976235819043072430 +sub:334984437475294142374221031664489193167379,-6135445036242663334683894840540269979231933,0:6470429473717957477058115872204759172399312 +sub:78029827510297184965229487811790757939762626812,-32404291595021766293653499499799280338229,0:78029859914588779986995781465290257739042965041 +sub:713392855478976816484264895166180199146764030460313,681291155333056129472241044283899139868686991,0:713392174187821483428135422925135915247624161773322 +sub:-80133415624337150636387109270312659175361915999,51418478774844443709286576402320460325196,0:-80133467042815925480830818556889061495822241195 +sub:880115711847568080735088547347709199159560057170765,93939048978536600599293035541531212947874110,0:880115617908519102198487948054673657628347109296655 +sub:6923910812034533596353419663722878592724935671,484167528133286735810248062291120475761574,0:6923426644506400309617609415660587472249174097 +sub:67181341858171188344681106006257889001113561091,-275892233786910833508198970431602677775347,0:67181617750404975255514614205228320603791336438 +sub:36921718877954581697392970162605715186348102300,94932105400913864317595606773063738421165759973115,0:-94895183682035909735898213802901132705979411870815 +sub:10176087189864101236325835126503742119508524,578515167611780503112210135879212793628134689743,0:-578504991524590639010973810044086289886015181219 +sub:771806623592639026200339778481682177781432660780,67004362616728326045114859791690823708021066956420,0:-66232555993135687018914520013209141530239634295640 +sub:-203402851288321919373536431407297524778554,6479472994213736597322939815331596128853683,0:-6682875845502058516696476246738893653632237 +sub:1472434831082398237848463668763914130244321191790,749284377551792267939683738695982222675701748529,0:723150453530605969908779930067931907568619443261 +sub:21819548957613983312659642613368102599157263541546,-43027293878272366259573611249912277474953128041,0:21862576251492255678919216224618014876632216669587 +sub:79183581106215686052084319942513882987033006034916,395676242411723933204666672941564134969621059,0:79183185429973274328151115275840941422898036413857 +sub:8848994582532139477750176043869310148875814,308406836916867466802062976742038687492470522689,0:-308397987922284934662585226565994818182321646875 +sub:7723560617201337569325102213658726205516718762753,10703682032080071751681616104703726510312121990,0:7712856935169257497573420597554022479006406640763 +sub:57399920075594463974650254762286091360205308040447,7737623533444627764626187063734986201237515268274,0:49662296542149836210024067698551105158967792772173 +sub:9235227695889244745982433565536373274090597220112,107148050059803991302004419466765330676586504,0:9235120547839184941991131561116906508759920633608 +sub:-4983756542035372848701023851198318990123574220609,-6542643049007414884687990348404270219346342352782197,0:6537659292465379511839289324553071900356218778561588 +sub:567419840932221417516346055492012551836180868531246,33746605794257306032350927932072975156967743676747,0:533673235137964111483995127559939576679213124854499 +sub:587649861585950611495201008010198217521972105575,887181300999163339932116937542961612984777530930,0:-299531439413212728436915929532763395462805425355 +sub:7453222478591891189413329402038211767394218016685,2017672006030135323721939597399603743488046383,0:7451204806585861054089607462440812163650729970302 +sub:2861829900660252465253636986401989994945337,773601832041130668133623108987574604308317806,0:-770740002140470415668369472001172614313372469 +sub:1854813068723965360605974071849448846065646688997753,-1779594647650002771086955563648126785119135484216483,0:3634407716373968131692929635497575631184782173214236 +sub:92477926938178288909943789222630295714892817851483,-9993806749512159715432826828952487671606121447735045,0:10086284676450338004342770618175117967321014265586528 +sub:180006337772988467709872310927140175108921733,2381572659355146492539589222943064206470713510957947,0:-2381572479348808719551121513070753279330538402036214 +sub:-8062115630203258999893376666703748484646367,-242384162973621030696116727652753612307623848798,0:242376100857990827437116834276086908559139202431 +sub:-9512092783939545330832128518113211511839319679,51817273821892700393156339701080192019872355095563,0:-51826785914676639938487171829598305231384194415242 +sub:95014753687636191420633875239958137975948173417195,-3085034910995602744319197683314962939217430996273791,0:3180049664683238935739831558554921077193379169690986 +sub:-851020909203213144832385221818295668814907441557232,920708095345140363620526592235073155935947208,0:-851021829911308489972748842344887903888063377504440 +sub:57322816917914786923271397439113286785049794499,375876690150945835847772932354648419953665427305,0:-318553873233031048924501534915535133168615632806 +sub:31393149038789273525817858949583645513566324353,414359836823939404881738593288787821854173,0:31392734678952449586412977210990356725744470180 +sub:77504028676487775641669635436308236988049655601524,181344091581225499628551847769549638986540093069,0:77322684584906550142041083588538687349063115508455 +sub:98633986434584756460936637580630245052082529240,4571853594019360336499761737542755082748090242,0:94062132840565396124436875843087489969334438998 +sub:72702371263558464947877213929280953160835791,336826520924373293318758608698133996765552613,0:-264124149660814828370881394768853043604716822 +sub:790131994620824397445459877738169154533174191,3152340776901124584130874954251376174718487427033,0:-3151550644906503759733429494373638005563954252842 +sub:-9550173574955362798449947158209546914492142849353,-54424792605728662879926674617913575370555620507,0:-9495748782349634135570020483591633339121587228846 +sub:94354150013483998466350999623761463016719477838,6188045953454972757543729666811730031705853499240,0:-6093691803441488759077378667187968568689134021402 +sub:3939113274773256610453330771473753217221500577791591,-8856764963107169782992507920019475780655171681871327,0:12795878237880426393445838691493228997876672259662918 +sub:2660941406633181818791417317975166457527878033652214,7055550945359964654212545682444924769432938191323615,0:-4394609538726782835421128364469758311905060157671401 +sub:6672381018209518975788815573873682181604983076,69748594953382081761188754597777837110112667,0:6602632423256136894027626819275904344494870409 +sub:-22928680073391300326697730831966862930951563902710,-36030604459777331413643572771813761886932316,0:-22928644042786840549366317188394091117189676970394 +sub:906731248248897060644189710812453469279110754543,-41959270679040328466239441893560854573456943089818,0:42866001927289225526883631604373308042736053844361 +sub:-70638227944710922429439115847001418432478750483,760914797512164822868407393497280368562831931857,0:-831553025456875745297846509344281786995310682340 +sub:-216358205244444335173319801401182209472584639,998326193886993948549118716632444642265383767831852,0:-998326410245199192993453889952246043447593240416491 +sub:9580122909801568750668900466947122420236232215529435,-62027973553309464740272784879673114659231909,0:9580122971829542303978365207219907299909346874761344 +sub:622693558963818873312878405559947227488964435,3981112093580815021150239981188100077575880890208,0:-3980489400021851202276927102782540130348391925773 +sub:866815675276233673264562843306494664048668452463644611,71519824955354947547025359232296671791960617075,0:866815603756408717909615296281135431751996660503027536 +sub:-6687913766044745929873407959705938856856788714,-128082208096293248054363272445011912033353379,0:-6559831557948452681819044687260926944823435335 +sub:6533704846133682195298434566037164357331105933,-9099620103006618056421372601941016491284861199065,0:9106153807852751738616671036507053655642192304998 +sub:4119542544028390490425044803879052308401738542548112,-20834003332412447609236300940967058715737799257,0:4119563378031722902872654040179993275460454280347369 +sub:-13158459479990345059531702133456996581106330236513,888807402238789998415182036488079992896567250394,0:-14047266882229135057946884169945076574002897486907 +sub:986374598296880992789870555481914795958300865,36115966024290721654021137035289387632631652243,0:-35129591425993840661231266479807472836673351378 +sub:60328360173152774817583105641423657510833102534,806537457680548774367999519005704564118620169512120612,0:-806537397352188601215224701422598922694962658679018078 +sub:8497710798125734752308241652761644166763994003249,2232134954790237265184644308782501409978670104200558,0:-2223637243992111530432336067129739765811906110197309 +sub:-66833280768590802448180039862748595225905660580,8736830538198277449921336865075351529251534384,0:-75570111306789079898101376727823946755157194964 +sub:912827735433629466385516382081400733023462641070447,4902935580754276432455992085105349174803805305833,0:907924799852875189953060389996295383848658835764614 +sub:5478598360832354100644271821080131609231404518792,-47055673068764638632714990426082071032104852775171,0:52534271429596992733359262247162202641336257293963 +sub:7690586776927788135745843200669172025110973236,384324896599663253158847925223211417882480709853337445,0:-384324888909076476231059789477368217213308684742364209 +sub:983884777941532996194149884936915312060876070737,518287984800732830855502265279223067978197266689047,0:-517304100022791297859308115394286152666136390618310 +sub:-954694380473047886020997568695000343640652324258341,14189460325400480062958182003318094361774366261792942,0:-15144154705873527948979179572013094705415018586051283 +sub:61441847820605789319902797573300129174741870859,-56353161438453661015964270802670942459168904316247488,0:56353222880301481621753590705468515759298079058118347 +sub:840900363013208299376170217559531949250066389223,-518733806293446093467395721640110032406740773472,0:1359634169306654392843565939199641981656807162695 +sub:2801043712260244666215482898915857882171271259,30068822738933846329923273175088581474609748837369043,0:-30068819937890134069678606959605682558751866666097784 +sub:39332562720628190237986833106169417514936299004,3977882056567658721057988043991788532782214317,0:35354680664060531516928845062177628982154084687 +sub:4875943313527670330837641575224800871607771346650,3006293236431797162023390328257380215745687023197,0:1869650077095873168814251246967420655862084323453 +sub:1046076579612442168236157596521887526129291572,56509310551736435818443805857748077305452153240874241,0:-56509309505659856206001637621590480783564627111582669 +sub:68801970722430443700036017990845232711747541145506,3921528808796839431326261733514349542141553429,0:68798049193621646860604691729111718362205399592077 +sub:7996124256938877464175310613395477260421185912077919187,43920453269964575011284701085185099530091428989544,0:7996080336485607499600299328694392075321655820648929643 +sub:437847871205482940383237227334352005149025155566700,8912640649325787853768245140880891930970131371688993,0:-8474792778120304913385007913546539925821106216122293 +sub:-189562142066164910097303467426752455631983999971824429,-3126396058243394757216280555044878821697145366839147,0:-186435746007921515340087186871707576810286854604985282 +sub:3738151126960474749651813623570168405472279315305,16849954488569956342093577361010810357803346759,0:3721301172471904793309720046209157595114475968546 +sub:326436788465045244627154191800265908625864556666530,8436920985951650690723103995113757167828613977782053802,0:-8436594549163185645478476840921956901919988113225387272 +sub:73862903715165018158730950116899815638213415384,3605176405676828750083989599730691253025429971416,0:-3531313501961663731925258649613791437387216556032 +sub:-98508500558610553174664717035831451337440647751,-85349349113075502208578338510421486004026291637018909,0:85349250604574943598025163845704450172574954196371158 +sub:-3958479771038348317047929281014493361412362156,74460379620572355406333334733218930851102604423,0:-78418859391610703723381264014233424212514966579 +sub:-2678832891454610091209266352796918435982227896,844180754012069973260601080737112141842619632733391282,0:-844180756690902864715211171946378494639538068715619178 +sub:62145977984087344899814827854294051292745009920192834974,7334739588662979743633482328597512684449095879737,0:62145970649347756236835084220811722695232325471096955237 +sub:829628512088735025241917875963770566118880397874,2778273578473650916716745944557448674527619910366636167,0:-2778272748845138827981720702639572710757053791486238293 +sub:5475358208178590127449325322332321821544579907242021829,5101549647265375935536396006666544834314249747938912445,0:373808560913214191912929315665776987230330159303109384 +sub:-327933746445993810109526304208281604193537699541388,-17513330151263794083025328269239503268164355683299,0:-310420416294730016026500975939042100925373343858089 +sub:-97299271106272768099051589856225693996221199008328,-683640181471185906440394924792222282513250833654408,0:586340910364913138341343334935996588517029634646080 +sub:81950415706753285772469335186046579994901810195099988,-695576496751235568817818414861599429774724685935,0:81951111283250037008038153004461441594331584919785923 +sub:11733022337838616680086438101577803026869925229236251633,4209981603742836477443590186310139108935024708250714,0:11728812356234873843608994511391492887760990204528000919 +sub:2993252088056118669505330045592351552378298855615136540,12751727236236955721686048352301817814151141431,0:2993252075304391433268374323906303200076481041463995109 +sub:39376759077330221210471049201931709948853198615,-9493608874721279041170835115951049053361083855467392,0:9493648251480356371392045587000250985071032708666007 +sub:-5280130155085387575883303159292113846385931782810769147,-1019810672320943407741389860781837676645351883469636964,0:-4260319482764444168141913298510276169740579899341132183 +sub:8457922806422768126334853404146638292374687915778812,995127687303275765352581834049367391219012453856914,0:7462795119119492360982271570097270901155675461921898 +sub:34992662458077134231839550916665303135384048742,-8152964279502937641561776276851678598174407814,0:43145626737580071873401327193516981733558456556 +sub:8237492058118191763481523977841344753346311488313,1647118892275027900093320780430922273315158677508003654,0:-1647110654782969781901557298906944431970405331196515341 +sub:-440042339580320057764506833117106015591230779324161,513962930617733479729549861446740257284856596728706,0:-954005270198053537494056694563846272876087376052867 +sub:34635151931992497392391616758693644900635250427499823,287128980133325949899403223688828310849990578079457307,0:-252493828201333452507011606930134665949355327651957484 +sub:48138028043471938379654489799905392276347294678190375860,8955461479465751553200394404645878189278984773776867,0:48129072581992472628101289405500746398158015693416598993 +sub:7624317887859192567599023956675797189693348039462742,-973928186389609942202650295012119719585450666839535260,0:981552504277469134770249318968795516775144014878998002 +sub:775402642132715473344595954662582545794117369927872,63796684229986115177275440213147384846517231365197485,0:-63021281587853399703930844258484802300723113995269613 +sub:37362432357418646911115330814724472853415155235293,87036796847105652716376950065916449694424391617602112013,0:-87036759484673295297730038950585634969951538202446876720 +sub:-300945445086734604702237356948834421909997080585835251,86543393214880176913230280671573673375238923042066,0:-301031988479949484879150587229505995583372319508877317 +sub:-654047435982290398129267970179757606710004276417490112,86422930881746427524648992269920847889306495489,0:-654047522405221279875695494828749876630852165723985601 +sub:794552108714326403336258405676646043844624401498072689,544976653015779028031808690831373018858631899320,0:794551563737673387557230373867955212471605542866173369 +sub:-195959798494693192093817249845807727728979751653,18593677965094459754532848130637776457537309190937253673,0:-18593678161054258249226040224455026303345036919917005326 +sub:57601304615929231199752161276702979414912411756145,21951958716061857914468826747760163180070915240014675524,0:-21951901114757241985237626995598886477091500327602919379 +sub:311215074108149476976205428525338649682414980832,6243249733271681693520367645680387625166806885842687456,0:-6243249422056607585370890669474959099828157203427706624 +sub:-60089258178336658544420554675373945148810656687928409220,-940949437845306471952666460412774999437620754784474,0:-60088317228898813237948602008913532373811219067173624746 +sub:3844895658482592533059556269556968661475827694950384997,527322363491124024058755005552497077118499938802,0:3844895131160229041935532210801963108978750576450446195 +sub:-6028944995177498518136854918757906591099625985414,15888968609159402431030920451645796896759203224067431,0:-15894997554154579929549057306564554803350302850052845 +sub:996013497441974701923950607149438472739078933691,112407411020615162605964831561295393767448218127,0:883606086421359539317985775588143078971630715564 +sub:7719318511816366427665580178076378029426275595533,163667549683108101581704958685911902179912256741218,0:-155948231171291735154039378507835524150485981145685 +sub:123382564431290774896664572552493052435404643704458759934,12531798191484951858836698658135874099473672299388553,0:123370032633099289944805735853834916561305170032159371381 +sub:942048756549299165967164928739420673047263758767141,3639275805983487223033248868875293658626128636190227,0:-2697227049434188057066083940135872985578864877423086 +sub:240418823794626925772533604032962688702579243574687,4907674204394917198714890794857507854118108024516422187,0:-4907433785571122571789118261253474891429405445272847500 +sub:3950213238876863129818663666502819327768719939127457701,29991402193339371342321385670768500228753395231039352972,0:-26041188954462508212502722004265680900984675291911895271 +sub:1920667868219534801099538208015399489683153418341349572065,-233412004414149707586851107620826952570732551540827551954,0:2154079872633684508686389315636226442253885969882177124019 +sub:7784321585128756839986661147453831080387260908002873,586237266875238457979621090825032494806800315405801,0:7198084318253518382007040056628798585580460592597072 +sub:-34225848774985487393407814198681047162140030645991253741,-789489361585689258214473176784928536166156096643657,0:-34225059285623901704149599725504262233603864489894610084 +sub:-944338971240124849797024756328867740674305651345965,649970029057878269623349411694378680589331156335769959,0:-650914368029118394473146436450707548330005461987115924 +sub:25816073494421415375915233416338690441492640884943818729,764159631162282034769988362928740167840568754650018844,0:25051913863259133341145245053409950273652072130293799885 +sub:7111381553325219432932289055091214481651627513743376,7385563406175559235314072692841151936136627185182905,0:-274181852850339802381783637749937454484999671439529 +sub:-438137611853268269308435226684643695607887735487389,5824616025576441892684517623276732904299681537303913,0:-6262753637429710161992952849961376599907569272791302 +sub:-9680790659167697968786181797074343179561171865505840566,-932899327759500157755319258322165056527752927868968726,0:-8747891331408197811030862538752178123033418937636871840 +sub:567793364811051880825781313748966696400236576537363041402,-976578291468928773578542746545826341079985184892523837,0:568769943102520809599359856495512522741316561722255565239 +sub:38007779187090670273244552314378701844162920433585869254,7187767815567041059760334263355184283280579165883650238,0:30820011371523629213484218051023517560882341267702219016 +sub:9014053603553462724377168305482782158101121369010869473906,755601637469656651454003843855153366578358802242924461,0:9013298001915993067725714301638927004734543010208626549445 + +# Small integer subtraction tests + +subv:3358604991,36411,0:3358568580 +subv:674222429,18986,0:674203443 +subv:-3,-29805,=1:29802 +subv:3,-61063,=1:61066 +subv:2717723,-25258,=1:2742981 +subv:394,-40508,=2:40902 +subv:4744781967,21435,0:4744760532 +subv:-14,50287,0:-50301 +subv:2197,3582,=2:-1385 +subv:-5296,38162,=2:-43458 +subv:-258774,57544,=2:-316318 +subv:7417476246,-58958,=2:7417535204 +subv:6714936,-40949,0:6755885 +subv:15862,-58672,0:74534 +subv:958081,21046,0:937035 +subv:82515,-11287,0:93802 +subv:72715,-25449,0:98164 +subv:-8346662975566,52150,0:-8346663027716 +subv:96216,-33648,=2:129864 +subv:71597071124556,40786,0:71597071083770 +subv:2795133710510,-24996,=1:2795133735506 +subv:8501300888546,1685,0:8501300886861 +subv:3877092429,45143,0:3877047286 +subv:-9123902,27698,0:-9151600 +subv:-71914098152,-49684,0:-71914048468 +subv:-5633175963555389,-13681,0:-5633175963541708 +subv:-68774492,24946,0:-68799438 +subv:2837978518,2447,=1:2837976071 +subv:9527903026793981,34045,=2:9527903026759936 +subv:-719766995836501,-14683,=1:-719766995821818 +subv:6826892934542,-9599,0:6826892944141 +subv:474765520,-36545,=2:474802065 +subv:137980222,12896,0:137967326 +subv:4124108674,61743,0:4124046931 +subv:-4977334202151,16161,0:-4977334218312 +subv:-6764356933,33130,=1:-6764390063 +subv:6639990082377605303,63220,0:6639990082377542083 +subv:68384248282,-28652,0:68384276934 +subv:-64782488650,-31866,=2:-64782456784 +subv:84126983615,63328,0:84126920287 +subv:280281352217,19756,=1:280281332461 +subv:-337730569530652702,55596,0:-337730569530708298 +subv:750462053456012,-18056,=1:750462053474068 +subv:-859984251764611,60341,0:-859984251824952 +subv:781147832162694072159,10186,0:781147832162694061973 +subv:414707731902540,13874,0:414707731888666 +subv:4749293013793395,-27594,0:4749293013820989 +subv:-476780935041195291,-51859,0:-476780935041143432 +subv:-3619074244886709,38416,=1:-3619074244925125 +subv:97855199057493,40752,0:97855199016741 +subv:777675086535345464853,9892,=2:777675086535345454961 +subv:3103441257588144,4992,0:3103441257583152 +subv:136564148041720,53068,=2:136564147988652 +subv:-4664978338218772692212,46644,0:-4664978338218772738856 +subv:235299291342838779459,27155,=1:235299291342838752304 +subv:45286262426870,28782,0:45286262398088 +subv:422289955984703063,27236,=2:422289955984675827 +subv:-6379926829937406097,-63773,0:-6379926829937342324 +subv:830836702855178852980658,-61406,=1:830836702855178853042064 +subv:4000074483936047411,59077,=2:4000074483935988334 +subv:1622930723651719839167208,63514,0:1622930723651719839103694 +subv:532951482400205192926144,57956,0:532951482400205192868188 +subv:148980429628794512840,63138,=2:148980429628794449702 +subv:-9890648040727702186064,-46766,=1:-9890648040727702139298 +subv:-10934480308082214085686,63224,=2:-10934480308082214148910 +subv:355809482274653919711872,32446,0:355809482274653919679426 +subv:-33926193961684655624,11389,=2:-33926193961684667013 +subv:-7186493575578045620,15528,=1:-7186493575578061148 +subv:34706765155128499193360248,83,=1:34706765155128499193360165 +subv:4328479538590740673745630,14623,0:4328479538590740673731007 +subv:-963713498430054741223932789,30239,0:-963713498430054741223963028 +subv:-831264221344401371,39516,0:-831264221344440887 +subv:318721481318817753735405,52833,0:318721481318817753682572 +subv:-62693787119478234447,27553,=1:-62693787119478262000 +subv:-7016655669525046977522194886,32638,=2:-7016655669525046977522227524 +subv:608134301020199755515,29066,0:608134301020199726449 Index: contrib/isl/imath/tests/test.bc =================================================================== --- /dev/null +++ contrib/isl/imath/tests/test.bc @@ -0,0 +1,155 @@ +/* e(a, b, m) := a^b (mod m) */ +define e(a, b, m) { + auto s, sb; + + sb = obase; obase = 16; + s = 1; + while(b != 0) { + if((b % 2) == 1) { + s = (s * a) % m; + } + b /= 2; + a = (a * a) % m; + } + obase = sb; + return (s); +} + +/* g(a, b) := (a, b) */ +define g(a, b) { + auto r; + + while(b != 0) { + r = a % b; + a = b; + b = r; + } + if(a < 0) { + return(-a); + } else { + return(a); + } +} + +define a(x) { + if(x < 0) { + return (-x); + } else { + return (x); + } +} + +xgu = 0; xgv = 0; +define x(a, b) { + auto u, v, x, y, t, r; + + if(a(b) > a(a)) { + t = b; b = a; a = t; r = 1; + } else { + r = 0; + } + + u = 1; v = 0; + x = 0; y = 1; + + while(b != 0) { + t = a / b; + + a = a - (t * b); + v = v - (t * y); + u = u - (t * x); + + if(a(a) < a(b)) { + t = a; a = b; b = t; + t = v; v = y; y = t; + t = u; u = x; x = t; + } + } + + if(r) { + xgu = v; xgv = u; + } else { + xgu = u; xgv = v; + } + + if(a < 0) { + return (-a); + } else { + return (a); + } +} + +define i(a, m) { + auto c; + + c = x(a, m); + if(c != 1) + return(0); + + return ((xgu + m) % m); +} + +scale = 0 +rand_modulus = 2860385147 +rand_base = 129 +rand_seed = 10342799 + +define srand(s) { + rand_seed = s; +} + +define rand(n) { + auto r; + + r = (rand_seed * rand_base) % rand_modulus; + rand_seed = r; + return(r % n); +} + +define rand_digits(k) { + auto s; + + s = 0; + while(k > 0) { + s = (s * 10) + rand(10); + k = k - 1; + } + + return(s); +} + +define rval(ndigits, probneg) { + auto x; + x = rand_digits(ndigits); + if(probneg > 0 && rand(100) < probneg) + x = x * -1; + return(x); +} + +for(i = 2; i < 100; i += 4) { + value = rand_digits(i); + obase = 256; + print "readuns:", value; + obase = 10; + print ":", value, "\n" +} + +/* +for(i = 2; i < 100; i += 4) { + for(j = 0; j < 2; ++j) { + ndig = rand(7); + base = rval(ndig, 20); + expt = rand_digits(i); + mod = rand_digits(i); + + result = e(base, expt, mod); + if(result < 0) { + result = result + mod; + } + print "emodbv:", base, ",", expt, ",", mod, ",0:", result, "\n"; + print "emodbv:", base, ",", expt, ",", mod, ",=2:", result, "\n"; + print "emodbv:", base, ",", expt, ",", mod, ",=3:", result, "\n"; + } +} +*/ +halt Index: contrib/isl/imath/tests/test.sh =================================================================== --- /dev/null +++ contrib/isl/imath/tests/test.sh @@ -0,0 +1,77 @@ +#!/bin/sh +## +## Name: test.sh +## Purpose: Run test suites for IMath library. +## Author: M. J. Fromberger +## + +if [ ! -f ../imtest ] ; then + echo "I can't find the imath test driver 'imtest', did you build it?" + echo "I can't proceed with the unit tests until you do so, sorry." + exit 1 +fi + +echo "-- Running all available unit tests" +../imtest *.t | grep -v OK + +echo "" +echo "-- Running test to compute 1024 decimal digits of pi" +if [ ! -f ../pi ] ; then + echo "I can't find the pi computing program, did you build it?" + echo "I can't proceed with the pi test until you do so, sorry." + exit 1 +fi + +tempfile="/tmp/pi.1024.$$" + +../pi 1024 | tr -d '\r\n' > ${tempfile} +if cmp -s ${tempfile} ./pi1024.txt ; then + echo " PASSED 1024 digits" +else + echo " FAILED" + echo "Obtained:" + cat ${tempfile} + echo "Expected:" + cat ./pi1024.txt +fi +rm -f ${tempfile} + +tempfile="/tmp/pi.1698.$$" + +echo "-- Running test to compute 1698 hexadecimal digits of pi" + +../pi 1698 16 | tr -d '\r\n' > ${tempfile} +if cmp -s ${tempfile} ./pi1698-16.txt ; then + echo " PASSED 1698 digits" +else + echo " FAILED" + echo "Obtained:" + cat ${tempfile} + echo "Expected:" + cat ./pi1698-16.txt +fi +rm -f ${tempfile} + +tempfile="/tmp/pi.1500.$$" + +echo "-- Running test to compute 1500 decimal digits of pi" + +../pi 1500 10 | tr -d '\r\n' > ${tempfile} +if cmp -s ${tempfile} ./pi1500-10.txt ; then + echo " PASSED 1500 digits" +else + echo " FAILED" + echo "Obtained:" + cat ${tempfile} + echo "Expected:" + cat ./pi1500-10.txt +fi +rm -f ${tempfile} + +echo "-- Running regression tests" + +for bug in bug-swap ; do + ../${bug} +done + +exit 0 Index: contrib/isl/imath_wrap/gmp_compat.h =================================================================== --- /dev/null +++ contrib/isl/imath_wrap/gmp_compat.h @@ -0,0 +1,2 @@ +#include "wrap.h" +#include "../imath/gmp_compat.h" Index: contrib/isl/imath_wrap/gmp_compat.c =================================================================== --- /dev/null +++ contrib/isl/imath_wrap/gmp_compat.c @@ -0,0 +1,2 @@ +#include "wrap.h" +#include "../imath/gmp_compat.c" Index: contrib/isl/imath_wrap/imath.h =================================================================== --- /dev/null +++ contrib/isl/imath_wrap/imath.h @@ -0,0 +1,2 @@ +#include "wrap.h" +#include "../imath/imath.h" Index: contrib/isl/imath_wrap/imath.c =================================================================== --- /dev/null +++ contrib/isl/imath_wrap/imath.c @@ -0,0 +1,2 @@ +#include "wrap.h" +#include "../imath/imath.c" Index: contrib/isl/imath_wrap/imrat.h =================================================================== --- /dev/null +++ contrib/isl/imath_wrap/imrat.h @@ -0,0 +1,2 @@ +#include "wrap.h" +#include "../imath/imrat.h" Index: contrib/isl/imath_wrap/imrat.c =================================================================== --- /dev/null +++ contrib/isl/imath_wrap/imrat.c @@ -0,0 +1,2 @@ +#include "wrap.h" +#include "../imath/imrat.c" Index: contrib/isl/imath_wrap/wrap.h =================================================================== --- /dev/null +++ contrib/isl/imath_wrap/wrap.h @@ -0,0 +1,171 @@ +#ifndef ISL_IMATH_WRAP +#define ISL_IMATH_WRAP + +#define MP_BADARG ISL_MP_BADARG +#define MP_FALSE ISL_MP_FALSE +#define MP_MEMORY ISL_MP_MEMORY +#define MP_MINERR ISL_MP_MINERR +#define MP_NEG ISL_MP_NEG +#define MP_OK ISL_MP_OK +#define MP_RANGE ISL_MP_RANGE +#define MP_TRUE ISL_MP_TRUE +#define MP_TRUNC ISL_MP_TRUNC +#define MP_UNDEF ISL_MP_UNDEF +#define MP_ZPOS ISL_MP_ZPOS + +#define impq_canonicalize isl_impq_canonicalize +#define impq_clear isl_impq_clear +#define impq_cmp isl_impq_cmp +#define impq_denref isl_impq_denref +#define impq_get_str isl_impq_get_str +#define impq_init isl_impq_init +#define impq_mul isl_impq_mul +#define impq_numref isl_impq_numref +#define impq_set isl_impq_set +#define impq_set_str isl_impq_set_str +#define impq_set_ui isl_impq_set_ui +#define impq_sgn isl_impq_sgn +#define impz_abs isl_impz_abs +#define impz_add isl_impz_add +#define impz_addmul isl_impz_addmul +#define impz_add_ui isl_impz_add_ui +#define impz_cdiv_q isl_impz_cdiv_q +#define impz_clear isl_impz_clear +#define impz_cmp isl_impz_cmp +#define impz_cmpabs isl_impz_cmpabs +#define impz_cmp_si isl_impz_cmp_si +#define impz_divexact isl_impz_divexact +#define impz_divexact_ui isl_impz_divexact_ui +#define impz_divisible_p isl_impz_divisible_p +#define impz_export isl_impz_export +#define impz_fdiv_q isl_impz_fdiv_q +#define impz_fdiv_r isl_impz_fdiv_r +#define impz_gcd isl_impz_gcd +#define impz_get_si isl_impz_get_si +#define impz_get_str isl_impz_get_str +#define impz_get_ui isl_impz_get_ui +#define impz_import isl_impz_import +#define impz_init isl_impz_init +#define impz_lcm isl_impz_lcm +#define impz_mul isl_impz_mul +#define impz_mul_2exp isl_impz_mul_2exp +#define impz_mul_ui isl_impz_mul_ui +#define impz_neg isl_impz_neg +#define impz_pow_ui isl_impz_pow_ui +#define impz_set isl_impz_set +#define impz_set_si isl_impz_set_si +#define impz_set_str isl_impz_set_str +#define impz_set_ui isl_impz_set_ui +#define impz_sgn isl_impz_sgn +#define impz_sizeinbase isl_impz_sizeinbase +#define impz_sub isl_impz_sub +#define impz_submul isl_impz_submul +#define impz_sub_ui isl_impz_sub_ui +#define impz_swap isl_impz_swap +#define impz_tdiv_q isl_impz_tdiv_q +#define mp_error_string isl_mp_error_string +#define mp_int_abs isl_mp_int_abs +#define mp_int_add isl_mp_int_add +#define mp_int_add_value isl_mp_int_add_value +#define mp_int_alloc isl_mp_int_alloc +#define mp_int_binary_len isl_mp_int_binary_len +#define mp_int_clear isl_mp_int_clear +#define mp_int_compare isl_mp_int_compare +#define mp_int_compare_unsigned isl_mp_int_compare_unsigned +#define mp_int_compare_uvalue isl_mp_int_compare_uvalue +#define mp_int_compare_value isl_mp_int_compare_value +#define mp_int_compare_zero isl_mp_int_compare_zero +#define mp_int_copy isl_mp_int_copy +#define mp_int_count_bits isl_mp_int_count_bits +#define mp_int_div isl_mp_int_div +#define mp_int_divisible_value isl_mp_int_divisible_value +#define mp_int_div_pow2 isl_mp_int_div_pow2 +#define mp_int_div_value isl_mp_int_div_value +#define mp_int_egcd isl_mp_int_egcd +#define mp_int_expt isl_mp_int_expt +#define mp_int_expt_full isl_mp_int_expt_full +#define mp_int_exptmod isl_mp_int_exptmod +#define mp_int_exptmod_bvalue isl_mp_int_exptmod_bvalue +#define mp_int_exptmod_evalue isl_mp_int_exptmod_evalue +#define mp_int_exptmod_known isl_mp_int_exptmod_known +#define mp_int_expt_value isl_mp_int_expt_value +#define mp_int_free isl_mp_int_free +#define mp_int_gcd isl_mp_int_gcd +#define mp_int_init isl_mp_int_init +#define mp_int_init_copy isl_mp_int_init_copy +#define mp_int_init_size isl_mp_int_init_size +#define mp_int_init_uvalue isl_mp_int_init_uvalue +#define mp_int_init_value isl_mp_int_init_value +#define mp_int_invmod isl_mp_int_invmod +#define mp_int_is_pow2 isl_mp_int_is_pow2 +#define mp_int_lcm isl_mp_int_lcm +#define mp_int_mod isl_mp_int_mod +#define mp_int_mul isl_mp_int_mul +#define mp_int_mul_pow2 isl_mp_int_mul_pow2 +#define mp_int_mul_value isl_mp_int_mul_value +#define mp_int_neg isl_mp_int_neg +#define mp_int_read_binary isl_mp_int_read_binary +#define mp_int_read_cstring isl_mp_int_read_cstring +#define mp_int_read_string isl_mp_int_read_string +#define mp_int_read_unsigned isl_mp_int_read_unsigned +#define mp_int_redux_const isl_mp_int_redux_const +#define mp_int_root isl_mp_int_root +#define mp_int_set_uvalue isl_mp_int_set_uvalue +#define mp_int_set_value isl_mp_int_set_value +#define mp_int_sqr isl_mp_int_sqr +#define mp_int_string_len isl_mp_int_string_len +#define mp_int_sub isl_mp_int_sub +#define mp_int_sub_value isl_mp_int_sub_value +#define mp_int_swap isl_mp_int_swap +#define mp_int_to_binary isl_mp_int_to_binary +#define mp_int_to_int isl_mp_int_to_int +#define mp_int_to_string isl_mp_int_to_string +#define mp_int_to_uint isl_mp_int_to_uint +#define mp_int_to_unsigned isl_mp_int_to_unsigned +#define mp_int_unsigned_len isl_mp_int_unsigned_len +#define mp_int_zero isl_mp_int_zero +#define mp_rat_abs isl_mp_rat_abs +#define mp_rat_add isl_mp_rat_add +#define mp_rat_add_int isl_mp_rat_add_int +#define mp_rat_alloc isl_mp_rat_alloc +#define mp_rat_clear isl_mp_rat_clear +#define mp_rat_compare isl_mp_rat_compare +#define mp_rat_compare_unsigned isl_mp_rat_compare_unsigned +#define mp_rat_compare_value isl_mp_rat_compare_value +#define mp_rat_compare_zero isl_mp_rat_compare_zero +#define mp_rat_copy isl_mp_rat_copy +#define mp_rat_decimal_len isl_mp_rat_decimal_len +#define mp_rat_denom isl_mp_rat_denom +#define mp_rat_denom_ref isl_mp_rat_denom_ref +#define mp_rat_div isl_mp_rat_div +#define mp_rat_div_int isl_mp_rat_div_int +#define mp_rat_expt isl_mp_rat_expt +#define mp_rat_free isl_mp_rat_free +#define mp_rat_init isl_mp_rat_init +#define mp_rat_init_copy isl_mp_rat_init_copy +#define mp_rat_init_size isl_mp_rat_init_size +#define mp_rat_is_integer isl_mp_rat_is_integer +#define mp_rat_mul isl_mp_rat_mul +#define mp_rat_mul_int isl_mp_rat_mul_int +#define mp_rat_neg isl_mp_rat_neg +#define mp_rat_numer isl_mp_rat_numer +#define mp_rat_numer_ref isl_mp_rat_numer_ref +#define mp_rat_read_cdecimal isl_mp_rat_read_cdecimal +#define mp_rat_read_cstring isl_mp_rat_read_cstring +#define mp_rat_read_decimal isl_mp_rat_read_decimal +#define mp_rat_read_string isl_mp_rat_read_string +#define mp_rat_read_ustring isl_mp_rat_read_ustring +#define mp_rat_recip isl_mp_rat_recip +#define mp_rat_reduce isl_mp_rat_reduce +#define mp_rat_set_uvalue isl_mp_rat_set_uvalue +#define mp_rat_set_value isl_mp_rat_set_value +#define mp_rat_sign isl_mp_rat_sign +#define mp_rat_string_len isl_mp_rat_string_len +#define mp_rat_sub isl_mp_rat_sub +#define mp_rat_sub_int isl_mp_rat_sub_int +#define mp_rat_to_decimal isl_mp_rat_to_decimal +#define mp_rat_to_ints isl_mp_rat_to_ints +#define mp_rat_to_string isl_mp_rat_to_string +#define mp_rat_zero isl_mp_rat_zero + +#endif Index: contrib/isl/include/isl/aff.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/aff.h @@ -0,0 +1,1042 @@ +#ifndef ISL_AFF_H +#define ISL_AFF_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_aff *isl_aff_zero_on_domain(__isl_take isl_local_space *ls); +__isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls, + __isl_take isl_val *val); +__isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos); +__isl_give isl_aff *isl_aff_nan_on_domain(__isl_take isl_local_space *ls); + +__isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff); +__isl_null isl_aff *isl_aff_free(__isl_take isl_aff *aff); + +isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff); +uint32_t isl_aff_get_hash(__isl_keep isl_aff *aff); + +int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type); +isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_space *isl_aff_get_domain_space(__isl_keep isl_aff *aff); +__isl_give isl_space *isl_aff_get_space(__isl_keep isl_aff *aff); +__isl_give isl_local_space *isl_aff_get_domain_local_space( + __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); +__isl_give isl_val *isl_aff_get_constant_val(__isl_keep isl_aff *aff); +__isl_give isl_val *isl_aff_get_coefficient_val(__isl_keep isl_aff *aff, + enum isl_dim_type type, int pos); +int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff, + enum isl_dim_type type, int pos); +__isl_give isl_val *isl_aff_get_denominator_val(__isl_keep isl_aff *aff); +__isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v); +__isl_give isl_aff *isl_aff_set_constant_val(__isl_take isl_aff *aff, + __isl_take isl_val *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_coefficient_val(__isl_take isl_aff *aff, + enum isl_dim_type type, int pos, __isl_take isl_val *v); +__isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v); +__isl_give isl_aff *isl_aff_add_constant_val(__isl_take isl_aff *aff, + __isl_take isl_val *v); +__isl_give isl_aff *isl_aff_add_constant_num_si(__isl_take isl_aff *aff, 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_aff *isl_aff_add_coefficient_val(__isl_take isl_aff *aff, + enum isl_dim_type type, int pos, __isl_take isl_val *v); + +isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff); + +__isl_give isl_aff *isl_aff_set_tuple_id(__isl_take isl_aff *aff, + enum isl_dim_type type, __isl_take isl_id *id); +__isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned pos, const char *s); +__isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); + +int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type, + const char *name); + +isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1, + __isl_keep isl_aff *aff2); +isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff); +isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff); + +__isl_give isl_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos); + +__isl_export +__isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff); +__isl_export +__isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff); +__isl_export +__isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff); +__isl_overload +__isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff, + __isl_take isl_val *mod); + +__isl_export +__isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + +__isl_overload +__isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff, + __isl_take isl_val *v); +__isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f); +__isl_overload +__isl_give isl_aff *isl_aff_scale_down_val(__isl_take isl_aff *aff, + __isl_take isl_val *v); + +__isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_aff *isl_aff_add_dims(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned n); +__isl_give isl_aff *isl_aff_move_dims(__isl_take isl_aff *aff, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); +__isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff); + +__isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff, + __isl_take isl_space *model); + +__isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff, + __isl_take isl_set *context); +__isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff, + __isl_take isl_set *context); + +__isl_give isl_aff *isl_aff_pullback_aff(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_overload +__isl_give isl_aff *isl_aff_pullback_multi_aff(__isl_take isl_aff *aff, + __isl_take isl_multi_aff *ma); + +__isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff); +__isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff); + +__isl_give isl_basic_set *isl_aff_eq_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_set *isl_aff_eq_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_set *isl_aff_ne_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_give isl_basic_set *isl_aff_le_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_set *isl_aff_le_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_give isl_basic_set *isl_aff_lt_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_set *isl_aff_lt_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_give isl_basic_set *isl_aff_ge_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_set *isl_aff_ge_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_give isl_basic_set *isl_aff_gt_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +__isl_export +__isl_give isl_set *isl_aff_gt_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + +__isl_constructor +__isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str); +__isl_give char *isl_aff_to_str(__isl_keep 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); + +isl_ctx *isl_pw_aff_get_ctx(__isl_keep isl_pw_aff *pwaff); +uint32_t isl_pw_aff_get_hash(__isl_keep isl_pw_aff *pa); +__isl_give isl_space *isl_pw_aff_get_domain_space(__isl_keep isl_pw_aff *pwaff); +__isl_give isl_space *isl_pw_aff_get_space(__isl_keep isl_pw_aff *pwaff); + +__isl_constructor +__isl_give isl_pw_aff *isl_pw_aff_from_aff(__isl_take isl_aff *aff); +__isl_give isl_pw_aff *isl_pw_aff_empty(__isl_take isl_space *dim); +__isl_give isl_pw_aff *isl_pw_aff_alloc(__isl_take isl_set *set, + __isl_take isl_aff *aff); +__isl_give isl_pw_aff *isl_pw_aff_zero_on_domain( + __isl_take isl_local_space *ls); +__isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos); +__isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls); +__isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain, + __isl_take isl_val *v); + +__isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set); + +const char *isl_pw_aff_get_dim_name(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type, unsigned pos); +isl_bool isl_pw_aff_has_dim_id(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type, unsigned pos); +__isl_give isl_id *isl_pw_aff_get_dim_id(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type, unsigned pos); +__isl_give isl_pw_aff *isl_pw_aff_set_dim_id(__isl_take isl_pw_aff *pma, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); + +int isl_pw_aff_find_dim_by_name(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type, const char *name); + +isl_bool isl_pw_aff_is_empty(__isl_keep isl_pw_aff *pwaff); +isl_bool isl_pw_aff_involves_nan(__isl_keep isl_pw_aff *pa); +int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1, + __isl_keep isl_pw_aff *pa2); +isl_bool isl_pw_aff_plain_is_equal(__isl_keep isl_pw_aff *pwaff1, + __isl_keep isl_pw_aff *pwaff2); +isl_bool isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1, + __isl_keep isl_pw_aff *pa2); + +__isl_give isl_pw_aff *isl_pw_aff_union_min(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_give isl_pw_aff *isl_pw_aff_union_max(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_union_add(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + +__isl_give isl_pw_aff *isl_pw_aff_copy(__isl_keep isl_pw_aff *pwaff); +__isl_null isl_pw_aff *isl_pw_aff_free(__isl_take isl_pw_aff *pwaff); + +unsigned isl_pw_aff_dim(__isl_keep isl_pw_aff *pwaff, enum isl_dim_type type); +isl_bool isl_pw_aff_involves_dims(__isl_keep isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned first, unsigned n); + +isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff); + +__isl_give isl_pw_aff *isl_pw_aff_project_domain_on_params( + __isl_take isl_pw_aff *pa); + +__isl_give isl_pw_aff *isl_pw_aff_align_params(__isl_take isl_pw_aff *pwaff, + __isl_take isl_space *model); + +isl_bool isl_pw_aff_has_tuple_id(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type); +__isl_give isl_id *isl_pw_aff_get_tuple_id(__isl_keep isl_pw_aff *pa, + enum isl_dim_type type); +__isl_give isl_pw_aff *isl_pw_aff_set_tuple_id(__isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, __isl_take isl_id *id); +__isl_give isl_pw_aff *isl_pw_aff_reset_tuple_id(__isl_take isl_pw_aff *pa, + enum isl_dim_type type); +__isl_give isl_pw_aff *isl_pw_aff_reset_user(__isl_take isl_pw_aff *pa); + +__isl_give isl_set *isl_pw_aff_params(__isl_take isl_pw_aff *pwa); +__isl_give isl_set *isl_pw_aff_domain(__isl_take isl_pw_aff *pwaff); +__isl_give isl_pw_aff *isl_pw_aff_from_range(__isl_take isl_pw_aff *pwa); + +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_sub(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_neg(__isl_take isl_pw_aff *pwaff); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff); +__isl_overload +__isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa, + __isl_take isl_val *mod); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_tdiv_q(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + +__isl_give isl_pw_aff *isl_pw_aff_intersect_params(__isl_take isl_pw_aff *pa, + __isl_take isl_set *set); +__isl_give isl_pw_aff *isl_pw_aff_intersect_domain(__isl_take isl_pw_aff *pa, + __isl_take isl_set *set); +__isl_give isl_pw_aff *isl_pw_aff_subtract_domain(__isl_take isl_pw_aff *pa, + __isl_take isl_set *set); + +__isl_export +__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond, + __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false); + +__isl_overload +__isl_give isl_pw_aff *isl_pw_aff_scale_val(__isl_take isl_pw_aff *pa, + __isl_take isl_val *v); +__isl_overload +__isl_give isl_pw_aff *isl_pw_aff_scale_down_val(__isl_take isl_pw_aff *pa, + __isl_take isl_val *f); + +__isl_give isl_pw_aff *isl_pw_aff_insert_dims(__isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_pw_aff *isl_pw_aff_add_dims(__isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned n); +__isl_give isl_pw_aff *isl_pw_aff_move_dims(__isl_take isl_pw_aff *pa, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); +__isl_give isl_pw_aff *isl_pw_aff_drop_dims(__isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_pw_aff *isl_pw_aff_coalesce(__isl_take isl_pw_aff *pwqp); +__isl_give isl_pw_aff *isl_pw_aff_gist(__isl_take isl_pw_aff *pwaff, + __isl_take isl_set *context); +__isl_give isl_pw_aff *isl_pw_aff_gist_params(__isl_take isl_pw_aff *pwaff, + __isl_take isl_set *context); + +__isl_overload +__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_aff( + __isl_take isl_pw_aff *pa, __isl_take isl_multi_aff *ma); +__isl_overload +__isl_give isl_pw_aff *isl_pw_aff_pullback_pw_multi_aff( + __isl_take isl_pw_aff *pa, __isl_take isl_pw_multi_aff *pma); +__isl_overload +__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff( + __isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa); + +int isl_pw_aff_n_piece(__isl_keep isl_pw_aff *pwaff); +isl_stat isl_pw_aff_foreach_piece(__isl_keep isl_pw_aff *pwaff, + isl_stat (*fn)(__isl_take isl_set *set, __isl_take isl_aff *aff, + void *user), void *user); + +__isl_give isl_set *isl_set_from_pw_aff(__isl_take isl_pw_aff *pwaff); +__isl_give isl_map *isl_map_from_pw_aff(__isl_take isl_pw_aff *pwaff); + +__isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa); +__isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff); +__isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff); +__isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff); + +__isl_export +__isl_give isl_set *isl_pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_set *isl_pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_set *isl_pw_aff_le_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); +__isl_export +__isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2); + +__isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); +__isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); +__isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + +__isl_constructor +__isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str); +__isl_give char *isl_pw_aff_to_str(__isl_keep isl_pw_aff *pa); +__isl_give isl_printer *isl_printer_print_pw_aff(__isl_take isl_printer *p, + __isl_keep isl_pw_aff *pwaff); +void isl_pw_aff_dump(__isl_keep isl_pw_aff *pwaff); + +__isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list); +__isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list); + +__isl_give isl_set *isl_pw_aff_list_eq_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); +__isl_give isl_set *isl_pw_aff_list_ne_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); +__isl_give isl_set *isl_pw_aff_list_le_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); +__isl_give isl_set *isl_pw_aff_list_lt_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); +__isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); +__isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2); + +ISL_DECLARE_MULTI(aff) +ISL_DECLARE_MULTI_CMP(aff) +ISL_DECLARE_MULTI_NEG(aff) +ISL_DECLARE_MULTI_DIMS(aff) +ISL_DECLARE_MULTI_WITH_DOMAIN(aff) + +__isl_constructor +__isl_give isl_multi_aff *isl_multi_aff_from_aff(__isl_take isl_aff *aff); +__isl_give isl_multi_aff *isl_multi_aff_identity(__isl_take isl_space *space); +__isl_give isl_multi_aff *isl_multi_aff_domain_map(__isl_take isl_space *space); +__isl_give isl_multi_aff *isl_multi_aff_range_map(__isl_take isl_space *space); +__isl_give isl_multi_aff *isl_multi_aff_project_out_map( + __isl_take isl_space *space, enum isl_dim_type type, + unsigned first, unsigned n); + +__isl_give isl_multi_aff *isl_multi_aff_multi_val_on_space( + __isl_take isl_space *space, __isl_take isl_multi_val *mv); + +__isl_give isl_multi_aff *isl_multi_aff_floor(__isl_take isl_multi_aff *ma); + +__isl_give isl_multi_aff *isl_multi_aff_gist_params( + __isl_take isl_multi_aff *maff, __isl_take isl_set *context); +__isl_give isl_multi_aff *isl_multi_aff_gist(__isl_take isl_multi_aff *maff, + __isl_take isl_set *context); + +__isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff, + __isl_give isl_local_space **ls); + +__isl_overload +__isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff( + __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2); + +__isl_give isl_multi_aff *isl_multi_aff_move_dims(__isl_take isl_multi_aff *ma, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); + +__isl_give isl_set *isl_multi_aff_lex_lt_set(__isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); +__isl_give isl_set *isl_multi_aff_lex_le_set(__isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); +__isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); +__isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2); + +__isl_give char *isl_multi_aff_to_str(__isl_keep isl_multi_aff *ma); +__isl_give isl_printer *isl_printer_print_multi_aff(__isl_take isl_printer *p, + __isl_keep isl_multi_aff *maff); + +__isl_constructor +__isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx, + const char *str); +void isl_multi_aff_dump(__isl_keep isl_multi_aff *maff); + +ISL_DECLARE_MULTI(pw_aff) +ISL_DECLARE_MULTI_NEG(pw_aff) +ISL_DECLARE_MULTI_DIMS(pw_aff) +ISL_DECLARE_MULTI_WITH_DOMAIN(pw_aff) + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(__isl_take isl_space *space); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity( + __isl_take isl_space *space); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map( + __isl_take isl_space *space); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map( + __isl_take isl_space *space, enum isl_dim_type type, + unsigned first, unsigned n); +__isl_constructor +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff( + __isl_take isl_multi_aff *ma); +__isl_constructor +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff( + __isl_take isl_pw_aff *pa); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_alloc(__isl_take isl_set *set, + __isl_take isl_multi_aff *maff); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_copy( + __isl_keep isl_pw_multi_aff *pma); +__isl_null isl_pw_multi_aff *isl_pw_multi_aff_free( + __isl_take isl_pw_multi_aff *pma); + +unsigned isl_pw_multi_aff_dim(__isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); +__isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff( + __isl_keep isl_pw_multi_aff *pma, int pos); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff( + __isl_take isl_pw_multi_aff *pma, unsigned pos, + __isl_take isl_pw_aff *pa); + +isl_ctx *isl_pw_multi_aff_get_ctx(__isl_keep isl_pw_multi_aff *pma); +__isl_give isl_space *isl_pw_multi_aff_get_domain_space( + __isl_keep isl_pw_multi_aff *pma); +__isl_give isl_space *isl_pw_multi_aff_get_space( + __isl_keep isl_pw_multi_aff *pma); +isl_bool isl_pw_multi_aff_has_tuple_name(__isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); +const char *isl_pw_multi_aff_get_tuple_name(__isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); +__isl_give isl_id *isl_pw_multi_aff_get_tuple_id( + __isl_keep isl_pw_multi_aff *pma, enum isl_dim_type type); +isl_bool isl_pw_multi_aff_has_tuple_id(__isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_tuple_id( + __isl_take isl_pw_multi_aff *pma, + enum isl_dim_type type, __isl_take isl_id *id); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_tuple_id( + __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_user( + __isl_take isl_pw_multi_aff *pma); + +int isl_pw_multi_aff_find_dim_by_name(__isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type, const char *name); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_drop_dims( + __isl_take isl_pw_multi_aff *pma, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_set *isl_pw_multi_aff_domain(__isl_take isl_pw_multi_aff *pma); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_empty(__isl_take isl_space *space); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain( + __isl_take isl_set *set); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_multi_val_on_domain( + __isl_take isl_set *domain, __isl_take isl_multi_val *mv); + +const char *isl_pw_multi_aff_get_dim_name(__isl_keep isl_pw_multi_aff *pma, + enum isl_dim_type type, unsigned pos); +__isl_give isl_id *isl_pw_multi_aff_get_dim_id( + __isl_keep isl_pw_multi_aff *pma, enum isl_dim_type type, + unsigned pos); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_dim_id( + __isl_take isl_pw_multi_aff *pma, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); + +isl_bool isl_pw_multi_aff_involves_nan(__isl_keep isl_pw_multi_aff *pma); +isl_bool isl_pw_multi_aff_plain_is_equal(__isl_keep isl_pw_multi_aff *pma1, + __isl_keep isl_pw_multi_aff *pma2); +isl_bool isl_pw_multi_aff_is_equal(__isl_keep isl_pw_multi_aff *pma1, + __isl_keep isl_pw_multi_aff *pma2); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_fix_si( + __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, + unsigned pos, int value); + +__isl_export +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_neg( + __isl_take isl_pw_multi_aff *pma); + +__isl_export +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_add( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_val( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_val *v); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_val( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_val *v); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2); + +__isl_give isl_multi_aff *isl_multi_aff_flatten_domain( + __isl_take isl_multi_aff *ma); + +__isl_export +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); +__isl_export +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_flat_range_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); +__isl_export +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_params( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_domain( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_subtract_domain( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_domain_on_params( + __isl_take isl_pw_multi_aff *pma); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_align_params( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_space *model); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_coalesce( + __isl_take isl_pw_multi_aff *pma); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist_params( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set); + +__isl_overload +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_pullback_multi_aff( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_aff *ma); +__isl_overload +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_pullback_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); + +int isl_pw_multi_aff_n_piece(__isl_keep isl_pw_multi_aff *pma); +isl_stat isl_pw_multi_aff_foreach_piece(__isl_keep isl_pw_multi_aff *pma, + isl_stat (*fn)(__isl_take isl_set *set, __isl_take isl_multi_aff *maff, + void *user), void *user); + +__isl_give isl_map *isl_map_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma); +__isl_give isl_set *isl_set_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma); + +__isl_give char *isl_pw_multi_aff_to_str(__isl_keep isl_pw_multi_aff *pma); +__isl_give isl_printer *isl_printer_print_pw_multi_aff(__isl_take isl_printer *p, + __isl_keep isl_pw_multi_aff *pma); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map); + +__isl_constructor +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx, + const char *str); +void isl_pw_multi_aff_dump(__isl_keep isl_pw_multi_aff *pma); + + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_empty( + __isl_take isl_space *space); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff( + __isl_take isl_aff *aff); +__isl_constructor +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain( + __isl_take isl_union_set *uset); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_copy( + __isl_keep isl_union_pw_multi_aff *upma); +__isl_null isl_union_pw_multi_aff *isl_union_pw_multi_aff_free( + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_union_pw_multi_aff *isl_union_set_identity_union_pw_multi_aff( + __isl_take isl_union_set *uset); + +__isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff( + __isl_keep isl_union_pw_multi_aff *upma, int pos); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_add_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_pw_multi_aff *pma); + +isl_ctx *isl_union_pw_multi_aff_get_ctx( + __isl_keep isl_union_pw_multi_aff *upma); +__isl_give isl_space *isl_union_pw_multi_aff_get_space( + __isl_keep isl_union_pw_multi_aff *upma); + +unsigned isl_union_pw_multi_aff_dim(__isl_keep isl_union_pw_multi_aff *upma, + enum isl_dim_type type); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_set_dim_name( + __isl_take isl_union_pw_multi_aff *upma, + enum isl_dim_type type, unsigned pos, const char *s); + +int isl_union_pw_multi_aff_find_dim_by_name( + __isl_keep isl_union_pw_multi_aff *upma, enum isl_dim_type type, + const char *name); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_drop_dims( + __isl_take isl_union_pw_multi_aff *upma, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_reset_user( + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_coalesce( + __isl_take isl_union_pw_multi_aff *upma); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_gist_params( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_set *context); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_gist( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_union_set *context); + +__isl_overload +__isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_align_params( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *model); + +int isl_union_pw_multi_aff_n_pw_multi_aff( + __isl_keep isl_union_pw_multi_aff *upma); + +isl_stat isl_union_pw_multi_aff_foreach_pw_multi_aff( + __isl_keep isl_union_pw_multi_aff *upma, + isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user), + void *user); +__isl_give isl_pw_multi_aff *isl_union_pw_multi_aff_extract_pw_multi_aff( + __isl_keep isl_union_pw_multi_aff *upma, __isl_take isl_space *space); + +isl_bool isl_union_pw_multi_aff_involves_nan( + __isl_keep isl_union_pw_multi_aff *upma); +isl_bool isl_union_pw_multi_aff_plain_is_equal( + __isl_keep isl_union_pw_multi_aff *upma1, + __isl_keep isl_union_pw_multi_aff *upma2); + +__isl_give isl_union_set *isl_union_pw_multi_aff_domain( + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_neg( + __isl_take isl_union_pw_multi_aff *upma); + +__isl_export +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_add( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); +__isl_export +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_union_add( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_sub( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_val( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_val *val); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_down_val( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_val *val); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_multi_val( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_multi_val *mv); + +__isl_export +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_intersect_params( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_set *set); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_intersect_domain( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_union_set *uset); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_subtract_domain( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_union_set *uset); + +__isl_overload +__isl_give isl_union_map *isl_union_map_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_printer *isl_printer_print_union_pw_multi_aff( + __isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set( + __isl_take isl_union_set *uset); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map( + __isl_take isl_union_map *umap); + +__isl_constructor +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str( + isl_ctx *ctx, const char *str); +void isl_union_pw_multi_aff_dump(__isl_keep isl_union_pw_multi_aff *upma); +__isl_give char *isl_union_pw_multi_aff_to_str( + __isl_keep isl_union_pw_multi_aff *upma); + +uint32_t isl_multi_pw_aff_get_hash(__isl_keep isl_multi_pw_aff *mpa); + +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_identity( + __isl_take isl_space *space); +__isl_constructor +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma); +__isl_constructor +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_aff( + __isl_take isl_pw_aff *pa); +__isl_give isl_set *isl_multi_pw_aff_domain(__isl_take isl_multi_pw_aff *mpa); +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_intersect_params( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *set); +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_intersect_domain( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *domain); + +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_coalesce( + __isl_take isl_multi_pw_aff *mpa); +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *set); +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist_params( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *set); + +isl_bool isl_multi_pw_aff_is_cst(__isl_keep isl_multi_pw_aff *mpa); +isl_bool isl_multi_pw_aff_is_equal(__isl_keep isl_multi_pw_aff *mpa1, + __isl_keep isl_multi_pw_aff *mpa2); + +__isl_overload +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma); +__isl_overload +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_pw_multi_aff( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma); +__isl_overload +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2); + +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_move_dims( + __isl_take isl_multi_pw_aff *pma, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); + +__isl_give isl_set *isl_set_from_multi_pw_aff(__isl_take isl_multi_pw_aff *mpa); +__isl_give isl_map *isl_map_from_multi_pw_aff(__isl_take isl_multi_pw_aff *mpa); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa); +__isl_constructor +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma); + +__isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); +__isl_give isl_map *isl_multi_pw_aff_lex_lt_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2); +__isl_give isl_map *isl_multi_pw_aff_lex_gt_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2); + +__isl_constructor +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give char *isl_multi_pw_aff_to_str(__isl_keep isl_multi_pw_aff *mpa); +__isl_give isl_printer *isl_printer_print_multi_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_multi_pw_aff *mpa); +void isl_multi_pw_aff_dump(__isl_keep isl_multi_pw_aff *mpa); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_copy( + __isl_keep isl_union_pw_aff *upa); +__isl_null isl_union_pw_aff *isl_union_pw_aff_free( + __isl_take isl_union_pw_aff *upa); + +isl_ctx *isl_union_pw_aff_get_ctx(__isl_keep isl_union_pw_aff *upa); +__isl_give isl_space *isl_union_pw_aff_get_space( + __isl_keep isl_union_pw_aff *upa); + +unsigned isl_union_pw_aff_dim(__isl_keep isl_union_pw_aff *upa, + enum isl_dim_type type); +__isl_give isl_union_pw_aff *isl_union_pw_aff_set_dim_name( + __isl_take isl_union_pw_aff *upa, enum isl_dim_type type, + unsigned pos, const char *s); + +int isl_union_pw_aff_find_dim_by_name(__isl_keep isl_union_pw_aff *upa, + enum isl_dim_type type, const char *name); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_drop_dims( + __isl_take isl_union_pw_aff *upa, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_pw_aff *isl_union_pw_aff_reset_user( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_empty( + __isl_take isl_space *space); +__isl_constructor +__isl_give isl_union_pw_aff *isl_union_pw_aff_from_pw_aff( + __isl_take isl_pw_aff *pa); +__isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_val *v); +__isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_aff *aff); +__isl_give isl_union_pw_aff *isl_union_pw_aff_add_pw_aff( + __isl_take isl_union_pw_aff *upa, __isl_take isl_pw_aff *pa); + +__isl_constructor +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); + +int isl_union_pw_aff_n_pw_aff(__isl_keep isl_union_pw_aff *upa); + +isl_stat isl_union_pw_aff_foreach_pw_aff(__isl_keep isl_union_pw_aff *upa, + isl_stat (*fn)(__isl_take isl_pw_aff *pa, void *user), void *user); +__isl_give isl_pw_aff *isl_union_pw_aff_extract_pw_aff( + __isl_keep isl_union_pw_aff *upa, __isl_take isl_space *space); + +isl_bool isl_union_pw_aff_involves_nan(__isl_keep isl_union_pw_aff *upa); +isl_bool isl_union_pw_aff_plain_is_equal(__isl_keep isl_union_pw_aff *upa1, + __isl_keep isl_union_pw_aff *upa2); + +__isl_give isl_union_set *isl_union_pw_aff_domain( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_neg( + __isl_take isl_union_pw_aff *upa); + +__isl_export +__isl_give isl_union_pw_aff *isl_union_pw_aff_add( + __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2); +__isl_export +__isl_give isl_union_pw_aff *isl_union_pw_aff_union_add( + __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2); +__isl_give isl_union_pw_aff *isl_union_pw_aff_sub( + __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_coalesce( + __isl_take isl_union_pw_aff *upa); +__isl_give isl_union_pw_aff *isl_union_pw_aff_gist( + __isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *context); +__isl_give isl_union_pw_aff *isl_union_pw_aff_gist_params( + __isl_take isl_union_pw_aff *upa, __isl_take isl_set *context); + +__isl_overload +__isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_floor( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_scale_val( + __isl_take isl_union_pw_aff *upa, __isl_take isl_val *v); +__isl_give isl_union_pw_aff *isl_union_pw_aff_scale_down_val( + __isl_take isl_union_pw_aff *upa, __isl_take isl_val *v); +__isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val( + __isl_take isl_union_pw_aff *upa, __isl_take isl_val *f); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_align_params( + __isl_take isl_union_pw_aff *upa, __isl_take isl_space *model); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_intersect_params( + __isl_take isl_union_pw_aff *upa, __isl_take isl_set *set); +__isl_give isl_union_pw_aff *isl_union_pw_aff_intersect_domain( + __isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *uset); +__isl_give isl_union_pw_aff *isl_union_pw_aff_subtract_domain( + __isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *uset); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_set_dim_name( + __isl_take isl_union_pw_aff *upa, + enum isl_dim_type type, unsigned pos, const char *s); + +__isl_give isl_union_set *isl_union_pw_aff_zero_union_set( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_map *isl_union_map_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); + +__isl_constructor +__isl_give isl_union_pw_aff *isl_union_pw_aff_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give char *isl_union_pw_aff_to_str(__isl_keep isl_union_pw_aff *upa); +__isl_give isl_printer *isl_printer_print_union_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa); +void isl_union_pw_aff_dump(__isl_keep isl_union_pw_aff *upa); + +ISL_DECLARE_MULTI(union_pw_aff) +ISL_DECLARE_MULTI_NEG(union_pw_aff) + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma); +__isl_constructor +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); +__isl_constructor +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_floor( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_domain( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_set *uset); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_params( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *params); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *set); + +__isl_give isl_union_set *isl_multi_union_pw_aff_domain( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_coalesce( + __isl_take isl_multi_union_pw_aff *aff); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_gist( + __isl_take isl_multi_union_pw_aff *aff, + __isl_take isl_union_set *context); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_gist_params( + __isl_take isl_multi_union_pw_aff *aff, __isl_take isl_set *context); + +__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma); +__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_pw_multi_aff *pma); + +__isl_overload +__isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_export +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_union_add( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); + +__isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map( + __isl_take isl_union_map *umap); +__isl_overload +__isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_multi_pw_aff *isl_multi_union_pw_aff_extract_multi_pw_aff( + __isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space); + +__isl_constructor +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_read_from_str( + isl_ctx *ctx, const char *str); +__isl_give char *isl_multi_union_pw_aff_to_str( + __isl_keep isl_multi_union_pw_aff *mupa); +__isl_give isl_printer *isl_printer_print_multi_union_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa); +void isl_multi_union_pw_aff_dump(__isl_keep isl_multi_union_pw_aff *mupa); + +ISL_DECLARE_LIST_FN(union_pw_aff) +ISL_DECLARE_LIST_FN(union_pw_multi_aff) + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/aff_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/aff_type.h @@ -0,0 +1,50 @@ +#ifndef ISL_AFF_TYPE_H +#define ISL_AFF_TYPE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct __isl_subclass(isl_multi_aff) __isl_subclass(isl_pw_aff) isl_aff; +typedef struct isl_aff isl_aff; + +ISL_DECLARE_LIST(aff) + +struct __isl_subclass(isl_multi_pw_aff) __isl_subclass(isl_pw_multi_aff) + __isl_subclass(isl_union_pw_aff) isl_pw_aff; +typedef struct isl_pw_aff isl_pw_aff; + +ISL_DECLARE_LIST(pw_aff) + +struct __isl_subclass(isl_multi_union_pw_aff) + __isl_subclass(isl_union_pw_multi_aff) isl_union_pw_aff; +typedef struct isl_union_pw_aff isl_union_pw_aff; + +ISL_DECLARE_LIST_TYPE(union_pw_aff) + +struct __isl_subclass(isl_multi_pw_aff) __isl_subclass(isl_pw_multi_aff) + isl_multi_aff; +typedef struct isl_multi_aff isl_multi_aff; + +struct __isl_subclass(isl_multi_pw_aff) __isl_subclass(isl_union_pw_multi_aff) + isl_pw_multi_aff; +typedef struct isl_pw_multi_aff isl_pw_multi_aff; + +struct __isl_export isl_union_pw_multi_aff; +typedef struct isl_union_pw_multi_aff isl_union_pw_multi_aff; + +ISL_DECLARE_LIST_TYPE(union_pw_multi_aff) + +struct __isl_subclass(isl_multi_union_pw_aff) isl_multi_pw_aff; +typedef struct isl_multi_pw_aff isl_multi_pw_aff; + +struct __isl_export isl_multi_union_pw_aff; +typedef struct isl_multi_union_pw_aff isl_multi_union_pw_aff; + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/arg.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/arg.h @@ -0,0 +1,324 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_ARG_H +#define ISL_ARG_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_arg_choice { + const char *name; + unsigned value; +}; + +struct isl_arg_flags { + const char *name; + unsigned mask; + unsigned value; +}; + +enum isl_arg_type { + isl_arg_end, + isl_arg_alias, + isl_arg_arg, + isl_arg_bool, + isl_arg_child, + isl_arg_choice, + isl_arg_flags, + isl_arg_footer, + isl_arg_int, + isl_arg_user, + isl_arg_long, + isl_arg_ulong, + isl_arg_str, + isl_arg_str_list, + isl_arg_version +}; + +struct isl_args; + +struct isl_arg { + enum isl_arg_type type; + char short_name; + const char *long_name; + const char *argument_name; + size_t offset; + const char *help_msg; +#define ISL_ARG_SINGLE_DASH (1 << 0) +#define ISL_ARG_BOOL_ARG (1 << 1) +#define ISL_ARG_HIDDEN (1 << 2) + unsigned flags; + union { + struct { + struct isl_arg_choice *choice; + unsigned default_value; + unsigned default_selected; + int (*set)(void *opt, unsigned val); + } choice; + struct { + struct isl_arg_flags *flags; + unsigned default_value; + } flags; + struct { + unsigned default_value; + int (*set)(void *opt, unsigned val); + } b; + struct { + int default_value; + } i; + struct { + long default_value; + long default_selected; + int (*set)(void *opt, long val); + } l; + struct { + unsigned long default_value; + } ul; + struct { + const char *default_value; + } str; + struct { + size_t offset_n; + } str_list; + struct { + struct isl_args *child; + } child; + struct { + void (*print_version)(void); + } version; + struct { + int (*init)(void*); + void (*clear)(void*); + } user; + } u; +}; + +struct isl_args { + size_t options_size; + struct isl_arg *args; +}; + +#define ISL_ARGS_START(s,name) \ + struct isl_arg name ## LIST[]; \ + struct isl_args name = { sizeof(s), name ## LIST }; \ + struct isl_arg name ## LIST[] = { +#define ISL_ARGS_END \ + { isl_arg_end } }; + +#define ISL_ARG_ALIAS(l) { \ + .type = isl_arg_alias, \ + .long_name = l, \ +}, +#define ISL_ARG_ARG(st,f,a,d) { \ + .type = isl_arg_arg, \ + .argument_name = a, \ + .offset = offsetof(st, f), \ + .u = { .str = { .default_value = d } } \ +}, +#define ISL_ARG_FOOTER(h) { \ + .type = isl_arg_footer, \ + .help_msg = h, \ +}, +#define ISL_ARG_CHOICE(st,f,s,l,c,d,h) { \ + .type = isl_arg_choice, \ + .short_name = s, \ + .long_name = l, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .u = { .choice = { .choice = c, .default_value = d, \ + .default_selected = d, .set = NULL } } \ +}, +#define ISL_ARG_OPT_CHOICE(st,f,s,l,c,d,ds,h) { \ + .type = isl_arg_choice, \ + .short_name = s, \ + .long_name = l, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .u = { .choice = { .choice = c, .default_value = d, \ + .default_selected = ds, .set = NULL } } \ +}, +#define ISL_ARG_PHANTOM_USER_CHOICE_F(s,l,c,setter,d,h,fl) { \ + .type = isl_arg_choice, \ + .short_name = s, \ + .long_name = l, \ + .offset = -1, \ + .help_msg = h, \ + .flags = fl, \ + .u = { .choice = { .choice = c, .default_value = d, \ + .default_selected = d, .set = setter } } \ +}, +#define ISL_ARG_USER_OPT_CHOICE(st,f,s,l,c,setter,d,ds,h) { \ + .type = isl_arg_choice, \ + .short_name = s, \ + .long_name = l, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .u = { .choice = { .choice = c, .default_value = d, \ + .default_selected = ds, .set = setter } } \ +}, +#define _ISL_ARG_BOOL_F(o,s,l,setter,d,h,fl) { \ + .type = isl_arg_bool, \ + .short_name = s, \ + .long_name = l, \ + .offset = o, \ + .help_msg = h, \ + .flags = fl, \ + .u = { .b = { .default_value = d, .set = setter } } \ +}, +#define ISL_ARG_BOOL_F(st,f,s,l,d,h,fl) \ + _ISL_ARG_BOOL_F(offsetof(st, f),s,l,NULL,d,h,fl) +#define ISL_ARG_BOOL(st,f,s,l,d,h) \ + ISL_ARG_BOOL_F(st,f,s,l,d,h,0) +#define ISL_ARG_PHANTOM_BOOL_F(s,l,setter,h,fl) \ + _ISL_ARG_BOOL_F(-1,s,l,setter,0,h,fl) +#define ISL_ARG_PHANTOM_BOOL(s,l,setter,h) \ + ISL_ARG_PHANTOM_BOOL_F(s,l,setter,h,0) +#define ISL_ARG_INT_F(st,f,s,l,a,d,h,fl) { \ + .type = isl_arg_int, \ + .short_name = s, \ + .long_name = l, \ + .argument_name = a, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .flags = fl, \ + .u = { .ul = { .default_value = d } } \ +}, +#define ISL_ARG_INT(st,f,s,l,a,d,h) \ + ISL_ARG_INT_F(st,f,s,l,a,d,h,0) +#define ISL_ARG_LONG(st,f,s,lo,d,h) { \ + .type = isl_arg_long, \ + .short_name = s, \ + .long_name = lo, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .u = { .l = { .default_value = d, .default_selected = d, \ + .set = NULL } } \ +}, +#define ISL_ARG_USER_LONG(st,f,s,lo,setter,d,h) { \ + .type = isl_arg_long, \ + .short_name = s, \ + .long_name = lo, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .u = { .l = { .default_value = d, .default_selected = d, \ + .set = setter } } \ +}, +#define ISL_ARG_OPT_LONG(st,f,s,lo,d,ds,h) { \ + .type = isl_arg_long, \ + .short_name = s, \ + .long_name = lo, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .u = { .l = { .default_value = d, .default_selected = ds, \ + .set = NULL } } \ +}, +#define ISL_ARG_ULONG(st,f,s,l,d,h) { \ + .type = isl_arg_ulong, \ + .short_name = s, \ + .long_name = l, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .u = { .ul = { .default_value = d } } \ +}, +#define ISL_ARG_STR_F(st,f,s,l,a,d,h,fl) { \ + .type = isl_arg_str, \ + .short_name = s, \ + .long_name = l, \ + .argument_name = a, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .flags = fl, \ + .u = { .str = { .default_value = d } } \ +}, +#define ISL_ARG_STR(st,f,s,l,a,d,h) \ + ISL_ARG_STR_F(st,f,s,l,a,d,h,0) +#define ISL_ARG_STR_LIST(st,f_n,f_l,s,l,a,h) { \ + .type = isl_arg_str_list, \ + .short_name = s, \ + .long_name = l, \ + .argument_name = a, \ + .offset = offsetof(st, f_l), \ + .help_msg = h, \ + .u = { .str_list = { .offset_n = offsetof(st, f_n) } } \ +}, +#define _ISL_ARG_CHILD(o,l,c,h,fl) { \ + .type = isl_arg_child, \ + .long_name = l, \ + .offset = o, \ + .help_msg = h, \ + .flags = fl, \ + .u = { .child = { .child = c } } \ +}, +#define ISL_ARG_CHILD(st,f,l,c,h) \ + _ISL_ARG_CHILD(offsetof(st, f),l,c,h,0) +#define ISL_ARG_GROUP_F(l,c,h,fl) \ + _ISL_ARG_CHILD(-1,l,c,h,fl) +#define ISL_ARG_GROUP(l,c,h) \ + ISL_ARG_GROUP_F(l,c,h,0) +#define ISL_ARG_FLAGS(st,f,s,l,c,d,h) { \ + .type = isl_arg_flags, \ + .short_name = s, \ + .long_name = l, \ + .offset = offsetof(st, f), \ + .help_msg = h, \ + .u = { .flags = { .flags = c, .default_value = d } } \ +}, +#define ISL_ARG_USER(st,f,i,c) { \ + .type = isl_arg_user, \ + .offset = offsetof(st, f), \ + .u = { .user = { .init = i, .clear = c} } \ +}, +#define ISL_ARG_VERSION(print) { \ + .type = isl_arg_version, \ + .u = { .version = { .print_version = print } } \ +}, + +#define ISL_ARG_ALL (1 << 0) +#define ISL_ARG_SKIP_HELP (1 << 1) + +void isl_args_set_defaults(struct isl_args *args, void *opt); +void isl_args_free(struct isl_args *args, void *opt); +int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt, + unsigned flags); + +#define ISL_ARG_DECL(prefix,st,args) \ +extern struct isl_args args; \ +st *prefix ## _new_with_defaults(void); \ +void prefix ## _free(st *opt); \ +int prefix ## _parse(st *opt, int argc, char **argv, unsigned flags); + +#define ISL_ARG_DEF(prefix,st,args) \ +st *prefix ## _new_with_defaults() \ +{ \ + st *opt = (st *)calloc(1, sizeof(st)); \ + if (opt) \ + isl_args_set_defaults(&(args), opt); \ + return opt; \ +} \ + \ +void prefix ## _free(st *opt) \ +{ \ + isl_args_free(&(args), opt); \ +} \ + \ +int prefix ## _parse(st *opt, int argc, char **argv, unsigned flags) \ +{ \ + return isl_args_parse(&(args), argc, argv, opt, flags); \ +} + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/ast.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/ast.h @@ -0,0 +1,193 @@ +#ifndef ISL_AST_H +#define ISL_AST_H + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +isl_stat isl_options_set_ast_iterator_type(isl_ctx *ctx, const char *val); +const char *isl_options_get_ast_iterator_type(isl_ctx *ctx); + +isl_stat isl_options_set_ast_always_print_block(isl_ctx *ctx, int val); +int isl_options_get_ast_always_print_block(isl_ctx *ctx); + +__isl_give isl_ast_expr *isl_ast_expr_from_val(__isl_take isl_val *v); +__isl_give isl_ast_expr *isl_ast_expr_from_id(__isl_take isl_id *id); +__isl_give isl_ast_expr *isl_ast_expr_neg(__isl_take isl_ast_expr *expr); +__isl_give isl_ast_expr *isl_ast_expr_add(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_sub(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_mul(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_div(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_pdiv_q(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_pdiv_r(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_and(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_and_then(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_or(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_or_else(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_le(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_lt(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_ge(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_gt(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_eq(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_ast_expr_access(__isl_take isl_ast_expr *array, + __isl_take isl_ast_expr_list *indices); +__isl_give isl_ast_expr *isl_ast_expr_call(__isl_take isl_ast_expr *function, + __isl_take isl_ast_expr_list *arguments); +__isl_give isl_ast_expr *isl_ast_expr_address_of(__isl_take isl_ast_expr *expr); + +__isl_give isl_ast_expr *isl_ast_expr_copy(__isl_keep isl_ast_expr *expr); +__isl_null isl_ast_expr *isl_ast_expr_free(__isl_take isl_ast_expr *expr); + +isl_ctx *isl_ast_expr_get_ctx(__isl_keep isl_ast_expr *expr); +enum isl_ast_expr_type isl_ast_expr_get_type(__isl_keep isl_ast_expr *expr); +__isl_give isl_val *isl_ast_expr_get_val(__isl_keep isl_ast_expr *expr); +__isl_give isl_id *isl_ast_expr_get_id(__isl_keep isl_ast_expr *expr); + +enum isl_ast_op_type isl_ast_expr_get_op_type(__isl_keep isl_ast_expr *expr); +int isl_ast_expr_get_op_n_arg(__isl_keep isl_ast_expr *expr); +__isl_give isl_ast_expr *isl_ast_expr_get_op_arg(__isl_keep isl_ast_expr *expr, + int pos); +__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr, + int pos, __isl_take isl_ast_expr *arg); + +isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1, + __isl_keep isl_ast_expr *expr2); + +__isl_give isl_ast_expr *isl_ast_expr_substitute_ids( + __isl_take isl_ast_expr *expr, __isl_take isl_id_to_ast_expr *id2expr); + +__isl_give isl_printer *isl_printer_print_ast_expr(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr); +void isl_ast_expr_dump(__isl_keep isl_ast_expr *expr); +__isl_give char *isl_ast_expr_to_str(__isl_keep isl_ast_expr *expr); +__isl_export +__isl_give char *isl_ast_expr_to_C_str(__isl_keep isl_ast_expr *expr); + +__isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr); +__isl_give isl_ast_node *isl_ast_node_copy(__isl_keep isl_ast_node *node); +__isl_null isl_ast_node *isl_ast_node_free(__isl_take isl_ast_node *node); + +isl_ctx *isl_ast_node_get_ctx(__isl_keep isl_ast_node *node); +enum isl_ast_node_type isl_ast_node_get_type(__isl_keep isl_ast_node *node); + +__isl_give isl_ast_node *isl_ast_node_set_annotation( + __isl_take isl_ast_node *node, __isl_take isl_id *annotation); +__isl_give isl_id *isl_ast_node_get_annotation(__isl_keep isl_ast_node *node); + +__isl_give isl_ast_expr *isl_ast_node_for_get_iterator( + __isl_keep isl_ast_node *node); +__isl_give isl_ast_expr *isl_ast_node_for_get_init( + __isl_keep isl_ast_node *node); +__isl_give isl_ast_expr *isl_ast_node_for_get_cond( + __isl_keep isl_ast_node *node); +__isl_give isl_ast_expr *isl_ast_node_for_get_inc( + __isl_keep isl_ast_node *node); +__isl_give isl_ast_node *isl_ast_node_for_get_body( + __isl_keep isl_ast_node *node); +isl_bool isl_ast_node_for_is_degenerate(__isl_keep isl_ast_node *node); + +__isl_give isl_ast_expr *isl_ast_node_if_get_cond( + __isl_keep isl_ast_node *node); +__isl_give isl_ast_node *isl_ast_node_if_get_then( + __isl_keep isl_ast_node *node); +isl_bool isl_ast_node_if_has_else(__isl_keep isl_ast_node *node); +__isl_give isl_ast_node *isl_ast_node_if_get_else( + __isl_keep isl_ast_node *node); + +__isl_give isl_ast_node_list *isl_ast_node_block_get_children( + __isl_keep isl_ast_node *node); + +__isl_give isl_id *isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node); +__isl_give isl_ast_node *isl_ast_node_mark_get_node( + __isl_keep isl_ast_node *node); + +__isl_give isl_ast_expr *isl_ast_node_user_get_expr( + __isl_keep isl_ast_node *node); + +isl_stat isl_ast_node_foreach_descendant_top_down( + __isl_keep isl_ast_node *node, + isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user); + +__isl_give isl_printer *isl_printer_print_ast_node(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node); +void isl_ast_node_dump(__isl_keep isl_ast_node *node); +__isl_give char *isl_ast_node_to_str(__isl_keep isl_ast_node *node); + +__isl_give isl_ast_print_options *isl_ast_print_options_alloc(isl_ctx *ctx); +__isl_give isl_ast_print_options *isl_ast_print_options_copy( + __isl_keep isl_ast_print_options *options); +__isl_null isl_ast_print_options *isl_ast_print_options_free( + __isl_take isl_ast_print_options *options); +isl_ctx *isl_ast_print_options_get_ctx( + __isl_keep isl_ast_print_options *options); + +__isl_give isl_ast_print_options *isl_ast_print_options_set_print_user( + __isl_take isl_ast_print_options *options, + __isl_give isl_printer *(*print_user)(__isl_take isl_printer *p, + __isl_take isl_ast_print_options *options, + __isl_keep isl_ast_node *node, void *user), + void *user); +__isl_give isl_ast_print_options *isl_ast_print_options_set_print_for( + __isl_take isl_ast_print_options *options, + __isl_give isl_printer *(*print_for)(__isl_take isl_printer *p, + __isl_take isl_ast_print_options *options, + __isl_keep isl_ast_node *node, void *user), + void *user); + +isl_stat isl_options_set_ast_print_macro_once(isl_ctx *ctx, int val); +int isl_options_get_ast_print_macro_once(isl_ctx *ctx); + +isl_stat isl_ast_expr_foreach_ast_op_type(__isl_keep isl_ast_expr *expr, + isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user); +isl_stat isl_ast_node_foreach_ast_op_type(__isl_keep isl_ast_node *node, + isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user); +__isl_give isl_printer *isl_ast_op_type_set_print_name( + __isl_take isl_printer *p, enum isl_ast_op_type type, + __isl_keep const char *name); +__isl_give isl_printer *isl_ast_op_type_print_macro( + enum isl_ast_op_type type, __isl_take isl_printer *p); +__isl_give isl_printer *isl_ast_expr_print_macros( + __isl_keep isl_ast_expr *expr, __isl_take isl_printer *p); +__isl_give isl_printer *isl_ast_node_print_macros( + __isl_keep isl_ast_node *node, __isl_take isl_printer *p); +__isl_give isl_printer *isl_ast_node_print(__isl_keep isl_ast_node *node, + __isl_take isl_printer *p, + __isl_take isl_ast_print_options *options); +__isl_give isl_printer *isl_ast_node_for_print(__isl_keep isl_ast_node *node, + __isl_take isl_printer *p, + __isl_take isl_ast_print_options *options); +__isl_give isl_printer *isl_ast_node_if_print(__isl_keep isl_ast_node *node, + __isl_take isl_printer *p, + __isl_take isl_ast_print_options *options); + +__isl_export +__isl_give char *isl_ast_node_to_C_str(__isl_keep isl_ast_node *node); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/ast_build.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/ast_build.h @@ -0,0 +1,128 @@ +#ifndef ISL_AST_CONTEXT_H +#define ISL_AST_CONTEXT_H + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct __isl_export isl_ast_build; +typedef struct isl_ast_build isl_ast_build; + + +isl_stat isl_options_set_ast_build_atomic_upper_bound(isl_ctx *ctx, int val); +int isl_options_get_ast_build_atomic_upper_bound(isl_ctx *ctx); + +isl_stat isl_options_set_ast_build_prefer_pdiv(isl_ctx *ctx, int val); +int isl_options_get_ast_build_prefer_pdiv(isl_ctx *ctx); + +isl_stat isl_options_set_ast_build_detect_min_max(isl_ctx *ctx, int val); +int isl_options_get_ast_build_detect_min_max(isl_ctx *ctx); + +isl_stat isl_options_set_ast_build_exploit_nested_bounds(isl_ctx *ctx, int val); +int isl_options_get_ast_build_exploit_nested_bounds(isl_ctx *ctx); + +isl_stat isl_options_set_ast_build_group_coscheduled(isl_ctx *ctx, int val); +int isl_options_get_ast_build_group_coscheduled(isl_ctx *ctx); + +#define ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT 0 +#define ISL_AST_BUILD_SEPARATION_BOUNDS_IMPLICIT 1 +isl_stat isl_options_set_ast_build_separation_bounds(isl_ctx *ctx, int val); +int isl_options_get_ast_build_separation_bounds(isl_ctx *ctx); + +isl_stat isl_options_set_ast_build_scale_strides(isl_ctx *ctx, int val); +int isl_options_get_ast_build_scale_strides(isl_ctx *ctx); + +isl_stat isl_options_set_ast_build_allow_else(isl_ctx *ctx, int val); +int isl_options_get_ast_build_allow_else(isl_ctx *ctx); + +isl_stat isl_options_set_ast_build_allow_or(isl_ctx *ctx, int val); +int isl_options_get_ast_build_allow_or(isl_ctx *ctx); + +isl_ctx *isl_ast_build_get_ctx(__isl_keep isl_ast_build *build); + +__isl_constructor +__isl_give isl_ast_build *isl_ast_build_alloc(isl_ctx *ctx); +__isl_export +__isl_give isl_ast_build *isl_ast_build_from_context(__isl_take isl_set *set); + +__isl_give isl_space *isl_ast_build_get_schedule_space( + __isl_keep isl_ast_build *build); +__isl_give isl_union_map *isl_ast_build_get_schedule( + __isl_keep isl_ast_build *build); + +__isl_give isl_ast_build *isl_ast_build_restrict( + __isl_take isl_ast_build *build, __isl_take isl_set *set); + +__isl_give isl_ast_build *isl_ast_build_copy( + __isl_keep isl_ast_build *build); +__isl_null isl_ast_build *isl_ast_build_free( + __isl_take isl_ast_build *build); + +__isl_give isl_ast_build *isl_ast_build_set_options( + __isl_take isl_ast_build *build, + __isl_take isl_union_map *options); +__isl_give isl_ast_build *isl_ast_build_set_iterators( + __isl_take isl_ast_build *build, + __isl_take isl_id_list *iterators); +__isl_give isl_ast_build *isl_ast_build_set_at_each_domain( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user), void *user); +__isl_give isl_ast_build *isl_ast_build_set_before_each_for( + __isl_take isl_ast_build *build, + __isl_give isl_id *(*fn)(__isl_keep isl_ast_build *build, + void *user), void *user); +__isl_give isl_ast_build *isl_ast_build_set_after_each_for( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user), void *user); +__isl_give isl_ast_build *isl_ast_build_set_before_each_mark( + __isl_take isl_ast_build *build, + isl_stat (*fn)(__isl_keep isl_id *mark, __isl_keep isl_ast_build *build, + void *user), void *user); +__isl_give isl_ast_build *isl_ast_build_set_after_each_mark( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user), void *user); +__isl_give isl_ast_build *isl_ast_build_set_create_leaf( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_build *build, + void *user), void *user); + +__isl_overload +__isl_give isl_ast_expr *isl_ast_build_expr_from_set( + __isl_keep isl_ast_build *build, __isl_take isl_set *set); +__isl_overload +__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa); +__isl_overload +__isl_give isl_ast_expr *isl_ast_build_access_from_pw_multi_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma); +__isl_overload +__isl_give isl_ast_expr *isl_ast_build_access_from_multi_pw_aff( + __isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa); +__isl_overload +__isl_give isl_ast_expr *isl_ast_build_call_from_pw_multi_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma); +__isl_overload +__isl_give isl_ast_expr *isl_ast_build_call_from_multi_pw_aff( + __isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa); + +__isl_give isl_ast_node *isl_ast_build_node_from_schedule( + __isl_keep isl_ast_build *build, __isl_take isl_schedule *schedule); +__isl_export +__isl_give isl_ast_node *isl_ast_build_node_from_schedule_map( + __isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule); +__isl_give isl_ast_node *isl_ast_build_ast_from_schedule( + __isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/ast_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/ast_type.h @@ -0,0 +1,80 @@ +#ifndef ISL_AST_TYPE_H +#define ISL_AST_TYPE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct __isl_export isl_ast_expr; +typedef struct isl_ast_expr isl_ast_expr; + +struct __isl_export isl_ast_node; +typedef struct isl_ast_node isl_ast_node; + +enum isl_ast_op_type { + isl_ast_op_error = -1, + isl_ast_op_and, + isl_ast_op_and_then, + isl_ast_op_or, + isl_ast_op_or_else, + isl_ast_op_max, + isl_ast_op_min, + isl_ast_op_minus, + isl_ast_op_add, + isl_ast_op_sub, + isl_ast_op_mul, + isl_ast_op_div, + isl_ast_op_fdiv_q, /* Round towards -infty */ + isl_ast_op_pdiv_q, /* Dividend is non-negative */ + isl_ast_op_pdiv_r, /* Dividend is non-negative */ + isl_ast_op_zdiv_r, /* Result only compared against zero */ + isl_ast_op_cond, + isl_ast_op_select, + isl_ast_op_eq, + isl_ast_op_le, + isl_ast_op_lt, + isl_ast_op_ge, + isl_ast_op_gt, + isl_ast_op_call, + isl_ast_op_access, + isl_ast_op_member, + isl_ast_op_address_of +}; + +enum isl_ast_expr_type { + isl_ast_expr_error = -1, + isl_ast_expr_op, + isl_ast_expr_id, + isl_ast_expr_int +}; + +enum isl_ast_node_type { + isl_ast_node_error = -1, + isl_ast_node_for = 1, + isl_ast_node_if, + isl_ast_node_block, + isl_ast_node_mark, + isl_ast_node_user +}; + +enum isl_ast_loop_type { + isl_ast_loop_error = -1, + isl_ast_loop_default = 0, + isl_ast_loop_atomic, + isl_ast_loop_unroll, + isl_ast_loop_separate +}; + +struct isl_ast_print_options; +typedef struct isl_ast_print_options isl_ast_print_options; + +ISL_DECLARE_LIST(ast_expr) +ISL_DECLARE_LIST(ast_node) + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/constraint.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/constraint.h @@ -0,0 +1,147 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_CONSTRAINT_H +#define ISL_CONSTRAINT_H + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_constraint; +typedef struct isl_constraint isl_constraint; + +ISL_DECLARE_LIST(constraint) + +isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c); + +__isl_give isl_constraint *isl_constraint_alloc_equality( + __isl_take isl_local_space *ls); +__isl_give isl_constraint *isl_constraint_alloc_inequality( + __isl_take isl_local_space *ls); +__isl_give isl_constraint *isl_equality_alloc(__isl_take isl_local_space *ls); +__isl_give isl_constraint *isl_inequality_alloc(__isl_take isl_local_space *ls); + +struct isl_constraint *isl_constraint_cow(struct isl_constraint *c); +struct isl_constraint *isl_constraint_copy(struct isl_constraint *c); +__isl_null isl_constraint *isl_constraint_free(__isl_take isl_constraint *c); + +int isl_basic_map_n_constraint(__isl_keep isl_basic_map *bmap); +int isl_basic_set_n_constraint(__isl_keep isl_basic_set *bset); +isl_stat isl_basic_map_foreach_constraint(__isl_keep isl_basic_map *bmap, + isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user); +isl_stat isl_basic_set_foreach_constraint(__isl_keep isl_basic_set *bset, + isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user); +__isl_give isl_constraint_list *isl_basic_map_get_constraint_list( + __isl_keep isl_basic_map *bmap); +__isl_give isl_constraint_list *isl_basic_set_get_constraint_list( + __isl_keep isl_basic_set *bset); +int isl_constraint_is_equal(struct isl_constraint *constraint1, + struct isl_constraint *constraint2); + +isl_stat isl_basic_set_foreach_bound_pair(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, + isl_stat (*fn)(__isl_take isl_constraint *lower, + __isl_take isl_constraint *upper, + __isl_take isl_basic_set *bset, void *user), void *user); + +__isl_give isl_basic_map *isl_basic_map_add_constraint( + __isl_take isl_basic_map *bmap, __isl_take isl_constraint *constraint); +__isl_give isl_basic_set *isl_basic_set_add_constraint( + __isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint); +__isl_give isl_map *isl_map_add_constraint(__isl_take isl_map *map, + __isl_take isl_constraint *constraint); +__isl_give isl_set *isl_set_add_constraint(__isl_take isl_set *set, + __isl_take isl_constraint *constraint); + +isl_bool isl_basic_map_has_defining_equality( + __isl_keep isl_basic_map *bmap, enum isl_dim_type type, int pos, + __isl_give isl_constraint **c); +isl_bool isl_basic_set_has_defining_equality( + struct isl_basic_set *bset, enum isl_dim_type type, int pos, + struct isl_constraint **constraint); +isl_bool isl_basic_set_has_defining_inequalities( + struct isl_basic_set *bset, enum isl_dim_type type, int pos, + struct isl_constraint **lower, + struct isl_constraint **upper); + +__isl_give isl_space *isl_constraint_get_space( + __isl_keep isl_constraint *constraint); +__isl_give isl_local_space *isl_constraint_get_local_space( + __isl_keep isl_constraint *constraint); +int isl_constraint_dim(struct isl_constraint *constraint, + enum isl_dim_type type); + +isl_bool 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); +__isl_give isl_val *isl_constraint_get_constant_val( + __isl_keep isl_constraint *constraint); +__isl_give isl_val *isl_constraint_get_coefficient_val( + __isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos); +__isl_give isl_constraint *isl_constraint_set_constant_si( + __isl_take isl_constraint *constraint, int v); +__isl_give isl_constraint *isl_constraint_set_constant_val( + __isl_take isl_constraint *constraint, __isl_take isl_val *v); +__isl_give isl_constraint *isl_constraint_set_coefficient_si( + __isl_take isl_constraint *constraint, + enum isl_dim_type type, int pos, int v); +__isl_give isl_constraint *isl_constraint_set_coefficient_val( + __isl_take isl_constraint *constraint, + enum isl_dim_type type, int pos, __isl_take isl_val *v); + +__isl_give isl_aff *isl_constraint_get_div(__isl_keep isl_constraint *constraint, + int pos); + +struct isl_constraint *isl_constraint_negate(struct isl_constraint *constraint); + +isl_bool isl_constraint_is_equality(__isl_keep isl_constraint *constraint); +int isl_constraint_is_div_constraint(__isl_keep isl_constraint *constraint); + +isl_bool isl_constraint_is_lower_bound(__isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned pos); +isl_bool isl_constraint_is_upper_bound(__isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned pos); + +__isl_give isl_basic_map *isl_basic_map_from_constraint( + __isl_take isl_constraint *constraint); +__isl_give isl_basic_set *isl_basic_set_from_constraint( + __isl_take 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_aff *isl_constraint_get_aff( + __isl_keep isl_constraint *constraint); +__isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff); +__isl_give isl_constraint *isl_inequality_from_aff(__isl_take isl_aff *aff); + +int isl_constraint_plain_cmp(__isl_keep isl_constraint *c1, + __isl_keep isl_constraint *c2); +int isl_constraint_cmp_last_non_zero(__isl_keep isl_constraint *c1, + __isl_keep isl_constraint *c2); + +__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 + +#endif Index: contrib/isl/include/isl/ctx.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/ctx.h @@ -0,0 +1,258 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_CTX_H +#define ISL_CTX_H + +#include +#include + +#include + +#ifndef __isl_give +#define __isl_give +#endif +#ifndef __isl_take +#define __isl_take +#endif +#ifndef __isl_keep +#define __isl_keep +#endif +#ifndef __isl_null +#define __isl_null +#endif +#ifndef __isl_export +#define __isl_export +#endif +#ifndef __isl_overload +#define __isl_overload +#endif +#ifndef __isl_constructor +#define __isl_constructor +#endif +#ifndef __isl_subclass +#define __isl_subclass(super) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Nearly all isa functions require a struct isl_ctx allocated using + * isl_ctx_alloc. This ctx contains (or will contain) options that + * control the behavior of the library and some caches. + * + * An object allocated within a given ctx should never be used inside + * another ctx. Functions for moving objects from one ctx to another + * will be added as the need arises. + * + * A given context should only be used inside a single thread. + * A global context for synchronization between different threads + * as well as functions for moving a context to a different thread + * will be added as the need arises. + * + * If anything goes wrong (out of memory, failed assertion), then + * the library will currently simply abort. This will be made + * configurable in the future. + * Users of the library should expect functions that return + * a pointer to a structure, to return NULL, indicating failure. + * Any function accepting a pointer to a structure will treat + * a NULL argument as a failure, resulting in the function freeing + * the remaining structures (if any) and returning NULL itself + * (in case of pointer return type). + * The only exception is the isl_ctx argument, which should never be NULL. + */ +struct isl_stats { + long gbr_solved_lps; +}; +enum isl_error { + isl_error_none = 0, + isl_error_abort, + isl_error_alloc, + isl_error_unknown, + isl_error_internal, + isl_error_invalid, + isl_error_quota, + isl_error_unsupported +}; +typedef enum { + isl_stat_error = -1, + isl_stat_ok = 0 +} isl_stat; +typedef enum { + isl_bool_error = -1, + isl_bool_false = 0, + isl_bool_true = 1 +} isl_bool; +isl_bool isl_bool_not(isl_bool b); +struct isl_ctx; +typedef struct isl_ctx isl_ctx; + +/* Some helper macros */ + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define ISL_DEPRECATED __attribute__((__deprecated__)) +#else +#define ISL_DEPRECATED +#endif + +#define ISL_FL_INIT(l, f) (l) = (f) /* Specific flags location. */ +#define ISL_FL_SET(l, f) ((l) |= (f)) +#define ISL_FL_CLR(l, f) ((l) &= ~(f)) +#define ISL_FL_ISSET(l, f) (!!((l) & (f))) + +#define ISL_F_INIT(p, f) ISL_FL_INIT((p)->flags, f) /* Structure element flags. */ +#define ISL_F_SET(p, f) ISL_FL_SET((p)->flags, f) +#define ISL_F_CLR(p, f) ISL_FL_CLR((p)->flags, f) +#define ISL_F_ISSET(p, f) ISL_FL_ISSET((p)->flags, f) + +void *isl_malloc_or_die(isl_ctx *ctx, size_t size); +void *isl_calloc_or_die(isl_ctx *ctx, size_t nmemb, size_t size); +void *isl_realloc_or_die(isl_ctx *ctx, void *ptr, size_t size); + +#define isl_alloc(ctx,type,size) ((type *)isl_malloc_or_die(ctx, size)) +#define isl_calloc(ctx,type,size) ((type *)isl_calloc_or_die(ctx,\ + 1, size)) +#define isl_realloc(ctx,ptr,type,size) ((type *)isl_realloc_or_die(ctx,\ + ptr, size)) +#define isl_alloc_type(ctx,type) isl_alloc(ctx,type,sizeof(type)) +#define isl_calloc_type(ctx,type) isl_calloc(ctx,type,sizeof(type)) +#define isl_realloc_type(ctx,ptr,type) isl_realloc(ctx,ptr,type,sizeof(type)) +#define isl_alloc_array(ctx,type,n) isl_alloc(ctx,type,(n)*sizeof(type)) +#define isl_calloc_array(ctx,type,n) ((type *)isl_calloc_or_die(ctx,\ + n, sizeof(type))) +#define isl_realloc_array(ctx,ptr,type,n) \ + isl_realloc(ctx,ptr,type,(n)*sizeof(type)) + +#define isl_die(ctx,errno,msg,code) \ + do { \ + isl_handle_error(ctx, errno, msg, __FILE__, __LINE__); \ + code; \ + } while (0) + +void isl_handle_error(isl_ctx *ctx, enum isl_error error, const char *msg, + const char *file, int line); + +#define isl_assert4(ctx,test,code,errno) \ + do { \ + if (test) \ + break; \ + isl_die(ctx, errno, "Assertion \"" #test "\" failed", code); \ + } while (0) +#define isl_assert(ctx,test,code) \ + isl_assert4(ctx,test,code,isl_error_unknown) + +#define isl_min(a,b) ((a < b) ? (a) : (b)) + +/* struct isl_ctx functions */ + +struct isl_options *isl_ctx_options(isl_ctx *ctx); + +isl_ctx *isl_ctx_alloc_with_options(struct isl_args *args, + __isl_take void *opt); +isl_ctx *isl_ctx_alloc(void); +void *isl_ctx_peek_options(isl_ctx *ctx, struct isl_args *args); +int isl_ctx_parse_options(isl_ctx *ctx, int argc, char **argv, unsigned flags); +void isl_ctx_ref(struct isl_ctx *ctx); +void isl_ctx_deref(struct isl_ctx *ctx); +void isl_ctx_free(isl_ctx *ctx); + +void isl_ctx_abort(isl_ctx *ctx); +void isl_ctx_resume(isl_ctx *ctx); +int isl_ctx_aborted(isl_ctx *ctx); + +void isl_ctx_set_max_operations(isl_ctx *ctx, unsigned long max_operations); +unsigned long isl_ctx_get_max_operations(isl_ctx *ctx); +void isl_ctx_reset_operations(isl_ctx *ctx); + +#define ISL_ARG_CTX_DECL(prefix,st,args) \ +st *isl_ctx_peek_ ## prefix(isl_ctx *ctx); + +#define ISL_ARG_CTX_DEF(prefix,st,args) \ +st *isl_ctx_peek_ ## prefix(isl_ctx *ctx) \ +{ \ + return (st *)isl_ctx_peek_options(ctx, &(args)); \ +} + +#define ISL_CTX_GET_INT_DEF(prefix,st,args,field) \ +int prefix ## _get_ ## field(isl_ctx *ctx) \ +{ \ + st *options; \ + options = isl_ctx_peek_ ## prefix(ctx); \ + if (!options) \ + isl_die(ctx, isl_error_invalid, \ + "isl_ctx does not reference " #prefix, \ + return -1); \ + return options->field; \ +} + +#define ISL_CTX_SET_INT_DEF(prefix,st,args,field) \ +isl_stat prefix ## _set_ ## field(isl_ctx *ctx, int val) \ +{ \ + st *options; \ + options = isl_ctx_peek_ ## prefix(ctx); \ + if (!options) \ + isl_die(ctx, isl_error_invalid, \ + "isl_ctx does not reference " #prefix, \ + return isl_stat_error); \ + options->field = val; \ + return isl_stat_ok; \ +} + +#define ISL_CTX_GET_STR_DEF(prefix,st,args,field) \ +const char *prefix ## _get_ ## field(isl_ctx *ctx) \ +{ \ + st *options; \ + options = isl_ctx_peek_ ## prefix(ctx); \ + if (!options) \ + isl_die(ctx, isl_error_invalid, \ + "isl_ctx does not reference " #prefix, \ + return NULL); \ + return options->field; \ +} + +#define ISL_CTX_SET_STR_DEF(prefix,st,args,field) \ +isl_stat prefix ## _set_ ## field(isl_ctx *ctx, const char *val) \ +{ \ + st *options; \ + options = isl_ctx_peek_ ## prefix(ctx); \ + if (!options) \ + isl_die(ctx, isl_error_invalid, \ + "isl_ctx does not reference " #prefix, \ + return isl_stat_error); \ + if (!val) \ + return isl_stat_error; \ + free(options->field); \ + options->field = strdup(val); \ + if (!options->field) \ + return isl_stat_error; \ + return isl_stat_ok; \ +} + +#define ISL_CTX_GET_BOOL_DEF(prefix,st,args,field) \ + ISL_CTX_GET_INT_DEF(prefix,st,args,field) + +#define ISL_CTX_SET_BOOL_DEF(prefix,st,args,field) \ + ISL_CTX_SET_INT_DEF(prefix,st,args,field) + +#define ISL_CTX_GET_CHOICE_DEF(prefix,st,args,field) \ + ISL_CTX_GET_INT_DEF(prefix,st,args,field) + +#define ISL_CTX_SET_CHOICE_DEF(prefix,st,args,field) \ + ISL_CTX_SET_INT_DEF(prefix,st,args,field) + +enum isl_error isl_ctx_last_error(isl_ctx *ctx); +void isl_ctx_reset_error(isl_ctx *ctx); +void isl_ctx_set_error(isl_ctx *ctx, enum isl_error error); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/flow.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/flow.h @@ -0,0 +1,156 @@ +#ifndef ISL_FLOW_H +#define ISL_FLOW_H + +#include + +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Let n (>= 0) be the number of iterators shared by first and second. + * If first precedes second textually return 2 * n + 1, + * otherwise return 2 * n. + */ +typedef int (*isl_access_level_before)(void *first, void *second); + +struct isl_restriction; +typedef struct isl_restriction isl_restriction; + +__isl_null isl_restriction *isl_restriction_free( + __isl_take isl_restriction *restr); +__isl_give isl_restriction *isl_restriction_empty( + __isl_take isl_map *source_map); +__isl_give isl_restriction *isl_restriction_none( + __isl_take isl_map *source_map); +__isl_give isl_restriction *isl_restriction_input( + __isl_take isl_set *source_restr, __isl_take isl_set *sink_restr); +__isl_give isl_restriction *isl_restriction_output( + __isl_take isl_set *source_restr); + +isl_ctx *isl_restriction_get_ctx(__isl_keep isl_restriction *restr); + +typedef __isl_give isl_restriction *(*isl_access_restrict)( + __isl_keep isl_map *source_map, __isl_keep isl_set *sink, + void *source_user, void *user); + +struct isl_access_info; +typedef struct isl_access_info isl_access_info; +struct isl_flow; +typedef struct isl_flow isl_flow; + +__isl_give isl_access_info *isl_access_info_alloc(__isl_take isl_map *sink, + void *sink_user, isl_access_level_before fn, int max_source); +__isl_give isl_access_info *isl_access_info_set_restrict( + __isl_take isl_access_info *acc, isl_access_restrict fn, void *user); +__isl_give isl_access_info *isl_access_info_add_source( + __isl_take isl_access_info *acc, __isl_take isl_map *source, + int must, void *source_user); +__isl_null isl_access_info *isl_access_info_free( + __isl_take isl_access_info *acc); + +isl_ctx *isl_access_info_get_ctx(__isl_keep isl_access_info *acc); + +__isl_give isl_flow *isl_access_info_compute_flow(__isl_take isl_access_info *acc); +isl_stat isl_flow_foreach(__isl_keep isl_flow *deps, + isl_stat (*fn)(__isl_take isl_map *dep, int must, void *dep_user, + void *user), + void *user); +__isl_give isl_map *isl_flow_get_no_source(__isl_keep isl_flow *deps, int must); +void isl_flow_free(__isl_take isl_flow *deps); + +isl_ctx *isl_flow_get_ctx(__isl_keep isl_flow *deps); + +struct __isl_export isl_union_access_info; +typedef struct isl_union_access_info isl_union_access_info; +struct __isl_export isl_union_flow; +typedef struct isl_union_flow isl_union_flow; + +__isl_constructor +__isl_give isl_union_access_info *isl_union_access_info_from_sink( + __isl_take isl_union_map *sink); +__isl_export +__isl_give isl_union_access_info *isl_union_access_info_set_must_source( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *must_source); +__isl_export +__isl_give isl_union_access_info *isl_union_access_info_set_may_source( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *may_source); +__isl_export +__isl_give isl_union_access_info *isl_union_access_info_set_kill( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *kill); +__isl_export +__isl_give isl_union_access_info *isl_union_access_info_set_schedule( + __isl_take isl_union_access_info *access, + __isl_take isl_schedule *schedule); +__isl_export +__isl_give isl_union_access_info *isl_union_access_info_set_schedule_map( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *schedule_map); +__isl_give isl_union_access_info *isl_union_access_info_copy( + __isl_keep isl_union_access_info *access); +__isl_null isl_union_access_info *isl_union_access_info_free( + __isl_take isl_union_access_info *access); + +isl_ctx *isl_union_access_info_get_ctx( + __isl_keep isl_union_access_info *access); + +__isl_give isl_union_access_info *isl_union_access_info_read_from_file( + isl_ctx *ctx, FILE *input); +__isl_give isl_printer *isl_printer_print_union_access_info( + __isl_take isl_printer *p, __isl_keep isl_union_access_info *access); +__isl_give char *isl_union_access_info_to_str( + __isl_keep isl_union_access_info *access); + +__isl_export +__isl_give isl_union_flow *isl_union_access_info_compute_flow( + __isl_take isl_union_access_info *access); + +isl_ctx *isl_union_flow_get_ctx(__isl_keep isl_union_flow *flow); +__isl_give isl_union_flow *isl_union_flow_copy( + __isl_keep isl_union_flow *flow); +__isl_export +__isl_give isl_union_map *isl_union_flow_get_must_dependence( + __isl_keep isl_union_flow *flow); +__isl_export +__isl_give isl_union_map *isl_union_flow_get_may_dependence( + __isl_keep isl_union_flow *flow); +__isl_export +__isl_give isl_union_map *isl_union_flow_get_full_must_dependence( + __isl_keep isl_union_flow *flow); +__isl_export +__isl_give isl_union_map *isl_union_flow_get_full_may_dependence( + __isl_keep isl_union_flow *flow); +__isl_export +__isl_give isl_union_map *isl_union_flow_get_must_no_source( + __isl_keep isl_union_flow *flow); +__isl_export +__isl_give isl_union_map *isl_union_flow_get_may_no_source( + __isl_keep isl_union_flow *flow); +__isl_null isl_union_flow *isl_union_flow_free(__isl_take isl_union_flow *flow); + +__isl_give isl_printer *isl_printer_print_union_flow( + __isl_take isl_printer *p, __isl_keep isl_union_flow *flow); +__isl_give char *isl_union_flow_to_str(__isl_keep isl_union_flow *flow); + +int isl_union_map_compute_flow(__isl_take isl_union_map *sink, + __isl_take isl_union_map *must_source, + __isl_take isl_union_map *may_source, + __isl_take isl_union_map *schedule, + __isl_give isl_union_map **must_dep, __isl_give isl_union_map **may_dep, + __isl_give isl_union_map **must_no_source, + __isl_give isl_union_map **may_no_source); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/hash.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/hash.h @@ -0,0 +1,77 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_HASH_H +#define ISL_HASH_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#define isl_hash_init() (2166136261u) +#define isl_hash_byte(h,b) do { \ + h *= 16777619; \ + h ^= b; \ + } while(0) +#define isl_hash_hash(h,h2) \ + do { \ + isl_hash_byte(h, (h2) & 0xFF); \ + isl_hash_byte(h, ((h2) >> 8) & 0xFF); \ + isl_hash_byte(h, ((h2) >> 16) & 0xFF); \ + isl_hash_byte(h, ((h2) >> 24) & 0xFF); \ + } while(0) +#define isl_hash_bits(h,bits) \ + ((bits) == 32) ? (h) : \ + ((bits) >= 16) ? \ + ((h) >> (bits)) ^ ((h) & (((uint32_t)1 << (bits)) - 1)) : \ + (((h) >> (bits)) ^ (h)) & (((uint32_t)1 << (bits)) - 1) + +uint32_t isl_hash_string(uint32_t hash, const char *s); +uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len); + +#define isl_hash_builtin(h,l) isl_hash_mem(h, &l, sizeof(l)) + +struct isl_hash_table_entry +{ + uint32_t hash; + void *data; +}; + +struct isl_hash_table { + int bits; + int n; + struct isl_hash_table_entry *entries; +}; + +struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size); +void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table); + +int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table, + int min_size); +void isl_hash_table_clear(struct isl_hash_table *table); +struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx, + struct isl_hash_table *table, + uint32_t key_hash, + int (*eq)(const void *entry, const void *val), + const void *val, int reserve); +isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table, + isl_stat (*fn)(void **entry, void *user), void *user); +void isl_hash_table_remove(struct isl_ctx *ctx, + struct isl_hash_table *table, + struct isl_hash_table_entry *entry); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/hmap.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/hmap.h @@ -0,0 +1,55 @@ +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#define ISL_xCAT(A,B) A ## B +#define ISL_CAT(A,B) ISL_xCAT(A,B) +#define ISL_xFN(TYPE,NAME) TYPE ## _ ## NAME +#define ISL_FN(TYPE,NAME) ISL_xFN(TYPE,NAME) + +struct ISL_HMAP; +typedef struct ISL_HMAP ISL_HMAP; + +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,alloc)(isl_ctx *ctx, int min_size); +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,copy)(__isl_keep ISL_HMAP *hmap); +__isl_null ISL_HMAP *ISL_FN(ISL_HMAP,free)(__isl_take ISL_HMAP *hmap); + +isl_ctx *ISL_FN(ISL_HMAP,get_ctx)(__isl_keep ISL_HMAP *hmap); + +__isl_give ISL_MAYBE(ISL_VAL) ISL_FN(ISL_HMAP,try_get)( + __isl_keep ISL_HMAP *hmap, __isl_keep ISL_KEY *key); +isl_bool ISL_FN(ISL_HMAP,has)(__isl_keep ISL_HMAP *hmap, + __isl_keep ISL_KEY *key); +__isl_give ISL_VAL *ISL_FN(ISL_HMAP,get)(__isl_keep ISL_HMAP *hmap, + __isl_take ISL_KEY *key); +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,set)(__isl_take ISL_HMAP *hmap, + __isl_take ISL_KEY *key, __isl_take ISL_VAL *val); +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,drop)(__isl_take ISL_HMAP *hmap, + __isl_take ISL_KEY *key); + +isl_stat ISL_FN(ISL_HMAP,foreach)(__isl_keep ISL_HMAP *hmap, + isl_stat (*fn)(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val, + void *user), + void *user); + +__isl_give isl_printer *ISL_FN(isl_printer_print,ISL_HMAP_SUFFIX)( + __isl_take isl_printer *p, __isl_keep ISL_HMAP *hmap); +void ISL_FN(ISL_HMAP,dump)(__isl_keep ISL_HMAP *hmap); + +#undef ISL_xCAT +#undef ISL_CAT +#undef ISL_KEY +#undef ISL_VAL +#undef ISL_xFN +#undef ISL_FN +#undef ISL_xHMAP +#undef ISL_yHMAP +#undef ISL_HMAP + +#if defined(__cplusplus) +} +#endif Index: contrib/isl/include/isl/hmap_templ.c =================================================================== --- /dev/null +++ contrib/isl/include/isl/hmap_templ.c @@ -0,0 +1,417 @@ +/* + * Copyright 2011 INRIA Saclay + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include + +#define ISL_xCAT(A,B) A ## B +#define ISL_CAT(A,B) ISL_xCAT(A,B) +#define ISL_xFN(TYPE,NAME) TYPE ## _ ## NAME +#define ISL_FN(TYPE,NAME) ISL_xFN(TYPE,NAME) +#define ISL_xS(TYPE1,TYPE2,NAME) struct isl_ ## TYPE1 ## _ ## TYPE2 ## _ ## NAME +#define ISL_yS(TYPE1,TYPE2,NAME) ISL_xS(TYPE1,TYPE2,NAME) +#define ISL_S(NAME) ISL_yS(ISL_KEY,ISL_VAL,NAME) + +struct ISL_HMAP { + int ref; + isl_ctx *ctx; + struct isl_hash_table table; +}; + +ISL_S(pair) { + ISL_KEY *key; + ISL_VAL *val; +}; + +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,alloc)(isl_ctx *ctx, int min_size) +{ + ISL_HMAP *hmap; + + hmap = isl_calloc_type(ctx, ISL_HMAP); + if (!hmap) + return NULL; + + hmap->ctx = ctx; + isl_ctx_ref(ctx); + hmap->ref = 1; + + if (isl_hash_table_init(ctx, &hmap->table, min_size) < 0) + return ISL_FN(ISL_HMAP,free)(hmap); + + return hmap; +} + +static isl_stat free_pair(void **entry, void *user) +{ + ISL_S(pair) *pair = *entry; + ISL_FN(ISL_KEY,free)(pair->key); + ISL_FN(ISL_VAL,free)(pair->val); + free(pair); + *entry = NULL; + return isl_stat_ok; +} + +__isl_null ISL_HMAP *ISL_FN(ISL_HMAP,free)(__isl_take ISL_HMAP *hmap) +{ + if (!hmap) + return NULL; + if (--hmap->ref > 0) + return NULL; + isl_hash_table_foreach(hmap->ctx, &hmap->table, &free_pair, NULL); + isl_hash_table_clear(&hmap->table); + isl_ctx_deref(hmap->ctx); + free(hmap); + return NULL; +} + +isl_ctx *ISL_FN(ISL_HMAP,get_ctx)(__isl_keep ISL_HMAP *hmap) +{ + return hmap ? hmap->ctx : NULL; +} + +/* Add a mapping from "key" to "val" to the associative array + * pointed to by user. + */ +static isl_stat add_key_val(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val, + void *user) +{ + ISL_HMAP **hmap = (ISL_HMAP **) user; + + *hmap = ISL_FN(ISL_HMAP,set)(*hmap, key, val); + + if (!*hmap) + return isl_stat_error; + + return isl_stat_ok; +} + +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,dup)(__isl_keep ISL_HMAP *hmap) +{ + ISL_HMAP *dup; + + if (!hmap) + return NULL; + + dup = ISL_FN(ISL_HMAP,alloc)(hmap->ctx, hmap->table.n); + if (ISL_FN(ISL_HMAP,foreach)(hmap, &add_key_val, &dup) < 0) + return ISL_FN(ISL_HMAP,free)(dup); + + return dup; +} + +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,cow)(__isl_take ISL_HMAP *hmap) +{ + if (!hmap) + return NULL; + + if (hmap->ref == 1) + return hmap; + hmap->ref--; + return ISL_FN(ISL_HMAP,dup)(hmap); +} + +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,copy)(__isl_keep ISL_HMAP *hmap) +{ + if (!hmap) + return NULL; + + hmap->ref++; + return hmap; +} + +static int has_key(const void *entry, const void *c_key) +{ + const ISL_S(pair) *pair = entry; + ISL_KEY *key = (ISL_KEY *) c_key; + + return ISL_KEY_IS_EQUAL(pair->key, key); +} + +/* If "hmap" contains a value associated to "key", then return + * (isl_bool_true, copy of value). + * Otherwise, return + * (isl_bool_false, NULL). + * If an error occurs, then return + * (isl_bool_error, NULL). + */ +__isl_give ISL_MAYBE(ISL_VAL) ISL_FN(ISL_HMAP,try_get)( + __isl_keep ISL_HMAP *hmap, __isl_keep ISL_KEY *key) +{ + struct isl_hash_table_entry *entry; + ISL_S(pair) *pair; + uint32_t hash; + ISL_MAYBE(ISL_VAL) res = { isl_bool_false, NULL }; + + if (!hmap || !key) + goto error; + + hash = ISL_FN(ISL_KEY,get_hash)(key); + entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash, + &has_key, key, 0); + + if (!entry) + return res; + + pair = entry->data; + + res.valid = isl_bool_true; + res.value = ISL_FN(ISL_VAL,copy)(pair->val); + if (!res.value) + res.valid = isl_bool_error; + return res; +error: + res.valid = isl_bool_error; + res.value = NULL; + return res; +} + +/* If "hmap" contains a value associated to "key", then return + * isl_bool_true. Otherwise, return isl_bool_false. + * Return isl_bool_error on error. + */ +isl_bool ISL_FN(ISL_HMAP,has)(__isl_keep ISL_HMAP *hmap, + __isl_keep ISL_KEY *key) +{ + ISL_MAYBE(ISL_VAL) res; + + res = ISL_FN(ISL_HMAP,try_get)(hmap, key); + ISL_FN(ISL_VAL,free)(res.value); + + return res.valid; +} + +/* If "hmap" contains a value associated to "key", then return + * a copy of that value. Otherwise, return NULL. + * Return NULL on error. + */ +__isl_give ISL_VAL *ISL_FN(ISL_HMAP,get)(__isl_keep ISL_HMAP *hmap, + __isl_take ISL_KEY *key) +{ + ISL_VAL *res; + + res = ISL_FN(ISL_HMAP,try_get)(hmap, key).value; + ISL_FN(ISL_KEY,free)(key); + return res; +} + +/* Remove the mapping between "key" and its associated value (if any) + * from "hmap". + * + * If "key" is not mapped to anything, then we leave "hmap" untouched" + */ +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,drop)(__isl_take ISL_HMAP *hmap, + __isl_take ISL_KEY *key) +{ + struct isl_hash_table_entry *entry; + ISL_S(pair) *pair; + uint32_t hash; + + if (!hmap || !key) + goto error; + + hash = ISL_FN(ISL_KEY,get_hash)(key); + entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash, + &has_key, key, 0); + if (!entry) { + ISL_FN(ISL_KEY,free)(key); + return hmap; + } + + hmap = ISL_FN(ISL_HMAP,cow)(hmap); + if (!hmap) + goto error; + entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash, + &has_key, key, 0); + ISL_FN(ISL_KEY,free)(key); + + if (!entry) + isl_die(hmap->ctx, isl_error_internal, + "missing entry" , goto error); + + pair = entry->data; + isl_hash_table_remove(hmap->ctx, &hmap->table, entry); + ISL_FN(ISL_KEY,free)(pair->key); + ISL_FN(ISL_VAL,free)(pair->val); + free(pair); + + return hmap; +error: + ISL_FN(ISL_KEY,free)(key); + ISL_FN(ISL_HMAP,free)(hmap); + return NULL; +} + +/* Add a mapping from "key" to "val" to "hmap". + * If "key" was already mapped to something else, then that mapping + * is replaced. + * If key happened to be mapped to "val" already, then we leave + * "hmap" untouched. + */ +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,set)(__isl_take ISL_HMAP *hmap, + __isl_take ISL_KEY *key, __isl_take ISL_VAL *val) +{ + struct isl_hash_table_entry *entry; + ISL_S(pair) *pair; + uint32_t hash; + + if (!hmap || !key || !val) + goto error; + + hash = ISL_FN(ISL_KEY,get_hash)(key); + entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash, + &has_key, key, 0); + if (entry) { + int equal; + pair = entry->data; + equal = ISL_VAL_IS_EQUAL(pair->val, val); + if (equal < 0) + goto error; + if (equal) { + ISL_FN(ISL_KEY,free)(key); + ISL_FN(ISL_VAL,free)(val); + return hmap; + } + } + + hmap = ISL_FN(ISL_HMAP,cow)(hmap); + if (!hmap) + goto error; + + entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash, + &has_key, key, 1); + + if (!entry) + goto error; + + if (entry->data) { + pair = entry->data; + ISL_FN(ISL_VAL,free)(pair->val); + pair->val = val; + ISL_FN(ISL_KEY,free)(key); + return hmap; + } + + pair = isl_alloc_type(hmap->ctx, ISL_S(pair)); + if (!pair) + goto error; + + entry->data = pair; + pair->key = key; + pair->val = val; + return hmap; +error: + ISL_FN(ISL_KEY,free)(key); + ISL_FN(ISL_VAL,free)(val); + return ISL_FN(ISL_HMAP,free)(hmap); +} + +/* Internal data structure for isl_map_to_basic_set_foreach. + * + * fn is the function that should be called on each entry. + * user is the user-specified final argument to fn. + */ +ISL_S(foreach_data) { + isl_stat (*fn)(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val, + void *user); + void *user; +}; + +/* Call data->fn on a copy of the key and value in *entry. + */ +static isl_stat call_on_copy(void **entry, void *user) +{ + ISL_S(pair) *pair = *entry; + ISL_S(foreach_data) *data = (ISL_S(foreach_data) *) user; + + return data->fn(ISL_FN(ISL_KEY,copy)(pair->key), + ISL_FN(ISL_VAL,copy)(pair->val), data->user); +} + +/* Call "fn" on each pair of key and value in "hmap". + */ +isl_stat ISL_FN(ISL_HMAP,foreach)(__isl_keep ISL_HMAP *hmap, + isl_stat (*fn)(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val, + void *user), + void *user) +{ + ISL_S(foreach_data) data = { fn, user }; + + if (!hmap) + return isl_stat_error; + + return isl_hash_table_foreach(hmap->ctx, &hmap->table, + &call_on_copy, &data); +} + +/* Internal data structure for print_pair. + * + * p is the printer on which the associative array is being printed. + * first is set if the current key-value pair is the first to be printed. + */ +ISL_S(print_data) { + isl_printer *p; + int first; +}; + +/* Print the given key-value pair to data->p. + */ +static isl_stat print_pair(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val, + void *user) +{ + ISL_S(print_data) *data = user; + + if (!data->first) + data->p = isl_printer_print_str(data->p, ", "); + data->p = ISL_KEY_PRINT(data->p, key); + data->p = isl_printer_print_str(data->p, ": "); + data->p = ISL_VAL_PRINT(data->p, val); + data->first = 0; + + ISL_FN(ISL_KEY,free)(key); + ISL_FN(ISL_VAL,free)(val); + return isl_stat_ok; +} + +/* Print the associative array to "p". + */ +__isl_give isl_printer *ISL_FN(isl_printer_print,ISL_HMAP_SUFFIX)( + __isl_take isl_printer *p, __isl_keep ISL_HMAP *hmap) +{ + ISL_S(print_data) data; + + if (!p || !hmap) + return isl_printer_free(p); + + p = isl_printer_print_str(p, "{"); + data.p = p; + data.first = 1; + if (ISL_FN(ISL_HMAP,foreach)(hmap, &print_pair, &data) < 0) + data.p = isl_printer_free(data.p); + p = data.p; + p = isl_printer_print_str(p, "}"); + + return p; +} + +void ISL_FN(ISL_HMAP,dump)(__isl_keep ISL_HMAP *hmap) +{ + isl_printer *printer; + + if (!hmap) + return; + + printer = isl_printer_to_file(ISL_FN(ISL_HMAP,get_ctx)(hmap), stderr); + printer = ISL_FN(isl_printer_print,ISL_HMAP_SUFFIX)(printer, hmap); + printer = isl_printer_end_line(printer); + + isl_printer_free(printer); +} Index: contrib/isl/include/isl/id.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/id.h @@ -0,0 +1,41 @@ +#ifndef ISL_ID_H +#define ISL_ID_H + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_id; +typedef struct isl_id isl_id; + +ISL_DECLARE_LIST(id) + +isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id); +uint32_t isl_id_get_hash(__isl_keep isl_id *id); + +__isl_give isl_id *isl_id_alloc(isl_ctx *ctx, + __isl_keep const char *name, void *user); +__isl_give isl_id *isl_id_copy(isl_id *id); +__isl_null isl_id *isl_id_free(__isl_take isl_id *id); + +void *isl_id_get_user(__isl_keep isl_id *id); +__isl_keep const char *isl_id_get_name(__isl_keep isl_id *id); + +__isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, + void (*free_user)(void *user)); + +__isl_give char *isl_id_to_str(__isl_keep isl_id *id); +__isl_give isl_printer *isl_printer_print_id(__isl_take isl_printer *p, + __isl_keep isl_id *id); +void isl_id_dump(__isl_keep isl_id *id); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/id_to_ast_expr.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/id_to_ast_expr.h @@ -0,0 +1,18 @@ +#ifndef ISL_ID_TO_AST_EXPR_H +#define ISL_ID_TO_AST_EXPR_H + +#include +#include +#include + +#define ISL_KEY isl_id +#define ISL_VAL isl_ast_expr +#define ISL_HMAP_SUFFIX id_to_ast_expr +#define ISL_HMAP isl_id_to_ast_expr +#include +#undef ISL_KEY +#undef ISL_VAL +#undef ISL_HMAP_SUFFIX +#undef ISL_HMAP + +#endif Index: contrib/isl/include/isl/id_to_id.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/id_to_id.h @@ -0,0 +1,17 @@ +#ifndef ISL_ID_TO_ID_H +#define ISL_ID_TO_ID_H + +#include +#include + +#define ISL_KEY isl_id +#define ISL_VAL isl_id +#define ISL_HMAP_SUFFIX id_to_id +#define ISL_HMAP isl_id_to_id +#include +#undef ISL_KEY +#undef ISL_VAL +#undef ISL_HMAP_SUFFIX +#undef ISL_HMAP + +#endif Index: contrib/isl/include/isl/id_to_pw_aff.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/id_to_pw_aff.h @@ -0,0 +1,18 @@ +#ifndef ISL_ID_TO_PW_AFF_H +#define ISL_ID_TO_PW_AFF_H + +#include +#include +#include + +#define ISL_KEY isl_id +#define ISL_VAL isl_pw_aff +#define ISL_HMAP_SUFFIX id_to_pw_aff +#define ISL_HMAP isl_id_to_pw_aff +#include +#undef ISL_KEY +#undef ISL_VAL +#undef ISL_HMAP_SUFFIX +#undef ISL_HMAP + +#endif Index: contrib/isl/include/isl/ilp.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/ilp.h @@ -0,0 +1,38 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_ILP_H +#define ISL_ILP_H + +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_val *isl_basic_set_max_val(__isl_keep isl_basic_set *bset, + __isl_keep isl_aff *obj); +__isl_export +__isl_give isl_val *isl_set_min_val(__isl_keep isl_set *set, + __isl_keep isl_aff *obj); +__isl_export +__isl_give isl_val *isl_set_max_val(__isl_keep isl_set *set, + __isl_keep isl_aff *obj); +__isl_give isl_multi_val *isl_union_set_min_multi_union_pw_aff( + __isl_keep isl_union_set *set, __isl_keep isl_multi_union_pw_aff *obj); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/list.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/list.h @@ -0,0 +1,81 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_LIST_H +#define ISL_LIST_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#define ISL_DECLARE_LIST_TYPE(EL) \ +struct isl_##EL; \ +struct isl_##EL##_list; \ +typedef struct isl_##EL##_list isl_##EL##_list; +#define ISL_DECLARE_LIST_FN(EL) \ +isl_ctx *isl_##EL##_list_get_ctx(__isl_keep isl_##EL##_list *list); \ +__isl_give isl_##EL##_list *isl_##EL##_list_from_##EL( \ + __isl_take struct isl_##EL *el); \ +__isl_give isl_##EL##_list *isl_##EL##_list_alloc(isl_ctx *ctx, int n); \ +__isl_give isl_##EL##_list *isl_##EL##_list_copy( \ + __isl_keep isl_##EL##_list *list); \ +__isl_null isl_##EL##_list *isl_##EL##_list_free( \ + __isl_take isl_##EL##_list *list); \ +__isl_give isl_##EL##_list *isl_##EL##_list_add( \ + __isl_take isl_##EL##_list *list, \ + __isl_take struct isl_##EL *el); \ +__isl_give isl_##EL##_list *isl_##EL##_list_insert( \ + __isl_take isl_##EL##_list *list, unsigned pos, \ + __isl_take struct isl_##EL *el); \ +__isl_give isl_##EL##_list *isl_##EL##_list_drop( \ + __isl_take isl_##EL##_list *list, unsigned first, unsigned n); \ +__isl_give isl_##EL##_list *isl_##EL##_list_concat( \ + __isl_take isl_##EL##_list *list1, \ + __isl_take isl_##EL##_list *list2); \ +int isl_##EL##_list_n_##EL(__isl_keep isl_##EL##_list *list); \ +__isl_give struct isl_##EL *isl_##EL##_list_get_##EL( \ + __isl_keep isl_##EL##_list *list, int index); \ +__isl_give struct isl_##EL##_list *isl_##EL##_list_set_##EL( \ + __isl_take struct isl_##EL##_list *list, int index, \ + __isl_take struct isl_##EL *el); \ +isl_stat isl_##EL##_list_foreach(__isl_keep isl_##EL##_list *list, \ + isl_stat (*fn)(__isl_take struct isl_##EL *el, void *user), \ + void *user); \ +__isl_give isl_##EL##_list *isl_##EL##_list_map( \ + __isl_take isl_##EL##_list *list, \ + __isl_give isl_##EL * (*fn)(__isl_take isl_##EL *el, \ + void *user), \ + void *user); \ +__isl_give isl_##EL##_list *isl_##EL##_list_sort( \ + __isl_take isl_##EL##_list *list, \ + int (*cmp)(__isl_keep struct isl_##EL *a, \ + __isl_keep struct isl_##EL *b, \ + void *user), void *user); \ +isl_stat isl_##EL##_list_foreach_scc(__isl_keep isl_##EL##_list *list, \ + isl_bool (*follows)(__isl_keep struct isl_##EL *a, \ + __isl_keep struct isl_##EL *b, void *user), \ + void *follows_user, \ + isl_stat (*fn)(__isl_take isl_##EL##_list *scc, void *user), \ + void *fn_user); \ +__isl_give isl_printer *isl_printer_print_##EL##_list( \ + __isl_take isl_printer *p, __isl_keep isl_##EL##_list *list); \ +void isl_##EL##_list_dump(__isl_keep isl_##EL##_list *list); + +#define ISL_DECLARE_LIST(EL) \ + ISL_DECLARE_LIST_TYPE(EL) \ + ISL_DECLARE_LIST_FN(EL) + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/local_space.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/local_space.h @@ -0,0 +1,95 @@ +#ifndef ISL_LOCAL_SPACE_H +#define ISL_LOCAL_SPACE_H + +#include +#include +#include +#include + +#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_space(__isl_take isl_space *dim); + +__isl_give isl_local_space *isl_local_space_copy( + __isl_keep isl_local_space *ls); +__isl_null isl_local_space *isl_local_space_free( + __isl_take isl_local_space *ls); + +isl_bool isl_local_space_is_params(__isl_keep isl_local_space *ls); +isl_bool isl_local_space_is_set(__isl_keep isl_local_space *ls); + +__isl_give isl_local_space *isl_local_space_set_tuple_id( + __isl_take isl_local_space *ls, + enum isl_dim_type type, __isl_take isl_id *id); + +int isl_local_space_dim(__isl_keep isl_local_space *ls, + enum isl_dim_type type); +isl_bool isl_local_space_has_dim_name(__isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos); +const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos); +__isl_give isl_local_space *isl_local_space_set_dim_name( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, const char *s); +isl_bool isl_local_space_has_dim_id(__isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos); +__isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos); +__isl_give isl_local_space *isl_local_space_set_dim_id( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); +__isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls); +__isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls, + int pos); + +int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls, + enum isl_dim_type type, const char *name); + +__isl_give isl_local_space *isl_local_space_domain( + __isl_take isl_local_space *ls); +__isl_give isl_local_space *isl_local_space_range( + __isl_take isl_local_space *ls); +__isl_give isl_local_space *isl_local_space_from_domain( + __isl_take isl_local_space *ls); +__isl_give isl_local_space *isl_local_space_add_dims( + __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n); +__isl_give isl_local_space *isl_local_space_drop_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_local_space *isl_local_space_insert_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_local_space *isl_local_space_intersect( + __isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2); + +__isl_give isl_local_space *isl_local_space_wrap( + __isl_take isl_local_space *ls); + +isl_bool isl_local_space_is_equal(__isl_keep isl_local_space *ls1, + __isl_keep isl_local_space *ls2); + +__isl_give isl_basic_map *isl_local_space_lifting( + __isl_take isl_local_space *ls); + +__isl_give isl_local_space *isl_local_space_flatten_domain( + __isl_take isl_local_space *ls); +__isl_give isl_local_space *isl_local_space_flatten_range( + __isl_take isl_local_space *ls); + +__isl_give isl_printer *isl_printer_print_local_space(__isl_take isl_printer *p, + __isl_keep isl_local_space *ls); +void isl_local_space_dump(__isl_keep isl_local_space *ls); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/lp.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/lp.h @@ -0,0 +1,37 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_LP_H +#define ISL_LP_H + +#include +#include +#include + +enum isl_lp_result { + isl_lp_error = -1, + isl_lp_ok = 0, + isl_lp_unbounded, + isl_lp_empty +}; + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_val *isl_basic_set_min_lp_val(__isl_keep isl_basic_set *bset, + __isl_keep isl_aff *obj); +__isl_give isl_val *isl_basic_set_max_lp_val(__isl_keep isl_basic_set *bset, + __isl_keep isl_aff *obj); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/map.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/map.h @@ -0,0 +1,675 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_MAP_H +#define ISL_MAP_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +ISL_DEPRECATED +unsigned isl_basic_map_n_in(__isl_keep const isl_basic_map *bmap); +ISL_DEPRECATED +unsigned isl_basic_map_n_out(__isl_keep const isl_basic_map *bmap); +ISL_DEPRECATED +unsigned isl_basic_map_n_param(__isl_keep const isl_basic_map *bmap); +ISL_DEPRECATED +unsigned isl_basic_map_n_div(__isl_keep const isl_basic_map *bmap); +unsigned isl_basic_map_total_dim(__isl_keep const isl_basic_map *bmap); +unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type); + +ISL_DEPRECATED +unsigned isl_map_n_in(__isl_keep const isl_map *map); +ISL_DEPRECATED +unsigned isl_map_n_out(__isl_keep const isl_map *map); +ISL_DEPRECATED +unsigned isl_map_n_param(__isl_keep const isl_map *map); +unsigned isl_map_dim(__isl_keep isl_map *map, enum isl_dim_type type); + +isl_ctx *isl_basic_map_get_ctx(__isl_keep isl_basic_map *bmap); +isl_ctx *isl_map_get_ctx(__isl_keep isl_map *map); +__isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap); +__isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map); + +__isl_give isl_aff *isl_basic_map_get_div(__isl_keep 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, + enum isl_dim_type type); +isl_bool isl_map_has_tuple_name(__isl_keep isl_map *map, + enum isl_dim_type type); +const char *isl_map_get_tuple_name(__isl_keep isl_map *map, + enum isl_dim_type type); +__isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map, + enum isl_dim_type type, const char *s); +const char *isl_basic_map_get_dim_name(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos); +isl_bool isl_map_has_dim_name(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); +const char *isl_map_get_dim_name(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); +__isl_give isl_basic_map *isl_basic_map_set_dim_name( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, const char *s); +__isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, const char *s); + +__isl_give isl_basic_map *isl_basic_map_set_tuple_id( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, __isl_take isl_id *id); +__isl_give isl_map *isl_map_set_dim_id(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); +isl_bool isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos); +isl_bool isl_map_has_dim_id(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); +__isl_give isl_id *isl_map_get_dim_id(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); +__isl_give isl_map *isl_map_set_tuple_id(__isl_take isl_map *map, + enum isl_dim_type type, __isl_take isl_id *id); +__isl_give isl_map *isl_map_reset_tuple_id(__isl_take isl_map *map, + enum isl_dim_type type); +isl_bool isl_map_has_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type); +__isl_give isl_id *isl_map_get_tuple_id(__isl_keep isl_map *map, + enum isl_dim_type type); +__isl_give isl_map *isl_map_reset_user(__isl_take isl_map *map); + +int isl_basic_map_find_dim_by_name(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, const char *name); +int isl_map_find_dim_by_id(__isl_keep isl_map *map, enum isl_dim_type type, + __isl_keep isl_id *id); +int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type, + const char *name); + +isl_bool isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap); + +__isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_space *dim); +__isl_null isl_basic_map *isl_basic_map_free(__isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_copy(__isl_keep isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_equal( + __isl_take isl_space *dim, unsigned n_equal); +__isl_give isl_basic_map *isl_basic_map_less_at(__isl_take isl_space *dim, + unsigned pos); +__isl_give isl_basic_map *isl_basic_map_more_at(__isl_take isl_space *dim, + unsigned pos); +__isl_give isl_basic_map *isl_basic_map_empty(__isl_take isl_space *space); +__isl_give isl_basic_map *isl_basic_map_universe(__isl_take isl_space *space); +__isl_give isl_basic_map *isl_basic_map_nat_universe(__isl_take isl_space *dim); +__isl_give isl_basic_map *isl_basic_map_remove_redundancies( + __isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_remove_redundancies(__isl_take isl_map *map); +__isl_give isl_basic_map *isl_map_simple_hull(__isl_take isl_map *map); +__isl_export +__isl_give isl_basic_map *isl_map_unshifted_simple_hull( + __isl_take isl_map *map); +__isl_give isl_basic_map *isl_map_plain_unshifted_simple_hull( + __isl_take isl_map *map); +__isl_give isl_basic_map *isl_map_unshifted_simple_hull_from_map_list( + __isl_take isl_map *map, __isl_take isl_map_list *list); + +__isl_export +__isl_give isl_basic_map *isl_basic_map_intersect_domain( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *bset); +__isl_export +__isl_give isl_basic_map *isl_basic_map_intersect_range( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *bset); +__isl_export +__isl_give isl_basic_map *isl_basic_map_intersect( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); +__isl_give isl_basic_map *isl_basic_map_list_intersect( + __isl_take isl_basic_map_list *list); +__isl_export +__isl_give isl_map *isl_basic_map_union( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); +__isl_export +__isl_give isl_basic_map *isl_basic_map_apply_domain( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); +__isl_export +__isl_give isl_basic_map *isl_basic_map_apply_range( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); +__isl_export +__isl_give isl_basic_map *isl_basic_map_affine_hull( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_preimage_domain_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma); +__isl_give isl_basic_map *isl_basic_map_preimage_range_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma); +__isl_export +__isl_give isl_basic_map *isl_basic_map_reverse(__isl_take isl_basic_map *bmap); +__isl_give isl_basic_set *isl_basic_map_domain(__isl_take isl_basic_map *bmap); +__isl_give isl_basic_set *isl_basic_map_range(__isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_domain_map( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_range_map( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_remove_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_map *isl_basic_map_eliminate( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_export +__isl_give isl_basic_map *isl_basic_map_sample(__isl_take isl_basic_map *bmap); +__isl_export +__isl_give isl_basic_map *isl_basic_map_detect_equalities( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx, + FILE *input); +__isl_constructor +__isl_give isl_basic_map *isl_basic_map_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give isl_map *isl_map_read_from_file(isl_ctx *ctx, FILE *input); +__isl_constructor +__isl_give isl_map *isl_map_read_from_str(isl_ctx *ctx, const char *str); +void isl_basic_map_dump(__isl_keep isl_basic_map *bmap); +void isl_map_dump(__isl_keep isl_map *map); +__isl_give char *isl_basic_map_to_str(__isl_keep isl_basic_map *bmap); +__isl_give isl_printer *isl_printer_print_basic_map( + __isl_take isl_printer *printer, __isl_keep isl_basic_map *bmap); +__isl_give char *isl_map_to_str(__isl_keep isl_map *map); +__isl_give isl_printer *isl_printer_print_map(__isl_take isl_printer *printer, + __isl_keep isl_map *map); +__isl_give isl_basic_map *isl_basic_map_fix_si(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value); +__isl_give isl_basic_map *isl_basic_map_fix_val(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v); +__isl_give isl_basic_map *isl_basic_map_lower_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value); +__isl_give isl_basic_map *isl_basic_map_upper_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value); + +__isl_give isl_basic_map *isl_basic_map_sum(__isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); +__isl_give isl_basic_map *isl_basic_map_neg(__isl_take isl_basic_map *bmap); + +__isl_give isl_map *isl_map_sum(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_neg(__isl_take isl_map *map); +__isl_give isl_map *isl_map_floordiv_val(__isl_take isl_map *map, + __isl_take isl_val *d); + +__isl_export +isl_bool isl_basic_map_is_equal(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); +isl_bool isl_basic_map_is_disjoint(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); + +__isl_give isl_map *isl_basic_map_partial_lexmax( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); +__isl_give isl_map *isl_basic_map_partial_lexmin( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); +__isl_give isl_map *isl_map_partial_lexmax( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty); +__isl_give isl_map *isl_map_partial_lexmin( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty); +__isl_export +__isl_give isl_map *isl_basic_map_lexmin(__isl_take isl_basic_map *bmap); +__isl_export +__isl_give isl_map *isl_basic_map_lexmax(__isl_take isl_basic_map *bmap); +__isl_export +__isl_give isl_map *isl_map_lexmin(__isl_take isl_map *map); +__isl_export +__isl_give isl_map *isl_map_lexmax(__isl_take isl_map *map); +__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmin_pw_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); +__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmax_pw_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); +__isl_give isl_pw_multi_aff *isl_basic_map_lexmin_pw_multi_aff( + __isl_take isl_basic_map *bmap); +__isl_give isl_pw_multi_aff *isl_map_lexmin_pw_multi_aff( + __isl_take isl_map *map); +__isl_give isl_pw_multi_aff *isl_map_lexmax_pw_multi_aff( + __isl_take isl_map *map); + +void isl_basic_map_print_internal(__isl_keep isl_basic_map *bmap, + FILE *out, int indent); + +__isl_give isl_val *isl_basic_map_plain_get_val_if_fixed( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos); + +isl_bool isl_basic_map_image_is_bounded(__isl_keep isl_basic_map *bmap); +isl_bool isl_basic_map_plain_is_universe(__isl_keep isl_basic_map *bmap); +isl_bool isl_basic_map_is_universe(__isl_keep isl_basic_map *bmap); +isl_bool isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap); +__isl_export +isl_bool isl_basic_map_is_empty(__isl_keep isl_basic_map *bmap); +__isl_export +isl_bool isl_basic_map_is_subset(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); +isl_bool isl_basic_map_is_strict_subset(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); + +__isl_give isl_map *isl_map_universe(__isl_take isl_space *space); +__isl_give isl_map *isl_map_nat_universe(__isl_take isl_space *dim); +__isl_give isl_map *isl_map_empty(__isl_take isl_space *space); +__isl_give isl_map *isl_map_identity(__isl_take isl_space *dim); +__isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_space *dim, unsigned n); +__isl_give isl_map *isl_map_lex_le_first(__isl_take isl_space *dim, unsigned n); +__isl_give isl_map *isl_map_lex_lt(__isl_take isl_space *set_dim); +__isl_give isl_map *isl_map_lex_le(__isl_take isl_space *set_dim); +__isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_space *dim, unsigned n); +__isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_space *dim, unsigned n); +__isl_give isl_map *isl_map_lex_gt(__isl_take isl_space *set_dim); +__isl_give isl_map *isl_map_lex_ge(__isl_take isl_space *set_dim); +__isl_null isl_map *isl_map_free(__isl_take isl_map *map); +__isl_give isl_map *isl_map_copy(__isl_keep isl_map *map); +__isl_export +__isl_give isl_map *isl_map_reverse(__isl_take isl_map *map); +__isl_export +__isl_give isl_map *isl_map_union( + __isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_union_disjoint( + __isl_take isl_map *map1, __isl_take isl_map *map2); +__isl_export +__isl_give isl_map *isl_map_intersect_domain( + __isl_take isl_map *map, + __isl_take isl_set *set); +__isl_export +__isl_give isl_map *isl_map_intersect_range( + __isl_take isl_map *map, + __isl_take isl_set *set); +__isl_give isl_map *isl_map_intersect_domain_factor_range( + __isl_take isl_map *map, __isl_take isl_map *factor); +__isl_give isl_map *isl_map_intersect_range_factor_range( + __isl_take isl_map *map, __isl_take isl_map *factor); +__isl_export +__isl_give isl_map *isl_map_apply_domain( + __isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_export +__isl_give isl_map *isl_map_apply_range( + __isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map, + __isl_take isl_multi_aff *ma); +__isl_give isl_map *isl_map_preimage_range_multi_aff(__isl_take isl_map *map, + __isl_take isl_multi_aff *ma); +__isl_give isl_map *isl_map_preimage_domain_pw_multi_aff( + __isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma); +__isl_give isl_map *isl_map_preimage_range_pw_multi_aff( + __isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma); +__isl_give isl_map *isl_map_preimage_domain_multi_pw_aff( + __isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa); +__isl_give isl_basic_map *isl_basic_map_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); +__isl_give isl_map *isl_map_product(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_basic_map *isl_basic_map_domain_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); +__isl_give isl_basic_map *isl_basic_map_range_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); +__isl_give isl_map *isl_map_domain_product(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_basic_map *isl_basic_map_flat_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); +__isl_give isl_map *isl_map_flat_product(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_basic_map *isl_basic_map_flat_range_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); +__isl_give isl_map *isl_map_flat_domain_product(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_flat_range_product(__isl_take isl_map *map1, + __isl_take isl_map *map2); +isl_bool isl_map_domain_is_wrapping(__isl_keep isl_map *map); +isl_bool isl_map_range_is_wrapping(__isl_keep isl_map *map); +isl_bool isl_map_is_product(__isl_keep isl_map *map); +__isl_give isl_map *isl_map_factor_domain(__isl_take isl_map *map); +__isl_give isl_map *isl_map_factor_range(__isl_take isl_map *map); +__isl_give isl_map *isl_map_domain_factor_domain(__isl_take isl_map *map); +__isl_give isl_map *isl_map_domain_factor_range(__isl_take isl_map *map); +__isl_give isl_map *isl_map_range_factor_domain(__isl_take isl_map *map); +__isl_give isl_map *isl_map_range_factor_range(__isl_take isl_map *map); +__isl_export +__isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_export +__isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map, + __isl_take isl_set *params); +__isl_export +__isl_give isl_map *isl_map_subtract( + __isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_subtract_domain(__isl_take isl_map *map, + __isl_take isl_set *dom); +__isl_give isl_map *isl_map_subtract_range(__isl_take isl_map *map, + __isl_take isl_set *dom); +__isl_export +__isl_give isl_map *isl_map_complement(__isl_take isl_map *map); +struct isl_map *isl_map_fix_input_si(struct isl_map *map, + unsigned input, int value); +__isl_give isl_map *isl_map_fix_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value); +__isl_give isl_map *isl_map_fix_val(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v); +__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value); +__isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value); +__isl_export +__isl_give isl_basic_set *isl_basic_map_deltas(__isl_take isl_basic_map *bmap); +__isl_export +__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map); +__isl_give isl_basic_map *isl_basic_map_deltas_map( + __isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map); +__isl_export +__isl_give isl_map *isl_map_detect_equalities(__isl_take isl_map *map); +__isl_export +__isl_give isl_basic_map *isl_map_affine_hull(__isl_take isl_map *map); +__isl_give isl_basic_map *isl_map_convex_hull(__isl_take isl_map *map); +__isl_export +__isl_give isl_basic_map *isl_map_polyhedral_hull(__isl_take isl_map *map); +__isl_give isl_basic_map *isl_basic_map_add_dims(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned n); +__isl_give isl_map *isl_map_add_dims(__isl_take isl_map *map, + enum isl_dim_type type, unsigned n); +__isl_give isl_basic_map *isl_basic_map_insert_dims( + __isl_take isl_basic_map *bmap, enum isl_dim_type type, + unsigned pos, unsigned n); +__isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, unsigned n); +__isl_give isl_basic_map *isl_basic_map_move_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); +__isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); +__isl_give isl_basic_map *isl_basic_map_project_out( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_map *isl_map_project_out(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_map *isl_basic_map_remove_divs( + __isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_remove_unknown_divs(__isl_take isl_map *map); +__isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map); +__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_map *isl_map_remove_dims(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_map *isl_map_remove_divs_involving_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, + unsigned first, unsigned n); + +__isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); +__isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); +__isl_give isl_map *isl_map_order_ge(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); +__isl_give isl_map *isl_map_order_le(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); +__isl_give isl_map *isl_map_equate(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); +__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); +__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); +__isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); +__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); + +__isl_export +__isl_give isl_map *isl_set_identity(__isl_take isl_set *set); + +__isl_export +isl_bool isl_basic_set_is_wrapping(__isl_keep isl_basic_set *bset); +__isl_export +isl_bool isl_set_is_wrapping(__isl_keep isl_set *set); +__isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap); +__isl_give isl_set *isl_map_wrap(__isl_take isl_map *map); +__isl_give isl_basic_map *isl_basic_set_unwrap(__isl_take isl_basic_set *bset); +__isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set); +__isl_export +__isl_give isl_basic_map *isl_basic_map_flatten(__isl_take isl_basic_map *bmap); +__isl_export +__isl_give isl_map *isl_map_flatten(__isl_take isl_map *map); +__isl_export +__isl_give isl_basic_map *isl_basic_map_flatten_domain( + __isl_take isl_basic_map *bmap); +__isl_export +__isl_give isl_basic_map *isl_basic_map_flatten_range( + __isl_take isl_basic_map *bmap); +__isl_export +__isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map); +__isl_export +__isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map); +__isl_export +__isl_give isl_basic_set *isl_basic_set_flatten(__isl_take isl_basic_set *bset); +__isl_export +__isl_give isl_set *isl_set_flatten(__isl_take isl_set *set); +__isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set); +__isl_give isl_set *isl_map_params(__isl_take isl_map *map); +__isl_give isl_set *isl_map_domain(__isl_take isl_map *bmap); +__isl_give isl_set *isl_map_range(__isl_take isl_map *map); +__isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map); +__isl_give isl_map *isl_map_range_map(__isl_take isl_map *map); +__isl_give isl_map *isl_set_wrapped_domain_map(__isl_take isl_set *set); +__isl_constructor +__isl_give isl_map *isl_map_from_basic_map(__isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set); +__isl_give isl_basic_map *isl_basic_map_from_domain( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_map *isl_basic_map_from_range( + __isl_take isl_basic_set *bset); +__isl_give isl_map *isl_map_from_range(__isl_take isl_set *set); +__isl_give isl_basic_map *isl_basic_map_from_domain_and_range( + __isl_take isl_basic_set *domain, __isl_take isl_basic_set *range); +__isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain, + __isl_take isl_set *range); +__isl_export +__isl_give isl_basic_map *isl_map_sample(__isl_take isl_map *map); + +isl_bool isl_map_plain_is_empty(__isl_keep isl_map *map); +isl_bool isl_map_plain_is_universe(__isl_keep isl_map *map); +__isl_export +isl_bool isl_map_is_empty(__isl_keep isl_map *map); +__isl_export +isl_bool isl_map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2); +__isl_export +isl_bool isl_map_is_strict_subset(__isl_keep isl_map *map1, + __isl_keep isl_map *map2); +__isl_export +isl_bool isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2); +__isl_export +isl_bool isl_map_is_disjoint(__isl_keep isl_map *map1, + __isl_keep isl_map *map2); +isl_bool isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap); +isl_bool isl_map_plain_is_single_valued(__isl_keep isl_map *map); +__isl_export +isl_bool isl_map_is_single_valued(__isl_keep isl_map *map); +isl_bool isl_map_plain_is_injective(__isl_keep isl_map *map); +__isl_export +isl_bool isl_map_is_injective(__isl_keep isl_map *map); +__isl_export +isl_bool isl_map_is_bijective(__isl_keep isl_map *map); +isl_bool isl_map_is_identity(__isl_keep isl_map *map); +int isl_map_is_translation(__isl_keep isl_map *map); +isl_bool isl_map_has_equal_space(__isl_keep isl_map *map1, + __isl_keep isl_map *map2); + +isl_bool isl_basic_map_can_zip(__isl_keep isl_basic_map *bmap); +isl_bool isl_map_can_zip(__isl_keep isl_map *map); +__isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_zip(__isl_take isl_map *map); + +isl_bool isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap); +isl_bool isl_map_can_curry(__isl_keep isl_map *map); +__isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_curry(__isl_take isl_map *map); + +isl_bool isl_map_can_range_curry(__isl_keep isl_map *map); +__isl_give isl_map *isl_map_range_curry(__isl_take isl_map *map); + +isl_bool isl_basic_map_can_uncurry(__isl_keep isl_basic_map *bmap); +isl_bool isl_map_can_uncurry(__isl_keep isl_map *map); +__isl_give isl_basic_map *isl_basic_map_uncurry(__isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_uncurry(__isl_take isl_map *map); + +__isl_give isl_map *isl_map_make_disjoint(__isl_take isl_map *map); +__isl_give isl_map *isl_basic_map_compute_divs(__isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_compute_divs(__isl_take isl_map *map); +ISL_DEPRECATED +__isl_give isl_map *isl_map_align_divs(__isl_take isl_map *map); + +__isl_give isl_basic_map *isl_basic_map_drop_constraints_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_map *isl_basic_map_drop_constraints_not_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_map *isl_map_drop_constraints_involving_dims( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_map *isl_map_drop_constraints_not_involving_dims( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); + +isl_bool isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); +isl_bool isl_map_involves_dims(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); + +void isl_map_print_internal(__isl_keep isl_map *map, FILE *out, int indent); + +__isl_give isl_val *isl_map_plain_get_val_if_fixed(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos); + +__isl_give isl_basic_map *isl_basic_map_gist_domain( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *context); +__isl_export +__isl_give isl_basic_map *isl_basic_map_gist(__isl_take isl_basic_map *bmap, + __isl_take isl_basic_map *context); +__isl_export +__isl_give isl_map *isl_map_gist(__isl_take isl_map *map, + __isl_take isl_map *context); +__isl_export +__isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map, + __isl_take isl_set *context); +__isl_give isl_map *isl_map_gist_range(__isl_take isl_map *map, + __isl_take isl_set *context); +__isl_give isl_map *isl_map_gist_params(__isl_take isl_map *map, + __isl_take isl_set *context); +__isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map, + __isl_take isl_basic_map *context); + +__isl_export +__isl_give isl_map *isl_map_coalesce(__isl_take isl_map *map); + +isl_bool isl_map_plain_is_equal(__isl_keep isl_map *map1, + __isl_keep isl_map *map2); + +uint32_t isl_map_get_hash(__isl_keep isl_map *map); + +int isl_map_n_basic_map(__isl_keep isl_map *map); +__isl_export +isl_stat isl_map_foreach_basic_map(__isl_keep isl_map *map, + isl_stat (*fn)(__isl_take isl_basic_map *bmap, void *user), void *user); + +__isl_give isl_map *isl_map_fixed_power_val(__isl_take isl_map *map, + __isl_take isl_val *exp); +__isl_give isl_map *isl_map_power(__isl_take isl_map *map, int *exact); +__isl_give isl_map *isl_map_reaching_path_lengths(__isl_take isl_map *map, + int *exact); +__isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map, + int *exact); + +__isl_give isl_map *isl_map_lex_le_map(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_lex_lt_map(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1, + __isl_take isl_map *map2); +__isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1, + __isl_take isl_map *map2); + +__isl_give isl_basic_map *isl_basic_map_align_params( + __isl_take isl_basic_map *bmap, __isl_take isl_space *model); +__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map, + __isl_take isl_space *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, + enum isl_dim_type c4, enum isl_dim_type c5); +__isl_give isl_mat *isl_basic_map_inequalities_matrix( + __isl_keep isl_basic_map *bmap, enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, + enum isl_dim_type c4, enum isl_dim_type c5); +__isl_give isl_basic_map *isl_basic_map_from_constraint_matrices( + __isl_take isl_space *dim, + __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, + enum isl_dim_type c4, enum isl_dim_type c5); + +__isl_give isl_basic_map *isl_basic_map_from_aff(__isl_take isl_aff *aff); +__isl_give isl_basic_map *isl_basic_map_from_multi_aff( + __isl_take isl_multi_aff *maff); +__isl_give isl_basic_map *isl_basic_map_from_aff_list( + __isl_take isl_space *domain_dim, __isl_take isl_aff_list *list); + +__isl_give isl_map *isl_map_from_aff(__isl_take isl_aff *aff); +__isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff); + +__isl_give isl_pw_aff *isl_map_dim_min(__isl_take isl_map *map, int pos); +__isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos); + +ISL_DECLARE_LIST_FN(basic_map) +ISL_DECLARE_LIST_FN(map) + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/map_to_basic_set.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/map_to_basic_set.h @@ -0,0 +1,18 @@ +#ifndef ISL_MAP_TO_BASIC_SET_H +#define ISL_MAP_TO_BASIC_SET_H + +#include +#include +#include + +#define ISL_KEY isl_map +#define ISL_VAL isl_basic_set +#define ISL_HMAP_SUFFIX map_to_basic_set +#define ISL_HMAP isl_map_to_basic_set +#include +#undef ISL_KEY +#undef ISL_VAL +#undef ISL_HMAP_SUFFIX +#undef ISL_HMAP + +#endif Index: contrib/isl/include/isl/map_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/map_type.h @@ -0,0 +1,37 @@ +#ifndef ISL_MAP_TYPE_H +#define ISL_MAP_TYPE_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct __isl_subclass(isl_map) isl_basic_map; +typedef struct isl_basic_map isl_basic_map; +ISL_DECLARE_LIST_TYPE(basic_map) +struct __isl_subclass(isl_union_map) isl_map; +typedef struct isl_map isl_map; +ISL_DECLARE_LIST_TYPE(map) + +#ifndef isl_basic_set +struct __isl_subclass(isl_set) isl_basic_set; +typedef struct isl_basic_set isl_basic_set; +ISL_DECLARE_LIST_TYPE(basic_set) +#endif + +#ifndef isl_set +struct __isl_subclass(isl_union_set) isl_set; +typedef struct isl_set isl_set; +ISL_DECLARE_LIST_TYPE(set) +#endif + +ISL_DECLARE_LIST_FN(basic_set) +ISL_DECLARE_LIST_FN(set) + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/mat.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/mat.h @@ -0,0 +1,121 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_MAT_H +#define ISL_MAT_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +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(isl_ctx *ctx, + unsigned n_row, unsigned n_col); +__isl_give isl_mat *isl_mat_dup(__isl_keep isl_mat *mat); +struct isl_mat *isl_mat_extend(struct isl_mat *mat, + unsigned n_row, unsigned n_col); +struct isl_mat *isl_mat_identity(struct isl_ctx *ctx, unsigned n_row); +__isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat); +__isl_give isl_mat *isl_mat_cow(__isl_take isl_mat *mat); +__isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat); + +int isl_mat_rows(__isl_keep isl_mat *mat); +int isl_mat_cols(__isl_keep isl_mat *mat); +__isl_give isl_val *isl_mat_get_element_val(__isl_keep isl_mat *mat, + int row, int col); +__isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat, + int row, int col, int v); +__isl_give isl_mat *isl_mat_set_element_val(__isl_take isl_mat *mat, + int row, int col, __isl_take isl_val *v); + +__isl_give isl_mat *isl_mat_swap_cols(__isl_take isl_mat *mat, + unsigned i, unsigned j); +__isl_give isl_mat *isl_mat_swap_rows(__isl_take isl_mat *mat, + unsigned i, unsigned j); + +__isl_give isl_vec *isl_mat_vec_product(__isl_take isl_mat *mat, + __isl_take isl_vec *vec); +__isl_give isl_vec *isl_vec_mat_product(__isl_take isl_vec *vec, + __isl_take isl_mat *mat); +__isl_give isl_vec *isl_mat_vec_inverse_product(__isl_take isl_mat *mat, + __isl_take isl_vec *vec); +__isl_give isl_mat *isl_mat_aff_direct_sum(__isl_take isl_mat *left, + __isl_take isl_mat *right); +__isl_give isl_mat *isl_mat_diagonal(__isl_take isl_mat *mat1, + __isl_take isl_mat *mat2); +__isl_give isl_mat *isl_mat_left_hermite(__isl_take isl_mat *M, int neg, + __isl_give isl_mat **U, __isl_give isl_mat **Q); +__isl_give isl_mat *isl_mat_lin_to_aff(__isl_take isl_mat *mat); +__isl_give isl_mat *isl_mat_inverse_product(__isl_take isl_mat *left, + __isl_take isl_mat *right); +__isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left, + __isl_take isl_mat *right); +__isl_give isl_mat *isl_mat_transpose(__isl_take isl_mat *mat); +__isl_give isl_mat *isl_mat_right_inverse(__isl_take isl_mat *mat); +__isl_give isl_mat *isl_mat_right_kernel(__isl_take isl_mat *mat); + +__isl_give isl_mat *isl_mat_normalize(__isl_take isl_mat *mat); +__isl_give isl_mat *isl_mat_normalize_row(__isl_take isl_mat *mat, int row); + +__isl_give isl_mat *isl_mat_drop_cols(__isl_take isl_mat *mat, + unsigned col, unsigned n); +__isl_give isl_mat *isl_mat_drop_rows(__isl_take isl_mat *mat, + unsigned row, unsigned n); +__isl_give isl_mat *isl_mat_insert_cols(__isl_take isl_mat *mat, + unsigned col, unsigned n); +__isl_give isl_mat *isl_mat_insert_rows(__isl_take isl_mat *mat, + unsigned row, unsigned n); +__isl_give isl_mat *isl_mat_move_cols(__isl_take isl_mat *mat, + unsigned dst_col, unsigned src_col, unsigned n); +__isl_give isl_mat *isl_mat_add_rows(__isl_take isl_mat *mat, unsigned n); +__isl_give isl_mat *isl_mat_insert_zero_cols(__isl_take isl_mat *mat, + unsigned first, unsigned n); +__isl_give isl_mat *isl_mat_add_zero_cols(__isl_take isl_mat *mat, unsigned n); +__isl_give isl_mat *isl_mat_insert_zero_rows(__isl_take isl_mat *mat, + unsigned row, unsigned n); +__isl_give isl_mat *isl_mat_add_zero_rows(__isl_take isl_mat *mat, unsigned n); + +void isl_mat_col_add(__isl_keep isl_mat *mat, int dst_col, int src_col); + +__isl_give isl_mat *isl_mat_unimodular_complete(__isl_take isl_mat *M, int row); +__isl_give isl_mat *isl_mat_row_basis(__isl_take isl_mat *mat); +__isl_give isl_mat *isl_mat_row_basis_extension( + __isl_take isl_mat *mat1, __isl_take isl_mat *mat2); + +__isl_give isl_mat *isl_mat_from_row_vec(__isl_take isl_vec *vec); +__isl_give isl_mat *isl_mat_concat(__isl_take isl_mat *top, + __isl_take isl_mat *bot); +__isl_give isl_mat *isl_mat_vec_concat(__isl_take isl_mat *top, + __isl_take isl_vec *bot); + +isl_bool isl_mat_is_equal(__isl_keep isl_mat *mat1, __isl_keep isl_mat *mat2); +isl_bool isl_mat_has_linearly_independent_rows(__isl_keep isl_mat *mat1, + __isl_keep isl_mat *mat2); + +int isl_mat_rank(__isl_keep isl_mat *mat); +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) +} +#endif + +#endif Index: contrib/isl/include/isl/maybe.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/maybe.h @@ -0,0 +1,7 @@ +#ifndef ISL_MAYBE_H +#define ISL_MAYBE_H + +#define ISL_xMAYBE(TYPE) isl_maybe_ ## TYPE +#define ISL_MAYBE(TYPE) ISL_xMAYBE(TYPE) + +#endif Index: contrib/isl/include/isl/maybe_ast_expr.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/maybe_ast_expr.h @@ -0,0 +1,8 @@ +#ifndef ISL_MAYBE_AST_EXPR_H +#define ISL_MAYBE_AST_EXPR_H + +#define ISL_TYPE isl_ast_expr +#include +#undef ISL_TYPE + +#endif Index: contrib/isl/include/isl/maybe_basic_set.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/maybe_basic_set.h @@ -0,0 +1,8 @@ +#ifndef ISL_MAYBE_BASIC_SET_H +#define ISL_MAYBE_BASIC_SET_H + +#define ISL_TYPE isl_basic_set +#include +#undef ISL_TYPE + +#endif Index: contrib/isl/include/isl/maybe_id.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/maybe_id.h @@ -0,0 +1,8 @@ +#ifndef ISL_MAYBE_ID_H +#define ISL_MAYBE_ID_H + +#define ISL_TYPE isl_id +#include +#undef ISL_TYPE + +#endif Index: contrib/isl/include/isl/maybe_pw_aff.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/maybe_pw_aff.h @@ -0,0 +1,8 @@ +#ifndef ISL_MAYBE_PW_AFF_H +#define ISL_MAYBE_PW_AFF_H + +#define ISL_TYPE isl_pw_aff +#include +#undef ISL_TYPE + +#endif Index: contrib/isl/include/isl/maybe_templ.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/maybe_templ.h @@ -0,0 +1,12 @@ +#include +#include + +/* A structure that possibly contains a pointer to an object of type ISL_TYPE. + * The pointer in "value" is only valid if "valid" is isl_bool_true. + * Otherwise, "value" is set to NULL. + */ +struct ISL_MAYBE(ISL_TYPE) { + isl_bool valid; + ISL_TYPE *value; +}; +typedef struct ISL_MAYBE(ISL_TYPE) ISL_MAYBE(ISL_TYPE); Index: contrib/isl/include/isl/multi.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/multi.h @@ -0,0 +1,152 @@ +#ifndef ISL_MULTI_H +#define ISL_MULTI_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#define ISL_DECLARE_MULTI(BASE) \ +unsigned isl_multi_##BASE##_dim(__isl_keep isl_multi_##BASE *multi, \ + enum isl_dim_type type); \ +isl_ctx *isl_multi_##BASE##_get_ctx( \ + __isl_keep isl_multi_##BASE *multi); \ +__isl_give isl_space *isl_multi_##BASE##_get_space( \ + __isl_keep isl_multi_##BASE *multi); \ +__isl_give isl_space *isl_multi_##BASE##_get_domain_space( \ + __isl_keep isl_multi_##BASE *multi); \ +int isl_multi_##BASE##_find_dim_by_name( \ + __isl_keep isl_multi_##BASE *multi, \ + enum isl_dim_type type, const char *name); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_from_##BASE##_list( \ + __isl_take isl_space *space, __isl_take isl_##BASE##_list *list); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_zero( \ + __isl_take isl_space *space); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_copy( \ + __isl_keep isl_multi_##BASE *multi); \ +__isl_null isl_multi_##BASE *isl_multi_##BASE##_free( \ + __isl_take isl_multi_##BASE *multi); \ +isl_bool isl_multi_##BASE##_plain_is_equal( \ + __isl_keep isl_multi_##BASE *multi1, \ + __isl_keep isl_multi_##BASE *multi2); \ +isl_bool isl_multi_##BASE##_involves_nan( \ + __isl_keep isl_multi_##BASE *multi); \ +int isl_multi_##BASE##_find_dim_by_id( \ + __isl_keep isl_multi_##BASE *multi, enum isl_dim_type type, \ + __isl_keep isl_id *id); \ +__isl_give isl_id *isl_multi_##BASE##_get_dim_id( \ + __isl_take isl_multi_##BASE *multi, \ + enum isl_dim_type type, unsigned pos); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_dim_name( \ + __isl_take isl_multi_##BASE *multi, \ + enum isl_dim_type type, unsigned pos, const char *s); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_dim_id( \ + __isl_take isl_multi_##BASE *multi, \ + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); \ +const char *isl_multi_##BASE##_get_tuple_name( \ + __isl_keep isl_multi_##BASE *multi, enum isl_dim_type type); \ +isl_bool isl_multi_##BASE##_has_tuple_id( \ + __isl_keep isl_multi_##BASE *multi, enum isl_dim_type type); \ +__isl_give isl_id *isl_multi_##BASE##_get_tuple_id( \ + __isl_keep isl_multi_##BASE *multi, enum isl_dim_type type); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_tuple_name( \ + __isl_take isl_multi_##BASE *multi, \ + enum isl_dim_type type, const char *s); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_tuple_id( \ + __isl_take isl_multi_##BASE *multi, \ + enum isl_dim_type type, __isl_take isl_id *id); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_reset_tuple_id( \ + __isl_take isl_multi_##BASE *multi, enum isl_dim_type type); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_reset_user( \ + __isl_take isl_multi_##BASE *multi); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_drop_dims( \ + __isl_take isl_multi_##BASE *multi, enum isl_dim_type type, \ + unsigned first, unsigned n); \ +__isl_give isl_##BASE *isl_multi_##BASE##_get_##BASE( \ + __isl_keep isl_multi_##BASE *multi, int pos); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_##BASE( \ + __isl_take isl_multi_##BASE *multi, int pos, \ + __isl_take isl_##BASE *el); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_splice( \ + __isl_take isl_multi_##BASE *multi1, unsigned pos, \ + __isl_take isl_multi_##BASE *multi2); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_flatten_range( \ + __isl_take isl_multi_##BASE *multi); \ +__isl_export \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_flat_range_product( \ + __isl_take isl_multi_##BASE *multi1, \ + __isl_take isl_multi_##BASE *multi2); \ +__isl_export \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_product( \ + __isl_take isl_multi_##BASE *multi1, \ + __isl_take isl_multi_##BASE *multi2); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_factor_range( \ + __isl_take isl_multi_##BASE *multi); \ +isl_bool isl_multi_##BASE##_range_is_wrapping( \ + __isl_keep isl_multi_##BASE *multi); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_factor_domain( \ + __isl_take isl_multi_##BASE *multi); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_factor_range( \ + __isl_take isl_multi_##BASE *multi); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_val( \ + __isl_take isl_multi_##BASE *multi, __isl_take isl_val *v); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_down_val( \ + __isl_take isl_multi_##BASE *multi, __isl_take isl_val *v); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_multi_val( \ + __isl_take isl_multi_##BASE *multi, \ + __isl_take isl_multi_val *mv); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_down_multi_val( \ + __isl_take isl_multi_##BASE *multi, \ + __isl_take isl_multi_val *mv); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_mod_multi_val( \ + __isl_take isl_multi_##BASE *multi, \ + __isl_take isl_multi_val *mv); \ +__isl_export \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_add( \ + __isl_take isl_multi_##BASE *multi1, \ + __isl_take isl_multi_##BASE *multi2); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_sub( \ + __isl_take isl_multi_##BASE *multi1, \ + __isl_take isl_multi_##BASE *multi2); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_align_params( \ + __isl_take isl_multi_##BASE *multi, \ + __isl_take isl_space *model); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_from_range( \ + __isl_take isl_multi_##BASE *multi); + +#define ISL_DECLARE_MULTI_CMP(BASE) \ +int isl_multi_##BASE##_plain_cmp(__isl_keep isl_multi_##BASE *multi1, \ + __isl_keep isl_multi_##BASE *multi2); + +#define ISL_DECLARE_MULTI_NEG(BASE) \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_neg( \ + __isl_take isl_multi_##BASE *multi); + +#define ISL_DECLARE_MULTI_DIMS(BASE) \ +isl_bool isl_multi_##BASE##_involves_dims( \ + __isl_keep isl_multi_##BASE *multi, enum isl_dim_type type, \ + unsigned first, unsigned n); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_insert_dims( \ + __isl_take isl_multi_##BASE *multi, enum isl_dim_type type, \ + unsigned first, unsigned n); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_add_dims( \ + __isl_take isl_multi_##BASE *multi, enum isl_dim_type type, \ + unsigned n); + +#define ISL_DECLARE_MULTI_WITH_DOMAIN(BASE) \ +__isl_export \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_product( \ + __isl_take isl_multi_##BASE *multi1, \ + __isl_take isl_multi_##BASE *multi2); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_splice( \ + __isl_take isl_multi_##BASE *multi1, unsigned in_pos, \ + unsigned out_pos, __isl_take isl_multi_##BASE *multi2); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/obj.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/obj.h @@ -0,0 +1,57 @@ +#ifndef ISL_OBJ_H +#define ISL_OBJ_H + +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_obj_vtable { + void *(*copy)(void *v1); + void *(*add)(void *v1, void *v2); + __isl_give isl_printer *(*print)(__isl_take isl_printer *p, void *v); + void (*free)(void *v); +}; +typedef struct isl_obj_vtable *isl_obj_type; +extern struct isl_obj_vtable isl_obj_none_vtable; +#define isl_obj_none (&isl_obj_none_vtable) +extern struct isl_obj_vtable isl_obj_int_vtable; +#define isl_obj_int (&isl_obj_int_vtable) +extern struct isl_obj_vtable isl_obj_val_vtable; +#define isl_obj_val (&isl_obj_val_vtable) +extern struct isl_obj_vtable isl_obj_set_vtable; +#define isl_obj_set (&isl_obj_set_vtable) +extern struct isl_obj_vtable isl_obj_union_set_vtable; +#define isl_obj_union_set (&isl_obj_union_set_vtable) +extern struct isl_obj_vtable isl_obj_map_vtable; +#define isl_obj_map (&isl_obj_map_vtable) +extern struct isl_obj_vtable isl_obj_union_map_vtable; +#define isl_obj_union_map (&isl_obj_union_map_vtable) +extern struct isl_obj_vtable isl_obj_pw_multi_aff_vtable; +#define isl_obj_pw_multi_aff (&isl_obj_pw_multi_aff_vtable) +extern struct isl_obj_vtable isl_obj_pw_qpolynomial_vtable; +#define isl_obj_pw_qpolynomial (&isl_obj_pw_qpolynomial_vtable) +extern struct isl_obj_vtable isl_obj_union_pw_qpolynomial_vtable; +#define isl_obj_union_pw_qpolynomial (&isl_obj_union_pw_qpolynomial_vtable) +extern struct isl_obj_vtable isl_obj_pw_qpolynomial_fold_vtable; +#define isl_obj_pw_qpolynomial_fold (&isl_obj_pw_qpolynomial_fold_vtable) +extern struct isl_obj_vtable isl_obj_union_pw_qpolynomial_fold_vtable; +#define isl_obj_union_pw_qpolynomial_fold (&isl_obj_union_pw_qpolynomial_fold_vtable) +extern struct isl_obj_vtable isl_obj_schedule_vtable; +#define isl_obj_schedule (&isl_obj_schedule_vtable) +struct isl_obj { + isl_obj_type type; + void *v; +}; + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/options.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/options.h @@ -0,0 +1,53 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_OPTIONS_H +#define ISL_OPTIONS_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_options; + +ISL_ARG_DECL(isl_options, struct isl_options, isl_options_args) + +#define ISL_BOUND_BERNSTEIN 0 +#define ISL_BOUND_RANGE 1 +isl_stat isl_options_set_bound(isl_ctx *ctx, int val); +int isl_options_get_bound(isl_ctx *ctx); + +#define ISL_ON_ERROR_WARN 0 +#define ISL_ON_ERROR_CONTINUE 1 +#define ISL_ON_ERROR_ABORT 2 +isl_stat isl_options_set_on_error(isl_ctx *ctx, int val); +int isl_options_get_on_error(isl_ctx *ctx); + +isl_stat isl_options_set_gbr_only_first(isl_ctx *ctx, int val); +int isl_options_get_gbr_only_first(isl_ctx *ctx); + +#define ISL_SCHEDULE_ALGORITHM_ISL 0 +#define ISL_SCHEDULE_ALGORITHM_FEAUTRIER 1 +isl_stat isl_options_set_schedule_algorithm(isl_ctx *ctx, int val); +int isl_options_get_schedule_algorithm(isl_ctx *ctx); + +isl_stat isl_options_set_pip_symmetry(isl_ctx *ctx, int val); +int isl_options_get_pip_symmetry(isl_ctx *ctx); + +isl_stat isl_options_set_coalesce_bounded_wrapping(isl_ctx *ctx, int val); +int isl_options_get_coalesce_bounded_wrapping(isl_ctx *ctx); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/point.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/point.h @@ -0,0 +1,44 @@ +#ifndef ISL_POINT_H +#define ISL_POINT_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct __isl_subclass(isl_basic_set) isl_point; +typedef struct isl_point isl_point; + +isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt); +__isl_give isl_space *isl_point_get_space(__isl_keep isl_point *pnt); + +__isl_give isl_point *isl_point_zero(__isl_take isl_space *dim); +__isl_give isl_point *isl_point_copy(__isl_keep isl_point *pnt); +__isl_null isl_point *isl_point_free(__isl_take isl_point *pnt); + +__isl_give isl_val *isl_point_get_coordinate_val(__isl_keep isl_point *pnt, + enum isl_dim_type type, int pos); +__isl_give isl_point *isl_point_set_coordinate_val(__isl_take isl_point *pnt, + enum isl_dim_type type, int pos, __isl_take isl_val *v); + +__isl_give isl_point *isl_point_add_ui(__isl_take isl_point *pnt, + enum isl_dim_type type, int pos, unsigned val); +__isl_give isl_point *isl_point_sub_ui(__isl_take isl_point *pnt, + enum isl_dim_type type, int pos, unsigned val); + +__isl_give isl_point *isl_point_void(__isl_take isl_space *dim); +isl_bool isl_point_is_void(__isl_keep isl_point *pnt); + +__isl_give isl_printer *isl_printer_print_point( + __isl_take isl_printer *printer, __isl_keep isl_point *pnt); +__isl_give char *isl_point_to_str(__isl_keep isl_point *pnt); +void isl_point_dump(__isl_keep isl_point *pnt); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/polynomial.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/polynomial.h @@ -0,0 +1,696 @@ +#ifndef ISL_POLYNOMIAL_H +#define ISL_POLYNOMIAL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +isl_ctx *isl_qpolynomial_get_ctx(__isl_keep isl_qpolynomial *qp); +__isl_give isl_space *isl_qpolynomial_get_domain_space( + __isl_keep isl_qpolynomial *qp); +__isl_give isl_space *isl_qpolynomial_get_space(__isl_keep isl_qpolynomial *qp); +unsigned isl_qpolynomial_dim(__isl_keep isl_qpolynomial *qp, + enum isl_dim_type type); +isl_bool isl_qpolynomial_involves_dims(__isl_keep isl_qpolynomial *qp, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_val *isl_qpolynomial_get_constant_val( + __isl_keep isl_qpolynomial *qp); + +__isl_give isl_qpolynomial *isl_qpolynomial_set_dim_name( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type type, unsigned pos, const char *s); + +__isl_give isl_qpolynomial *isl_qpolynomial_zero_on_domain(__isl_take isl_space *dim); +__isl_give isl_qpolynomial *isl_qpolynomial_one_on_domain(__isl_take isl_space *dim); +__isl_give isl_qpolynomial *isl_qpolynomial_infty_on_domain(__isl_take isl_space *dim); +__isl_give isl_qpolynomial *isl_qpolynomial_neginfty_on_domain(__isl_take isl_space *dim); +__isl_give isl_qpolynomial *isl_qpolynomial_nan_on_domain(__isl_take isl_space *dim); +__isl_give isl_qpolynomial *isl_qpolynomial_val_on_domain( + __isl_take isl_space *space, __isl_take isl_val *val); +__isl_give isl_qpolynomial *isl_qpolynomial_var_on_domain(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned pos); +__isl_give isl_qpolynomial *isl_qpolynomial_copy(__isl_keep isl_qpolynomial *qp); +__isl_null isl_qpolynomial *isl_qpolynomial_free( + __isl_take isl_qpolynomial *qp); + +isl_bool isl_qpolynomial_plain_is_equal(__isl_keep isl_qpolynomial *qp1, + __isl_keep isl_qpolynomial *qp2); +isl_bool isl_qpolynomial_is_zero(__isl_keep isl_qpolynomial *qp); +isl_bool isl_qpolynomial_is_nan(__isl_keep isl_qpolynomial *qp); +isl_bool isl_qpolynomial_is_infty(__isl_keep isl_qpolynomial *qp); +isl_bool isl_qpolynomial_is_neginfty(__isl_keep isl_qpolynomial *qp); +int isl_qpolynomial_sgn(__isl_keep isl_qpolynomial *qp); + +__isl_give isl_qpolynomial *isl_qpolynomial_neg(__isl_take isl_qpolynomial *qp); +__isl_give isl_qpolynomial *isl_qpolynomial_add(__isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2); +__isl_give isl_qpolynomial *isl_qpolynomial_sub(__isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2); +__isl_give isl_qpolynomial *isl_qpolynomial_mul(__isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2); +__isl_give isl_qpolynomial *isl_qpolynomial_pow(__isl_take isl_qpolynomial *qp, + unsigned power); +__isl_give isl_qpolynomial *isl_qpolynomial_scale_val( + __isl_take isl_qpolynomial *qp, __isl_take isl_val *v); +__isl_give isl_qpolynomial *isl_qpolynomial_scale_down_val( + __isl_take isl_qpolynomial *qp, __isl_take isl_val *v); + +__isl_give isl_qpolynomial *isl_qpolynomial_insert_dims( + __isl_take isl_qpolynomial *qp, enum isl_dim_type type, + unsigned first, unsigned n); +__isl_give isl_qpolynomial *isl_qpolynomial_add_dims( + __isl_take isl_qpolynomial *qp, enum isl_dim_type type, unsigned n); +__isl_give isl_qpolynomial *isl_qpolynomial_move_dims( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); +__isl_give isl_qpolynomial *isl_qpolynomial_project_domain_on_params( + __isl_take isl_qpolynomial *qp); +__isl_give isl_qpolynomial *isl_qpolynomial_drop_dims( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_qpolynomial *isl_qpolynomial_substitute( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type type, unsigned first, unsigned n, + __isl_keep isl_qpolynomial **subs); + +isl_stat isl_qpolynomial_as_polynomial_on_domain(__isl_keep isl_qpolynomial *qp, + __isl_keep isl_basic_set *bset, + isl_stat (*fn)(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, void *user), void *user); + +__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_space *model); + +isl_ctx *isl_term_get_ctx(__isl_keep isl_term *term); + +__isl_give isl_term *isl_term_copy(__isl_keep isl_term *term); +void isl_term_free(__isl_take isl_term *term); + +unsigned isl_term_dim(__isl_keep isl_term *term, enum isl_dim_type type); +__isl_give isl_val *isl_term_get_coefficient_val(__isl_keep isl_term *term); +int isl_term_get_exp(__isl_keep isl_term *term, + enum isl_dim_type type, unsigned pos); +__isl_give isl_aff *isl_term_get_div(__isl_keep isl_term *term, unsigned pos); + +isl_stat isl_qpolynomial_foreach_term(__isl_keep isl_qpolynomial *qp, + isl_stat (*fn)(__isl_take isl_term *term, void *user), void *user); + +__isl_give isl_val *isl_qpolynomial_eval(__isl_take isl_qpolynomial *qp, + __isl_take isl_point *pnt); + +__isl_give isl_qpolynomial *isl_qpolynomial_gist_params( + __isl_take isl_qpolynomial *qp, __isl_take isl_set *context); +__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); + +__isl_give isl_printer *isl_printer_print_qpolynomial( + __isl_take isl_printer *p, __isl_keep isl_qpolynomial *qp); +void isl_qpolynomial_print(__isl_keep isl_qpolynomial *qp, FILE *out, + unsigned output_format); +void isl_qpolynomial_dump(__isl_keep isl_qpolynomial *qp); + +isl_ctx *isl_pw_qpolynomial_get_ctx(__isl_keep isl_pw_qpolynomial *pwqp); + +isl_bool isl_pw_qpolynomial_involves_nan(__isl_keep isl_pw_qpolynomial *pwqp); +isl_bool isl_pw_qpolynomial_plain_is_equal(__isl_keep isl_pw_qpolynomial *pwqp1, + __isl_keep isl_pw_qpolynomial *pwqp2); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_zero(__isl_take isl_space *dim); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_alloc(__isl_take isl_set *set, + __isl_take isl_qpolynomial *qp); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_qpolynomial( + __isl_take isl_qpolynomial *qp); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_copy( + __isl_keep isl_pw_qpolynomial *pwqp); +__isl_null isl_pw_qpolynomial *isl_pw_qpolynomial_free( + __isl_take isl_pw_qpolynomial *pwqp); + +isl_bool isl_pw_qpolynomial_is_zero(__isl_keep isl_pw_qpolynomial *pwqp); + +__isl_give isl_space *isl_pw_qpolynomial_get_domain_space( + __isl_keep isl_pw_qpolynomial *pwqp); +__isl_give isl_space *isl_pw_qpolynomial_get_space( + __isl_keep isl_pw_qpolynomial *pwqp); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_domain_space( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_space *dim); +unsigned isl_pw_qpolynomial_dim(__isl_keep isl_pw_qpolynomial *pwqp, + enum isl_dim_type type); +isl_bool isl_pw_qpolynomial_involves_dims(__isl_keep isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned first, unsigned n); +isl_bool isl_pw_qpolynomial_has_equal_space( + __isl_keep isl_pw_qpolynomial *pwqp1, + __isl_keep isl_pw_qpolynomial *pwqp2); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_set_dim_name( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned pos, const char *s); + +int isl_pw_qpolynomial_find_dim_by_name(__isl_keep isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, const char *name); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_user( + __isl_take isl_pw_qpolynomial *pwqp); + +__isl_export +__isl_give isl_set *isl_pw_qpolynomial_domain(__isl_take isl_pw_qpolynomial *pwqp); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_intersect_domain( + __isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_intersect_params( + __isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_subtract_domain( + __isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_project_domain_on_params( + __isl_take isl_pw_qpolynomial *pwqp); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_range( + __isl_take isl_pw_qpolynomial *pwqp); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_drop_dims( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_split_dims( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sub( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_disjoint( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_neg( + __isl_take isl_pw_qpolynomial *pwqp); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_scale_val( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_val *v); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_scale_down_val( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_val *v); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_pow( + __isl_take isl_pw_qpolynomial *pwqp, unsigned exponent); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_insert_dims( + __isl_take isl_pw_qpolynomial *pwqp, enum isl_dim_type type, + unsigned first, unsigned n); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_dims( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned n); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_move_dims( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_fix_val( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned n, __isl_take isl_val *v); + +__isl_export +__isl_give isl_val *isl_pw_qpolynomial_eval( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_point *pnt); + +__isl_give isl_val *isl_pw_qpolynomial_max(__isl_take isl_pw_qpolynomial *pwqp); +__isl_give isl_val *isl_pw_qpolynomial_min(__isl_take isl_pw_qpolynomial *pwqp); + +int isl_pw_qpolynomial_n_piece(__isl_keep isl_pw_qpolynomial *pwqp); +isl_stat isl_pw_qpolynomial_foreach_piece(__isl_keep isl_pw_qpolynomial *pwqp, + isl_stat (*fn)(__isl_take isl_set *set, __isl_take isl_qpolynomial *qp, + void *user), void *user); +isl_stat isl_pw_qpolynomial_foreach_lifted_piece( + __isl_keep isl_pw_qpolynomial *pwqp, + isl_stat (*fn)(__isl_take isl_set *set, __isl_take isl_qpolynomial *qp, + void *user), void *user); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_pw_aff( + __isl_take isl_pw_aff *pwaff); + +__isl_constructor +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx, + FILE *input); +__isl_give char *isl_pw_qpolynomial_to_str(__isl_keep isl_pw_qpolynomial *pwqp); +__isl_give isl_printer *isl_printer_print_pw_qpolynomial( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp); +void isl_pw_qpolynomial_print(__isl_keep isl_pw_qpolynomial *pwqp, FILE *out, + unsigned output_format); +void isl_pw_qpolynomial_dump(__isl_keep isl_pw_qpolynomial *pwqp); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_coalesce( + __isl_take isl_pw_qpolynomial *pwqp); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_gist( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_set *context); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_gist_params( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_set *context); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_split_periods( + __isl_take isl_pw_qpolynomial *pwqp, int max_periods); + +__isl_give isl_pw_qpolynomial *isl_basic_set_multiplicative_call( + __isl_take isl_basic_set *bset, + __isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset)); + +isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold); +enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type, + __isl_take isl_space *dim); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc( + enum isl_fold type, __isl_take isl_qpolynomial *qp); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy( + __isl_keep isl_qpolynomial_fold *fold); +void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold); + +int isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold); +isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold); +int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1, + __isl_keep isl_qpolynomial_fold *fold2); + +__isl_give isl_space *isl_qpolynomial_fold_get_domain_space( + __isl_keep isl_qpolynomial_fold *fold); +__isl_give isl_space *isl_qpolynomial_fold_get_space( + __isl_keep isl_qpolynomial_fold *fold); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold( + __isl_take isl_qpolynomial_fold *fold1, + __isl_take isl_qpolynomial_fold *fold2); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned first, unsigned n, + __isl_keep isl_qpolynomial **subs); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fix_val( + __isl_take isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type type, unsigned n, __isl_take isl_val *v); + +__isl_give isl_val *isl_qpolynomial_fold_eval( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params( + __isl_take isl_qpolynomial_fold *fold, __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); + +isl_stat isl_qpolynomial_fold_foreach_qpolynomial( + __isl_keep isl_qpolynomial_fold *fold, + isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user); + +__isl_give isl_printer *isl_printer_print_qpolynomial_fold( + __isl_take isl_printer *p, __isl_keep isl_qpolynomial_fold *fold); +void isl_qpolynomial_fold_print(__isl_keep isl_qpolynomial_fold *fold, FILE *out, + unsigned output_format); +void isl_qpolynomial_fold_dump(__isl_keep isl_qpolynomial_fold *fold); + +isl_ctx *isl_pw_qpolynomial_fold_get_ctx(__isl_keep isl_pw_qpolynomial_fold *pwf); + +isl_bool isl_pw_qpolynomial_fold_involves_nan( + __isl_keep isl_pw_qpolynomial_fold *pwf); +isl_bool isl_pw_qpolynomial_fold_plain_is_equal( + __isl_keep isl_pw_qpolynomial_fold *pwf1, + __isl_keep isl_pw_qpolynomial_fold *pwf2); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial( + enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_alloc( + enum isl_fold type, + __isl_take isl_set *set, __isl_take isl_qpolynomial_fold *fold); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_copy( + __isl_keep isl_pw_qpolynomial_fold *pwf); +__isl_null isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_free( + __isl_take isl_pw_qpolynomial_fold *pwf); + +isl_bool isl_pw_qpolynomial_fold_is_zero( + __isl_keep isl_pw_qpolynomial_fold *pwf); + +__isl_give isl_space *isl_pw_qpolynomial_fold_get_domain_space( + __isl_keep isl_pw_qpolynomial_fold *pwf); +__isl_give isl_space *isl_pw_qpolynomial_fold_get_space( + __isl_keep isl_pw_qpolynomial_fold *pwf); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_reset_space( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_space *dim); +unsigned isl_pw_qpolynomial_fold_dim(__isl_keep isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type type); +isl_bool isl_pw_qpolynomial_fold_has_equal_space( + __isl_keep isl_pw_qpolynomial_fold *pwf1, + __isl_keep isl_pw_qpolynomial_fold *pwf2); + +size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_zero( + __isl_take isl_space *dim, enum isl_fold type); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_set_dim_name( + __isl_take isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type type, unsigned pos, const char *s); + +int isl_pw_qpolynomial_fold_find_dim_by_name( + __isl_keep isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type type, const char *name); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_reset_user( + __isl_take isl_pw_qpolynomial_fold *pwf); + +__isl_give isl_set *isl_pw_qpolynomial_fold_domain( + __isl_take isl_pw_qpolynomial_fold *pwf); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_intersect_domain( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_intersect_params( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_subtract_domain( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add( + __isl_take isl_pw_qpolynomial_fold *pwf1, + __isl_take isl_pw_qpolynomial_fold *pwf2); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold( + __isl_take isl_pw_qpolynomial_fold *pwf1, + __isl_take isl_pw_qpolynomial_fold *pwf2); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add_disjoint( + __isl_take isl_pw_qpolynomial_fold *pwf1, + __isl_take isl_pw_qpolynomial_fold *pwf2); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_scale_val( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_val *v); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_scale_down_val( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_val *v); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_project_domain_on_params( + __isl_take isl_pw_qpolynomial_fold *pwf); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_range( + __isl_take isl_pw_qpolynomial_fold *pwf); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_drop_dims( + __isl_take isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_move_dims( + __isl_take isl_pw_qpolynomial_fold *pwf, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); + +__isl_give isl_val *isl_pw_qpolynomial_fold_eval( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_point *pnt); + +int isl_pw_qpolynomial_fold_n_piece(__isl_keep isl_pw_qpolynomial_fold *pwf); +isl_stat isl_pw_qpolynomial_fold_foreach_piece( + __isl_keep isl_pw_qpolynomial_fold *pwf, + isl_stat (*fn)(__isl_take isl_set *set, + __isl_take isl_qpolynomial_fold *fold, void *user), void *user); +isl_stat isl_pw_qpolynomial_fold_foreach_lifted_piece( + __isl_keep isl_pw_qpolynomial_fold *pwf, + isl_stat (*fn)(__isl_take isl_set *set, + __isl_take isl_qpolynomial_fold *fold, void *user), void *user); + +__isl_give isl_printer *isl_printer_print_pw_qpolynomial_fold( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf); +void isl_pw_qpolynomial_fold_print(__isl_keep isl_pw_qpolynomial_fold *pwf, + FILE *out, unsigned output_format); +void isl_pw_qpolynomial_fold_dump(__isl_keep isl_pw_qpolynomial_fold *pwf); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_coalesce( + __isl_take isl_pw_qpolynomial_fold *pwf); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_gist( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *context); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_gist_params( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *context); + +__isl_give isl_val *isl_pw_qpolynomial_fold_max( + __isl_take isl_pw_qpolynomial_fold *pwf); +__isl_give isl_val *isl_pw_qpolynomial_fold_min( + __isl_take isl_pw_qpolynomial_fold *pwf); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_bound( + __isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type, int *tight); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_bound( + __isl_take isl_pw_qpolynomial_fold *pwf, int *tight); +__isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold( + __isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf, + int *tight); +__isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold( + __isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf, + int *tight); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_to_polynomial( + __isl_take isl_pw_qpolynomial *pwqp, int sign); + +isl_ctx *isl_union_pw_qpolynomial_get_ctx( + __isl_keep isl_union_pw_qpolynomial *upwqp); + +unsigned isl_union_pw_qpolynomial_dim( + __isl_keep isl_union_pw_qpolynomial *upwqp, enum isl_dim_type type); + +isl_bool isl_union_pw_qpolynomial_involves_nan( + __isl_keep isl_union_pw_qpolynomial *upwqp); +isl_bool isl_union_pw_qpolynomial_plain_is_equal( + __isl_keep isl_union_pw_qpolynomial *upwqp1, + __isl_keep isl_union_pw_qpolynomial *upwqp2); + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_from_pw_qpolynomial(__isl_take isl_pw_qpolynomial *pwqp); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_zero( + __isl_take isl_space *dim); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_add_pw_qpolynomial( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_pw_qpolynomial *pwqp); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_copy( + __isl_keep isl_union_pw_qpolynomial *upwqp); +__isl_null isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_free( + __isl_take isl_union_pw_qpolynomial *upwqp); + +__isl_constructor +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str( + isl_ctx *ctx, const char *str); +__isl_give char *isl_union_pw_qpolynomial_to_str( + __isl_keep isl_union_pw_qpolynomial *upwqp); + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_neg( + __isl_take isl_union_pw_qpolynomial *upwqp); + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_add( + __isl_take isl_union_pw_qpolynomial *upwqp1, + __isl_take isl_union_pw_qpolynomial *upwqp2); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sub( + __isl_take isl_union_pw_qpolynomial *upwqp1, + __isl_take isl_union_pw_qpolynomial *upwqp2); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul( + __isl_take isl_union_pw_qpolynomial *upwqp1, + __isl_take isl_union_pw_qpolynomial *upwqp2); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_scale_val( + __isl_take isl_union_pw_qpolynomial *upwqp, __isl_take isl_val *v); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_scale_down_val( + __isl_take isl_union_pw_qpolynomial *upwqp, __isl_take isl_val *v); + +__isl_export +__isl_give isl_union_set *isl_union_pw_qpolynomial_domain( + __isl_take isl_union_pw_qpolynomial *upwqp); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_intersect_domain( + __isl_take isl_union_pw_qpolynomial *upwpq, + __isl_take isl_union_set *uset); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_intersect_params( + __isl_take isl_union_pw_qpolynomial *upwpq, + __isl_take isl_set *set); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_subtract_domain( + __isl_take isl_union_pw_qpolynomial *upwpq, + __isl_take isl_union_set *uset); + +__isl_give isl_space *isl_union_pw_qpolynomial_get_space( + __isl_keep isl_union_pw_qpolynomial *upwqp); + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_set_dim_name( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, unsigned pos, const char *s); + +int isl_union_pw_qpolynomial_find_dim_by_name( + __isl_keep isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, const char *name); + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_drop_dims( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_reset_user( + __isl_take isl_union_pw_qpolynomial *upwqp); + +__isl_export +__isl_give isl_val *isl_union_pw_qpolynomial_eval( + __isl_take isl_union_pw_qpolynomial *upwqp, __isl_take isl_point *pnt); + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_coalesce( + __isl_take isl_union_pw_qpolynomial *upwqp); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_gist( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_union_set *context); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_gist_params( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_set *context); + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_align_params( + __isl_take isl_union_pw_qpolynomial *upwqp, + __isl_take isl_space *model); + +int isl_union_pw_qpolynomial_n_pw_qpolynomial( + __isl_keep isl_union_pw_qpolynomial *upwqp); +isl_stat isl_union_pw_qpolynomial_foreach_pw_qpolynomial( + __isl_keep isl_union_pw_qpolynomial *upwqp, + isl_stat (*fn)(__isl_take isl_pw_qpolynomial *pwqp, void *user), + void *user); +__isl_give isl_pw_qpolynomial *isl_union_pw_qpolynomial_extract_pw_qpolynomial( + __isl_keep isl_union_pw_qpolynomial *upwqp, __isl_take isl_space *dim); + +__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial( + __isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp); + +isl_ctx *isl_union_pw_qpolynomial_fold_get_ctx( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + +unsigned isl_union_pw_qpolynomial_fold_dim( + __isl_keep isl_union_pw_qpolynomial_fold *upwf, enum isl_dim_type type); + +isl_bool isl_union_pw_qpolynomial_fold_involves_nan( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); +isl_bool isl_union_pw_qpolynomial_fold_plain_is_equal( + __isl_keep isl_union_pw_qpolynomial_fold *upwf1, + __isl_keep isl_union_pw_qpolynomial_fold *upwf2); + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(__isl_take isl_pw_qpolynomial_fold *pwf); +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_zero( + __isl_take isl_space *dim, enum isl_fold type); +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( + __isl_take isl_union_pw_qpolynomial_fold *upwqp, + __isl_take isl_pw_qpolynomial_fold *pwqp); +__isl_null isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_free( + __isl_take isl_union_pw_qpolynomial_fold *upwf); +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_copy( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold( + __isl_take isl_union_pw_qpolynomial_fold *upwf1, + __isl_take isl_union_pw_qpolynomial_fold *upwf2); +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_pw_qpolynomial *upwqp); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_scale_val( + __isl_take isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_val *v); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_scale_down_val( + __isl_take isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_val *v); + +__isl_give isl_union_set *isl_union_pw_qpolynomial_fold_domain( + __isl_take isl_union_pw_qpolynomial_fold *upwf); +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_intersect_domain( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_set *uset); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_intersect_params( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_set *set); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_subtract_domain( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_set *uset); + +enum isl_fold isl_union_pw_qpolynomial_fold_get_type( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); +__isl_give isl_space *isl_union_pw_qpolynomial_fold_get_space( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_set_dim_name( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, unsigned pos, const char *s); + +int isl_union_pw_qpolynomial_fold_find_dim_by_name( + __isl_keep isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, const char *name); + +__isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_drop_dims( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_reset_user( + __isl_take isl_union_pw_qpolynomial_fold *upwf); + +__isl_give isl_val *isl_union_pw_qpolynomial_fold_eval( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_point *pnt); + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_coalesce( + __isl_take isl_union_pw_qpolynomial_fold *upwf); +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_gist( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_set *context); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_gist_params( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_set *context); + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_align_params( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_space *model); + +int isl_union_pw_qpolynomial_fold_n_pw_qpolynomial_fold( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); +isl_stat isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold( + __isl_keep isl_union_pw_qpolynomial_fold *upwf, + isl_stat (*fn)(__isl_take isl_pw_qpolynomial_fold *pwf, + void *user), void *user); +__isl_give isl_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_extract_pw_qpolynomial_fold( + __isl_keep isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_space *dim); + +__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial_fold( + __isl_take isl_printer *p, + __isl_keep isl_union_pw_qpolynomial_fold *upwf); + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_bound( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_fold type, int *tight); +__isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold( + __isl_take isl_union_set *uset, + __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight); +__isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight); + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_to_polynomial( + __isl_take isl_union_pw_qpolynomial *upwqp, int sign); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/polynomial_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/polynomial_type.h @@ -0,0 +1,31 @@ +#ifndef ISL_POLYNOMIAL_TYPE_H +#define ISL_POLYNOMIAL_TYPE_H + +struct isl_qpolynomial; +typedef struct isl_qpolynomial isl_qpolynomial; + +struct isl_term; +typedef struct isl_term isl_term; + +struct __isl_export isl_pw_qpolynomial; +typedef struct isl_pw_qpolynomial isl_pw_qpolynomial; + +enum isl_fold { + isl_fold_min, + isl_fold_max, + isl_fold_list +}; + +struct isl_qpolynomial_fold; +typedef struct isl_qpolynomial_fold isl_qpolynomial_fold; + +struct isl_pw_qpolynomial_fold; +typedef struct isl_pw_qpolynomial_fold isl_pw_qpolynomial_fold; + +struct __isl_export isl_union_pw_qpolynomial; +typedef struct isl_union_pw_qpolynomial isl_union_pw_qpolynomial; + +struct isl_union_pw_qpolynomial_fold; +typedef struct isl_union_pw_qpolynomial_fold isl_union_pw_qpolynomial_fold; + +#endif Index: contrib/isl/include/isl/printer.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/printer.h @@ -0,0 +1,84 @@ +#ifndef ISL_PRINTER_H +#define ISL_PRINTER_H + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file); +__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx); +__isl_null isl_printer *isl_printer_free(__isl_take isl_printer *printer); + +isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer); +FILE *isl_printer_get_file(__isl_keep isl_printer *printer); + +__isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer); + +__isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p, + int indent); +__isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p, + int indent); + +#define ISL_FORMAT_ISL 0 +#define ISL_FORMAT_POLYLIB 1 +#define ISL_FORMAT_POLYLIB_CONSTRAINTS 2 +#define ISL_FORMAT_OMEGA 3 +#define ISL_FORMAT_C 4 +#define ISL_FORMAT_LATEX 5 +#define ISL_FORMAT_EXT_POLYLIB 6 +__isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p, + int output_format); +int isl_printer_get_output_format(__isl_keep isl_printer *p); + +#define ISL_YAML_STYLE_BLOCK 0 +#define ISL_YAML_STYLE_FLOW 1 +__isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p, + int yaml_style); +int isl_printer_get_yaml_style(__isl_keep isl_printer *p); + +__isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p, + const char *prefix); +__isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p, + const char *prefix); +__isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p, + const char *suffix); +__isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p, + int width); + +isl_bool isl_printer_has_note(__isl_keep isl_printer *p, + __isl_keep isl_id *id); +__isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p, + __isl_take isl_id *id); +__isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p, + __isl_take isl_id *id, __isl_take isl_id *note); + +__isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p, + double d); +__isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i); +__isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p, + const char *s); + +__isl_give isl_printer *isl_printer_yaml_start_mapping( + __isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_yaml_end_mapping( + __isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_yaml_start_sequence( + __isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_yaml_end_sequence( + __isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p); + +__isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/printer_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/printer_type.h @@ -0,0 +1,15 @@ +#ifndef ISL_PRINTER_TYPE_H +#define ISL_PRINTER_TYPE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_printer; +typedef struct isl_printer isl_printer; + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/schedule.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/schedule.h @@ -0,0 +1,199 @@ +#ifndef ISL_SCHEDULE_H +#define ISL_SCHEDULE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct __isl_export isl_schedule_constraints; +typedef struct isl_schedule_constraints isl_schedule_constraints; + +isl_stat isl_options_set_schedule_max_coefficient(isl_ctx *ctx, int val); +int isl_options_get_schedule_max_coefficient(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_max_constant_term(isl_ctx *ctx, int val); +int isl_options_get_schedule_max_constant_term(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_maximize_band_depth(isl_ctx *ctx, int val); +int isl_options_get_schedule_maximize_band_depth(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_maximize_coincidence(isl_ctx *ctx, int val); +int isl_options_get_schedule_maximize_coincidence(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_outer_coincidence(isl_ctx *ctx, int val); +int isl_options_get_schedule_outer_coincidence(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_split_scaled(isl_ctx *ctx, int val); +int isl_options_get_schedule_split_scaled(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_treat_coalescing(isl_ctx *ctx, int val); +int isl_options_get_schedule_treat_coalescing(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_separate_components(isl_ctx *ctx, int val); +int isl_options_get_schedule_separate_components(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_serialize_sccs(isl_ctx *ctx, int val); +int isl_options_get_schedule_serialize_sccs(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_whole_component(isl_ctx *ctx, int val); +int isl_options_get_schedule_whole_component(isl_ctx *ctx); + +isl_stat isl_options_set_schedule_carry_self_first(isl_ctx *ctx, int val); +int isl_options_get_schedule_carry_self_first(isl_ctx *ctx); + +__isl_give isl_schedule_constraints *isl_schedule_constraints_copy( + __isl_keep isl_schedule_constraints *sc); +__isl_export +__isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain( + __isl_take isl_union_set *domain); +__isl_export +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_context( + __isl_take isl_schedule_constraints *sc, __isl_take isl_set *context); +__isl_export +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *validity); +__isl_export +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_coincidence( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *coincidence); +__isl_export +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_proximity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *proximity); +__isl_export +__isl_give isl_schedule_constraints * +isl_schedule_constraints_set_conditional_validity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *condition, + __isl_take isl_union_map *validity); +__isl_null isl_schedule_constraints *isl_schedule_constraints_free( + __isl_take isl_schedule_constraints *sc); + +isl_ctx *isl_schedule_constraints_get_ctx( + __isl_keep isl_schedule_constraints *sc); +__isl_export +__isl_give isl_union_set *isl_schedule_constraints_get_domain( + __isl_keep isl_schedule_constraints *sc); +__isl_export +__isl_give isl_set *isl_schedule_constraints_get_context( + __isl_keep isl_schedule_constraints *sc); +__isl_export +__isl_give isl_union_map *isl_schedule_constraints_get_validity( + __isl_keep isl_schedule_constraints *sc); +__isl_export +__isl_give isl_union_map *isl_schedule_constraints_get_coincidence( + __isl_keep isl_schedule_constraints *sc); +__isl_export +__isl_give isl_union_map *isl_schedule_constraints_get_proximity( + __isl_keep isl_schedule_constraints *sc); +__isl_export +__isl_give isl_union_map *isl_schedule_constraints_get_conditional_validity( + __isl_keep isl_schedule_constraints *sc); +__isl_export +__isl_give isl_union_map * +isl_schedule_constraints_get_conditional_validity_condition( + __isl_keep isl_schedule_constraints *sc); + +__isl_give isl_schedule_constraints *isl_schedule_constraints_apply( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *umap); + +__isl_constructor +__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_str( + isl_ctx *ctx, const char *str); +__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_file( + isl_ctx *ctx, FILE *input); +__isl_give isl_printer *isl_printer_print_schedule_constraints( + __isl_take isl_printer *p, __isl_keep isl_schedule_constraints *sc); +void isl_schedule_constraints_dump(__isl_keep isl_schedule_constraints *sc); +__isl_give char *isl_schedule_constraints_to_str( + __isl_keep isl_schedule_constraints *sc); + +__isl_export +__isl_give isl_schedule *isl_schedule_constraints_compute_schedule( + __isl_take isl_schedule_constraints *sc); + +__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_give isl_schedule *isl_schedule_empty(__isl_take isl_space *space); +__isl_give isl_schedule *isl_schedule_from_domain( + __isl_take isl_union_set *domain); +__isl_give isl_schedule *isl_schedule_copy(__isl_keep isl_schedule *sched); +__isl_null isl_schedule *isl_schedule_free(__isl_take isl_schedule *sched); +__isl_export +__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched); + +isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *sched); +isl_bool isl_schedule_plain_is_equal(__isl_keep isl_schedule *schedule1, + __isl_keep isl_schedule *schedule2); + +__isl_export +__isl_give isl_schedule_node *isl_schedule_get_root( + __isl_keep isl_schedule *schedule); +__isl_give isl_union_set *isl_schedule_get_domain( + __isl_keep isl_schedule *schedule); + +isl_stat isl_schedule_foreach_schedule_node_top_down( + __isl_keep isl_schedule *sched, + isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user), + void *user); +__isl_give isl_schedule *isl_schedule_map_schedule_node_bottom_up( + __isl_take isl_schedule *schedule, + __isl_give isl_schedule_node *(*fn)( + __isl_take isl_schedule_node *node, void *user), void *user); + +__isl_give isl_schedule *isl_schedule_insert_context( + __isl_take isl_schedule *schedule, __isl_take isl_set *context); +__isl_give isl_schedule *isl_schedule_insert_partial_schedule( + __isl_take isl_schedule *schedule, + __isl_take isl_multi_union_pw_aff *partial); +__isl_give isl_schedule *isl_schedule_insert_guard( + __isl_take isl_schedule *schedule, __isl_take isl_set *guard); +__isl_give isl_schedule *isl_schedule_sequence( + __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2); +__isl_give isl_schedule *isl_schedule_set( + __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2); +__isl_give isl_schedule *isl_schedule_intersect_domain( + __isl_take isl_schedule *schedule, __isl_take isl_union_set *domain); +__isl_give isl_schedule *isl_schedule_gist_domain_params( + __isl_take isl_schedule *schedule, __isl_take isl_set *context); + +__isl_give isl_schedule *isl_schedule_reset_user( + __isl_take isl_schedule *schedule); +__isl_give isl_schedule *isl_schedule_align_params( + __isl_take isl_schedule *schedule, __isl_take isl_space *space); +__isl_overload +__isl_give isl_schedule *isl_schedule_pullback_union_pw_multi_aff( + __isl_take isl_schedule *schedule, + __isl_take isl_union_pw_multi_aff *upma); +__isl_give isl_schedule *isl_schedule_expand(__isl_take isl_schedule *schedule, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_schedule *expansion); + +__isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input); +__isl_constructor +__isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p, + __isl_keep isl_schedule *schedule); +void isl_schedule_dump(__isl_keep isl_schedule *schedule); +__isl_give char *isl_schedule_to_str(__isl_keep isl_schedule *schedule); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/schedule_node.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/schedule_node.h @@ -0,0 +1,242 @@ +#ifndef ISL_SCHEDULE_NODE_H +#define ISL_SCHEDULE_NODE_H + +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_schedule_node *isl_schedule_node_from_domain( + __isl_take isl_union_set *domain); +__isl_give isl_schedule_node *isl_schedule_node_from_extension( + __isl_take isl_union_map *extension); +__isl_give isl_schedule_node *isl_schedule_node_copy( + __isl_keep isl_schedule_node *node); +__isl_null isl_schedule_node *isl_schedule_node_free( + __isl_take isl_schedule_node *node); + +isl_bool isl_schedule_node_is_equal(__isl_keep isl_schedule_node *node1, + __isl_keep isl_schedule_node *node2); + +isl_ctx *isl_schedule_node_get_ctx(__isl_keep isl_schedule_node *node); +enum isl_schedule_node_type isl_schedule_node_get_type( + __isl_keep isl_schedule_node *node); +enum isl_schedule_node_type isl_schedule_node_get_parent_type( + __isl_keep isl_schedule_node *node); +__isl_export +__isl_give isl_schedule *isl_schedule_node_get_schedule( + __isl_keep isl_schedule_node *node); + +isl_stat isl_schedule_node_foreach_descendant_top_down( + __isl_keep isl_schedule_node *node, + isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user), + void *user); +isl_bool isl_schedule_node_every_descendant(__isl_keep isl_schedule_node *node, + isl_bool (*test)(__isl_keep isl_schedule_node *node, void *user), + void *user); +isl_stat isl_schedule_node_foreach_ancestor_top_down( + __isl_keep isl_schedule_node *node, + isl_stat (*fn)(__isl_keep isl_schedule_node *node, void *user), + void *user); +__isl_give isl_schedule_node *isl_schedule_node_map_descendant_bottom_up( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node, + void *user), void *user); + +int isl_schedule_node_get_tree_depth(__isl_keep isl_schedule_node *node); +isl_bool isl_schedule_node_has_parent(__isl_keep isl_schedule_node *node); +isl_bool isl_schedule_node_has_children(__isl_keep isl_schedule_node *node); +isl_bool isl_schedule_node_has_previous_sibling( + __isl_keep isl_schedule_node *node); +isl_bool isl_schedule_node_has_next_sibling(__isl_keep isl_schedule_node *node); +int isl_schedule_node_n_children(__isl_keep isl_schedule_node *node); +int isl_schedule_node_get_child_position(__isl_keep isl_schedule_node *node); +int isl_schedule_node_get_ancestor_child_position( + __isl_keep isl_schedule_node *node, + __isl_keep isl_schedule_node *ancestor); +__isl_give isl_schedule_node *isl_schedule_node_get_child( + __isl_keep isl_schedule_node *node, int pos); +__isl_give isl_schedule_node *isl_schedule_node_get_shared_ancestor( + __isl_keep isl_schedule_node *node1, + __isl_keep isl_schedule_node *node2); + +__isl_give isl_schedule_node *isl_schedule_node_root( + __isl_take isl_schedule_node *node); +__isl_export +__isl_give isl_schedule_node *isl_schedule_node_parent( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_ancestor( + __isl_take isl_schedule_node *node, int generation); +__isl_export +__isl_give isl_schedule_node *isl_schedule_node_child( + __isl_take isl_schedule_node *node, int pos); +__isl_give isl_schedule_node *isl_schedule_node_first_child( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_previous_sibling( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_next_sibling( + __isl_take isl_schedule_node *node); + +isl_bool isl_schedule_node_is_subtree_anchored( + __isl_keep isl_schedule_node *node); + +__isl_give isl_schedule_node *isl_schedule_node_group( + __isl_take isl_schedule_node *node, __isl_take isl_id *group_id); + +__isl_give isl_schedule_node *isl_schedule_node_sequence_splice_child( + __isl_take isl_schedule_node *node, int pos); + +__isl_give isl_space *isl_schedule_node_band_get_space( + __isl_keep isl_schedule_node *node); +__isl_give isl_multi_union_pw_aff *isl_schedule_node_band_get_partial_schedule( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_band_get_partial_schedule_union_map( + __isl_keep isl_schedule_node *node); +enum isl_ast_loop_type isl_schedule_node_band_member_get_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos); +__isl_give isl_schedule_node *isl_schedule_node_band_member_set_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type); +enum isl_ast_loop_type isl_schedule_node_band_member_get_isolate_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos); +__isl_give isl_schedule_node * +isl_schedule_node_band_member_set_isolate_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type); +__isl_give isl_union_set *isl_schedule_node_band_get_ast_build_options( + __isl_keep isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_band_set_ast_build_options( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *options); +__isl_give isl_set *isl_schedule_node_band_get_ast_isolate_option( + __isl_keep isl_schedule_node *node); +unsigned isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node); +__isl_export +isl_bool isl_schedule_node_band_member_get_coincident( + __isl_keep isl_schedule_node *node, int pos); +__isl_export +__isl_give isl_schedule_node *isl_schedule_node_band_member_set_coincident( + __isl_take isl_schedule_node *node, int pos, int coincident); +isl_bool isl_schedule_node_band_get_permutable( + __isl_keep isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_band_set_permutable( + __isl_take isl_schedule_node *node, int permutable); + +isl_stat isl_options_set_tile_scale_tile_loops(isl_ctx *ctx, int val); +int isl_options_get_tile_scale_tile_loops(isl_ctx *ctx); +isl_stat isl_options_set_tile_shift_point_loops(isl_ctx *ctx, int val); +int isl_options_get_tile_shift_point_loops(isl_ctx *ctx); + +__isl_give isl_schedule_node *isl_schedule_node_band_scale( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_node *isl_schedule_node_band_scale_down( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_node *isl_schedule_node_band_mod( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_node *isl_schedule_node_band_shift( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *shift); +__isl_give isl_schedule_node *isl_schedule_node_band_tile( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes); +__isl_give isl_schedule_node *isl_schedule_node_band_sink( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_band_split( + __isl_take isl_schedule_node *node, int pos); + +__isl_give isl_set *isl_schedule_node_context_get_context( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_set *isl_schedule_node_domain_get_domain( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_expansion_get_expansion( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_pw_multi_aff *isl_schedule_node_expansion_get_contraction( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_extension_get_extension( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_set *isl_schedule_node_filter_get_filter( + __isl_keep isl_schedule_node *node); +__isl_give isl_set *isl_schedule_node_guard_get_guard( + __isl_keep isl_schedule_node *node); +__isl_give isl_id *isl_schedule_node_mark_get_id( + __isl_keep isl_schedule_node *node); + +int isl_schedule_node_get_schedule_depth(__isl_keep isl_schedule_node *node); +__isl_give isl_union_set *isl_schedule_node_get_domain( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_set *isl_schedule_node_get_universe_domain( + __isl_keep isl_schedule_node *node); +__isl_export +__isl_give isl_multi_union_pw_aff * +isl_schedule_node_get_prefix_schedule_multi_union_pw_aff( + __isl_keep isl_schedule_node *node); +__isl_export +__isl_give isl_union_pw_multi_aff * +isl_schedule_node_get_prefix_schedule_union_pw_multi_aff( + __isl_keep isl_schedule_node *node); +__isl_export +__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_union_map( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_relation( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_get_subtree_schedule_union_map( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_get_subtree_expansion( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_pw_multi_aff *isl_schedule_node_get_subtree_contraction( + __isl_keep isl_schedule_node *node); + +__isl_give isl_schedule_node *isl_schedule_node_insert_context( + __isl_take isl_schedule_node *node, __isl_take isl_set *context); +__isl_give isl_schedule_node *isl_schedule_node_insert_partial_schedule( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *schedule); +__isl_give isl_schedule_node *isl_schedule_node_insert_filter( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter); +__isl_give isl_schedule_node *isl_schedule_node_insert_guard( + __isl_take isl_schedule_node *node, __isl_take isl_set *context); +__isl_give isl_schedule_node *isl_schedule_node_insert_mark( + __isl_take isl_schedule_node *node, __isl_take isl_id *mark); +__isl_give isl_schedule_node *isl_schedule_node_insert_sequence( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters); +__isl_give isl_schedule_node *isl_schedule_node_insert_set( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters); + +__isl_give isl_schedule_node *isl_schedule_node_cut( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_delete( + __isl_take isl_schedule_node *node); + +__isl_give isl_schedule_node *isl_schedule_node_order_before( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter); +__isl_give isl_schedule_node *isl_schedule_node_order_after( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter); + +__isl_give isl_schedule_node *isl_schedule_node_graft_before( + __isl_take isl_schedule_node *node, + __isl_take isl_schedule_node *graft); +__isl_give isl_schedule_node *isl_schedule_node_graft_after( + __isl_take isl_schedule_node *node, + __isl_take isl_schedule_node *graft); + +__isl_give isl_schedule_node *isl_schedule_node_reset_user( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_align_params( + __isl_take isl_schedule_node *node, __isl_take isl_space *space); + +__isl_give isl_printer *isl_printer_print_schedule_node( + __isl_take isl_printer *p, __isl_keep isl_schedule_node *node); +void isl_schedule_node_dump(__isl_keep isl_schedule_node *node); +__isl_give char *isl_schedule_node_to_str(__isl_keep isl_schedule_node *node); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/schedule_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/schedule_type.h @@ -0,0 +1,33 @@ +#ifndef ISL_SCHEDULE_TYPE_H +#define ISL_SCHEDULE_TYPE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +enum isl_schedule_node_type { + isl_schedule_node_error = -1, + isl_schedule_node_band, + isl_schedule_node_context, + isl_schedule_node_domain, + isl_schedule_node_expansion, + isl_schedule_node_extension, + isl_schedule_node_filter, + isl_schedule_node_leaf, + isl_schedule_node_guard, + isl_schedule_node_mark, + isl_schedule_node_sequence, + isl_schedule_node_set +}; + +struct __isl_export isl_schedule_node; +typedef struct isl_schedule_node isl_schedule_node; + +struct __isl_export isl_schedule; +typedef struct isl_schedule isl_schedule; + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/set.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/set.h @@ -0,0 +1,515 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_SET_H +#define ISL_SET_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +unsigned isl_basic_set_n_dim(__isl_keep isl_basic_set *bset); +unsigned isl_basic_set_n_param(__isl_keep isl_basic_set *bset); +unsigned isl_basic_set_total_dim(__isl_keep const isl_basic_set *bset); +unsigned isl_basic_set_dim(__isl_keep isl_basic_set *bset, + enum isl_dim_type type); + +unsigned isl_set_n_dim(__isl_keep isl_set *set); +unsigned isl_set_n_param(__isl_keep isl_set *set); +unsigned isl_set_dim(__isl_keep isl_set *set, enum isl_dim_type type); + +isl_ctx *isl_basic_set_get_ctx(__isl_keep isl_basic_set *bset); +isl_ctx *isl_set_get_ctx(__isl_keep isl_set *set); +__isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset); +__isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set); +__isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set, + __isl_take isl_space *dim); + +__isl_give isl_aff *isl_basic_set_get_div(__isl_keep 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); +isl_bool isl_set_has_tuple_name(__isl_keep isl_set *set); +const char *isl_set_get_tuple_name(__isl_keep isl_set *set); +__isl_give isl_basic_set *isl_basic_set_set_tuple_name( + __isl_take isl_basic_set *set, const char *s); +__isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set, + const char *s); +const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos); +__isl_give isl_basic_set *isl_basic_set_set_dim_name( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, const char *s); +isl_bool isl_set_has_dim_name(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +const char *isl_set_get_dim_name(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +__isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, const char *s); + +__isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos); +__isl_give isl_basic_set *isl_basic_set_set_tuple_id( + __isl_take isl_basic_set *bset, __isl_take isl_id *id); +__isl_give isl_set *isl_set_set_dim_id(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); +isl_bool isl_set_has_dim_id(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +__isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +__isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set, + __isl_take isl_id *id); +__isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set); +isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set); +__isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set); +__isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set); + +int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type, + __isl_keep isl_id *id); +int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type, + const char *name); + +int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset); + +__isl_null isl_basic_set *isl_basic_set_free(__isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_copy(__isl_keep isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_empty(__isl_take isl_space *space); +__isl_give isl_basic_set *isl_basic_set_universe(__isl_take isl_space *space); +__isl_give isl_basic_set *isl_basic_set_nat_universe(__isl_take isl_space *dim); +__isl_give isl_basic_set *isl_basic_set_positive_orthant( + __isl_take isl_space *space); +void isl_basic_set_print_internal(__isl_keep isl_basic_set *bset, + FILE *out, int indent); +__isl_export +__isl_give isl_basic_set *isl_basic_set_intersect( + __isl_take isl_basic_set *bset1, + __isl_take isl_basic_set *bset2); +__isl_export +__isl_give isl_basic_set *isl_basic_set_intersect_params( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2); +__isl_export +__isl_give isl_basic_set *isl_basic_set_apply( + __isl_take isl_basic_set *bset, + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_set *isl_basic_set_preimage_multi_aff( + __isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma); +__isl_export +__isl_give isl_basic_set *isl_basic_set_affine_hull( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_remove_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_export +__isl_give isl_basic_set *isl_basic_set_sample(__isl_take isl_basic_set *bset); +__isl_export +__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_set *isl_set_remove_redundancies(__isl_take isl_set *set); +__isl_give isl_basic_set *isl_basic_set_list_intersect( + __isl_take struct isl_basic_set_list *list); + +__isl_give isl_set *isl_set_list_union(__isl_take isl_set_list *list); + +__isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx, + FILE *input); +__isl_constructor +__isl_give isl_basic_set *isl_basic_set_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give isl_set *isl_set_read_from_file(isl_ctx *ctx, FILE *input); +__isl_constructor +__isl_give isl_set *isl_set_read_from_str(isl_ctx *ctx, const char *str); +void isl_basic_set_dump(__isl_keep isl_basic_set *bset); +void isl_set_dump(__isl_keep isl_set *set); +__isl_give isl_printer *isl_printer_print_basic_set( + __isl_take isl_printer *printer, __isl_keep isl_basic_set *bset); +__isl_give isl_printer *isl_printer_print_set(__isl_take isl_printer *printer, + __isl_keep isl_set *map); +__isl_give isl_basic_set *isl_basic_set_fix_si(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, int value); +__isl_give isl_basic_set *isl_basic_set_fix_val(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v); +__isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value); +__isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value); +__isl_give isl_basic_set *isl_basic_set_lower_bound_val( + __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value); +__isl_give isl_set *isl_set_lower_bound_val(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *value); +__isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value); +__isl_give isl_basic_set *isl_basic_set_upper_bound_val( + __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value); +__isl_give isl_set *isl_set_upper_bound_val(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *value); + +__isl_give isl_set *isl_set_equate(__isl_take isl_set *set, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2); + +__isl_export +isl_bool isl_basic_set_is_equal(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2); +isl_bool isl_basic_set_is_disjoint(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2); + +__isl_give isl_set *isl_basic_set_partial_lexmin( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); +__isl_give isl_set *isl_basic_set_partial_lexmax( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); +__isl_give isl_set *isl_set_partial_lexmin( + __isl_take isl_set *set, __isl_take isl_set *dom, + __isl_give isl_set **empty); +__isl_give isl_set *isl_set_partial_lexmax( + __isl_take isl_set *set, __isl_take isl_set *dom, + __isl_give isl_set **empty); +__isl_export +__isl_give isl_set *isl_basic_set_lexmin(__isl_take isl_basic_set *bset); +__isl_export +__isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset); +__isl_export +__isl_give isl_set *isl_set_lexmin(__isl_take isl_set *set); +__isl_export +__isl_give isl_set *isl_set_lexmax(__isl_take isl_set *set); +__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmin_pw_multi_aff( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); +__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmax_pw_multi_aff( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty); +__isl_give isl_pw_multi_aff *isl_set_lexmin_pw_multi_aff( + __isl_take isl_set *set); +__isl_give isl_pw_multi_aff *isl_set_lexmax_pw_multi_aff( + __isl_take isl_set *set); + +__isl_export +__isl_give isl_set *isl_basic_set_union( + __isl_take isl_basic_set *bset1, + __isl_take isl_basic_set *bset2); + +int isl_basic_set_compare_at(struct isl_basic_set *bset1, + struct isl_basic_set *bset2, int pos); +int isl_set_follows_at(__isl_keep isl_set *set1, + __isl_keep isl_set *set2, int pos); + +__isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_from_params( + __isl_take isl_basic_set *bset); +__isl_give isl_set *isl_set_params(__isl_take isl_set *set); +__isl_give isl_set *isl_set_from_params(__isl_take isl_set *set); + +isl_stat isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, unsigned n, int *signs); + +isl_bool isl_basic_set_plain_is_universe(__isl_keep isl_basic_set *bset); +isl_bool isl_basic_set_is_universe(__isl_keep isl_basic_set *bset); +isl_bool isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset); +__isl_export +isl_bool isl_basic_set_is_empty(__isl_keep isl_basic_set *bset); +isl_bool isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset); +__isl_export +isl_bool isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2); +isl_bool isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2); + +__isl_give isl_set *isl_set_empty(__isl_take isl_space *space); +__isl_give isl_set *isl_set_universe(__isl_take isl_space *space); +__isl_give isl_set *isl_set_nat_universe(__isl_take isl_space *dim); +__isl_give isl_set *isl_set_copy(__isl_keep isl_set *set); +__isl_null isl_set *isl_set_free(__isl_take isl_set *set); +__isl_constructor +__isl_give isl_set *isl_set_from_basic_set(__isl_take isl_basic_set *bset); +__isl_export +__isl_give isl_basic_set *isl_set_sample(__isl_take isl_set *set); +__isl_export +__isl_give isl_point *isl_basic_set_sample_point(__isl_take isl_basic_set *bset); +__isl_export +__isl_give isl_point *isl_set_sample_point(__isl_take isl_set *set); +__isl_export +__isl_give isl_set *isl_set_detect_equalities(__isl_take isl_set *set); +__isl_export +__isl_give isl_basic_set *isl_set_affine_hull(__isl_take isl_set *set); +__isl_give isl_basic_set *isl_set_convex_hull(__isl_take isl_set *set); +__isl_export +__isl_give isl_basic_set *isl_set_polyhedral_hull(__isl_take isl_set *set); +__isl_give isl_basic_set *isl_set_simple_hull(__isl_take isl_set *set); +__isl_export +__isl_give isl_basic_set *isl_set_unshifted_simple_hull( + __isl_take isl_set *set); +__isl_give isl_basic_set *isl_set_plain_unshifted_simple_hull( + __isl_take isl_set *set); +__isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list( + __isl_take isl_set *set, __isl_take isl_set_list *list); +__isl_give isl_basic_set *isl_set_bounded_simple_hull(__isl_take isl_set *set); + +__isl_give isl_set *isl_set_union_disjoint( + __isl_take isl_set *set1, __isl_take isl_set *set2); +__isl_export +__isl_give isl_set *isl_set_union( + __isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_give isl_set *isl_set_product(__isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_give isl_basic_set *isl_basic_set_flat_product( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2); +__isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_export +__isl_give isl_set *isl_set_intersect( + __isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_export +__isl_give isl_set *isl_set_intersect_params(__isl_take isl_set *set, + __isl_take isl_set *params); +__isl_export +__isl_give isl_set *isl_set_subtract( + __isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_export +__isl_give isl_set *isl_set_complement(__isl_take isl_set *set); +__isl_export +__isl_give isl_set *isl_set_apply( + __isl_take isl_set *set, + __isl_take isl_map *map); +__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set, + __isl_take isl_multi_aff *ma); +__isl_give isl_set *isl_set_preimage_pw_multi_aff(__isl_take isl_set *set, + __isl_take isl_pw_multi_aff *pma); +__isl_give isl_set *isl_set_preimage_multi_pw_aff(__isl_take isl_set *set, + __isl_take isl_multi_pw_aff *mpa); +__isl_give isl_set *isl_set_fix_val(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v); +struct isl_set *isl_set_fix_dim_si(struct isl_set *set, + unsigned dim, int value); +__isl_give isl_basic_set *isl_basic_set_insert_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, unsigned n); +__isl_give isl_set *isl_set_insert_dims(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, unsigned n); +__isl_give isl_basic_set *isl_basic_set_add_dims(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned n); +ISL_DEPRECATED +__isl_give isl_basic_set *isl_basic_set_add(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned n); +__isl_give isl_set *isl_set_add_dims(__isl_take isl_set *set, + enum isl_dim_type type, unsigned n); +__isl_give isl_basic_set *isl_basic_set_move_dims(__isl_take isl_basic_set *bset, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); +__isl_give isl_set *isl_set_move_dims(__isl_take isl_set *set, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); +__isl_give isl_basic_set *isl_basic_set_project_out( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_set *isl_set_project_out(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_map *isl_set_project_onto_map(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_set *isl_basic_set_remove_divs( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_eliminate( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set, + unsigned first, unsigned n); +__isl_give isl_set *isl_set_remove_dims(__isl_take isl_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_set *isl_basic_set_remove_divs_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_set *isl_basic_set_remove_unknown_divs( + __isl_take isl_basic_set *bset); +__isl_give isl_set *isl_set_remove_unknown_divs(__isl_take isl_set *set); +__isl_give isl_set *isl_set_remove_divs(__isl_take isl_set *set); +__isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_set *isl_basic_set_drop_constraints_not_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_set *isl_set_drop_constraints_involving_dims( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_set *isl_set_drop_constraints_not_involving_dims( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); + +isl_bool isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +isl_bool 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); +isl_bool isl_set_plain_is_empty(__isl_keep isl_set *set); +isl_bool isl_set_plain_is_universe(__isl_keep isl_set *set); +isl_bool isl_set_is_params(__isl_keep isl_set *set); +__isl_export +isl_bool isl_set_is_empty(__isl_keep isl_set *set); +isl_bool isl_set_is_bounded(__isl_keep isl_set *set); +__isl_export +isl_bool isl_set_is_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2); +__isl_export +isl_bool isl_set_is_strict_subset(__isl_keep isl_set *set1, + __isl_keep isl_set *set2); +__isl_export +isl_bool isl_set_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2); +__isl_export +isl_bool isl_set_is_disjoint(__isl_keep isl_set *set1, + __isl_keep isl_set *set2); +isl_bool isl_set_is_singleton(__isl_keep isl_set *set); +isl_bool isl_set_is_box(__isl_keep isl_set *set); +isl_bool isl_set_has_equal_space(__isl_keep isl_set *set1, + __isl_keep isl_set *set2); + +__isl_give isl_set *isl_set_sum(__isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_give isl_basic_set *isl_basic_set_neg(__isl_take isl_basic_set *bset); +__isl_give isl_set *isl_set_neg(__isl_take isl_set *set); + +__isl_give isl_set *isl_set_make_disjoint(__isl_take isl_set *set); +__isl_give isl_set *isl_basic_set_compute_divs(__isl_take isl_basic_set *bset); +__isl_give isl_set *isl_set_compute_divs(__isl_take isl_set *set); +ISL_DEPRECATED +__isl_give isl_set *isl_set_align_divs(__isl_take isl_set *set); + +__isl_give isl_val *isl_set_plain_get_val_if_fixed(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +isl_bool isl_set_dim_is_bounded(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +isl_bool isl_set_dim_has_lower_bound(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +isl_bool isl_set_dim_has_upper_bound(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +isl_bool isl_set_dim_has_any_lower_bound(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); +isl_bool isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos); + +__isl_export +__isl_give isl_basic_set *isl_basic_set_gist(__isl_take isl_basic_set *bset, + __isl_take isl_basic_set *context); +__isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *context); +__isl_export +__isl_give isl_set *isl_set_gist(__isl_take isl_set *set, + __isl_take isl_set *context); +__isl_give isl_set *isl_set_gist_params(__isl_take isl_set *set, + __isl_take isl_set *context); +isl_stat isl_set_dim_residue_class_val(__isl_keep isl_set *set, + int pos, __isl_give isl_val **modulo, __isl_give isl_val **residue); + +__isl_export +__isl_give isl_set *isl_set_coalesce(__isl_take isl_set *set); + +int isl_set_plain_cmp(__isl_keep isl_set *set1, __isl_keep isl_set *set2); +isl_bool isl_set_plain_is_equal(__isl_keep isl_set *set1, + __isl_keep isl_set *set2); +isl_bool isl_set_plain_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_n_basic_set(__isl_keep isl_set *set); +__isl_export +isl_stat isl_set_foreach_basic_set(__isl_keep isl_set *set, + isl_stat (*fn)(__isl_take isl_basic_set *bset, void *user), void *user); +__isl_give isl_basic_set_list *isl_set_get_basic_set_list( + __isl_keep isl_set *set); + +isl_stat isl_set_foreach_point(__isl_keep isl_set *set, + isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user); +__isl_give isl_val *isl_set_count_val(__isl_keep isl_set *set); + +__isl_constructor +__isl_give isl_basic_set *isl_basic_set_from_point(__isl_take isl_point *pnt); +__isl_constructor +__isl_give isl_set *isl_set_from_point(__isl_take isl_point *pnt); +__isl_give isl_basic_set *isl_basic_set_box_from_points( + __isl_take isl_point *pnt1, __isl_take isl_point *pnt2); +__isl_give isl_set *isl_set_box_from_points(__isl_take isl_point *pnt1, + __isl_take isl_point *pnt2); + +__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_map *isl_set_lex_le_set(__isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_give isl_map *isl_set_lex_lt_set(__isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_give isl_map *isl_set_lex_ge_set(__isl_take isl_set *set1, + __isl_take isl_set *set2); +__isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1, + __isl_take isl_set *set2); + +int isl_set_size(__isl_keep isl_set *set); + +__isl_give isl_basic_set *isl_basic_set_align_params( + __isl_take isl_basic_set *bset, __isl_take isl_space *model); +__isl_give isl_set *isl_set_align_params(__isl_take isl_set *set, + __isl_take isl_space *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_inequalities_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_basic_set *isl_basic_set_from_constraint_matrices( + __isl_take isl_space *dim, + __isl_take isl_mat *eq, __isl_take isl_mat *ineq, 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_list *isl_basic_set_list_coefficients( + __isl_take isl_basic_set_list *list); +__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); + +__isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos); +__isl_give isl_pw_aff *isl_set_dim_min(__isl_take isl_set *set, int pos); + +__isl_give char *isl_basic_set_to_str(__isl_keep isl_basic_set *bset); +__isl_give char *isl_set_to_str(__isl_keep isl_set *set); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/set_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/set_type.h @@ -0,0 +1,6 @@ +#ifndef ISL_SET_TYPE_H +#define ISL_SET_TYPE_H + +#include + +#endif Index: contrib/isl/include/isl/space.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/space.h @@ -0,0 +1,187 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_SPACE_H +#define ISL_SPACE_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_space; +typedef struct isl_space isl_space; + +enum isl_dim_type { + isl_dim_cst, + isl_dim_param, + isl_dim_in, + isl_dim_out, + isl_dim_set = isl_dim_out, + isl_dim_div, + isl_dim_all +}; + +isl_ctx *isl_space_get_ctx(__isl_keep isl_space *dim); +__isl_give isl_space *isl_space_alloc(isl_ctx *ctx, + unsigned nparam, unsigned n_in, unsigned n_out); +__isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx, + unsigned nparam, unsigned dim); +__isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam); +__isl_give isl_space *isl_space_copy(__isl_keep isl_space *dim); +__isl_null isl_space *isl_space_free(__isl_take isl_space *space); + +isl_bool isl_space_is_params(__isl_keep isl_space *space); +isl_bool isl_space_is_set(__isl_keep isl_space *space); +isl_bool isl_space_is_map(__isl_keep isl_space *space); + +__isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *dim, + enum isl_dim_type type, const char *s); +isl_bool isl_space_has_tuple_name(__isl_keep isl_space *space, + enum isl_dim_type type); +__isl_keep const char *isl_space_get_tuple_name(__isl_keep isl_space *dim, + enum isl_dim_type type); +__isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *dim, + enum isl_dim_type type, __isl_take isl_id *id); +__isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *dim, + enum isl_dim_type type); +isl_bool isl_space_has_tuple_id(__isl_keep isl_space *dim, + enum isl_dim_type type); +__isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *dim, + enum isl_dim_type type); +__isl_give isl_space *isl_space_reset_user(__isl_take isl_space *space); + +__isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); +isl_bool isl_space_has_dim_id(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos); +__isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos); + +int isl_space_find_dim_by_id(__isl_keep isl_space *dim, enum isl_dim_type type, + __isl_keep isl_id *id); +int isl_space_find_dim_by_name(__isl_keep isl_space *space, + enum isl_dim_type type, const char *name); + +isl_bool isl_space_has_dim_name(__isl_keep isl_space *space, + enum isl_dim_type type, unsigned pos); +__isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned pos, + __isl_keep const char *name); +__isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos); + +ISL_DEPRECATED +__isl_give isl_space *isl_space_extend(__isl_take isl_space *dim, + unsigned nparam, unsigned n_in, unsigned n_out); +__isl_give isl_space *isl_space_add_dims(__isl_take isl_space *space, + enum isl_dim_type type, unsigned n); +__isl_give isl_space *isl_space_move_dims(__isl_take isl_space *space, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); +__isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned pos, unsigned n); +__isl_give isl_space *isl_space_join(__isl_take isl_space *left, + __isl_take isl_space *right); +__isl_give isl_space *isl_space_product(__isl_take isl_space *left, + __isl_take isl_space *right); +__isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left, + __isl_take isl_space *right); +__isl_give isl_space *isl_space_range_product(__isl_take isl_space *left, + __isl_take isl_space *right); +__isl_give isl_space *isl_space_factor_domain(__isl_take isl_space *space); +__isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space); +__isl_give isl_space *isl_space_domain_factor_domain( + __isl_take isl_space *space); +__isl_give isl_space *isl_space_domain_factor_range( + __isl_take isl_space *space); +__isl_give isl_space *isl_space_range_factor_domain( + __isl_take isl_space *space); +__isl_give isl_space *isl_space_range_factor_range( + __isl_take isl_space *space); +__isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space); +__isl_give isl_space *isl_space_map_from_domain_and_range( + __isl_take isl_space *domain, __isl_take isl_space *range); +__isl_give isl_space *isl_space_reverse(__isl_take isl_space *dim); +__isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned first, unsigned num); +ISL_DEPRECATED +__isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *dim, + unsigned first, unsigned n); +ISL_DEPRECATED +__isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *dim, + unsigned first, unsigned n); +__isl_give isl_space *isl_space_domain(__isl_take isl_space *space); +__isl_give isl_space *isl_space_from_domain(__isl_take isl_space *dim); +__isl_give isl_space *isl_space_range(__isl_take isl_space *space); +__isl_give isl_space *isl_space_from_range(__isl_take isl_space *dim); +__isl_give isl_space *isl_space_domain_map(__isl_take isl_space *space); +__isl_give isl_space *isl_space_range_map(__isl_take isl_space *space); +__isl_give isl_space *isl_space_params(__isl_take isl_space *space); +__isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space); + +__isl_give isl_space *isl_space_align_params(__isl_take isl_space *dim1, + __isl_take isl_space *dim2); + +isl_bool isl_space_is_wrapping(__isl_keep isl_space *dim); +isl_bool isl_space_domain_is_wrapping(__isl_keep isl_space *space); +isl_bool isl_space_range_is_wrapping(__isl_keep isl_space *space); +isl_bool isl_space_is_product(__isl_keep isl_space *space); +__isl_give isl_space *isl_space_wrap(__isl_take isl_space *dim); +__isl_give isl_space *isl_space_unwrap(__isl_take isl_space *dim); + +isl_bool isl_space_can_zip(__isl_keep isl_space *space); +__isl_give isl_space *isl_space_zip(__isl_take isl_space *dim); + +isl_bool isl_space_can_curry(__isl_keep isl_space *space); +__isl_give isl_space *isl_space_curry(__isl_take isl_space *space); + +isl_bool isl_space_can_range_curry(__isl_keep isl_space *space); +__isl_give isl_space *isl_space_range_curry(__isl_take isl_space *space); + +isl_bool isl_space_can_uncurry(__isl_keep isl_space *space); +__isl_give isl_space *isl_space_uncurry(__isl_take isl_space *space); + +isl_bool isl_space_is_domain(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); +isl_bool isl_space_is_range(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); +isl_bool isl_space_is_equal(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); +isl_bool isl_space_has_equal_params(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); +isl_bool isl_space_has_equal_tuples(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); +isl_bool isl_space_tuple_is_equal(__isl_keep isl_space *space1, + enum isl_dim_type type1, __isl_keep isl_space *space2, + enum isl_dim_type type2); +ISL_DEPRECATED +isl_bool isl_space_match(__isl_keep isl_space *space1, enum isl_dim_type type1, + __isl_keep isl_space *space2, enum isl_dim_type type2); +ISL_DEPRECATED +int isl_space_tuple_match(__isl_keep isl_space *space1, enum isl_dim_type type1, + __isl_keep isl_space *space2, enum isl_dim_type type2); +unsigned isl_space_dim(__isl_keep isl_space *dim, enum isl_dim_type type); + +__isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *space); +__isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *space); + +__isl_give char *isl_space_to_str(__isl_keep isl_space *space); +__isl_give isl_printer *isl_printer_print_space(__isl_take isl_printer *p, + __isl_keep isl_space *dim); +void isl_space_dump(__isl_keep isl_space *dim); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/stream.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/stream.h @@ -0,0 +1,97 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_STREAM_H +#define ISL_STREAM_H + +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +enum isl_token_type { ISL_TOKEN_ERROR = -1, + ISL_TOKEN_UNKNOWN = 256, ISL_TOKEN_VALUE, + ISL_TOKEN_IDENT, ISL_TOKEN_GE, + ISL_TOKEN_LE, ISL_TOKEN_GT, ISL_TOKEN_LT, + ISL_TOKEN_NE, ISL_TOKEN_EQ_EQ, + ISL_TOKEN_LEX_GE, ISL_TOKEN_LEX_LE, + ISL_TOKEN_LEX_GT, ISL_TOKEN_LEX_LT, + ISL_TOKEN_TO, ISL_TOKEN_AND, + ISL_TOKEN_OR, ISL_TOKEN_EXISTS, ISL_TOKEN_NOT, + ISL_TOKEN_DEF, ISL_TOKEN_INFTY, ISL_TOKEN_NAN, + ISL_TOKEN_MIN, ISL_TOKEN_MAX, ISL_TOKEN_RAT, + ISL_TOKEN_TRUE, ISL_TOKEN_FALSE, + ISL_TOKEN_CEILD, ISL_TOKEN_FLOORD, ISL_TOKEN_MOD, + ISL_TOKEN_STRING, + ISL_TOKEN_MAP, ISL_TOKEN_AFF, + ISL_TOKEN_CEIL, ISL_TOKEN_FLOOR, + ISL_TOKEN_IMPLIES, + ISL_TOKEN_LAST }; + +struct isl_token; + +__isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok); +__isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok); +int isl_token_get_type(struct isl_token *tok); +void isl_token_free(struct isl_token *tok); + +struct isl_stream; +typedef struct isl_stream isl_stream; + +__isl_give isl_stream *isl_stream_new_file(isl_ctx *ctx, FILE *file); +__isl_give isl_stream *isl_stream_new_str(isl_ctx *ctx, const char *str); +void isl_stream_free(__isl_take isl_stream *s); + +isl_ctx *isl_stream_get_ctx(__isl_keep isl_stream *s); + +void isl_stream_error(__isl_keep isl_stream *s, struct isl_token *tok, + char *msg); + +struct isl_token *isl_stream_next_token(__isl_keep isl_stream *s); +struct isl_token *isl_stream_next_token_on_same_line(__isl_keep isl_stream *s); +int isl_stream_next_token_is(__isl_keep isl_stream *s, int type); +void isl_stream_push_token(__isl_keep isl_stream *s, struct isl_token *tok); +void isl_stream_flush_tokens(__isl_keep isl_stream *s); +int isl_stream_eat_if_available(__isl_keep isl_stream *s, int type); +char *isl_stream_read_ident_if_available(__isl_keep isl_stream *s); +int isl_stream_eat(__isl_keep isl_stream *s, int type); +int isl_stream_is_empty(__isl_keep isl_stream *s); +int isl_stream_skip_line(__isl_keep isl_stream *s); + +enum isl_token_type isl_stream_register_keyword(__isl_keep isl_stream *s, + const char *name); + +struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s); +__isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s); +__isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s); +__isl_give isl_map *isl_stream_read_map(__isl_keep isl_stream *s); +__isl_give isl_set *isl_stream_read_set(__isl_keep isl_stream *s); +__isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial( + __isl_keep isl_stream *s); +__isl_give isl_union_set *isl_stream_read_union_set(__isl_keep isl_stream *s); +__isl_give isl_union_map *isl_stream_read_union_map(__isl_keep isl_stream *s); +__isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s); + +int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s); +int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s); +int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s); +int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s); +int isl_stream_yaml_next(__isl_keep isl_stream *s); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/union_map.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/union_map.h @@ -0,0 +1,306 @@ +#ifndef ISL_UNION_MAP_H +#define ISL_UNION_MAP_H + +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +unsigned isl_union_map_dim(__isl_keep isl_union_map *umap, + enum isl_dim_type type); +isl_bool isl_union_map_involves_dims(__isl_keep isl_union_map *umap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_id *isl_union_map_get_dim_id(__isl_keep isl_union_map *umap, + enum isl_dim_type type, unsigned pos); + +__isl_constructor +__isl_give isl_union_map *isl_union_map_from_basic_map( + __isl_take isl_basic_map *bmap); +__isl_constructor +__isl_give isl_union_map *isl_union_map_from_map(__isl_take isl_map *map); +__isl_give isl_union_map *isl_union_map_empty(__isl_take isl_space *space); +__isl_give isl_union_map *isl_union_map_copy(__isl_keep isl_union_map *umap); +__isl_null isl_union_map *isl_union_map_free(__isl_take isl_union_map *umap); + +isl_ctx *isl_union_map_get_ctx(__isl_keep isl_union_map *umap); +__isl_give isl_space *isl_union_map_get_space(__isl_keep isl_union_map *umap); + +__isl_give isl_union_map *isl_union_map_reset_user( + __isl_take isl_union_map *umap); + +int isl_union_map_find_dim_by_name(__isl_keep isl_union_map *umap, + enum isl_dim_type type, const char *name); + +__isl_give isl_union_map *isl_union_map_universe( + __isl_take isl_union_map *umap); +__isl_give isl_set *isl_union_map_params(__isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_set *isl_union_map_domain(__isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_set *isl_union_map_range(__isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_domain_map( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_pw_multi_aff *isl_union_map_domain_map_union_pw_multi_aff( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_range_map( + __isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_set_wrapped_domain_map( + __isl_take isl_union_set *uset); +__isl_give isl_union_map *isl_union_map_from_domain( + __isl_take isl_union_set *uset); +__isl_give isl_union_map *isl_union_map_from_range( + __isl_take isl_union_set *uset); + +__isl_export +__isl_give isl_union_map *isl_union_map_affine_hull( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_polyhedral_hull( + __isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_map_remove_redundancies( + __isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_map_simple_hull( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_coalesce( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_compute_divs( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_lexmin(__isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_lexmax(__isl_take isl_union_map *umap); + +__isl_give isl_union_map *isl_union_map_add_map(__isl_take isl_union_map *umap, + __isl_take isl_map *map); +__isl_export +__isl_give isl_union_map *isl_union_map_union(__isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); +__isl_export +__isl_give isl_union_map *isl_union_map_subtract( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_export +__isl_give isl_union_map *isl_union_map_intersect( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_export +__isl_give isl_union_map *isl_union_map_intersect_params( + __isl_take isl_union_map *umap, __isl_take isl_set *set); +__isl_export +__isl_give isl_union_map *isl_union_map_product(__isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); +__isl_export +__isl_give isl_union_map *isl_union_map_domain_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_give isl_union_map *isl_union_map_flat_domain_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_export +__isl_give isl_union_map *isl_union_map_range_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_give isl_union_map *isl_union_map_flat_range_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_export +__isl_give isl_union_map *isl_union_map_domain_factor_domain( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_domain_factor_range( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_range_factor_domain( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_range_factor_range( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_factor_domain( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_factor_range( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_gist(__isl_take isl_union_map *umap, + __isl_take isl_union_map *context); +__isl_export +__isl_give isl_union_map *isl_union_map_gist_params( + __isl_take isl_union_map *umap, __isl_take isl_set *set); +__isl_export +__isl_give isl_union_map *isl_union_map_gist_domain( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset); +__isl_export +__isl_give isl_union_map *isl_union_map_gist_range( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset); + +__isl_export +__isl_give isl_union_map *isl_union_map_intersect_domain( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset); +__isl_export +__isl_give isl_union_map *isl_union_map_intersect_range( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset); +__isl_give isl_union_map *isl_union_map_intersect_range_factor_range( + __isl_take isl_union_map *umap, __isl_take isl_union_map *factor); + +__isl_export +__isl_give isl_union_map *isl_union_map_subtract_domain( + __isl_take isl_union_map *umap, __isl_take isl_union_set *dom); +__isl_export +__isl_give isl_union_map *isl_union_map_subtract_range( + __isl_take isl_union_map *umap, __isl_take isl_union_set *dom); + +__isl_export +__isl_give isl_union_map *isl_union_map_apply_domain( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_export +__isl_give isl_union_map *isl_union_map_apply_range( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_give isl_union_map *isl_union_map_preimage_domain_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma); +__isl_give isl_union_map *isl_union_map_preimage_range_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma); +__isl_give isl_union_map *isl_union_map_preimage_domain_pw_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma); +__isl_give isl_union_map *isl_union_map_preimage_range_pw_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma); +__isl_give isl_union_map *isl_union_map_preimage_domain_multi_pw_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_pw_aff *mpa); +__isl_give isl_union_map *isl_union_map_preimage_domain_union_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_multi_aff *upma); +__isl_give isl_union_map *isl_union_map_preimage_range_union_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_multi_aff *upma); +__isl_export +__isl_give isl_union_map *isl_union_map_reverse(__isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_map_from_domain_and_range( + __isl_take isl_union_set *domain, __isl_take isl_union_set *range); + +__isl_export +__isl_give isl_union_map *isl_union_map_detect_equalities( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_set *isl_union_map_deltas(__isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_map_deltas_map( + __isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset); + +__isl_give isl_union_map *isl_union_map_project_out( + __isl_take isl_union_map *umap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_map *isl_union_map_remove_divs( + __isl_take isl_union_map *bmap); + +isl_bool isl_union_map_plain_is_empty(__isl_keep isl_union_map *umap); +__isl_export +isl_bool isl_union_map_is_empty(__isl_keep isl_union_map *umap); +__isl_export +isl_bool isl_union_map_is_single_valued(__isl_keep isl_union_map *umap); +isl_bool isl_union_map_plain_is_injective(__isl_keep isl_union_map *umap); +__isl_export +isl_bool isl_union_map_is_injective(__isl_keep isl_union_map *umap); +__isl_export +isl_bool isl_union_map_is_bijective(__isl_keep isl_union_map *umap); +isl_bool isl_union_map_is_identity(__isl_keep isl_union_map *umap); + +__isl_export +isl_bool isl_union_map_is_subset(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); +__isl_export +isl_bool isl_union_map_is_equal(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); +isl_bool isl_union_map_is_disjoint(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); +__isl_export +isl_bool isl_union_map_is_strict_subset(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); + +uint32_t isl_union_map_get_hash(__isl_keep isl_union_map *umap); + +int isl_union_map_n_map(__isl_keep isl_union_map *umap); +__isl_export +isl_stat isl_union_map_foreach_map(__isl_keep isl_union_map *umap, + isl_stat (*fn)(__isl_take isl_map *map, void *user), void *user); +isl_bool isl_union_map_every_map(__isl_keep isl_union_map *umap, + isl_bool (*test)(__isl_keep isl_map *map, void *user), void *user); +__isl_give isl_union_map *isl_union_map_remove_map_if( + __isl_take isl_union_map *umap, + isl_bool (*fn)(__isl_keep isl_map *map, void *user), void *user); +isl_bool isl_union_map_contains(__isl_keep isl_union_map *umap, + __isl_keep isl_space *space); +__isl_give isl_map *isl_union_map_extract_map(__isl_keep isl_union_map *umap, + __isl_take isl_space *dim); +__isl_give isl_map *isl_map_from_union_map(__isl_take isl_union_map *umap); + +__isl_give isl_basic_map *isl_union_map_sample(__isl_take isl_union_map *umap); + +__isl_overload +__isl_give isl_union_map *isl_union_map_fixed_power_val( + __isl_take isl_union_map *umap, __isl_take isl_val *exp); +__isl_give isl_union_map *isl_union_map_power(__isl_take isl_union_map *umap, + int *exact); +__isl_give isl_union_map *isl_union_map_transitive_closure( + __isl_take isl_union_map *umap, int *exact); + +__isl_give isl_union_map *isl_union_map_lex_lt_union_map( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_give isl_union_map *isl_union_map_lex_le_union_map( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_give isl_union_map *isl_union_map_lex_gt_union_map( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_give isl_union_map *isl_union_map_lex_ge_union_map( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); + +__isl_overload +__isl_give isl_union_map *isl_union_map_eq_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); +__isl_give isl_union_map *isl_union_map_lex_lt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); +__isl_give isl_union_map *isl_union_map_lex_gt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx, + FILE *input); +__isl_constructor +__isl_give isl_union_map *isl_union_map_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give char *isl_union_map_to_str(__isl_keep isl_union_map *umap); +__isl_give isl_printer *isl_printer_print_union_map(__isl_take isl_printer *p, + __isl_keep isl_union_map *umap); +void isl_union_map_dump(__isl_keep isl_union_map *umap); + +__isl_export +__isl_give isl_union_set *isl_union_map_wrap(__isl_take isl_union_map *umap); +__isl_export +__isl_give isl_union_map *isl_union_set_unwrap(__isl_take isl_union_set *uset); + +__isl_export +__isl_give isl_union_map *isl_union_map_zip(__isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_map_curry(__isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_map_range_curry( + __isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_map_uncurry(__isl_take isl_union_map *umap); + +__isl_give isl_union_map *isl_union_map_align_params( + __isl_take isl_union_map *umap, __isl_take isl_space *model); +__isl_give isl_union_set *isl_union_set_align_params( + __isl_take isl_union_set *uset, __isl_take isl_space *model); + +ISL_DECLARE_LIST_FN(union_map) + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/union_map_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/union_map_type.h @@ -0,0 +1,24 @@ +#ifndef ISL_UNION_MAP_TYPE_H +#define ISL_UNION_MAP_TYPE_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct __isl_export isl_union_map; +typedef struct isl_union_map isl_union_map; +ISL_DECLARE_LIST_TYPE(union_map) +#ifndef isl_union_set +struct __isl_export isl_union_set; +typedef struct isl_union_set isl_union_set; +ISL_DECLARE_LIST_TYPE(union_set) +#endif + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/union_set.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/union_set.h @@ -0,0 +1,176 @@ +#ifndef ISL_UNION_SET_H +#define ISL_UNION_SET_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +unsigned isl_union_set_dim(__isl_keep isl_union_set *uset, + enum isl_dim_type type); + +__isl_constructor +__isl_give isl_union_set *isl_union_set_from_basic_set( + __isl_take isl_basic_set *bset); +__isl_constructor +__isl_give isl_union_set *isl_union_set_from_set(__isl_take isl_set *set); +__isl_give isl_union_set *isl_union_set_empty(__isl_take isl_space *space); +__isl_give isl_union_set *isl_union_set_copy(__isl_keep isl_union_set *uset); +__isl_null isl_union_set *isl_union_set_free(__isl_take isl_union_set *uset); + +isl_ctx *isl_union_set_get_ctx(__isl_keep isl_union_set *uset); +__isl_give isl_space *isl_union_set_get_space(__isl_keep isl_union_set *uset); + +__isl_give isl_union_set *isl_union_set_reset_user( + __isl_take isl_union_set *uset); + +__isl_give isl_union_set *isl_union_set_universe( + __isl_take isl_union_set *uset); +__isl_give isl_set *isl_union_set_params(__isl_take isl_union_set *uset); + +__isl_export +__isl_give isl_union_set *isl_union_set_detect_equalities( + __isl_take isl_union_set *uset); +__isl_export +__isl_give isl_union_set *isl_union_set_affine_hull( + __isl_take isl_union_set *uset); +__isl_export +__isl_give isl_union_set *isl_union_set_polyhedral_hull( + __isl_take isl_union_set *uset); +__isl_give isl_union_set *isl_union_set_remove_redundancies( + __isl_take isl_union_set *uset); +__isl_give isl_union_set *isl_union_set_simple_hull( + __isl_take isl_union_set *uset); +__isl_export +__isl_give isl_union_set *isl_union_set_coalesce( + __isl_take isl_union_set *uset); +__isl_export +__isl_give isl_union_set *isl_union_set_compute_divs( + __isl_take isl_union_set *uset); +__isl_export +__isl_give isl_union_set *isl_union_set_lexmin(__isl_take isl_union_set *uset); +__isl_export +__isl_give isl_union_set *isl_union_set_lexmax(__isl_take isl_union_set *uset); + +__isl_give isl_union_set *isl_union_set_add_set(__isl_take isl_union_set *uset, + __isl_take isl_set *set); +__isl_export +__isl_give isl_union_set *isl_union_set_union(__isl_take isl_union_set *uset1, + __isl_take isl_union_set *uset2); +__isl_export +__isl_give isl_union_set *isl_union_set_subtract( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2); +__isl_export +__isl_give isl_union_set *isl_union_set_intersect( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2); +__isl_export +__isl_give isl_union_set *isl_union_set_intersect_params( + __isl_take isl_union_set *uset, __isl_take isl_set *set); +__isl_give isl_union_set *isl_union_set_product(__isl_take isl_union_set *uset1, + __isl_take isl_union_set *uset2); +__isl_export +__isl_give isl_union_set *isl_union_set_gist(__isl_take isl_union_set *uset, + __isl_take isl_union_set *context); +__isl_export +__isl_give isl_union_set *isl_union_set_gist_params( + __isl_take isl_union_set *uset, __isl_take isl_set *set); + +__isl_export +__isl_give isl_union_set *isl_union_set_apply( + __isl_take isl_union_set *uset, __isl_take isl_union_map *umap); +__isl_overload +__isl_give isl_union_set *isl_union_set_preimage_multi_aff( + __isl_take isl_union_set *uset, __isl_take isl_multi_aff *ma); +__isl_overload +__isl_give isl_union_set *isl_union_set_preimage_pw_multi_aff( + __isl_take isl_union_set *uset, __isl_take isl_pw_multi_aff *pma); +__isl_overload +__isl_give isl_union_set *isl_union_set_preimage_union_pw_multi_aff( + __isl_take isl_union_set *uset, + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_union_set *isl_union_set_project_out( + __isl_take isl_union_set *uset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_set *isl_union_set_remove_divs( + __isl_take isl_union_set *bset); + +isl_bool isl_union_set_is_params(__isl_keep isl_union_set *uset); +__isl_export +isl_bool isl_union_set_is_empty(__isl_keep isl_union_set *uset); + +__isl_export +isl_bool isl_union_set_is_subset(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); +__isl_export +isl_bool isl_union_set_is_equal(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); +isl_bool isl_union_set_is_disjoint(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); +__isl_export +isl_bool isl_union_set_is_strict_subset(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); + +uint32_t isl_union_set_get_hash(__isl_keep isl_union_set *uset); + +int isl_union_set_n_set(__isl_keep isl_union_set *uset); +__isl_export +isl_stat isl_union_set_foreach_set(__isl_keep isl_union_set *uset, + isl_stat (*fn)(__isl_take isl_set *set, void *user), void *user); +__isl_give isl_basic_set_list *isl_union_set_get_basic_set_list( + __isl_keep isl_union_set *uset); +isl_bool isl_union_set_contains(__isl_keep isl_union_set *uset, + __isl_keep isl_space *space); +__isl_give isl_set *isl_union_set_extract_set(__isl_keep isl_union_set *uset, + __isl_take isl_space *dim); +__isl_give isl_set *isl_set_from_union_set(__isl_take isl_union_set *uset); +__isl_export +isl_stat isl_union_set_foreach_point(__isl_keep isl_union_set *uset, + isl_stat (*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_export +__isl_give isl_point *isl_union_set_sample_point( + __isl_take isl_union_set *uset); + +__isl_constructor +__isl_give isl_union_set *isl_union_set_from_point(__isl_take isl_point *pnt); + +__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_take isl_union_set *uset1, __isl_take isl_union_set *uset2); +__isl_give isl_union_map *isl_union_set_lex_gt_union_set( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2); +__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_constructor +__isl_give isl_union_set *isl_union_set_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give char *isl_union_set_to_str(__isl_keep isl_union_set *uset); +__isl_give isl_printer *isl_printer_print_union_set(__isl_take isl_printer *p, + __isl_keep isl_union_set *uset); +void isl_union_set_dump(__isl_keep isl_union_set *uset); + +ISL_DECLARE_LIST_FN(union_set) + +__isl_give isl_union_set *isl_union_set_list_union( + __isl_take isl_union_set_list *list); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/union_set_type.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/union_set_type.h @@ -0,0 +1,6 @@ +#ifndef ISL_UNION_SET_TYPE_H +#define ISL_UNION_SET_TYPE_H + +#include + +#endif Index: contrib/isl/include/isl/val.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/val.h @@ -0,0 +1,167 @@ +#ifndef ISL_VAL_H +#define ISL_VAL_H + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct __isl_export isl_val; +typedef struct isl_val isl_val; + +ISL_DECLARE_LIST(val) + +struct __isl_export isl_multi_val; +typedef struct isl_multi_val isl_multi_val; + +ISL_DECLARE_MULTI(val) +ISL_DECLARE_MULTI_NEG(val) +ISL_DECLARE_MULTI_DIMS(val) +ISL_DECLARE_MULTI_WITH_DOMAIN(val) + +__isl_export +__isl_give isl_val *isl_val_zero(isl_ctx *ctx); +__isl_export +__isl_give isl_val *isl_val_one(isl_ctx *ctx); +__isl_export +__isl_give isl_val *isl_val_negone(isl_ctx *ctx); +__isl_export +__isl_give isl_val *isl_val_nan(isl_ctx *ctx); +__isl_export +__isl_give isl_val *isl_val_infty(isl_ctx *ctx); +__isl_export +__isl_give isl_val *isl_val_neginfty(isl_ctx *ctx); +__isl_constructor +__isl_give isl_val *isl_val_int_from_si(isl_ctx *ctx, long i); +__isl_give isl_val *isl_val_int_from_ui(isl_ctx *ctx, unsigned long u); +__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, size_t n, + size_t size, const void *chunks); + +__isl_give isl_val *isl_val_copy(__isl_keep isl_val *v); +__isl_null isl_val *isl_val_free(__isl_take isl_val *v); + +isl_ctx *isl_val_get_ctx(__isl_keep isl_val *val); +uint32_t isl_val_get_hash(__isl_keep isl_val *val); +long isl_val_get_num_si(__isl_keep isl_val *v); +long isl_val_get_den_si(__isl_keep isl_val *v); +__isl_give isl_val *isl_val_get_den_val(__isl_keep isl_val *v); +double isl_val_get_d(__isl_keep isl_val *v); +size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, size_t size); +int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, size_t size, + void *chunks); + +__isl_give isl_val *isl_val_set_si(__isl_take isl_val *v, long i); + +__isl_export +__isl_give isl_val *isl_val_abs(__isl_take isl_val *v); +__isl_export +__isl_give isl_val *isl_val_neg(__isl_take isl_val *v); +__isl_export +__isl_give isl_val *isl_val_inv(__isl_take isl_val *v); +__isl_export +__isl_give isl_val *isl_val_floor(__isl_take isl_val *v); +__isl_export +__isl_give isl_val *isl_val_ceil(__isl_take isl_val *v); +__isl_export +__isl_give isl_val *isl_val_trunc(__isl_take isl_val *v); +__isl_give isl_val *isl_val_2exp(__isl_take isl_val *v); +__isl_export +__isl_give isl_val *isl_val_min(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_export +__isl_give isl_val *isl_val_max(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_export +__isl_give isl_val *isl_val_add(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_give isl_val *isl_val_add_ui(__isl_take isl_val *v1, unsigned long v2); +__isl_export +__isl_give isl_val *isl_val_sub(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_give isl_val *isl_val_sub_ui(__isl_take isl_val *v1, unsigned long v2); +__isl_export +__isl_give isl_val *isl_val_mul(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_give isl_val *isl_val_mul_ui(__isl_take isl_val *v1, unsigned long v2); +__isl_export +__isl_give isl_val *isl_val_div(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_give isl_val *isl_val_div_ui(__isl_take isl_val *v1, unsigned long v2); +__isl_export +__isl_give isl_val *isl_val_mod(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_export +__isl_give isl_val *isl_val_gcd(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_give isl_val *isl_val_gcdext(__isl_take isl_val *v1, + __isl_take isl_val *v2, __isl_give isl_val **x, __isl_give isl_val **y); + +__isl_export +int isl_val_sgn(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_zero(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_one(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_negone(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_nonneg(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_nonpos(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_pos(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_neg(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_int(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_rat(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_nan(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_infty(__isl_keep isl_val *v); +__isl_export +isl_bool isl_val_is_neginfty(__isl_keep isl_val *v); + +__isl_export +int isl_val_cmp_si(__isl_keep isl_val *v, long i); + +__isl_export +isl_bool isl_val_lt(__isl_keep isl_val *v1, __isl_keep isl_val *v2); +__isl_export +isl_bool isl_val_le(__isl_keep isl_val *v1, __isl_keep isl_val *v2); +__isl_export +isl_bool isl_val_gt(__isl_keep isl_val *v1, __isl_keep isl_val *v2); +__isl_export +isl_bool isl_val_ge(__isl_keep isl_val *v1, __isl_keep isl_val *v2); +__isl_export +isl_bool isl_val_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2); +__isl_export +isl_bool isl_val_ne(__isl_keep isl_val *v1, __isl_keep isl_val *v2); +__isl_export +isl_bool isl_val_abs_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2); + +__isl_export +isl_bool isl_val_is_divisible_by(__isl_keep isl_val *v1, + __isl_keep isl_val *v2); + +__isl_constructor +__isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx, const char *str); +__isl_give isl_printer *isl_printer_print_val(__isl_take isl_printer *p, + __isl_keep isl_val *v); +void isl_val_dump(__isl_keep isl_val *v); +__isl_give char *isl_val_to_str(__isl_keep isl_val *v); + +__isl_give isl_multi_val *isl_multi_val_add_val(__isl_take isl_multi_val *mv, + __isl_take isl_val *v); +__isl_give isl_multi_val *isl_multi_val_mod_val(__isl_take isl_multi_val *mv, + __isl_take isl_val *v); + +__isl_give isl_multi_val *isl_multi_val_read_from_str(isl_ctx *ctx, + const char *str); +__isl_give isl_printer *isl_printer_print_multi_val(__isl_take isl_printer *p, + __isl_keep isl_multi_val *mv); +void isl_multi_val_dump(__isl_keep isl_multi_val *mv); +__isl_give char *isl_multi_val_to_str(__isl_keep isl_multi_val *mv); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/val_gmp.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/val_gmp.h @@ -0,0 +1,21 @@ +#ifndef ISL_VAL_GMP_H +#define ISL_VAL_GMP_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_val *isl_val_int_from_gmp(isl_ctx *ctx, mpz_t z); +__isl_give isl_val *isl_val_from_gmp(isl_ctx *ctx, + const mpz_t n, const mpz_t d); +int isl_val_get_num_gmp(__isl_keep isl_val *v, mpz_t z); +int isl_val_get_den_gmp(__isl_keep isl_val *v, mpz_t z); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/vec.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/vec.h @@ -0,0 +1,79 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_VEC_H +#define ISL_VEC_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_vec; +typedef struct isl_vec isl_vec; + +__isl_give isl_vec *isl_vec_alloc(isl_ctx *ctx, unsigned size); +__isl_give isl_vec *isl_vec_zero(isl_ctx *ctx, unsigned size); +__isl_give isl_vec *isl_vec_copy(__isl_keep isl_vec *vec); +__isl_null isl_vec *isl_vec_free(__isl_take isl_vec *vec); + +isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec); + +int isl_vec_size(__isl_keep isl_vec *vec); +__isl_give isl_val *isl_vec_get_element_val(__isl_keep isl_vec *vec, int pos); +__isl_give isl_vec *isl_vec_set_element_si(__isl_take isl_vec *vec, + int pos, int v); +__isl_give isl_vec *isl_vec_set_element_val(__isl_take isl_vec *vec, + int pos, __isl_take isl_val *v); + +isl_bool isl_vec_is_equal(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2); +int isl_vec_cmp_element(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2, + int pos); + +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_ceil(__isl_take isl_vec *vec); +struct isl_vec *isl_vec_normalize(struct isl_vec *vec); +__isl_give isl_vec *isl_vec_set_si(__isl_take isl_vec *vec, int v); +__isl_give isl_vec *isl_vec_set_val(__isl_take isl_vec *vec, + __isl_take isl_val *v); +__isl_give isl_vec *isl_vec_clr(__isl_take isl_vec *vec); +__isl_give isl_vec *isl_vec_neg(__isl_take isl_vec *vec); +__isl_give isl_vec *isl_vec_add(__isl_take isl_vec *vec1, + __isl_take isl_vec *vec2); +__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_concat(__isl_take isl_vec *vec1, + __isl_take isl_vec *vec2); + +__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); + +__isl_give isl_vec *isl_vec_drop_els(__isl_take isl_vec *vec, + unsigned pos, unsigned n); +__isl_give isl_vec *isl_vec_insert_els(__isl_take isl_vec *vec, + unsigned pos, unsigned n); +__isl_give isl_vec *isl_vec_insert_zero_els(__isl_take isl_vec *vec, + unsigned pos, unsigned n); +__isl_give isl_vec *isl_vec_move_els(__isl_take isl_vec *vec, + unsigned dst_col, unsigned src_col, unsigned n); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/version.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/version.h @@ -0,0 +1,14 @@ +#ifndef ISL_VERSION_H +#define ISL_VERSION_H + +#if defined(__cplusplus) +extern "C" { +#endif + +const char *isl_version(void); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/include/isl/vertices.h =================================================================== --- /dev/null +++ contrib/isl/include/isl/vertices.h @@ -0,0 +1,47 @@ +#ifndef ISL_VERTICES_H +#define ISL_VERTICES_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_external_vertex; +typedef struct isl_external_vertex isl_vertex; + +struct isl_cell; +typedef struct isl_cell isl_cell; + +struct isl_vertices; +typedef struct isl_vertices isl_vertices; + +isl_ctx *isl_vertex_get_ctx(__isl_keep isl_vertex *vertex); +int isl_vertex_get_id(__isl_keep isl_vertex *vertex); +__isl_give isl_basic_set *isl_vertex_get_domain(__isl_keep isl_vertex *vertex); +__isl_give isl_multi_aff *isl_vertex_get_expr(__isl_keep isl_vertex *vertex); +void isl_vertex_free(__isl_take isl_vertex *vertex); + +__isl_give isl_vertices *isl_basic_set_compute_vertices( + __isl_keep isl_basic_set *bset); +isl_ctx *isl_vertices_get_ctx(__isl_keep isl_vertices *vertices); +int isl_vertices_get_n_vertices(__isl_keep isl_vertices *vertices); +isl_stat isl_vertices_foreach_vertex(__isl_keep isl_vertices *vertices, + isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user); +__isl_null isl_vertices *isl_vertices_free(__isl_take isl_vertices *vertices); + +isl_ctx *isl_cell_get_ctx(__isl_keep isl_cell *cell); +__isl_give isl_basic_set *isl_cell_get_domain(__isl_keep isl_cell *cell); +isl_stat isl_cell_foreach_vertex(__isl_keep isl_cell *cell, + isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user); +void isl_cell_free(__isl_take isl_cell *cell); + +isl_stat isl_vertices_foreach_cell(__isl_keep isl_vertices *vertices, + isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/interface/Makefile.am =================================================================== --- /dev/null +++ contrib/isl/interface/Makefile.am @@ -0,0 +1,60 @@ +AUTOMAKE_OPTIONS = nostdinc + +noinst_PROGRAMS = extract_interface +if HAVE_CXX11 + noinst_PROGRAMS += isl_test_cpp-noexceptions + TESTS = isl_test_cpp-noexceptions +endif + +includes = -I$(top_builddir) -I$(top_srcdir) \ + -I$(top_builddir)/include -I$(top_srcdir)/include + +extract_interface_CPPFLAGS = $(includes) +extract_interface_CXXFLAGS = $(CLANG_CXXFLAGS) +extract_interface_SOURCES = \ + generator.h \ + generator.cc \ + python.h \ + python.cc \ + cpp.h \ + cpp.cc \ + extract_interface.h \ + extract_interface.cc +extract_interface_LDFLAGS = $(CLANG_LDFLAGS) +extract_interface_LDADD = \ + -lclangFrontend -lclangSerialization -lclangParse -lclangSema \ + $(LIB_CLANG_EDIT) \ + -lclangAnalysis -lclangAST -lclangLex -lclangBasic -lclangDriver \ + $(CLANG_LIBS) $(CLANG_LDFLAGS) + +isl_test_cpp_noexceptions_CPPFLAGS = $(includes) -I. +isl_test_cpp_noexceptions_CXXFLAGS = @CXX11FLAGS@ +isl_test_cpp_noexceptions_SOURCES = \ + isl_test_cpp-noexceptions.cc \ + isl-noexceptions.h +isl_test_cpp_noexceptions_LDFLAGS = @MP_LDFLAGS@ +isl_test_cpp_noexceptions_LDADD = ../libisl.la @MP_LIBS@ + +BUILT_SOURCES = isl-noexceptions.h +CLEANFILES = isl.py isl-noexceptions.h + +# dummy library that captures the dependencies on all headers +# that are relevant for the bindings +noinst_LIBRARIES = libdep.a +libdep_a_CPPFLAGS = $(includes) +libdep_a_SOURCES = all.c + +isl.py: extract_interface libdep.a isl.py.top + (cat $(srcdir)/isl.py.top; \ + ./extract_interface$(EXEEXT) --language=python $(includes) \ + $(srcdir)/all.h) \ + > isl.py + +isl-noexceptions.h: extract_interface libdep.a isl-noexceptions.h.top + (cat $(srcdir)/isl-noexceptions.h.top; \ + ./extract_interface$(EXEEXT) --language=cpp $(includes) \ + $(srcdir)/all.h) \ + > isl-noexceptions.h + +dist-hook: isl.py isl-noexceptions.h + cp isl.py isl-noexceptions.h $(distdir)/ Index: contrib/isl/interface/all.h =================================================================== --- /dev/null +++ contrib/isl/interface/all.h @@ -0,0 +1,11 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include Index: contrib/isl/interface/all.c =================================================================== --- /dev/null +++ contrib/isl/interface/all.c @@ -0,0 +1 @@ +#include "all.h" Index: contrib/isl/interface/cpp.h =================================================================== --- /dev/null +++ contrib/isl/interface/cpp.h @@ -0,0 +1,75 @@ +#include "generator.h" + +using namespace std; +using namespace clang; + +class cpp_generator : public generator { +public: + cpp_generator(set &exported_types, + set exported_functions, + set functions) : + generator(exported_types, exported_functions, functions) {} + + enum function_kind { + function_kind_static_method, + function_kind_member_method, + function_kind_constructor, + }; + + virtual void generate(); +private: + void print_file(ostream &os, std::string filename); + void print_forward_declarations(ostream &os); + void print_declarations(ostream &os); + void print_class(ostream &os, const isl_class &clazz); + void print_class_forward_decl(ostream &os, const isl_class &clazz); + void print_class_factory_decl(ostream &os, const isl_class &clazz, + const std::string &prefix = std::string()); + void print_private_constructors_decl(ostream &os, + const isl_class &clazz); + void print_copy_assignment_decl(ostream &os, const isl_class &clazz); + void print_public_constructors_decl(ostream &os, + const isl_class &clazz); + void print_constructors_decl(ostream &os, const isl_class &clazz); + void print_destructor_decl(ostream &os, const isl_class &clazz); + void print_ptr_decl(ostream &os, const isl_class &clazz); + void print_methods_decl(ostream &os, const isl_class &clazz); + void print_method_group_decl(ostream &os, const isl_class &clazz, + const string &fullname, const set &methods); + void print_method_decl(ostream &os, const isl_class &clazz, + const string &fullname, FunctionDecl *method, + function_kind kind); + void print_implementations(ostream &os); + void print_class_impl(ostream &os, const isl_class &clazz); + void print_class_factory_impl(ostream &os, const isl_class &clazz); + void print_private_constructors_impl(ostream &os, + const isl_class &clazz); + void print_public_constructors_impl(ostream &os, + const isl_class &clazz); + void print_constructors_impl(ostream &os, const isl_class &clazz); + void print_copy_assignment_impl(ostream &os, const isl_class &clazz); + void print_destructor_impl(ostream &os, const isl_class &clazz); + void print_ptr_impl(ostream &os, const isl_class &clazz); + void print_methods_impl(ostream &os, const isl_class &clazz); + void print_method_group_impl(ostream &os, const isl_class &clazz, + const string &fullname, const set &methods); + void print_method_impl(ostream &os, const isl_class &clazz, + const string &fullname, FunctionDecl *method, + function_kind kind); + void print_method_param_use(ostream &os, ParmVarDecl *param, + bool load_from_this_ptr); + void print_method_header(ostream &os, const isl_class &clazz, + FunctionDecl *method, const string &fullname, + bool is_declaration, function_kind kind); + string generate_callback_args(QualType type, bool cpp); + string generate_callback_type(QualType type); + void print_callback_local(ostream &os, ParmVarDecl *param); + std::string rename_method(std::string name); + string type2cpp(const isl_class &clazz); + string type2cpp(string type_string); + string type2cpp(QualType type); + bool is_implicit_conversion(const isl_class &clazz, FunctionDecl *cons); + bool is_subclass(QualType subclass_type, const isl_class &class_type); + function_kind get_method_kind(const isl_class &clazz, + FunctionDecl *method); +}; Index: contrib/isl/interface/cpp.cc =================================================================== --- /dev/null +++ contrib/isl/interface/cpp.cc @@ -0,0 +1,1103 @@ +/* + * Copyright 2016, 2017 Tobias Grosser. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as + * representing official policies, either expressed or implied, of + * Tobias Grosser. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cpp.h" +#include "isl_config.h" + +/* Print string formatted according to "fmt" to ostream "os". + * + * This osprintf method allows us to use printf style formatting constructs when + * writing to an ostream. + */ +static void osprintf(ostream &os, const char *format, ...) +{ + va_list arguments; + char *string_pointer; + size_t size; + + va_start(arguments, format); + size = vsnprintf(NULL, 0, format, arguments); + string_pointer = new char[size + 1]; + va_end(arguments); + va_start(arguments, format); + vsnprintf(string_pointer, size + 1, format, arguments); + va_end(arguments); + os << string_pointer; + delete[] string_pointer; +} + +/* Convert "l" to a string. + */ +static std::string to_string(long l) +{ + std::ostringstream strm; + strm << l; + return strm.str(); +} + +/* Generate a cpp interface based on the extracted types and functions. + * + * Print first a set of forward declarations for all isl wrapper + * classes, then the declarations of the classes, and at the end all + * implementations. + */ +void cpp_generator::generate() +{ + ostream &os = cout; + + osprintf(os, "\n"); + osprintf(os, "namespace isl {\n\n"); + osprintf(os, "inline namespace noexceptions {\n\n"); + + print_forward_declarations(os); + osprintf(os, "\n"); + print_declarations(os); + osprintf(os, "\n"); + print_implementations(os); + + osprintf(os, "} // namespace noexceptions\n"); + osprintf(os, "} // namespace isl\n\n"); + osprintf(os, "#endif /* ISL_CPP_NOEXCEPTIONS */\n"); +} + +/* Print forward declarations for all classes to "os". +*/ +void cpp_generator::print_forward_declarations(ostream &os) +{ + map::iterator ci; + + osprintf(os, "// forward declarations\n"); + + for (ci = classes.begin(); ci != classes.end(); ++ci) + print_class_forward_decl(os, ci->second); +} + +/* Print all declarations to "os". + */ +void cpp_generator::print_declarations(ostream &os) +{ + map::iterator ci; + bool first = true; + + for (ci = classes.begin(); ci != classes.end(); ++ci) { + if (first) + first = false; + else + osprintf(os, "\n"); + + print_class(os, ci->second); + } +} + +/* Print all implementations to "os". + */ +void cpp_generator::print_implementations(ostream &os) +{ + map::iterator ci; + bool first = true; + + for (ci = classes.begin(); ci != classes.end(); ++ci) { + if (first) + first = false; + else + osprintf(os, "\n"); + + print_class_impl(os, ci->second); + } +} + +/* Print declarations for class "clazz" to "os". + */ +void cpp_generator::print_class(ostream &os, const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "// declarations for isl::%s\n", cppname); + + print_class_factory_decl(os, clazz); + osprintf(os, "\n"); + osprintf(os, "class %s {\n", cppname); + print_class_factory_decl(os, clazz, " friend "); + osprintf(os, "\n"); + osprintf(os, " %s *ptr = nullptr;\n", name); + osprintf(os, "\n"); + print_private_constructors_decl(os, clazz); + osprintf(os, "\n"); + osprintf(os, "public:\n"); + print_public_constructors_decl(os, clazz); + print_constructors_decl(os, clazz); + print_copy_assignment_decl(os, clazz); + print_destructor_decl(os, clazz); + print_ptr_decl(os, clazz); + osprintf(os, "\n"); + print_methods_decl(os, clazz); + + osprintf(os, "};\n"); +} + +/* Print forward declaration of class "clazz" to "os". + */ +void cpp_generator::print_class_forward_decl(ostream &os, + const isl_class &clazz) +{ + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "class %s;\n", cppname); +} + +/* Print global factory functions to "os". + * + * Each class has two global factory functions: + * + * isl::set manage(__isl_take isl_set *ptr); + * isl::set manage_copy(__isl_keep isl_set *ptr); + * + * A user can construct isl C++ objects from a raw pointer and indicate whether + * they intend to take the ownership of the object or not through these global + * factory functions. This ensures isl object creation is very explicit and + * pointers are not converted by accident. Thanks to overloading, manage() and + * manage_copy() can be called on any isl raw pointer and the corresponding + * object is automatically created, without the user having to choose the right + * isl object type. + */ +void cpp_generator::print_class_factory_decl(ostream &os, + const isl_class &clazz, const std::string &prefix) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + os << prefix; + osprintf(os, "inline isl::%s manage(__isl_take %s *ptr);\n", cppname, + name); + os << prefix; + osprintf(os, "inline isl::%s manage_copy(__isl_keep %s *ptr);\n", + cppname, name); +} + +/* Print declarations of private constructors for class "clazz" to "os". + * + * Each class has currently one private constructor: + * + * 1) Constructor from a plain isl_* C pointer + * + * Example: + * + * set(__isl_take isl_set *ptr); + * + * The raw pointer constructor is kept private. Object creation is only + * possible through isl::manage() or isl::manage_copy(). + */ +void cpp_generator::print_private_constructors_decl(ostream &os, + const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname, + name); +} + +/* Print declarations of public constructors for class "clazz" to "os". + * + * Each class currently has two public constructors: + * + * 1) A default constructor + * 2) A copy constructor + * + * Example: + * + * set(); + * set(const isl::set &set); + */ +void cpp_generator::print_public_constructors_decl(ostream &os, + const isl_class &clazz) +{ + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + osprintf(os, " inline /* implicit */ %s();\n", cppname); + + osprintf(os, " inline /* implicit */ %s(const isl::%s &obj);\n", + cppname, cppname); +} + +/* Print declarations for constructors for class "class" to "os". + * + * For each isl function that is marked as __isl_constructor, + * add a corresponding C++ constructor. + * + * Example: + * + * inline /\* implicit *\/ union_set(isl::basic_set bset); + * inline /\* implicit *\/ union_set(isl::set set); + * inline explicit val(isl::ctx ctx, long i); + * inline explicit val(isl::ctx ctx, const std::string &str); + */ +void cpp_generator::print_constructors_decl(ostream &os, + const isl_class &clazz) +{ + set::const_iterator in; + const set &constructors = clazz.constructors; + + for (in = constructors.begin(); in != constructors.end(); ++in) { + FunctionDecl *cons = *in; + string fullname = cons->getName(); + function_kind kind = function_kind_constructor; + + print_method_decl(os, clazz, fullname, cons, kind); + } +} + +/* Print declarations of copy assignment operator for class "clazz" + * to "os". + * + * Each class has one assignment operator. + * + * isl:set &set::operator=(isl::set obj) + * + */ +void cpp_generator::print_copy_assignment_decl(ostream &os, + const isl_class &clazz) +{ + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, " inline isl::%s &operator=(isl::%s obj);\n", cppname, + cppname); +} + +/* Print declaration of destructor for class "clazz" to "os". + */ +void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz) +{ + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, " inline ~%s();\n", cppname); +} + +/* Print declaration of pointer functions for class "clazz" to "os". + * + * To obtain a raw pointer three functions are provided: + * + * 1) __isl_give isl_set *copy() + * + * Returns a pointer to a _copy_ of the internal object + * + * 2) __isl_keep isl_set *get() + * + * Returns a pointer to the internal object + * + * 3) __isl_give isl_set *release() + * + * Returns a pointer to the internal object and resets the + * internal pointer to nullptr. + * + * We also provide functionality to explicitly check if a pointer is + * currently managed by this object. + * + * 4) bool is_null() + * + * Check if the current object is a null pointer. + * + * The functions get() and release() model the value_ptr proposed in + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf. + * The copy() function is an extension to allow the user to explicitly + * copy the underlying object. + * + * Also generate a declaration to delete copy() for r-values, for + * r-values release() should be used to avoid unnecessary copies. + */ +void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + + osprintf(os, " inline __isl_give %s *copy() const &;\n", name); + osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name); + osprintf(os, " inline __isl_keep %s *get() const;\n", name); + osprintf(os, " inline __isl_give %s *release();\n", name); + osprintf(os, " inline bool is_null() const;\n"); +} + +/* Print declarations for methods in class "clazz" to "os". + */ +void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz) +{ + map >::const_iterator it; + + for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) + print_method_group_decl(os, clazz, it->first, it->second); +} + +/* Print declarations for methods "methods" of name "fullname" in class "clazz" + * to "os". + * + * "fullname" is the name of the generated C++ method. It commonly corresponds + * to the isl name, with the object type prefix dropped. + * In case of overloaded methods, the result type suffix has also been removed. + */ +void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz, + const string &fullname, const set &methods) +{ + set::const_iterator it; + + for (it = methods.begin(); it != methods.end(); ++it) { + function_kind kind = get_method_kind(clazz, *it); + print_method_decl(os, clazz, fullname, *it, kind); + } +} + +/* Print declarations for "method" in class "clazz" to "os". + * + * "fullname" is the name of the generated C++ method. It commonly corresponds + * to the isl name, with the object type prefix dropped. + * In case of overloaded methods, the result type suffix has also been removed. + * + * "kind" specifies the kind of method that should be generated. + */ +void cpp_generator::print_method_decl(ostream &os, const isl_class &clazz, + const string &fullname, FunctionDecl *method, function_kind kind) +{ + print_method_header(os, clazz, method, fullname, true, kind); +} + +/* Print implementations for class "clazz" to "os". + */ +void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz) +{ + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "// implementations for isl::%s\n", cppname); + + print_class_factory_impl(os, clazz); + osprintf(os, "\n"); + print_public_constructors_impl(os, clazz); + osprintf(os, "\n"); + print_private_constructors_impl(os, clazz); + osprintf(os, "\n"); + print_constructors_impl(os, clazz); + osprintf(os, "\n"); + print_copy_assignment_impl(os, clazz); + osprintf(os, "\n"); + print_destructor_impl(os, clazz); + osprintf(os, "\n"); + print_ptr_impl(os, clazz); + osprintf(os, "\n"); + print_methods_impl(os, clazz); +} + +/* Print implementation of global factory function to "os". + */ +void cpp_generator::print_class_factory_impl(ostream &os, + const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "isl::%s manage(__isl_take %s *ptr) {\n", cppname, name); + osprintf(os, " return %s(ptr);\n", cppname); + osprintf(os, "}\n"); + + osprintf(os, "isl::%s manage_copy(__isl_keep %s *ptr) {\n", cppname, + name); + osprintf(os, " return %s(%s_copy(ptr));\n", cppname, name); + osprintf(os, "}\n"); +} + +/* Print implementations of private constructors for class "clazz" to "os". + */ +void cpp_generator::print_private_constructors_impl(ostream &os, + const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n", + cppname, cppname, name); +} + +/* Print implementations of public constructors for class "clazz" to "os". + */ +void cpp_generator::print_public_constructors_impl(ostream &os, + const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname); + osprintf(os, "%s::%s(const isl::%s &obj)\n : ptr(obj.copy()) {}\n", + cppname, cppname, cppname, name); +} + +/* Print implementations of constructors for class "clazz" to "os". + */ +void cpp_generator::print_constructors_impl(ostream &os, + const isl_class &clazz) +{ + set::const_iterator in; + const set constructors = clazz.constructors; + + for (in = constructors.begin(); in != constructors.end(); ++in) { + FunctionDecl *cons = *in; + string fullname = cons->getName(); + function_kind kind = function_kind_constructor; + + print_method_impl(os, clazz, fullname, cons, kind); + } +} + +/* Print implementation of copy assignment operator for class "clazz" to "os". + */ +void cpp_generator::print_copy_assignment_impl(ostream &os, + const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "%s &%s::operator=(isl::%s obj) {\n", cppname, + cppname, cppname); + osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name); + osprintf(os, " return *this;\n"); + osprintf(os, "}\n"); +} + +/* Print implementation of destructor for class "clazz" to "os". + */ +void cpp_generator::print_destructor_impl(ostream &os, + const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "%s::~%s() {\n", cppname, cppname); + osprintf(os, " if (ptr)\n"); + osprintf(os, " %s_free(ptr);\n", name); + osprintf(os, "}\n"); +} + +/* Print implementation of ptr() functions for class "clazz" to "os". + */ +void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz) +{ + const char *name = clazz.name.c_str(); + std::string cppstring = type2cpp(clazz); + const char *cppname = cppstring.c_str(); + + osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname); + osprintf(os, " return %s_copy(ptr);\n", name); + osprintf(os, "}\n\n"); + osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname); + osprintf(os, " return ptr;\n"); + osprintf(os, "}\n\n"); + osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname); + osprintf(os, " %s *tmp = ptr;\n", name); + osprintf(os, " ptr = nullptr;\n"); + osprintf(os, " return tmp;\n"); + osprintf(os, "}\n\n"); + osprintf(os, "bool %s::is_null() const {\n", cppname); + osprintf(os, " return ptr == nullptr;\n"); + osprintf(os, "}\n"); +} + +/* Print definitions for methods of class "clazz" to "os". + */ +void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz) +{ + map >::const_iterator it; + bool first = true; + + for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) { + if (first) + first = false; + else + osprintf(os, "\n"); + print_method_group_impl(os, clazz, it->first, it->second); + } +} + +/* Print definitions for methods "methods" of name "fullname" in class "clazz" + * to "os". + * + * "fullname" is the name of the generated C++ method. It commonly corresponds + * to the isl name, with the object type prefix dropped. + * In case of overloaded methods, the result type suffix has also been removed. + * + * "kind" specifies the kind of method that should be generated. + */ +void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz, + const string &fullname, const set &methods) +{ + set::const_iterator it; + bool first = true; + + for (it = methods.begin(); it != methods.end(); ++it) { + function_kind kind; + if (first) + first = false; + else + osprintf(os, "\n"); + kind = get_method_kind(clazz, *it); + print_method_impl(os, clazz, fullname, *it, kind); + } +} + +/* Print the use of "param" to "os". + * + * "load_from_this_ptr" specifies whether the parameter should be loaded from + * the this-ptr. In case a value is loaded from a this pointer, the original + * value must be preserved and must consequently be copied. Values that are + * loaded from parameters do not need to be preserved, as such values will + * already be copies of the actual parameters. It is consequently possible + * to directly take the pointer from these values, which saves + * an unnecessary copy. + * + * In case the parameter is a callback function, two parameters get printed, + * a wrapper for the callback function and a pointer to the actual + * callback function. The wrapper is expected to be available + * in a previously declared variable _lambda, while + * the actual callback function is expected in _p. + * The caller of this function must ensure that these variables exist. + */ +void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param, + bool load_from_this_ptr) +{ + string name = param->getName().str(); + const char *name_str = name.c_str(); + QualType type = param->getOriginalType(); + + if (type->isIntegerType()) { + osprintf(os, "%s", name_str); + return; + } + + if (is_string(type)) { + osprintf(os, "%s.c_str()", name_str); + return; + } + + if (is_callback(type)) { + osprintf(os, "%s_lambda, ", name_str); + osprintf(os, "&%s_p", name_str); + return; + } + + if (!load_from_this_ptr && !is_callback(type)) + osprintf(os, "%s.", name_str); + + if (keeps(param)) { + osprintf(os, "get()"); + } else { + if (load_from_this_ptr) + osprintf(os, "copy()"); + else + osprintf(os, "release()"); + } +} + +/* Print definition for "method" in class "clazz" to "os". + * + * "fullname" is the name of the generated C++ method. It commonly corresponds + * to the isl name, with the object type prefix dropped. + * In case of overloaded methods, the result type suffix has also been removed. + * + * "kind" specifies the kind of method that should be generated. + * + * This method distinguishes three kinds of methods: member methods, static + * methods, and constructors. + * + * Member methods call "method" by passing to the underlying isl function the + * isl object belonging to "this" as first argument and the remaining arguments + * as subsequent arguments. The result of the isl function is returned as a new + * object if the underlying isl function returns an isl_* ptr or an isl_bool + * value, as std::string if the isl function returns 'const char *', and as + * unmodified return value otherwise. + * + * Static methods call "method" by passing all arguments to the underlying isl + * function, as no this-pointer is available. The result is a newly managed + * isl C++ object. + * + * Constructors create a new object from a given set of input parameters. They + * do not return a value, but instead update the pointer stored inside the + * newly created object. + * + * If the method has a callback argument, we reduce the number of parameters + * that are exposed by one to hide the user pointer from the interface. On + * the C++ side no user pointer is needed, as arguments can be forwarded + * as part of the std::function argument which specifies the callback function. + */ +void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz, + const string &fullname, FunctionDecl *method, function_kind kind) +{ + string cname = fullname.substr(clazz.name.length() + 1); + string methodname = method->getName(); + int num_params = method->getNumParams(); + QualType return_type = method->getReturnType(); + string rettype_str = type2cpp(return_type); + bool has_callback = false; + + print_method_header(os, clazz, method, fullname, false, kind); + + for (int i = 0; i < num_params; ++i) { + ParmVarDecl *param = method->getParamDecl(i); + if (is_callback(param->getType())) { + has_callback = true; + num_params -= 1; + print_callback_local(os, param); + } + } + + osprintf(os, " auto res = %s(", methodname.c_str()); + + for (int i = 0; i < num_params; ++i) { + ParmVarDecl *param = method->getParamDecl(i); + bool load_from_this_ptr = false; + + if (i == 0 && kind == function_kind_member_method) + load_from_this_ptr = true; + + print_method_param_use(os, param, load_from_this_ptr); + + if (i != num_params - 1) + osprintf(os, ", "); + } + osprintf(os, ");\n"); + + if (kind == function_kind_constructor) { + osprintf(os, " ptr = res;\n"); + } else if (is_isl_type(return_type) || is_isl_bool(return_type)) { + osprintf(os, " return manage(res);\n"); + } else if (has_callback) { + osprintf(os, " return %s(res);\n", rettype_str.c_str()); + } else if (is_string(return_type)) { + osprintf(os, " std::string tmp(res);\n"); + if (gives(method)) + osprintf(os, " free(res);\n"); + osprintf(os, " return tmp;\n"); + } else { + osprintf(os, " return res;\n"); + } + + osprintf(os, "}\n"); +} + +/* Print the header for "method" in class "clazz" to "os". + * + * Print the header of a declaration if "is_declaration" is set, otherwise print + * the header of a method definition. + * + * "fullname" is the name of the generated C++ method. It commonly corresponds + * to the isl name, with the object type prefix dropped. + * In case of overloaded methods, the result type suffix has also been removed. + * + * "kind" specifies the kind of method that should be generated. + * + * This function prints headers for member methods, static methods, and + * constructors, either for their declaration or definition. + * + * Member functions are declared as "const", as they do not change the current + * object, but instead create a new object. They always retrieve the first + * parameter of the original isl function from the this-pointer of the object, + * such that only starting at the second parameter the parameters of the + * original function become part of the method's interface. + * + * A function + * + * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1, + * __isl_take isl_set *s2); + * + * is translated into: + * + * inline isl::set intersect(isl::set set2) const; + * + * For static functions and constructors all parameters of the original isl + * function are exposed. + * + * Parameters that are defined as __isl_keep or are of type string, are passed + * as const reference, which allows the compiler to optimize the parameter + * transfer. + * + * Constructors are marked as explicit using the C++ keyword 'explicit' or as + * implicit using a comment in place of the explicit keyword. By annotating + * implicit constructors with a comment, users of the interface are made + * aware of the potential danger that implicit construction is possible + * for these constructors, whereas without a comment not every user would + * know that implicit construction is allowed in absence of an explicit keyword. + */ +void cpp_generator::print_method_header(ostream &os, const isl_class &clazz, + FunctionDecl *method, const string &fullname, bool is_declaration, + function_kind kind) +{ + string cname = fullname.substr(clazz.name.length() + 1); + string rettype_str = type2cpp(method->getReturnType()); + string classname = type2cpp(clazz); + int num_params = method->getNumParams(); + int first_param = 0; + + cname = rename_method(cname); + if (kind == function_kind_member_method) + first_param = 1; + + if (is_declaration) { + osprintf(os, " "); + + if (kind == function_kind_static_method) + osprintf(os, "static "); + + osprintf(os, "inline "); + + if (kind == function_kind_constructor) { + if (is_implicit_conversion(clazz, method)) + osprintf(os, "/* implicit */ "); + else + osprintf(os, "explicit "); + } + } + + if (kind != function_kind_constructor) + osprintf(os, "%s ", rettype_str.c_str()); + + if (!is_declaration) + osprintf(os, "%s::", classname.c_str()); + + if (kind != function_kind_constructor) + osprintf(os, "%s", cname.c_str()); + else + osprintf(os, "%s", classname.c_str()); + + osprintf(os, "("); + + for (int i = first_param; i < num_params; ++i) { + ParmVarDecl *param = method->getParamDecl(i); + QualType type = param->getOriginalType(); + string cpptype = type2cpp(type); + + if (is_callback(type)) + num_params--; + + if (keeps(param) || is_string(type) || is_callback(type)) + osprintf(os, "const %s &%s", cpptype.c_str(), + param->getName().str().c_str()); + else + osprintf(os, "%s %s", cpptype.c_str(), + param->getName().str().c_str()); + + if (i != num_params - 1) + osprintf(os, ", "); + } + + osprintf(os, ")"); + + if (kind == function_kind_member_method) + osprintf(os, " const"); + + if (is_declaration) + osprintf(os, ";\n"); + else + osprintf(os, " {\n"); +} + +/* Generate the list of argument types for a callback function of + * type "type". If "cpp" is set, then generate the C++ type list, otherwise + * the C type list. + * + * For a callback of type + * + * isl_stat (*)(__isl_take isl_map *map, void *user) + * + * the following C++ argument list is generated: + * + * isl::map + */ +string cpp_generator::generate_callback_args(QualType type, bool cpp) +{ + std::string type_str; + const FunctionProtoType *callback; + int num_params; + + callback = type->getPointeeType()->getAs(); + num_params = callback->getNumArgs(); + if (cpp) + num_params--; + + for (long i = 0; i < num_params; i++) { + QualType type = callback->getArgType(i); + + if (cpp) + type_str += type2cpp(type); + else + type_str += type.getAsString(); + + if (!cpp) + type_str += "arg_" + ::to_string(i); + + if (i != num_params - 1) + type_str += ", "; + } + + return type_str; +} + +/* Generate the full cpp type of a callback function of type "type". + * + * For a callback of type + * + * isl_stat (*)(__isl_take isl_map *map, void *user) + * + * the following type is generated: + * + * std::function + */ +string cpp_generator::generate_callback_type(QualType type) +{ + std::string type_str; + const FunctionProtoType *callback = type->getPointeeType()->getAs(); + QualType return_type = callback->getReturnType(); + string rettype_str = type2cpp(return_type); + + type_str = "std::function<"; + type_str += rettype_str; + type_str += "("; + type_str += generate_callback_args(type, true); + type_str += ")>"; + + return type_str; +} + +/* Print the local variables that are needed for a callback argument, + * in particular, print a lambda function that wraps the callback and + * a pointer to the actual C++ callback function. + * + * For a callback of the form + * + * isl_stat (*fn)(__isl_take isl_map *map, void *user) + * + * the following lambda function is generated: + * + * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat { + * auto *func = *static_cast **>(arg_1); + * stat ret = (*func)(isl::manage(arg_0)); + * return isl_stat(ret); + * }; + * + * The pointer to the std::function C++ callback function is stored in fn_p. + * This std::function object represents the actual user + * callback function together with the locally captured state at the caller. + * + * The lambda function is expected to be used as a C callback function + * where the lambda itself is provided as the function pointer and + * where the user void pointer is a pointer to fn_p. + * The std::function object is extracted from the pointer to fn_p + * inside the lambda function. + * The double indirection is used to avoid having to worry about + * const casting. + */ +void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param) { + string pname; + QualType ptype; + string call_args, c_args, cpp_args, rettype, last_idx; + const FunctionProtoType *callback; + int num_params; + + pname = param->getName().str(); + ptype = param->getType(); + + c_args = generate_callback_args(ptype, false); + cpp_args = generate_callback_type(ptype); + + callback = ptype->getPointeeType()->getAs(); + rettype = callback->getReturnType().getAsString(); + num_params = callback->getNumArgs(); + + last_idx = ::to_string(num_params - 1); + + for (long i = 0; i < num_params - 1; i++) { + call_args += "isl::manage(arg_" + ::to_string(i) + ")"; + if (i != num_params - 2) + call_args += ", "; + } + + osprintf(os, " auto %s_p = &%s;\n", pname.c_str(), pname.c_str()); + osprintf(os, + " auto %s_lambda = [](%s) -> %s {\n" + " auto *func = *static_cast(arg_%s);\n" + " stat ret = (*func)(%s);\n" + " return isl_stat(ret);\n" + " };\n", + pname.c_str(), c_args.c_str(), rettype.c_str(), + cpp_args.c_str(), last_idx.c_str(), call_args.c_str()); +} + +/* An array listing functions that must be renamed and the function name they + * should be renamed to. We currently rename functions in case their name would + * match a reserved C++ keyword, which is not allowed in C++. + */ +static const char *rename_map[][2] = { + { "union", "unite" }, +}; + +/* Rename method "name" in case the method name in the C++ bindings should not + * match the name in the C bindings. We do this for example to avoid + * C++ keywords. + */ +std::string cpp_generator::rename_method(std::string name) +{ + for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++) + if (name.compare(rename_map[i][0]) == 0) + return rename_map[i][1]; + + return name; +} + +/* Translate isl class "clazz" to its corresponding C++ type. + */ +string cpp_generator::type2cpp(const isl_class &clazz) +{ + return type2cpp(clazz.name); +} + +/* Translate type string "type_str" to its C++ name counterpart. +*/ +string cpp_generator::type2cpp(string type_str) +{ + return type_str.substr(4); +} + +/* Translate QualType "type" to its C++ name counterpart. + */ +string cpp_generator::type2cpp(QualType type) +{ + if (is_isl_type(type)) + return "isl::" + type2cpp(type->getPointeeType().getAsString()); + + if (is_isl_bool(type)) + return "isl::boolean"; + + if (is_isl_stat(type)) + return "isl::stat"; + + if (type->isIntegerType()) + return type.getAsString(); + + if (is_string(type)) + return "std::string"; + + if (is_callback(type)) + return generate_callback_type(type); + + die("Cannot convert type to C++ type"); +} + +/* Check if "subclass_type" is a subclass of "class_type". + */ +bool cpp_generator::is_subclass(QualType subclass_type, + const isl_class &class_type) +{ + std::string type_str = subclass_type->getPointeeType().getAsString(); + std::vector superclasses; + std::vector parents; + std::vector::iterator ci; + + superclasses = generator::find_superclasses(classes[type_str].type); + + for (ci = superclasses.begin(); ci < superclasses.end(); ci++) + parents.push_back(&classes[*ci]); + + while (!parents.empty()) { + const isl_class *candidate = parents.back(); + + parents.pop_back(); + + if (&class_type == candidate) + return true; + + superclasses = generator::find_superclasses(candidate->type); + + for (ci = superclasses.begin(); ci < superclasses.end(); ci++) + parents.push_back(&classes[*ci]); + } + + return false; +} + +/* Check if "cons" is an implicit conversion constructor of class "clazz". + * + * An implicit conversion constructor is generated in case "cons" has a single + * parameter, where the parameter type is a subclass of the class that is + * currently being generated. + */ +bool cpp_generator::is_implicit_conversion(const isl_class &clazz, + FunctionDecl *cons) +{ + ParmVarDecl *param = cons->getParamDecl(0); + QualType type = param->getOriginalType(); + + int num_params = cons->getNumParams(); + if (num_params != 1) + return false; + + if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz)) + return true; + + return false; +} + +/* Get kind of "method" in "clazz". + * + * Given the declaration of a static or member method, returns its kind. + */ +cpp_generator::function_kind cpp_generator::get_method_kind( + const isl_class &clazz, FunctionDecl *method) +{ + if (is_static(clazz, method)) + return function_kind_static_method; + else + return function_kind_member_method; +} Index: contrib/isl/interface/extract_interface.h =================================================================== --- /dev/null +++ contrib/isl/interface/extract_interface.h @@ -0,0 +1,3 @@ +#include + +bool has_annotation(clang::Decl *decl, const char *name); Index: contrib/isl/interface/extract_interface.cc =================================================================== --- /dev/null +++ contrib/isl/interface/extract_interface.cc @@ -0,0 +1,468 @@ +/* + * Copyright 2011 Sven Verdoolaege. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as + * representing official policies, either expressed or implied, of + * Sven Verdoolaege. + */ + +#include "isl_config.h" + +#include +#include +#ifdef HAVE_ADT_OWNINGPTR_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H +#include +#else +#include +#endif +#include +#include +#include +#ifdef HAVE_LEX_PREPROCESSOROPTIONS_H +#include +#else +#include +#endif +#include +#include +#include + +#include "extract_interface.h" +#include "generator.h" +#include "python.h" +#include "cpp.h" + +using namespace std; +using namespace clang; +using namespace clang::driver; + +#ifdef HAVE_ADT_OWNINGPTR_H +#define unique_ptr llvm::OwningPtr +#endif + +static llvm::cl::opt InputFilename(llvm::cl::Positional, + llvm::cl::Required, llvm::cl::desc("")); +static llvm::cl::list Includes("I", + llvm::cl::desc("Header search path"), + llvm::cl::value_desc("path"), llvm::cl::Prefix); + +static llvm::cl::opt Language(llvm::cl::Required, + llvm::cl::ValueRequired, "language", + llvm::cl::desc("Bindings to generate"), + llvm::cl::value_desc("name")); + +static const char *ResourceDir = + CLANG_PREFIX "/lib/clang/" CLANG_VERSION_STRING; + +/* Does decl have an attribute of the following form? + * + * __attribute__((annotate("name"))) + */ +bool has_annotation(Decl *decl, const char *name) +{ + if (!decl->hasAttrs()) + return false; + + AttrVec attrs = decl->getAttrs(); + for (AttrVec::const_iterator i = attrs.begin() ; i != attrs.end(); ++i) { + const AnnotateAttr *ann = dyn_cast(*i); + if (!ann) + continue; + if (ann->getAnnotation().str() == name) + return true; + } + + return false; +} + +/* Is decl marked as exported? + */ +static bool is_exported(Decl *decl) +{ + return has_annotation(decl, "isl_export"); +} + +/* Collect all types and functions that are annotated "isl_export" + * in "exported_types" and "exported_function". Collect all function + * declarations in "functions". + * + * We currently only consider single declarations. + */ +struct MyASTConsumer : public ASTConsumer { + set exported_types; + set exported_functions; + set functions; + + virtual HandleTopLevelDeclReturn HandleTopLevelDecl(DeclGroupRef D) { + Decl *decl; + + if (!D.isSingleDecl()) + return HandleTopLevelDeclContinue; + decl = D.getSingleDecl(); + if (isa(decl)) + functions.insert(cast(decl)); + if (!is_exported(decl)) + return HandleTopLevelDeclContinue; + switch (decl->getKind()) { + case Decl::Record: + exported_types.insert(cast(decl)); + break; + case Decl::Function: + exported_functions.insert(cast(decl)); + break; + default: + break; + } + return HandleTopLevelDeclContinue; + } +}; + +#ifdef USE_ARRAYREF + +#ifdef HAVE_CXXISPRODUCTION +static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) +{ + return new Driver(binary, llvm::sys::getDefaultTargetTriple(), + "", false, false, Diags); +} +#elif defined(HAVE_ISPRODUCTION) +static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) +{ + return new Driver(binary, llvm::sys::getDefaultTargetTriple(), + "", false, Diags); +} +#elif defined(DRIVER_CTOR_TAKES_DEFAULTIMAGENAME) +static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) +{ + return new Driver(binary, llvm::sys::getDefaultTargetTriple(), + "", Diags); +} +#else +static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) +{ + return new Driver(binary, llvm::sys::getDefaultTargetTriple(), Diags); +} +#endif + +namespace clang { namespace driver { class Job; } } + +/* Clang changed its API from 3.5 to 3.6 and once more in 3.7. + * We fix this with a simple overloaded function here. + */ +struct ClangAPI { + static Job *command(Job *J) { return J; } + static Job *command(Job &J) { return &J; } + static Command *command(Command &C) { return &C; } +}; + +/* Create a CompilerInvocation object that stores the command line + * arguments constructed by the driver. + * The arguments are mainly useful for setting up the system include + * paths on newer clangs and on some platforms. + */ +static CompilerInvocation *construct_invocation(const char *filename, + DiagnosticsEngine &Diags) +{ + const char *binary = CLANG_PREFIX"/bin/clang"; + const unique_ptr driver(construct_driver(binary, Diags)); + std::vector Argv; + Argv.push_back(binary); + Argv.push_back(filename); + const unique_ptr compilation( + driver->BuildCompilation(llvm::ArrayRef(Argv))); + JobList &Jobs = compilation->getJobs(); + + Command *cmd = cast(ClangAPI::command(*Jobs.begin())); + if (strcmp(cmd->getCreator().getName(), "clang")) + return NULL; + + const ArgStringList *args = &cmd->getArguments(); + + CompilerInvocation *invocation = new CompilerInvocation; + CompilerInvocation::CreateFromArgs(*invocation, args->data() + 1, + args->data() + args->size(), + Diags); + return invocation; +} + +#else + +static CompilerInvocation *construct_invocation(const char *filename, + DiagnosticsEngine &Diags) +{ + return NULL; +} + +#endif + +#ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H + +static TextDiagnosticPrinter *construct_printer(void) +{ + return new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions()); +} + +#else + +static TextDiagnosticPrinter *construct_printer(void) +{ + DiagnosticOptions DO; + return new TextDiagnosticPrinter(llvm::errs(), DO); +} + +#endif + +#ifdef CREATETARGETINFO_TAKES_SHARED_PTR + +static TargetInfo *create_target_info(CompilerInstance *Clang, + DiagnosticsEngine &Diags) +{ + shared_ptr TO = Clang->getInvocation().TargetOpts; + TO->Triple = llvm::sys::getDefaultTargetTriple(); + return TargetInfo::CreateTargetInfo(Diags, TO); +} + +#elif defined(CREATETARGETINFO_TAKES_POINTER) + +static TargetInfo *create_target_info(CompilerInstance *Clang, + DiagnosticsEngine &Diags) +{ + TargetOptions &TO = Clang->getTargetOpts(); + TO.Triple = llvm::sys::getDefaultTargetTriple(); + return TargetInfo::CreateTargetInfo(Diags, &TO); +} + +#else + +static TargetInfo *create_target_info(CompilerInstance *Clang, + DiagnosticsEngine &Diags) +{ + TargetOptions &TO = Clang->getTargetOpts(); + TO.Triple = llvm::sys::getDefaultTargetTriple(); + return TargetInfo::CreateTargetInfo(Diags, TO); +} + +#endif + +#ifdef CREATEDIAGNOSTICS_TAKES_ARG + +static void create_diagnostics(CompilerInstance *Clang) +{ + Clang->createDiagnostics(0, NULL, construct_printer()); +} + +#else + +static void create_diagnostics(CompilerInstance *Clang) +{ + Clang->createDiagnostics(construct_printer()); +} + +#endif + +#ifdef CREATEPREPROCESSOR_TAKES_TUKIND + +static void create_preprocessor(CompilerInstance *Clang) +{ + Clang->createPreprocessor(TU_Complete); +} + +#else + +static void create_preprocessor(CompilerInstance *Clang) +{ + Clang->createPreprocessor(); +} + +#endif + +#ifdef ADDPATH_TAKES_4_ARGUMENTS + +void add_path(HeaderSearchOptions &HSO, string Path) +{ + HSO.AddPath(Path, frontend::Angled, false, false); +} + +#else + +void add_path(HeaderSearchOptions &HSO, string Path) +{ + HSO.AddPath(Path, frontend::Angled, true, false, false); +} + +#endif + +#ifdef HAVE_SETMAINFILEID + +static void create_main_file_id(SourceManager &SM, const FileEntry *file) +{ + SM.setMainFileID(SM.createFileID(file, SourceLocation(), + SrcMgr::C_User)); +} + +#else + +static void create_main_file_id(SourceManager &SM, const FileEntry *file) +{ + SM.createMainFileID(file); +} + +#endif + +#ifdef SETLANGDEFAULTS_TAKES_5_ARGUMENTS + +static void set_lang_defaults(CompilerInstance *Clang) +{ + PreprocessorOptions &PO = Clang->getPreprocessorOpts(); + TargetOptions &TO = Clang->getTargetOpts(); + llvm::Triple T(TO.Triple); + CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, T, PO, + LangStandard::lang_unspecified); +} + +#else + +static void set_lang_defaults(CompilerInstance *Clang) +{ + CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, + LangStandard::lang_unspecified); +} + +#endif + +#ifdef SETINVOCATION_TAKES_SHARED_PTR + +static void set_invocation(CompilerInstance *Clang, + CompilerInvocation *invocation) +{ + Clang->setInvocation(std::make_shared(*invocation)); +} + +#else + +static void set_invocation(CompilerInstance *Clang, + CompilerInvocation *invocation) +{ + Clang->setInvocation(invocation); +} + +#endif + +int main(int argc, char *argv[]) +{ + llvm::cl::ParseCommandLineOptions(argc, argv); + + CompilerInstance *Clang = new CompilerInstance(); + create_diagnostics(Clang); + DiagnosticsEngine &Diags = Clang->getDiagnostics(); + Diags.setSuppressSystemWarnings(true); + CompilerInvocation *invocation = + construct_invocation(InputFilename.c_str(), Diags); + if (invocation) + set_invocation(Clang, invocation); + Clang->createFileManager(); + Clang->createSourceManager(Clang->getFileManager()); + TargetInfo *target = create_target_info(Clang, Diags); + Clang->setTarget(target); + set_lang_defaults(Clang); + HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts(); + LangOptions &LO = Clang->getLangOpts(); + PreprocessorOptions &PO = Clang->getPreprocessorOpts(); + HSO.ResourceDir = ResourceDir; + + for (llvm::cl::list::size_type i = 0; i < Includes.size(); ++i) + add_path(HSO, Includes[i]); + + PO.addMacroDef("__isl_give=__attribute__((annotate(\"isl_give\")))"); + PO.addMacroDef("__isl_keep=__attribute__((annotate(\"isl_keep\")))"); + PO.addMacroDef("__isl_take=__attribute__((annotate(\"isl_take\")))"); + PO.addMacroDef("__isl_export=__attribute__((annotate(\"isl_export\")))"); + PO.addMacroDef("__isl_overload=" + "__attribute__((annotate(\"isl_overload\"))) " + "__attribute__((annotate(\"isl_export\")))"); + PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))"); + PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))"); + + create_preprocessor(Clang); + Preprocessor &PP = Clang->getPreprocessor(); + + PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), LO); + + const FileEntry *file = Clang->getFileManager().getFile(InputFilename); + assert(file); + create_main_file_id(Clang->getSourceManager(), file); + + Clang->createASTContext(); + MyASTConsumer consumer; + Sema *sema = new Sema(PP, Clang->getASTContext(), consumer); + + Diags.getClient()->BeginSourceFile(LO, &PP); + ParseAST(*sema); + Diags.getClient()->EndSourceFile(); + + generator *gen = NULL; + if (Language.compare("python") == 0) + gen = new python_generator(consumer.exported_types, + consumer.exported_functions, consumer.functions); + else if (Language.compare("cpp") == 0) + gen = new cpp_generator(consumer.exported_types, + consumer.exported_functions, consumer.functions); + else + cerr << "Language '" << Language << "' not recognized." << endl + << "Not generating bindings." << endl; + + if (gen) + gen->generate(); + + delete sema; + delete Clang; + llvm::llvm_shutdown(); + + return 0; +} Index: contrib/isl/interface/generator.h =================================================================== --- /dev/null +++ contrib/isl/interface/generator.h @@ -0,0 +1,72 @@ +#ifndef ISL_INTERFACE_GENERATOR_H +#define ISL_INTERFACE_GENERATOR_H + +#include +#include +#include + +#include + +using namespace std; +using namespace clang; + +/* isl_class collects all constructors and methods for an isl "class". + * "name" is the name of the class. + * "type" is the declaration that introduces the type. + * "methods" contains the set of methods, grouped by method name. + * "fn_to_str" is a reference to the *_to_str method of this class, if any. + * "fn_copy" is a reference to the *_copy method of this class, if any. + * "fn_free" is a reference to the *_free method of this class, if any. + */ +struct isl_class { + string name; + RecordDecl *type; + set constructors; + map > methods; + FunctionDecl *fn_to_str; + FunctionDecl *fn_copy; + FunctionDecl *fn_free; +}; + +/* Base class for interface generators. + */ +class generator { +protected: + map classes; + map functions_by_name; + +public: + generator(set &exported_types, + set exported_functions, + set functions); + + virtual void generate() = 0; + virtual ~generator() {}; + +protected: + void print_class_header(const isl_class &clazz, const string &name, + const vector &super); + string drop_type_suffix(string name, FunctionDecl *method); + void die(const char *msg) __attribute__((noreturn)); + void die(string msg) __attribute__((noreturn)); + vector find_superclasses(RecordDecl *decl); + bool is_overload(Decl *decl); + bool is_constructor(Decl *decl); + bool takes(Decl *decl); + bool keeps(Decl *decl); + bool gives(Decl *decl); + isl_class *method2class(map &classes, + FunctionDecl *fd); + bool is_isl_ctx(QualType type); + bool first_arg_is_isl_ctx(FunctionDecl *fd); + bool is_isl_type(QualType type); + bool is_isl_bool(QualType type); + bool is_isl_stat(QualType type); + bool is_callback(QualType type); + bool is_string(QualType type); + bool is_static(const isl_class &clazz, FunctionDecl *method); + string extract_type(QualType type); + FunctionDecl *find_by_name(const string &name, bool required); +}; + +#endif /* ISL_INTERFACE_GENERATOR_H */ Index: contrib/isl/interface/generator.cc =================================================================== --- /dev/null +++ contrib/isl/interface/generator.cc @@ -0,0 +1,349 @@ +/* + * Copyright 2011,2015 Sven Verdoolaege. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as + * representing official policies, either expressed or implied, of + * Sven Verdoolaege. + */ + +#include +#include + +#include + +#include "isl_config.h" +#include "extract_interface.h" +#include "generator.h" + +/* Should "method" be considered to be a static method? + * That is, is the first argument something other than + * an instance of the class? + */ +bool generator::is_static(const isl_class &clazz, FunctionDecl *method) +{ + ParmVarDecl *param = method->getParamDecl(0); + QualType type = param->getOriginalType(); + + if (!is_isl_type(type)) + return true; + return extract_type(type) != clazz.name; +} + +/* Find the FunctionDecl with name "name", + * returning NULL if there is no such FunctionDecl. + * If "required" is set, then error out if no FunctionDecl can be found. + */ +FunctionDecl *generator::find_by_name(const string &name, bool required) +{ + map::iterator i; + + i = functions_by_name.find(name); + if (i != functions_by_name.end()) + return i->second; + if (required) + die("No " + name + " function found"); + return NULL; +} + +/* Collect all functions that belong to a certain type, separating + * constructors from regular methods and keeping track of the _to_str, + * _copy and _free functions, if any, separately. If there are any overloaded + * functions, then they are grouped based on their name after removing the + * argument type suffix. + */ +generator::generator(set &exported_types, + set exported_functions, set functions) +{ + map::iterator ci; + + set::iterator in; + for (in = functions.begin(); in != functions.end(); ++in) { + FunctionDecl *decl = *in; + functions_by_name[decl->getName()] = decl; + } + + set::iterator it; + for (it = exported_types.begin(); it != exported_types.end(); ++it) { + RecordDecl *decl = *it; + string name = decl->getName(); + classes[name].name = name; + classes[name].type = decl; + classes[name].fn_to_str = find_by_name(name + "_to_str", false); + classes[name].fn_copy = find_by_name(name + "_copy", true); + classes[name].fn_free = find_by_name(name + "_free", true); + } + + for (in = exported_functions.begin(); in != exported_functions.end(); + ++in) { + isl_class *c = method2class(classes, *in); + if (!c) + continue; + if (is_constructor(*in)) { + c->constructors.insert(*in); + } else { + FunctionDecl *method = *in; + string fullname = method->getName(); + fullname = drop_type_suffix(fullname, method); + c->methods[fullname].insert(method); + } + } +} + +/* Print error message "msg" and abort. + */ +void generator::die(const char *msg) +{ + fprintf(stderr, "%s\n", msg); + abort(); +} + +/* Print error message "msg" and abort. + */ +void generator::die(string msg) +{ + die(msg.c_str()); +} + +/* Return a sequence of the types of which the given type declaration is + * marked as being a subtype. + * The order of the types is the opposite of the order in which they + * appear in the source. In particular, the first annotation + * is the one that is closest to the annotated type and the corresponding + * type is then also the first that will appear in the sequence of types. + */ +std::vector generator::find_superclasses(RecordDecl *decl) +{ + vector super; + + if (!decl->hasAttrs()) + return super; + + string sub = "isl_subclass"; + size_t len = sub.length(); + AttrVec attrs = decl->getAttrs(); + for (AttrVec::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { + const AnnotateAttr *ann = dyn_cast(*i); + if (!ann) + continue; + string s = ann->getAnnotation().str(); + if (s.substr(0, len) == sub) { + s = s.substr(len + 1, s.length() - len - 2); + super.push_back(s); + } + } + + return super; +} + +/* Is decl marked as being part of an overloaded method? + */ +bool generator::is_overload(Decl *decl) +{ + return has_annotation(decl, "isl_overload"); +} + +/* Is decl marked as a constructor? + */ +bool generator::is_constructor(Decl *decl) +{ + return has_annotation(decl, "isl_constructor"); +} + +/* Is decl marked as consuming a reference? + */ +bool generator::takes(Decl *decl) +{ + return has_annotation(decl, "isl_take"); +} + +/* Is decl marked as preserving a reference? + */ +bool generator::keeps(Decl *decl) +{ + return has_annotation(decl, "isl_keep"); +} + +/* Is decl marked as returning a reference that is required to be freed. + */ +bool generator::gives(Decl *decl) +{ + return has_annotation(decl, "isl_give"); +} + +/* Return the class that has a name that matches the initial part + * of the name of function "fd" or NULL if no such class could be found. + */ +isl_class *generator::method2class(map &classes, + FunctionDecl *fd) +{ + string best; + map::iterator ci; + string name = fd->getNameAsString(); + + for (ci = classes.begin(); ci != classes.end(); ++ci) { + if (name.substr(0, ci->first.length()) == ci->first) + best = ci->first; + } + + if (classes.find(best) == classes.end()) { + cerr << "Unable to find class of " << name << endl; + return NULL; + } + + return &classes[best]; +} + +/* Is "type" the type "isl_ctx *"? + */ +bool generator::is_isl_ctx(QualType type) +{ + if (!type->isPointerType()) + return 0; + type = type->getPointeeType(); + if (type.getAsString() != "isl_ctx") + return false; + + return true; +} + +/* Is the first argument of "fd" of type "isl_ctx *"? + */ +bool generator::first_arg_is_isl_ctx(FunctionDecl *fd) +{ + ParmVarDecl *param; + + if (fd->getNumParams() < 1) + return false; + + param = fd->getParamDecl(0); + return is_isl_ctx(param->getOriginalType()); +} + +/* Is "type" that of a pointer to an isl_* structure? + */ +bool generator::is_isl_type(QualType type) +{ + if (type->isPointerType()) { + string s; + + type = type->getPointeeType(); + if (type->isFunctionType()) + return false; + s = type.getAsString(); + return s.substr(0, 4) == "isl_"; + } + + return false; +} + +/* Is "type" the type isl_bool? + */ +bool generator::is_isl_bool(QualType type) +{ + string s; + + if (type->isPointerType()) + return false; + + s = type.getAsString(); + return s == "isl_bool"; +} + +/* Is "type" the type isl_stat? + */ +bool generator::is_isl_stat(QualType type) +{ + string s; + + if (type->isPointerType()) + return false; + + s = type.getAsString(); + return s == "isl_stat"; +} + + +/* Is "type" that of a pointer to a function? + */ +bool generator::is_callback(QualType type) +{ + if (!type->isPointerType()) + return false; + type = type->getPointeeType(); + return type->isFunctionType(); +} + +/* Is "type" that of "char *" of "const char *"? + */ +bool generator::is_string(QualType type) +{ + if (type->isPointerType()) { + string s = type->getPointeeType().getAsString(); + return s == "const char" || s == "char"; + } + + return false; +} + +/* Return the name of the type that "type" points to. + * The input "type" is assumed to be a pointer type. + */ +string generator::extract_type(QualType type) +{ + if (type->isPointerType()) + return type->getPointeeType().getAsString(); + die("Cannot extract type from non-pointer type"); +} + +/* If "method" is overloaded, then drop the suffix of "name" + * corresponding to the type of the final argument and + * return the modified name (or the original name if + * no modifications were made). + */ +string generator::drop_type_suffix(string name, FunctionDecl *method) +{ + int num_params; + ParmVarDecl *param; + string type; + size_t name_len, type_len; + + if (!is_overload(method)) + return name; + + num_params = method->getNumParams(); + param = method->getParamDecl(num_params - 1); + type = extract_type(param->getOriginalType()); + type = type.substr(4); + name_len = name.length(); + type_len = type.length(); + + if (name_len > type_len && name.substr(name_len - type_len) == type) + name = name.substr(0, name_len - type_len - 1); + + return name; +} Index: contrib/isl/interface/isl-noexceptions.h.top =================================================================== --- /dev/null +++ contrib/isl/interface/isl-noexceptions.h.top @@ -0,0 +1,95 @@ +/// These are automatically generated C++ bindings without exceptions for isl. +/// +/// isl is a library for computing with integer sets and maps described by +/// Presburger formulas. On top of this, isl provides various tools for +/// polyhedral compilation, ranging from dependence analysis over scheduling +/// to AST generation. + +#ifndef ISL_CPP_NOEXCEPTIONS +#define ISL_CPP_NOEXCEPTIONS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace isl { +inline namespace noexceptions { + +#define ISLPP_STRINGIZE_(X) #X +#define ISLPP_STRINGIZE(X) ISLPP_STRINGIZE_(X) + +#define ISLPP_ASSERT(test, message) \ + do { \ + if (test) \ + break; \ + fputs("Assertion \"" #test "\" failed at " __FILE__ \ + ":" ISLPP_STRINGIZE(__LINE__) "\n " message "\n", \ + stderr); \ + } while (0) + +class boolean { +private: + isl_bool val; + + friend isl::boolean manage(isl_bool val); + boolean(isl_bool val): val(val) {} +public: + boolean() + : val(isl_bool_error) {} + + /* implicit */ boolean(bool val) + : val(val ? isl_bool_true : isl_bool_false) {} + + bool is_error() const { return val == isl_bool_error; } + bool is_false() const { return val == isl_bool_false; } + bool is_true() const { return val == isl_bool_true; } + + explicit operator bool() const { + ISLPP_ASSERT(!is_error(), "IMPLEMENTATION ERROR: Unhandled error state"); + return is_true(); + } + + boolean operator!() const { + if (is_error()) + return *this; + return !is_true(); + } +}; + +inline isl::boolean manage(isl_bool val) { + return isl::boolean(val); +} + +class ctx { + isl_ctx *ptr; +public: + /* implicit */ ctx(isl_ctx *ctx) + : ptr(ctx) {} + isl_ctx *release() { + auto tmp = ptr; + ptr = nullptr; + return tmp; + } + isl_ctx *get() { + return ptr; + } +}; + +enum class stat { + ok = isl_stat_ok, + error = isl_stat_error +}; + +} +} // namespace isl Index: contrib/isl/interface/isl.py.top =================================================================== --- /dev/null +++ contrib/isl/interface/isl.py.top @@ -0,0 +1,29 @@ +from ctypes import * + +isl = cdll.LoadLibrary("libisl.so") +libc = cdll.LoadLibrary("libc.so.6") + +class Error(Exception): + pass + +class Context: + defaultInstance = None + + def __init__(self): + ptr = isl.isl_ctx_alloc() + self.ptr = ptr + + def __del__(self): + isl.isl_ctx_free(self) + + def from_param(self): + return c_void_p(self.ptr) + + @staticmethod + def getDefaultInstance(): + if Context.defaultInstance == None: + Context.defaultInstance = Context() + return Context.defaultInstance + +isl.isl_ctx_alloc.restype = c_void_p +isl.isl_ctx_free.argtypes = [Context] Index: contrib/isl/interface/isl_test_cpp-noexceptions.cc =================================================================== --- /dev/null +++ contrib/isl/interface/isl_test_cpp-noexceptions.cc @@ -0,0 +1,337 @@ +/* Copyright 2016-2017 Tobias Grosser + * + * Use of this software is governed by the MIT license + * + * Written by Tobias Grosser, Weststrasse 47, CH-8003, Zurich + */ + +#include +#include +#include +#include +#include + +#include + +static void assert_impl(bool condition, const char *file, int line, + const char *message) +{ + if (condition) + return; + + fprintf(stderr, "Assertion failed in %s:%d %s\n", file, line, message); + exit(EXIT_FAILURE); +} + +static void assert_impl(isl::boolean condition, const char *file, int line, + const char *message) +{ + assert_impl(bool(condition), file, line, message); +} + +#define assert(exp) assert_impl(exp, __FILE__, __LINE__, #exp) + +/* Test the pointer interface for interaction between isl C and C++ types. + * + * This tests: + * - construction from an isl C object + * - check that constructed objects are non-null + * - get a non-owned C pointer from an isl C++ object usable in __isl_keep + * methods + * - use copy to get an owned C pointer from an isl C++ object which is usable + * in __isl_take methods. Verify that the original C++ object retains a valid + * pointer. + * - use release to get an owned C pointer from an isl C++ object which is + * usable in __isl_take methods. Verify that the original C++ object gave up + * its pointer and now is null. + */ +void test_pointer(isl::ctx ctx) +{ + isl_set *c_empty = isl_set_read_from_str(ctx.get(), "{ : false }"); + isl::set empty = isl::manage(c_empty); + assert(empty.is_empty()); + assert(isl_set_is_empty(empty.get())); + + assert(!empty.is_null()); + isl_set_free(empty.copy()); + assert(!empty.is_null()); + isl_set_free(empty.release()); + assert(empty.is_null()); +} + +/* Test that isl objects can be constructed. + * + * This tests: + * - construction of a null object + * - construction from a string + * - construction from an integer + * - static constructor without a parameter + * - conversion construction (implicit) + * - conversion construction (explicit) + * + * The tests to construct from integers and strings cover functionality that + * is also tested in the parameter type tests, but here we verify that + * multiple overloaded constructors are available and that overload resolution + * works as expected. + * + * Construction from an isl C pointer is tested in test_pointer. + */ +void test_constructors(isl::ctx ctx) +{ + isl::val null; + assert(null.is_null()); + + isl::val zero_from_str = isl::val(ctx, "0"); + assert(zero_from_str.is_zero()); + + isl::val zero_int_con = isl::val(ctx, 0); + assert(zero_int_con.is_zero()); + + isl::val zero_static_con = isl::val::zero(ctx); + assert(zero_static_con.is_zero()); + + isl::basic_set bs(ctx, "{ [1] }"); + isl::set result(ctx, "{ [1] }"); + isl::set s = bs; + assert(s.is_equal(result)); + isl::set s2(bs); + assert(s.unite(s2).is_equal(result)); +} + +/* Test integer function parameters. + * + * Verify that extreme values and zero work. + */ +void test_parameters_int(isl::ctx ctx) +{ + isl::val long_max_str(ctx, std::to_string(LONG_MAX)); + isl::val long_max_int(ctx, LONG_MAX); + assert(long_max_str.eq(long_max_int)); + + isl::val long_min_str(ctx, std::to_string(LONG_MIN)); + isl::val long_min_int(ctx, LONG_MIN); + assert(long_min_str.eq(long_min_int)); + + isl::val long_zero_str = isl::val(ctx, std::to_string(0)); + isl::val long_zero_int = isl::val(ctx, 0); + assert(long_zero_str.eq(long_zero_int)); +} + +/* Test isl objects parameters. + * + * Verify that isl objects can be passed as lvalue and rvalue parameters. + * Also verify that isl object parameters are automatically type converted if + * there is an inheritance relation. Finally, test function calls without + * any additional parameters, apart from the isl object on which + * the method is called. + */ +void test_parameters_obj(isl::ctx ctx) +{ + isl::set a(ctx, "{ [0] }"); + isl::set b(ctx, "{ [1] }"); + isl::set c(ctx, "{ [2] }"); + isl::set expected(ctx, "{ [i] : 0 <= i <= 2 }"); + + isl::set tmp = a.unite(b); + isl::set res_lvalue_param = tmp.unite(c); + assert(res_lvalue_param.is_equal(expected)); + + isl::set res_rvalue_param = a.unite(b).unite(c); + assert(res_rvalue_param.is_equal(expected)); + + isl::basic_set a2(ctx, "{ [0] }"); + assert(a.is_equal(a2)); + + isl::val two(ctx, 2); + isl::val half(ctx, "1/2"); + isl::val res_only_this_param = two.inv(); + assert(res_only_this_param.eq(half)); +} + +/* Test different kinds of parameters to be passed to functions. + * + * This includes integer and isl C++ object parameters. + */ +void test_parameters(isl::ctx ctx) +{ + test_parameters_int(ctx); + test_parameters_obj(ctx); +} + +/* Test that isl objects are returned correctly. + * + * This only tests that after combining two objects, the result is successfully + * returned. + */ +void test_return_obj(isl::ctx ctx) +{ + isl::val one(ctx, "1"); + isl::val two(ctx, "2"); + isl::val three(ctx, "3"); + + isl::val res = one.add(two); + + assert(res.eq(three)); +} + +/* Test that integer values are returned correctly. + */ +void test_return_int(isl::ctx ctx) +{ + isl::val one(ctx, "1"); + isl::val neg_one(ctx, "-1"); + isl::val zero(ctx, "0"); + + assert(one.sgn() > 0); + assert(neg_one.sgn() < 0); + assert(zero.sgn() == 0); +} + +/* Test that isl_bool values are returned correctly. + * + * We check in detail the following parts of the isl::boolean class: + * - The is_true, is_false, and is_error functions return true in case they + * are called on a true, false, or error instance of isl::boolean, + * respectively + * - Explicit conversion to 'bool' + * - Implicit conversion to 'bool' + * - The complement operator + * - Explicit construction from 'true' and 'false' + * - Explicit construction form isl_bool + */ +void test_return_bool(isl::ctx ctx) +{ + isl::set empty(ctx, "{ : false }"); + isl::set univ(ctx, "{ : }"); + isl::set null; + + isl::boolean b_true = empty.is_empty(); + isl::boolean b_false = univ.is_empty(); + isl::boolean b_error = null.is_empty(); + + assert(b_true.is_true()); + assert(!b_true.is_false()); + assert(!b_true.is_error()); + + assert(!b_false.is_true()); + assert(b_false.is_false()); + assert(!b_false.is_error()); + + assert(!b_error.is_true()); + assert(!b_error.is_false()); + assert(b_error.is_error()); + + assert(bool(b_true) == true); + assert(bool(b_false) == false); + + assert(b_true); + + assert((!b_false).is_true()); + assert((!b_true).is_false()); + assert((!b_error).is_error()); + + assert(isl::boolean(true).is_true()); + assert(!isl::boolean(true).is_false()); + assert(!isl::boolean(true).is_error()); + + assert(isl::boolean(false).is_false()); + assert(!isl::boolean(false).is_true()); + assert(!isl::boolean(false).is_error()); + + assert(isl::manage(isl_bool_true).is_true()); + assert(!isl::manage(isl_bool_true).is_false()); + assert(!isl::manage(isl_bool_true).is_error()); + + assert(isl::manage(isl_bool_false).is_false()); + assert(!isl::manage(isl_bool_false).is_true()); + assert(!isl::manage(isl_bool_false).is_error()); + + assert(isl::manage(isl_bool_error).is_error()); + assert(!isl::manage(isl_bool_error).is_true()); + assert(!isl::manage(isl_bool_error).is_false()); +} + +/* Test that strings are returned correctly. + */ +void test_return_string(isl::ctx ctx) +{ + isl::set context(ctx, "[n] -> { : }"); + isl::ast_build build = isl::ast_build::from_context(context); + isl::pw_aff pw_aff(ctx, "[n] -> { [n] }"); + + isl::ast_expr expr = build.expr_from(pw_aff); + const char *expected_string = "n"; + assert(expected_string == expr.to_C_str()); +} + +/* Test that return values are handled correctly. + * + * Test that isl C++ objects, integers, boolean values, and strings are + * returned correctly. + */ +void test_return(isl::ctx ctx) +{ + test_return_obj(ctx); + test_return_int(ctx); + test_return_bool(ctx); + test_return_string(ctx); +} + +/* Test that foreach functions are modeled correctly. + * + * Verify that lambdas are correctly called as callback of a 'foreach' + * function and that variables captured by the lambda work correctly. Also + * check that the foreach function takes account of the return value of the + * lambda and aborts in case isl::stat::error is returned and then returns + * isl::stat::error itself. + */ +void test_foreach(isl::ctx ctx) +{ + isl::set s(ctx, "{ [0]; [1]; [2] }"); + + std::vector basic_sets; + + auto add_to_vector = [&] (isl::basic_set bs) { + basic_sets.push_back(bs); + return isl::stat::ok; + }; + + isl::stat ret1 = s.foreach_basic_set(add_to_vector); + + assert(ret1 == isl::stat::ok); + assert(basic_sets.size() == 3); + assert(isl::set(basic_sets[0]).is_subset(s)); + assert(isl::set(basic_sets[1]).is_subset(s)); + assert(isl::set(basic_sets[2]).is_subset(s)); + assert(!basic_sets[0].is_equal(basic_sets[1])); + + auto fail = [&] (isl::basic_set bs) { + return isl::stat::error; + }; + + isl::stat ret2 = s.foreach_basic_set(fail); + + assert(ret2 == isl::stat::error); +} + +/* Test the isl C++ interface + * + * This includes: + * - The isl C <-> C++ pointer interface + * - Object construction + * - Different parameter types + * - Different return types + * - Foreach functions + */ +int main() +{ + isl_ctx *ctx = isl_ctx_alloc(); + + test_pointer(ctx); + test_constructors(ctx); + test_parameters(ctx); + test_return(ctx); + test_foreach(ctx); + + isl_ctx_free(ctx); +} Index: contrib/isl/interface/python.h =================================================================== --- /dev/null +++ contrib/isl/interface/python.h @@ -0,0 +1,45 @@ +#include +#include +#include "generator.h" + +using namespace std; +using namespace clang; + +class python_generator : public generator { +private: + set done; + +public: + python_generator(set &exported_types, + set exported_functions, + set functions) : + generator(exported_types, exported_functions, functions) {} + + virtual void generate(); + +private: + void print(const isl_class &clazz); + void print_method_header(bool is_static, const string &name, int n_arg); + void print_class_header(const isl_class &clazz, const string &name, + const vector &super); + void print_type_check(const string &type, int pos, bool upcast, + const string &super, const string &name, int n); + void print_callback(QualType type, int arg); + void print_arg_in_call(FunctionDecl *fd, int arg, int skip); + void print_argtypes(FunctionDecl *fd); + void print_method_return(FunctionDecl *method); + void print_restype(FunctionDecl *fd); + void print(map &classes, set &done); + void print_constructor(const isl_class &clazz, FunctionDecl *method); + void print_representation(const isl_class &clazz, + const string &python_name); + void print_method_type(FunctionDecl *fd); + void print_method_types(const isl_class &clazz); + void print_method(const isl_class &clazz, FunctionDecl *method, + vector super); + void print_method_overload(const isl_class &clazz, + FunctionDecl *method); + void print_method(const isl_class &clazz, const string &fullname, + const set &methods, vector super); + +}; Index: contrib/isl/interface/python.cc =================================================================== --- /dev/null +++ contrib/isl/interface/python.cc @@ -0,0 +1,673 @@ +/* + * Copyright 2011,2015 Sven Verdoolaege. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as + * representing official policies, either expressed or implied, of + * Sven Verdoolaege. + */ + +#include "isl_config.h" + +#include +#include +#include +#include + +#include "python.h" +#include "generator.h" + +/* Drop the "isl_" initial part of the type name "name". + */ +static string type2python(string name) +{ + return name.substr(4); +} + +/* Print the header of the method "name" with "n_arg" arguments. + * If "is_static" is set, then mark the python method as static. + * + * If the method is called "from", then rename it to "convert_from" + * because "from" is a python keyword. + */ +void python_generator::print_method_header(bool is_static, const string &name, + int n_arg) +{ + const char *s; + + if (is_static) + printf(" @staticmethod\n"); + + s = name.c_str(); + if (name == "from") + s = "convert_from"; + + printf(" def %s(", s); + for (int i = 0; i < n_arg; ++i) { + if (i) + printf(", "); + printf("arg%d", i); + } + printf("):\n"); +} + +/* Print a check that the argument in position "pos" is of type "type". + * If this fails and if "upcast" is set, then convert the first + * argument to "super" and call the method "name" on it, passing + * the remaining of the "n" arguments. + * If the check fails and "upcast" is not set, then simply raise + * an exception. + * If "upcast" is not set, then the "super", "name" and "n" arguments + * to this function are ignored. + */ +void python_generator::print_type_check(const string &type, int pos, + bool upcast, const string &super, const string &name, int n) +{ + printf(" try:\n"); + printf(" if not arg%d.__class__ is %s:\n", + pos, type.c_str()); + printf(" arg%d = %s(arg%d)\n", + pos, type.c_str(), pos); + printf(" except:\n"); + if (upcast) { + printf(" return %s(arg0).%s(", + type2python(super).c_str(), name.c_str()); + for (int i = 1; i < n; ++i) { + if (i != 1) + printf(", "); + printf("arg%d", i); + } + printf(")\n"); + } else + printf(" raise\n"); +} + +/* Construct a wrapper for a callback argument (at position "arg"). + * Assign the wrapper to "cb". We assume here that a function call + * has at most one callback argument. + * + * The wrapper converts the arguments of the callback to python types. + * If any exception is thrown, the wrapper keeps track of it in exc_info[0] + * and returns -1. Otherwise the wrapper returns 0. + */ +void python_generator::print_callback(QualType type, int arg) +{ + const FunctionProtoType *fn = type->getAs(); + unsigned n_arg = fn->getNumArgs(); + + printf(" exc_info = [None]\n"); + printf(" fn = CFUNCTYPE(c_int"); + for (unsigned i = 0; i < n_arg - 1; ++i) { + if (!is_isl_type(fn->getArgType(i))) + die("Argument has non-isl type"); + printf(", c_void_p"); + } + printf(", c_void_p)\n"); + printf(" def cb_func("); + for (unsigned i = 0; i < n_arg; ++i) { + if (i) + printf(", "); + printf("cb_arg%d", i); + } + printf("):\n"); + for (unsigned i = 0; i < n_arg - 1; ++i) { + string arg_type; + arg_type = type2python(extract_type(fn->getArgType(i))); + printf(" cb_arg%d = %s(ctx=arg0.ctx, " + "ptr=cb_arg%d)\n", i, arg_type.c_str(), i); + } + printf(" try:\n"); + printf(" arg%d(", arg); + for (unsigned i = 0; i < n_arg - 1; ++i) { + if (i) + printf(", "); + printf("cb_arg%d", i); + } + printf(")\n"); + printf(" except:\n"); + printf(" import sys\n"); + printf(" exc_info[0] = sys.exc_info()\n"); + printf(" return -1\n"); + printf(" return 0\n"); + printf(" cb = fn(cb_func)\n"); +} + +/* Print the argument at position "arg" in call to "fd". + * "skip" is the number of initial arguments of "fd" that are + * skipped in the Python method. + * + * If the argument is a callback, then print a reference to + * the callback wrapper "cb". + * Otherwise, if the argument is marked as consuming a reference, + * then pass a copy of the pointer stored in the corresponding + * argument passed to the Python method. + * Otherwise, if the argument is a pointer, then pass this pointer itself. + * Otherwise, pass the argument directly. + */ +void python_generator::print_arg_in_call(FunctionDecl *fd, int arg, int skip) +{ + ParmVarDecl *param = fd->getParamDecl(arg); + QualType type = param->getOriginalType(); + if (is_callback(type)) { + printf("cb"); + } else if (takes(param)) { + string type_s = extract_type(type); + printf("isl.%s_copy(arg%d.ptr)", type_s.c_str(), arg - skip); + } else if (type->isPointerType()) { + printf("arg%d.ptr", arg - skip); + } else { + printf("arg%d", arg - skip); + } +} + +/* Print the return statement of the python method corresponding + * to the C function "method". + * + * If the return type is a (const) char *, then convert the result + * to a Python string, raising an error on NULL and freeing + * the C string if needed. For python 3 compatibility, the string returned + * by isl is explicitly decoded as an 'ascii' string. This is correct + * as all strings returned by isl are expected to be 'ascii'. + * + * If the return type is isl_bool, then convert the result to + * a Python boolean, raising an error on isl_bool_error. + */ +void python_generator::print_method_return(FunctionDecl *method) +{ + QualType return_type = method->getReturnType(); + + if (is_isl_type(return_type)) { + string type; + + type = type2python(extract_type(return_type)); + printf(" return %s(ctx=ctx, ptr=res)\n", type.c_str()); + } else if (is_string(return_type)) { + printf(" if res == 0:\n"); + printf(" raise\n"); + printf(" string = " + "cast(res, c_char_p).value.decode('ascii')\n"); + + if (gives(method)) + printf(" libc.free(res)\n"); + + printf(" return string\n"); + } else if (is_isl_bool(return_type)) { + printf(" if res < 0:\n"); + printf(" raise\n"); + printf(" return bool(res)\n"); + } else { + printf(" return res\n"); + } +} + +/* Print a python method corresponding to the C function "method". + * "super" contains the superclasses of the class to which the method belongs, + * with the first element corresponding to the annotation that appears + * closest to the annotated type. This superclass is the least + * general extension of the annotated type in the linearization + * of the class hierarchy. + * + * If the first argument of "method" is something other than an instance + * of the class, then mark the python method as static. + * If, moreover, this first argument is an isl_ctx, then remove + * it from the arguments of the Python method. + * + * If the function has a callback argument, then it also has a "user" + * argument. Since Python has closures, there is no need for such + * a user argument in the Python interface, so we simply drop it. + * We also create a wrapper ("cb") for the callback. + * + * For each argument of the function that refers to an isl structure, + * including the object on which the method is called, + * we check if the corresponding actual argument is of the right type. + * If not, we try to convert it to the right type. + * If that doesn't work and if "super" contains at least one element, we try + * to convert self to the type of the first superclass in "super" and + * call the corresponding method. + * + * If the function consumes a reference, then we pass it a copy of + * the actual argument. + */ +void python_generator::print_method(const isl_class &clazz, + FunctionDecl *method, vector super) +{ + string fullname = method->getName(); + string cname = fullname.substr(clazz.name.length() + 1); + int num_params = method->getNumParams(); + int drop_user = 0; + int drop_ctx = first_arg_is_isl_ctx(method); + + for (int i = 1; i < num_params; ++i) { + ParmVarDecl *param = method->getParamDecl(i); + QualType type = param->getOriginalType(); + if (is_callback(type)) + drop_user = 1; + } + + print_method_header(is_static(clazz, method), cname, + num_params - drop_ctx - drop_user); + + for (int i = drop_ctx; i < num_params; ++i) { + ParmVarDecl *param = method->getParamDecl(i); + string type; + if (!is_isl_type(param->getOriginalType())) + continue; + type = type2python(extract_type(param->getOriginalType())); + if (!drop_ctx && i > 0 && super.size() > 0) + print_type_check(type, i - drop_ctx, true, super[0], + cname, num_params - drop_user); + else + print_type_check(type, i - drop_ctx, false, "", + cname, -1); + } + for (int i = 1; i < num_params; ++i) { + ParmVarDecl *param = method->getParamDecl(i); + QualType type = param->getOriginalType(); + if (!is_callback(type)) + continue; + print_callback(type->getPointeeType(), i - drop_ctx); + } + if (drop_ctx) + printf(" ctx = Context.getDefaultInstance()\n"); + else + printf(" ctx = arg0.ctx\n"); + printf(" res = isl.%s(", fullname.c_str()); + if (drop_ctx) + printf("ctx"); + else + print_arg_in_call(method, 0, 0); + for (int i = 1; i < num_params - drop_user; ++i) { + printf(", "); + print_arg_in_call(method, i, drop_ctx); + } + if (drop_user) + printf(", None"); + printf(")\n"); + + if (drop_user) { + printf(" if exc_info[0] != None:\n"); + printf(" raise (exc_info[0][0], " + "exc_info[0][1], exc_info[0][2])\n"); + } + + print_method_return(method); +} + +/* Print part of an overloaded python method corresponding to the C function + * "method". + * + * In particular, print code to test whether the arguments passed to + * the python method correspond to the arguments expected by "method" + * and to call "method" if they do. + */ +void python_generator::print_method_overload(const isl_class &clazz, + FunctionDecl *method) +{ + string fullname = method->getName(); + int num_params = method->getNumParams(); + int first; + string type; + + first = is_static(clazz, method) ? 0 : 1; + + printf(" if "); + for (int i = first; i < num_params; ++i) { + if (i > first) + printf(" and "); + ParmVarDecl *param = method->getParamDecl(i); + if (is_isl_type(param->getOriginalType())) { + string type; + type = extract_type(param->getOriginalType()); + type = type2python(type); + printf("arg%d.__class__ is %s", i, type.c_str()); + } else + printf("type(arg%d) == str", i); + } + printf(":\n"); + printf(" res = isl.%s(", fullname.c_str()); + print_arg_in_call(method, 0, 0); + for (int i = 1; i < num_params; ++i) { + printf(", "); + print_arg_in_call(method, i, 0); + } + printf(")\n"); + type = type2python(extract_type(method->getReturnType())); + printf(" return %s(ctx=arg0.ctx, ptr=res)\n", type.c_str()); +} + +/* Print a python method with a name derived from "fullname" + * corresponding to the C functions "methods". + * "super" contains the superclasses of the class to which the method belongs. + * + * If "methods" consists of a single element that is not marked overloaded, + * the use print_method to print the method. + * Otherwise, print an overloaded method with pieces corresponding + * to each function in "methods". + */ +void python_generator::print_method(const isl_class &clazz, + const string &fullname, const set &methods, + vector super) +{ + string cname; + set::const_iterator it; + int num_params; + FunctionDecl *any_method; + + any_method = *methods.begin(); + if (methods.size() == 1 && !is_overload(any_method)) { + print_method(clazz, any_method, super); + return; + } + + cname = fullname.substr(clazz.name.length() + 1); + num_params = any_method->getNumParams(); + + print_method_header(is_static(clazz, any_method), cname, num_params); + + for (it = methods.begin(); it != methods.end(); ++it) + print_method_overload(clazz, *it); +} + +/* Print part of the constructor for this isl_class. + * + * In particular, check if the actual arguments correspond to the + * formal arguments of "cons" and if so call "cons" and put the + * result in self.ptr and a reference to the default context in self.ctx. + * + * If the function consumes a reference, then we pass it a copy of + * the actual argument. + * + * If the function takes a string argument, the python string is first + * encoded as a byte sequence, using 'ascii' as encoding. This assumes + * that all strings passed to isl can be converted to 'ascii'. + */ +void python_generator::print_constructor(const isl_class &clazz, + FunctionDecl *cons) +{ + string fullname = cons->getName(); + string cname = fullname.substr(clazz.name.length() + 1); + int num_params = cons->getNumParams(); + int drop_ctx = first_arg_is_isl_ctx(cons); + + printf(" if len(args) == %d", num_params - drop_ctx); + for (int i = drop_ctx; i < num_params; ++i) { + ParmVarDecl *param = cons->getParamDecl(i); + QualType type = param->getOriginalType(); + if (is_isl_type(type)) { + string s; + s = type2python(extract_type(type)); + printf(" and args[%d].__class__ is %s", + i - drop_ctx, s.c_str()); + } else if (type->isPointerType()) { + printf(" and type(args[%d]) == str", i - drop_ctx); + } else { + printf(" and type(args[%d]) == int", i - drop_ctx); + } + } + printf(":\n"); + printf(" self.ctx = Context.getDefaultInstance()\n"); + printf(" self.ptr = isl.%s(", fullname.c_str()); + if (drop_ctx) + printf("self.ctx"); + for (int i = drop_ctx; i < num_params; ++i) { + ParmVarDecl *param = cons->getParamDecl(i); + QualType type = param->getOriginalType(); + if (i) + printf(", "); + if (is_isl_type(type)) { + if (takes(param)) { + string type; + type = extract_type(param->getOriginalType()); + printf("isl.%s_copy(args[%d].ptr)", + type.c_str(), i - drop_ctx); + } else + printf("args[%d].ptr", i - drop_ctx); + } else if (is_string(type)) { + printf("args[%d].encode('ascii')", i - drop_ctx); + } else { + printf("args[%d]", i - drop_ctx); + } + } + printf(")\n"); + printf(" return\n"); +} + +/* Print the header of the class "name" with superclasses "super". + * The order of the superclasses is the opposite of the order + * in which the corresponding annotations appear in the source code. + */ +void python_generator::print_class_header(const isl_class &clazz, + const string &name, const vector &super) +{ + printf("class %s", name.c_str()); + if (super.size() > 0) { + printf("("); + for (unsigned i = 0; i < super.size(); ++i) { + if (i > 0) + printf(", "); + printf("%s", type2python(super[i]).c_str()); + } + printf(")"); + } else { + printf("(object)"); + } + printf(":\n"); +} + +/* Tell ctypes about the return type of "fd". + * In particular, if "fd" returns a pointer to an isl object, + * then tell ctypes it returns a "c_void_p". + * Similarly, if "fd" returns an isl_bool, + * then tell ctypes it returns a "c_bool". + * If "fd" returns a char *, then simply tell ctypes. + */ +void python_generator::print_restype(FunctionDecl *fd) +{ + string fullname = fd->getName(); + QualType type = fd->getReturnType(); + if (is_isl_type(type)) + printf("isl.%s.restype = c_void_p\n", fullname.c_str()); + else if (is_isl_bool(type)) + printf("isl.%s.restype = c_bool\n", fullname.c_str()); + else if (is_string(type)) + printf("isl.%s.restype = POINTER(c_char)\n", fullname.c_str()); +} + +/* Tell ctypes about the types of the arguments of the function "fd". + */ +void python_generator::print_argtypes(FunctionDecl *fd) +{ + string fullname = fd->getName(); + int n = fd->getNumParams(); + int drop_user = 0; + + printf("isl.%s.argtypes = [", fullname.c_str()); + for (int i = 0; i < n - drop_user; ++i) { + ParmVarDecl *param = fd->getParamDecl(i); + QualType type = param->getOriginalType(); + if (is_callback(type)) + drop_user = 1; + if (i) + printf(", "); + if (is_isl_ctx(type)) + printf("Context"); + else if (is_isl_type(type) || is_callback(type)) + printf("c_void_p"); + else if (is_string(type)) + printf("c_char_p"); + else + printf("c_int"); + } + if (drop_user) + printf(", c_void_p"); + printf("]\n"); +} + +/* Print type definitions for the method 'fd'. + */ +void python_generator::print_method_type(FunctionDecl *fd) +{ + print_restype(fd); + print_argtypes(fd); +} + +/* Print declarations for methods printing the class representation, + * provided there is a corresponding *_to_str function. + * + * In particular, provide an implementation of __str__ and __repr__ methods to + * override the default representation used by python. Python uses __str__ to + * pretty print the class (e.g., when calling print(obj)) and uses __repr__ + * when printing a precise representation of an object (e.g., when dumping it + * in the REPL console). + * + * Check the type of the argument before calling the *_to_str function + * on it in case the method was called on an object from a subclass. + * + * The return value of the *_to_str function is decoded to a python string + * assuming an 'ascii' encoding. This is necessary for python 3 compatibility. + */ +void python_generator::print_representation(const isl_class &clazz, + const string &python_name) +{ + if (!clazz.fn_to_str) + return; + + printf(" def __str__(arg0):\n"); + print_type_check(python_name, 0, false, "", "", -1); + printf(" ptr = isl.%s(arg0.ptr)\n", + string(clazz.fn_to_str->getName()).c_str()); + printf(" res = cast(ptr, c_char_p).value.decode('ascii')\n"); + printf(" libc.free(ptr)\n"); + printf(" return res\n"); + printf(" def __repr__(self):\n"); + printf(" s = str(self)\n"); + printf(" if '\"' in s:\n"); + printf(" return 'isl.%s(\"\"\"%%s\"\"\")' %% s\n", + python_name.c_str()); + printf(" else:\n"); + printf(" return 'isl.%s(\"%%s\")' %% s\n", + python_name.c_str()); +} + +/* Print code to set method type signatures. + * + * To be able to call C functions it is necessary to explicitly set their + * argument and result types. Do this for all exported constructors and + * methods, as well as for the *_to_str method, if it exists. + * Assuming each exported class has a *_copy and a *_free method, + * also unconditionally set the type of such methods. + */ +void python_generator::print_method_types(const isl_class &clazz) +{ + set::const_iterator in; + map >::const_iterator it; + + for (in = clazz.constructors.begin(); in != clazz.constructors.end(); + ++in) + print_method_type(*in); + + for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) + for (in = it->second.begin(); in != it->second.end(); ++in) + print_method_type(*in); + + print_method_type(clazz.fn_copy); + print_method_type(clazz.fn_free); + if (clazz.fn_to_str) + print_method_type(clazz.fn_to_str); +} + +/* Print out the definition of this isl_class. + * + * We first check if this isl_class is a subclass of one or more other classes. + * If it is, we make sure those superclasses are printed out first. + * + * Then we print a constructor with several cases, one for constructing + * a Python object from a return value and one for each function that + * was marked as a constructor. + * + * Next, we print out some common methods and the methods corresponding + * to functions that are not marked as constructors. + * + * Finally, we tell ctypes about the types of the arguments of the + * constructor functions and the return types of those function returning + * an isl object. + */ +void python_generator::print(const isl_class &clazz) +{ + string p_name = type2python(clazz.name); + set::const_iterator in; + map >::const_iterator it; + vector super = find_superclasses(clazz.type); + + for (unsigned i = 0; i < super.size(); ++i) + if (done.find(super[i]) == done.end()) + print(classes[super[i]]); + done.insert(clazz.name); + + printf("\n"); + print_class_header(clazz, p_name, super); + printf(" def __init__(self, *args, **keywords):\n"); + + printf(" if \"ptr\" in keywords:\n"); + printf(" self.ctx = keywords[\"ctx\"]\n"); + printf(" self.ptr = keywords[\"ptr\"]\n"); + printf(" return\n"); + + for (in = clazz.constructors.begin(); in != clazz.constructors.end(); + ++in) + print_constructor(clazz, *in); + printf(" raise Error\n"); + printf(" def __del__(self):\n"); + printf(" if hasattr(self, 'ptr'):\n"); + printf(" isl.%s_free(self.ptr)\n", clazz.name.c_str()); + + print_representation(clazz, p_name); + + for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) + print_method(clazz, it->first, it->second, super); + + printf("\n"); + + print_method_types(clazz); +} + +/* Generate a python interface based on the extracted types and + * functions. + * + * Print out each class in turn. If one of these is a subclass of some + * other class, make sure the superclass is printed out first. + * functions. + */ +void python_generator::generate() +{ + map::iterator ci; + + for (ci = classes.begin(); ci != classes.end(); ++ci) { + if (done.find(ci->first) == done.end()) + print(ci->second); + } +} Index: contrib/isl/isl.py =================================================================== --- /dev/null +++ contrib/isl/isl.py @@ -0,0 +1,100 @@ +import gdb +import re + +# GDB Pretty Printers for most isl objects +class IslObjectPrinter: + """Print an isl object""" + def __init__ (self, val, type): + self.val = val + self.type = type + + def to_string (self): + # Cast val to a void pointer to stop gdb using this pretty + # printer for the pointer which would lead to an infinite loop. + void_ptr = gdb.lookup_type('void').pointer() + value = str(self.val.cast(void_ptr)) + printer = gdb.parse_and_eval("isl_printer_to_str(isl_" + + str(self.type) + + "_get_ctx(" + value + "))") + printer = gdb.parse_and_eval("isl_printer_print_" + + str(self.type) + "(" + + str(printer) + ", " + + value + ")") + string = gdb.parse_and_eval("(char*)isl_printer_get_str(" + + str(printer) + ")") + gdb.parse_and_eval("isl_printer_free(" + str(printer) + ")") + return string + + def display_hint (self): + return 'string' + +class IslIntPrinter: + """Print an isl_int """ + def __init__ (self, val): + self.val = val + + def to_string (self): + # Cast val to a void pointer to stop gdb using this pretty + # printer for the pointer which would lead to an infinite loop. + void_ptr = gdb.lookup_type('void').pointer() + value = str(self.val.cast(void_ptr)) + + context = gdb.parse_and_eval("isl_ctx_alloc()") + printer = gdb.parse_and_eval("isl_printer_to_str(" + + str(context) + ")") + printer = gdb.parse_and_eval("isl_printer_print_isl_int(" + + str(printer) + ", " + + value + ")") + string = gdb.parse_and_eval("(char*)isl_printer_get_str(" + + str(printer) + ")") + gdb.parse_and_eval("isl_printer_free(" + str(printer) + ")") + gdb.parse_and_eval("isl_ctx_free(" + str(context) + ")") + return string + + def display_hint (self): + return 'string' + +class IslPrintCommand (gdb.Command): + """Print an isl value.""" + def __init__ (self): + super (IslPrintCommand, self).__init__ ("islprint", + gdb.COMMAND_OBSCURE) + def invoke (self, arg, from_tty): + arg = gdb.parse_and_eval(arg); + printer = str_lookup_function(arg) + + if printer == None: + print "No isl printer for this type" + return + + print printer.to_string() + +IslPrintCommand() + +def str_lookup_function (val): + if val.type.code != gdb.TYPE_CODE_PTR: + if str(val.type) == "isl_int": + return IslIntPrinter(val) + else: + return None + + lookup_tag = val.type.target() + regex = re.compile ("^isl_(.*)$") + + if lookup_tag == None: + return None + + m = regex.match (str(lookup_tag)) + + if m: + # Those types of printers defined in isl. + if m.group(1) in ["basic_set", "set", "union_set", "basic_map", + "map", "union_map", "qpolynomial", + "pw_qpolynomial", "pw_qpolynomial_fold", + "union_pw_qpolynomial", + "union_pw_qpolynomial_fold"]: + return IslObjectPrinter(val, m.group(1)) + return None + +# Do not register the pretty printer. +# gdb.current_objfile().pretty_printers.append(str_lookup_function) Index: contrib/isl/isl_aff.c =================================================================== --- /dev/null +++ contrib/isl/isl_aff.c @@ -0,0 +1,8875 @@ +/* + * Copyright 2011 INRIA Saclay + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#define ISL_DIM_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef BASE +#define BASE aff + +#include + +#undef BASE +#define BASE pw_aff + +#include + +#undef BASE +#define BASE union_pw_aff + +#include + +#undef BASE +#define BASE union_pw_multi_aff + +#include + +__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); + if (!isl_local_space_divs_known(ls)) + isl_die(ctx, isl_error_invalid, "local space has unknown divs", + goto error); + if (!isl_local_space_is_set(ls)) + isl_die(ctx, isl_error_invalid, + "domain of affine expression should be a set", + goto error); + + total = isl_local_space_dim(ls, isl_dim_all); + v = isl_vec_alloc(ctx, 1 + 1 + total); + return isl_aff_alloc_vec(ls, v); +error: + isl_local_space_free(ls); + return NULL; +} + +__isl_give isl_aff *isl_aff_zero_on_domain(__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; +} + +/* Return a piecewise affine expression defined on the specified domain + * that is equal to zero. + */ +__isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(__isl_take isl_local_space *ls) +{ + return isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls)); +} + +/* Return an affine expression defined on the specified domain + * that represents NaN. + */ +__isl_give isl_aff *isl_aff_nan_on_domain(__isl_take isl_local_space *ls) +{ + isl_aff *aff; + + aff = isl_aff_alloc(ls); + if (!aff) + return NULL; + + isl_seq_clr(aff->v->el, aff->v->size); + + return aff; +} + +/* Return a piecewise affine expression defined on the specified domain + * that represents NaN. + */ +__isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls) +{ + return isl_pw_aff_from_aff(isl_aff_nan_on_domain(ls)); +} + +/* Return an affine expression that is equal to "val" on + * domain local space "ls". + */ +__isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls, + __isl_take isl_val *val) +{ + isl_aff *aff; + + if (!ls || !val) + goto error; + if (!isl_val_is_rat(val)) + isl_die(isl_val_get_ctx(val), isl_error_invalid, + "expecting rational value", goto error); + + aff = isl_aff_alloc(isl_local_space_copy(ls)); + if (!aff) + goto error; + + isl_seq_clr(aff->v->el + 2, aff->v->size - 2); + isl_int_set(aff->v->el[1], val->n); + isl_int_set(aff->v->el[0], val->d); + + isl_local_space_free(ls); + isl_val_free(val); + return aff; +error: + isl_local_space_free(ls); + isl_val_free(val); + return NULL; +} + +/* Return an affine expression that is equal to the specified dimension + * in "ls". + */ +__isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos) +{ + isl_space *space; + isl_aff *aff; + + if (!ls) + return NULL; + + space = isl_local_space_get_space(ls); + if (!space) + goto error; + if (isl_space_is_map(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "expecting (parameter) set space", goto error); + if (pos >= isl_local_space_dim(ls, type)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "position out of bounds", goto error); + + isl_space_free(space); + aff = isl_aff_alloc(ls); + if (!aff) + return NULL; + + pos += isl_local_space_offset(aff->ls, type); + + isl_int_set_si(aff->v->el[0], 1); + isl_seq_clr(aff->v->el + 1, aff->v->size - 1); + isl_int_set_si(aff->v->el[1 + pos], 1); + + return aff; +error: + isl_local_space_free(ls); + isl_space_free(space); + return NULL; +} + +/* Return a piecewise affine expression that is equal to + * the specified dimension in "ls". + */ +__isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos) +{ + return isl_pw_aff_from_aff(isl_aff_var_on_domain(ls, type, pos)); +} + +__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); +} + +__isl_null isl_aff *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; +} + +/* Return a hash value that digests "aff". + */ +uint32_t isl_aff_get_hash(__isl_keep isl_aff *aff) +{ + uint32_t hash, ls_hash, v_hash; + + if (!aff) + return 0; + + hash = isl_hash_init(); + ls_hash = isl_local_space_get_hash(aff->ls); + isl_hash_hash(hash, ls_hash); + v_hash = isl_vec_get_hash(aff->v); + isl_hash_hash(hash, v_hash); + + return hash; +} + +/* Externally, an isl_aff has a map space, but internally, the + * ls field corresponds to the domain of that space. + */ +int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type) +{ + if (!aff) + return 0; + if (type == isl_dim_out) + return 1; + if (type == isl_dim_in) + type = isl_dim_set; + return isl_local_space_dim(aff->ls, type); +} + +/* Return the position of the dimension of the given type and name + * in "aff". + * Return -1 if no such dimension can be found. + */ +int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type, + const char *name) +{ + if (!aff) + return -1; + if (type == isl_dim_out) + return -1; + if (type == isl_dim_in) + type = isl_dim_set; + return isl_local_space_find_dim_by_name(aff->ls, type, name); +} + +__isl_give isl_space *isl_aff_get_domain_space(__isl_keep isl_aff *aff) +{ + return aff ? isl_local_space_get_space(aff->ls) : NULL; +} + +__isl_give isl_space *isl_aff_get_space(__isl_keep isl_aff *aff) +{ + isl_space *space; + if (!aff) + return NULL; + space = isl_local_space_get_space(aff->ls); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, 1); + return space; +} + +__isl_give isl_local_space *isl_aff_get_domain_local_space( + __isl_keep isl_aff *aff) +{ + return aff ? isl_local_space_copy(aff->ls) : NULL; +} + +__isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff) +{ + isl_local_space *ls; + if (!aff) + return NULL; + ls = isl_local_space_copy(aff->ls); + ls = isl_local_space_from_domain(ls); + ls = isl_local_space_add_dims(ls, isl_dim_out, 1); + return ls; +} + +/* Externally, an isl_aff has a map space, but internally, the + * ls field corresponds to the domain of that space. + */ +const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff, + enum isl_dim_type type, unsigned pos) +{ + if (!aff) + return NULL; + if (type == isl_dim_out) + return NULL; + if (type == isl_dim_in) + type = isl_dim_set; + return isl_local_space_get_dim_name(aff->ls, type, pos); +} + +__isl_give isl_aff *isl_aff_reset_domain_space(__isl_take isl_aff *aff, + __isl_take isl_space *dim) +{ + aff = isl_aff_cow(aff); + if (!aff || !dim) + goto error; + + aff->ls = isl_local_space_reset_space(aff->ls, dim); + if (!aff->ls) + return isl_aff_free(aff); + + return aff; +error: + isl_aff_free(aff); + isl_space_free(dim); + return NULL; +} + +/* Reset the space of "aff". This function is called from isl_pw_templ.c + * and doesn't know if the space of an element object is represented + * directly or through its domain. It therefore passes along both. + */ +__isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff, + __isl_take isl_space *space, __isl_take isl_space *domain) +{ + isl_space_free(space); + return isl_aff_reset_domain_space(aff, domain); +} + +/* Reorder the coefficients of the affine expression based + * on the given reordering. + * The reordering r is assumed to have been extended with the local + * variables. + */ +static __isl_give isl_vec *vec_reorder(__isl_take isl_vec *vec, + __isl_take isl_reordering *r, int n_div) +{ + isl_vec *res; + int i; + + if (!vec || !r) + goto error; + + res = isl_vec_alloc(vec->ctx, + 2 + isl_space_dim(r->dim, isl_dim_all) + n_div); + if (!res) + goto error; + isl_seq_cpy(res->el, vec->el, 2); + isl_seq_clr(res->el + 2, res->size - 2); + for (i = 0; i < r->len; ++i) + isl_int_set(res->el[2 + r->pos[i]], vec->el[2 + i]); + + isl_reordering_free(r); + isl_vec_free(vec); + return res; +error: + isl_vec_free(vec); + isl_reordering_free(r); + return NULL; +} + +/* Reorder the dimensions of the domain of "aff" according + * to the given reordering. + */ +__isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff, + __isl_take isl_reordering *r) +{ + aff = isl_aff_cow(aff); + if (!aff) + goto error; + + r = isl_reordering_extend(r, aff->ls->div->n_row); + aff->v = vec_reorder(aff->v, isl_reordering_copy(r), + aff->ls->div->n_row); + aff->ls = isl_local_space_realign(aff->ls, r); + + if (!aff->v || !aff->ls) + return isl_aff_free(aff); + + return aff; +error: + isl_aff_free(aff); + isl_reordering_free(r); + return NULL; +} + +__isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff, + __isl_take isl_space *model) +{ + isl_bool equal_params; + + if (!aff || !model) + goto error; + + equal_params = isl_space_has_equal_params(aff->ls->dim, model); + if (equal_params < 0) + goto error; + if (!equal_params) { + isl_reordering *exp; + + model = isl_space_drop_dims(model, isl_dim_in, + 0, isl_space_dim(model, isl_dim_in)); + model = isl_space_drop_dims(model, isl_dim_out, + 0, isl_space_dim(model, isl_dim_out)); + exp = isl_parameter_alignment_reordering(aff->ls->dim, model); + exp = isl_reordering_extend_space(exp, + isl_aff_get_domain_space(aff)); + aff = isl_aff_realign_domain(aff, exp); + } + + isl_space_free(model); + return aff; +error: + isl_space_free(model); + isl_aff_free(aff); + return NULL; +} + +/* Is "aff" obviously equal to zero? + * + * If the denominator is zero, then "aff" is not equal to zero. + */ +isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff) +{ + if (!aff) + return isl_bool_error; + + if (isl_int_is_zero(aff->v->el[0])) + return isl_bool_false; + return isl_seq_first_non_zero(aff->v->el + 1, aff->v->size - 1) < 0; +} + +/* Does "aff" represent NaN? + */ +isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff) +{ + if (!aff) + return isl_bool_error; + + return isl_seq_first_non_zero(aff->v->el, 2) < 0; +} + +/* Are "aff1" and "aff2" obviously equal? + * + * NaN is not equal to anything, not even to another NaN. + */ +isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1, + __isl_keep isl_aff *aff2) +{ + isl_bool equal; + + if (!aff1 || !aff2) + return isl_bool_error; + + if (isl_aff_is_nan(aff1) || isl_aff_is_nan(aff2)) + return isl_bool_false; + + equal = isl_local_space_is_equal(aff1->ls, aff2->ls); + if (equal < 0 || !equal) + return equal; + + return isl_vec_is_equal(aff1->v, aff2->v); +} + +/* Return the common denominator of "aff" in "v". + * + * We cannot return anything meaningful in case of a NaN. + */ +isl_stat isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v) +{ + if (!aff) + return isl_stat_error; + if (isl_aff_is_nan(aff)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "cannot get denominator of NaN", return isl_stat_error); + isl_int_set(*v, aff->v->el[0]); + return isl_stat_ok; +} + +/* Return the common denominator of "aff". + */ +__isl_give isl_val *isl_aff_get_denominator_val(__isl_keep isl_aff *aff) +{ + isl_ctx *ctx; + + if (!aff) + return NULL; + + ctx = isl_aff_get_ctx(aff); + if (isl_aff_is_nan(aff)) + return isl_val_nan(ctx); + return isl_val_int_from_isl_int(ctx, aff->v->el[0]); +} + +/* Return the constant term of "aff". + */ +__isl_give isl_val *isl_aff_get_constant_val(__isl_keep isl_aff *aff) +{ + isl_ctx *ctx; + isl_val *v; + + if (!aff) + return NULL; + + ctx = isl_aff_get_ctx(aff); + if (isl_aff_is_nan(aff)) + return isl_val_nan(ctx); + v = isl_val_rat_from_isl_int(ctx, aff->v->el[1], aff->v->el[0]); + return isl_val_normalize(v); +} + +/* Return the coefficient of the variable of type "type" at position "pos" + * of "aff". + */ +__isl_give isl_val *isl_aff_get_coefficient_val(__isl_keep isl_aff *aff, + enum isl_dim_type type, int pos) +{ + isl_ctx *ctx; + isl_val *v; + + if (!aff) + return NULL; + + ctx = isl_aff_get_ctx(aff); + if (type == isl_dim_out) + isl_die(ctx, isl_error_invalid, + "output/set dimension does not have a coefficient", + return NULL); + if (type == isl_dim_in) + type = isl_dim_set; + + if (pos >= isl_local_space_dim(aff->ls, type)) + isl_die(ctx, isl_error_invalid, + "position out of bounds", return NULL); + + if (isl_aff_is_nan(aff)) + return isl_val_nan(ctx); + pos += isl_local_space_offset(aff->ls, type); + v = isl_val_rat_from_isl_int(ctx, aff->v->el[1 + pos], aff->v->el[0]); + return isl_val_normalize(v); +} + +/* Return the sign of the coefficient of the variable of type "type" + * at position "pos" of "aff". + */ +int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff, enum isl_dim_type type, + int pos) +{ + isl_ctx *ctx; + + if (!aff) + return 0; + + ctx = isl_aff_get_ctx(aff); + if (type == isl_dim_out) + isl_die(ctx, isl_error_invalid, + "output/set dimension does not have a coefficient", + return 0); + if (type == isl_dim_in) + type = isl_dim_set; + + if (pos >= isl_local_space_dim(aff->ls, type)) + isl_die(ctx, isl_error_invalid, + "position out of bounds", return 0); + + pos += isl_local_space_offset(aff->ls, type); + return isl_int_sgn(aff->v->el[1 + pos]); +} + +/* Replace the numerator of the constant term of "aff" by "v". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v) +{ + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) + 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_set(aff->v->el[1], v); + + return aff; +} + +/* Replace the constant term of "aff" by "v". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_set_constant_val(__isl_take isl_aff *aff, + __isl_take isl_val *v) +{ + if (!aff || !v) + goto error; + + if (isl_aff_is_nan(aff)) { + isl_val_free(v); + return aff; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "expecting rational value", goto error); + + if (isl_int_eq(aff->v->el[1], v->n) && + isl_int_eq(aff->v->el[0], v->d)) { + isl_val_free(v); + return aff; + } + + aff = isl_aff_cow(aff); + if (!aff) + goto error; + aff->v = isl_vec_cow(aff->v); + if (!aff->v) + goto error; + + if (isl_int_eq(aff->v->el[0], v->d)) { + isl_int_set(aff->v->el[1], v->n); + } else if (isl_int_is_one(v->d)) { + isl_int_mul(aff->v->el[1], aff->v->el[0], v->n); + } else { + isl_seq_scale(aff->v->el + 1, + aff->v->el + 1, v->d, aff->v->size - 1); + isl_int_mul(aff->v->el[1], aff->v->el[0], v->n); + isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); + aff->v = isl_vec_normalize(aff->v); + if (!aff->v) + goto error; + } + + isl_val_free(v); + return aff; +error: + isl_aff_free(aff); + isl_val_free(v); + return NULL; +} + +/* Add "v" to the constant term of "aff". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v) +{ + if (isl_int_is_zero(v)) + return aff; + + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) + 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; +} + +/* Add "v" to the constant term of "aff". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_add_constant_val(__isl_take isl_aff *aff, + __isl_take isl_val *v) +{ + if (!aff || !v) + goto error; + + if (isl_aff_is_nan(aff) || isl_val_is_zero(v)) { + isl_val_free(v); + return aff; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "expecting rational value", goto error); + + aff = isl_aff_cow(aff); + if (!aff) + goto error; + + aff->v = isl_vec_cow(aff->v); + if (!aff->v) + goto error; + + if (isl_int_is_one(v->d)) { + isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n); + } else if (isl_int_eq(aff->v->el[0], v->d)) { + isl_int_add(aff->v->el[1], aff->v->el[1], v->n); + aff->v = isl_vec_normalize(aff->v); + if (!aff->v) + goto error; + } else { + isl_seq_scale(aff->v->el + 1, + aff->v->el + 1, v->d, aff->v->size - 1); + isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n); + isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); + aff->v = isl_vec_normalize(aff->v); + if (!aff->v) + goto error; + } + + isl_val_free(v); + return aff; +error: + isl_aff_free(aff); + isl_val_free(v); + return NULL; +} + +__isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v) +{ + isl_int t; + + isl_int_init(t); + isl_int_set_si(t, v); + aff = isl_aff_add_constant(aff, t); + isl_int_clear(t); + + return aff; +} + +/* Add "v" to the numerator of the constant term of "aff". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_add_constant_num(__isl_take isl_aff *aff, isl_int v) +{ + if (isl_int_is_zero(v)) + return aff; + + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) + 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_add(aff->v->el[1], aff->v->el[1], v); + + return aff; +} + +/* Add "v" to the numerator of the constant term of "aff". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_add_constant_num_si(__isl_take isl_aff *aff, int v) +{ + isl_int t; + + if (v == 0) + return aff; + + isl_int_init(t); + isl_int_set_si(t, v); + aff = isl_aff_add_constant_num(aff, t); + isl_int_clear(t); + + return aff; +} + +/* Replace the numerator of the constant term of "aff" by "v". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v) +{ + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) + 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_set_si(aff->v->el[1], v); + + return aff; +} + +/* Replace the numerator of the coefficient of the variable of type "type" + * at position "pos" of "aff" by "v". + * + * A NaN is unaffected by this operation. + */ +__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 (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "output/set dimension does not have a coefficient", + return isl_aff_free(aff)); + if (type == isl_dim_in) + type = isl_dim_set; + + 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)); + + if (isl_aff_is_nan(aff)) + 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); + + pos += isl_local_space_offset(aff->ls, type); + isl_int_set(aff->v->el[1 + pos], v); + + return aff; +} + +/* Replace the numerator of the coefficient of the variable of type "type" + * at position "pos" of "aff" by "v". + * + * A NaN is unaffected by this operation. + */ +__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 (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "output/set dimension does not have a coefficient", + return isl_aff_free(aff)); + if (type == isl_dim_in) + type = isl_dim_set; + + if (pos < 0 || 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)); + + if (isl_aff_is_nan(aff)) + return aff; + pos += isl_local_space_offset(aff->ls, type); + if (isl_int_cmp_si(aff->v->el[1 + pos], v) == 0) + 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_set_si(aff->v->el[1 + pos], v); + + return aff; +} + +/* Replace the coefficient of the variable of type "type" at position "pos" + * of "aff" by "v". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_set_coefficient_val(__isl_take isl_aff *aff, + enum isl_dim_type type, int pos, __isl_take isl_val *v) +{ + if (!aff || !v) + goto error; + + if (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "output/set dimension does not have a coefficient", + goto error); + if (type == isl_dim_in) + type = isl_dim_set; + + if (pos >= isl_local_space_dim(aff->ls, type)) + isl_die(aff->v->ctx, isl_error_invalid, + "position out of bounds", goto error); + + if (isl_aff_is_nan(aff)) { + isl_val_free(v); + return aff; + } + if (!isl_val_is_rat(v)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "expecting rational value", goto error); + + pos += isl_local_space_offset(aff->ls, type); + if (isl_int_eq(aff->v->el[1 + pos], v->n) && + isl_int_eq(aff->v->el[0], v->d)) { + isl_val_free(v); + return aff; + } + + aff = isl_aff_cow(aff); + if (!aff) + goto error; + aff->v = isl_vec_cow(aff->v); + if (!aff->v) + goto error; + + if (isl_int_eq(aff->v->el[0], v->d)) { + isl_int_set(aff->v->el[1 + pos], v->n); + } else if (isl_int_is_one(v->d)) { + isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n); + } else { + isl_seq_scale(aff->v->el + 1, + aff->v->el + 1, v->d, aff->v->size - 1); + isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n); + isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); + aff->v = isl_vec_normalize(aff->v); + if (!aff->v) + goto error; + } + + isl_val_free(v); + return aff; +error: + isl_aff_free(aff); + isl_val_free(v); + return NULL; +} + +/* Add "v" to the coefficient of the variable of type "type" + * at position "pos" of "aff". + * + * A NaN is unaffected by this operation. + */ +__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 (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "output/set dimension does not have a coefficient", + return isl_aff_free(aff)); + if (type == isl_dim_in) + type = isl_dim_set; + + 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)); + + if (isl_aff_is_nan(aff)) + 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); + + pos += isl_local_space_offset(aff->ls, type); + isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v); + + return aff; +} + +/* Add "v" to the coefficient of the variable of type "type" + * at position "pos" of "aff". + * + * A NaN is unaffected by this operation. + */ +__isl_give isl_aff *isl_aff_add_coefficient_val(__isl_take isl_aff *aff, + enum isl_dim_type type, int pos, __isl_take isl_val *v) +{ + if (!aff || !v) + goto error; + + if (isl_val_is_zero(v)) { + isl_val_free(v); + return aff; + } + + if (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "output/set dimension does not have a coefficient", + goto error); + if (type == isl_dim_in) + type = isl_dim_set; + + if (pos >= isl_local_space_dim(aff->ls, type)) + isl_die(aff->v->ctx, isl_error_invalid, + "position out of bounds", goto error); + + if (isl_aff_is_nan(aff)) { + isl_val_free(v); + return aff; + } + if (!isl_val_is_rat(v)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "expecting rational value", goto error); + + aff = isl_aff_cow(aff); + if (!aff) + goto error; + + aff->v = isl_vec_cow(aff->v); + if (!aff->v) + goto error; + + pos += isl_local_space_offset(aff->ls, type); + if (isl_int_is_one(v->d)) { + isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n); + } else if (isl_int_eq(aff->v->el[0], v->d)) { + isl_int_add(aff->v->el[1 + pos], aff->v->el[1 + pos], v->n); + aff->v = isl_vec_normalize(aff->v); + if (!aff->v) + goto error; + } else { + isl_seq_scale(aff->v->el + 1, + aff->v->el + 1, v->d, aff->v->size - 1); + isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n); + isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); + aff->v = isl_vec_normalize(aff->v); + if (!aff->v) + goto error; + } + + isl_val_free(v); + return aff; +error: + isl_aff_free(aff); + isl_val_free(v); + return NULL; +} + +__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_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos) +{ + if (!aff) + return NULL; + + return isl_local_space_get_div(aff->ls, pos); +} + +/* Return the negation of "aff". + * + * As a special case, -NaN = NaN. + */ +__isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff) +{ + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) + 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_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1); + + return aff; +} + +/* Remove divs from the local space that do not appear in the affine + * expression. + * We currently only remove divs at the end. + * Some intermediate divs may also not appear directly in the affine + * expression, but we would also need to check that no other divs are + * defined in terms of them. + */ +__isl_give isl_aff *isl_aff_remove_unused_divs(__isl_take isl_aff *aff) +{ + int pos; + int off; + int n; + + if (!aff) + return NULL; + + n = isl_local_space_dim(aff->ls, isl_dim_div); + off = isl_local_space_offset(aff->ls, isl_dim_div); + + pos = isl_seq_last_non_zero(aff->v->el + 1 + off, n) + 1; + if (pos == n) + return aff; + + aff = isl_aff_cow(aff); + if (!aff) + return NULL; + + aff->ls = isl_local_space_drop_dims(aff->ls, isl_dim_div, pos, n - pos); + aff->v = isl_vec_drop_els(aff->v, 1 + off + pos, n - pos); + if (!aff->ls || !aff->v) + return isl_aff_free(aff); + + return aff; +} + +/* Look for any divs in the aff->ls with a denominator equal to one + * and plug them into the affine expression and any subsequent divs + * that may reference the div. + */ +static __isl_give isl_aff *plug_in_integral_divs(__isl_take isl_aff *aff) +{ + int i, n; + int len; + isl_int v; + isl_vec *vec; + isl_local_space *ls; + unsigned pos; + + if (!aff) + return NULL; + + n = isl_local_space_dim(aff->ls, isl_dim_div); + len = aff->v->size; + for (i = 0; i < n; ++i) { + if (!isl_int_is_one(aff->ls->div->row[i][0])) + continue; + ls = isl_local_space_copy(aff->ls); + ls = isl_local_space_substitute_seq(ls, isl_dim_div, i, + aff->ls->div->row[i], len, i + 1, n - (i + 1)); + vec = isl_vec_copy(aff->v); + vec = isl_vec_cow(vec); + if (!ls || !vec) + goto error; + + isl_int_init(v); + + pos = isl_local_space_offset(aff->ls, isl_dim_div) + i; + isl_seq_substitute(vec->el, pos, aff->ls->div->row[i], + len, len, v); + + isl_int_clear(v); + + isl_vec_free(aff->v); + aff->v = vec; + isl_local_space_free(aff->ls); + aff->ls = ls; + } + + return aff; +error: + isl_vec_free(vec); + isl_local_space_free(ls); + return isl_aff_free(aff); +} + +/* Look for any divs j that appear with a unit coefficient inside + * the definitions of other divs i and plug them into the definitions + * of the divs i. + * + * In particular, an expression of the form + * + * floor((f(..) + floor(g(..)/n))/m) + * + * is simplified to + * + * floor((n * f(..) + g(..))/(n * m)) + * + * This simplification is correct because we can move the expression + * f(..) into the inner floor in the original expression to obtain + * + * floor(floor((n * f(..) + g(..))/n)/m) + * + * from which we can derive the simplified expression. + */ +static __isl_give isl_aff *plug_in_unit_divs(__isl_take isl_aff *aff) +{ + int i, j, n; + int off; + + if (!aff) + return NULL; + + n = isl_local_space_dim(aff->ls, isl_dim_div); + off = isl_local_space_offset(aff->ls, isl_dim_div); + for (i = 1; i < n; ++i) { + for (j = 0; j < i; ++j) { + if (!isl_int_is_one(aff->ls->div->row[i][1 + off + j])) + continue; + aff->ls = isl_local_space_substitute_seq(aff->ls, + isl_dim_div, j, aff->ls->div->row[j], + aff->v->size, i, 1); + if (!aff->ls) + return isl_aff_free(aff); + } + } + + return aff; +} + +/* Swap divs "a" and "b" in "aff", which is assumed to be non-NULL. + * + * Even though this function is only called on isl_affs with a single + * reference, we are careful to only change aff->v and aff->ls together. + */ +static __isl_give isl_aff *swap_div(__isl_take isl_aff *aff, int a, int b) +{ + unsigned off = isl_local_space_offset(aff->ls, isl_dim_div); + isl_local_space *ls; + isl_vec *v; + + ls = isl_local_space_copy(aff->ls); + ls = isl_local_space_swap_div(ls, a, b); + v = isl_vec_copy(aff->v); + v = isl_vec_cow(v); + if (!ls || !v) + goto error; + + isl_int_swap(v->el[1 + off + a], v->el[1 + off + b]); + isl_vec_free(aff->v); + aff->v = v; + isl_local_space_free(aff->ls); + aff->ls = ls; + + return aff; +error: + isl_vec_free(v); + isl_local_space_free(ls); + return isl_aff_free(aff); +} + +/* Merge divs "a" and "b" in "aff", which is assumed to be non-NULL. + * + * We currently do not actually remove div "b", but simply add its + * coefficient to that of "a" and then zero it out. + */ +static __isl_give isl_aff *merge_divs(__isl_take isl_aff *aff, int a, int b) +{ + unsigned off = isl_local_space_offset(aff->ls, isl_dim_div); + + if (isl_int_is_zero(aff->v->el[1 + off + b])) + return aff; + + aff->v = isl_vec_cow(aff->v); + if (!aff->v) + return isl_aff_free(aff); + + isl_int_add(aff->v->el[1 + off + a], + aff->v->el[1 + off + a], aff->v->el[1 + off + b]); + isl_int_set_si(aff->v->el[1 + off + b], 0); + + return aff; +} + +/* Sort the divs in the local space of "aff" according to + * the comparison function "cmp_row" in isl_local_space.c, + * combining the coefficients of identical divs. + * + * Reordering divs does not change the semantics of "aff", + * so there is no need to call isl_aff_cow. + * Moreover, this function is currently only called on isl_affs + * with a single reference. + */ +static __isl_give isl_aff *sort_divs(__isl_take isl_aff *aff) +{ + int i, j, n; + + if (!aff) + return NULL; + + n = isl_aff_dim(aff, isl_dim_div); + for (i = 1; i < n; ++i) { + for (j = i - 1; j >= 0; --j) { + int cmp = isl_mat_cmp_div(aff->ls->div, j, j + 1); + if (cmp < 0) + break; + if (cmp == 0) + aff = merge_divs(aff, j, j + 1); + else + aff = swap_div(aff, j, j + 1); + if (!aff) + return NULL; + } + } + + return aff; +} + +/* Normalize the representation of "aff". + * + * This function should only be called of "new" isl_affs, i.e., + * with only a single reference. We therefore do not need to + * worry about affecting other instances. + */ +__isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff) +{ + if (!aff) + return NULL; + aff->v = isl_vec_normalize(aff->v); + if (!aff->v) + return isl_aff_free(aff); + aff = plug_in_integral_divs(aff); + aff = plug_in_unit_divs(aff); + aff = sort_divs(aff); + aff = isl_aff_remove_unused_divs(aff); + return aff; +} + +/* Given f, return floor(f). + * If f is an integer expression, then just return f. + * If f is a constant, then return the constant floor(f). + * Otherwise, if f = g/m, write g = q m + r, + * create a new div d = [r/m] and return the expression q + d. + * The coefficients in r are taken to lie between -m/2 and m/2. + * + * reduce_div_coefficients performs the same normalization. + * + * As a special case, floor(NaN) = NaN. + */ +__isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff) +{ + int i; + int size; + isl_ctx *ctx; + isl_vec *div; + + if (!aff) + return NULL; + + if (isl_aff_is_nan(aff)) + return aff; + if (isl_int_is_one(aff->v->el[0])) + 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); + + if (isl_aff_is_cst(aff)) { + isl_int_fdiv_q(aff->v->el[1], aff->v->el[1], aff->v->el[0]); + isl_int_set_si(aff->v->el[0], 1); + return aff; + } + + div = isl_vec_copy(aff->v); + div = isl_vec_cow(div); + if (!div) + return isl_aff_free(aff); + + ctx = isl_aff_get_ctx(aff); + isl_int_fdiv_q(aff->v->el[0], aff->v->el[0], ctx->two); + for (i = 1; i < aff->v->size; ++i) { + isl_int_fdiv_r(div->el[i], div->el[i], div->el[0]); + isl_int_fdiv_q(aff->v->el[i], aff->v->el[i], div->el[0]); + if (isl_int_gt(div->el[i], aff->v->el[0])) { + isl_int_sub(div->el[i], div->el[i], div->el[0]); + isl_int_add_ui(aff->v->el[i], aff->v->el[i], 1); + } + } + + aff->ls = isl_local_space_add_div(aff->ls, div); + if (!aff->ls) + return isl_aff_free(aff); + + size = aff->v->size; + aff->v = isl_vec_extend(aff->v, size + 1); + if (!aff->v) + return isl_aff_free(aff); + isl_int_set_si(aff->v->el[0], 1); + isl_int_set_si(aff->v->el[size], 1); + + aff = isl_aff_normalize(aff); + + return aff; +} + +/* Compute + * + * aff mod m = aff - m * floor(aff/m) + * + * with m an integer value. + */ +__isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff, + __isl_take isl_val *m) +{ + isl_aff *res; + + if (!aff || !m) + goto error; + + if (!isl_val_is_int(m)) + isl_die(isl_val_get_ctx(m), isl_error_invalid, + "expecting integer modulo", goto error); + + res = isl_aff_copy(aff); + aff = isl_aff_scale_down_val(aff, isl_val_copy(m)); + aff = isl_aff_floor(aff); + aff = isl_aff_scale_val(aff, m); + res = isl_aff_sub(res, aff); + + return res; +error: + isl_aff_free(aff); + isl_val_free(m); + return NULL; +} + +/* Compute + * + * pwaff mod m = pwaff - m * floor(pwaff/m) + */ +__isl_give isl_pw_aff *isl_pw_aff_mod(__isl_take isl_pw_aff *pwaff, isl_int m) +{ + isl_pw_aff *res; + + res = isl_pw_aff_copy(pwaff); + pwaff = isl_pw_aff_scale_down(pwaff, m); + pwaff = isl_pw_aff_floor(pwaff); + pwaff = isl_pw_aff_scale(pwaff, m); + res = isl_pw_aff_sub(res, pwaff); + + return res; +} + +/* Compute + * + * pa mod m = pa - m * floor(pa/m) + * + * with m an integer value. + */ +__isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa, + __isl_take isl_val *m) +{ + if (!pa || !m) + goto error; + if (!isl_val_is_int(m)) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "expecting integer modulo", goto error); + pa = isl_pw_aff_mod(pa, m->n); + isl_val_free(m); + return pa; +error: + isl_pw_aff_free(pa); + isl_val_free(m); + return NULL; +} + +/* Given f, return ceil(f). + * If f is an integer expression, then just return f. + * Otherwise, let f be the expression + * + * e/m + * + * then return + * + * floor((e + m - 1)/m) + * + * As a special case, ceil(NaN) = NaN. + */ +__isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff) +{ + if (!aff) + return NULL; + + if (isl_aff_is_nan(aff)) + return aff; + if (isl_int_is_one(aff->v->el[0])) + 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_add(aff->v->el[1], aff->v->el[1], aff->v->el[0]); + isl_int_sub_ui(aff->v->el[1], aff->v->el[1], 1); + aff = isl_aff_floor(aff); + + return aff; +} + +/* 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 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); + offset = 1 + isl_local_space_offset(aff->ls, isl_dim_div); + + aff->v = isl_vec_expand(aff->v, offset, old_n_div, exp, new_n_div); + aff->ls = isl_local_space_replace_divs(aff->ls, div); + if (!aff->v || !aff->ls) + return isl_aff_free(aff); + return aff; +error: + isl_aff_free(aff); + isl_mat_free(div); + return NULL; +} + +/* Add two affine expressions that live in the same local space. + */ +static __isl_give isl_aff *add_expanded(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + isl_int gcd, f; + + aff1 = isl_aff_cow(aff1); + if (!aff1 || !aff2) + goto error; + + aff1->v = isl_vec_cow(aff1->v); + if (!aff1->v) + goto error; + + isl_int_init(gcd); + isl_int_init(f); + isl_int_gcd(gcd, aff1->v->el[0], aff2->v->el[0]); + isl_int_divexact(f, aff2->v->el[0], gcd); + isl_seq_scale(aff1->v->el + 1, aff1->v->el + 1, f, aff1->v->size - 1); + isl_int_divexact(f, aff1->v->el[0], gcd); + isl_seq_addmul(aff1->v->el + 1, f, aff2->v->el + 1, aff1->v->size - 1); + isl_int_divexact(f, aff2->v->el[0], gcd); + isl_int_mul(aff1->v->el[0], aff1->v->el[0], f); + isl_int_clear(f); + isl_int_clear(gcd); + + isl_aff_free(aff2); + return aff1; +error: + isl_aff_free(aff1); + isl_aff_free(aff2); + return NULL; +} + +/* Return the sum of "aff1" and "aff2". + * + * If either of the two is NaN, then the result is NaN. + */ +__isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + isl_ctx *ctx; + int *exp1 = NULL; + int *exp2 = NULL; + isl_mat *div; + int n_div1, n_div2; + + if (!aff1 || !aff2) + goto error; + + ctx = isl_aff_get_ctx(aff1); + if (!isl_space_is_equal(aff1->ls->dim, aff2->ls->dim)) + isl_die(ctx, isl_error_invalid, + "spaces don't match", goto error); + + if (isl_aff_is_nan(aff1)) { + isl_aff_free(aff2); + return aff1; + } + if (isl_aff_is_nan(aff2)) { + isl_aff_free(aff1); + return aff2; + } + + n_div1 = isl_aff_dim(aff1, isl_dim_div); + n_div2 = isl_aff_dim(aff2, isl_dim_div); + if (n_div1 == 0 && n_div2 == 0) + return add_expanded(aff1, aff2); + + exp1 = isl_alloc_array(ctx, int, n_div1); + exp2 = isl_alloc_array(ctx, int, n_div2); + if ((n_div1 && !exp1) || (n_div2 && !exp2)) + goto error; + + div = isl_merge_divs(aff1->ls->div, aff2->ls->div, exp1, exp2); + aff1 = isl_aff_expand_divs(aff1, isl_mat_copy(div), exp1); + aff2 = isl_aff_expand_divs(aff2, div, exp2); + free(exp1); + free(exp2); + + return add_expanded(aff1, aff2); +error: + free(exp1); + free(exp2); + isl_aff_free(aff1); + isl_aff_free(aff2); + return NULL; +} + +__isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + return isl_aff_add(aff1, isl_aff_neg(aff2)); +} + +/* Return the result of scaling "aff" by a factor of "f". + * + * As a special case, f * NaN = NaN. + */ +__isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f) +{ + isl_int gcd; + + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) + return aff; + + if (isl_int_is_one(f)) + 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); + + if (isl_int_is_pos(f) && isl_int_is_divisible_by(aff->v->el[0], f)) { + isl_int_divexact(aff->v->el[0], aff->v->el[0], f); + return aff; + } + + isl_int_init(gcd); + isl_int_gcd(gcd, aff->v->el[0], f); + isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd); + isl_int_divexact(gcd, f, gcd); + isl_seq_scale(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1); + isl_int_clear(gcd); + + return aff; +} + +/* Multiple "aff" by "v". + */ +__isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff, + __isl_take isl_val *v) +{ + if (!aff || !v) + goto error; + + if (isl_val_is_one(v)) { + isl_val_free(v); + return aff; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "expecting rational factor", goto error); + + aff = isl_aff_scale(aff, v->n); + aff = isl_aff_scale_down(aff, v->d); + + isl_val_free(v); + return aff; +error: + isl_aff_free(aff); + isl_val_free(v); + return NULL; +} + +/* Return the result of scaling "aff" down by a factor of "f". + * + * As a special case, NaN/f = NaN. + */ +__isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f) +{ + isl_int gcd; + + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) + return aff; + + if (isl_int_is_one(f)) + return aff; + + aff = isl_aff_cow(aff); + if (!aff) + return NULL; + + if (isl_int_is_zero(f)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "cannot scale down by zero", return isl_aff_free(aff)); + + aff->v = isl_vec_cow(aff->v); + if (!aff->v) + return isl_aff_free(aff); + + isl_int_init(gcd); + isl_seq_gcd(aff->v->el + 1, aff->v->size - 1, &gcd); + isl_int_gcd(gcd, gcd, f); + isl_seq_scale_down(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1); + isl_int_divexact(gcd, f, gcd); + isl_int_mul(aff->v->el[0], aff->v->el[0], gcd); + isl_int_clear(gcd); + + return aff; +} + +/* Divide "aff" by "v". + */ +__isl_give isl_aff *isl_aff_scale_down_val(__isl_take isl_aff *aff, + __isl_take isl_val *v) +{ + if (!aff || !v) + goto error; + + if (isl_val_is_one(v)) { + isl_val_free(v); + return aff; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "expecting rational factor", goto error); + if (!isl_val_is_pos(v)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "factor needs to be positive", goto error); + + aff = isl_aff_scale(aff, v->d); + aff = isl_aff_scale_down(aff, v->n); + + isl_val_free(v); + return aff; +error: + isl_aff_free(aff); + isl_val_free(v); + return NULL; +} + +__isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f) +{ + isl_int v; + + if (f == 1) + return aff; + + isl_int_init(v); + isl_int_set_ui(v, f); + aff = isl_aff_scale_down(aff, v); + isl_int_clear(v); + + return aff; +} + +__isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned pos, const char *s) +{ + aff = isl_aff_cow(aff); + if (!aff) + return NULL; + if (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "cannot set name of output/set dimension", + return isl_aff_free(aff)); + if (type == isl_dim_in) + type = isl_dim_set; + aff->ls = isl_local_space_set_dim_name(aff->ls, type, pos, s); + if (!aff->ls) + return isl_aff_free(aff); + + return aff; +} + +__isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) +{ + aff = isl_aff_cow(aff); + if (!aff) + goto error; + if (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "cannot set name of output/set dimension", + goto error); + if (type == isl_dim_in) + type = isl_dim_set; + aff->ls = isl_local_space_set_dim_id(aff->ls, type, pos, id); + if (!aff->ls) + return isl_aff_free(aff); + + return aff; +error: + isl_id_free(id); + isl_aff_free(aff); + return NULL; +} + +/* Replace the identifier of the input tuple of "aff" by "id". + * type is currently required to be equal to isl_dim_in + */ +__isl_give isl_aff *isl_aff_set_tuple_id(__isl_take isl_aff *aff, + enum isl_dim_type type, __isl_take isl_id *id) +{ + aff = isl_aff_cow(aff); + if (!aff) + goto error; + if (type != isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "cannot only set id of input tuple", goto error); + aff->ls = isl_local_space_set_tuple_id(aff->ls, isl_dim_set, id); + if (!aff->ls) + return isl_aff_free(aff); + + return aff; +error: + isl_id_free(id); + isl_aff_free(aff); + return NULL; +} + +/* Exploit the equalities in "eq" to simplify the affine expression + * and the expressions of the integer divisions in the local space. + * The integer divisions in this local space are assumed to appear + * as regular dimensions in "eq". + */ +static __isl_give isl_aff *isl_aff_substitute_equalities_lifted( + __isl_take isl_aff *aff, __isl_take isl_basic_set *eq) +{ + int i, j; + unsigned total; + unsigned n_div; + + if (!eq) + goto error; + if (eq->n_eq == 0) { + isl_basic_set_free(eq); + return aff; + } + + aff = isl_aff_cow(aff); + if (!aff) + goto error; + + aff->ls = isl_local_space_substitute_equalities(aff->ls, + isl_basic_set_copy(eq)); + aff->v = isl_vec_cow(aff->v); + if (!aff->ls || !aff->v) + goto error; + + total = 1 + isl_space_dim(eq->dim, isl_dim_all); + n_div = eq->n_div; + for (i = 0; i < eq->n_eq; ++i) { + j = isl_seq_last_non_zero(eq->eq[i], total + n_div); + if (j < 0 || j == 0 || j >= total) + continue; + + isl_seq_elim(aff->v->el + 1, eq->eq[i], j, total, + &aff->v->el[0]); + } + + isl_basic_set_free(eq); + aff = isl_aff_normalize(aff); + return aff; +error: + isl_basic_set_free(eq); + isl_aff_free(aff); + return NULL; +} + +/* Exploit the equalities in "eq" to simplify the affine expression + * and the expressions of the integer divisions in the local space. + */ +__isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff, + __isl_take isl_basic_set *eq) +{ + int n_div; + + if (!aff || !eq) + goto error; + n_div = isl_local_space_dim(aff->ls, isl_dim_div); + if (n_div > 0) + eq = isl_basic_set_add_dims(eq, isl_dim_set, n_div); + return isl_aff_substitute_equalities_lifted(aff, eq); +error: + isl_basic_set_free(eq); + isl_aff_free(aff); + return NULL; +} + +/* Look for equalities among the variables shared by context and aff + * and the integer divisions of aff, if any. + * The equalities are then used to eliminate coefficients and/or integer + * divisions from aff. + */ +__isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff, + __isl_take isl_set *context) +{ + isl_basic_set *hull; + int n_div; + + if (!aff) + goto error; + n_div = isl_local_space_dim(aff->ls, isl_dim_div); + if (n_div > 0) { + isl_basic_set *bset; + isl_local_space *ls; + context = isl_set_add_dims(context, isl_dim_set, n_div); + ls = isl_aff_get_domain_local_space(aff); + bset = isl_basic_set_from_local_space(ls); + bset = isl_basic_set_lift(bset); + bset = isl_basic_set_flatten(bset); + context = isl_set_intersect(context, + isl_set_from_basic_set(bset)); + } + + hull = isl_set_affine_hull(context); + return isl_aff_substitute_equalities_lifted(aff, hull); +error: + isl_aff_free(aff); + isl_set_free(context); + return NULL; +} + +__isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff, + __isl_take isl_set *context) +{ + isl_set *dom_context = isl_set_universe(isl_aff_get_domain_space(aff)); + dom_context = isl_set_intersect_params(dom_context, context); + return isl_aff_gist(aff, dom_context); +} + +/* Return a basic set containing those elements in the space + * of aff where it is positive. "rational" should not be set. + * + * If "aff" is NaN, then it is not positive. + */ +static __isl_give isl_basic_set *aff_pos_basic_set(__isl_take isl_aff *aff, + int rational) +{ + isl_constraint *ineq; + isl_basic_set *bset; + isl_val *c; + + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) { + isl_space *space = isl_aff_get_domain_space(aff); + isl_aff_free(aff); + return isl_basic_set_empty(space); + } + if (rational) + isl_die(isl_aff_get_ctx(aff), isl_error_unsupported, + "rational sets not supported", goto error); + + ineq = isl_inequality_from_aff(aff); + c = isl_constraint_get_constant_val(ineq); + c = isl_val_sub_ui(c, 1); + ineq = isl_constraint_set_constant_val(ineq, c); + + bset = isl_basic_set_from_constraint(ineq); + bset = isl_basic_set_simplify(bset); + return bset; +error: + isl_aff_free(aff); + return NULL; +} + +/* Return a basic set containing those elements in the space + * of aff where it is non-negative. + * If "rational" is set, then return a rational basic set. + * + * If "aff" is NaN, then it is not non-negative (it's not negative either). + */ +static __isl_give isl_basic_set *aff_nonneg_basic_set( + __isl_take isl_aff *aff, int rational) +{ + isl_constraint *ineq; + isl_basic_set *bset; + + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) { + isl_space *space = isl_aff_get_domain_space(aff); + isl_aff_free(aff); + return isl_basic_set_empty(space); + } + + ineq = isl_inequality_from_aff(aff); + + bset = isl_basic_set_from_constraint(ineq); + if (rational) + bset = isl_basic_set_set_rational(bset); + bset = isl_basic_set_simplify(bset); + return bset; +} + +/* Return a basic set containing those elements in the space + * of aff where it is non-negative. + */ +__isl_give isl_basic_set *isl_aff_nonneg_basic_set(__isl_take isl_aff *aff) +{ + return aff_nonneg_basic_set(aff, 0); +} + +/* Return a basic set containing those elements in the domain space + * of "aff" where it is positive. + */ +__isl_give isl_basic_set *isl_aff_pos_basic_set(__isl_take isl_aff *aff) +{ + aff = isl_aff_add_constant_num_si(aff, -1); + return isl_aff_nonneg_basic_set(aff); +} + +/* Return a basic set containing those elements in the domain space + * of aff where it is negative. + */ +__isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff) +{ + aff = isl_aff_neg(aff); + return isl_aff_pos_basic_set(aff); +} + +/* Return a basic set containing those elements in the space + * of aff where it is zero. + * If "rational" is set, then return a rational basic set. + * + * If "aff" is NaN, then it is not zero. + */ +static __isl_give isl_basic_set *aff_zero_basic_set(__isl_take isl_aff *aff, + int rational) +{ + isl_constraint *ineq; + isl_basic_set *bset; + + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) { + isl_space *space = isl_aff_get_domain_space(aff); + isl_aff_free(aff); + return isl_basic_set_empty(space); + } + + ineq = isl_equality_from_aff(aff); + + bset = isl_basic_set_from_constraint(ineq); + if (rational) + bset = isl_basic_set_set_rational(bset); + bset = isl_basic_set_simplify(bset); + return bset; +} + +/* Return a basic set containing those elements in the space + * of aff where it is zero. + */ +__isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff) +{ + return aff_zero_basic_set(aff, 0); +} + +/* Return a basic set containing those elements in the shared space + * of aff1 and aff2 where aff1 is greater than or equal to aff2. + */ +__isl_give isl_basic_set *isl_aff_ge_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + aff1 = isl_aff_sub(aff1, aff2); + + return isl_aff_nonneg_basic_set(aff1); +} + +/* Return a basic set containing those elements in the shared domain space + * of "aff1" and "aff2" where "aff1" is greater than "aff2". + */ +__isl_give isl_basic_set *isl_aff_gt_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + aff1 = isl_aff_sub(aff1, aff2); + + return isl_aff_pos_basic_set(aff1); +} + +/* Return a set containing those elements in the shared space + * of aff1 and aff2 where aff1 is greater than or equal to aff2. + */ +__isl_give isl_set *isl_aff_ge_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + return isl_set_from_basic_set(isl_aff_ge_basic_set(aff1, aff2)); +} + +/* Return a set containing those elements in the shared domain space + * of aff1 and aff2 where aff1 is greater than aff2. + * + * If either of the two inputs is NaN, then the result is empty, + * as comparisons with NaN always return false. + */ +__isl_give isl_set *isl_aff_gt_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + return isl_set_from_basic_set(isl_aff_gt_basic_set(aff1, aff2)); +} + +/* Return a basic set containing those elements in the shared space + * of aff1 and aff2 where aff1 is smaller than or equal to aff2. + */ +__isl_give isl_basic_set *isl_aff_le_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + return isl_aff_ge_basic_set(aff2, aff1); +} + +/* Return a basic set containing those elements in the shared domain space + * of "aff1" and "aff2" where "aff1" is smaller than "aff2". + */ +__isl_give isl_basic_set *isl_aff_lt_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + return isl_aff_gt_basic_set(aff2, aff1); +} + +/* Return a set containing those elements in the shared space + * of aff1 and aff2 where aff1 is smaller than or equal to aff2. + */ +__isl_give isl_set *isl_aff_le_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + return isl_aff_ge_set(aff2, aff1); +} + +/* Return a set containing those elements in the shared domain space + * of "aff1" and "aff2" where "aff1" is smaller than "aff2". + */ +__isl_give isl_set *isl_aff_lt_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + return isl_set_from_basic_set(isl_aff_lt_basic_set(aff1, aff2)); +} + +/* Return a basic set containing those elements in the shared space + * of aff1 and aff2 where aff1 and aff2 are equal. + */ +__isl_give isl_basic_set *isl_aff_eq_basic_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + aff1 = isl_aff_sub(aff1, aff2); + + return isl_aff_zero_basic_set(aff1); +} + +/* Return a set containing those elements in the shared space + * of aff1 and aff2 where aff1 and aff2 are equal. + */ +__isl_give isl_set *isl_aff_eq_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + return isl_set_from_basic_set(isl_aff_eq_basic_set(aff1, aff2)); +} + +/* Return a set containing those elements in the shared domain space + * of aff1 and aff2 where aff1 and aff2 are not equal. + * + * If either of the two inputs is NaN, then the result is empty, + * as comparisons with NaN always return false. + */ +__isl_give isl_set *isl_aff_ne_set(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + isl_set *set_lt, *set_gt; + + set_lt = isl_aff_lt_set(isl_aff_copy(aff1), + isl_aff_copy(aff2)); + set_gt = isl_aff_gt_set(aff1, aff2); + return isl_set_union_disjoint(set_lt, set_gt); +} + +__isl_give isl_aff *isl_aff_add_on_domain(__isl_keep isl_set *dom, + __isl_take isl_aff *aff1, __isl_take isl_aff *aff2) +{ + aff1 = isl_aff_add(aff1, aff2); + aff1 = isl_aff_gist(aff1, isl_set_copy(dom)); + return aff1; +} + +int isl_aff_is_empty(__isl_keep isl_aff *aff) +{ + if (!aff) + return -1; + + return 0; +} + +/* Check whether the given affine expression has non-zero coefficient + * for any dimension in the given range or if any of these dimensions + * appear with non-zero coefficients in any of the integer divisions + * involved in the affine expression. + */ +isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + isl_ctx *ctx; + int *active = NULL; + isl_bool involves = isl_bool_false; + + if (!aff) + return isl_bool_error; + if (n == 0) + return isl_bool_false; + + ctx = isl_aff_get_ctx(aff); + if (first + n > isl_aff_dim(aff, type)) + isl_die(ctx, isl_error_invalid, + "range out of bounds", return isl_bool_error); + + active = isl_local_space_get_active(aff->ls, aff->v->el + 2); + if (!active) + goto error; + + first += isl_local_space_offset(aff->ls, type) - 1; + for (i = 0; i < n; ++i) + if (active[first + i]) { + involves = isl_bool_true; + break; + } + + free(active); + + return involves; +error: + free(active); + return isl_bool_error; +} + +__isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_ctx *ctx; + + if (!aff) + return NULL; + if (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "cannot drop output/set dimension", + return isl_aff_free(aff)); + if (type == isl_dim_in) + type = isl_dim_set; + if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type)) + return aff; + + ctx = isl_aff_get_ctx(aff); + if (first + n > isl_local_space_dim(aff->ls, type)) + isl_die(ctx, isl_error_invalid, "range out of bounds", + return isl_aff_free(aff)); + + aff = isl_aff_cow(aff); + if (!aff) + return NULL; + + aff->ls = isl_local_space_drop_dims(aff->ls, type, first, n); + if (!aff->ls) + return isl_aff_free(aff); + + first += 1 + isl_local_space_offset(aff->ls, type); + aff->v = isl_vec_drop_els(aff->v, first, n); + if (!aff->v) + return isl_aff_free(aff); + + return aff; +} + +/* Project the domain of the affine expression onto its parameter space. + * The affine expression may not involve any of the domain dimensions. + */ +__isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff) +{ + isl_space *space; + unsigned n; + int involves; + + n = isl_aff_dim(aff, isl_dim_in); + involves = isl_aff_involves_dims(aff, isl_dim_in, 0, n); + if (involves < 0) + return isl_aff_free(aff); + if (involves) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "affine expression involves some of the domain dimensions", + return isl_aff_free(aff)); + aff = isl_aff_drop_dims(aff, isl_dim_in, 0, n); + space = isl_aff_get_domain_space(aff); + space = isl_space_params(space); + aff = isl_aff_reset_domain_space(aff, space); + return aff; +} + +__isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_ctx *ctx; + + if (!aff) + return NULL; + if (type == isl_dim_out) + isl_die(aff->v->ctx, isl_error_invalid, + "cannot insert output/set dimensions", + return isl_aff_free(aff)); + if (type == isl_dim_in) + type = isl_dim_set; + if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type)) + return aff; + + ctx = isl_aff_get_ctx(aff); + if (first > isl_local_space_dim(aff->ls, type)) + isl_die(ctx, isl_error_invalid, "position out of bounds", + return isl_aff_free(aff)); + + aff = isl_aff_cow(aff); + if (!aff) + return NULL; + + aff->ls = isl_local_space_insert_dims(aff->ls, type, first, n); + if (!aff->ls) + return isl_aff_free(aff); + + first += 1 + isl_local_space_offset(aff->ls, type); + aff->v = isl_vec_insert_zero_els(aff->v, first, n); + if (!aff->v) + return isl_aff_free(aff); + + return aff; +} + +__isl_give isl_aff *isl_aff_add_dims(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned n) +{ + unsigned pos; + + pos = isl_aff_dim(aff, type); + + return isl_aff_insert_dims(aff, type, pos, n); +} + +__isl_give isl_pw_aff *isl_pw_aff_add_dims(__isl_take isl_pw_aff *pwaff, + enum isl_dim_type type, unsigned n) +{ + unsigned pos; + + pos = isl_pw_aff_dim(pwaff, type); + + return isl_pw_aff_insert_dims(pwaff, type, pos, n); +} + +/* Move the "n" dimensions of "src_type" starting at "src_pos" of "aff" + * to dimensions of "dst_type" at "dst_pos". + * + * We only support moving input dimensions to parameters and vice versa. + */ +__isl_give isl_aff *isl_aff_move_dims(__isl_take isl_aff *aff, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + unsigned g_dst_pos; + unsigned g_src_pos; + + if (!aff) + return NULL; + if (n == 0 && + !isl_local_space_is_named_or_nested(aff->ls, src_type) && + !isl_local_space_is_named_or_nested(aff->ls, dst_type)) + return aff; + + if (dst_type == isl_dim_out || src_type == isl_dim_out) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "cannot move output/set dimension", + return isl_aff_free(aff)); + if (dst_type == isl_dim_div || src_type == isl_dim_div) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "cannot move divs", return isl_aff_free(aff)); + if (dst_type == isl_dim_in) + dst_type = isl_dim_set; + if (src_type == isl_dim_in) + src_type = isl_dim_set; + + if (src_pos + n > isl_local_space_dim(aff->ls, src_type)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "range out of bounds", return isl_aff_free(aff)); + if (dst_type == src_type) + isl_die(isl_aff_get_ctx(aff), isl_error_unsupported, + "moving dims within the same type not supported", + return isl_aff_free(aff)); + + aff = isl_aff_cow(aff); + if (!aff) + return NULL; + + g_src_pos = 1 + isl_local_space_offset(aff->ls, src_type) + src_pos; + g_dst_pos = 1 + isl_local_space_offset(aff->ls, dst_type) + dst_pos; + if (dst_type > src_type) + g_dst_pos -= n; + + aff->v = isl_vec_move_els(aff->v, g_dst_pos, g_src_pos, n); + aff->ls = isl_local_space_move_dims(aff->ls, dst_type, dst_pos, + src_type, src_pos, n); + if (!aff->v || !aff->ls) + return isl_aff_free(aff); + + aff = sort_divs(aff); + + return aff; +} + +__isl_give isl_pw_aff *isl_pw_aff_from_aff(__isl_take isl_aff *aff) +{ + isl_set *dom = isl_set_universe(isl_aff_get_domain_space(aff)); + return isl_pw_aff_alloc(dom, aff); +} + +#define isl_aff_involves_nan isl_aff_is_nan + +#undef PW +#define PW isl_pw_aff +#undef EL +#define EL isl_aff +#undef EL_IS_ZERO +#define EL_IS_ZERO is_empty +#undef ZERO +#define ZERO empty +#undef IS_ZERO +#define IS_ZERO is_empty +#undef FIELD +#define FIELD aff +#undef DEFAULT_IS_ZERO +#define DEFAULT_IS_ZERO 0 + +#define NO_EVAL +#define NO_OPT +#define NO_LIFT +#define NO_MORPH + +#include +#include +#include + +#undef UNION +#define UNION isl_union_pw_aff +#undef PART +#define PART isl_pw_aff +#undef PARTS +#define PARTS pw_aff + +#include +#include + +static __isl_give isl_set *align_params_pw_pw_set_and( + __isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2, + __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2)) +{ + isl_bool equal_params; + + if (!pwaff1 || !pwaff2) + goto error; + equal_params = isl_space_has_equal_params(pwaff1->dim, pwaff2->dim); + if (equal_params < 0) + goto error; + if (equal_params) + return fn(pwaff1, pwaff2); + if (!isl_space_has_named_params(pwaff1->dim) || + !isl_space_has_named_params(pwaff2->dim)) + isl_die(isl_pw_aff_get_ctx(pwaff1), isl_error_invalid, + "unaligned unnamed parameters", goto error); + pwaff1 = isl_pw_aff_align_params(pwaff1, isl_pw_aff_get_space(pwaff2)); + pwaff2 = isl_pw_aff_align_params(pwaff2, isl_pw_aff_get_space(pwaff1)); + return fn(pwaff1, pwaff2); +error: + isl_pw_aff_free(pwaff1); + isl_pw_aff_free(pwaff2); + return NULL; +} + +/* Align the parameters of the to isl_pw_aff arguments and + * then apply a function "fn" on them that returns an isl_map. + */ +static __isl_give isl_map *align_params_pw_pw_map_and( + __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2, + __isl_give isl_map *(*fn)(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2)) +{ + isl_bool equal_params; + + if (!pa1 || !pa2) + goto error; + equal_params = isl_space_has_equal_params(pa1->dim, pa2->dim); + if (equal_params < 0) + goto error; + if (equal_params) + return fn(pa1, pa2); + if (!isl_space_has_named_params(pa1->dim) || + !isl_space_has_named_params(pa2->dim)) + isl_die(isl_pw_aff_get_ctx(pa1), isl_error_invalid, + "unaligned unnamed parameters", goto error); + pa1 = isl_pw_aff_align_params(pa1, isl_pw_aff_get_space(pa2)); + pa2 = isl_pw_aff_align_params(pa2, isl_pw_aff_get_space(pa1)); + return fn(pa1, pa2); +error: + isl_pw_aff_free(pa1); + isl_pw_aff_free(pa2); + return NULL; +} + +/* Compute a piecewise quasi-affine expression with a domain that + * is the union of those of pwaff1 and pwaff2 and such that on each + * cell, the quasi-affine expression is the maximum of those of pwaff1 + * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given + * cell, then the associated expression is the defined one. + */ +static __isl_give isl_pw_aff *pw_aff_union_max(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_ge_set); +} + +__isl_give isl_pw_aff *isl_pw_aff_union_max(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, + &pw_aff_union_max); +} + +/* Compute a piecewise quasi-affine expression with a domain that + * is the union of those of pwaff1 and pwaff2 and such that on each + * cell, the quasi-affine expression is the minimum of those of pwaff1 + * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given + * cell, then the associated expression is the defined one. + */ +static __isl_give isl_pw_aff *pw_aff_union_min(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_le_set); +} + +__isl_give isl_pw_aff *isl_pw_aff_union_min(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, + &pw_aff_union_min); +} + +__isl_give isl_pw_aff *isl_pw_aff_union_opt(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2, int max) +{ + if (max) + return isl_pw_aff_union_max(pwaff1, pwaff2); + else + return isl_pw_aff_union_min(pwaff1, pwaff2); +} + +/* Construct a map with as domain the domain of pwaff and + * one-dimensional range corresponding to the affine expressions. + */ +static __isl_give isl_map *map_from_pw_aff(__isl_take isl_pw_aff *pwaff) +{ + int i; + isl_space *dim; + isl_map *map; + + if (!pwaff) + return NULL; + + dim = isl_pw_aff_get_space(pwaff); + map = isl_map_empty(dim); + + for (i = 0; i < pwaff->n; ++i) { + isl_basic_map *bmap; + isl_map *map_i; + + bmap = isl_basic_map_from_aff(isl_aff_copy(pwaff->p[i].aff)); + map_i = isl_map_from_basic_map(bmap); + map_i = isl_map_intersect_domain(map_i, + isl_set_copy(pwaff->p[i].set)); + map = isl_map_union_disjoint(map, map_i); + } + + isl_pw_aff_free(pwaff); + + return map; +} + +/* Construct a map with as domain the domain of pwaff and + * one-dimensional range corresponding to the affine expressions. + */ +__isl_give isl_map *isl_map_from_pw_aff(__isl_take isl_pw_aff *pwaff) +{ + if (!pwaff) + return NULL; + if (isl_space_is_set(pwaff->dim)) + isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid, + "space of input is not a map", goto error); + return map_from_pw_aff(pwaff); +error: + isl_pw_aff_free(pwaff); + return NULL; +} + +/* Construct a one-dimensional set with as parameter domain + * the domain of pwaff and the single set dimension + * corresponding to the affine expressions. + */ +__isl_give isl_set *isl_set_from_pw_aff(__isl_take isl_pw_aff *pwaff) +{ + if (!pwaff) + return NULL; + if (!isl_space_is_set(pwaff->dim)) + isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid, + "space of input is not a set", goto error); + return map_from_pw_aff(pwaff); +error: + isl_pw_aff_free(pwaff); + return NULL; +} + +/* Return a set containing those elements in the domain + * of "pwaff" where it satisfies "fn" (if complement is 0) or + * does not satisfy "fn" (if complement is 1). + * + * The pieces with a NaN never belong to the result since + * NaN does not satisfy any property. + */ +static __isl_give isl_set *pw_aff_locus(__isl_take isl_pw_aff *pwaff, + __isl_give isl_basic_set *(*fn)(__isl_take isl_aff *aff, int rational), + int complement) +{ + int i; + isl_set *set; + + if (!pwaff) + return NULL; + + set = isl_set_empty(isl_pw_aff_get_domain_space(pwaff)); + + for (i = 0; i < pwaff->n; ++i) { + isl_basic_set *bset; + isl_set *set_i, *locus; + isl_bool rational; + + if (isl_aff_is_nan(pwaff->p[i].aff)) + continue; + + rational = isl_set_has_rational(pwaff->p[i].set); + bset = fn(isl_aff_copy(pwaff->p[i].aff), rational); + locus = isl_set_from_basic_set(bset); + set_i = isl_set_copy(pwaff->p[i].set); + if (complement) + set_i = isl_set_subtract(set_i, locus); + else + set_i = isl_set_intersect(set_i, locus); + set = isl_set_union_disjoint(set, set_i); + } + + isl_pw_aff_free(pwaff); + + return set; +} + +/* Return a set containing those elements in the domain + * of "pa" where it is positive. + */ +__isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa) +{ + return pw_aff_locus(pa, &aff_pos_basic_set, 0); +} + +/* Return a set containing those elements in the domain + * of pwaff where it is non-negative. + */ +__isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff) +{ + return pw_aff_locus(pwaff, &aff_nonneg_basic_set, 0); +} + +/* Return a set containing those elements in the domain + * of pwaff where it is zero. + */ +__isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) +{ + return pw_aff_locus(pwaff, &aff_zero_basic_set, 0); +} + +/* Return a set containing those elements in the domain + * of pwaff where it is not zero. + */ +__isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff) +{ + return pw_aff_locus(pwaff, &aff_zero_basic_set, 1); +} + +/* Return a set containing those elements in the shared domain + * of pwaff1 and pwaff2 where pwaff1 is greater than (or equal) to pwaff2. + * + * We compute the difference on the shared domain and then construct + * the set of values where this difference is non-negative. + * If strict is set, we first subtract 1 from the difference. + * If equal is set, we only return the elements where pwaff1 and pwaff2 + * are equal. + */ +static __isl_give isl_set *pw_aff_gte_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2, int strict, int equal) +{ + isl_set *set1, *set2; + + set1 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)); + set2 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)); + set1 = isl_set_intersect(set1, set2); + pwaff1 = isl_pw_aff_intersect_domain(pwaff1, isl_set_copy(set1)); + pwaff2 = isl_pw_aff_intersect_domain(pwaff2, isl_set_copy(set1)); + pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_neg(pwaff2)); + + if (strict) { + isl_space *dim = isl_set_get_space(set1); + isl_aff *aff; + aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim)); + aff = isl_aff_add_constant_si(aff, -1); + pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_alloc(set1, aff)); + } else + isl_set_free(set1); + + if (equal) + return isl_pw_aff_zero_set(pwaff1); + return isl_pw_aff_nonneg_set(pwaff1); +} + +/* Return a set containing those elements in the shared domain + * of pwaff1 and pwaff2 where pwaff1 is equal to pwaff2. + */ +static __isl_give isl_set *pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return pw_aff_gte_set(pwaff1, pwaff2, 0, 1); +} + +__isl_give isl_set *isl_pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_eq_set); +} + +/* Return a set containing those elements in the shared domain + * of pwaff1 and pwaff2 where pwaff1 is greater than or equal to pwaff2. + */ +static __isl_give isl_set *pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return pw_aff_gte_set(pwaff1, pwaff2, 0, 0); +} + +__isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_ge_set); +} + +/* Return a set containing those elements in the shared domain + * of pwaff1 and pwaff2 where pwaff1 is strictly greater than pwaff2. + */ +static __isl_give isl_set *pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return pw_aff_gte_set(pwaff1, pwaff2, 1, 0); +} + +__isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_gt_set); +} + +__isl_give isl_set *isl_pw_aff_le_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_ge_set(pwaff2, pwaff1); +} + +__isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_gt_set(pwaff2, pwaff1); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function values are ordered in the same way as "order", + * which returns a set in the shared domain of its two arguments. + * The parameters of "pa1" and "pa2" are assumed to have been aligned. + * + * Let "pa1" and "pa2" be defined on domains A and B respectively. + * We first pull back the two functions such that they are defined on + * the domain [A -> B]. Then we apply "order", resulting in a set + * in the space [A -> B]. Finally, we unwrap this set to obtain + * a map in the space A -> B. + */ +static __isl_give isl_map *isl_pw_aff_order_map_aligned( + __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2, + __isl_give isl_set *(*order)(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2)) +{ + isl_space *space1, *space2; + isl_multi_aff *ma; + isl_set *set; + + space1 = isl_space_domain(isl_pw_aff_get_space(pa1)); + space2 = isl_space_domain(isl_pw_aff_get_space(pa2)); + space1 = isl_space_map_from_domain_and_range(space1, space2); + ma = isl_multi_aff_domain_map(isl_space_copy(space1)); + pa1 = isl_pw_aff_pullback_multi_aff(pa1, ma); + ma = isl_multi_aff_range_map(space1); + pa2 = isl_pw_aff_pullback_multi_aff(pa2, ma); + set = order(pa1, pa2); + + return isl_set_unwrap(set); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function values are equal. + * The parameters of "pa1" and "pa2" are assumed to have been aligned. + */ +static __isl_give isl_map *isl_pw_aff_eq_map_aligned(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_eq_set); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function values are equal. + */ +__isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_eq_map_aligned); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function value of "pa1" is less than the function value of "pa2". + * The parameters of "pa1" and "pa2" are assumed to have been aligned. + */ +static __isl_give isl_map *isl_pw_aff_lt_map_aligned(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_lt_set); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function value of "pa1" is less than the function value of "pa2". + */ +__isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_lt_map_aligned); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function value of "pa1" is greater than the function value + * of "pa2". + * The parameters of "pa1" and "pa2" are assumed to have been aligned. + */ +static __isl_give isl_map *isl_pw_aff_gt_map_aligned(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_gt_set); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function value of "pa1" is greater than the function value + * of "pa2". + */ +__isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_gt_map_aligned); +} + +/* Return a set containing those elements in the shared domain + * of the elements of list1 and list2 where each element in list1 + * has the relation specified by "fn" with each element in list2. + */ +static __isl_give isl_set *pw_aff_list_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2, + __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2)) +{ + int i, j; + isl_ctx *ctx; + isl_set *set; + + if (!list1 || !list2) + goto error; + + ctx = isl_pw_aff_list_get_ctx(list1); + if (list1->n < 1 || list2->n < 1) + isl_die(ctx, isl_error_invalid, + "list should contain at least one element", goto error); + + set = isl_set_universe(isl_pw_aff_get_domain_space(list1->p[0])); + for (i = 0; i < list1->n; ++i) + for (j = 0; j < list2->n; ++j) { + isl_set *set_ij; + + set_ij = fn(isl_pw_aff_copy(list1->p[i]), + isl_pw_aff_copy(list2->p[j])); + set = isl_set_intersect(set, set_ij); + } + + isl_pw_aff_list_free(list1); + isl_pw_aff_list_free(list2); + return set; +error: + isl_pw_aff_list_free(list1); + isl_pw_aff_list_free(list2); + return NULL; +} + +/* Return a set containing those elements in the shared domain + * of the elements of list1 and list2 where each element in list1 + * is equal to each element in list2. + */ +__isl_give isl_set *isl_pw_aff_list_eq_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2) +{ + return pw_aff_list_set(list1, list2, &isl_pw_aff_eq_set); +} + +__isl_give isl_set *isl_pw_aff_list_ne_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2) +{ + return pw_aff_list_set(list1, list2, &isl_pw_aff_ne_set); +} + +/* Return a set containing those elements in the shared domain + * of the elements of list1 and list2 where each element in list1 + * is less than or equal to each element in list2. + */ +__isl_give isl_set *isl_pw_aff_list_le_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2) +{ + return pw_aff_list_set(list1, list2, &isl_pw_aff_le_set); +} + +__isl_give isl_set *isl_pw_aff_list_lt_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2) +{ + return pw_aff_list_set(list1, list2, &isl_pw_aff_lt_set); +} + +__isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2) +{ + return pw_aff_list_set(list1, list2, &isl_pw_aff_ge_set); +} + +__isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1, + __isl_take isl_pw_aff_list *list2) +{ + return pw_aff_list_set(list1, list2, &isl_pw_aff_gt_set); +} + + +/* Return a set containing those elements in the shared domain + * of pwaff1 and pwaff2 where pwaff1 is not equal to pwaff2. + */ +static __isl_give isl_set *pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + isl_set *set_lt, *set_gt; + + set_lt = isl_pw_aff_lt_set(isl_pw_aff_copy(pwaff1), + isl_pw_aff_copy(pwaff2)); + set_gt = isl_pw_aff_gt_set(pwaff1, pwaff2); + return isl_set_union_disjoint(set_lt, set_gt); +} + +__isl_give isl_set *isl_pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_ne_set); +} + +__isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff, + isl_int v) +{ + int i; + + if (isl_int_is_one(v)) + return pwaff; + if (!isl_int_is_pos(v)) + isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid, + "factor needs to be positive", + return isl_pw_aff_free(pwaff)); + pwaff = isl_pw_aff_cow(pwaff); + if (!pwaff) + return NULL; + if (pwaff->n == 0) + return pwaff; + + for (i = 0; i < pwaff->n; ++i) { + pwaff->p[i].aff = isl_aff_scale_down(pwaff->p[i].aff, v); + if (!pwaff->p[i].aff) + return isl_pw_aff_free(pwaff); + } + + return pwaff; +} + +__isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff) +{ + int i; + + pwaff = isl_pw_aff_cow(pwaff); + if (!pwaff) + return NULL; + if (pwaff->n == 0) + return pwaff; + + for (i = 0; i < pwaff->n; ++i) { + pwaff->p[i].aff = isl_aff_floor(pwaff->p[i].aff); + if (!pwaff->p[i].aff) + return isl_pw_aff_free(pwaff); + } + + return pwaff; +} + +__isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff) +{ + int i; + + pwaff = isl_pw_aff_cow(pwaff); + if (!pwaff) + return NULL; + if (pwaff->n == 0) + return pwaff; + + for (i = 0; i < pwaff->n; ++i) { + pwaff->p[i].aff = isl_aff_ceil(pwaff->p[i].aff); + if (!pwaff->p[i].aff) + return isl_pw_aff_free(pwaff); + } + + return pwaff; +} + +/* Assuming that "cond1" and "cond2" are disjoint, + * return an affine expression that is equal to pwaff1 on cond1 + * and to pwaff2 on cond2. + */ +static __isl_give isl_pw_aff *isl_pw_aff_select( + __isl_take isl_set *cond1, __isl_take isl_pw_aff *pwaff1, + __isl_take isl_set *cond2, __isl_take isl_pw_aff *pwaff2) +{ + pwaff1 = isl_pw_aff_intersect_domain(pwaff1, cond1); + pwaff2 = isl_pw_aff_intersect_domain(pwaff2, cond2); + + return isl_pw_aff_add_disjoint(pwaff1, pwaff2); +} + +/* Return an affine expression that is equal to pwaff_true for elements + * where "cond" is non-zero and to pwaff_false for elements where "cond" + * is zero. + * That is, return cond ? pwaff_true : pwaff_false; + * + * If "cond" involves and NaN, then we conservatively return a NaN + * on its entire domain. In principle, we could consider the pieces + * where it is NaN separately from those where it is not. + * + * If "pwaff_true" and "pwaff_false" are obviously equal to each other, + * then only use the domain of "cond" to restrict the domain. + */ +__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond, + __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false) +{ + isl_set *cond_true, *cond_false; + isl_bool equal; + + if (!cond) + goto error; + if (isl_pw_aff_involves_nan(cond)) { + isl_space *space = isl_pw_aff_get_domain_space(cond); + isl_local_space *ls = isl_local_space_from_space(space); + isl_pw_aff_free(cond); + isl_pw_aff_free(pwaff_true); + isl_pw_aff_free(pwaff_false); + return isl_pw_aff_nan_on_domain(ls); + } + + pwaff_true = isl_pw_aff_align_params(pwaff_true, + isl_pw_aff_get_space(pwaff_false)); + pwaff_false = isl_pw_aff_align_params(pwaff_false, + isl_pw_aff_get_space(pwaff_true)); + equal = isl_pw_aff_plain_is_equal(pwaff_true, pwaff_false); + if (equal < 0) + goto error; + if (equal) { + isl_set *dom; + + dom = isl_set_coalesce(isl_pw_aff_domain(cond)); + isl_pw_aff_free(pwaff_false); + return isl_pw_aff_intersect_domain(pwaff_true, dom); + } + + cond_true = isl_pw_aff_non_zero_set(isl_pw_aff_copy(cond)); + cond_false = isl_pw_aff_zero_set(cond); + return isl_pw_aff_select(cond_true, pwaff_true, + cond_false, pwaff_false); +error: + isl_pw_aff_free(cond); + isl_pw_aff_free(pwaff_true); + isl_pw_aff_free(pwaff_false); + return NULL; +} + +isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff) +{ + if (!aff) + return isl_bool_error; + + return isl_seq_first_non_zero(aff->v->el + 2, aff->v->size - 2) == -1; +} + +/* Check whether pwaff is a piecewise constant. + */ +isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff) +{ + int i; + + if (!pwaff) + return isl_bool_error; + + for (i = 0; i < pwaff->n; ++i) { + isl_bool is_cst = isl_aff_is_cst(pwaff->p[i].aff); + if (is_cst < 0 || !is_cst) + return is_cst; + } + + return isl_bool_true; +} + +/* Are all elements of "mpa" piecewise constants? + */ +isl_bool isl_multi_pw_aff_is_cst(__isl_keep isl_multi_pw_aff *mpa) +{ + int i; + + if (!mpa) + return isl_bool_error; + + for (i = 0; i < mpa->n; ++i) { + isl_bool is_cst = isl_pw_aff_is_cst(mpa->p[i]); + if (is_cst < 0 || !is_cst) + return is_cst; + } + + return isl_bool_true; +} + +/* Return the product of "aff1" and "aff2". + * + * If either of the two is NaN, then the result is NaN. + * + * Otherwise, at least one of "aff1" or "aff2" needs to be a constant. + */ +__isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + if (!aff1 || !aff2) + goto error; + + if (isl_aff_is_nan(aff1)) { + isl_aff_free(aff2); + return aff1; + } + if (isl_aff_is_nan(aff2)) { + isl_aff_free(aff1); + return aff2; + } + + if (!isl_aff_is_cst(aff2) && isl_aff_is_cst(aff1)) + return isl_aff_mul(aff2, aff1); + + if (!isl_aff_is_cst(aff2)) + isl_die(isl_aff_get_ctx(aff1), isl_error_invalid, + "at least one affine expression should be constant", + goto error); + + aff1 = isl_aff_cow(aff1); + if (!aff1 || !aff2) + goto error; + + aff1 = isl_aff_scale(aff1, aff2->v->el[1]); + aff1 = isl_aff_scale_down(aff1, aff2->v->el[0]); + + isl_aff_free(aff2); + return aff1; +error: + isl_aff_free(aff1); + isl_aff_free(aff2); + return NULL; +} + +/* Divide "aff1" by "aff2", assuming "aff2" is a constant. + * + * If either of the two is NaN, then the result is NaN. + */ +__isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + int is_cst; + int neg; + + if (!aff1 || !aff2) + goto error; + + if (isl_aff_is_nan(aff1)) { + isl_aff_free(aff2); + return aff1; + } + if (isl_aff_is_nan(aff2)) { + isl_aff_free(aff1); + return aff2; + } + + is_cst = isl_aff_is_cst(aff2); + if (is_cst < 0) + goto error; + if (!is_cst) + isl_die(isl_aff_get_ctx(aff2), isl_error_invalid, + "second argument should be a constant", goto error); + + if (!aff2) + goto error; + + neg = isl_int_is_neg(aff2->v->el[1]); + if (neg) { + isl_int_neg(aff2->v->el[0], aff2->v->el[0]); + isl_int_neg(aff2->v->el[1], aff2->v->el[1]); + } + + aff1 = isl_aff_scale(aff1, aff2->v->el[0]); + aff1 = isl_aff_scale_down(aff1, aff2->v->el[1]); + + if (neg) { + isl_int_neg(aff2->v->el[0], aff2->v->el[0]); + isl_int_neg(aff2->v->el[1], aff2->v->el[1]); + } + + isl_aff_free(aff2); + return aff1; +error: + isl_aff_free(aff1); + isl_aff_free(aff2); + return NULL; +} + +static __isl_give isl_pw_aff *pw_aff_add(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_add); +} + +__isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, &pw_aff_add); +} + +__isl_give isl_pw_aff *isl_pw_aff_union_add(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_union_add_(pwaff1, pwaff2); +} + +static __isl_give isl_pw_aff *pw_aff_mul(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_mul); +} + +__isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, &pw_aff_mul); +} + +static __isl_give isl_pw_aff *pw_aff_div(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return isl_pw_aff_on_shared_domain(pa1, pa2, &isl_aff_div); +} + +/* Divide "pa1" by "pa2", assuming "pa2" is a piecewise constant. + */ +__isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + int is_cst; + + is_cst = isl_pw_aff_is_cst(pa2); + if (is_cst < 0) + goto error; + if (!is_cst) + isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid, + "second argument should be a piecewise constant", + goto error); + return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_div); +error: + isl_pw_aff_free(pa1); + isl_pw_aff_free(pa2); + return NULL; +} + +/* Compute the quotient of the integer division of "pa1" by "pa2" + * with rounding towards zero. + * "pa2" is assumed to be a piecewise constant. + * + * In particular, return + * + * pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2) + * + */ +__isl_give isl_pw_aff *isl_pw_aff_tdiv_q(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + int is_cst; + isl_set *cond; + isl_pw_aff *f, *c; + + is_cst = isl_pw_aff_is_cst(pa2); + if (is_cst < 0) + goto error; + if (!is_cst) + isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid, + "second argument should be a piecewise constant", + goto error); + + pa1 = isl_pw_aff_div(pa1, pa2); + + cond = isl_pw_aff_nonneg_set(isl_pw_aff_copy(pa1)); + f = isl_pw_aff_floor(isl_pw_aff_copy(pa1)); + c = isl_pw_aff_ceil(pa1); + return isl_pw_aff_cond(isl_set_indicator_function(cond), f, c); +error: + isl_pw_aff_free(pa1); + isl_pw_aff_free(pa2); + return NULL; +} + +/* Compute the remainder of the integer division of "pa1" by "pa2" + * with rounding towards zero. + * "pa2" is assumed to be a piecewise constant. + * + * In particular, return + * + * pa1 - pa2 * (pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2)) + * + */ +__isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + int is_cst; + isl_pw_aff *res; + + is_cst = isl_pw_aff_is_cst(pa2); + if (is_cst < 0) + goto error; + if (!is_cst) + isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid, + "second argument should be a piecewise constant", + goto error); + res = isl_pw_aff_tdiv_q(isl_pw_aff_copy(pa1), isl_pw_aff_copy(pa2)); + res = isl_pw_aff_mul(pa2, res); + res = isl_pw_aff_sub(pa1, res); + return res; +error: + isl_pw_aff_free(pa1); + isl_pw_aff_free(pa2); + return NULL; +} + +/* Does either of "pa1" or "pa2" involve any NaN2? + */ +static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1, + __isl_keep isl_pw_aff *pa2) +{ + isl_bool has_nan; + + has_nan = isl_pw_aff_involves_nan(pa1); + if (has_nan < 0 || has_nan) + return has_nan; + return isl_pw_aff_involves_nan(pa2); +} + +/* Replace "pa1" and "pa2" (at least one of which involves a NaN) + * by a NaN on their shared domain. + * + * In principle, the result could be refined to only being NaN + * on the parts of this domain where at least one of "pa1" or "pa2" is NaN. + */ +static __isl_give isl_pw_aff *replace_by_nan(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + isl_local_space *ls; + isl_set *dom; + isl_pw_aff *pa; + + dom = isl_set_intersect(isl_pw_aff_domain(pa1), isl_pw_aff_domain(pa2)); + ls = isl_local_space_from_space(isl_set_get_space(dom)); + pa = isl_pw_aff_nan_on_domain(ls); + pa = isl_pw_aff_intersect_domain(pa, dom); + + return pa; +} + +static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + isl_set *le; + isl_set *dom; + + dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)), + isl_pw_aff_domain(isl_pw_aff_copy(pwaff2))); + le = isl_pw_aff_le_set(isl_pw_aff_copy(pwaff1), + isl_pw_aff_copy(pwaff2)); + dom = isl_set_subtract(dom, isl_set_copy(le)); + return isl_pw_aff_select(le, pwaff1, dom, pwaff2); +} + +static __isl_give isl_pw_aff *pw_aff_max(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + isl_set *ge; + isl_set *dom; + + dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)), + isl_pw_aff_domain(isl_pw_aff_copy(pwaff2))); + ge = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1), + isl_pw_aff_copy(pwaff2)); + dom = isl_set_subtract(dom, isl_set_copy(ge)); + return isl_pw_aff_select(ge, pwaff1, dom, pwaff2); +} + +/* Return an expression for the minimum (if "max" is not set) or + * the maximum (if "max" is set) of "pa1" and "pa2". + * If either expression involves any NaN, then return a NaN + * on the shared domain as result. + */ +static __isl_give isl_pw_aff *pw_aff_min_max(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2, int max) +{ + isl_bool has_nan; + + has_nan = either_involves_nan(pa1, pa2); + if (has_nan < 0) + pa1 = isl_pw_aff_free(pa1); + else if (has_nan) + return replace_by_nan(pa1, pa2); + + if (max) + return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_max); + else + return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_min); +} + +/* Return an expression for the minimum of "pwaff1" and "pwaff2". + */ +__isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return pw_aff_min_max(pwaff1, pwaff2, 0); +} + +/* Return an expression for the maximum of "pwaff1" and "pwaff2". + */ +__isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2) +{ + return pw_aff_min_max(pwaff1, pwaff2, 1); +} + +static __isl_give isl_pw_aff *pw_aff_list_reduce( + __isl_take isl_pw_aff_list *list, + __isl_give isl_pw_aff *(*fn)(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2)) +{ + int i; + isl_ctx *ctx; + isl_pw_aff *res; + + if (!list) + return NULL; + + ctx = isl_pw_aff_list_get_ctx(list); + if (list->n < 1) + isl_die(ctx, isl_error_invalid, + "list should contain at least one element", goto error); + + res = isl_pw_aff_copy(list->p[0]); + for (i = 1; i < list->n; ++i) + res = fn(res, isl_pw_aff_copy(list->p[i])); + + isl_pw_aff_list_free(list); + return res; +error: + isl_pw_aff_list_free(list); + return NULL; +} + +/* Return an isl_pw_aff that maps each element in the intersection of the + * domains of the elements of list to the minimal corresponding affine + * expression. + */ +__isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list) +{ + return pw_aff_list_reduce(list, &isl_pw_aff_min); +} + +/* Return an isl_pw_aff that maps each element in the intersection of the + * domains of the elements of list to the maximal corresponding affine + * expression. + */ +__isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list) +{ + return pw_aff_list_reduce(list, &isl_pw_aff_max); +} + +/* Mark the domains of "pwaff" as rational. + */ +__isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff) +{ + int i; + + pwaff = isl_pw_aff_cow(pwaff); + if (!pwaff) + return NULL; + if (pwaff->n == 0) + return pwaff; + + for (i = 0; i < pwaff->n; ++i) { + pwaff->p[i].set = isl_set_set_rational(pwaff->p[i].set); + if (!pwaff->p[i].set) + return isl_pw_aff_free(pwaff); + } + + return pwaff; +} + +/* Mark the domains of the elements of "list" as rational. + */ +__isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational( + __isl_take isl_pw_aff_list *list) +{ + int i, n; + + if (!list) + return NULL; + if (list->n == 0) + return list; + + n = list->n; + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + + pa = isl_pw_aff_list_get_pw_aff(list, i); + pa = isl_pw_aff_set_rational(pa); + list = isl_pw_aff_list_set_pw_aff(list, i, pa); + } + + return list; +} + +/* Do the parameters of "aff" match those of "space"? + */ +isl_bool isl_aff_matching_params(__isl_keep isl_aff *aff, + __isl_keep isl_space *space) +{ + isl_space *aff_space; + isl_bool match; + + if (!aff || !space) + return isl_bool_error; + + aff_space = isl_aff_get_domain_space(aff); + + match = isl_space_has_equal_params(space, aff_space); + + isl_space_free(aff_space); + return match; +} + +/* Check that the domain space of "aff" matches "space". + */ +isl_stat isl_aff_check_match_domain_space(__isl_keep isl_aff *aff, + __isl_keep isl_space *space) +{ + isl_space *aff_space; + isl_bool match; + + if (!aff || !space) + return isl_stat_error; + + aff_space = isl_aff_get_domain_space(aff); + + match = isl_space_has_equal_params(space, aff_space); + if (match < 0) + goto error; + if (!match) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "parameters don't match", goto error); + match = isl_space_tuple_is_equal(space, isl_dim_in, + aff_space, isl_dim_set); + if (match < 0) + goto error; + if (!match) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "domains don't match", goto error); + isl_space_free(aff_space); + return isl_stat_ok; +error: + isl_space_free(aff_space); + return isl_stat_error; +} + +#undef BASE +#define BASE aff +#undef DOMBASE +#define DOMBASE set +#define NO_DOMAIN + +#include +#include +#include +#include +#include + +#undef NO_DOMAIN + +/* Construct an isl_multi_aff living in "space" that corresponds + * to the affine transformation matrix "mat". + */ +__isl_give isl_multi_aff *isl_multi_aff_from_aff_mat( + __isl_take isl_space *space, __isl_take isl_mat *mat) +{ + isl_ctx *ctx; + isl_local_space *ls = NULL; + isl_multi_aff *ma = NULL; + int n_row, n_col, n_out, total; + int i; + + if (!space || !mat) + goto error; + + ctx = isl_mat_get_ctx(mat); + + n_row = isl_mat_rows(mat); + n_col = isl_mat_cols(mat); + if (n_row < 1) + isl_die(ctx, isl_error_invalid, + "insufficient number of rows", goto error); + if (n_col < 1) + isl_die(ctx, isl_error_invalid, + "insufficient number of columns", goto error); + n_out = isl_space_dim(space, isl_dim_out); + total = isl_space_dim(space, isl_dim_all); + if (1 + n_out != n_row || 2 + total != n_row + n_col) + isl_die(ctx, isl_error_invalid, + "dimension mismatch", goto error); + + ma = isl_multi_aff_zero(isl_space_copy(space)); + ls = isl_local_space_from_space(isl_space_domain(space)); + + for (i = 0; i < n_row - 1; ++i) { + isl_vec *v; + isl_aff *aff; + + v = isl_vec_alloc(ctx, 1 + n_col); + if (!v) + goto error; + isl_int_set(v->el[0], mat->row[0][0]); + isl_seq_cpy(v->el + 1, mat->row[1 + i], n_col); + v = isl_vec_normalize(v); + aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + + isl_local_space_free(ls); + isl_mat_free(mat); + return ma; +error: + isl_local_space_free(ls); + isl_mat_free(mat); + isl_multi_aff_free(ma); + return NULL; +} + +/* Remove any internal structure of the domain of "ma". + * If there is any such internal structure in the input, + * then the name of the corresponding space is also removed. + */ +__isl_give isl_multi_aff *isl_multi_aff_flatten_domain( + __isl_take isl_multi_aff *ma) +{ + isl_space *space; + + if (!ma) + return NULL; + + if (!ma->space->nested[0]) + return ma; + + space = isl_multi_aff_get_space(ma); + space = isl_space_flatten_domain(space); + ma = isl_multi_aff_reset_space(ma, space); + + return ma; +} + +/* Given a map space, return an isl_multi_aff that maps a wrapped copy + * of the space to its domain. + */ +__isl_give isl_multi_aff *isl_multi_aff_domain_map(__isl_take isl_space *space) +{ + int i, n_in; + isl_local_space *ls; + isl_multi_aff *ma; + + if (!space) + return NULL; + if (!isl_space_is_map(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "not a map space", goto error); + + n_in = isl_space_dim(space, isl_dim_in); + space = isl_space_domain_map(space); + + ma = isl_multi_aff_alloc(isl_space_copy(space)); + if (n_in == 0) { + isl_space_free(space); + return ma; + } + + space = isl_space_domain(space); + ls = isl_local_space_from_space(space); + for (i = 0; i < n_in; ++i) { + isl_aff *aff; + + aff = isl_aff_var_on_domain(isl_local_space_copy(ls), + isl_dim_set, i); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + isl_local_space_free(ls); + return ma; +error: + isl_space_free(space); + return NULL; +} + +/* Given a map space, return an isl_multi_aff that maps a wrapped copy + * of the space to its range. + */ +__isl_give isl_multi_aff *isl_multi_aff_range_map(__isl_take isl_space *space) +{ + int i, n_in, n_out; + isl_local_space *ls; + isl_multi_aff *ma; + + if (!space) + return NULL; + if (!isl_space_is_map(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "not a map space", goto error); + + n_in = isl_space_dim(space, isl_dim_in); + n_out = isl_space_dim(space, isl_dim_out); + space = isl_space_range_map(space); + + ma = isl_multi_aff_alloc(isl_space_copy(space)); + if (n_out == 0) { + isl_space_free(space); + return ma; + } + + space = isl_space_domain(space); + ls = isl_local_space_from_space(space); + for (i = 0; i < n_out; ++i) { + isl_aff *aff; + + aff = isl_aff_var_on_domain(isl_local_space_copy(ls), + isl_dim_set, n_in + i); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + isl_local_space_free(ls); + return ma; +error: + isl_space_free(space); + return NULL; +} + +/* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy + * of the space to its range. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map( + __isl_take isl_space *space) +{ + return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_range_map(space)); +} + +/* Given the space of a set and a range of set dimensions, + * construct an isl_multi_aff that projects out those dimensions. + */ +__isl_give isl_multi_aff *isl_multi_aff_project_out_map( + __isl_take isl_space *space, enum isl_dim_type type, + unsigned first, unsigned n) +{ + int i, dim; + isl_local_space *ls; + isl_multi_aff *ma; + + if (!space) + return NULL; + if (!isl_space_is_set(space)) + isl_die(isl_space_get_ctx(space), isl_error_unsupported, + "expecting set space", goto error); + if (type != isl_dim_set) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "only set dimensions can be projected out", goto error); + + dim = isl_space_dim(space, isl_dim_set); + if (first + n > dim) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "range out of bounds", goto error); + + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, dim - n); + + if (dim == n) + return isl_multi_aff_alloc(space); + + ma = isl_multi_aff_alloc(isl_space_copy(space)); + space = isl_space_domain(space); + ls = isl_local_space_from_space(space); + + for (i = 0; i < first; ++i) { + isl_aff *aff; + + aff = isl_aff_var_on_domain(isl_local_space_copy(ls), + isl_dim_set, i); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + + for (i = 0; i < dim - (first + n); ++i) { + isl_aff *aff; + + aff = isl_aff_var_on_domain(isl_local_space_copy(ls), + isl_dim_set, first + n + i); + ma = isl_multi_aff_set_aff(ma, first + i, aff); + } + + isl_local_space_free(ls); + return ma; +error: + isl_space_free(space); + return NULL; +} + +/* Given the space of a set and a range of set dimensions, + * construct an isl_pw_multi_aff that projects out those dimensions. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map( + __isl_take isl_space *space, enum isl_dim_type type, + unsigned first, unsigned n) +{ + isl_multi_aff *ma; + + ma = isl_multi_aff_project_out_map(space, type, first, n); + return isl_pw_multi_aff_from_multi_aff(ma); +} + +/* Create an isl_pw_multi_aff with the given isl_multi_aff on a universe + * domain. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff( + __isl_take isl_multi_aff *ma) +{ + isl_set *dom = isl_set_universe(isl_multi_aff_get_domain_space(ma)); + return isl_pw_multi_aff_alloc(dom, ma); +} + +/* Create a piecewise multi-affine expression in the given space that maps each + * input dimension to the corresponding output dimension. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity( + __isl_take isl_space *space) +{ + return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_identity(space)); +} + +/* Exploit the equalities in "eq" to simplify the affine expressions. + */ +static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities( + __isl_take isl_multi_aff *maff, __isl_take isl_basic_set *eq) +{ + int i; + + maff = isl_multi_aff_cow(maff); + if (!maff || !eq) + goto error; + + for (i = 0; i < maff->n; ++i) { + maff->p[i] = isl_aff_substitute_equalities(maff->p[i], + isl_basic_set_copy(eq)); + if (!maff->p[i]) + goto error; + } + + isl_basic_set_free(eq); + return maff; +error: + isl_basic_set_free(eq); + isl_multi_aff_free(maff); + return NULL; +} + +__isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff, + isl_int f) +{ + int i; + + maff = isl_multi_aff_cow(maff); + if (!maff) + return NULL; + + for (i = 0; i < maff->n; ++i) { + maff->p[i] = isl_aff_scale(maff->p[i], f); + if (!maff->p[i]) + return isl_multi_aff_free(maff); + } + + return maff; +} + +__isl_give isl_multi_aff *isl_multi_aff_add_on_domain(__isl_keep isl_set *dom, + __isl_take isl_multi_aff *maff1, __isl_take isl_multi_aff *maff2) +{ + maff1 = isl_multi_aff_add(maff1, maff2); + maff1 = isl_multi_aff_gist(maff1, isl_set_copy(dom)); + return maff1; +} + +int isl_multi_aff_is_empty(__isl_keep isl_multi_aff *maff) +{ + if (!maff) + return -1; + + return 0; +} + +/* Return the set of domain elements where "ma1" is lexicographically + * smaller than or equal to "ma2". + */ +__isl_give isl_set *isl_multi_aff_lex_le_set(__isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2) +{ + return isl_multi_aff_lex_ge_set(ma2, ma1); +} + +/* Return the set of domain elements where "ma1" is lexicographically + * smaller than "ma2". + */ +__isl_give isl_set *isl_multi_aff_lex_lt_set(__isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2) +{ + return isl_multi_aff_lex_gt_set(ma2, ma1); +} + +/* Return the set of domain elements where "ma1" and "ma2" + * satisfy "order". + */ +static __isl_give isl_set *isl_multi_aff_order_set( + __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2, + __isl_give isl_map *order(__isl_take isl_space *set_space)) +{ + isl_space *space; + isl_map *map1, *map2; + isl_map *map, *ge; + + map1 = isl_map_from_multi_aff(ma1); + map2 = isl_map_from_multi_aff(ma2); + map = isl_map_range_product(map1, map2); + space = isl_space_range(isl_map_get_space(map)); + space = isl_space_domain(isl_space_unwrap(space)); + ge = order(space); + map = isl_map_intersect_range(map, isl_map_wrap(ge)); + + return isl_map_domain(map); +} + +/* Return the set of domain elements where "ma1" is lexicographically + * greater than or equal to "ma2". + */ +__isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2) +{ + return isl_multi_aff_order_set(ma1, ma2, &isl_map_lex_ge); +} + +/* Return the set of domain elements where "ma1" is lexicographically + * greater than "ma2". + */ +__isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1, + __isl_take isl_multi_aff *ma2) +{ + return isl_multi_aff_order_set(ma1, ma2, &isl_map_lex_gt); +} + +#undef PW +#define PW isl_pw_multi_aff +#undef EL +#define EL isl_multi_aff +#undef EL_IS_ZERO +#define EL_IS_ZERO is_empty +#undef ZERO +#define ZERO empty +#undef IS_ZERO +#define IS_ZERO is_empty +#undef FIELD +#define FIELD maff +#undef DEFAULT_IS_ZERO +#define DEFAULT_IS_ZERO 0 + +#define NO_SUB +#define NO_EVAL +#define NO_OPT +#define NO_INVOLVES_DIMS +#define NO_INSERT_DIMS +#define NO_LIFT +#define NO_MORPH + +#include +#include + +#undef NO_SUB + +#undef UNION +#define UNION isl_union_pw_multi_aff +#undef PART +#define PART isl_pw_multi_aff +#undef PARTS +#define PARTS pw_multi_aff + +#include +#include + +static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmax( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_union_opt_cmp(pma1, pma2, + &isl_multi_aff_lex_ge_set); +} + +/* Given two piecewise multi affine expressions, return a piecewise + * multi-affine expression defined on the union of the definition domains + * of the inputs that is equal to the lexicographic maximum of the two + * inputs on each cell. If only one of the two inputs is defined on + * a given cell, then it is considered to be the maximum. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, + &pw_multi_aff_union_lexmax); +} + +static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmin( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_union_opt_cmp(pma1, pma2, + &isl_multi_aff_lex_le_set); +} + +/* Given two piecewise multi affine expressions, return a piecewise + * multi-affine expression defined on the union of the definition domains + * of the inputs that is equal to the lexicographic minimum of the two + * inputs on each cell. If only one of the two inputs is defined on + * a given cell, then it is considered to be the minimum. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin( + __isl_take isl_pw_multi_aff *pma1, + __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, + &pw_multi_aff_union_lexmin); +} + +static __isl_give isl_pw_multi_aff *pw_multi_aff_add( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_on_shared_domain(pma1, pma2, + &isl_multi_aff_add); +} + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_add( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, + &pw_multi_aff_add); +} + +static __isl_give isl_pw_multi_aff *pw_multi_aff_sub( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_on_shared_domain(pma1, pma2, + &isl_multi_aff_sub); +} + +/* Subtract "pma2" from "pma1" and return the result. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, + &pw_multi_aff_sub); +} + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_union_add_(pma1, pma2); +} + +/* Compute the sum of "upa1" and "upa2" on the union of their domains, + * with the actual sum on the shared domain and + * the defined expression on the symmetric difference of the domains. + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_union_add( + __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2) +{ + return isl_union_pw_aff_union_add_(upa1, upa2); +} + +/* Compute the sum of "upma1" and "upma2" on the union of their domains, + * with the actual sum on the shared domain and + * the defined expression on the symmetric difference of the domains. + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_union_add( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2) +{ + return isl_union_pw_multi_aff_union_add_(upma1, upma2); +} + +/* Given two piecewise multi-affine expressions A -> B and C -> D, + * construct a piecewise multi-affine expression [A -> C] -> [B -> D]. + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + int i, j, n; + isl_space *space; + isl_pw_multi_aff *res; + + if (!pma1 || !pma2) + goto error; + + n = pma1->n * pma2->n; + space = isl_space_product(isl_space_copy(pma1->dim), + isl_space_copy(pma2->dim)); + res = isl_pw_multi_aff_alloc_size(space, n); + + for (i = 0; i < pma1->n; ++i) { + for (j = 0; j < pma2->n; ++j) { + isl_set *domain; + isl_multi_aff *ma; + + domain = isl_set_product(isl_set_copy(pma1->p[i].set), + isl_set_copy(pma2->p[j].set)); + ma = isl_multi_aff_product( + isl_multi_aff_copy(pma1->p[i].maff), + isl_multi_aff_copy(pma2->p[j].maff)); + res = isl_pw_multi_aff_add_piece(res, domain, ma); + } + } + + isl_pw_multi_aff_free(pma1); + isl_pw_multi_aff_free(pma2); + return res; +error: + isl_pw_multi_aff_free(pma1); + isl_pw_multi_aff_free(pma2); + return NULL; +} + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, + &pw_multi_aff_product); +} + +/* Construct a map mapping the domain of the piecewise multi-affine expression + * to its range, with each dimension in the range equated to the + * corresponding affine expression on its cell. + * + * If the domain of "pma" is rational, then so is the constructed "map". + */ +__isl_give isl_map *isl_map_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma) +{ + int i; + isl_map *map; + + if (!pma) + return NULL; + + map = isl_map_empty(isl_pw_multi_aff_get_space(pma)); + + for (i = 0; i < pma->n; ++i) { + isl_bool rational; + isl_multi_aff *maff; + isl_basic_map *bmap; + isl_map *map_i; + + rational = isl_set_is_rational(pma->p[i].set); + if (rational < 0) + map = isl_map_free(map); + maff = isl_multi_aff_copy(pma->p[i].maff); + bmap = isl_basic_map_from_multi_aff2(maff, rational); + map_i = isl_map_from_basic_map(bmap); + map_i = isl_map_intersect_domain(map_i, + isl_set_copy(pma->p[i].set)); + map = isl_map_union_disjoint(map, map_i); + } + + isl_pw_multi_aff_free(pma); + return map; +} + +__isl_give isl_set *isl_set_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma) +{ + if (!pma) + return NULL; + + if (!isl_space_is_set(pma->dim)) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "isl_pw_multi_aff cannot be converted into an isl_set", + goto error); + + return isl_map_from_pw_multi_aff(pma); +error: + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* Subtract the initial "n" elements in "ma" with coefficients in "c" and + * denominator "denom". + * "denom" is allowed to be negative, in which case the actual denominator + * is -denom and the expressions are added instead. + */ +static __isl_give isl_aff *subtract_initial(__isl_take isl_aff *aff, + __isl_keep isl_multi_aff *ma, int n, isl_int *c, isl_int denom) +{ + int i, first; + int sign; + isl_int d; + + first = isl_seq_first_non_zero(c, n); + if (first == -1) + return aff; + + sign = isl_int_sgn(denom); + isl_int_init(d); + isl_int_abs(d, denom); + for (i = first; i < n; ++i) { + isl_aff *aff_i; + + if (isl_int_is_zero(c[i])) + continue; + aff_i = isl_multi_aff_get_aff(ma, i); + aff_i = isl_aff_scale(aff_i, c[i]); + aff_i = isl_aff_scale_down(aff_i, d); + if (sign >= 0) + aff = isl_aff_sub(aff, aff_i); + else + aff = isl_aff_add(aff, aff_i); + } + isl_int_clear(d); + + return aff; +} + +/* Extract an affine expression that expresses the output dimension "pos" + * of "bmap" in terms of the parameters and input dimensions from + * equality "eq". + * Note that this expression may involve integer divisions defined + * in terms of parameters and input dimensions. + * The equality may also involve references to earlier (but not later) + * output dimensions. These are replaced by the corresponding elements + * in "ma". + * + * If the equality is of the form + * + * f(i) + h(j) + a x + g(i) = 0, + * + * with f(i) a linear combinations of the parameters and input dimensions, + * g(i) a linear combination of integer divisions defined in terms of the same + * and h(j) a linear combinations of earlier output dimensions, + * then the affine expression is + * + * (-f(i) - g(i))/a - h(j)/a + * + * If the equality is of the form + * + * f(i) + h(j) - a x + g(i) = 0, + * + * then the affine expression is + * + * (f(i) + g(i))/a - h(j)/(-a) + * + * + * If "div" refers to an integer division (i.e., it is smaller than + * the number of integer divisions), then the equality constraint + * does involve an integer division (the one at position "div") that + * is defined in terms of output dimensions. However, this integer + * division can be eliminated by exploiting a pair of constraints + * x >= l and x <= l + n, with n smaller than the coefficient of "div" + * in the equality constraint. "ineq" refers to inequality x >= l, i.e., + * -l + x >= 0. + * In particular, let + * + * x = e(i) + m floor(...) + * + * with e(i) the expression derived above and floor(...) the integer + * division involving output dimensions. + * From + * + * l <= x <= l + n, + * + * we have + * + * 0 <= x - l <= n + * + * This means + * + * e(i) + m floor(...) - l = (e(i) + m floor(...) - l) mod m + * = (e(i) - l) mod m + * + * Therefore, + * + * x - l = (e(i) - l) mod m + * + * or + * + * x = ((e(i) - l) mod m) + l + * + * The variable "shift" below contains the expression -l, which may + * also involve a linear combination of earlier output dimensions. + */ +static __isl_give isl_aff *extract_aff_from_equality( + __isl_keep isl_basic_map *bmap, int pos, int eq, int div, int ineq, + __isl_keep isl_multi_aff *ma) +{ + unsigned o_out; + unsigned n_div, n_out; + isl_ctx *ctx; + isl_local_space *ls; + isl_aff *aff, *shift; + isl_val *mod; + + ctx = isl_basic_map_get_ctx(bmap); + ls = isl_basic_map_get_local_space(bmap); + ls = isl_local_space_domain(ls); + aff = isl_aff_alloc(isl_local_space_copy(ls)); + if (!aff) + goto error; + o_out = isl_basic_map_offset(bmap, isl_dim_out); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + if (isl_int_is_neg(bmap->eq[eq][o_out + pos])) { + isl_seq_cpy(aff->v->el + 1, bmap->eq[eq], o_out); + isl_seq_cpy(aff->v->el + 1 + o_out, + bmap->eq[eq] + o_out + n_out, n_div); + } else { + isl_seq_neg(aff->v->el + 1, bmap->eq[eq], o_out); + isl_seq_neg(aff->v->el + 1 + o_out, + bmap->eq[eq] + o_out + n_out, n_div); + } + if (div < n_div) + isl_int_set_si(aff->v->el[1 + o_out + div], 0); + isl_int_abs(aff->v->el[0], bmap->eq[eq][o_out + pos]); + aff = subtract_initial(aff, ma, pos, bmap->eq[eq] + o_out, + bmap->eq[eq][o_out + pos]); + if (div < n_div) { + shift = isl_aff_alloc(isl_local_space_copy(ls)); + if (!shift) + goto error; + isl_seq_cpy(shift->v->el + 1, bmap->ineq[ineq], o_out); + isl_seq_cpy(shift->v->el + 1 + o_out, + bmap->ineq[ineq] + o_out + n_out, n_div); + isl_int_set_si(shift->v->el[0], 1); + shift = subtract_initial(shift, ma, pos, + bmap->ineq[ineq] + o_out, ctx->negone); + aff = isl_aff_add(aff, isl_aff_copy(shift)); + mod = isl_val_int_from_isl_int(ctx, + bmap->eq[eq][o_out + n_out + div]); + mod = isl_val_abs(mod); + aff = isl_aff_mod_val(aff, mod); + aff = isl_aff_sub(aff, shift); + } + + isl_local_space_free(ls); + return aff; +error: + isl_local_space_free(ls); + isl_aff_free(aff); + return NULL; +} + +/* Given a basic map with output dimensions defined + * in terms of the parameters input dimensions and earlier + * output dimensions using an equality (and possibly a pair on inequalities), + * extract an isl_aff that expresses output dimension "pos" in terms + * of the parameters and input dimensions. + * Note that this expression may involve integer divisions defined + * in terms of parameters and input dimensions. + * "ma" contains the expressions corresponding to earlier output dimensions. + * + * This function shares some similarities with + * isl_basic_map_has_defining_equality and isl_constraint_get_bound. + */ +static __isl_give isl_aff *extract_isl_aff_from_basic_map( + __isl_keep isl_basic_map *bmap, int pos, __isl_keep isl_multi_aff *ma) +{ + int eq, div, ineq; + isl_aff *aff; + + if (!bmap) + return NULL; + eq = isl_basic_map_output_defining_equality(bmap, pos, &div, &ineq); + if (eq >= bmap->n_eq) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "unable to find suitable equality", return NULL); + aff = extract_aff_from_equality(bmap, pos, eq, div, ineq, ma); + + aff = isl_aff_remove_unused_divs(aff); + return aff; +} + +/* Given a basic map where each output dimension is defined + * in terms of the parameters and input dimensions using an equality, + * extract an isl_multi_aff that expresses the output dimensions in terms + * of the parameters and input dimensions. + */ +static __isl_give isl_multi_aff *extract_isl_multi_aff_from_basic_map( + __isl_take isl_basic_map *bmap) +{ + int i; + unsigned n_out; + isl_multi_aff *ma; + + if (!bmap) + return NULL; + + ma = isl_multi_aff_alloc(isl_basic_map_get_space(bmap)); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + + for (i = 0; i < n_out; ++i) { + isl_aff *aff; + + aff = extract_isl_aff_from_basic_map(bmap, i, ma); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + + isl_basic_map_free(bmap); + + return ma; +} + +/* Given a basic set where each set dimension is defined + * in terms of the parameters using an equality, + * extract an isl_multi_aff that expresses the set dimensions in terms + * of the parameters. + */ +__isl_give isl_multi_aff *isl_multi_aff_from_basic_set_equalities( + __isl_take isl_basic_set *bset) +{ + return extract_isl_multi_aff_from_basic_map(bset); +} + +/* Create an isl_pw_multi_aff that is equivalent to + * isl_map_intersect_domain(isl_map_from_basic_map(bmap), domain). + * The given basic map is such that each output dimension is defined + * in terms of the parameters and input dimensions using an equality. + * + * Since some applications expect the result of isl_pw_multi_aff_from_map + * to only contain integer affine expressions, we compute the floor + * of the expression before returning. + * + * Remove all constraints involving local variables without + * an explicit representation (resulting in the removal of those + * local variables) prior to the actual extraction to ensure + * that the local spaces in which the resulting affine expressions + * are created do not contain any unknown local variables. + * Removing such constraints is safe because constraints involving + * unknown local variables are not used to determine whether + * a basic map is obviously single-valued. + */ +static __isl_give isl_pw_multi_aff *plain_pw_multi_aff_from_map( + __isl_take isl_set *domain, __isl_take isl_basic_map *bmap) +{ + isl_multi_aff *ma; + + bmap = isl_basic_map_drop_constraint_involving_unknown_divs(bmap); + ma = extract_isl_multi_aff_from_basic_map(bmap); + ma = isl_multi_aff_floor(ma); + return isl_pw_multi_aff_alloc(domain, ma); +} + +/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. + * This obviously only works if the input "map" is single-valued. + * If so, we compute the lexicographic minimum of the image in the form + * of an isl_pw_multi_aff. Since the image is unique, it is equal + * to its lexicographic minimum. + * If the input is not single-valued, we produce an error. + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_base( + __isl_take isl_map *map) +{ + int i; + int sv; + isl_pw_multi_aff *pma; + + sv = isl_map_is_single_valued(map); + if (sv < 0) + goto error; + if (!sv) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "map is not single-valued", goto error); + map = isl_map_make_disjoint(map); + if (!map) + return NULL; + + pma = isl_pw_multi_aff_empty(isl_map_get_space(map)); + + for (i = 0; i < map->n; ++i) { + isl_pw_multi_aff *pma_i; + isl_basic_map *bmap; + bmap = isl_basic_map_copy(map->p[i]); + pma_i = isl_basic_map_lexmin_pw_multi_aff(bmap); + pma = isl_pw_multi_aff_add_disjoint(pma, pma_i); + } + + isl_map_free(map); + return pma; +error: + isl_map_free(map); + return NULL; +} + +/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map, + * taking into account that the output dimension at position "d" + * can be represented as + * + * x = floor((e(...) + c1) / m) + * + * given that constraint "i" is of the form + * + * e(...) + c1 - m x >= 0 + * + * + * Let "map" be of the form + * + * A -> B + * + * We construct a mapping + * + * A -> [A -> x = floor(...)] + * + * apply that to the map, obtaining + * + * [A -> x = floor(...)] -> B + * + * and equate dimension "d" to x. + * We then compute a isl_pw_multi_aff representation of the resulting map + * and plug in the mapping above. + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_div( + __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i) +{ + isl_ctx *ctx; + isl_space *space; + isl_local_space *ls; + isl_multi_aff *ma; + isl_aff *aff; + isl_vec *v; + isl_map *insert; + int offset; + int n; + int n_in; + isl_pw_multi_aff *pma; + isl_bool is_set; + + is_set = isl_map_is_set(map); + if (is_set < 0) + goto error; + + offset = isl_basic_map_offset(hull, isl_dim_out); + ctx = isl_map_get_ctx(map); + space = isl_space_domain(isl_map_get_space(map)); + n_in = isl_space_dim(space, isl_dim_set); + n = isl_space_dim(space, isl_dim_all); + + v = isl_vec_alloc(ctx, 1 + 1 + n); + if (v) { + isl_int_neg(v->el[0], hull->ineq[i][offset + d]); + isl_seq_cpy(v->el + 1, hull->ineq[i], 1 + n); + } + isl_basic_map_free(hull); + + ls = isl_local_space_from_space(isl_space_copy(space)); + aff = isl_aff_alloc_vec(ls, v); + aff = isl_aff_floor(aff); + if (is_set) { + isl_space_free(space); + ma = isl_multi_aff_from_aff(aff); + } else { + ma = isl_multi_aff_identity(isl_space_map_from_set(space)); + ma = isl_multi_aff_range_product(ma, + isl_multi_aff_from_aff(aff)); + } + + insert = isl_map_from_multi_aff(isl_multi_aff_copy(ma)); + map = isl_map_apply_domain(map, insert); + map = isl_map_equate(map, isl_dim_in, n_in, isl_dim_out, d); + pma = isl_pw_multi_aff_from_map(map); + pma = isl_pw_multi_aff_pullback_multi_aff(pma, ma); + + return pma; +error: + isl_map_free(map); + isl_basic_map_free(hull); + return NULL; +} + +/* Is constraint "c" of the form + * + * e(...) + c1 - m x >= 0 + * + * or + * + * -e(...) + c2 + m x >= 0 + * + * where m > 1 and e only depends on parameters and input dimemnsions? + * + * "offset" is the offset of the output dimensions + * "pos" is the position of output dimension x. + */ +static int is_potential_div_constraint(isl_int *c, int offset, int d, int total) +{ + if (isl_int_is_zero(c[offset + d])) + return 0; + if (isl_int_is_one(c[offset + d])) + return 0; + if (isl_int_is_negone(c[offset + d])) + return 0; + if (isl_seq_first_non_zero(c + offset, d) != -1) + return 0; + if (isl_seq_first_non_zero(c + offset + d + 1, + total - (offset + d + 1)) != -1) + return 0; + return 1; +} + +/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. + * + * As a special case, we first check if there is any pair of constraints, + * shared by all the basic maps in "map" that force a given dimension + * to be equal to the floor of some affine combination of the input dimensions. + * + * In particular, if we can find two constraints + * + * e(...) + c1 - m x >= 0 i.e., m x <= e(...) + c1 + * + * and + * + * -e(...) + c2 + m x >= 0 i.e., m x >= e(...) - c2 + * + * where m > 1 and e only depends on parameters and input dimemnsions, + * and such that + * + * c1 + c2 < m i.e., -c2 >= c1 - (m - 1) + * + * then we know that we can take + * + * x = floor((e(...) + c1) / m) + * + * without having to perform any computation. + * + * Note that we know that + * + * c1 + c2 >= 1 + * + * If c1 + c2 were 0, then we would have detected an equality during + * simplification. If c1 + c2 were negative, then we would have detected + * a contradiction. + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_div( + __isl_take isl_map *map) +{ + int d, dim; + int i, j, n; + int offset, total; + isl_int sum; + isl_basic_map *hull; + + hull = isl_map_unshifted_simple_hull(isl_map_copy(map)); + if (!hull) + goto error; + + isl_int_init(sum); + dim = isl_map_dim(map, isl_dim_out); + offset = isl_basic_map_offset(hull, isl_dim_out); + total = 1 + isl_basic_map_total_dim(hull); + n = hull->n_ineq; + for (d = 0; d < dim; ++d) { + for (i = 0; i < n; ++i) { + if (!is_potential_div_constraint(hull->ineq[i], + offset, d, total)) + continue; + for (j = i + 1; j < n; ++j) { + if (!isl_seq_is_neg(hull->ineq[i] + 1, + hull->ineq[j] + 1, total - 1)) + continue; + isl_int_add(sum, hull->ineq[i][0], + hull->ineq[j][0]); + if (isl_int_abs_lt(sum, + hull->ineq[i][offset + d])) + break; + + } + if (j >= n) + continue; + isl_int_clear(sum); + if (isl_int_is_pos(hull->ineq[j][offset + d])) + j = i; + return pw_multi_aff_from_map_div(map, hull, d, j); + } + } + isl_int_clear(sum); + isl_basic_map_free(hull); + return pw_multi_aff_from_map_base(map); +error: + isl_map_free(map); + isl_basic_map_free(hull); + return NULL; +} + +/* Given an affine expression + * + * [A -> B] -> f(A,B) + * + * construct an isl_multi_aff + * + * [A -> B] -> B' + * + * such that dimension "d" in B' is set to "aff" and the remaining + * dimensions are set equal to the corresponding dimensions in B. + * "n_in" is the dimension of the space A. + * "n_out" is the dimension of the space B. + * + * If "is_set" is set, then the affine expression is of the form + * + * [B] -> f(B) + * + * and we construct an isl_multi_aff + * + * B -> B' + */ +static __isl_give isl_multi_aff *range_map(__isl_take isl_aff *aff, int d, + unsigned n_in, unsigned n_out, int is_set) +{ + int i; + isl_multi_aff *ma; + isl_space *space, *space2; + isl_local_space *ls; + + space = isl_aff_get_domain_space(aff); + ls = isl_local_space_from_space(isl_space_copy(space)); + space2 = isl_space_copy(space); + if (!is_set) + space2 = isl_space_range(isl_space_unwrap(space2)); + space = isl_space_map_from_domain_and_range(space, space2); + ma = isl_multi_aff_alloc(space); + ma = isl_multi_aff_set_aff(ma, d, aff); + + for (i = 0; i < n_out; ++i) { + if (i == d) + continue; + aff = isl_aff_var_on_domain(isl_local_space_copy(ls), + isl_dim_set, n_in + i); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + + isl_local_space_free(ls); + + return ma; +} + +/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map, + * taking into account that the dimension at position "d" can be written as + * + * x = m a + f(..) (1) + * + * where m is equal to "gcd". + * "i" is the index of the equality in "hull" that defines f(..). + * In particular, the equality is of the form + * + * f(..) - x + m g(existentials) = 0 + * + * or + * + * -f(..) + x + m g(existentials) = 0 + * + * We basically plug (1) into "map", resulting in a map with "a" + * in the range instead of "x". The corresponding isl_pw_multi_aff + * defining "a" is then plugged back into (1) to obtain a definition for "x". + * + * Specifically, given the input map + * + * A -> B + * + * We first wrap it into a set + * + * [A -> B] + * + * and define (1) on top of the corresponding space, resulting in "aff". + * We use this to create an isl_multi_aff that maps the output position "d" + * from "a" to "x", leaving all other (intput and output) dimensions unchanged. + * We plug this into the wrapped map, unwrap the result and compute the + * corresponding isl_pw_multi_aff. + * The result is an expression + * + * A -> T(A) + * + * We adjust that to + * + * A -> [A -> T(A)] + * + * so that we can plug that into "aff", after extending the latter to + * a mapping + * + * [A -> B] -> B' + * + * + * If "map" is actually a set, then there is no "A" space, meaning + * that we do not need to perform any wrapping, and that the result + * of the recursive call is of the form + * + * [T] + * + * which is plugged into a mapping of the form + * + * B -> B' + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_stride( + __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i, + isl_int gcd) +{ + isl_set *set; + isl_space *space; + isl_local_space *ls; + isl_aff *aff; + isl_multi_aff *ma; + isl_pw_multi_aff *pma, *id; + unsigned n_in; + unsigned o_out; + unsigned n_out; + isl_bool is_set; + + is_set = isl_map_is_set(map); + if (is_set < 0) + goto error; + + n_in = isl_basic_map_dim(hull, isl_dim_in); + n_out = isl_basic_map_dim(hull, isl_dim_out); + o_out = isl_basic_map_offset(hull, isl_dim_out); + + if (is_set) + set = map; + else + set = isl_map_wrap(map); + space = isl_space_map_from_set(isl_set_get_space(set)); + ma = isl_multi_aff_identity(space); + ls = isl_local_space_from_space(isl_set_get_space(set)); + aff = isl_aff_alloc(ls); + if (aff) { + isl_int_set_si(aff->v->el[0], 1); + if (isl_int_is_one(hull->eq[i][o_out + d])) + isl_seq_neg(aff->v->el + 1, hull->eq[i], + aff->v->size - 1); + else + isl_seq_cpy(aff->v->el + 1, hull->eq[i], + aff->v->size - 1); + isl_int_set(aff->v->el[1 + o_out + d], gcd); + } + ma = isl_multi_aff_set_aff(ma, n_in + d, isl_aff_copy(aff)); + set = isl_set_preimage_multi_aff(set, ma); + + ma = range_map(aff, d, n_in, n_out, is_set); + + if (is_set) + map = set; + else + map = isl_set_unwrap(set); + pma = isl_pw_multi_aff_from_map(map); + + if (!is_set) { + space = isl_pw_multi_aff_get_domain_space(pma); + space = isl_space_map_from_set(space); + id = isl_pw_multi_aff_identity(space); + pma = isl_pw_multi_aff_range_product(id, pma); + } + id = isl_pw_multi_aff_from_multi_aff(ma); + pma = isl_pw_multi_aff_pullback_pw_multi_aff(id, pma); + + isl_basic_map_free(hull); + return pma; +error: + isl_map_free(map); + isl_basic_map_free(hull); + return NULL; +} + +/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. + * "hull" contains the equalities valid for "map". + * + * Check if any of the output dimensions is "strided". + * That is, we check if it can be written as + * + * x = m a + f(..) + * + * with m greater than 1, a some combination of existentially quantified + * variables and f an expression in the parameters and input dimensions. + * If so, we remove the stride in pw_multi_aff_from_map_stride. + * + * Otherwise, we continue with pw_multi_aff_from_map_check_div for a further + * special case. + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_strides( + __isl_take isl_map *map, __isl_take isl_basic_map *hull) +{ + int i, j; + unsigned n_out; + unsigned o_out; + unsigned n_div; + unsigned o_div; + isl_int gcd; + + n_div = isl_basic_map_dim(hull, isl_dim_div); + o_div = isl_basic_map_offset(hull, isl_dim_div); + + if (n_div == 0) { + isl_basic_map_free(hull); + return pw_multi_aff_from_map_check_div(map); + } + + isl_int_init(gcd); + + n_out = isl_basic_map_dim(hull, isl_dim_out); + o_out = isl_basic_map_offset(hull, isl_dim_out); + + for (i = 0; i < n_out; ++i) { + for (j = 0; j < hull->n_eq; ++j) { + isl_int *eq = hull->eq[j]; + isl_pw_multi_aff *res; + + if (!isl_int_is_one(eq[o_out + i]) && + !isl_int_is_negone(eq[o_out + i])) + continue; + if (isl_seq_first_non_zero(eq + o_out, i) != -1) + continue; + if (isl_seq_first_non_zero(eq + o_out + i + 1, + n_out - (i + 1)) != -1) + continue; + isl_seq_gcd(eq + o_div, n_div, &gcd); + if (isl_int_is_zero(gcd)) + continue; + if (isl_int_is_one(gcd)) + continue; + + res = pw_multi_aff_from_map_stride(map, hull, + i, j, gcd); + isl_int_clear(gcd); + return res; + } + } + + isl_int_clear(gcd); + isl_basic_map_free(hull); + return pw_multi_aff_from_map_check_div(map); +} + +/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. + * + * As a special case, we first check if all output dimensions are uniquely + * defined in terms of the parameters and input dimensions over the entire + * domain. If so, we extract the desired isl_pw_multi_aff directly + * from the affine hull of "map" and its domain. + * + * Otherwise, continue with pw_multi_aff_from_map_check_strides for more + * special cases. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map) +{ + isl_bool sv; + isl_basic_map *hull; + + if (!map) + return NULL; + + if (isl_map_n_basic_map(map) == 1) { + hull = isl_map_unshifted_simple_hull(isl_map_copy(map)); + hull = isl_basic_map_plain_affine_hull(hull); + sv = isl_basic_map_plain_is_single_valued(hull); + if (sv >= 0 && sv) + return plain_pw_multi_aff_from_map(isl_map_domain(map), + hull); + isl_basic_map_free(hull); + } + map = isl_map_detect_equalities(map); + hull = isl_map_unshifted_simple_hull(isl_map_copy(map)); + sv = isl_basic_map_plain_is_single_valued(hull); + if (sv >= 0 && sv) + return plain_pw_multi_aff_from_map(isl_map_domain(map), hull); + if (sv >= 0) + return pw_multi_aff_from_map_check_strides(map, hull); + isl_basic_map_free(hull); + isl_map_free(map); + return NULL; +} + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set) +{ + return isl_pw_multi_aff_from_map(set); +} + +/* Convert "map" into an isl_pw_multi_aff (if possible) and + * add it to *user. + */ +static isl_stat pw_multi_aff_from_map(__isl_take isl_map *map, void *user) +{ + isl_union_pw_multi_aff **upma = user; + isl_pw_multi_aff *pma; + + pma = isl_pw_multi_aff_from_map(map); + *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma); + + return *upma ? isl_stat_ok : isl_stat_error; +} + +/* Create an isl_union_pw_multi_aff with the given isl_aff on a universe + * domain. + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff( + __isl_take isl_aff *aff) +{ + isl_multi_aff *ma; + isl_pw_multi_aff *pma; + + ma = isl_multi_aff_from_aff(aff); + pma = isl_pw_multi_aff_from_multi_aff(ma); + return isl_union_pw_multi_aff_from_pw_multi_aff(pma); +} + +/* Try and create an isl_union_pw_multi_aff that is equivalent + * to the given isl_union_map. + * The isl_union_map is required to be single-valued in each space. + * Otherwise, an error is produced. + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map( + __isl_take isl_union_map *umap) +{ + isl_space *space; + isl_union_pw_multi_aff *upma; + + space = isl_union_map_get_space(umap); + upma = isl_union_pw_multi_aff_empty(space); + if (isl_union_map_foreach_map(umap, &pw_multi_aff_from_map, &upma) < 0) + upma = isl_union_pw_multi_aff_free(upma); + isl_union_map_free(umap); + + return upma; +} + +/* Try and create an isl_union_pw_multi_aff that is equivalent + * to the given isl_union_set. + * The isl_union_set is required to be a singleton in each space. + * Otherwise, an error is produced. + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set( + __isl_take isl_union_set *uset) +{ + return isl_union_pw_multi_aff_from_union_map(uset); +} + +/* Return the piecewise affine expression "set ? 1 : 0". + */ +__isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set) +{ + isl_pw_aff *pa; + isl_space *space = isl_set_get_space(set); + isl_local_space *ls = isl_local_space_from_space(space); + isl_aff *zero = isl_aff_zero_on_domain(isl_local_space_copy(ls)); + isl_aff *one = isl_aff_zero_on_domain(ls); + + one = isl_aff_add_constant_si(one, 1); + pa = isl_pw_aff_alloc(isl_set_copy(set), one); + set = isl_set_complement(set); + pa = isl_pw_aff_add_disjoint(pa, isl_pw_aff_alloc(set, zero)); + + return pa; +} + +/* Plug in "subs" for dimension "type", "pos" of "aff". + * + * Let i be the dimension to replace and let "subs" be of the form + * + * f/d + * + * and "aff" of the form + * + * (a i + g)/m + * + * The result is + * + * (a f + d g')/(m d) + * + * where g' is the result of plugging in "subs" in each of the integer + * divisions in g. + */ +__isl_give isl_aff *isl_aff_substitute(__isl_take isl_aff *aff, + enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) +{ + isl_ctx *ctx; + isl_int v; + + aff = isl_aff_cow(aff); + if (!aff || !subs) + return isl_aff_free(aff); + + ctx = isl_aff_get_ctx(aff); + if (!isl_space_is_equal(aff->ls->dim, subs->ls->dim)) + isl_die(ctx, isl_error_invalid, + "spaces don't match", return isl_aff_free(aff)); + if (isl_local_space_dim(subs->ls, isl_dim_div) != 0) + isl_die(ctx, isl_error_unsupported, + "cannot handle divs yet", return isl_aff_free(aff)); + + aff->ls = isl_local_space_substitute(aff->ls, type, pos, subs); + if (!aff->ls) + return isl_aff_free(aff); + + 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_init(v); + isl_seq_substitute(aff->v->el, pos, subs->v->el, + aff->v->size, subs->v->size, v); + isl_int_clear(v); + + return aff; +} + +/* Plug in "subs" for dimension "type", "pos" in each of the affine + * expressions in "maff". + */ +__isl_give isl_multi_aff *isl_multi_aff_substitute( + __isl_take isl_multi_aff *maff, enum isl_dim_type type, unsigned pos, + __isl_keep isl_aff *subs) +{ + int i; + + maff = isl_multi_aff_cow(maff); + if (!maff || !subs) + return isl_multi_aff_free(maff); + + if (type == isl_dim_in) + type = isl_dim_set; + + for (i = 0; i < maff->n; ++i) { + maff->p[i] = isl_aff_substitute(maff->p[i], type, pos, subs); + if (!maff->p[i]) + return isl_multi_aff_free(maff); + } + + return maff; +} + +/* Plug in "subs" for dimension "type", "pos" of "pma". + * + * pma is of the form + * + * A_i(v) -> M_i(v) + * + * while subs is of the form + * + * v' = B_j(v) -> S_j + * + * Each pair i,j such that C_ij = A_i \cap B_i is non-empty + * has a contribution in the result, in particular + * + * C_ij(S_j) -> M_i(S_j) + * + * Note that plugging in S_j in C_ij may also result in an empty set + * and this contribution should simply be discarded. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute( + __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, unsigned pos, + __isl_keep isl_pw_aff *subs) +{ + int i, j, n; + isl_pw_multi_aff *res; + + if (!pma || !subs) + return isl_pw_multi_aff_free(pma); + + n = pma->n * subs->n; + res = isl_pw_multi_aff_alloc_size(isl_space_copy(pma->dim), n); + + for (i = 0; i < pma->n; ++i) { + for (j = 0; j < subs->n; ++j) { + isl_set *common; + isl_multi_aff *res_ij; + int empty; + + common = isl_set_intersect( + isl_set_copy(pma->p[i].set), + isl_set_copy(subs->p[j].set)); + common = isl_set_substitute(common, + type, pos, subs->p[j].aff); + empty = isl_set_plain_is_empty(common); + if (empty < 0 || empty) { + isl_set_free(common); + if (empty < 0) + goto error; + continue; + } + + res_ij = isl_multi_aff_substitute( + isl_multi_aff_copy(pma->p[i].maff), + type, pos, subs->p[j].aff); + + res = isl_pw_multi_aff_add_piece(res, common, res_ij); + } + } + + isl_pw_multi_aff_free(pma); + return res; +error: + isl_pw_multi_aff_free(pma); + isl_pw_multi_aff_free(res); + return NULL; +} + +/* Compute the preimage of a range of dimensions in the affine expression "src" + * under "ma" and put the result in "dst". The number of dimensions in "src" + * that precede the range is given by "n_before". The number of dimensions + * in the range is given by the number of output dimensions of "ma". + * The number of dimensions that follow the range is given by "n_after". + * If "has_denom" is set (to one), + * then "src" and "dst" have an extra initial denominator. + * "n_div_ma" is the number of existentials in "ma" + * "n_div_bset" is the number of existentials in "src" + * The resulting "dst" (which is assumed to have been allocated by + * the caller) contains coefficients for both sets of existentials, + * first those in "ma" and then those in "src". + * f, c1, c2 and g are temporary objects that have been initialized + * by the caller. + * + * Let src represent the expression + * + * (a(p) + f_u u + b v + f_w w + c(divs))/d + * + * and let ma represent the expressions + * + * v_i = (r_i(p) + s_i(y) + t_i(divs'))/m_i + * + * We start out with the following expression for dst: + * + * (a(p) + f_u u + 0 y + f_w w + 0 divs' + c(divs) + f \sum_i b_i v_i)/d + * + * with the multiplication factor f initially equal to 1 + * and f \sum_i b_i v_i kept separately. + * For each x_i that we substitute, we multiply the numerator + * (and denominator) of dst by c_1 = m_i and add the numerator + * of the x_i expression multiplied by c_2 = f b_i, + * after removing the common factors of c_1 and c_2. + * The multiplication factor f also needs to be multiplied by c_1 + * for the next x_j, j > i. + */ +void isl_seq_preimage(isl_int *dst, isl_int *src, + __isl_keep isl_multi_aff *ma, int n_before, int n_after, + int n_div_ma, int n_div_bmap, + isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom) +{ + int i; + int n_param, n_in, n_out; + int o_dst, o_src; + + n_param = isl_multi_aff_dim(ma, isl_dim_param); + n_in = isl_multi_aff_dim(ma, isl_dim_in); + n_out = isl_multi_aff_dim(ma, isl_dim_out); + + isl_seq_cpy(dst, src, has_denom + 1 + n_param + n_before); + o_dst = o_src = has_denom + 1 + n_param + n_before; + isl_seq_clr(dst + o_dst, n_in); + o_dst += n_in; + o_src += n_out; + isl_seq_cpy(dst + o_dst, src + o_src, n_after); + o_dst += n_after; + o_src += n_after; + isl_seq_clr(dst + o_dst, n_div_ma); + o_dst += n_div_ma; + isl_seq_cpy(dst + o_dst, src + o_src, n_div_bmap); + + isl_int_set_si(f, 1); + + for (i = 0; i < n_out; ++i) { + int offset = has_denom + 1 + n_param + n_before + i; + + if (isl_int_is_zero(src[offset])) + continue; + isl_int_set(c1, ma->p[i]->v->el[0]); + isl_int_mul(c2, f, src[offset]); + isl_int_gcd(g, c1, c2); + isl_int_divexact(c1, c1, g); + isl_int_divexact(c2, c2, g); + + isl_int_mul(f, f, c1); + o_dst = has_denom; + o_src = 1; + isl_seq_combine(dst + o_dst, c1, dst + o_dst, + c2, ma->p[i]->v->el + o_src, 1 + n_param); + o_dst += 1 + n_param; + o_src += 1 + n_param; + isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_before); + o_dst += n_before; + isl_seq_combine(dst + o_dst, c1, dst + o_dst, + c2, ma->p[i]->v->el + o_src, n_in); + o_dst += n_in; + o_src += n_in; + isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_after); + o_dst += n_after; + isl_seq_combine(dst + o_dst, c1, dst + o_dst, + c2, ma->p[i]->v->el + o_src, n_div_ma); + o_dst += n_div_ma; + o_src += n_div_ma; + isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_div_bmap); + if (has_denom) + isl_int_mul(dst[0], dst[0], c1); + } +} + +/* Compute the pullback of "aff" by the function represented by "ma". + * In other words, plug in "ma" in "aff". The result is an affine expression + * defined over the domain space of "ma". + * + * If "aff" is represented by + * + * (a(p) + b x + c(divs))/d + * + * and ma is represented by + * + * x = D(p) + F(y) + G(divs') + * + * then the result is + * + * (a(p) + b D(p) + b F(y) + b G(divs') + c(divs))/d + * + * The divs in the local space of the input are similarly adjusted + * through a call to isl_local_space_preimage_multi_aff. + */ +__isl_give isl_aff *isl_aff_pullback_multi_aff(__isl_take isl_aff *aff, + __isl_take isl_multi_aff *ma) +{ + isl_aff *res = NULL; + isl_local_space *ls; + int n_div_aff, n_div_ma; + isl_int f, c1, c2, g; + + ma = isl_multi_aff_align_divs(ma); + if (!aff || !ma) + goto error; + + n_div_aff = isl_aff_dim(aff, isl_dim_div); + n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0; + + ls = isl_aff_get_domain_local_space(aff); + ls = isl_local_space_preimage_multi_aff(ls, isl_multi_aff_copy(ma)); + res = isl_aff_alloc(ls); + if (!res) + goto error; + + isl_int_init(f); + isl_int_init(c1); + isl_int_init(c2); + isl_int_init(g); + + isl_seq_preimage(res->v->el, aff->v->el, ma, 0, 0, n_div_ma, n_div_aff, + f, c1, c2, g, 1); + + isl_int_clear(f); + isl_int_clear(c1); + isl_int_clear(c2); + isl_int_clear(g); + + isl_aff_free(aff); + isl_multi_aff_free(ma); + res = isl_aff_normalize(res); + return res; +error: + isl_aff_free(aff); + isl_multi_aff_free(ma); + isl_aff_free(res); + return NULL; +} + +/* Compute the pullback of "aff1" by the function represented by "aff2". + * In other words, plug in "aff2" in "aff1". The result is an affine expression + * defined over the domain space of "aff1". + * + * The domain of "aff1" should match the range of "aff2", which means + * that it should be single-dimensional. + */ +__isl_give isl_aff *isl_aff_pullback_aff(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2) +{ + isl_multi_aff *ma; + + ma = isl_multi_aff_from_aff(aff2); + return isl_aff_pullback_multi_aff(aff1, ma); +} + +/* Compute the pullback of "ma1" by the function represented by "ma2". + * In other words, plug in "ma2" in "ma1". + * + * The parameters of "ma1" and "ma2" are assumed to have been aligned. + */ +static __isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff_aligned( + __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2) +{ + int i; + isl_space *space = NULL; + + ma2 = isl_multi_aff_align_divs(ma2); + ma1 = isl_multi_aff_cow(ma1); + if (!ma1 || !ma2) + goto error; + + space = isl_space_join(isl_multi_aff_get_space(ma2), + isl_multi_aff_get_space(ma1)); + + for (i = 0; i < ma1->n; ++i) { + ma1->p[i] = isl_aff_pullback_multi_aff(ma1->p[i], + isl_multi_aff_copy(ma2)); + if (!ma1->p[i]) + goto error; + } + + ma1 = isl_multi_aff_reset_space(ma1, space); + isl_multi_aff_free(ma2); + return ma1; +error: + isl_space_free(space); + isl_multi_aff_free(ma2); + isl_multi_aff_free(ma1); + return NULL; +} + +/* Compute the pullback of "ma1" by the function represented by "ma2". + * In other words, plug in "ma2" in "ma1". + */ +__isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff( + __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2) +{ + return isl_multi_aff_align_params_multi_multi_and(ma1, ma2, + &isl_multi_aff_pullback_multi_aff_aligned); +} + +/* Extend the local space of "dst" to include the divs + * in the local space of "src". + * + * If "src" does not have any divs or if the local spaces of "dst" and + * "src" are the same, then no extension is required. + */ +__isl_give isl_aff *isl_aff_align_divs(__isl_take isl_aff *dst, + __isl_keep isl_aff *src) +{ + isl_ctx *ctx; + int src_n_div, dst_n_div; + int *exp1 = NULL; + int *exp2 = NULL; + isl_bool equal; + isl_mat *div; + + if (!src || !dst) + return isl_aff_free(dst); + + ctx = isl_aff_get_ctx(src); + equal = isl_local_space_has_equal_space(src->ls, dst->ls); + if (equal < 0) + return isl_aff_free(dst); + if (!equal) + isl_die(ctx, isl_error_invalid, + "spaces don't match", goto error); + + src_n_div = isl_local_space_dim(src->ls, isl_dim_div); + if (src_n_div == 0) + return dst; + equal = isl_local_space_is_equal(src->ls, dst->ls); + if (equal < 0) + return isl_aff_free(dst); + if (equal) + return dst; + + dst_n_div = isl_local_space_dim(dst->ls, isl_dim_div); + exp1 = isl_alloc_array(ctx, int, src_n_div); + exp2 = isl_alloc_array(ctx, int, dst_n_div); + if (!exp1 || (dst_n_div && !exp2)) + goto error; + + div = isl_merge_divs(src->ls->div, dst->ls->div, exp1, exp2); + dst = isl_aff_expand_divs(dst, div, exp2); + free(exp1); + free(exp2); + + return dst; +error: + free(exp1); + free(exp2); + return isl_aff_free(dst); +} + +/* Adjust the local spaces of the affine expressions in "maff" + * such that they all have the save divs. + */ +__isl_give isl_multi_aff *isl_multi_aff_align_divs( + __isl_take isl_multi_aff *maff) +{ + int i; + + if (!maff) + return NULL; + if (maff->n == 0) + return maff; + maff = isl_multi_aff_cow(maff); + if (!maff) + return NULL; + + for (i = 1; i < maff->n; ++i) + maff->p[0] = isl_aff_align_divs(maff->p[0], maff->p[i]); + for (i = 1; i < maff->n; ++i) { + maff->p[i] = isl_aff_align_divs(maff->p[i], maff->p[0]); + if (!maff->p[i]) + return isl_multi_aff_free(maff); + } + + return maff; +} + +__isl_give isl_aff *isl_aff_lift(__isl_take isl_aff *aff) +{ + aff = isl_aff_cow(aff); + if (!aff) + return NULL; + + aff->ls = isl_local_space_lift(aff->ls); + if (!aff->ls) + return isl_aff_free(aff); + + return aff; +} + +/* Lift "maff" to a space with extra dimensions such that the result + * has no more existentially quantified variables. + * If "ls" is not NULL, then *ls is assigned the local space that lies + * at the basis of the lifting applied to "maff". + */ +__isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff, + __isl_give isl_local_space **ls) +{ + int i; + isl_space *space; + unsigned n_div; + + if (ls) + *ls = NULL; + + if (!maff) + return NULL; + + if (maff->n == 0) { + if (ls) { + isl_space *space = isl_multi_aff_get_domain_space(maff); + *ls = isl_local_space_from_space(space); + if (!*ls) + return isl_multi_aff_free(maff); + } + return maff; + } + + maff = isl_multi_aff_cow(maff); + maff = isl_multi_aff_align_divs(maff); + if (!maff) + return NULL; + + n_div = isl_aff_dim(maff->p[0], isl_dim_div); + space = isl_multi_aff_get_space(maff); + space = isl_space_lift(isl_space_domain(space), n_div); + space = isl_space_extend_domain_with_range(space, + isl_multi_aff_get_space(maff)); + if (!space) + return isl_multi_aff_free(maff); + isl_space_free(maff->space); + maff->space = space; + + if (ls) { + *ls = isl_aff_get_domain_local_space(maff->p[0]); + if (!*ls) + return isl_multi_aff_free(maff); + } + + for (i = 0; i < maff->n; ++i) { + maff->p[i] = isl_aff_lift(maff->p[i]); + if (!maff->p[i]) + goto error; + } + + return maff; +error: + if (ls) + isl_local_space_free(*ls); + return isl_multi_aff_free(maff); +} + + +/* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma". + */ +__isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff( + __isl_keep isl_pw_multi_aff *pma, int pos) +{ + int i; + int n_out; + isl_space *space; + isl_pw_aff *pa; + + if (!pma) + return NULL; + + n_out = isl_pw_multi_aff_dim(pma, isl_dim_out); + if (pos < 0 || pos >= n_out) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "index out of bounds", return NULL); + + space = isl_pw_multi_aff_get_space(pma); + space = isl_space_drop_dims(space, isl_dim_out, + pos + 1, n_out - pos - 1); + space = isl_space_drop_dims(space, isl_dim_out, 0, pos); + + pa = isl_pw_aff_alloc_size(space, pma->n); + for (i = 0; i < pma->n; ++i) { + isl_aff *aff; + aff = isl_multi_aff_get_aff(pma->p[i].maff, pos); + pa = isl_pw_aff_add_piece(pa, isl_set_copy(pma->p[i].set), aff); + } + + return pa; +} + +/* Return an isl_pw_multi_aff with the given "set" as domain and + * an unnamed zero-dimensional range. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain( + __isl_take isl_set *set) +{ + isl_multi_aff *ma; + isl_space *space; + + space = isl_set_get_space(set); + space = isl_space_from_domain(space); + ma = isl_multi_aff_zero(space); + return isl_pw_multi_aff_alloc(set, ma); +} + +/* Add an isl_pw_multi_aff with the given "set" as domain and + * an unnamed zero-dimensional range to *user. + */ +static isl_stat add_pw_multi_aff_from_domain(__isl_take isl_set *set, + void *user) +{ + isl_union_pw_multi_aff **upma = user; + isl_pw_multi_aff *pma; + + pma = isl_pw_multi_aff_from_domain(set); + *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma); + + return isl_stat_ok; +} + +/* Return an isl_union_pw_multi_aff with the given "uset" as domain and + * an unnamed zero-dimensional range. + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain( + __isl_take isl_union_set *uset) +{ + isl_space *space; + isl_union_pw_multi_aff *upma; + + if (!uset) + return NULL; + + space = isl_union_set_get_space(uset); + upma = isl_union_pw_multi_aff_empty(space); + + if (isl_union_set_foreach_set(uset, + &add_pw_multi_aff_from_domain, &upma) < 0) + goto error; + + isl_union_set_free(uset); + return upma; +error: + isl_union_set_free(uset); + isl_union_pw_multi_aff_free(upma); + return NULL; +} + +/* Convert "pma" to an isl_map and add it to *umap. + */ +static isl_stat map_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma, + void *user) +{ + isl_union_map **umap = user; + isl_map *map; + + map = isl_map_from_pw_multi_aff(pma); + *umap = isl_union_map_add_map(*umap, map); + + return isl_stat_ok; +} + +/* Construct a union map mapping the domain of the union + * piecewise multi-affine expression to its range, with each dimension + * in the range equated to the corresponding affine expression on its cell. + */ +__isl_give isl_union_map *isl_union_map_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma) +{ + isl_space *space; + isl_union_map *umap; + + if (!upma) + return NULL; + + space = isl_union_pw_multi_aff_get_space(upma); + umap = isl_union_map_empty(space); + + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, + &map_from_pw_multi_aff, &umap) < 0) + goto error; + + isl_union_pw_multi_aff_free(upma); + return umap; +error: + isl_union_pw_multi_aff_free(upma); + isl_union_map_free(umap); + return NULL; +} + +/* Local data for bin_entry and the callback "fn". + */ +struct isl_union_pw_multi_aff_bin_data { + isl_union_pw_multi_aff *upma2; + isl_union_pw_multi_aff *res; + isl_pw_multi_aff *pma; + isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user); +}; + +/* Given an isl_pw_multi_aff from upma1, store it in data->pma + * and call data->fn for each isl_pw_multi_aff in data->upma2. + */ +static isl_stat bin_entry(__isl_take isl_pw_multi_aff *pma, void *user) +{ + struct isl_union_pw_multi_aff_bin_data *data = user; + isl_stat r; + + data->pma = pma; + r = isl_union_pw_multi_aff_foreach_pw_multi_aff(data->upma2, + data->fn, data); + isl_pw_multi_aff_free(pma); + + return r; +} + +/* Call "fn" on each pair of isl_pw_multi_affs in "upma1" and "upma2". + * The isl_pw_multi_aff from upma1 is stored in data->pma (where data is + * passed as user field) and the isl_pw_multi_aff from upma2 is available + * as *entry. The callback should adjust data->res if desired. + */ +static __isl_give isl_union_pw_multi_aff *bin_op( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2, + isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user)) +{ + isl_space *space; + struct isl_union_pw_multi_aff_bin_data data = { NULL, NULL, NULL, fn }; + + space = isl_union_pw_multi_aff_get_space(upma2); + upma1 = isl_union_pw_multi_aff_align_params(upma1, space); + space = isl_union_pw_multi_aff_get_space(upma1); + upma2 = isl_union_pw_multi_aff_align_params(upma2, space); + + if (!upma1 || !upma2) + goto error; + + data.upma2 = upma2; + data.res = isl_union_pw_multi_aff_alloc_same_size(upma1); + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma1, + &bin_entry, &data) < 0) + goto error; + + isl_union_pw_multi_aff_free(upma1); + isl_union_pw_multi_aff_free(upma2); + return data.res; +error: + isl_union_pw_multi_aff_free(upma1); + isl_union_pw_multi_aff_free(upma2); + isl_union_pw_multi_aff_free(data.res); + return NULL; +} + +/* Given two aligned isl_pw_multi_affs A -> B and C -> D, + * construct an isl_pw_multi_aff (A * C) -> [B -> D]. + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_range_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + isl_space *space; + + space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1), + isl_pw_multi_aff_get_space(pma2)); + return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space, + &isl_multi_aff_range_product); +} + +/* Given two isl_pw_multi_affs A -> B and C -> D, + * construct an isl_pw_multi_aff (A * C) -> [B -> D]. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, + &pw_multi_aff_range_product); +} + +/* Given two aligned isl_pw_multi_affs A -> B and C -> D, + * construct an isl_pw_multi_aff (A * C) -> (B, D). + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_flat_range_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + isl_space *space; + + space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1), + isl_pw_multi_aff_get_space(pma2)); + space = isl_space_flatten_range(space); + return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space, + &isl_multi_aff_flat_range_product); +} + +/* Given two isl_pw_multi_affs A -> B and C -> D, + * construct an isl_pw_multi_aff (A * C) -> (B, D). + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_flat_range_product( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) +{ + return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, + &pw_multi_aff_flat_range_product); +} + +/* If data->pma and "pma2" have the same domain space, then compute + * their flat range product and the result to data->res. + */ +static isl_stat flat_range_product_entry(__isl_take isl_pw_multi_aff *pma2, + void *user) +{ + struct isl_union_pw_multi_aff_bin_data *data = user; + + if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in, + pma2->dim, isl_dim_in)) { + isl_pw_multi_aff_free(pma2); + return isl_stat_ok; + } + + pma2 = isl_pw_multi_aff_flat_range_product( + isl_pw_multi_aff_copy(data->pma), pma2); + + data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2); + + return isl_stat_ok; +} + +/* Given two isl_union_pw_multi_affs A -> B and C -> D, + * construct an isl_union_pw_multi_aff (A * C) -> (B, D). + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2) +{ + return bin_op(upma1, upma2, &flat_range_product_entry); +} + +/* Replace the affine expressions at position "pos" in "pma" by "pa". + * The parameters are assumed to have been aligned. + * + * The implementation essentially performs an isl_pw_*_on_shared_domain, + * except that it works on two different isl_pw_* types. + */ +static __isl_give isl_pw_multi_aff *pw_multi_aff_set_pw_aff( + __isl_take isl_pw_multi_aff *pma, unsigned pos, + __isl_take isl_pw_aff *pa) +{ + int i, j, n; + isl_pw_multi_aff *res = NULL; + + if (!pma || !pa) + goto error; + + if (!isl_space_tuple_is_equal(pma->dim, isl_dim_in, + pa->dim, isl_dim_in)) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "domains don't match", goto error); + if (pos >= isl_pw_multi_aff_dim(pma, isl_dim_out)) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "index out of bounds", goto error); + + n = pma->n * pa->n; + res = isl_pw_multi_aff_alloc_size(isl_pw_multi_aff_get_space(pma), n); + + for (i = 0; i < pma->n; ++i) { + for (j = 0; j < pa->n; ++j) { + isl_set *common; + isl_multi_aff *res_ij; + int empty; + + common = isl_set_intersect(isl_set_copy(pma->p[i].set), + isl_set_copy(pa->p[j].set)); + empty = isl_set_plain_is_empty(common); + if (empty < 0 || empty) { + isl_set_free(common); + if (empty < 0) + goto error; + continue; + } + + res_ij = isl_multi_aff_set_aff( + isl_multi_aff_copy(pma->p[i].maff), pos, + isl_aff_copy(pa->p[j].aff)); + res_ij = isl_multi_aff_gist(res_ij, + isl_set_copy(common)); + + res = isl_pw_multi_aff_add_piece(res, common, res_ij); + } + } + + isl_pw_multi_aff_free(pma); + isl_pw_aff_free(pa); + return res; +error: + isl_pw_multi_aff_free(pma); + isl_pw_aff_free(pa); + return isl_pw_multi_aff_free(res); +} + +/* Replace the affine expressions at position "pos" in "pma" by "pa". + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff( + __isl_take isl_pw_multi_aff *pma, unsigned pos, + __isl_take isl_pw_aff *pa) +{ + isl_bool equal_params; + + if (!pma || !pa) + goto error; + equal_params = isl_space_has_equal_params(pma->dim, pa->dim); + if (equal_params < 0) + goto error; + if (equal_params) + return pw_multi_aff_set_pw_aff(pma, pos, pa); + if (!isl_space_has_named_params(pma->dim) || + !isl_space_has_named_params(pa->dim)) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "unaligned unnamed parameters", goto error); + pma = isl_pw_multi_aff_align_params(pma, isl_pw_aff_get_space(pa)); + pa = isl_pw_aff_align_params(pa, isl_pw_multi_aff_get_space(pma)); + return pw_multi_aff_set_pw_aff(pma, pos, pa); +error: + isl_pw_multi_aff_free(pma); + isl_pw_aff_free(pa); + return NULL; +} + +/* Do the parameters of "pa" match those of "space"? + */ +isl_bool isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa, + __isl_keep isl_space *space) +{ + isl_space *pa_space; + isl_bool match; + + if (!pa || !space) + return isl_bool_error; + + pa_space = isl_pw_aff_get_space(pa); + + match = isl_space_has_equal_params(space, pa_space); + + isl_space_free(pa_space); + return match; +} + +/* Check that the domain space of "pa" matches "space". + */ +isl_stat isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa, + __isl_keep isl_space *space) +{ + isl_space *pa_space; + isl_bool match; + + if (!pa || !space) + return isl_stat_error; + + pa_space = isl_pw_aff_get_space(pa); + + match = isl_space_has_equal_params(space, pa_space); + if (match < 0) + goto error; + if (!match) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "parameters don't match", goto error); + match = isl_space_tuple_is_equal(space, isl_dim_in, + pa_space, isl_dim_in); + if (match < 0) + goto error; + if (!match) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "domains don't match", goto error); + isl_space_free(pa_space); + return isl_stat_ok; +error: + isl_space_free(pa_space); + return isl_stat_error; +} + +#undef BASE +#define BASE pw_aff +#undef DOMBASE +#define DOMBASE set + +#include +#include +#include +#include +#include +#include + +/* Scale the elements of "pma" by the corresponding elements of "mv". + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv) +{ + int i; + isl_bool equal_params; + + pma = isl_pw_multi_aff_cow(pma); + if (!pma || !mv) + goto error; + if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out, + mv->space, isl_dim_set)) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "spaces don't match", goto error); + equal_params = isl_space_has_equal_params(pma->dim, mv->space); + if (equal_params < 0) + goto error; + if (!equal_params) { + pma = isl_pw_multi_aff_align_params(pma, + isl_multi_val_get_space(mv)); + mv = isl_multi_val_align_params(mv, + isl_pw_multi_aff_get_space(pma)); + if (!pma || !mv) + goto error; + } + + for (i = 0; i < pma->n; ++i) { + pma->p[i].maff = isl_multi_aff_scale_multi_val(pma->p[i].maff, + isl_multi_val_copy(mv)); + if (!pma->p[i].maff) + goto error; + } + + isl_multi_val_free(mv); + return pma; +error: + isl_multi_val_free(mv); + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* This function is called for each entry of an isl_union_pw_multi_aff. + * If the space of the entry matches that of data->mv, + * then apply isl_pw_multi_aff_scale_multi_val and return the result. + * Otherwise, return an empty isl_pw_multi_aff. + */ +static __isl_give isl_pw_multi_aff *union_pw_multi_aff_scale_multi_val_entry( + __isl_take isl_pw_multi_aff *pma, void *user) +{ + isl_multi_val *mv = user; + + if (!pma) + return NULL; + if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out, + mv->space, isl_dim_set)) { + isl_space *space = isl_pw_multi_aff_get_space(pma); + isl_pw_multi_aff_free(pma); + return isl_pw_multi_aff_empty(space); + } + + return isl_pw_multi_aff_scale_multi_val(pma, isl_multi_val_copy(mv)); +} + +/* Scale the elements of "upma" by the corresponding elements of "mv", + * for those entries that match the space of "mv". + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_multi_val( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_multi_val *mv) +{ + upma = isl_union_pw_multi_aff_align_params(upma, + isl_multi_val_get_space(mv)); + mv = isl_multi_val_align_params(mv, + isl_union_pw_multi_aff_get_space(upma)); + if (!upma || !mv) + goto error; + + return isl_union_pw_multi_aff_transform(upma, + &union_pw_multi_aff_scale_multi_val_entry, mv); + + isl_multi_val_free(mv); + return upma; +error: + isl_multi_val_free(mv); + isl_union_pw_multi_aff_free(upma); + return NULL; +} + +/* Construct and return a piecewise multi affine expression + * in the given space with value zero in each of the output dimensions and + * a universe domain. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(__isl_take isl_space *space) +{ + return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_zero(space)); +} + +/* Construct and return a piecewise multi affine expression + * that is equal to the given piecewise affine expression. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff( + __isl_take isl_pw_aff *pa) +{ + int i; + isl_space *space; + isl_pw_multi_aff *pma; + + if (!pa) + return NULL; + + space = isl_pw_aff_get_space(pa); + pma = isl_pw_multi_aff_alloc_size(space, pa->n); + + for (i = 0; i < pa->n; ++i) { + isl_set *set; + isl_multi_aff *ma; + + set = isl_set_copy(pa->p[i].set); + ma = isl_multi_aff_from_aff(isl_aff_copy(pa->p[i].aff)); + pma = isl_pw_multi_aff_add_piece(pma, set, ma); + } + + isl_pw_aff_free(pa); + return pma; +} + +/* Construct a set or map mapping the shared (parameter) domain + * of the piecewise affine expressions to the range of "mpa" + * with each dimension in the range equated to the + * corresponding piecewise affine expression. + */ +static __isl_give isl_map *map_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa) +{ + int i; + isl_space *space; + isl_map *map; + + if (!mpa) + return NULL; + + if (isl_space_dim(mpa->space, isl_dim_out) != mpa->n) + isl_die(isl_multi_pw_aff_get_ctx(mpa), isl_error_internal, + "invalid space", goto error); + + space = isl_multi_pw_aff_get_domain_space(mpa); + map = isl_map_universe(isl_space_from_domain(space)); + + for (i = 0; i < mpa->n; ++i) { + isl_pw_aff *pa; + isl_map *map_i; + + pa = isl_pw_aff_copy(mpa->p[i]); + map_i = map_from_pw_aff(pa); + + map = isl_map_flat_range_product(map, map_i); + } + + map = isl_map_reset_space(map, isl_multi_pw_aff_get_space(mpa)); + + isl_multi_pw_aff_free(mpa); + return map; +error: + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Construct a map mapping the shared domain + * of the piecewise affine expressions to the range of "mpa" + * with each dimension in the range equated to the + * corresponding piecewise affine expression. + */ +__isl_give isl_map *isl_map_from_multi_pw_aff(__isl_take isl_multi_pw_aff *mpa) +{ + if (!mpa) + return NULL; + if (isl_space_is_set(mpa->space)) + isl_die(isl_multi_pw_aff_get_ctx(mpa), isl_error_internal, + "space of input is not a map", goto error); + + return map_from_multi_pw_aff(mpa); +error: + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Construct a set mapping the shared parameter domain + * of the piecewise affine expressions to the space of "mpa" + * with each dimension in the range equated to the + * corresponding piecewise affine expression. + */ +__isl_give isl_set *isl_set_from_multi_pw_aff(__isl_take isl_multi_pw_aff *mpa) +{ + if (!mpa) + return NULL; + if (!isl_space_is_set(mpa->space)) + isl_die(isl_multi_pw_aff_get_ctx(mpa), isl_error_internal, + "space of input is not a set", goto error); + + return map_from_multi_pw_aff(mpa); +error: + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Construct and return a piecewise multi affine expression + * that is equal to the given multi piecewise affine expression + * on the shared domain of the piecewise affine expressions. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa) +{ + int i; + isl_space *space; + isl_pw_aff *pa; + isl_pw_multi_aff *pma; + + if (!mpa) + return NULL; + + space = isl_multi_pw_aff_get_space(mpa); + + if (mpa->n == 0) { + isl_multi_pw_aff_free(mpa); + return isl_pw_multi_aff_zero(space); + } + + pa = isl_multi_pw_aff_get_pw_aff(mpa, 0); + pma = isl_pw_multi_aff_from_pw_aff(pa); + + for (i = 1; i < mpa->n; ++i) { + isl_pw_multi_aff *pma_i; + + pa = isl_multi_pw_aff_get_pw_aff(mpa, i); + pma_i = isl_pw_multi_aff_from_pw_aff(pa); + pma = isl_pw_multi_aff_range_product(pma, pma_i); + } + + pma = isl_pw_multi_aff_reset_space(pma, space); + + isl_multi_pw_aff_free(mpa); + return pma; +} + +/* Construct and return a multi piecewise affine expression + * that is equal to the given multi affine expression. + */ +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma) +{ + int i, n; + isl_multi_pw_aff *mpa; + + if (!ma) + return NULL; + + n = isl_multi_aff_dim(ma, isl_dim_out); + mpa = isl_multi_pw_aff_alloc(isl_multi_aff_get_space(ma)); + + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + + pa = isl_pw_aff_from_aff(isl_multi_aff_get_aff(ma, i)); + mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa); + } + + isl_multi_aff_free(ma); + return mpa; +} + +/* Construct and return a multi piecewise affine expression + * that is equal to the given piecewise multi affine expression. + */ +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_multi_aff( + __isl_take isl_pw_multi_aff *pma) +{ + int i, n; + isl_space *space; + isl_multi_pw_aff *mpa; + + if (!pma) + return NULL; + + n = isl_pw_multi_aff_dim(pma, isl_dim_out); + space = isl_pw_multi_aff_get_space(pma); + mpa = isl_multi_pw_aff_alloc(space); + + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + + pa = isl_pw_multi_aff_get_pw_aff(pma, i); + mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa); + } + + isl_pw_multi_aff_free(pma); + return mpa; +} + +/* Do "pa1" and "pa2" represent the same function? + * + * We first check if they are obviously equal. + * If not, we convert them to maps and check if those are equal. + * + * If "pa1" or "pa2" contain any NaNs, then they are considered + * not to be the same. A NaN is not equal to anything, not even + * to another NaN. + */ +isl_bool isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1, + __isl_keep isl_pw_aff *pa2) +{ + isl_bool equal; + isl_bool has_nan; + isl_map *map1, *map2; + + if (!pa1 || !pa2) + return isl_bool_error; + + equal = isl_pw_aff_plain_is_equal(pa1, pa2); + if (equal < 0 || equal) + return equal; + has_nan = either_involves_nan(pa1, pa2); + if (has_nan < 0) + return isl_bool_error; + if (has_nan) + return isl_bool_false; + + map1 = map_from_pw_aff(isl_pw_aff_copy(pa1)); + map2 = map_from_pw_aff(isl_pw_aff_copy(pa2)); + equal = isl_map_is_equal(map1, map2); + isl_map_free(map1); + isl_map_free(map2); + + return equal; +} + +/* Do "mpa1" and "mpa2" represent the same function? + * + * Note that we cannot convert the entire isl_multi_pw_aff + * to a map because the domains of the piecewise affine expressions + * may not be the same. + */ +isl_bool isl_multi_pw_aff_is_equal(__isl_keep isl_multi_pw_aff *mpa1, + __isl_keep isl_multi_pw_aff *mpa2) +{ + int i; + isl_bool equal, equal_params; + + if (!mpa1 || !mpa2) + return isl_bool_error; + + equal_params = isl_space_has_equal_params(mpa1->space, mpa2->space); + if (equal_params < 0) + return isl_bool_error; + if (!equal_params) { + if (!isl_space_has_named_params(mpa1->space)) + return isl_bool_false; + if (!isl_space_has_named_params(mpa2->space)) + return isl_bool_false; + mpa1 = isl_multi_pw_aff_copy(mpa1); + mpa2 = isl_multi_pw_aff_copy(mpa2); + mpa1 = isl_multi_pw_aff_align_params(mpa1, + isl_multi_pw_aff_get_space(mpa2)); + mpa2 = isl_multi_pw_aff_align_params(mpa2, + isl_multi_pw_aff_get_space(mpa1)); + equal = isl_multi_pw_aff_is_equal(mpa1, mpa2); + isl_multi_pw_aff_free(mpa1); + isl_multi_pw_aff_free(mpa2); + return equal; + } + + equal = isl_space_is_equal(mpa1->space, mpa2->space); + if (equal < 0 || !equal) + return equal; + + for (i = 0; i < mpa1->n; ++i) { + equal = isl_pw_aff_is_equal(mpa1->p[i], mpa2->p[i]); + if (equal < 0 || !equal) + return equal; + } + + return isl_bool_true; +} + +/* Do "pma1" and "pma2" represent the same function? + * + * First check if they are obviously equal. + * If not, then convert them to maps and check if those are equal. + * + * If "pa1" or "pa2" contain any NaNs, then they are considered + * not to be the same. A NaN is not equal to anything, not even + * to another NaN. + */ +isl_bool isl_pw_multi_aff_is_equal(__isl_keep isl_pw_multi_aff *pma1, + __isl_keep isl_pw_multi_aff *pma2) +{ + isl_bool equal; + isl_bool has_nan; + isl_map *map1, *map2; + + if (!pma1 || !pma2) + return isl_bool_error; + + equal = isl_pw_multi_aff_plain_is_equal(pma1, pma2); + if (equal < 0 || equal) + return equal; + has_nan = isl_pw_multi_aff_involves_nan(pma1); + if (has_nan >= 0 && !has_nan) + has_nan = isl_pw_multi_aff_involves_nan(pma2); + if (has_nan < 0 || has_nan) + return isl_bool_not(has_nan); + + map1 = isl_map_from_pw_multi_aff(isl_pw_multi_aff_copy(pma1)); + map2 = isl_map_from_pw_multi_aff(isl_pw_multi_aff_copy(pma2)); + equal = isl_map_is_equal(map1, map2); + isl_map_free(map1); + isl_map_free(map2); + + return equal; +} + +/* Compute the pullback of "mpa" by the function represented by "ma". + * In other words, plug in "ma" in "mpa". + * + * The parameters of "mpa" and "ma" are assumed to have been aligned. + */ +static __isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff_aligned( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma) +{ + int i; + isl_space *space = NULL; + + mpa = isl_multi_pw_aff_cow(mpa); + if (!mpa || !ma) + goto error; + + space = isl_space_join(isl_multi_aff_get_space(ma), + isl_multi_pw_aff_get_space(mpa)); + if (!space) + goto error; + + for (i = 0; i < mpa->n; ++i) { + mpa->p[i] = isl_pw_aff_pullback_multi_aff(mpa->p[i], + isl_multi_aff_copy(ma)); + if (!mpa->p[i]) + goto error; + } + + isl_multi_aff_free(ma); + isl_space_free(mpa->space); + mpa->space = space; + return mpa; +error: + isl_space_free(space); + isl_multi_pw_aff_free(mpa); + isl_multi_aff_free(ma); + return NULL; +} + +/* Compute the pullback of "mpa" by the function represented by "ma". + * In other words, plug in "ma" in "mpa". + */ +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma) +{ + isl_bool equal_params; + + if (!mpa || !ma) + goto error; + equal_params = isl_space_has_equal_params(mpa->space, ma->space); + if (equal_params < 0) + goto error; + if (equal_params) + return isl_multi_pw_aff_pullback_multi_aff_aligned(mpa, ma); + mpa = isl_multi_pw_aff_align_params(mpa, isl_multi_aff_get_space(ma)); + ma = isl_multi_aff_align_params(ma, isl_multi_pw_aff_get_space(mpa)); + return isl_multi_pw_aff_pullback_multi_aff_aligned(mpa, ma); +error: + isl_multi_pw_aff_free(mpa); + isl_multi_aff_free(ma); + return NULL; +} + +/* Compute the pullback of "mpa" by the function represented by "pma". + * In other words, plug in "pma" in "mpa". + * + * The parameters of "mpa" and "mpa" are assumed to have been aligned. + */ +static __isl_give isl_multi_pw_aff * +isl_multi_pw_aff_pullback_pw_multi_aff_aligned( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma) +{ + int i; + isl_space *space = NULL; + + mpa = isl_multi_pw_aff_cow(mpa); + if (!mpa || !pma) + goto error; + + space = isl_space_join(isl_pw_multi_aff_get_space(pma), + isl_multi_pw_aff_get_space(mpa)); + + for (i = 0; i < mpa->n; ++i) { + mpa->p[i] = isl_pw_aff_pullback_pw_multi_aff_aligned(mpa->p[i], + isl_pw_multi_aff_copy(pma)); + if (!mpa->p[i]) + goto error; + } + + isl_pw_multi_aff_free(pma); + isl_space_free(mpa->space); + mpa->space = space; + return mpa; +error: + isl_space_free(space); + isl_multi_pw_aff_free(mpa); + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* Compute the pullback of "mpa" by the function represented by "pma". + * In other words, plug in "pma" in "mpa". + */ +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_pw_multi_aff( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma) +{ + isl_bool equal_params; + + if (!mpa || !pma) + goto error; + equal_params = isl_space_has_equal_params(mpa->space, pma->dim); + if (equal_params < 0) + goto error; + if (equal_params) + return isl_multi_pw_aff_pullback_pw_multi_aff_aligned(mpa, pma); + mpa = isl_multi_pw_aff_align_params(mpa, + isl_pw_multi_aff_get_space(pma)); + pma = isl_pw_multi_aff_align_params(pma, + isl_multi_pw_aff_get_space(mpa)); + return isl_multi_pw_aff_pullback_pw_multi_aff_aligned(mpa, pma); +error: + isl_multi_pw_aff_free(mpa); + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* Apply "aff" to "mpa". The range of "mpa" needs to be compatible + * with the domain of "aff". The domain of the result is the same + * as that of "mpa". + * "mpa" and "aff" are assumed to have been aligned. + * + * We first extract the parametric constant from "aff", defined + * over the correct domain. + * Then we add the appropriate combinations of the members of "mpa". + * Finally, we add the integer divisions through recursive calls. + */ +static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff_aligned( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff) +{ + int i, n_in, n_div; + isl_space *space; + isl_val *v; + isl_pw_aff *pa; + isl_aff *tmp; + + n_in = isl_aff_dim(aff, isl_dim_in); + n_div = isl_aff_dim(aff, isl_dim_div); + + space = isl_space_domain(isl_multi_pw_aff_get_space(mpa)); + tmp = isl_aff_copy(aff); + tmp = isl_aff_drop_dims(tmp, isl_dim_div, 0, n_div); + tmp = isl_aff_drop_dims(tmp, isl_dim_in, 0, n_in); + tmp = isl_aff_add_dims(tmp, isl_dim_in, + isl_space_dim(space, isl_dim_set)); + tmp = isl_aff_reset_domain_space(tmp, space); + pa = isl_pw_aff_from_aff(tmp); + + for (i = 0; i < n_in; ++i) { + isl_pw_aff *pa_i; + + if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1)) + continue; + v = isl_aff_get_coefficient_val(aff, isl_dim_in, i); + pa_i = isl_multi_pw_aff_get_pw_aff(mpa, i); + pa_i = isl_pw_aff_scale_val(pa_i, v); + pa = isl_pw_aff_add(pa, pa_i); + } + + for (i = 0; i < n_div; ++i) { + isl_aff *div; + isl_pw_aff *pa_i; + + if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1)) + continue; + div = isl_aff_get_div(aff, i); + pa_i = isl_multi_pw_aff_apply_aff_aligned( + isl_multi_pw_aff_copy(mpa), div); + pa_i = isl_pw_aff_floor(pa_i); + v = isl_aff_get_coefficient_val(aff, isl_dim_div, i); + pa_i = isl_pw_aff_scale_val(pa_i, v); + pa = isl_pw_aff_add(pa, pa_i); + } + + isl_multi_pw_aff_free(mpa); + isl_aff_free(aff); + + return pa; +} + +/* Apply "aff" to "mpa". The range of "mpa" needs to be compatible + * with the domain of "aff". The domain of the result is the same + * as that of "mpa". + */ +__isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff) +{ + isl_bool equal_params; + + if (!aff || !mpa) + goto error; + equal_params = isl_space_has_equal_params(aff->ls->dim, mpa->space); + if (equal_params < 0) + goto error; + if (equal_params) + return isl_multi_pw_aff_apply_aff_aligned(mpa, aff); + + aff = isl_aff_align_params(aff, isl_multi_pw_aff_get_space(mpa)); + mpa = isl_multi_pw_aff_align_params(mpa, isl_aff_get_space(aff)); + + return isl_multi_pw_aff_apply_aff_aligned(mpa, aff); +error: + isl_aff_free(aff); + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Apply "pa" to "mpa". The range of "mpa" needs to be compatible + * with the domain of "pa". The domain of the result is the same + * as that of "mpa". + * "mpa" and "pa" are assumed to have been aligned. + * + * We consider each piece in turn. Note that the domains of the + * pieces are assumed to be disjoint and they remain disjoint + * after taking the preimage (over the same function). + */ +static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff_aligned( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa) +{ + isl_space *space; + isl_pw_aff *res; + int i; + + if (!mpa || !pa) + goto error; + + space = isl_space_join(isl_multi_pw_aff_get_space(mpa), + isl_pw_aff_get_space(pa)); + res = isl_pw_aff_empty(space); + + for (i = 0; i < pa->n; ++i) { + isl_pw_aff *pa_i; + isl_set *domain; + + pa_i = isl_multi_pw_aff_apply_aff_aligned( + isl_multi_pw_aff_copy(mpa), + isl_aff_copy(pa->p[i].aff)); + domain = isl_set_copy(pa->p[i].set); + domain = isl_set_preimage_multi_pw_aff(domain, + isl_multi_pw_aff_copy(mpa)); + pa_i = isl_pw_aff_intersect_domain(pa_i, domain); + res = isl_pw_aff_add_disjoint(res, pa_i); + } + + isl_pw_aff_free(pa); + isl_multi_pw_aff_free(mpa); + return res; +error: + isl_pw_aff_free(pa); + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Apply "pa" to "mpa". The range of "mpa" needs to be compatible + * with the domain of "pa". The domain of the result is the same + * as that of "mpa". + */ +__isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa) +{ + isl_bool equal_params; + + if (!pa || !mpa) + goto error; + equal_params = isl_space_has_equal_params(pa->dim, mpa->space); + if (equal_params < 0) + goto error; + if (equal_params) + return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa); + + pa = isl_pw_aff_align_params(pa, isl_multi_pw_aff_get_space(mpa)); + mpa = isl_multi_pw_aff_align_params(mpa, isl_pw_aff_get_space(pa)); + + return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa); +error: + isl_pw_aff_free(pa); + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Compute the pullback of "pa" by the function represented by "mpa". + * In other words, plug in "mpa" in "pa". + * "pa" and "mpa" are assumed to have been aligned. + * + * The pullback is computed by applying "pa" to "mpa". + */ +static __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff_aligned( + __isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa) +{ + return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa); +} + +/* Compute the pullback of "pa" by the function represented by "mpa". + * In other words, plug in "mpa" in "pa". + * + * The pullback is computed by applying "pa" to "mpa". + */ +__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff( + __isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa) +{ + return isl_multi_pw_aff_apply_pw_aff(mpa, pa); +} + +/* Compute the pullback of "mpa1" by the function represented by "mpa2". + * In other words, plug in "mpa2" in "mpa1". + * + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * We pullback each member of "mpa1" in turn. + */ +static __isl_give isl_multi_pw_aff * +isl_multi_pw_aff_pullback_multi_pw_aff_aligned( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2) +{ + int i; + isl_space *space = NULL; + + mpa1 = isl_multi_pw_aff_cow(mpa1); + if (!mpa1 || !mpa2) + goto error; + + space = isl_space_join(isl_multi_pw_aff_get_space(mpa2), + isl_multi_pw_aff_get_space(mpa1)); + + for (i = 0; i < mpa1->n; ++i) { + mpa1->p[i] = isl_pw_aff_pullback_multi_pw_aff_aligned( + mpa1->p[i], isl_multi_pw_aff_copy(mpa2)); + if (!mpa1->p[i]) + goto error; + } + + mpa1 = isl_multi_pw_aff_reset_space(mpa1, space); + + isl_multi_pw_aff_free(mpa2); + return mpa1; +error: + isl_space_free(space); + isl_multi_pw_aff_free(mpa1); + isl_multi_pw_aff_free(mpa2); + return NULL; +} + +/* Compute the pullback of "mpa1" by the function represented by "mpa2". + * In other words, plug in "mpa2" in "mpa1". + */ +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2) +{ + return isl_multi_pw_aff_align_params_multi_multi_and(mpa1, mpa2, + &isl_multi_pw_aff_pullback_multi_pw_aff_aligned); +} + +/* Align the parameters of "mpa1" and "mpa2", check that the ranges + * of "mpa1" and "mpa2" live in the same space, construct map space + * between the domain spaces of "mpa1" and "mpa2" and call "order" + * with this map space as extract argument. + */ +static __isl_give isl_map *isl_multi_pw_aff_order_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2, + __isl_give isl_map *(*order)(__isl_keep isl_multi_pw_aff *mpa1, + __isl_keep isl_multi_pw_aff *mpa2, __isl_take isl_space *space)) +{ + int match; + isl_space *space1, *space2; + isl_map *res; + + mpa1 = isl_multi_pw_aff_align_params(mpa1, + isl_multi_pw_aff_get_space(mpa2)); + mpa2 = isl_multi_pw_aff_align_params(mpa2, + isl_multi_pw_aff_get_space(mpa1)); + if (!mpa1 || !mpa2) + goto error; + match = isl_space_tuple_is_equal(mpa1->space, isl_dim_out, + mpa2->space, isl_dim_out); + if (match < 0) + goto error; + if (!match) + isl_die(isl_multi_pw_aff_get_ctx(mpa1), isl_error_invalid, + "range spaces don't match", goto error); + space1 = isl_space_domain(isl_multi_pw_aff_get_space(mpa1)); + space2 = isl_space_domain(isl_multi_pw_aff_get_space(mpa2)); + space1 = isl_space_map_from_domain_and_range(space1, space2); + + res = order(mpa1, mpa2, space1); + isl_multi_pw_aff_free(mpa1); + isl_multi_pw_aff_free(mpa2); + return res; +error: + isl_multi_pw_aff_free(mpa1); + isl_multi_pw_aff_free(mpa2); + return NULL; +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function values are equal. "space" is the space of the result. + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * "mpa1" and "mpa2" are equal when each of the pairs of elements + * in the sequences are equal. + */ +static __isl_give isl_map *isl_multi_pw_aff_eq_map_on_space( + __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2, + __isl_take isl_space *space) +{ + int i, n; + isl_map *res; + + res = isl_map_universe(space); + + n = isl_multi_pw_aff_dim(mpa1, isl_dim_out); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa1, *pa2; + isl_map *map; + + pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i); + pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i); + map = isl_pw_aff_eq_map(pa1, pa2); + res = isl_map_intersect(res, map); + } + + return res; +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function values are equal. + */ +__isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2) +{ + return isl_multi_pw_aff_order_map(mpa1, mpa2, + &isl_multi_pw_aff_eq_map_on_space); +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function values of "mpa1" is lexicographically satisfies "base" + * compared to that of "mpa2". "space" is the space of the result. + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * "mpa1" lexicographically satisfies "base" compared to "mpa2" + * if its i-th element satisfies "base" when compared to + * the i-th element of "mpa2" while all previous elements are + * pairwise equal. + */ +static __isl_give isl_map *isl_multi_pw_aff_lex_map_on_space( + __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2, + __isl_give isl_map *(*base)(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2), + __isl_take isl_space *space) +{ + int i, n; + isl_map *res, *rest; + + res = isl_map_empty(isl_space_copy(space)); + rest = isl_map_universe(space); + + n = isl_multi_pw_aff_dim(mpa1, isl_dim_out); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa1, *pa2; + isl_map *map; + + pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i); + pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i); + map = base(pa1, pa2); + map = isl_map_intersect(map, isl_map_copy(rest)); + res = isl_map_union(res, map); + + if (i == n - 1) + continue; + + pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i); + pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i); + map = isl_pw_aff_eq_map(pa1, pa2); + rest = isl_map_intersect(rest, map); + } + + isl_map_free(rest); + return res; +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function value of "mpa1" is lexicographically less than that + * of "mpa2". "space" is the space of the result. + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * "mpa1" is less than "mpa2" if its i-th element is smaller + * than the i-th element of "mpa2" while all previous elements are + * pairwise equal. + */ +__isl_give isl_map *isl_multi_pw_aff_lex_lt_map_on_space( + __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2, + __isl_take isl_space *space) +{ + return isl_multi_pw_aff_lex_map_on_space(mpa1, mpa2, + &isl_pw_aff_lt_map, space); +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function value of "mpa1" is lexicographically less than that + * of "mpa2". + */ +__isl_give isl_map *isl_multi_pw_aff_lex_lt_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2) +{ + return isl_multi_pw_aff_order_map(mpa1, mpa2, + &isl_multi_pw_aff_lex_lt_map_on_space); +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function value of "mpa1" is lexicographically greater than that + * of "mpa2". "space" is the space of the result. + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * "mpa1" is greater than "mpa2" if its i-th element is greater + * than the i-th element of "mpa2" while all previous elements are + * pairwise equal. + */ +__isl_give isl_map *isl_multi_pw_aff_lex_gt_map_on_space( + __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2, + __isl_take isl_space *space) +{ + return isl_multi_pw_aff_lex_map_on_space(mpa1, mpa2, + &isl_pw_aff_gt_map, space); +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function value of "mpa1" is lexicographically greater than that + * of "mpa2". + */ +__isl_give isl_map *isl_multi_pw_aff_lex_gt_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2) +{ + return isl_multi_pw_aff_order_map(mpa1, mpa2, + &isl_multi_pw_aff_lex_gt_map_on_space); +} + +/* Compare two isl_affs. + * + * Return -1 if "aff1" is "smaller" than "aff2", 1 if "aff1" is "greater" + * than "aff2" and 0 if they are equal. + * + * The order is fairly arbitrary. We do consider expressions that only involve + * earlier dimensions as "smaller". + */ +int isl_aff_plain_cmp(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2) +{ + int cmp; + int last1, last2; + + if (aff1 == aff2) + return 0; + + if (!aff1) + return -1; + if (!aff2) + return 1; + + cmp = isl_local_space_cmp(aff1->ls, aff2->ls); + if (cmp != 0) + return cmp; + + last1 = isl_seq_last_non_zero(aff1->v->el + 1, aff1->v->size - 1); + last2 = isl_seq_last_non_zero(aff2->v->el + 1, aff1->v->size - 1); + if (last1 != last2) + return last1 - last2; + + return isl_seq_cmp(aff1->v->el, aff2->v->el, aff1->v->size); +} + +/* Compare two isl_pw_affs. + * + * Return -1 if "pa1" is "smaller" than "pa2", 1 if "pa1" is "greater" + * than "pa2" and 0 if they are equal. + * + * The order is fairly arbitrary. We do consider expressions that only involve + * earlier dimensions as "smaller". + */ +int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1, + __isl_keep isl_pw_aff *pa2) +{ + int i; + int cmp; + + if (pa1 == pa2) + return 0; + + if (!pa1) + return -1; + if (!pa2) + return 1; + + cmp = isl_space_cmp(pa1->dim, pa2->dim); + if (cmp != 0) + return cmp; + + if (pa1->n != pa2->n) + return pa1->n - pa2->n; + + for (i = 0; i < pa1->n; ++i) { + cmp = isl_set_plain_cmp(pa1->p[i].set, pa2->p[i].set); + if (cmp != 0) + return cmp; + cmp = isl_aff_plain_cmp(pa1->p[i].aff, pa2->p[i].aff); + if (cmp != 0) + return cmp; + } + + return 0; +} + +/* Return a piecewise affine expression that is equal to "v" on "domain". + */ +__isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain, + __isl_take isl_val *v) +{ + isl_space *space; + isl_local_space *ls; + isl_aff *aff; + + space = isl_set_get_space(domain); + ls = isl_local_space_from_space(space); + aff = isl_aff_val_on_domain(ls, v); + + return isl_pw_aff_alloc(domain, aff); +} + +/* Return a multi affine expression that is equal to "mv" on domain + * space "space". + */ +__isl_give isl_multi_aff *isl_multi_aff_multi_val_on_space( + __isl_take isl_space *space, __isl_take isl_multi_val *mv) +{ + int i, n; + isl_space *space2; + isl_local_space *ls; + isl_multi_aff *ma; + + if (!space || !mv) + goto error; + + n = isl_multi_val_dim(mv, isl_dim_set); + space2 = isl_multi_val_get_space(mv); + space2 = isl_space_align_params(space2, isl_space_copy(space)); + space = isl_space_align_params(space, isl_space_copy(space2)); + space = isl_space_map_from_domain_and_range(space, space2); + ma = isl_multi_aff_alloc(isl_space_copy(space)); + ls = isl_local_space_from_space(isl_space_domain(space)); + for (i = 0; i < n; ++i) { + isl_val *v; + isl_aff *aff; + + v = isl_multi_val_get_val(mv, i); + aff = isl_aff_val_on_domain(isl_local_space_copy(ls), v); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + isl_local_space_free(ls); + + isl_multi_val_free(mv); + return ma; +error: + isl_space_free(space); + isl_multi_val_free(mv); + return NULL; +} + +/* Return a piecewise multi-affine expression + * that is equal to "mv" on "domain". + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_multi_val_on_domain( + __isl_take isl_set *domain, __isl_take isl_multi_val *mv) +{ + isl_space *space; + isl_multi_aff *ma; + + space = isl_set_get_space(domain); + ma = isl_multi_aff_multi_val_on_space(space, mv); + + return isl_pw_multi_aff_alloc(domain, ma); +} + +/* Internal data structure for isl_union_pw_multi_aff_multi_val_on_domain. + * mv is the value that should be attained on each domain set + * res collects the results + */ +struct isl_union_pw_multi_aff_multi_val_on_domain_data { + isl_multi_val *mv; + isl_union_pw_multi_aff *res; +}; + +/* Create an isl_pw_multi_aff equal to data->mv on "domain" + * and add it to data->res. + */ +static isl_stat pw_multi_aff_multi_val_on_domain(__isl_take isl_set *domain, + void *user) +{ + struct isl_union_pw_multi_aff_multi_val_on_domain_data *data = user; + isl_pw_multi_aff *pma; + isl_multi_val *mv; + + mv = isl_multi_val_copy(data->mv); + pma = isl_pw_multi_aff_multi_val_on_domain(domain, mv); + data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Return a union piecewise multi-affine expression + * that is equal to "mv" on "domain". + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv) +{ + struct isl_union_pw_multi_aff_multi_val_on_domain_data data; + isl_space *space; + + space = isl_union_set_get_space(domain); + data.res = isl_union_pw_multi_aff_empty(space); + data.mv = mv; + if (isl_union_set_foreach_set(domain, + &pw_multi_aff_multi_val_on_domain, &data) < 0) + data.res = isl_union_pw_multi_aff_free(data.res); + isl_union_set_free(domain); + isl_multi_val_free(mv); + return data.res; +} + +/* Compute the pullback of data->pma by the function represented by "pma2", + * provided the spaces match, and add the results to data->res. + */ +static isl_stat pullback_entry(__isl_take isl_pw_multi_aff *pma2, void *user) +{ + struct isl_union_pw_multi_aff_bin_data *data = user; + + if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in, + pma2->dim, isl_dim_out)) { + isl_pw_multi_aff_free(pma2); + return isl_stat_ok; + } + + pma2 = isl_pw_multi_aff_pullback_pw_multi_aff( + isl_pw_multi_aff_copy(data->pma), pma2); + + data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2); + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Compute the pullback of "upma1" by the function represented by "upma2". + */ +__isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2) +{ + return bin_op(upma1, upma2, &pullback_entry); +} + +/* Check that the domain space of "upa" matches "space". + * + * This function is called from isl_multi_union_pw_aff_set_union_pw_aff and + * can in principle never fail since the space "space" is that + * of the isl_multi_union_pw_aff and is a set space such that + * there is no domain space to match. + * + * We check the parameters and double-check that "space" is + * indeed that of a set. + */ +static isl_stat isl_union_pw_aff_check_match_domain_space( + __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space) +{ + isl_space *upa_space; + isl_bool match; + + if (!upa || !space) + return isl_stat_error; + + match = isl_space_is_set(space); + if (match < 0) + return isl_stat_error; + if (!match) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "expecting set space", return -1); + + upa_space = isl_union_pw_aff_get_space(upa); + match = isl_space_has_equal_params(space, upa_space); + if (match < 0) + goto error; + if (!match) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "parameters don't match", goto error); + + isl_space_free(upa_space); + return isl_stat_ok; +error: + isl_space_free(upa_space); + return isl_stat_error; +} + +/* Do the parameters of "upa" match those of "space"? + */ +static isl_bool isl_union_pw_aff_matching_params( + __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space) +{ + isl_space *upa_space; + isl_bool match; + + if (!upa || !space) + return isl_bool_error; + + upa_space = isl_union_pw_aff_get_space(upa); + + match = isl_space_has_equal_params(space, upa_space); + + isl_space_free(upa_space); + return match; +} + +/* Internal data structure for isl_union_pw_aff_reset_domain_space. + * space represents the new parameters. + * res collects the results. + */ +struct isl_union_pw_aff_reset_params_data { + isl_space *space; + isl_union_pw_aff *res; +}; + +/* Replace the parameters of "pa" by data->space and + * add the result to data->res. + */ +static isl_stat reset_params(__isl_take isl_pw_aff *pa, void *user) +{ + struct isl_union_pw_aff_reset_params_data *data = user; + isl_space *space; + + space = isl_pw_aff_get_space(pa); + space = isl_space_replace(space, isl_dim_param, data->space); + pa = isl_pw_aff_reset_space(pa, space); + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Replace the domain space of "upa" by "space". + * Since a union expression does not have a (single) domain space, + * "space" is necessarily a parameter space. + * + * Since the order and the names of the parameters determine + * the hash value, we need to create a new hash table. + */ +static __isl_give isl_union_pw_aff *isl_union_pw_aff_reset_domain_space( + __isl_take isl_union_pw_aff *upa, __isl_take isl_space *space) +{ + struct isl_union_pw_aff_reset_params_data data = { space }; + isl_bool match; + + match = isl_union_pw_aff_matching_params(upa, space); + if (match < 0) + upa = isl_union_pw_aff_free(upa); + else if (match) { + isl_space_free(space); + return upa; + } + + data.res = isl_union_pw_aff_empty(isl_space_copy(space)); + if (isl_union_pw_aff_foreach_pw_aff(upa, &reset_params, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + + isl_union_pw_aff_free(upa); + isl_space_free(space); + return data.res; +} + +/* Return the floor of "pa". + */ +static __isl_give isl_pw_aff *floor_entry(__isl_take isl_pw_aff *pa, void *user) +{ + return isl_pw_aff_floor(pa); +} + +/* Given f, return floor(f). + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_floor( + __isl_take isl_union_pw_aff *upa) +{ + return isl_union_pw_aff_transform_inplace(upa, &floor_entry, NULL); +} + +/* Compute + * + * upa mod m = upa - m * floor(upa/m) + * + * with m an integer value. + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val( + __isl_take isl_union_pw_aff *upa, __isl_take isl_val *m) +{ + isl_union_pw_aff *res; + + if (!upa || !m) + goto error; + + if (!isl_val_is_int(m)) + isl_die(isl_val_get_ctx(m), isl_error_invalid, + "expecting integer modulo", goto error); + if (!isl_val_is_pos(m)) + isl_die(isl_val_get_ctx(m), isl_error_invalid, + "expecting positive modulo", goto error); + + res = isl_union_pw_aff_copy(upa); + upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(m)); + upa = isl_union_pw_aff_floor(upa); + upa = isl_union_pw_aff_scale_val(upa, m); + res = isl_union_pw_aff_sub(res, upa); + + return res; +error: + isl_val_free(m); + isl_union_pw_aff_free(upa); + return NULL; +} + +/* Internal data structure for isl_union_pw_aff_aff_on_domain. + * "aff" is the symbolic value that the resulting isl_union_pw_aff + * needs to attain. + * "res" collects the results. + */ +struct isl_union_pw_aff_aff_on_domain_data { + isl_aff *aff; + isl_union_pw_aff *res; +}; + +/* Construct a piecewise affine expression that is equal to data->aff + * on "domain" and add the result to data->res. + */ +static isl_stat pw_aff_aff_on_domain(__isl_take isl_set *domain, void *user) +{ + struct isl_union_pw_aff_aff_on_domain_data *data = user; + isl_pw_aff *pa; + isl_aff *aff; + int dim; + + aff = isl_aff_copy(data->aff); + dim = isl_set_dim(domain, isl_dim_set); + aff = isl_aff_add_dims(aff, isl_dim_in, dim); + aff = isl_aff_reset_domain_space(aff, isl_set_get_space(domain)); + pa = isl_pw_aff_alloc(domain, aff); + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Internal data structure for isl_union_pw_multi_aff_get_union_pw_aff. + * pos is the output position that needs to be extracted. + * res collects the results. + */ +struct isl_union_pw_multi_aff_get_union_pw_aff_data { + int pos; + isl_union_pw_aff *res; +}; + +/* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma" + * (assuming it has such a dimension) and add it to data->res. + */ +static isl_stat get_union_pw_aff(__isl_take isl_pw_multi_aff *pma, void *user) +{ + struct isl_union_pw_multi_aff_get_union_pw_aff_data *data = user; + int n_out; + isl_pw_aff *pa; + + if (!pma) + return isl_stat_error; + + n_out = isl_pw_multi_aff_dim(pma, isl_dim_out); + if (data->pos >= n_out) { + isl_pw_multi_aff_free(pma); + return isl_stat_ok; + } + + pa = isl_pw_multi_aff_get_pw_aff(pma, data->pos); + isl_pw_multi_aff_free(pma); + + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Extract an isl_union_pw_aff corresponding to + * output dimension "pos" of "upma". + */ +__isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff( + __isl_keep isl_union_pw_multi_aff *upma, int pos) +{ + struct isl_union_pw_multi_aff_get_union_pw_aff_data data; + isl_space *space; + + if (!upma) + return NULL; + + if (pos < 0) + isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid, + "cannot extract at negative position", return NULL); + + space = isl_union_pw_multi_aff_get_space(upma); + data.res = isl_union_pw_aff_empty(space); + data.pos = pos; + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, + &get_union_pw_aff, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + + return data.res; +} + +/* Return a union piecewise affine expression + * that is equal to "aff" on "domain". + * + * Construct an isl_pw_aff on each of the sets in "domain" and + * collect the results. + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_aff *aff) +{ + struct isl_union_pw_aff_aff_on_domain_data data; + isl_space *space; + + if (!domain || !aff) + goto error; + if (!isl_local_space_is_params(aff->ls)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "expecting parametric expression", goto error); + + space = isl_union_set_get_space(domain); + data.res = isl_union_pw_aff_empty(space); + data.aff = aff; + if (isl_union_set_foreach_set(domain, &pw_aff_aff_on_domain, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + isl_union_set_free(domain); + isl_aff_free(aff); + return data.res; +error: + isl_union_set_free(domain); + isl_aff_free(aff); + return NULL; +} + +/* Internal data structure for isl_union_pw_aff_val_on_domain. + * "v" is the value that the resulting isl_union_pw_aff needs to attain. + * "res" collects the results. + */ +struct isl_union_pw_aff_val_on_domain_data { + isl_val *v; + isl_union_pw_aff *res; +}; + +/* Construct a piecewise affine expression that is equal to data->v + * on "domain" and add the result to data->res. + */ +static isl_stat pw_aff_val_on_domain(__isl_take isl_set *domain, void *user) +{ + struct isl_union_pw_aff_val_on_domain_data *data = user; + isl_pw_aff *pa; + isl_val *v; + + v = isl_val_copy(data->v); + pa = isl_pw_aff_val_on_domain(domain, v); + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Return a union piecewise affine expression + * that is equal to "v" on "domain". + * + * Construct an isl_pw_aff on each of the sets in "domain" and + * collect the results. + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_val *v) +{ + struct isl_union_pw_aff_val_on_domain_data data; + isl_space *space; + + space = isl_union_set_get_space(domain); + data.res = isl_union_pw_aff_empty(space); + data.v = v; + if (isl_union_set_foreach_set(domain, &pw_aff_val_on_domain, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + isl_union_set_free(domain); + isl_val_free(v); + return data.res; +} + +/* Construct a piecewise multi affine expression + * that is equal to "pa" and add it to upma. + */ +static isl_stat pw_multi_aff_from_pw_aff_entry(__isl_take isl_pw_aff *pa, + void *user) +{ + isl_union_pw_multi_aff **upma = user; + isl_pw_multi_aff *pma; + + pma = isl_pw_multi_aff_from_pw_aff(pa); + *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma); + + return *upma ? isl_stat_ok : isl_stat_error; +} + +/* Construct and return a union piecewise multi affine expression + * that is equal to the given union piecewise affine expression. + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa) +{ + isl_space *space; + isl_union_pw_multi_aff *upma; + + if (!upa) + return NULL; + + space = isl_union_pw_aff_get_space(upa); + upma = isl_union_pw_multi_aff_empty(space); + + if (isl_union_pw_aff_foreach_pw_aff(upa, + &pw_multi_aff_from_pw_aff_entry, &upma) < 0) + upma = isl_union_pw_multi_aff_free(upma); + + isl_union_pw_aff_free(upa); + return upma; +} + +/* Compute the set of elements in the domain of "pa" where it is zero and + * add this set to "uset". + */ +static isl_stat zero_union_set(__isl_take isl_pw_aff *pa, void *user) +{ + isl_union_set **uset = (isl_union_set **)user; + + *uset = isl_union_set_add_set(*uset, isl_pw_aff_zero_set(pa)); + + return *uset ? isl_stat_ok : isl_stat_error; +} + +/* Return a union set containing those elements in the domain + * of "upa" where it is zero. + */ +__isl_give isl_union_set *isl_union_pw_aff_zero_union_set( + __isl_take isl_union_pw_aff *upa) +{ + isl_union_set *zero; + + zero = isl_union_set_empty(isl_union_pw_aff_get_space(upa)); + if (isl_union_pw_aff_foreach_pw_aff(upa, &zero_union_set, &zero) < 0) + zero = isl_union_set_free(zero); + + isl_union_pw_aff_free(upa); + return zero; +} + +/* Convert "pa" to an isl_map and add it to *umap. + */ +static isl_stat map_from_pw_aff_entry(__isl_take isl_pw_aff *pa, void *user) +{ + isl_union_map **umap = user; + isl_map *map; + + map = isl_map_from_pw_aff(pa); + *umap = isl_union_map_add_map(*umap, map); + + return *umap ? isl_stat_ok : isl_stat_error; +} + +/* Construct a union map mapping the domain of the union + * piecewise affine expression to its range, with the single output dimension + * equated to the corresponding affine expressions on their cells. + */ +__isl_give isl_union_map *isl_union_map_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa) +{ + isl_space *space; + isl_union_map *umap; + + if (!upa) + return NULL; + + space = isl_union_pw_aff_get_space(upa); + umap = isl_union_map_empty(space); + + if (isl_union_pw_aff_foreach_pw_aff(upa, &map_from_pw_aff_entry, + &umap) < 0) + umap = isl_union_map_free(umap); + + isl_union_pw_aff_free(upa); + return umap; +} + +/* Internal data structure for isl_union_pw_aff_pullback_union_pw_multi_aff. + * upma is the function that is plugged in. + * pa is the current part of the function in which upma is plugged in. + * res collects the results. + */ +struct isl_union_pw_aff_pullback_upma_data { + isl_union_pw_multi_aff *upma; + isl_pw_aff *pa; + isl_union_pw_aff *res; +}; + +/* Check if "pma" can be plugged into data->pa. + * If so, perform the pullback and add the result to data->res. + */ +static isl_stat pa_pb_pma(__isl_take isl_pw_multi_aff *pma, void *user) +{ + struct isl_union_pw_aff_pullback_upma_data *data = user; + isl_pw_aff *pa; + + if (!isl_space_tuple_is_equal(data->pa->dim, isl_dim_in, + pma->dim, isl_dim_out)) { + isl_pw_multi_aff_free(pma); + return isl_stat_ok; + } + + pa = isl_pw_aff_copy(data->pa); + pa = isl_pw_aff_pullback_pw_multi_aff(pa, pma); + + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Check if any of the elements of data->upma can be plugged into pa, + * add if so add the result to data->res. + */ +static isl_stat upa_pb_upma(__isl_take isl_pw_aff *pa, void *user) +{ + struct isl_union_pw_aff_pullback_upma_data *data = user; + isl_stat r; + + data->pa = pa; + r = isl_union_pw_multi_aff_foreach_pw_multi_aff(data->upma, + &pa_pb_pma, data); + isl_pw_aff_free(pa); + + return r; +} + +/* Compute the pullback of "upa" by the function represented by "upma". + * In other words, plug in "upma" in "upa". The result contains + * expressions defined over the domain space of "upma". + * + * Run over all pairs of elements in "upa" and "upma", perform + * the pullback when appropriate and collect the results. + * If the hash value were based on the domain space rather than + * the function space, then we could run through all elements + * of "upma" and directly pick out the corresponding element of "upa". + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_pw_multi_aff *upma) +{ + struct isl_union_pw_aff_pullback_upma_data data = { NULL, NULL }; + isl_space *space; + + space = isl_union_pw_multi_aff_get_space(upma); + upa = isl_union_pw_aff_align_params(upa, space); + space = isl_union_pw_aff_get_space(upa); + upma = isl_union_pw_multi_aff_align_params(upma, space); + + if (!upa || !upma) + goto error; + + data.upma = upma; + data.res = isl_union_pw_aff_alloc_same_size(upa); + if (isl_union_pw_aff_foreach_pw_aff(upa, &upa_pb_upma, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + + isl_union_pw_aff_free(upa); + isl_union_pw_multi_aff_free(upma); + return data.res; +error: + isl_union_pw_aff_free(upa); + isl_union_pw_multi_aff_free(upma); + return NULL; +} + +#undef BASE +#define BASE union_pw_aff +#undef DOMBASE +#define DOMBASE union_set + +#define NO_MOVE_DIMS +#define NO_DIMS +#define NO_DOMAIN +#define NO_PRODUCT +#define NO_SPLICE +#define NO_ZERO +#define NO_IDENTITY +#define NO_GIST + +#include +#include +#include +#include +#include +#include +#include + +/* Construct a multiple union piecewise affine expression + * in the given space with value zero in each of the output dimensions. + * + * Since there is no canonical zero value for + * a union piecewise affine expression, we can only construct + * a zero-dimensional "zero" value. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_zero( + __isl_take isl_space *space) +{ + if (!space) + return NULL; + + if (!isl_space_is_set(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "expecting set space", goto error); + if (isl_space_dim(space , isl_dim_out) != 0) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "expecting 0D space", goto error); + + return isl_multi_union_pw_aff_alloc(space); +error: + isl_space_free(space); + return NULL; +} + +/* Compute the sum of "mupa1" and "mupa2" on the union of their domains, + * with the actual sum on the shared domain and + * the defined expression on the symmetric difference of the domains. + * + * We simply iterate over the elements in both arguments and + * call isl_union_pw_aff_union_add on each of them. + */ +static __isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_union_add_aligned( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2) +{ + return isl_multi_union_pw_aff_bin_op(mupa1, mupa2, + &isl_union_pw_aff_union_add); +} + +/* Compute the sum of "mupa1" and "mupa2" on the union of their domains, + * with the actual sum on the shared domain and + * the defined expression on the symmetric difference of the domains. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_union_add( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2) +{ + return isl_multi_union_pw_aff_align_params_multi_multi_and(mupa1, mupa2, + &isl_multi_union_pw_aff_union_add_aligned); +} + +/* Construct and return a multi union piecewise affine expression + * that is equal to the given multi affine expression. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma) +{ + isl_multi_pw_aff *mpa; + + mpa = isl_multi_pw_aff_from_multi_aff(ma); + return isl_multi_union_pw_aff_from_multi_pw_aff(mpa); +} + +/* Construct and return a multi union piecewise affine expression + * that is equal to the given multi piecewise affine expression. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa) +{ + int i, n; + isl_space *space; + isl_multi_union_pw_aff *mupa; + + if (!mpa) + return NULL; + + space = isl_multi_pw_aff_get_space(mpa); + space = isl_space_range(space); + mupa = isl_multi_union_pw_aff_alloc(space); + + n = isl_multi_pw_aff_dim(mpa, isl_dim_out); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + isl_union_pw_aff *upa; + + pa = isl_multi_pw_aff_get_pw_aff(mpa, i); + upa = isl_union_pw_aff_from_pw_aff(pa); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_multi_pw_aff_free(mpa); + + return mupa; +} + +/* Extract the range space of "pma" and assign it to *space. + * If *space has already been set (through a previous call to this function), + * then check that the range space is the same. + */ +static isl_stat extract_space(__isl_take isl_pw_multi_aff *pma, void *user) +{ + isl_space **space = user; + isl_space *pma_space; + isl_bool equal; + + pma_space = isl_space_range(isl_pw_multi_aff_get_space(pma)); + isl_pw_multi_aff_free(pma); + + if (!pma_space) + return isl_stat_error; + if (!*space) { + *space = pma_space; + return isl_stat_ok; + } + + equal = isl_space_is_equal(pma_space, *space); + isl_space_free(pma_space); + + if (equal < 0) + return isl_stat_error; + if (!equal) + isl_die(isl_space_get_ctx(*space), isl_error_invalid, + "range spaces not the same", return isl_stat_error); + return isl_stat_ok; +} + +/* Construct and return a multi union piecewise affine expression + * that is equal to the given union piecewise multi affine expression. + * + * In order to be able to perform the conversion, the input + * needs to be non-empty and may only involve a single range space. + */ +__isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma) +{ + isl_space *space = NULL; + isl_multi_union_pw_aff *mupa; + int i, n; + + if (!upma) + return NULL; + if (isl_union_pw_multi_aff_n_pw_multi_aff(upma) == 0) + isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid, + "cannot extract range space from empty input", + goto error); + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, &extract_space, + &space) < 0) + goto error; + + if (!space) + goto error; + + n = isl_space_dim(space, isl_dim_set); + mupa = isl_multi_union_pw_aff_alloc(space); + + for (i = 0; i < n; ++i) { + isl_union_pw_aff *upa; + + upa = isl_union_pw_multi_aff_get_union_pw_aff(upma, i); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_union_pw_multi_aff_free(upma); + return mupa; +error: + isl_space_free(space); + isl_union_pw_multi_aff_free(upma); + return NULL; +} + +/* Try and create an isl_multi_union_pw_aff that is equivalent + * to the given isl_union_map. + * The isl_union_map is required to be single-valued in each space. + * Moreover, it cannot be empty and all range spaces need to be the same. + * Otherwise, an error is produced. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map( + __isl_take isl_union_map *umap) +{ + isl_union_pw_multi_aff *upma; + + upma = isl_union_pw_multi_aff_from_union_map(umap); + return isl_multi_union_pw_aff_from_union_pw_multi_aff(upma); +} + +/* Return a multiple union piecewise affine expression + * that is equal to "mv" on "domain", assuming "domain" and "mv" + * have been aligned. + */ +static __isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_multi_val_on_domain_aligned( + __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv) +{ + int i, n; + isl_space *space; + isl_multi_union_pw_aff *mupa; + + if (!domain || !mv) + goto error; + + n = isl_multi_val_dim(mv, isl_dim_set); + space = isl_multi_val_get_space(mv); + mupa = isl_multi_union_pw_aff_alloc(space); + for (i = 0; i < n; ++i) { + isl_val *v; + isl_union_pw_aff *upa; + + v = isl_multi_val_get_val(mv, i); + upa = isl_union_pw_aff_val_on_domain(isl_union_set_copy(domain), + v); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_union_set_free(domain); + isl_multi_val_free(mv); + return mupa; +error: + isl_union_set_free(domain); + isl_multi_val_free(mv); + return NULL; +} + +/* Return a multiple union piecewise affine expression + * that is equal to "mv" on "domain". + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv) +{ + isl_bool equal_params; + + if (!domain || !mv) + goto error; + equal_params = isl_space_has_equal_params(domain->dim, mv->space); + if (equal_params < 0) + goto error; + if (equal_params) + return isl_multi_union_pw_aff_multi_val_on_domain_aligned( + domain, mv); + domain = isl_union_set_align_params(domain, + isl_multi_val_get_space(mv)); + mv = isl_multi_val_align_params(mv, isl_union_set_get_space(domain)); + return isl_multi_union_pw_aff_multi_val_on_domain_aligned(domain, mv); +error: + isl_union_set_free(domain); + isl_multi_val_free(mv); + return NULL; +} + +/* Return a multiple union piecewise affine expression + * that is equal to "ma" on "domain", assuming "domain" and "ma" + * have been aligned. + */ +static __isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_multi_aff_on_domain_aligned( + __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma) +{ + int i, n; + isl_space *space; + isl_multi_union_pw_aff *mupa; + + if (!domain || !ma) + goto error; + + n = isl_multi_aff_dim(ma, isl_dim_set); + space = isl_multi_aff_get_space(ma); + mupa = isl_multi_union_pw_aff_alloc(space); + for (i = 0; i < n; ++i) { + isl_aff *aff; + isl_union_pw_aff *upa; + + aff = isl_multi_aff_get_aff(ma, i); + upa = isl_union_pw_aff_aff_on_domain(isl_union_set_copy(domain), + aff); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_union_set_free(domain); + isl_multi_aff_free(ma); + return mupa; +error: + isl_union_set_free(domain); + isl_multi_aff_free(ma); + return NULL; +} + +/* Return a multiple union piecewise affine expression + * that is equal to "ma" on "domain". + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma) +{ + isl_bool equal_params; + + if (!domain || !ma) + goto error; + equal_params = isl_space_has_equal_params(domain->dim, ma->space); + if (equal_params < 0) + goto error; + if (equal_params) + return isl_multi_union_pw_aff_multi_aff_on_domain_aligned( + domain, ma); + domain = isl_union_set_align_params(domain, + isl_multi_aff_get_space(ma)); + ma = isl_multi_aff_align_params(ma, isl_union_set_get_space(domain)); + return isl_multi_union_pw_aff_multi_aff_on_domain_aligned(domain, ma); +error: + isl_union_set_free(domain); + isl_multi_aff_free(ma); + return NULL; +} + +/* Return a union set containing those elements in the domains + * of the elements of "mupa" where they are all zero. + */ +__isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set( + __isl_take isl_multi_union_pw_aff *mupa) +{ + int i, n; + isl_union_pw_aff *upa; + isl_union_set *zero; + + if (!mupa) + return NULL; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot determine zero set " + "of zero-dimensional function", goto error); + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0); + zero = isl_union_pw_aff_zero_union_set(upa); + + for (i = 1; i < n; ++i) { + isl_union_set *zero_i; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + zero_i = isl_union_pw_aff_zero_union_set(upa); + + zero = isl_union_set_intersect(zero, zero_i); + } + + isl_multi_union_pw_aff_free(mupa); + return zero; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Construct a union map mapping the shared domain + * of the union piecewise affine expressions to the range of "mupa" + * with each dimension in the range equated to the + * corresponding union piecewise affine expression. + * + * The input cannot be zero-dimensional as there is + * no way to extract a domain from a zero-dimensional isl_multi_union_pw_aff. + */ +__isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa) +{ + int i, n; + isl_space *space; + isl_union_map *umap; + isl_union_pw_aff *upa; + + if (!mupa) + return NULL; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot determine domain of zero-dimensional " + "isl_multi_union_pw_aff", goto error); + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0); + umap = isl_union_map_from_union_pw_aff(upa); + + for (i = 1; i < n; ++i) { + isl_union_map *umap_i; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + umap_i = isl_union_map_from_union_pw_aff(upa); + umap = isl_union_map_flat_range_product(umap, umap_i); + } + + space = isl_multi_union_pw_aff_get_space(mupa); + umap = isl_union_map_reset_range_space(umap, space); + + isl_multi_union_pw_aff_free(mupa); + return umap; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Internal data structure for isl_union_pw_multi_aff_reset_range_space. + * "range" is the space from which to set the range space. + * "res" collects the results. + */ +struct isl_union_pw_multi_aff_reset_range_space_data { + isl_space *range; + isl_union_pw_multi_aff *res; +}; + +/* Replace the range space of "pma" by the range space of data->range and + * add the result to data->res. + */ +static isl_stat reset_range_space(__isl_take isl_pw_multi_aff *pma, void *user) +{ + struct isl_union_pw_multi_aff_reset_range_space_data *data = user; + isl_space *space; + + space = isl_pw_multi_aff_get_space(pma); + space = isl_space_domain(space); + space = isl_space_extend_domain_with_range(space, + isl_space_copy(data->range)); + pma = isl_pw_multi_aff_reset_space(pma, space); + data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Replace the range space of all the piecewise affine expressions in "upma" by + * the range space of "space". + * + * This assumes that all these expressions have the same output dimension. + * + * Since the spaces of the expressions change, so do their hash values. + * We therefore need to create a new isl_union_pw_multi_aff. + * Note that the hash value is currently computed based on the entire + * space even though there can only be a single expression with a given + * domain space. + */ +static __isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_reset_range_space( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *space) +{ + struct isl_union_pw_multi_aff_reset_range_space_data data = { space }; + isl_space *space_upma; + + space_upma = isl_union_pw_multi_aff_get_space(upma); + data.res = isl_union_pw_multi_aff_empty(space_upma); + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, + &reset_range_space, &data) < 0) + data.res = isl_union_pw_multi_aff_free(data.res); + + isl_space_free(space); + isl_union_pw_multi_aff_free(upma); + return data.res; +} + +/* Construct and return a union piecewise multi affine expression + * that is equal to the given multi union piecewise affine expression. + * + * In order to be able to perform the conversion, the input + * needs to have a least one output dimension. + */ +__isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa) +{ + int i, n; + isl_space *space; + isl_union_pw_multi_aff *upma; + isl_union_pw_aff *upa; + + if (!mupa) + return NULL; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot determine domain of zero-dimensional " + "isl_multi_union_pw_aff", goto error); + + space = isl_multi_union_pw_aff_get_space(mupa); + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0); + upma = isl_union_pw_multi_aff_from_union_pw_aff(upa); + + for (i = 1; i < n; ++i) { + isl_union_pw_multi_aff *upma_i; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + upma_i = isl_union_pw_multi_aff_from_union_pw_aff(upa); + upma = isl_union_pw_multi_aff_flat_range_product(upma, upma_i); + } + + upma = isl_union_pw_multi_aff_reset_range_space(upma, space); + + isl_multi_union_pw_aff_free(mupa); + return upma; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Intersect the range of "mupa" with "range". + * That is, keep only those domain elements that have a function value + * in "range". + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range) +{ + isl_union_pw_multi_aff *upma; + isl_union_set *domain; + isl_space *space; + int n; + int match; + + if (!mupa || !range) + goto error; + + space = isl_set_get_space(range); + match = isl_space_tuple_is_equal(mupa->space, isl_dim_set, + space, isl_dim_set); + isl_space_free(space); + if (match < 0) + goto error; + if (!match) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "space don't match", goto error); + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot intersect range of zero-dimensional " + "isl_multi_union_pw_aff", goto error); + + upma = isl_union_pw_multi_aff_from_multi_union_pw_aff( + isl_multi_union_pw_aff_copy(mupa)); + domain = isl_union_set_from_set(range); + domain = isl_union_set_preimage_union_pw_multi_aff(domain, upma); + mupa = isl_multi_union_pw_aff_intersect_domain(mupa, domain); + + return mupa; +error: + isl_multi_union_pw_aff_free(mupa); + isl_set_free(range); + return NULL; +} + +/* Return the shared domain of the elements of "mupa". + */ +__isl_give isl_union_set *isl_multi_union_pw_aff_domain( + __isl_take isl_multi_union_pw_aff *mupa) +{ + int i, n; + isl_union_pw_aff *upa; + isl_union_set *dom; + + if (!mupa) + return NULL; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot determine domain", goto error); + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0); + dom = isl_union_pw_aff_domain(upa); + for (i = 1; i < n; ++i) { + isl_union_set *dom_i; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + dom_i = isl_union_pw_aff_domain(upa); + dom = isl_union_set_intersect(dom, dom_i); + } + + isl_multi_union_pw_aff_free(mupa); + return dom; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Apply "aff" to "mupa". The space of "mupa" is equal to the domain of "aff". + * In particular, the spaces have been aligned. + * The result is defined over the shared domain of the elements of "mupa" + * + * We first extract the parametric constant part of "aff" and + * define that over the shared domain. + * Then we iterate over all input dimensions of "aff" and add the corresponding + * multiples of the elements of "mupa". + * Finally, we consider the integer divisions, calling the function + * recursively to obtain an isl_union_pw_aff corresponding to the + * integer division argument. + */ +static __isl_give isl_union_pw_aff *multi_union_pw_aff_apply_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff) +{ + int i, n_in, n_div; + isl_union_pw_aff *upa; + isl_union_set *uset; + isl_val *v; + isl_aff *cst; + + n_in = isl_aff_dim(aff, isl_dim_in); + n_div = isl_aff_dim(aff, isl_dim_div); + + uset = isl_multi_union_pw_aff_domain(isl_multi_union_pw_aff_copy(mupa)); + cst = isl_aff_copy(aff); + cst = isl_aff_drop_dims(cst, isl_dim_div, 0, n_div); + cst = isl_aff_drop_dims(cst, isl_dim_in, 0, n_in); + cst = isl_aff_project_domain_on_params(cst); + upa = isl_union_pw_aff_aff_on_domain(uset, cst); + + for (i = 0; i < n_in; ++i) { + isl_union_pw_aff *upa_i; + + if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1)) + continue; + v = isl_aff_get_coefficient_val(aff, isl_dim_in, i); + upa_i = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + upa_i = isl_union_pw_aff_scale_val(upa_i, v); + upa = isl_union_pw_aff_add(upa, upa_i); + } + + for (i = 0; i < n_div; ++i) { + isl_aff *div; + isl_union_pw_aff *upa_i; + + if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1)) + continue; + div = isl_aff_get_div(aff, i); + upa_i = multi_union_pw_aff_apply_aff( + isl_multi_union_pw_aff_copy(mupa), div); + upa_i = isl_union_pw_aff_floor(upa_i); + v = isl_aff_get_coefficient_val(aff, isl_dim_div, i); + upa_i = isl_union_pw_aff_scale_val(upa_i, v); + upa = isl_union_pw_aff_add(upa, upa_i); + } + + isl_multi_union_pw_aff_free(mupa); + isl_aff_free(aff); + + return upa; +} + +/* Apply "aff" to "mupa". The space of "mupa" needs to be compatible + * with the domain of "aff". + * Furthermore, the dimension of this space needs to be greater than zero. + * The result is defined over the shared domain of the elements of "mupa" + * + * We perform these checks and then hand over control to + * multi_union_pw_aff_apply_aff. + */ +__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff) +{ + isl_space *space1, *space2; + int equal; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_aff_get_space(aff)); + aff = isl_aff_align_params(aff, isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !aff) + goto error; + + space1 = isl_multi_union_pw_aff_get_space(mupa); + space2 = isl_aff_get_domain_space(aff); + equal = isl_space_is_equal(space1, space2); + isl_space_free(space1); + isl_space_free(space2); + if (equal < 0) + goto error; + if (!equal) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "spaces don't match", goto error); + if (isl_aff_dim(aff, isl_dim_in) == 0) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "cannot determine domains", goto error); + + return multi_union_pw_aff_apply_aff(mupa, aff); +error: + isl_multi_union_pw_aff_free(mupa); + isl_aff_free(aff); + return NULL; +} + +/* Apply "ma" to "mupa". The space of "mupa" needs to be compatible + * with the domain of "ma". + * Furthermore, the dimension of this space needs to be greater than zero, + * unless the dimension of the target space of "ma" is also zero. + * The result is defined over the shared domain of the elements of "mupa" + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma) +{ + isl_space *space1, *space2; + isl_multi_union_pw_aff *res; + int equal; + int i, n_out; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_multi_aff_get_space(ma)); + ma = isl_multi_aff_align_params(ma, + isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !ma) + goto error; + + space1 = isl_multi_union_pw_aff_get_space(mupa); + space2 = isl_multi_aff_get_domain_space(ma); + equal = isl_space_is_equal(space1, space2); + isl_space_free(space1); + isl_space_free(space2); + if (equal < 0) + goto error; + if (!equal) + isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid, + "spaces don't match", goto error); + n_out = isl_multi_aff_dim(ma, isl_dim_out); + if (isl_multi_aff_dim(ma, isl_dim_in) == 0 && n_out != 0) + isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid, + "cannot determine domains", goto error); + + space1 = isl_space_range(isl_multi_aff_get_space(ma)); + res = isl_multi_union_pw_aff_alloc(space1); + + for (i = 0; i < n_out; ++i) { + isl_aff *aff; + isl_union_pw_aff *upa; + + aff = isl_multi_aff_get_aff(ma, i); + upa = multi_union_pw_aff_apply_aff( + isl_multi_union_pw_aff_copy(mupa), aff); + res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa); + } + + isl_multi_aff_free(ma); + isl_multi_union_pw_aff_free(mupa); + return res; +error: + isl_multi_union_pw_aff_free(mupa); + isl_multi_aff_free(ma); + return NULL; +} + +/* Apply "pa" to "mupa". The space of "mupa" needs to be compatible + * with the domain of "pa". + * Furthermore, the dimension of this space needs to be greater than zero. + * The result is defined over the shared domain of the elements of "mupa" + */ +__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa) +{ + int i; + int equal; + isl_space *space, *space2; + isl_union_pw_aff *upa; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_pw_aff_get_space(pa)); + pa = isl_pw_aff_align_params(pa, + isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !pa) + goto error; + + space = isl_multi_union_pw_aff_get_space(mupa); + space2 = isl_pw_aff_get_domain_space(pa); + equal = isl_space_is_equal(space, space2); + isl_space_free(space); + isl_space_free(space2); + if (equal < 0) + goto error; + if (!equal) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "spaces don't match", goto error); + if (isl_pw_aff_dim(pa, isl_dim_in) == 0) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "cannot determine domains", goto error); + + space = isl_space_params(isl_multi_union_pw_aff_get_space(mupa)); + upa = isl_union_pw_aff_empty(space); + + for (i = 0; i < pa->n; ++i) { + isl_aff *aff; + isl_set *domain; + isl_multi_union_pw_aff *mupa_i; + isl_union_pw_aff *upa_i; + + mupa_i = isl_multi_union_pw_aff_copy(mupa); + domain = isl_set_copy(pa->p[i].set); + mupa_i = isl_multi_union_pw_aff_intersect_range(mupa_i, domain); + aff = isl_aff_copy(pa->p[i].aff); + upa_i = multi_union_pw_aff_apply_aff(mupa_i, aff); + upa = isl_union_pw_aff_union_add(upa, upa_i); + } + + isl_multi_union_pw_aff_free(mupa); + isl_pw_aff_free(pa); + return upa; +error: + isl_multi_union_pw_aff_free(mupa); + isl_pw_aff_free(pa); + return NULL; +} + +/* Apply "pma" to "mupa". The space of "mupa" needs to be compatible + * with the domain of "pma". + * Furthermore, the dimension of this space needs to be greater than zero, + * unless the dimension of the target space of "pma" is also zero. + * The result is defined over the shared domain of the elements of "mupa" + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_pw_multi_aff *pma) +{ + isl_space *space1, *space2; + isl_multi_union_pw_aff *res; + int equal; + int i, n_out; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_pw_multi_aff_get_space(pma)); + pma = isl_pw_multi_aff_align_params(pma, + isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !pma) + goto error; + + space1 = isl_multi_union_pw_aff_get_space(mupa); + space2 = isl_pw_multi_aff_get_domain_space(pma); + equal = isl_space_is_equal(space1, space2); + isl_space_free(space1); + isl_space_free(space2); + if (equal < 0) + goto error; + if (!equal) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "spaces don't match", goto error); + n_out = isl_pw_multi_aff_dim(pma, isl_dim_out); + if (isl_pw_multi_aff_dim(pma, isl_dim_in) == 0 && n_out != 0) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "cannot determine domains", goto error); + + space1 = isl_space_range(isl_pw_multi_aff_get_space(pma)); + res = isl_multi_union_pw_aff_alloc(space1); + + for (i = 0; i < n_out; ++i) { + isl_pw_aff *pa; + isl_union_pw_aff *upa; + + pa = isl_pw_multi_aff_get_pw_aff(pma, i); + upa = isl_multi_union_pw_aff_apply_pw_aff( + isl_multi_union_pw_aff_copy(mupa), pa); + res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa); + } + + isl_pw_multi_aff_free(pma); + isl_multi_union_pw_aff_free(mupa); + return res; +error: + isl_multi_union_pw_aff_free(mupa); + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* Compute the pullback of "mupa" by the function represented by "upma". + * In other words, plug in "upma" in "mupa". The result contains + * expressions defined over the domain space of "upma". + * + * Run over all elements of "mupa" and plug in "upma" in each of them. + */ +__isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_pw_multi_aff *upma) +{ + int i, n; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_union_pw_multi_aff_get_space(upma)); + upma = isl_union_pw_multi_aff_align_params(upma, + isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !upma) + goto error; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_union_pw_aff *upa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + upa = isl_union_pw_aff_pullback_union_pw_multi_aff(upa, + isl_union_pw_multi_aff_copy(upma)); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_union_pw_multi_aff_free(upma); + return mupa; +error: + isl_multi_union_pw_aff_free(mupa); + isl_union_pw_multi_aff_free(upma); + return NULL; +} + +/* Extract the sequence of elements in "mupa" with domain space "space" + * (ignoring parameters). + * + * For the elements of "mupa" that are not defined on the specified space, + * the corresponding element in the result is empty. + */ +__isl_give isl_multi_pw_aff *isl_multi_union_pw_aff_extract_multi_pw_aff( + __isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space) +{ + int i, n; + isl_bool equal_params; + isl_space *space_mpa = NULL; + isl_multi_pw_aff *mpa; + + if (!mupa || !space) + goto error; + + space_mpa = isl_multi_union_pw_aff_get_space(mupa); + equal_params = isl_space_has_equal_params(space_mpa, space); + if (equal_params < 0) + goto error; + if (!equal_params) { + space = isl_space_drop_dims(space, isl_dim_param, + 0, isl_space_dim(space, isl_dim_param)); + space = isl_space_align_params(space, + isl_space_copy(space_mpa)); + if (!space) + goto error; + } + space_mpa = isl_space_map_from_domain_and_range(isl_space_copy(space), + space_mpa); + mpa = isl_multi_pw_aff_alloc(space_mpa); + + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, 1); + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_union_pw_aff *upa; + isl_pw_aff *pa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + pa = isl_union_pw_aff_extract_pw_aff(upa, + isl_space_copy(space)); + mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa); + isl_union_pw_aff_free(upa); + } + + isl_space_free(space); + return mpa; +error: + isl_space_free(space_mpa); + isl_space_free(space); + return NULL; +} Index: contrib/isl/isl_aff_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_aff_private.h @@ -0,0 +1,180 @@ +#ifndef ISL_AFF_PRIVATE_H +#define ISL_AFF_PRIVATE_H + +#include +#include +#include +#include +#include +#include + +/* ls represents the domain space. + * + * If the first two elements of "v" (the denominator and the constant term) + * are zero, then the isl_aff represents NaN. + */ +struct isl_aff { + int ref; + + isl_local_space *ls; + isl_vec *v; +}; + +#undef EL +#define EL isl_aff + +#include + +struct isl_pw_aff_piece { + struct isl_set *set; + struct isl_aff *aff; +}; + +struct isl_pw_aff { + int ref; + + isl_space *dim; + + int n; + + size_t size; + struct isl_pw_aff_piece p[1]; +}; + +#undef EL +#define EL isl_pw_aff + +#include + +struct isl_pw_multi_aff_piece { + isl_set *set; + isl_multi_aff *maff; +}; + +struct isl_pw_multi_aff { + int ref; + + isl_space *dim; + + int n; + + size_t size; + struct isl_pw_multi_aff_piece p[1]; +}; + +__isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls, + __isl_take isl_vec *v); +__isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls); + +__isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff, + __isl_take isl_space *space, __isl_take isl_space *domain); +__isl_give isl_aff *isl_aff_reset_domain_space(__isl_take isl_aff *aff, + __isl_take isl_space *dim); +__isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff, + __isl_take isl_reordering *r); + +__isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_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_add_constant(__isl_take isl_aff *aff, isl_int v); + +int isl_aff_plain_cmp(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2); + +__isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff); + +__isl_give isl_aff *isl_aff_expand_divs( __isl_take isl_aff *aff, + __isl_take isl_mat *div, int *exp); + +__isl_give isl_pw_aff *isl_pw_aff_alloc_size(__isl_take isl_space *space, + int n); +__isl_give isl_pw_aff *isl_pw_aff_reset_space(__isl_take isl_pw_aff *pwaff, + __isl_take isl_space *dim); +__isl_give isl_pw_aff *isl_pw_aff_reset_domain_space( + __isl_take isl_pw_aff *pwaff, __isl_take isl_space *space); +__isl_give isl_pw_aff *isl_pw_aff_add_disjoint( + __isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); + +__isl_give isl_pw_aff *isl_pw_aff_union_opt(__isl_take isl_pw_aff *pwaff1, + __isl_take isl_pw_aff *pwaff2, int max); + +__isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff); +__isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational( + __isl_take isl_pw_aff_list *list); + +__isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f); +__isl_give isl_pw_aff *isl_pw_aff_scale(__isl_take isl_pw_aff *pwaff, + isl_int f); +__isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff, + isl_int f); + +isl_bool isl_aff_matching_params(__isl_keep isl_aff *aff, + __isl_keep isl_space *space); +isl_stat isl_aff_check_match_domain_space(__isl_keep isl_aff *aff, + __isl_keep isl_space *space); + +#undef BASE +#define BASE aff + +#include + +__isl_give isl_multi_aff *isl_multi_aff_dup(__isl_keep isl_multi_aff *multi); + +__isl_give isl_multi_aff *isl_multi_aff_align_divs( + __isl_take isl_multi_aff *maff); + +__isl_give isl_multi_aff *isl_multi_aff_from_basic_set_equalities( + __isl_take isl_basic_set *bset); + +__isl_give isl_multi_aff *isl_multi_aff_from_aff_mat( + __isl_take isl_space *space, __isl_take isl_mat *mat); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_domain_space( + __isl_take isl_pw_multi_aff *pwmaff, __isl_take isl_space *space); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_space( + __isl_take isl_pw_multi_aff *pwmaff, __isl_take isl_space *space); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_add_disjoint( + __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out( + __isl_take isl_pw_multi_aff *pma, + enum isl_dim_type type, unsigned first, unsigned n); + +void isl_seq_preimage(isl_int *dst, isl_int *src, + __isl_keep isl_multi_aff *ma, int n_before, int n_after, + int n_div_ma, int n_div_bmap, + isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom); + +__isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff, + __isl_take isl_basic_set *eq); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute( + __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, unsigned pos, + __isl_keep isl_pw_aff *subs); + +isl_bool isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa, + __isl_keep isl_space *space); +isl_stat isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa, + __isl_keep isl_space *space); + +__isl_give isl_basic_set *isl_aff_pos_basic_set(__isl_take isl_aff *aff); + +#undef BASE +#define BASE pw_aff + +#include + +#undef EL +#define EL isl_union_pw_aff + +#include + +#undef BASE +#define BASE union_pw_aff + +#include + +#undef EL +#define EL isl_union_pw_multi_aff + +#include + +#endif Index: contrib/isl/isl_affine_hull.c =================================================================== --- /dev/null +++ contrib/isl/isl_affine_hull.c @@ -0,0 +1,1220 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2012 Ecole Normale Superieure + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include "isl_equalities.h" +#include "isl_sample.h" +#include "isl_tab.h" +#include +#include + +#include +#include +#include +#include + +__isl_give isl_basic_map *isl_basic_map_implicit_equalities( + __isl_take isl_basic_map *bmap) +{ + struct isl_tab *tab; + + if (!bmap) + return bmap; + + bmap = isl_basic_map_gauss(bmap, NULL); + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) + return bmap; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NO_IMPLICIT)) + return bmap; + if (bmap->n_ineq <= 1) + return bmap; + + tab = isl_tab_from_basic_map(bmap, 0); + if (isl_tab_detect_implicit_equalities(tab) < 0) + goto error; + bmap = isl_basic_map_update_from_tab(bmap, tab); + isl_tab_free(tab); + bmap = isl_basic_map_gauss(bmap, NULL); + ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT); + return bmap; +error: + isl_tab_free(tab); + isl_basic_map_free(bmap); + return NULL; +} + +struct isl_basic_set *isl_basic_set_implicit_equalities( + struct isl_basic_set *bset) +{ + return bset_from_bmap( + isl_basic_map_implicit_equalities(bset_to_bmap(bset))); +} + +/* Make eq[row][col] of both bmaps equal so we can add the row + * add the column to the common matrix. + * Note that because of the echelon form, the columns of row row + * after column col are zero. + */ +static void set_common_multiple( + struct isl_basic_set *bset1, struct isl_basic_set *bset2, + unsigned row, unsigned col) +{ + isl_int m, c; + + if (isl_int_eq(bset1->eq[row][col], bset2->eq[row][col])) + return; + + isl_int_init(c); + isl_int_init(m); + isl_int_lcm(m, bset1->eq[row][col], bset2->eq[row][col]); + isl_int_divexact(c, m, bset1->eq[row][col]); + isl_seq_scale(bset1->eq[row], bset1->eq[row], c, col+1); + isl_int_divexact(c, m, bset2->eq[row][col]); + isl_seq_scale(bset2->eq[row], bset2->eq[row], c, col+1); + isl_int_clear(c); + isl_int_clear(m); +} + +/* Delete a given equality, moving all the following equalities one up. + */ +static void delete_row(struct isl_basic_set *bset, unsigned row) +{ + isl_int *t; + int r; + + t = bset->eq[row]; + bset->n_eq--; + for (r = row; r < bset->n_eq; ++r) + bset->eq[r] = bset->eq[r+1]; + bset->eq[bset->n_eq] = t; +} + +/* Make first row entries in column col of bset1 identical to + * those of bset2, using the fact that entry bset1->eq[row][col]=a + * is non-zero. Initially, these elements of bset1 are all zero. + * For each row i < row, we set + * A[i] = a * A[i] + B[i][col] * A[row] + * B[i] = a * B[i] + * so that + * A[i][col] = B[i][col] = a * old(B[i][col]) + */ +static void construct_column( + struct isl_basic_set *bset1, struct isl_basic_set *bset2, + unsigned row, unsigned col) +{ + int r; + isl_int a; + isl_int b; + unsigned total; + + isl_int_init(a); + isl_int_init(b); + total = 1 + isl_basic_set_n_dim(bset1); + for (r = 0; r < row; ++r) { + if (isl_int_is_zero(bset2->eq[r][col])) + continue; + isl_int_gcd(b, bset2->eq[r][col], bset1->eq[row][col]); + isl_int_divexact(a, bset1->eq[row][col], b); + isl_int_divexact(b, bset2->eq[r][col], b); + isl_seq_combine(bset1->eq[r], a, bset1->eq[r], + b, bset1->eq[row], total); + isl_seq_scale(bset2->eq[r], bset2->eq[r], a, total); + } + isl_int_clear(a); + isl_int_clear(b); + delete_row(bset1, row); +} + +/* Make first row entries in column col of bset1 identical to + * those of bset2, using only these entries of the two matrices. + * Let t be the last row with different entries. + * For each row i < t, we set + * A[i] = (A[t][col]-B[t][col]) * A[i] + (B[i][col]-A[i][col) * A[t] + * B[i] = (A[t][col]-B[t][col]) * B[i] + (B[i][col]-A[i][col) * B[t] + * so that + * A[i][col] = B[i][col] = old(A[t][col]*B[i][col]-A[i][col]*B[t][col]) + */ +static int transform_column( + struct isl_basic_set *bset1, struct isl_basic_set *bset2, + unsigned row, unsigned col) +{ + int i, t; + isl_int a, b, g; + unsigned total; + + for (t = row-1; t >= 0; --t) + if (isl_int_ne(bset1->eq[t][col], bset2->eq[t][col])) + break; + if (t < 0) + return 0; + + total = 1 + isl_basic_set_n_dim(bset1); + isl_int_init(a); + isl_int_init(b); + isl_int_init(g); + isl_int_sub(b, bset1->eq[t][col], bset2->eq[t][col]); + for (i = 0; i < t; ++i) { + isl_int_sub(a, bset2->eq[i][col], bset1->eq[i][col]); + isl_int_gcd(g, a, b); + isl_int_divexact(a, a, g); + isl_int_divexact(g, b, g); + isl_seq_combine(bset1->eq[i], g, bset1->eq[i], a, bset1->eq[t], + total); + isl_seq_combine(bset2->eq[i], g, bset2->eq[i], a, bset2->eq[t], + total); + } + isl_int_clear(a); + isl_int_clear(b); + isl_int_clear(g); + delete_row(bset1, t); + delete_row(bset2, t); + return 1; +} + +/* The implementation is based on Section 5.2 of Michael Karr, + * "Affine Relationships Among Variables of a Program", + * except that the echelon form we use starts from the last column + * and that we are dealing with integer coefficients. + */ +static struct isl_basic_set *affine_hull( + struct isl_basic_set *bset1, struct isl_basic_set *bset2) +{ + unsigned total; + int col; + int row; + + if (!bset1 || !bset2) + goto error; + + total = 1 + isl_basic_set_n_dim(bset1); + + row = 0; + for (col = total-1; col >= 0; --col) { + int is_zero1 = row >= bset1->n_eq || + isl_int_is_zero(bset1->eq[row][col]); + int is_zero2 = row >= bset2->n_eq || + isl_int_is_zero(bset2->eq[row][col]); + if (!is_zero1 && !is_zero2) { + set_common_multiple(bset1, bset2, row, col); + ++row; + } else if (!is_zero1 && is_zero2) { + construct_column(bset1, bset2, row, col); + } else if (is_zero1 && !is_zero2) { + construct_column(bset2, bset1, row, col); + } else { + if (transform_column(bset1, bset2, row, col)) + --row; + } + } + isl_assert(bset1->ctx, row == bset1->n_eq, goto error); + isl_basic_set_free(bset2); + bset1 = isl_basic_set_normalize_constraints(bset1); + return bset1; +error: + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return NULL; +} + +/* Find an integer point in the set represented by "tab" + * that lies outside of the equality "eq" e(x) = 0. + * If "up" is true, look for a point satisfying e(x) - 1 >= 0. + * Otherwise, look for a point satisfying -e(x) - 1 >= 0 (i.e., e(x) <= -1). + * The point, if found, is returned. + * If no point can be found, a zero-length vector is returned. + * + * Before solving an ILP problem, we first check if simply + * adding the normal of the constraint to one of the known + * integer points in the basic set represented by "tab" + * yields another point inside the basic set. + * + * The caller of this function ensures that the tableau is bounded or + * that tab->basis and tab->n_unbounded have been set appropriately. + */ +static struct isl_vec *outside_point(struct isl_tab *tab, isl_int *eq, int up) +{ + struct isl_ctx *ctx; + struct isl_vec *sample = NULL; + struct isl_tab_undo *snap; + unsigned dim; + + if (!tab) + return NULL; + ctx = tab->mat->ctx; + + dim = tab->n_var; + sample = isl_vec_alloc(ctx, 1 + dim); + if (!sample) + return NULL; + isl_int_set_si(sample->el[0], 1); + isl_seq_combine(sample->el + 1, + ctx->one, tab->bmap->sample->el + 1, + up ? ctx->one : ctx->negone, eq + 1, dim); + if (isl_basic_map_contains(tab->bmap, sample)) + return sample; + isl_vec_free(sample); + sample = NULL; + + snap = isl_tab_snap(tab); + + if (!up) + isl_seq_neg(eq, eq, 1 + dim); + isl_int_sub_ui(eq[0], eq[0], 1); + + if (isl_tab_extend_cons(tab, 1) < 0) + goto error; + if (isl_tab_add_ineq(tab, eq) < 0) + goto error; + + sample = isl_tab_sample(tab); + + isl_int_add_ui(eq[0], eq[0], 1); + if (!up) + isl_seq_neg(eq, eq, 1 + dim); + + if (sample && isl_tab_rollback(tab, snap) < 0) + goto error; + + return sample; +error: + isl_vec_free(sample); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_recession_cone( + __isl_take isl_basic_set *bset) +{ + int i; + + bset = isl_basic_set_cow(bset); + if (!bset) + return NULL; + isl_assert(bset->ctx, bset->n_div == 0, goto error); + + for (i = 0; i < bset->n_eq; ++i) + isl_int_set_si(bset->eq[i][0], 0); + + for (i = 0; i < bset->n_ineq; ++i) + isl_int_set_si(bset->ineq[i][0], 0); + + ISL_F_CLR(bset, ISL_BASIC_SET_NO_IMPLICIT); + return isl_basic_set_implicit_equalities(bset); +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Move "sample" to a point that is one up (or down) from the original + * point in dimension "pos". + */ +static void adjacent_point(__isl_keep isl_vec *sample, int pos, int up) +{ + if (up) + isl_int_add_ui(sample->el[1 + pos], sample->el[1 + pos], 1); + else + isl_int_sub_ui(sample->el[1 + pos], sample->el[1 + pos], 1); +} + +/* Check if any points that are adjacent to "sample" also belong to "bset". + * If so, add them to "hull" and return the updated hull. + * + * Before checking whether and adjacent point belongs to "bset", we first + * check whether it already belongs to "hull" as this test is typically + * much cheaper. + */ +static __isl_give isl_basic_set *add_adjacent_points( + __isl_take isl_basic_set *hull, __isl_take isl_vec *sample, + __isl_keep isl_basic_set *bset) +{ + int i, up; + int dim; + + if (!sample) + goto error; + + dim = isl_basic_set_dim(hull, isl_dim_set); + + for (i = 0; i < dim; ++i) { + for (up = 0; up <= 1; ++up) { + int contains; + isl_basic_set *point; + + adjacent_point(sample, i, up); + contains = isl_basic_set_contains(hull, sample); + if (contains < 0) + goto error; + if (contains) { + adjacent_point(sample, i, !up); + continue; + } + contains = isl_basic_set_contains(bset, sample); + if (contains < 0) + goto error; + if (contains) { + point = isl_basic_set_from_vec( + isl_vec_copy(sample)); + hull = affine_hull(hull, point); + } + adjacent_point(sample, i, !up); + if (contains) + break; + } + } + + isl_vec_free(sample); + + return hull; +error: + isl_vec_free(sample); + isl_basic_set_free(hull); + return NULL; +} + +/* Extend an initial (under-)approximation of the affine hull of basic + * set represented by the tableau "tab" + * by looking for points that do not satisfy one of the equalities + * in the current approximation and adding them to that approximation + * until no such points can be found any more. + * + * The caller of this function ensures that "tab" is bounded or + * that tab->basis and tab->n_unbounded have been set appropriately. + * + * "bset" may be either NULL or the basic set represented by "tab". + * If "bset" is not NULL, we check for any point we find if any + * of its adjacent points also belong to "bset". + */ +static __isl_give isl_basic_set *extend_affine_hull(struct isl_tab *tab, + __isl_take isl_basic_set *hull, __isl_keep isl_basic_set *bset) +{ + int i, j; + unsigned dim; + + if (!tab || !hull) + goto error; + + dim = tab->n_var; + + if (isl_tab_extend_cons(tab, 2 * dim + 1) < 0) + goto error; + + for (i = 0; i < dim; ++i) { + struct isl_vec *sample; + struct isl_basic_set *point; + for (j = 0; j < hull->n_eq; ++j) { + sample = outside_point(tab, hull->eq[j], 1); + if (!sample) + goto error; + if (sample->size > 0) + break; + isl_vec_free(sample); + sample = outside_point(tab, hull->eq[j], 0); + if (!sample) + goto error; + if (sample->size > 0) + break; + isl_vec_free(sample); + + if (isl_tab_add_eq(tab, hull->eq[j]) < 0) + goto error; + } + if (j == hull->n_eq) + break; + if (tab->samples && + isl_tab_add_sample(tab, isl_vec_copy(sample)) < 0) + hull = isl_basic_set_free(hull); + if (bset) + hull = add_adjacent_points(hull, isl_vec_copy(sample), + bset); + point = isl_basic_set_from_vec(sample); + hull = affine_hull(hull, point); + if (!hull) + return NULL; + } + + return hull; +error: + isl_basic_set_free(hull); + return NULL; +} + +/* Construct an initial underapproximation of the hull of "bset" + * from "sample" and any of its adjacent points that also belong to "bset". + */ +static __isl_give isl_basic_set *initialize_hull(__isl_keep isl_basic_set *bset, + __isl_take isl_vec *sample) +{ + isl_basic_set *hull; + + hull = isl_basic_set_from_vec(isl_vec_copy(sample)); + hull = add_adjacent_points(hull, sample, bset); + + return hull; +} + +/* Look for all equalities satisfied by the integer points in bset, + * which is assumed to be bounded. + * + * The equalities are obtained by successively looking for + * a point that is affinely independent of the points found so far. + * In particular, for each equality satisfied by the points so far, + * we check if there is any point on a hyperplane parallel to the + * corresponding hyperplane shifted by at least one (in either direction). + */ +static struct isl_basic_set *uset_affine_hull_bounded(struct isl_basic_set *bset) +{ + struct isl_vec *sample = NULL; + struct isl_basic_set *hull; + struct isl_tab *tab = NULL; + unsigned dim; + + if (isl_basic_set_plain_is_empty(bset)) + return bset; + + dim = isl_basic_set_n_dim(bset); + + if (bset->sample && bset->sample->size == 1 + dim) { + int contains = isl_basic_set_contains(bset, bset->sample); + if (contains < 0) + goto error; + if (contains) { + if (dim == 0) + return bset; + sample = isl_vec_copy(bset->sample); + } else { + isl_vec_free(bset->sample); + bset->sample = NULL; + } + } + + tab = isl_tab_from_basic_set(bset, 1); + if (!tab) + goto error; + if (tab->empty) { + isl_tab_free(tab); + isl_vec_free(sample); + return isl_basic_set_set_to_empty(bset); + } + + if (!sample) { + struct isl_tab_undo *snap; + snap = isl_tab_snap(tab); + sample = isl_tab_sample(tab); + if (isl_tab_rollback(tab, snap) < 0) + goto error; + isl_vec_free(tab->bmap->sample); + tab->bmap->sample = isl_vec_copy(sample); + } + + if (!sample) + goto error; + if (sample->size == 0) { + isl_tab_free(tab); + isl_vec_free(sample); + return isl_basic_set_set_to_empty(bset); + } + + hull = initialize_hull(bset, sample); + + hull = extend_affine_hull(tab, hull, bset); + isl_basic_set_free(bset); + isl_tab_free(tab); + + return hull; +error: + isl_vec_free(sample); + isl_tab_free(tab); + isl_basic_set_free(bset); + return NULL; +} + +/* Given an unbounded tableau and an integer point satisfying the tableau, + * construct an initial affine hull containing the recession cone + * shifted to the given point. + * + * The unbounded directions are taken from the last rows of the basis, + * which is assumed to have been initialized appropriately. + */ +static __isl_give isl_basic_set *initial_hull(struct isl_tab *tab, + __isl_take isl_vec *vec) +{ + int i; + int k; + struct isl_basic_set *bset = NULL; + struct isl_ctx *ctx; + unsigned dim; + + if (!vec || !tab) + return NULL; + ctx = vec->ctx; + isl_assert(ctx, vec->size != 0, goto error); + + bset = isl_basic_set_alloc(ctx, 0, vec->size - 1, 0, vec->size - 1, 0); + if (!bset) + goto error; + dim = isl_basic_set_n_dim(bset) - tab->n_unbounded; + for (i = 0; i < dim; ++i) { + k = isl_basic_set_alloc_equality(bset); + if (k < 0) + goto error; + isl_seq_cpy(bset->eq[k] + 1, tab->basis->row[1 + i] + 1, + vec->size - 1); + isl_seq_inner_product(bset->eq[k] + 1, vec->el +1, + vec->size - 1, &bset->eq[k][0]); + isl_int_neg(bset->eq[k][0], bset->eq[k][0]); + } + bset->sample = vec; + bset = isl_basic_set_gauss(bset, NULL); + + return bset; +error: + isl_basic_set_free(bset); + isl_vec_free(vec); + return NULL; +} + +/* Given a tableau of a set and a tableau of the corresponding + * recession cone, detect and add all equalities to the tableau. + * If the tableau is bounded, then we can simply keep the + * tableau in its state after the return from extend_affine_hull. + * However, if the tableau is unbounded, then + * isl_tab_set_initial_basis_with_cone will add some additional + * constraints to the tableau that have to be removed again. + * In this case, we therefore rollback to the state before + * any constraints were added and then add the equalities back in. + */ +struct isl_tab *isl_tab_detect_equalities(struct isl_tab *tab, + struct isl_tab *tab_cone) +{ + int j; + struct isl_vec *sample; + struct isl_basic_set *hull = NULL; + struct isl_tab_undo *snap; + + if (!tab || !tab_cone) + goto error; + + snap = isl_tab_snap(tab); + + isl_mat_free(tab->basis); + tab->basis = NULL; + + isl_assert(tab->mat->ctx, tab->bmap, goto error); + isl_assert(tab->mat->ctx, tab->samples, goto error); + isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, goto error); + isl_assert(tab->mat->ctx, tab->n_sample > tab->n_outside, goto error); + + if (isl_tab_set_initial_basis_with_cone(tab, tab_cone) < 0) + goto error; + + sample = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var); + if (!sample) + goto error; + + isl_seq_cpy(sample->el, tab->samples->row[tab->n_outside], sample->size); + + isl_vec_free(tab->bmap->sample); + tab->bmap->sample = isl_vec_copy(sample); + + if (tab->n_unbounded == 0) + hull = isl_basic_set_from_vec(isl_vec_copy(sample)); + else + hull = initial_hull(tab, isl_vec_copy(sample)); + + for (j = tab->n_outside + 1; j < tab->n_sample; ++j) { + isl_seq_cpy(sample->el, tab->samples->row[j], sample->size); + hull = affine_hull(hull, + isl_basic_set_from_vec(isl_vec_copy(sample))); + } + + isl_vec_free(sample); + + hull = extend_affine_hull(tab, hull, NULL); + if (!hull) + goto error; + + if (tab->n_unbounded == 0) { + isl_basic_set_free(hull); + return tab; + } + + if (isl_tab_rollback(tab, snap) < 0) + goto error; + + if (hull->n_eq > tab->n_zero) { + for (j = 0; j < hull->n_eq; ++j) { + isl_seq_normalize(tab->mat->ctx, hull->eq[j], 1 + tab->n_var); + if (isl_tab_add_eq(tab, hull->eq[j]) < 0) + goto error; + } + } + + isl_basic_set_free(hull); + + return tab; +error: + isl_basic_set_free(hull); + isl_tab_free(tab); + return NULL; +} + +/* Compute the affine hull of "bset", where "cone" is the recession cone + * of "bset". + * + * We first compute a unimodular transformation that puts the unbounded + * directions in the last dimensions. In particular, we take a transformation + * that maps all equalities to equalities (in HNF) on the first dimensions. + * Let x be the original dimensions and y the transformed, with y_1 bounded + * and y_2 unbounded. + * + * [ y_1 ] [ y_1 ] [ Q_1 ] + * x = U [ y_2 ] [ y_2 ] = [ Q_2 ] x + * + * Let's call the input basic set S. We compute S' = preimage(S, U) + * and drop the final dimensions including any constraints involving them. + * This results in set S''. + * Then we compute the affine hull A'' of S''. + * Let F y_1 >= g be the constraint system of A''. In the transformed + * space the y_2 are unbounded, so we can add them back without any constraints, + * resulting in + * + * [ y_1 ] + * [ F 0 ] [ y_2 ] >= g + * or + * [ Q_1 ] + * [ F 0 ] [ Q_2 ] x >= g + * or + * F Q_1 x >= g + * + * The affine hull in the original space is then obtained as + * A = preimage(A'', Q_1). + */ +static struct isl_basic_set *affine_hull_with_cone(struct isl_basic_set *bset, + struct isl_basic_set *cone) +{ + unsigned total; + unsigned cone_dim; + struct isl_basic_set *hull; + struct isl_mat *M, *U, *Q; + + if (!bset || !cone) + goto error; + + total = isl_basic_set_total_dim(cone); + cone_dim = total - cone->n_eq; + + 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; + isl_mat_free(M); + + U = isl_mat_lin_to_aff(U); + bset = isl_basic_set_preimage(bset, isl_mat_copy(U)); + + bset = isl_basic_set_drop_constraints_involving(bset, total - cone_dim, + cone_dim); + bset = isl_basic_set_drop_dims(bset, total - cone_dim, cone_dim); + + Q = isl_mat_lin_to_aff(Q); + Q = isl_mat_drop_rows(Q, 1 + total - cone_dim, cone_dim); + + if (bset && bset->sample && bset->sample->size == 1 + total) + bset->sample = isl_mat_vec_product(isl_mat_copy(Q), bset->sample); + + hull = uset_affine_hull_bounded(bset); + + if (!hull) { + isl_mat_free(Q); + isl_mat_free(U); + } else { + struct isl_vec *sample = isl_vec_copy(hull->sample); + U = isl_mat_drop_cols(U, 1 + total - cone_dim, cone_dim); + if (sample && sample->size > 0) + sample = isl_mat_vec_product(U, sample); + else + isl_mat_free(U); + hull = isl_basic_set_preimage(hull, Q); + if (hull) { + isl_vec_free(hull->sample); + hull->sample = sample; + } else + isl_vec_free(sample); + } + + isl_basic_set_free(cone); + + return hull; +error: + isl_basic_set_free(bset); + isl_basic_set_free(cone); + return NULL; +} + +/* Look for all equalities satisfied by the integer points in bset, + * which is assumed not to have any explicit equalities. + * + * The equalities are obtained by successively looking for + * a point that is affinely independent of the points found so far. + * In particular, for each equality satisfied by the points so far, + * we check if there is any point on a hyperplane parallel to the + * corresponding hyperplane shifted by at least one (in either direction). + * + * Before looking for any outside points, we first compute the recession + * cone. The directions of this recession cone will always be part + * of the affine hull, so there is no need for looking for any points + * in these directions. + * In particular, if the recession cone is full-dimensional, then + * the affine hull is simply the whole universe. + */ +static struct isl_basic_set *uset_affine_hull(struct isl_basic_set *bset) +{ + struct isl_basic_set *cone; + + if (isl_basic_set_plain_is_empty(bset)) + return bset; + + cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset)); + if (!cone) + goto error; + if (cone->n_eq == 0) { + isl_space *space; + space = isl_basic_set_get_space(bset); + isl_basic_set_free(cone); + isl_basic_set_free(bset); + return isl_basic_set_universe(space); + } + + if (cone->n_eq < isl_basic_set_total_dim(cone)) + return affine_hull_with_cone(bset, cone); + + isl_basic_set_free(cone); + return uset_affine_hull_bounded(bset); +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Look for all equalities satisfied by the integer points in bmap + * that are independent of the equalities already explicitly available + * in bmap. + * + * We first remove all equalities already explicitly available, + * then look for additional equalities in the reduced space + * and then transform the result to the original space. + * The original equalities are _not_ added to this set. This is + * the responsibility of the calling function. + * The resulting basic set has all meaning about the dimensions removed. + * In particular, dimensions that correspond to existential variables + * in bmap and that are found to be fixed are not removed. + */ +static struct isl_basic_set *equalities_in_underlying_set( + struct isl_basic_map *bmap) +{ + struct isl_mat *T1 = NULL; + struct isl_mat *T2 = NULL; + struct isl_basic_set *bset = NULL; + struct isl_basic_set *hull = NULL; + + bset = isl_basic_map_underlying_set(bmap); + if (!bset) + return NULL; + if (bset->n_eq) + bset = isl_basic_set_remove_equalities(bset, &T1, &T2); + if (!bset) + goto error; + + hull = uset_affine_hull(bset); + if (!T2) + return hull; + + if (!hull) { + isl_mat_free(T1); + isl_mat_free(T2); + } else { + struct isl_vec *sample = isl_vec_copy(hull->sample); + if (sample && sample->size > 0) + sample = isl_mat_vec_product(T1, sample); + else + isl_mat_free(T1); + hull = isl_basic_set_preimage(hull, T2); + if (hull) { + isl_vec_free(hull->sample); + hull->sample = sample; + } else + isl_vec_free(sample); + } + + return hull; +error: + isl_mat_free(T1); + isl_mat_free(T2); + isl_basic_set_free(bset); + isl_basic_set_free(hull); + return NULL; +} + +/* Detect and make explicit all equalities satisfied by the (integer) + * points in bmap. + */ +__isl_give isl_basic_map *isl_basic_map_detect_equalities( + __isl_take isl_basic_map *bmap) +{ + int i, j; + struct isl_basic_set *hull = NULL; + + if (!bmap) + return NULL; + if (bmap->n_ineq == 0) + return bmap; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) + return bmap; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_ALL_EQUALITIES)) + return bmap; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) + return isl_basic_map_implicit_equalities(bmap); + + hull = equalities_in_underlying_set(isl_basic_map_copy(bmap)); + if (!hull) + goto error; + if (ISL_F_ISSET(hull, ISL_BASIC_SET_EMPTY)) { + isl_basic_set_free(hull); + return isl_basic_map_set_to_empty(bmap); + } + bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim), 0, + hull->n_eq, 0); + for (i = 0; i < hull->n_eq; ++i) { + j = isl_basic_map_alloc_equality(bmap); + if (j < 0) + goto error; + isl_seq_cpy(bmap->eq[j], hull->eq[i], + 1 + isl_basic_set_total_dim(hull)); + } + isl_vec_free(bmap->sample); + bmap->sample = isl_vec_copy(hull->sample); + isl_basic_set_free(hull); + ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT | ISL_BASIC_MAP_ALL_EQUALITIES); + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_set_free(hull); + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_detect_equalities( + __isl_take isl_basic_set *bset) +{ + return bset_from_bmap( + isl_basic_map_detect_equalities(bset_to_bmap(bset))); +} + +__isl_give isl_map *isl_map_detect_equalities(__isl_take isl_map *map) +{ + return isl_map_inline_foreach_basic_map(map, + &isl_basic_map_detect_equalities); +} + +__isl_give isl_set *isl_set_detect_equalities(__isl_take isl_set *set) +{ + return set_from_map(isl_map_detect_equalities(set_to_map(set))); +} + +/* Return the superset of "bmap" described by the equalities + * satisfied by "bmap" that are already known. + */ +__isl_give isl_basic_map *isl_basic_map_plain_affine_hull( + __isl_take isl_basic_map *bmap) +{ + bmap = isl_basic_map_cow(bmap); + if (bmap) + isl_basic_map_free_inequality(bmap, bmap->n_ineq); + bmap = isl_basic_map_finalize(bmap); + return bmap; +} + +/* Return the superset of "bset" described by the equalities + * satisfied by "bset" that are already known. + */ +__isl_give isl_basic_set *isl_basic_set_plain_affine_hull( + __isl_take isl_basic_set *bset) +{ + return isl_basic_map_plain_affine_hull(bset); +} + +/* After computing the rational affine hull (by detecting the implicit + * equalities), we compute the additional equalities satisfied by + * the integer points (if any) and add the original equalities back in. + */ +__isl_give isl_basic_map *isl_basic_map_affine_hull( + __isl_take isl_basic_map *bmap) +{ + bmap = isl_basic_map_detect_equalities(bmap); + bmap = isl_basic_map_plain_affine_hull(bmap); + return bmap; +} + +struct isl_basic_set *isl_basic_set_affine_hull(struct isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_affine_hull(bset_to_bmap(bset))); +} + +/* Given a rational affine matrix "M", add stride constraints to "bmap" + * that ensure that + * + * M(x) + * + * is an integer vector. The variables x include all the variables + * of "bmap" except the unknown divs. + * + * If d is the common denominator of M, then we need to impose that + * + * d M(x) = 0 mod d + * + * or + * + * exists alpha : d M(x) = d alpha + * + * This function is similar to add_strides in isl_morph.c + */ +static __isl_give isl_basic_map *add_strides(__isl_take isl_basic_map *bmap, + __isl_keep isl_mat *M, int n_known) +{ + int i, div, k; + isl_int gcd; + + if (isl_int_is_one(M->row[0][0])) + return bmap; + + bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim), + M->n_row - 1, M->n_row - 1, 0); + + isl_int_init(gcd); + for (i = 1; i < M->n_row; ++i) { + isl_seq_gcd(M->row[i], M->n_col, &gcd); + if (isl_int_is_divisible_by(gcd, M->row[0][0])) + continue; + div = isl_basic_map_alloc_div(bmap); + if (div < 0) + goto error; + isl_int_set_si(bmap->div[div][0], 0); + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + isl_seq_cpy(bmap->eq[k], M->row[i], M->n_col); + isl_seq_clr(bmap->eq[k] + M->n_col, bmap->n_div - n_known); + isl_int_set(bmap->eq[k][M->n_col - n_known + div], + M->row[0][0]); + } + isl_int_clear(gcd); + + return bmap; +error: + isl_int_clear(gcd); + isl_basic_map_free(bmap); + return NULL; +} + +/* If there are any equalities that involve (multiple) unknown divs, + * then extract the stride information encoded by those equalities + * and make it explicitly available in "bmap". + * + * We first sort the divs so that the unknown divs appear last and + * then we count how many equalities involve these divs. + * + * Let these equalities be of the form + * + * A(x) + B y = 0 + * + * where y represents the unknown divs and x the remaining variables. + * Let [H 0] be the Hermite Normal Form of B, i.e., + * + * B = [H 0] Q + * + * Then x is a solution of the equalities iff + * + * H^-1 A(x) (= - [I 0] Q y) + * + * is an integer vector. Let d be the common denominator of H^-1. + * We impose + * + * d H^-1 A(x) = d alpha + * + * in add_strides, with alpha fresh existentially quantified variables. + */ +static __isl_give isl_basic_map *isl_basic_map_make_strides_explicit( + __isl_take isl_basic_map *bmap) +{ + int known; + int n_known; + int n, n_col; + int total; + isl_ctx *ctx; + isl_mat *A, *B, *M; + + known = isl_basic_map_divs_known(bmap); + if (known < 0) + return isl_basic_map_free(bmap); + if (known) + return bmap; + bmap = isl_basic_map_sort_divs(bmap); + bmap = isl_basic_map_gauss(bmap, NULL); + if (!bmap) + return NULL; + + for (n_known = 0; n_known < bmap->n_div; ++n_known) + if (isl_int_is_zero(bmap->div[n_known][0])) + break; + ctx = isl_basic_map_get_ctx(bmap); + total = isl_space_dim(bmap->dim, isl_dim_all); + for (n = 0; n < bmap->n_eq; ++n) + if (isl_seq_first_non_zero(bmap->eq[n] + 1 + total + n_known, + bmap->n_div - n_known) == -1) + break; + if (n == 0) + return bmap; + B = isl_mat_sub_alloc6(ctx, bmap->eq, 0, n, 0, 1 + total + n_known); + n_col = bmap->n_div - n_known; + A = isl_mat_sub_alloc6(ctx, bmap->eq, 0, n, 1 + total + n_known, n_col); + A = isl_mat_left_hermite(A, 0, NULL, NULL); + A = isl_mat_drop_cols(A, n, n_col - n); + A = isl_mat_lin_to_aff(A); + A = isl_mat_right_inverse(A); + B = isl_mat_insert_zero_rows(B, 0, 1); + B = isl_mat_set_element_si(B, 0, 0, 1); + M = isl_mat_product(A, B); + if (!M) + return isl_basic_map_free(bmap); + bmap = add_strides(bmap, M, n_known); + bmap = isl_basic_map_gauss(bmap, NULL); + isl_mat_free(M); + + return bmap; +} + +/* Compute the affine hull of each basic map in "map" separately + * and make all stride information explicit so that we can remove + * all unknown divs without losing this information. + * The result is also guaranteed to be gaussed. + * + * In simple cases where a div is determined by an equality, + * calling isl_basic_map_gauss is enough to make the stride information + * explicit, as it will derive an explicit representation for the div + * from the equality. If, however, the stride information + * is encoded through multiple unknown divs then we need to make + * some extra effort in isl_basic_map_make_strides_explicit. + */ +static __isl_give isl_map *isl_map_local_affine_hull(__isl_take isl_map *map) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_affine_hull(map->p[i]); + map->p[i] = isl_basic_map_gauss(map->p[i], NULL); + map->p[i] = isl_basic_map_make_strides_explicit(map->p[i]); + if (!map->p[i]) + return isl_map_free(map); + } + + return map; +} + +static __isl_give isl_set *isl_set_local_affine_hull(__isl_take isl_set *set) +{ + return isl_map_local_affine_hull(set); +} + +/* Return an empty basic map living in the same space as "map". + */ +static __isl_give isl_basic_map *replace_map_by_empty_basic_map( + __isl_take isl_map *map) +{ + isl_space *space; + + space = isl_map_get_space(map); + isl_map_free(map); + return isl_basic_map_empty(space); +} + +/* Compute the affine hull of "map". + * + * We first compute the affine hull of each basic map separately. + * Then we align the divs and recompute the affine hulls of the basic + * maps since some of them may now have extra divs. + * In order to avoid performing parametric integer programming to + * compute explicit expressions for the divs, possible leading to + * an explosion in the number of basic maps, we first drop all unknown + * divs before aligning the divs. Note that isl_map_local_affine_hull tries + * to make sure that all stride information is explicitly available + * in terms of known divs. This involves calling isl_basic_set_gauss, + * which is also needed because affine_hull assumes its input has been gaussed, + * while isl_map_affine_hull may be called on input that has not been gaussed, + * in particular from initial_facet_constraint. + * Similarly, align_divs may reorder some divs so that we need to + * gauss the result again. + * Finally, we combine the individual affine hulls into a single + * affine hull. + */ +__isl_give isl_basic_map *isl_map_affine_hull(__isl_take isl_map *map) +{ + struct isl_basic_map *model = NULL; + struct isl_basic_map *hull = NULL; + struct isl_set *set; + isl_basic_set *bset; + + map = isl_map_detect_equalities(map); + map = isl_map_local_affine_hull(map); + map = isl_map_remove_empty_parts(map); + map = isl_map_remove_unknown_divs(map); + map = isl_map_align_divs_internal(map); + + if (!map) + return NULL; + + if (map->n == 0) + return replace_map_by_empty_basic_map(map); + + model = isl_basic_map_copy(map->p[0]); + set = isl_map_underlying_set(map); + set = isl_set_cow(set); + set = isl_set_local_affine_hull(set); + if (!set) + goto error; + + while (set->n > 1) + set->p[0] = affine_hull(set->p[0], set->p[--set->n]); + + bset = isl_basic_set_copy(set->p[0]); + hull = isl_basic_map_overlying_set(bset, model); + isl_set_free(set); + hull = isl_basic_map_simplify(hull); + return isl_basic_map_finalize(hull); +error: + isl_basic_map_free(model); + isl_set_free(set); + return NULL; +} + +struct isl_basic_set *isl_set_affine_hull(struct isl_set *set) +{ + return bset_from_bmap(isl_map_affine_hull(set_to_map(set))); +} Index: contrib/isl/isl_arg.c =================================================================== --- /dev/null +++ contrib/isl/isl_arg.c @@ -0,0 +1,1311 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include + +#include +#include +#include + +static struct isl_arg help_arg[] = { +ISL_ARG_PHANTOM_BOOL('h', "help", NULL, "print this help, then exit") +}; + +static void set_default_choice(struct isl_arg *arg, void *opt) +{ + if (arg->offset == (size_t) -1) + return; + *(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value; +} + +static void set_default_flags(struct isl_arg *arg, void *opt) +{ + *(unsigned *)(((char *)opt) + arg->offset) = arg->u.flags.default_value; +} + +static void set_default_bool(struct isl_arg *arg, void *opt) +{ + if (arg->offset == (size_t) -1) + return; + *(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value; +} + +static void set_default_child(struct isl_arg *arg, void *opt) +{ + void *child; + + if (arg->offset == (size_t) -1) + child = opt; + else { + child = calloc(1, arg->u.child.child->options_size); + *(void **)(((char *)opt) + arg->offset) = child; + } + + if (child) + isl_args_set_defaults(arg->u.child.child, child); +} + +static void set_default_user(struct isl_arg *arg, void *opt) +{ + arg->u.user.init(((char *)opt) + arg->offset); +} + +static void set_default_int(struct isl_arg *arg, void *opt) +{ + *(int *)(((char *)opt) + arg->offset) = arg->u.i.default_value; +} + +static void set_default_long(struct isl_arg *arg, void *opt) +{ + *(long *)(((char *)opt) + arg->offset) = arg->u.l.default_value; +} + +static void set_default_ulong(struct isl_arg *arg, void *opt) +{ + *(unsigned long *)(((char *)opt) + arg->offset) = arg->u.ul.default_value; +} + +static void set_default_str(struct isl_arg *arg, void *opt) +{ + const char *str = NULL; + if (arg->u.str.default_value) + str = strdup(arg->u.str.default_value); + *(const char **)(((char *)opt) + arg->offset) = str; +} + +static void set_default_str_list(struct isl_arg *arg, void *opt) +{ + *(const char ***)(((char *) opt) + arg->offset) = NULL; + *(int *)(((char *) opt) + arg->u.str_list.offset_n) = 0; +} + +void isl_args_set_defaults(struct isl_args *args, void *opt) +{ + int i; + + for (i = 0; args->args[i].type != isl_arg_end; ++i) { + switch (args->args[i].type) { + case isl_arg_choice: + set_default_choice(&args->args[i], opt); + break; + case isl_arg_flags: + set_default_flags(&args->args[i], opt); + break; + case isl_arg_bool: + set_default_bool(&args->args[i], opt); + break; + case isl_arg_child: + set_default_child(&args->args[i], opt); + break; + case isl_arg_user: + set_default_user(&args->args[i], opt); + break; + case isl_arg_int: + set_default_int(&args->args[i], opt); + break; + case isl_arg_long: + set_default_long(&args->args[i], opt); + break; + case isl_arg_ulong: + set_default_ulong(&args->args[i], opt); + break; + case isl_arg_arg: + case isl_arg_str: + set_default_str(&args->args[i], opt); + break; + case isl_arg_str_list: + set_default_str_list(&args->args[i], opt); + break; + case isl_arg_alias: + case isl_arg_footer: + case isl_arg_version: + case isl_arg_end: + break; + } + } +} + +static void free_args(struct isl_arg *arg, void *opt); + +static void free_child(struct isl_arg *arg, void *opt) +{ + if (arg->offset == (size_t) -1) + free_args(arg->u.child.child->args, opt); + else + isl_args_free(arg->u.child.child, + *(void **)(((char *)opt) + arg->offset)); +} + +static void free_str_list(struct isl_arg *arg, void *opt) +{ + int i; + int n = *(int *)(((char *) opt) + arg->u.str_list.offset_n); + char **list = *(char ***)(((char *) opt) + arg->offset); + + for (i = 0; i < n; ++i) + free(list[i]); + free(list); +} + +static void free_user(struct isl_arg *arg, void *opt) +{ + if (arg->u.user.clear) + arg->u.user.clear(((char *)opt) + arg->offset); +} + +static void free_args(struct isl_arg *arg, void *opt) +{ + int i; + + for (i = 0; arg[i].type != isl_arg_end; ++i) { + switch (arg[i].type) { + case isl_arg_child: + free_child(&arg[i], opt); + break; + case isl_arg_arg: + case isl_arg_str: + free(*(char **)(((char *)opt) + arg[i].offset)); + break; + case isl_arg_str_list: + free_str_list(&arg[i], opt); + break; + case isl_arg_user: + free_user(&arg[i], opt); + break; + case isl_arg_alias: + case isl_arg_bool: + case isl_arg_choice: + case isl_arg_flags: + case isl_arg_int: + case isl_arg_long: + case isl_arg_ulong: + case isl_arg_version: + case isl_arg_footer: + case isl_arg_end: + break; + } + } +} + +void isl_args_free(struct isl_args *args, void *opt) +{ + if (!opt) + return; + + free_args(args->args, opt); + + free(opt); +} + +/* Data structure for collecting the prefixes of ancestor nodes. + * + * n is the number of prefixes. + * prefix[i] for i < n is a prefix of an ancestor. + * len[i] for i < n is the length of prefix[i]. + */ +struct isl_prefixes { + int n; + const char *prefix[10]; + size_t len[10]; +}; + +/* Add "prefix" to the list of prefixes and return the updated + * number of prefixes. + */ +static int add_prefix(struct isl_prefixes *prefixes, const char *prefix) +{ + int n = prefixes->n; + + if (!prefix) + return n; + + if (prefixes->n >= 10) { + fprintf(stderr, "too many prefixes\n"); + exit(EXIT_FAILURE); + } + prefixes->len[prefixes->n] = strlen(prefix); + prefixes->prefix[prefixes->n] = prefix; + prefixes->n++; + + return n; +} + +/* Drop all prefixes starting at "first". + */ +static void drop_prefix(struct isl_prefixes *prefixes, int first) +{ + prefixes->n = first; +} + +/* Print the prefixes in "prefixes". + */ +static int print_prefixes(struct isl_prefixes *prefixes) +{ + int i; + int len = 0; + + if (!prefixes) + return 0; + + for (i = 0; i < prefixes->n; ++i) { + printf("%s-", prefixes->prefix[i]); + len += strlen(prefixes->prefix[i]) + 1; + } + + return len; +} + +/* Check if "name" starts with one or more of the prefixes in "prefixes", + * starting at *first. If so, advance the pointer beyond the prefixes + * and return the updated pointer. Additionally, update *first to + * the index after the last prefix found. + */ +static const char *skip_prefixes(const char *name, + struct isl_prefixes *prefixes, int *first) +{ + int i; + + for (i = first ? *first : 0; i < prefixes->n; ++i) { + size_t len = prefixes->len[i]; + const char *prefix = prefixes->prefix[i]; + if (strncmp(name, prefix, len) == 0 && name[len] == '-') { + name += len + 1; + if (first) + *first = i + 1; + } + } + + return name; +} + +static int print_arg_help(struct isl_arg *decl, struct isl_prefixes *prefixes, + int no) +{ + int len = 0; + + if (!decl->long_name) { + printf(" -%c", decl->short_name); + return 4; + } + + if (decl->short_name) { + printf(" -%c, --", decl->short_name); + len += 8; + } else if (decl->flags & ISL_ARG_SINGLE_DASH) { + printf(" -"); + len += 3; + } else { + printf(" --"); + len += 8; + } + + if (no) { + printf("no-"); + len += 3; + } + len += print_prefixes(prefixes); + printf("%s", decl->long_name); + len += strlen(decl->long_name); + + while ((++decl)->type == isl_arg_alias) { + printf(", --"); + len += 4; + if (no) { + printf("no-"); + len += 3; + } + printf("%s", decl->long_name); + len += strlen(decl->long_name); + } + + return len; +} + +const void *isl_memrchr(const void *s, int c, size_t n) +{ + const char *p = s; + while (n-- > 0) + if (p[n] == c) + return p + n; + return NULL; +} + +static int wrap_msg(const char *s, int indent, int pos) +{ + int len; + int wrap_len = 75 - indent; + + if (pos + 1 >= indent) + printf("\n%*s", indent, ""); + else + printf("%*s", indent - pos, ""); + + len = strlen(s); + while (len > wrap_len) { + const char *space = isl_memrchr(s, ' ', wrap_len); + int l; + + if (!space) + space = strchr(s + wrap_len, ' '); + if (!space) + break; + l = space - s; + printf("%.*s", l, s); + s = space + 1; + len -= l + 1; + printf("\n%*s", indent, ""); + } + + printf("%s", s); + return len; +} + +static int print_help_msg(struct isl_arg *decl, int pos) +{ + if (!decl->help_msg) + return pos; + + return wrap_msg(decl->help_msg, 30, pos); +} + +static void print_default(struct isl_arg *decl, const char *def, int pos) +{ + const char *default_prefix = "[default: "; + const char *default_suffix = "]"; + int len; + + len = strlen(default_prefix) + strlen(def) + strlen(default_suffix); + + if (!decl->help_msg) { + if (pos >= 29) + printf("\n%30s", ""); + else + printf("%*s", 30 - pos, ""); + } else { + if (pos + len >= 48) + printf("\n%30s", ""); + else + printf(" "); + } + printf("%s%s%s", default_prefix, def, default_suffix); +} + +static void print_default_choice(struct isl_arg *decl, void *opt, int pos) +{ + int i; + const char *s = "none"; + unsigned *p; + + p = (unsigned *)(((char *) opt) + decl->offset); + for (i = 0; decl->u.choice.choice[i].name; ++i) + if (decl->u.choice.choice[i].value == *p) { + s = decl->u.choice.choice[i].name; + break; + } + + print_default(decl, s, pos); +} + +static void print_choice_help(struct isl_arg *decl, + struct isl_prefixes *prefixes, void *opt) +{ + int i; + int pos; + + pos = print_arg_help(decl, prefixes, 0); + printf("="); + pos++; + + for (i = 0; decl->u.choice.choice[i].name; ++i) { + if (i) { + printf("|"); + pos++; + } + printf("%s", decl->u.choice.choice[i].name); + pos += strlen(decl->u.choice.choice[i].name); + } + + pos = print_help_msg(decl, pos); + print_default_choice(decl, opt, pos); + + printf("\n"); +} + +static void print_default_flags(struct isl_arg *decl, void *opt, int pos) +{ + int i, first; + const char *default_prefix = "[default: "; + const char *default_suffix = "]"; + int len = strlen(default_prefix) + strlen(default_suffix); + unsigned *p; + + p = (unsigned *)(((char *) opt) + decl->offset); + for (i = 0; decl->u.flags.flags[i].name; ++i) + if ((*p & decl->u.flags.flags[i].mask) == + decl->u.flags.flags[i].value) + len += strlen(decl->u.flags.flags[i].name); + + if (!decl->help_msg) { + if (pos >= 29) + printf("\n%30s", ""); + else + printf("%*s", 30 - pos, ""); + } else { + if (pos + len >= 48) + printf("\n%30s", ""); + else + printf(" "); + } + printf("%s", default_prefix); + + for (first = 1, i = 0; decl->u.flags.flags[i].name; ++i) + if ((*p & decl->u.flags.flags[i].mask) == + decl->u.flags.flags[i].value) { + if (!first) + printf(","); + printf("%s", decl->u.flags.flags[i].name); + first = 0; + } + + printf("%s", default_suffix); +} + +static void print_flags_help(struct isl_arg *decl, + struct isl_prefixes *prefixes, void *opt) +{ + int i, j; + int pos; + + pos = print_arg_help(decl, prefixes, 0); + printf("="); + pos++; + + for (i = 0; decl->u.flags.flags[i].name; ++i) { + if (i) { + printf(","); + pos++; + } + for (j = i; + decl->u.flags.flags[j].mask == decl->u.flags.flags[i].mask; + ++j) { + if (j != i) { + printf("|"); + pos++; + } + printf("%s", decl->u.flags.flags[j].name); + pos += strlen(decl->u.flags.flags[j].name); + } + i = j - 1; + } + + pos = print_help_msg(decl, pos); + print_default_flags(decl, opt, pos); + + printf("\n"); +} + +static void print_bool_help(struct isl_arg *decl, + struct isl_prefixes *prefixes, void *opt) +{ + int pos; + unsigned *p = opt ? (unsigned *)(((char *) opt) + decl->offset) : NULL; + int no = p ? *p == 1 : 0; + pos = print_arg_help(decl, prefixes, no); + pos = print_help_msg(decl, pos); + if (decl->offset != (size_t) -1) + print_default(decl, no ? "yes" : "no", pos); + printf("\n"); +} + +static int print_argument_name(struct isl_arg *decl, const char *name, int pos) +{ + printf("%c<%s>", decl->long_name ? '=' : ' ', name); + return pos + 3 + strlen(name); +} + +static void print_int_help(struct isl_arg *decl, + struct isl_prefixes *prefixes, void *opt) +{ + int pos; + char val[20]; + int *p = (int *)(((char *) opt) + decl->offset); + pos = print_arg_help(decl, prefixes, 0); + pos = print_argument_name(decl, decl->argument_name, pos); + pos = print_help_msg(decl, pos); + snprintf(val, sizeof(val), "%d", *p); + print_default(decl, val, pos); + printf("\n"); +} + +static void print_long_help(struct isl_arg *decl, + struct isl_prefixes *prefixes, void *opt) +{ + int pos; + long *p = (long *)(((char *) opt) + decl->offset); + pos = print_arg_help(decl, prefixes, 0); + if (*p != decl->u.l.default_selected) { + printf("["); + pos++; + } + printf("=long"); + pos += 5; + if (*p != decl->u.l.default_selected) { + printf("]"); + pos++; + } + print_help_msg(decl, pos); + printf("\n"); +} + +static void print_ulong_help(struct isl_arg *decl, + struct isl_prefixes *prefixes) +{ + int pos; + pos = print_arg_help(decl, prefixes, 0); + printf("=ulong"); + pos += 6; + print_help_msg(decl, pos); + printf("\n"); +} + +static void print_str_help(struct isl_arg *decl, + struct isl_prefixes *prefixes, void *opt) +{ + int pos; + const char *a = decl->argument_name ? decl->argument_name : "string"; + const char **p = (const char **)(((char *) opt) + decl->offset); + pos = print_arg_help(decl, prefixes, 0); + pos = print_argument_name(decl, a, pos); + pos = print_help_msg(decl, pos); + if (*p) + print_default(decl, *p, pos); + printf("\n"); +} + +static void print_str_list_help(struct isl_arg *decl, + struct isl_prefixes *prefixes) +{ + int pos; + const char *a = decl->argument_name ? decl->argument_name : "string"; + pos = print_arg_help(decl, prefixes, 0); + pos = print_argument_name(decl, a, pos); + pos = print_help_msg(decl, pos); + printf("\n"); +} + +static void print_help(struct isl_arg *arg, + struct isl_prefixes *prefixes, void *opt) +{ + int i; + int any = 0; + + for (i = 0; arg[i].type != isl_arg_end; ++i) { + if (arg[i].flags & ISL_ARG_HIDDEN) + continue; + switch (arg[i].type) { + case isl_arg_flags: + print_flags_help(&arg[i], prefixes, opt); + any = 1; + break; + case isl_arg_choice: + print_choice_help(&arg[i], prefixes, opt); + any = 1; + break; + case isl_arg_bool: + print_bool_help(&arg[i], prefixes, opt); + any = 1; + break; + case isl_arg_int: + print_int_help(&arg[i], prefixes, opt); + any = 1; + break; + case isl_arg_long: + print_long_help(&arg[i], prefixes, opt); + any = 1; + break; + case isl_arg_ulong: + print_ulong_help(&arg[i], prefixes); + any = 1; + break; + case isl_arg_str: + print_str_help(&arg[i], prefixes, opt); + any = 1; + break; + case isl_arg_str_list: + print_str_list_help(&arg[i], prefixes); + any = 1; + break; + case isl_arg_alias: + case isl_arg_version: + case isl_arg_arg: + case isl_arg_footer: + case isl_arg_child: + case isl_arg_user: + case isl_arg_end: + break; + } + } + + for (i = 0; arg[i].type != isl_arg_end; ++i) { + void *child; + int first; + + if (arg[i].type != isl_arg_child) + continue; + if (arg[i].flags & ISL_ARG_HIDDEN) + continue; + + if (any) + printf("\n"); + if (arg[i].help_msg) + printf(" %s\n", arg[i].help_msg); + if (arg[i].offset == (size_t) -1) + child = opt; + else + child = *(void **)(((char *) opt) + arg[i].offset); + first = add_prefix(prefixes, arg[i].long_name); + print_help(arg[i].u.child.child->args, prefixes, child); + drop_prefix(prefixes, first); + any = 1; + } +} + +static const char *prog_name(const char *prog) +{ + const char *slash; + + slash = strrchr(prog, '/'); + if (slash) + prog = slash + 1; + if (strncmp(prog, "lt-", 3) == 0) + prog += 3; + + return prog; +} + +static int any_version(struct isl_arg *decl) +{ + int i; + + for (i = 0; decl[i].type != isl_arg_end; ++i) { + switch (decl[i].type) { + case isl_arg_version: + return 1; + case isl_arg_child: + if (any_version(decl[i].u.child.child->args)) + return 1; + break; + default: + break; + } + } + + return 0; +} + +static void print_help_and_exit(struct isl_arg *arg, const char *prog, + void *opt) +{ + int i; + struct isl_prefixes prefixes = { 0 }; + + printf("Usage: %s [OPTION...]", prog_name(prog)); + + for (i = 0; arg[i].type != isl_arg_end; ++i) + if (arg[i].type == isl_arg_arg) + printf(" %s", arg[i].argument_name); + + printf("\n\n"); + + print_help(arg, &prefixes, opt); + printf("\n"); + if (any_version(arg)) + printf(" -V, --version\n"); + print_bool_help(help_arg, NULL, NULL); + + for (i = 0; arg[i].type != isl_arg_end; ++i) { + if (arg[i].type != isl_arg_footer) + continue; + wrap_msg(arg[i].help_msg, 0, 0); + printf("\n"); + } + + exit(0); +} + +static int match_long_name(struct isl_arg *decl, + const char *start, const char *end) +{ + do { + if (end - start == strlen(decl->long_name) && + !strncmp(start, decl->long_name, end - start)) + return 1; + } while ((++decl)->type == isl_arg_alias); + + return 0; +} + +static const char *skip_dash_dash(struct isl_arg *decl, const char *arg) +{ + if (!strncmp(arg, "--", 2)) + return arg + 2; + if ((decl->flags & ISL_ARG_SINGLE_DASH) && arg[0] == '-') + return arg + 1; + return NULL; +} + +static const char *skip_name(struct isl_arg *decl, const char *arg, + struct isl_prefixes *prefixes, int need_argument, int *has_argument) +{ + const char *equal; + const char *name; + const char *end; + + if (arg[0] == '-' && arg[1] && arg[1] == decl->short_name) { + if (need_argument && !arg[2]) + return NULL; + if (has_argument) + *has_argument = arg[2] != '\0'; + return arg + 2; + } + if (!decl->long_name) + return NULL; + + name = skip_dash_dash(decl, arg); + if (!name) + return NULL; + + equal = strchr(name, '='); + if (need_argument && !equal) + return NULL; + + if (has_argument) + *has_argument = !!equal; + end = equal ? equal : name + strlen(name); + + name = skip_prefixes(name, prefixes, NULL); + + if (!match_long_name(decl, name, end)) + return NULL; + + return equal ? equal + 1 : end; +} + +static int parse_choice_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + int i; + int has_argument; + const char *choice; + + choice = skip_name(decl, arg[0], prefixes, 0, &has_argument); + if (!choice) + return 0; + + if (!has_argument && (!arg[1] || arg[1][0] == '-')) { + unsigned u = decl->u.choice.default_selected; + if (decl->offset != (size_t) -1) + *(unsigned *)(((char *)opt) + decl->offset) = u; + if (decl->u.choice.set) + decl->u.choice.set(opt, u); + + return 1; + } + + if (!has_argument) + choice = arg[1]; + + for (i = 0; decl->u.choice.choice[i].name; ++i) { + unsigned u; + + if (strcmp(choice, decl->u.choice.choice[i].name)) + continue; + + u = decl->u.choice.choice[i].value; + if (decl->offset != (size_t) -1) + *(unsigned *)(((char *)opt) + decl->offset) = u; + if (decl->u.choice.set) + decl->u.choice.set(opt, u); + + return has_argument ? 1 : 2; + } + + return 0; +} + +static int set_flag(struct isl_arg *decl, unsigned *val, const char *flag, + size_t len) +{ + int i; + + for (i = 0; decl->u.flags.flags[i].name; ++i) { + if (strncmp(flag, decl->u.flags.flags[i].name, len)) + continue; + + *val &= ~decl->u.flags.flags[i].mask; + *val |= decl->u.flags.flags[i].value; + + return 1; + } + + return 0; +} + +static int parse_flags_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + int has_argument; + const char *flags; + const char *comma; + unsigned val; + + flags = skip_name(decl, arg[0], prefixes, 0, &has_argument); + if (!flags) + return 0; + + if (!has_argument && !arg[1]) + return 0; + + if (!has_argument) + flags = arg[1]; + + val = 0; + + while ((comma = strchr(flags, ',')) != NULL) { + if (!set_flag(decl, &val, flags, comma - flags)) + return 0; + flags = comma + 1; + } + if (!set_flag(decl, &val, flags, strlen(flags))) + return 0; + + *(unsigned *)(((char *)opt) + decl->offset) = val; + + return has_argument ? 1 : 2; +} + +static int parse_bool_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + const char *name; + unsigned *p = (unsigned *)(((char *)opt) + decl->offset); + int next_prefix; + + if (skip_name(decl, arg[0], prefixes, 0, NULL)) { + if ((decl->flags & ISL_ARG_BOOL_ARG) && arg[1]) { + char *endptr; + int val = strtol(arg[1], &endptr, 0); + if (*endptr == '\0' && (val == 0 || val == 1)) { + if (decl->offset != (size_t) -1) + *p = val; + if (decl->u.b.set) + decl->u.b.set(opt, val); + return 2; + } + } + if (decl->offset != (size_t) -1) + *p = 1; + if (decl->u.b.set) + decl->u.b.set(opt, 1); + + return 1; + } + + if (!decl->long_name) + return 0; + + name = skip_dash_dash(decl, arg[0]); + if (!name) + return 0; + + next_prefix = 0; + name = skip_prefixes(name, prefixes, &next_prefix); + + if (strncmp(name, "no-", 3)) + return 0; + name += 3; + + name = skip_prefixes(name, prefixes, &next_prefix); + + if (match_long_name(decl, name, name + strlen(name))) { + if (decl->offset != (size_t) -1) + *p = 0; + if (decl->u.b.set) + decl->u.b.set(opt, 0); + + return 1; + } + + return 0; +} + +static int parse_str_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + int has_argument; + const char *s; + char **p = (char **)(((char *)opt) + decl->offset); + + s = skip_name(decl, arg[0], prefixes, 0, &has_argument); + if (!s) + return 0; + + if (has_argument) { + free(*p); + *p = strdup(s); + return 1; + } + + if (arg[1]) { + free(*p); + *p = strdup(arg[1]); + return 2; + } + + return 0; +} + +static int isl_arg_str_list_append(struct isl_arg *decl, void *opt, + const char *s) +{ + int *n = (int *)(((char *) opt) + decl->u.str_list.offset_n); + char **list = *(char ***)(((char *) opt) + decl->offset); + + list = realloc(list, (*n + 1) * sizeof(char *)); + if (!list) + return -1; + *(char ***)(((char *) opt) + decl->offset) = list; + list[*n] = strdup(s); + (*n)++; + return 0; +} + +static int parse_str_list_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + int has_argument; + const char *s; + + s = skip_name(decl, arg[0], prefixes, 0, &has_argument); + if (!s) + return 0; + + if (has_argument) { + isl_arg_str_list_append(decl, opt, s); + return 1; + } + + if (arg[1]) { + isl_arg_str_list_append(decl, opt, arg[1]); + return 2; + } + + return 0; +} + +static int parse_int_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + int has_argument; + const char *val; + char *endptr; + int *p = (int *)(((char *)opt) + decl->offset); + + val = skip_name(decl, arg[0], prefixes, 0, &has_argument); + if (!val) + return 0; + + if (has_argument) { + *p = atoi(val); + return 1; + } + + if (arg[1]) { + int i = strtol(arg[1], &endptr, 0); + if (*endptr == '\0') { + *p = i; + return 2; + } + } + + return 0; +} + +static int parse_long_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + int has_argument; + const char *val; + char *endptr; + long *p = (long *)(((char *)opt) + decl->offset); + + val = skip_name(decl, arg[0], prefixes, 0, &has_argument); + if (!val) + return 0; + + if (has_argument) { + long l = strtol(val, NULL, 0); + *p = l; + if (decl->u.l.set) + decl->u.l.set(opt, l); + return 1; + } + + if (arg[1]) { + long l = strtol(arg[1], &endptr, 0); + if (*endptr == '\0') { + *p = l; + if (decl->u.l.set) + decl->u.l.set(opt, l); + return 2; + } + } + + if (decl->u.l.default_value != decl->u.l.default_selected) { + *p = decl->u.l.default_selected; + if (decl->u.l.set) + decl->u.l.set(opt, decl->u.l.default_selected); + return 1; + } + + return 0; +} + +static int parse_ulong_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + int has_argument; + const char *val; + char *endptr; + unsigned long *p = (unsigned long *)(((char *)opt) + decl->offset); + + val = skip_name(decl, arg[0], prefixes, 0, &has_argument); + if (!val) + return 0; + + if (has_argument) { + *p = strtoul(val, NULL, 0); + return 1; + } + + if (arg[1]) { + unsigned long ul = strtoul(arg[1], &endptr, 0); + if (*endptr == '\0') { + *p = ul; + return 2; + } + } + + return 0; +} + +static int parse_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt); + +static int parse_child_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + void *child; + int first, parsed; + + if (decl->offset == (size_t) -1) + child = opt; + else + child = *(void **)(((char *)opt) + decl->offset); + + first = add_prefix(prefixes, decl->long_name); + parsed = parse_option(decl->u.child.child->args, arg, prefixes, child); + drop_prefix(prefixes, first); + + return parsed; +} + +static int parse_option(struct isl_arg *decl, char **arg, + struct isl_prefixes *prefixes, void *opt) +{ + int i; + + for (i = 0; decl[i].type != isl_arg_end; ++i) { + int parsed = 0; + switch (decl[i].type) { + case isl_arg_choice: + parsed = parse_choice_option(&decl[i], arg, + prefixes, opt); + break; + case isl_arg_flags: + parsed = parse_flags_option(&decl[i], arg, + prefixes, opt); + break; + case isl_arg_int: + parsed = parse_int_option(&decl[i], arg, prefixes, opt); + break; + case isl_arg_long: + parsed = parse_long_option(&decl[i], arg, + prefixes, opt); + break; + case isl_arg_ulong: + parsed = parse_ulong_option(&decl[i], arg, + prefixes, opt); + break; + case isl_arg_bool: + parsed = parse_bool_option(&decl[i], arg, + prefixes, opt); + break; + case isl_arg_str: + parsed = parse_str_option(&decl[i], arg, prefixes, opt); + break; + case isl_arg_str_list: + parsed = parse_str_list_option(&decl[i], arg, prefixes, + opt); + break; + case isl_arg_child: + parsed = parse_child_option(&decl[i], arg, + prefixes, opt); + break; + case isl_arg_alias: + case isl_arg_arg: + case isl_arg_footer: + case isl_arg_user: + case isl_arg_version: + case isl_arg_end: + break; + } + if (parsed) + return parsed; + } + + return 0; +} + +static void print_version(struct isl_arg *decl) +{ + int i; + + for (i = 0; decl[i].type != isl_arg_end; ++i) { + switch (decl[i].type) { + case isl_arg_version: + decl[i].u.version.print_version(); + break; + case isl_arg_child: + print_version(decl[i].u.child.child->args); + break; + default: + break; + } + } +} + +static void print_version_and_exit(struct isl_arg *decl) +{ + print_version(decl); + + exit(0); +} + +static int drop_argument(int argc, char **argv, int drop, int n) +{ + for (; drop + n < argc; ++drop) + argv[drop] = argv[drop + n]; + + return argc - n; +} + +static int n_arg(struct isl_arg *arg) +{ + int i; + int n_arg = 0; + + for (i = 0; arg[i].type != isl_arg_end; ++i) + if (arg[i].type == isl_arg_arg) + n_arg++; + + return n_arg; +} + +static int next_arg(struct isl_arg *arg, int a) +{ + for (++a; arg[a].type != isl_arg_end; ++a) + if (arg[a].type == isl_arg_arg) + return a; + + return -1; +} + +/* Unless ISL_ARG_SKIP_HELP is set, check if "arg" is + * equal to "--help" and if so call print_help_and_exit. + */ +static void check_help(struct isl_args *args, char *arg, char *prog, void *opt, + unsigned flags) +{ + if (ISL_FL_ISSET(flags, ISL_ARG_SKIP_HELP)) + return; + + if (strcmp(arg, "--help") == 0) + print_help_and_exit(args->args, prog, opt); +} + +int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt, + unsigned flags) +{ + int a = -1; + int skip = 0; + int i; + int n; + struct isl_prefixes prefixes = { 0 }; + + n = n_arg(args->args); + + for (i = 1; i < argc; ++i) { + if ((strcmp(argv[i], "--version") == 0 || + strcmp(argv[i], "-V") == 0) && any_version(args->args)) + print_version_and_exit(args->args); + } + + while (argc > 1 + skip) { + int parsed; + if (argv[1 + skip][0] != '-') { + a = next_arg(args->args, a); + if (a >= 0) { + char **p; + p = (char **)(((char *)opt)+args->args[a].offset); + free(*p); + *p = strdup(argv[1 + skip]); + argc = drop_argument(argc, argv, 1 + skip, 1); + --n; + } else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) { + fprintf(stderr, "%s: extra argument: %s\n", + prog_name(argv[0]), argv[1 + skip]); + exit(-1); + } else + ++skip; + continue; + } + check_help(args, argv[1 + skip], argv[0], opt, flags); + parsed = parse_option(args->args, &argv[1 + skip], + &prefixes, opt); + if (parsed) + argc = drop_argument(argc, argv, 1 + skip, parsed); + else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) { + fprintf(stderr, "%s: unrecognized option: %s\n", + prog_name(argv[0]), argv[1 + skip]); + exit(-1); + } else + ++skip; + } + + if (n > 0) { + fprintf(stderr, "%s: expecting %d more argument(s)\n", + prog_name(argv[0]), n); + exit(-1); + } + + return argc; +} Index: contrib/isl/isl_ast.c =================================================================== --- /dev/null +++ contrib/isl/isl_ast.c @@ -0,0 +1,2832 @@ +/* + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include + +#include +#include + +#undef BASE +#define BASE ast_expr + +#include + +#undef BASE +#define BASE ast_node + +#include + +isl_ctx *isl_ast_print_options_get_ctx( + __isl_keep isl_ast_print_options *options) +{ + return options ? options->ctx : NULL; +} + +__isl_give isl_ast_print_options *isl_ast_print_options_alloc(isl_ctx *ctx) +{ + isl_ast_print_options *options; + + options = isl_calloc_type(ctx, isl_ast_print_options); + if (!options) + return NULL; + + options->ctx = ctx; + isl_ctx_ref(ctx); + options->ref = 1; + + return options; +} + +__isl_give isl_ast_print_options *isl_ast_print_options_dup( + __isl_keep isl_ast_print_options *options) +{ + isl_ctx *ctx; + isl_ast_print_options *dup; + + if (!options) + return NULL; + + ctx = isl_ast_print_options_get_ctx(options); + dup = isl_ast_print_options_alloc(ctx); + if (!dup) + return NULL; + + dup->print_for = options->print_for; + dup->print_for_user = options->print_for_user; + dup->print_user = options->print_user; + dup->print_user_user = options->print_user_user; + + return dup; +} + +__isl_give isl_ast_print_options *isl_ast_print_options_cow( + __isl_take isl_ast_print_options *options) +{ + if (!options) + return NULL; + + if (options->ref == 1) + return options; + options->ref--; + return isl_ast_print_options_dup(options); +} + +__isl_give isl_ast_print_options *isl_ast_print_options_copy( + __isl_keep isl_ast_print_options *options) +{ + if (!options) + return NULL; + + options->ref++; + return options; +} + +__isl_null isl_ast_print_options *isl_ast_print_options_free( + __isl_take isl_ast_print_options *options) +{ + if (!options) + return NULL; + + if (--options->ref > 0) + return NULL; + + isl_ctx_deref(options->ctx); + + free(options); + return NULL; +} + +/* Set the print_user callback of "options" to "print_user". + * + * If this callback is set, then it used to print user nodes in the AST. + * Otherwise, the expression associated to the user node is printed. + */ +__isl_give isl_ast_print_options *isl_ast_print_options_set_print_user( + __isl_take isl_ast_print_options *options, + __isl_give isl_printer *(*print_user)(__isl_take isl_printer *p, + __isl_take isl_ast_print_options *options, + __isl_keep isl_ast_node *node, void *user), + void *user) +{ + options = isl_ast_print_options_cow(options); + if (!options) + return NULL; + + options->print_user = print_user; + options->print_user_user = user; + + return options; +} + +/* Set the print_for callback of "options" to "print_for". + * + * If this callback is set, then it used to print for nodes in the AST. + */ +__isl_give isl_ast_print_options *isl_ast_print_options_set_print_for( + __isl_take isl_ast_print_options *options, + __isl_give isl_printer *(*print_for)(__isl_take isl_printer *p, + __isl_take isl_ast_print_options *options, + __isl_keep isl_ast_node *node, void *user), + void *user) +{ + options = isl_ast_print_options_cow(options); + if (!options) + return NULL; + + options->print_for = print_for; + options->print_for_user = user; + + return options; +} + +__isl_give isl_ast_expr *isl_ast_expr_copy(__isl_keep isl_ast_expr *expr) +{ + if (!expr) + return NULL; + + expr->ref++; + return expr; +} + +__isl_give isl_ast_expr *isl_ast_expr_dup(__isl_keep isl_ast_expr *expr) +{ + int i; + isl_ctx *ctx; + isl_ast_expr *dup; + + if (!expr) + return NULL; + + ctx = isl_ast_expr_get_ctx(expr); + switch (expr->type) { + case isl_ast_expr_int: + dup = isl_ast_expr_from_val(isl_val_copy(expr->u.v)); + break; + case isl_ast_expr_id: + dup = isl_ast_expr_from_id(isl_id_copy(expr->u.id)); + break; + case isl_ast_expr_op: + dup = isl_ast_expr_alloc_op(ctx, + expr->u.op.op, expr->u.op.n_arg); + if (!dup) + return NULL; + for (i = 0; i < expr->u.op.n_arg; ++i) + dup->u.op.args[i] = + isl_ast_expr_copy(expr->u.op.args[i]); + break; + case isl_ast_expr_error: + dup = NULL; + } + + if (!dup) + return NULL; + + return dup; +} + +__isl_give isl_ast_expr *isl_ast_expr_cow(__isl_take isl_ast_expr *expr) +{ + if (!expr) + return NULL; + + if (expr->ref == 1) + return expr; + expr->ref--; + return isl_ast_expr_dup(expr); +} + +__isl_null isl_ast_expr *isl_ast_expr_free(__isl_take isl_ast_expr *expr) +{ + int i; + + if (!expr) + return NULL; + + if (--expr->ref > 0) + return NULL; + + isl_ctx_deref(expr->ctx); + + switch (expr->type) { + case isl_ast_expr_int: + isl_val_free(expr->u.v); + break; + case isl_ast_expr_id: + isl_id_free(expr->u.id); + break; + case isl_ast_expr_op: + if (expr->u.op.args) + for (i = 0; i < expr->u.op.n_arg; ++i) + isl_ast_expr_free(expr->u.op.args[i]); + free(expr->u.op.args); + break; + case isl_ast_expr_error: + break; + } + + free(expr); + return NULL; +} + +isl_ctx *isl_ast_expr_get_ctx(__isl_keep isl_ast_expr *expr) +{ + return expr ? expr->ctx : NULL; +} + +enum isl_ast_expr_type isl_ast_expr_get_type(__isl_keep isl_ast_expr *expr) +{ + return expr ? expr->type : isl_ast_expr_error; +} + +/* Return the integer value represented by "expr". + */ +__isl_give isl_val *isl_ast_expr_get_val(__isl_keep isl_ast_expr *expr) +{ + if (!expr) + return NULL; + if (expr->type != isl_ast_expr_int) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "expression not an int", return NULL); + return isl_val_copy(expr->u.v); +} + +__isl_give isl_id *isl_ast_expr_get_id(__isl_keep isl_ast_expr *expr) +{ + if (!expr) + return NULL; + if (expr->type != isl_ast_expr_id) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "expression not an identifier", return NULL); + + return isl_id_copy(expr->u.id); +} + +enum isl_ast_op_type isl_ast_expr_get_op_type(__isl_keep isl_ast_expr *expr) +{ + if (!expr) + return isl_ast_op_error; + if (expr->type != isl_ast_expr_op) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "expression not an operation", return isl_ast_op_error); + return expr->u.op.op; +} + +int isl_ast_expr_get_op_n_arg(__isl_keep isl_ast_expr *expr) +{ + if (!expr) + return -1; + if (expr->type != isl_ast_expr_op) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "expression not an operation", return -1); + return expr->u.op.n_arg; +} + +__isl_give isl_ast_expr *isl_ast_expr_get_op_arg(__isl_keep isl_ast_expr *expr, + int pos) +{ + if (!expr) + return NULL; + if (expr->type != isl_ast_expr_op) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "expression not an operation", return NULL); + if (pos < 0 || pos >= expr->u.op.n_arg) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "index out of bounds", return NULL); + + return isl_ast_expr_copy(expr->u.op.args[pos]); +} + +/* Replace the argument at position "pos" of "expr" by "arg". + */ +__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr, + int pos, __isl_take isl_ast_expr *arg) +{ + expr = isl_ast_expr_cow(expr); + if (!expr || !arg) + goto error; + if (expr->type != isl_ast_expr_op) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "expression not an operation", goto error); + if (pos < 0 || pos >= expr->u.op.n_arg) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "index out of bounds", goto error); + + isl_ast_expr_free(expr->u.op.args[pos]); + expr->u.op.args[pos] = arg; + + return expr; +error: + isl_ast_expr_free(arg); + return isl_ast_expr_free(expr); +} + +/* Is "expr1" equal to "expr2"? + */ +isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1, + __isl_keep isl_ast_expr *expr2) +{ + int i; + + if (!expr1 || !expr2) + return isl_bool_error; + + if (expr1 == expr2) + return isl_bool_true; + if (expr1->type != expr2->type) + return isl_bool_false; + switch (expr1->type) { + case isl_ast_expr_int: + return isl_val_eq(expr1->u.v, expr2->u.v); + case isl_ast_expr_id: + return expr1->u.id == expr2->u.id; + case isl_ast_expr_op: + if (expr1->u.op.op != expr2->u.op.op) + return isl_bool_false; + if (expr1->u.op.n_arg != expr2->u.op.n_arg) + return isl_bool_false; + for (i = 0; i < expr1->u.op.n_arg; ++i) { + isl_bool equal; + equal = isl_ast_expr_is_equal(expr1->u.op.args[i], + expr2->u.op.args[i]); + if (equal < 0 || !equal) + return equal; + } + return 1; + case isl_ast_expr_error: + return isl_bool_error; + } + + isl_die(isl_ast_expr_get_ctx(expr1), isl_error_internal, + "unhandled case", return isl_bool_error); +} + +/* Create a new operation expression of operation type "op", + * with "n_arg" as yet unspecified arguments. + */ +__isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx, + enum isl_ast_op_type op, int n_arg) +{ + isl_ast_expr *expr; + + expr = isl_calloc_type(ctx, isl_ast_expr); + if (!expr) + return NULL; + + expr->ctx = ctx; + isl_ctx_ref(ctx); + expr->ref = 1; + expr->type = isl_ast_expr_op; + expr->u.op.op = op; + expr->u.op.n_arg = n_arg; + expr->u.op.args = isl_calloc_array(ctx, isl_ast_expr *, n_arg); + + if (n_arg && !expr->u.op.args) + return isl_ast_expr_free(expr); + + return expr; +} + +/* Create a new id expression representing "id". + */ +__isl_give isl_ast_expr *isl_ast_expr_from_id(__isl_take isl_id *id) +{ + isl_ctx *ctx; + isl_ast_expr *expr; + + if (!id) + return NULL; + + ctx = isl_id_get_ctx(id); + expr = isl_calloc_type(ctx, isl_ast_expr); + if (!expr) + goto error; + + expr->ctx = ctx; + isl_ctx_ref(ctx); + expr->ref = 1; + expr->type = isl_ast_expr_id; + expr->u.id = id; + + return expr; +error: + isl_id_free(id); + return NULL; +} + +/* Create a new integer expression representing "i". + */ +__isl_give isl_ast_expr *isl_ast_expr_alloc_int_si(isl_ctx *ctx, int i) +{ + isl_ast_expr *expr; + + expr = isl_calloc_type(ctx, isl_ast_expr); + if (!expr) + return NULL; + + expr->ctx = ctx; + isl_ctx_ref(ctx); + expr->ref = 1; + expr->type = isl_ast_expr_int; + expr->u.v = isl_val_int_from_si(ctx, i); + if (!expr->u.v) + return isl_ast_expr_free(expr); + + return expr; +} + +/* Create a new integer expression representing "v". + */ +__isl_give isl_ast_expr *isl_ast_expr_from_val(__isl_take isl_val *v) +{ + isl_ctx *ctx; + isl_ast_expr *expr; + + if (!v) + return NULL; + if (!isl_val_is_int(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting integer value", goto error); + + ctx = isl_val_get_ctx(v); + expr = isl_calloc_type(ctx, isl_ast_expr); + if (!expr) + goto error; + + expr->ctx = ctx; + isl_ctx_ref(ctx); + expr->ref = 1; + expr->type = isl_ast_expr_int; + expr->u.v = v; + + return expr; +error: + isl_val_free(v); + return NULL; +} + +/* Create an expression representing the unary operation "type" applied to + * "arg". + */ +__isl_give isl_ast_expr *isl_ast_expr_alloc_unary(enum isl_ast_op_type type, + __isl_take isl_ast_expr *arg) +{ + isl_ctx *ctx; + isl_ast_expr *expr = NULL; + + if (!arg) + return NULL; + + ctx = isl_ast_expr_get_ctx(arg); + expr = isl_ast_expr_alloc_op(ctx, type, 1); + if (!expr) + goto error; + + expr->u.op.args[0] = arg; + + return expr; +error: + isl_ast_expr_free(arg); + return NULL; +} + +/* Create an expression representing the negation of "arg". + */ +__isl_give isl_ast_expr *isl_ast_expr_neg(__isl_take isl_ast_expr *arg) +{ + return isl_ast_expr_alloc_unary(isl_ast_op_minus, arg); +} + +/* Create an expression representing the address of "expr". + */ +__isl_give isl_ast_expr *isl_ast_expr_address_of(__isl_take isl_ast_expr *expr) +{ + if (!expr) + return NULL; + + if (isl_ast_expr_get_type(expr) != isl_ast_expr_op || + isl_ast_expr_get_op_type(expr) != isl_ast_op_access) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "can only take address of access expressions", + return isl_ast_expr_free(expr)); + + return isl_ast_expr_alloc_unary(isl_ast_op_address_of, expr); +} + +/* Create an expression representing the binary operation "type" + * applied to "expr1" and "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_alloc_binary(enum isl_ast_op_type type, + __isl_take isl_ast_expr *expr1, __isl_take isl_ast_expr *expr2) +{ + isl_ctx *ctx; + isl_ast_expr *expr = NULL; + + if (!expr1 || !expr2) + goto error; + + ctx = isl_ast_expr_get_ctx(expr1); + expr = isl_ast_expr_alloc_op(ctx, type, 2); + if (!expr) + goto error; + + expr->u.op.args[0] = expr1; + expr->u.op.args[1] = expr2; + + return expr; +error: + isl_ast_expr_free(expr1); + isl_ast_expr_free(expr2); + return NULL; +} + +/* Create an expression representing the sum of "expr1" and "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_add(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_add, expr1, expr2); +} + +/* Create an expression representing the difference of "expr1" and "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_sub(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_sub, expr1, expr2); +} + +/* Create an expression representing the product of "expr1" and "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_mul(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_mul, expr1, expr2); +} + +/* Create an expression representing the quotient of "expr1" and "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_div(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_div, expr1, expr2); +} + +/* Create an expression representing the quotient of the integer + * division of "expr1" by "expr2", where "expr1" is known to be + * non-negative. + */ +__isl_give isl_ast_expr *isl_ast_expr_pdiv_q(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_pdiv_q, expr1, expr2); +} + +/* Create an expression representing the remainder of the integer + * division of "expr1" by "expr2", where "expr1" is known to be + * non-negative. + */ +__isl_give isl_ast_expr *isl_ast_expr_pdiv_r(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_pdiv_r, expr1, expr2); +} + +/* Create an expression representing the conjunction of "expr1" and "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_and(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_and, expr1, expr2); +} + +/* Create an expression representing the conjunction of "expr1" and "expr2", + * where "expr2" is evaluated only if "expr1" is evaluated to true. + */ +__isl_give isl_ast_expr *isl_ast_expr_and_then(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_and_then, expr1, expr2); +} + +/* Create an expression representing the disjunction of "expr1" and "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_or(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_or, expr1, expr2); +} + +/* Create an expression representing the disjunction of "expr1" and "expr2", + * where "expr2" is evaluated only if "expr1" is evaluated to false. + */ +__isl_give isl_ast_expr *isl_ast_expr_or_else(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_or_else, expr1, expr2); +} + +/* Create an expression representing "expr1" less than or equal to "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_le(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_le, expr1, expr2); +} + +/* Create an expression representing "expr1" less than "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_lt(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_lt, expr1, expr2); +} + +/* Create an expression representing "expr1" greater than or equal to "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_ge(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_ge, expr1, expr2); +} + +/* Create an expression representing "expr1" greater than "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_gt(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_gt, expr1, expr2); +} + +/* Create an expression representing "expr1" equal to "expr2". + */ +__isl_give isl_ast_expr *isl_ast_expr_eq(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + return isl_ast_expr_alloc_binary(isl_ast_op_eq, expr1, expr2); +} + +/* Create an expression of type "type" with as arguments "arg0" followed + * by "arguments". + */ +static __isl_give isl_ast_expr *ast_expr_with_arguments( + enum isl_ast_op_type type, __isl_take isl_ast_expr *arg0, + __isl_take isl_ast_expr_list *arguments) +{ + int i, n; + isl_ctx *ctx; + isl_ast_expr *res = NULL; + + if (!arg0 || !arguments) + goto error; + + ctx = isl_ast_expr_get_ctx(arg0); + n = isl_ast_expr_list_n_ast_expr(arguments); + res = isl_ast_expr_alloc_op(ctx, type, 1 + n); + if (!res) + goto error; + for (i = 0; i < n; ++i) { + isl_ast_expr *arg; + arg = isl_ast_expr_list_get_ast_expr(arguments, i); + res->u.op.args[1 + i] = arg; + if (!arg) + goto error; + } + res->u.op.args[0] = arg0; + + isl_ast_expr_list_free(arguments); + return res; +error: + isl_ast_expr_free(arg0); + isl_ast_expr_list_free(arguments); + isl_ast_expr_free(res); + return NULL; +} + +/* Create an expression representing an access to "array" with index + * expressions "indices". + */ +__isl_give isl_ast_expr *isl_ast_expr_access(__isl_take isl_ast_expr *array, + __isl_take isl_ast_expr_list *indices) +{ + return ast_expr_with_arguments(isl_ast_op_access, array, indices); +} + +/* Create an expression representing a call to "function" with argument + * expressions "arguments". + */ +__isl_give isl_ast_expr *isl_ast_expr_call(__isl_take isl_ast_expr *function, + __isl_take isl_ast_expr_list *arguments) +{ + return ast_expr_with_arguments(isl_ast_op_call, function, arguments); +} + +/* For each subexpression of "expr" of type isl_ast_expr_id, + * if it appears in "id2expr", then replace it by the corresponding + * expression. + */ +__isl_give isl_ast_expr *isl_ast_expr_substitute_ids( + __isl_take isl_ast_expr *expr, __isl_take isl_id_to_ast_expr *id2expr) +{ + int i; + isl_maybe_isl_ast_expr m; + + if (!expr || !id2expr) + goto error; + + switch (expr->type) { + case isl_ast_expr_int: + break; + case isl_ast_expr_id: + m = isl_id_to_ast_expr_try_get(id2expr, expr->u.id); + if (m.valid < 0) + goto error; + if (!m.valid) + break; + isl_ast_expr_free(expr); + expr = m.value; + break; + case isl_ast_expr_op: + for (i = 0; i < expr->u.op.n_arg; ++i) { + isl_ast_expr *arg; + arg = isl_ast_expr_copy(expr->u.op.args[i]); + arg = isl_ast_expr_substitute_ids(arg, + isl_id_to_ast_expr_copy(id2expr)); + if (arg == expr->u.op.args[i]) { + isl_ast_expr_free(arg); + continue; + } + if (!arg) + expr = isl_ast_expr_free(expr); + expr = isl_ast_expr_cow(expr); + if (!expr) { + isl_ast_expr_free(arg); + break; + } + isl_ast_expr_free(expr->u.op.args[i]); + expr->u.op.args[i] = arg; + } + break; + case isl_ast_expr_error: + expr = isl_ast_expr_free(expr); + break; + } + + isl_id_to_ast_expr_free(id2expr); + return expr; +error: + isl_ast_expr_free(expr); + isl_id_to_ast_expr_free(id2expr); + return NULL; +} + +isl_ctx *isl_ast_node_get_ctx(__isl_keep isl_ast_node *node) +{ + return node ? node->ctx : NULL; +} + +enum isl_ast_node_type isl_ast_node_get_type(__isl_keep isl_ast_node *node) +{ + return node ? node->type : isl_ast_node_error; +} + +__isl_give isl_ast_node *isl_ast_node_alloc(isl_ctx *ctx, + enum isl_ast_node_type type) +{ + isl_ast_node *node; + + node = isl_calloc_type(ctx, isl_ast_node); + if (!node) + return NULL; + + node->ctx = ctx; + isl_ctx_ref(ctx); + node->ref = 1; + node->type = type; + + return node; +} + +/* Create an if node with the given guard. + * + * The then body needs to be filled in later. + */ +__isl_give isl_ast_node *isl_ast_node_alloc_if(__isl_take isl_ast_expr *guard) +{ + isl_ast_node *node; + + if (!guard) + return NULL; + + node = isl_ast_node_alloc(isl_ast_expr_get_ctx(guard), isl_ast_node_if); + if (!node) + goto error; + node->u.i.guard = guard; + + return node; +error: + isl_ast_expr_free(guard); + return NULL; +} + +/* Create a for node with the given iterator. + * + * The remaining fields need to be filled in later. + */ +__isl_give isl_ast_node *isl_ast_node_alloc_for(__isl_take isl_id *id) +{ + isl_ast_node *node; + isl_ctx *ctx; + + if (!id) + return NULL; + + ctx = isl_id_get_ctx(id); + node = isl_ast_node_alloc(ctx, isl_ast_node_for); + if (!node) + goto error; + + node->u.f.iterator = isl_ast_expr_from_id(id); + if (!node->u.f.iterator) + return isl_ast_node_free(node); + + return node; +error: + isl_id_free(id); + return NULL; +} + +/* Create a mark node, marking "node" with "id". + */ +__isl_give isl_ast_node *isl_ast_node_alloc_mark(__isl_take isl_id *id, + __isl_take isl_ast_node *node) +{ + isl_ctx *ctx; + isl_ast_node *mark; + + if (!id || !node) + goto error; + + ctx = isl_id_get_ctx(id); + mark = isl_ast_node_alloc(ctx, isl_ast_node_mark); + if (!mark) + goto error; + + mark->u.m.mark = id; + mark->u.m.node = node; + + return mark; +error: + isl_id_free(id); + isl_ast_node_free(node); + return NULL; +} + +/* Create a user node evaluating "expr". + */ +__isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr) +{ + isl_ctx *ctx; + isl_ast_node *node; + + if (!expr) + return NULL; + + ctx = isl_ast_expr_get_ctx(expr); + node = isl_ast_node_alloc(ctx, isl_ast_node_user); + if (!node) + goto error; + + node->u.e.expr = expr; + + return node; +error: + isl_ast_expr_free(expr); + return NULL; +} + +/* Create a block node with the given children. + */ +__isl_give isl_ast_node *isl_ast_node_alloc_block( + __isl_take isl_ast_node_list *list) +{ + isl_ast_node *node; + isl_ctx *ctx; + + if (!list) + return NULL; + + ctx = isl_ast_node_list_get_ctx(list); + node = isl_ast_node_alloc(ctx, isl_ast_node_block); + if (!node) + goto error; + + node->u.b.children = list; + + return node; +error: + isl_ast_node_list_free(list); + return NULL; +} + +/* Represent the given list of nodes as a single node, either by + * extract the node from a single element list or by creating + * a block node with the list of nodes as children. + */ +__isl_give isl_ast_node *isl_ast_node_from_ast_node_list( + __isl_take isl_ast_node_list *list) +{ + isl_ast_node *node; + + if (isl_ast_node_list_n_ast_node(list) != 1) + return isl_ast_node_alloc_block(list); + + node = isl_ast_node_list_get_ast_node(list, 0); + isl_ast_node_list_free(list); + + return node; +} + +__isl_give isl_ast_node *isl_ast_node_copy(__isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + + node->ref++; + return node; +} + +__isl_give isl_ast_node *isl_ast_node_dup(__isl_keep isl_ast_node *node) +{ + isl_ast_node *dup; + + if (!node) + return NULL; + + dup = isl_ast_node_alloc(isl_ast_node_get_ctx(node), node->type); + if (!dup) + return NULL; + + switch (node->type) { + case isl_ast_node_if: + dup->u.i.guard = isl_ast_expr_copy(node->u.i.guard); + dup->u.i.then = isl_ast_node_copy(node->u.i.then); + dup->u.i.else_node = isl_ast_node_copy(node->u.i.else_node); + if (!dup->u.i.guard || !dup->u.i.then || + (node->u.i.else_node && !dup->u.i.else_node)) + return isl_ast_node_free(dup); + break; + case isl_ast_node_for: + dup->u.f.iterator = isl_ast_expr_copy(node->u.f.iterator); + dup->u.f.init = isl_ast_expr_copy(node->u.f.init); + dup->u.f.cond = isl_ast_expr_copy(node->u.f.cond); + dup->u.f.inc = isl_ast_expr_copy(node->u.f.inc); + dup->u.f.body = isl_ast_node_copy(node->u.f.body); + if (!dup->u.f.iterator || !dup->u.f.init || !dup->u.f.cond || + !dup->u.f.inc || !dup->u.f.body) + return isl_ast_node_free(dup); + break; + case isl_ast_node_block: + dup->u.b.children = isl_ast_node_list_copy(node->u.b.children); + if (!dup->u.b.children) + return isl_ast_node_free(dup); + break; + case isl_ast_node_mark: + dup->u.m.mark = isl_id_copy(node->u.m.mark); + dup->u.m.node = isl_ast_node_copy(node->u.m.node); + if (!dup->u.m.mark || !dup->u.m.node) + return isl_ast_node_free(dup); + break; + case isl_ast_node_user: + dup->u.e.expr = isl_ast_expr_copy(node->u.e.expr); + if (!dup->u.e.expr) + return isl_ast_node_free(dup); + break; + case isl_ast_node_error: + break; + } + + return dup; +} + +__isl_give isl_ast_node *isl_ast_node_cow(__isl_take isl_ast_node *node) +{ + if (!node) + return NULL; + + if (node->ref == 1) + return node; + node->ref--; + return isl_ast_node_dup(node); +} + +__isl_null isl_ast_node *isl_ast_node_free(__isl_take isl_ast_node *node) +{ + if (!node) + return NULL; + + if (--node->ref > 0) + return NULL; + + switch (node->type) { + case isl_ast_node_if: + isl_ast_expr_free(node->u.i.guard); + isl_ast_node_free(node->u.i.then); + isl_ast_node_free(node->u.i.else_node); + break; + case isl_ast_node_for: + isl_ast_expr_free(node->u.f.iterator); + isl_ast_expr_free(node->u.f.init); + isl_ast_expr_free(node->u.f.cond); + isl_ast_expr_free(node->u.f.inc); + isl_ast_node_free(node->u.f.body); + break; + case isl_ast_node_block: + isl_ast_node_list_free(node->u.b.children); + break; + case isl_ast_node_mark: + isl_id_free(node->u.m.mark); + isl_ast_node_free(node->u.m.node); + break; + case isl_ast_node_user: + isl_ast_expr_free(node->u.e.expr); + break; + case isl_ast_node_error: + break; + } + + isl_id_free(node->annotation); + isl_ctx_deref(node->ctx); + free(node); + + return NULL; +} + +/* Replace the body of the for node "node" by "body". + */ +__isl_give isl_ast_node *isl_ast_node_for_set_body( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *body) +{ + node = isl_ast_node_cow(node); + if (!node || !body) + goto error; + if (node->type != isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a for node", goto error); + + isl_ast_node_free(node->u.f.body); + node->u.f.body = body; + + return node; +error: + isl_ast_node_free(node); + isl_ast_node_free(body); + return NULL; +} + +__isl_give isl_ast_node *isl_ast_node_for_get_body( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a for node", return NULL); + return isl_ast_node_copy(node->u.f.body); +} + +/* Mark the given for node as being degenerate. + */ +__isl_give isl_ast_node *isl_ast_node_for_mark_degenerate( + __isl_take isl_ast_node *node) +{ + node = isl_ast_node_cow(node); + if (!node) + return NULL; + node->u.f.degenerate = 1; + return node; +} + +isl_bool isl_ast_node_for_is_degenerate(__isl_keep isl_ast_node *node) +{ + if (!node) + return isl_bool_error; + if (node->type != isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a for node", return isl_bool_error); + return node->u.f.degenerate; +} + +__isl_give isl_ast_expr *isl_ast_node_for_get_iterator( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a for node", return NULL); + return isl_ast_expr_copy(node->u.f.iterator); +} + +__isl_give isl_ast_expr *isl_ast_node_for_get_init( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a for node", return NULL); + return isl_ast_expr_copy(node->u.f.init); +} + +/* Return the condition expression of the given for node. + * + * If the for node is degenerate, then the condition is not explicitly + * stored in the node. Instead, it is constructed as + * + * iterator <= init + */ +__isl_give isl_ast_expr *isl_ast_node_for_get_cond( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a for node", return NULL); + if (!node->u.f.degenerate) + return isl_ast_expr_copy(node->u.f.cond); + + return isl_ast_expr_alloc_binary(isl_ast_op_le, + isl_ast_expr_copy(node->u.f.iterator), + isl_ast_expr_copy(node->u.f.init)); +} + +/* Return the increment of the given for node. + * + * If the for node is degenerate, then the increment is not explicitly + * stored in the node. We simply return "1". + */ +__isl_give isl_ast_expr *isl_ast_node_for_get_inc( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a for node", return NULL); + if (!node->u.f.degenerate) + return isl_ast_expr_copy(node->u.f.inc); + return isl_ast_expr_alloc_int_si(isl_ast_node_get_ctx(node), 1); +} + +/* Replace the then branch of the if node "node" by "child". + */ +__isl_give isl_ast_node *isl_ast_node_if_set_then( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +{ + node = isl_ast_node_cow(node); + if (!node || !child) + goto error; + if (node->type != isl_ast_node_if) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not an if node", goto error); + + isl_ast_node_free(node->u.i.then); + node->u.i.then = child; + + return node; +error: + isl_ast_node_free(node); + isl_ast_node_free(child); + return NULL; +} + +__isl_give isl_ast_node *isl_ast_node_if_get_then( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_if) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not an if node", return NULL); + return isl_ast_node_copy(node->u.i.then); +} + +isl_bool isl_ast_node_if_has_else( + __isl_keep isl_ast_node *node) +{ + if (!node) + return isl_bool_error; + if (node->type != isl_ast_node_if) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not an if node", return isl_bool_error); + return node->u.i.else_node != NULL; +} + +__isl_give isl_ast_node *isl_ast_node_if_get_else( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_if) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not an if node", return NULL); + return isl_ast_node_copy(node->u.i.else_node); +} + +__isl_give isl_ast_expr *isl_ast_node_if_get_cond( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_if) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a guard node", return NULL); + return isl_ast_expr_copy(node->u.i.guard); +} + +__isl_give isl_ast_node_list *isl_ast_node_block_get_children( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_block) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a block node", return NULL); + return isl_ast_node_list_copy(node->u.b.children); +} + +__isl_give isl_ast_expr *isl_ast_node_user_get_expr( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_user) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a user node", return NULL); + + return isl_ast_expr_copy(node->u.e.expr); +} + +/* Return the mark identifier of the mark node "node". + */ +__isl_give isl_id *isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_mark) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a mark node", return NULL); + + return isl_id_copy(node->u.m.mark); +} + +/* Return the node marked by mark node "node". + */ +__isl_give isl_ast_node *isl_ast_node_mark_get_node( + __isl_keep isl_ast_node *node) +{ + if (!node) + return NULL; + if (node->type != isl_ast_node_mark) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a mark node", return NULL); + + return isl_ast_node_copy(node->u.m.node); +} + +__isl_give isl_id *isl_ast_node_get_annotation(__isl_keep isl_ast_node *node) +{ + return node ? isl_id_copy(node->annotation) : NULL; +} + +/* Replace node->annotation by "annotation". + */ +__isl_give isl_ast_node *isl_ast_node_set_annotation( + __isl_take isl_ast_node *node, __isl_take isl_id *annotation) +{ + node = isl_ast_node_cow(node); + if (!node || !annotation) + goto error; + + isl_id_free(node->annotation); + node->annotation = annotation; + + return node; +error: + isl_id_free(annotation); + return isl_ast_node_free(node); +} + +/* Traverse the elements of "list" and all their descendants + * in depth first preorder. + * + * Return isl_stat_ok on success and isl_stat_error on failure. + */ +static isl_stat nodelist_foreach(__isl_keep isl_ast_node_list *list, + isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user) +{ + int i; + + if (!list) + return isl_stat_error; + + for (i = 0; i < list->n; ++i) { + isl_stat ok; + isl_ast_node *node = list->p[i]; + + ok = isl_ast_node_foreach_descendant_top_down(node, fn, user); + if (ok < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Traverse the descendants of "node" (including the node itself) + * in depth first preorder. + * + * If "fn" returns isl_bool_error on any of the nodes, then the traversal + * is aborted. + * If "fn" returns isl_bool_false on any of the nodes, then the subtree rooted + * at that node is skipped. + * + * Return isl_stat_ok on success and isl_stat_error on failure. + */ +isl_stat isl_ast_node_foreach_descendant_top_down( + __isl_keep isl_ast_node *node, + isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user) +{ + isl_bool more; + isl_stat ok; + + if (!node) + return isl_stat_error; + + more = fn(node, user); + if (more < 0) + return isl_stat_error; + if (!more) + return isl_stat_ok; + + switch (node->type) { + case isl_ast_node_for: + node = node->u.f.body; + return isl_ast_node_foreach_descendant_top_down(node, fn, user); + case isl_ast_node_if: + ok = isl_ast_node_foreach_descendant_top_down(node->u.i.then, + fn, user); + if (ok < 0) + return isl_stat_error; + if (!node->u.i.else_node) + return isl_stat_ok; + node = node->u.i.else_node; + return isl_ast_node_foreach_descendant_top_down(node, fn, user); + case isl_ast_node_block: + return nodelist_foreach(node->u.b.children, fn, user); + case isl_ast_node_mark: + node = node->u.m.node; + return isl_ast_node_foreach_descendant_top_down(node, fn, user); + case isl_ast_node_user: + break; + case isl_ast_node_error: + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Textual C representation of the various operators. + */ +static char *op_str_c[] = { + [isl_ast_op_and] = "&&", + [isl_ast_op_and_then] = "&&", + [isl_ast_op_or] = "||", + [isl_ast_op_or_else] = "||", + [isl_ast_op_max] = "max", + [isl_ast_op_min] = "min", + [isl_ast_op_minus] = "-", + [isl_ast_op_add] = "+", + [isl_ast_op_sub] = "-", + [isl_ast_op_mul] = "*", + [isl_ast_op_fdiv_q] = "floord", + [isl_ast_op_pdiv_q] = "/", + [isl_ast_op_pdiv_r] = "%", + [isl_ast_op_zdiv_r] = "%", + [isl_ast_op_div] = "/", + [isl_ast_op_eq] = "==", + [isl_ast_op_le] = "<=", + [isl_ast_op_ge] = ">=", + [isl_ast_op_lt] = "<", + [isl_ast_op_gt] = ">", + [isl_ast_op_member] = ".", + [isl_ast_op_address_of] = "&" +}; + +/* Precedence in C of the various operators. + * Based on http://en.wikipedia.org/wiki/Operators_in_C_and_C++ + * Lowest value means highest precedence. + */ +static int op_prec[] = { + [isl_ast_op_and] = 13, + [isl_ast_op_and_then] = 13, + [isl_ast_op_or] = 14, + [isl_ast_op_or_else] = 14, + [isl_ast_op_max] = 2, + [isl_ast_op_min] = 2, + [isl_ast_op_minus] = 3, + [isl_ast_op_add] = 6, + [isl_ast_op_sub] = 6, + [isl_ast_op_mul] = 5, + [isl_ast_op_div] = 5, + [isl_ast_op_fdiv_q] = 2, + [isl_ast_op_pdiv_q] = 5, + [isl_ast_op_pdiv_r] = 5, + [isl_ast_op_zdiv_r] = 5, + [isl_ast_op_cond] = 15, + [isl_ast_op_select] = 15, + [isl_ast_op_eq] = 9, + [isl_ast_op_le] = 8, + [isl_ast_op_ge] = 8, + [isl_ast_op_lt] = 8, + [isl_ast_op_gt] = 8, + [isl_ast_op_call] = 2, + [isl_ast_op_access] = 2, + [isl_ast_op_member] = 2, + [isl_ast_op_address_of] = 3 +}; + +/* Is the operator left-to-right associative? + */ +static int op_left[] = { + [isl_ast_op_and] = 1, + [isl_ast_op_and_then] = 1, + [isl_ast_op_or] = 1, + [isl_ast_op_or_else] = 1, + [isl_ast_op_max] = 1, + [isl_ast_op_min] = 1, + [isl_ast_op_minus] = 0, + [isl_ast_op_add] = 1, + [isl_ast_op_sub] = 1, + [isl_ast_op_mul] = 1, + [isl_ast_op_div] = 1, + [isl_ast_op_fdiv_q] = 1, + [isl_ast_op_pdiv_q] = 1, + [isl_ast_op_pdiv_r] = 1, + [isl_ast_op_zdiv_r] = 1, + [isl_ast_op_cond] = 0, + [isl_ast_op_select] = 0, + [isl_ast_op_eq] = 1, + [isl_ast_op_le] = 1, + [isl_ast_op_ge] = 1, + [isl_ast_op_lt] = 1, + [isl_ast_op_gt] = 1, + [isl_ast_op_call] = 1, + [isl_ast_op_access] = 1, + [isl_ast_op_member] = 1, + [isl_ast_op_address_of] = 0 +}; + +static int is_and(enum isl_ast_op_type op) +{ + return op == isl_ast_op_and || op == isl_ast_op_and_then; +} + +static int is_or(enum isl_ast_op_type op) +{ + return op == isl_ast_op_or || op == isl_ast_op_or_else; +} + +static int is_add_sub(enum isl_ast_op_type op) +{ + return op == isl_ast_op_add || op == isl_ast_op_sub; +} + +static int is_div_mod(enum isl_ast_op_type op) +{ + return op == isl_ast_op_div || + op == isl_ast_op_pdiv_r || + op == isl_ast_op_zdiv_r; +} + +static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr); + +/* Do we need/want parentheses around "expr" as a subexpression of + * an "op" operation? If "left" is set, then "expr" is the left-most + * operand. + * + * We only need parentheses if "expr" represents an operation. + * + * If op has a higher precedence than expr->u.op.op, then we need + * parentheses. + * If op and expr->u.op.op have the same precedence, but the operations + * are performed in an order that is different from the associativity, + * then we need parentheses. + * + * An and inside an or technically does not require parentheses, + * but some compilers complain about that, so we add them anyway. + * + * Computations such as "a / b * c" and "a % b + c" can be somewhat + * difficult to read, so we add parentheses for those as well. + */ +static int sub_expr_need_parens(enum isl_ast_op_type op, + __isl_keep isl_ast_expr *expr, int left) +{ + if (expr->type != isl_ast_expr_op) + return 0; + + if (op_prec[expr->u.op.op] > op_prec[op]) + return 1; + if (op_prec[expr->u.op.op] == op_prec[op] && left != op_left[op]) + return 1; + + if (is_or(op) && is_and(expr->u.op.op)) + return 1; + if (op == isl_ast_op_mul && expr->u.op.op != isl_ast_op_mul && + op_prec[expr->u.op.op] == op_prec[op]) + return 1; + if (is_add_sub(op) && is_div_mod(expr->u.op.op)) + return 1; + + return 0; +} + +/* Print "expr" as a subexpression of an "op" operation in C format. + * If "left" is set, then "expr" is the left-most operand. + */ +static __isl_give isl_printer *print_sub_expr_c(__isl_take isl_printer *p, + enum isl_ast_op_type op, __isl_keep isl_ast_expr *expr, int left) +{ + int need_parens; + + need_parens = sub_expr_need_parens(op, expr, left); + + if (need_parens) + p = isl_printer_print_str(p, "("); + p = print_ast_expr_c(p, expr); + if (need_parens) + p = isl_printer_print_str(p, ")"); + return p; +} + +#define isl_ast_op_last isl_ast_op_address_of + +/* Data structure that holds the user-specified textual + * representations for the operators in C format. + * The entries are either NULL or copies of strings. + * A NULL entry means that the default name should be used. + */ +struct isl_ast_op_names { + char *op_str[isl_ast_op_last + 1]; +}; + +/* Create an empty struct isl_ast_op_names. + */ +static void *create_names(isl_ctx *ctx) +{ + return isl_calloc_type(ctx, struct isl_ast_op_names); +} + +/* Free a struct isl_ast_op_names along with all memory + * owned by the struct. + */ +static void free_names(void *user) +{ + int i; + struct isl_ast_op_names *names = user; + + if (!user) + return; + + for (i = 0; i <= isl_ast_op_last; ++i) + free(names->op_str[i]); + free(user); +} + +/* Create an identifier that is used to store + * an isl_ast_op_names note. + */ +static __isl_give isl_id *names_id(isl_ctx *ctx) +{ + return isl_id_alloc(ctx, "isl_ast_op_type_names", NULL); +} + +/* Ensure that "p" has a note identified by "id". + * If there is no such note yet, then it is created by "note_create" and + * scheduled do be freed by "note_free". + */ +static __isl_give isl_printer *alloc_note(__isl_take isl_printer *p, + __isl_keep isl_id *id, void *(*note_create)(isl_ctx *), + void (*note_free)(void *)) +{ + isl_ctx *ctx; + isl_id *note_id; + isl_bool has_note; + void *note; + + has_note = isl_printer_has_note(p, id); + if (has_note < 0) + return isl_printer_free(p); + if (has_note) + return p; + + ctx = isl_printer_get_ctx(p); + note = note_create(ctx); + if (!note) + return isl_printer_free(p); + note_id = isl_id_alloc(ctx, NULL, note); + if (!note_id) + note_free(note); + else + note_id = isl_id_set_free_user(note_id, note_free); + + p = isl_printer_set_note(p, isl_id_copy(id), note_id); + + return p; +} + +/* Ensure that "p" has an isl_ast_op_names note identified by "id". + */ +static __isl_give isl_printer *alloc_names(__isl_take isl_printer *p, + __isl_keep isl_id *id) +{ + return alloc_note(p, id, &create_names, &free_names); +} + +/* Retrieve the note identified by "id" from "p". + * The note is assumed to exist. + */ +static void *get_note(__isl_keep isl_printer *p, __isl_keep isl_id *id) +{ + void *note; + + id = isl_printer_get_note(p, isl_id_copy(id)); + note = isl_id_get_user(id); + isl_id_free(id); + + return note; +} + +/* Use "name" to print operations of type "type" to "p". + * + * Store the name in an isl_ast_op_names note attached to "p", such that + * it can be retrieved by get_op_str. + */ +__isl_give isl_printer *isl_ast_op_type_set_print_name( + __isl_take isl_printer *p, enum isl_ast_op_type type, + __isl_keep const char *name) +{ + isl_id *id; + struct isl_ast_op_names *names; + + if (!p) + return NULL; + if (type > isl_ast_op_last) + isl_die(isl_printer_get_ctx(p), isl_error_invalid, + "invalid type", return isl_printer_free(p)); + + id = names_id(isl_printer_get_ctx(p)); + p = alloc_names(p, id); + names = get_note(p, id); + isl_id_free(id); + if (!names) + return isl_printer_free(p); + free(names->op_str[type]); + names->op_str[type] = strdup(name); + + return p; +} + +/* Return the textual representation of "type" in C format. + * + * If there is a user-specified name in an isl_ast_op_names note + * associated to "p", then return that. + * Otherwise, return the default name in op_str. + */ +static const char *get_op_str_c(__isl_keep isl_printer *p, + enum isl_ast_op_type type) +{ + isl_id *id; + isl_bool has_names; + struct isl_ast_op_names *names = NULL; + + id = names_id(isl_printer_get_ctx(p)); + has_names = isl_printer_has_note(p, id); + if (has_names >= 0 && has_names) + names = get_note(p, id); + isl_id_free(id); + if (names && names->op_str[type]) + return names->op_str[type]; + return op_str_c[type]; +} + +/* Print a min or max reduction "expr" in C format. + */ +static __isl_give isl_printer *print_min_max_c(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr) +{ + int i = 0; + + for (i = 1; i < expr->u.op.n_arg; ++i) { + p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op)); + p = isl_printer_print_str(p, "("); + } + p = isl_printer_print_ast_expr(p, expr->u.op.args[0]); + for (i = 1; i < expr->u.op.n_arg; ++i) { + p = isl_printer_print_str(p, ", "); + p = print_ast_expr_c(p, expr->u.op.args[i]); + p = isl_printer_print_str(p, ")"); + } + + return p; +} + +/* Print a function call "expr" in C format. + * + * The first argument represents the function to be called. + */ +static __isl_give isl_printer *print_call_c(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr) +{ + int i = 0; + + p = print_ast_expr_c(p, expr->u.op.args[0]); + p = isl_printer_print_str(p, "("); + for (i = 1; i < expr->u.op.n_arg; ++i) { + if (i != 1) + p = isl_printer_print_str(p, ", "); + p = print_ast_expr_c(p, expr->u.op.args[i]); + } + p = isl_printer_print_str(p, ")"); + + return p; +} + +/* Print an array access "expr" in C format. + * + * The first argument represents the array being accessed. + */ +static __isl_give isl_printer *print_access_c(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr) +{ + int i = 0; + + p = print_ast_expr_c(p, expr->u.op.args[0]); + for (i = 1; i < expr->u.op.n_arg; ++i) { + p = isl_printer_print_str(p, "["); + p = print_ast_expr_c(p, expr->u.op.args[i]); + p = isl_printer_print_str(p, "]"); + } + + return p; +} + +/* Print "expr" to "p" in C format. + */ +static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr) +{ + if (!p) + return NULL; + if (!expr) + return isl_printer_free(p); + + switch (expr->type) { + case isl_ast_expr_op: + if (expr->u.op.op == isl_ast_op_call) { + p = print_call_c(p, expr); + break; + } + if (expr->u.op.op == isl_ast_op_access) { + p = print_access_c(p, expr); + break; + } + if (expr->u.op.n_arg == 1) { + p = isl_printer_print_str(p, + get_op_str_c(p, expr->u.op.op)); + p = print_sub_expr_c(p, expr->u.op.op, + expr->u.op.args[0], 0); + break; + } + if (expr->u.op.op == isl_ast_op_fdiv_q) { + const char *name = get_op_str_c(p, isl_ast_op_fdiv_q); + p = isl_printer_print_str(p, name); + p = isl_printer_print_str(p, "("); + p = print_ast_expr_c(p, expr->u.op.args[0]); + p = isl_printer_print_str(p, ", "); + p = print_ast_expr_c(p, expr->u.op.args[1]); + p = isl_printer_print_str(p, ")"); + break; + } + if (expr->u.op.op == isl_ast_op_max || + expr->u.op.op == isl_ast_op_min) { + p = print_min_max_c(p, expr); + break; + } + if (expr->u.op.op == isl_ast_op_cond || + expr->u.op.op == isl_ast_op_select) { + p = print_ast_expr_c(p, expr->u.op.args[0]); + p = isl_printer_print_str(p, " ? "); + p = print_ast_expr_c(p, expr->u.op.args[1]); + p = isl_printer_print_str(p, " : "); + p = print_ast_expr_c(p, expr->u.op.args[2]); + break; + } + if (expr->u.op.n_arg != 2) + isl_die(isl_printer_get_ctx(p), isl_error_internal, + "operation should have two arguments", + return isl_printer_free(p)); + p = print_sub_expr_c(p, expr->u.op.op, expr->u.op.args[0], 1); + if (expr->u.op.op != isl_ast_op_member) + p = isl_printer_print_str(p, " "); + p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op)); + if (expr->u.op.op != isl_ast_op_member) + p = isl_printer_print_str(p, " "); + p = print_sub_expr_c(p, expr->u.op.op, expr->u.op.args[1], 0); + break; + case isl_ast_expr_id: + p = isl_printer_print_str(p, isl_id_get_name(expr->u.id)); + break; + case isl_ast_expr_int: + p = isl_printer_print_val(p, expr->u.v); + break; + case isl_ast_expr_error: + break; + } + + return p; +} + +/* Textual representation of the isl_ast_op_type elements + * for use in a YAML representation of an isl_ast_expr. + */ +static char *op_str[] = { + [isl_ast_op_and] = "and", + [isl_ast_op_and_then] = "and_then", + [isl_ast_op_or] = "or", + [isl_ast_op_or_else] = "or_else", + [isl_ast_op_max] = "max", + [isl_ast_op_min] = "min", + [isl_ast_op_minus] = "minus", + [isl_ast_op_add] = "add", + [isl_ast_op_sub] = "sub", + [isl_ast_op_mul] = "mul", + [isl_ast_op_div] = "div", + [isl_ast_op_fdiv_q] = "fdiv_q", + [isl_ast_op_pdiv_q] = "pdiv_q", + [isl_ast_op_pdiv_r] = "pdiv_r", + [isl_ast_op_zdiv_r] = "zdiv_r", + [isl_ast_op_cond] = "cond", + [isl_ast_op_select] = "select", + [isl_ast_op_eq] = "eq", + [isl_ast_op_le] = "le", + [isl_ast_op_lt] = "lt", + [isl_ast_op_ge] = "ge", + [isl_ast_op_gt] = "gt", + [isl_ast_op_call] = "call", + [isl_ast_op_access] = "access", + [isl_ast_op_member] = "member", + [isl_ast_op_address_of] = "address_of" +}; + +static __isl_give isl_printer *print_ast_expr_isl(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr); + +/* Print the arguments of "expr" to "p" in isl format. + * + * If there are no arguments, then nothing needs to be printed. + * Otherwise add an "args" key to the current mapping with as value + * the list of arguments of "expr". + */ +static __isl_give isl_printer *print_arguments(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr) +{ + int i, n; + + n = isl_ast_expr_get_op_n_arg(expr); + if (n < 0) + return isl_printer_free(p); + if (n == 0) + return p; + + p = isl_printer_print_str(p, "args"); + p = isl_printer_yaml_next(p); + p = isl_printer_yaml_start_sequence(p); + for (i = 0; i < n; ++i) { + isl_ast_expr *arg; + + arg = isl_ast_expr_get_op_arg(expr, i); + p = print_ast_expr_isl(p, arg); + isl_ast_expr_free(arg); + p = isl_printer_yaml_next(p); + } + p = isl_printer_yaml_end_sequence(p); + + return p; +} + +/* Print "expr" to "p" in isl format. + * + * In particular, print the isl_ast_expr as a YAML document. + */ +static __isl_give isl_printer *print_ast_expr_isl(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr) +{ + enum isl_ast_expr_type type; + enum isl_ast_op_type op; + isl_id *id; + isl_val *v; + + if (!expr) + return isl_printer_free(p); + + p = isl_printer_yaml_start_mapping(p); + type = isl_ast_expr_get_type(expr); + switch (type) { + case isl_ast_expr_error: + return isl_printer_free(p); + case isl_ast_expr_op: + op = isl_ast_expr_get_op_type(expr); + if (op == isl_ast_op_error) + return isl_printer_free(p); + p = isl_printer_print_str(p, "op"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, op_str[op]); + p = isl_printer_yaml_next(p); + p = print_arguments(p, expr); + break; + case isl_ast_expr_id: + p = isl_printer_print_str(p, "id"); + p = isl_printer_yaml_next(p); + id = isl_ast_expr_get_id(expr); + p = isl_printer_print_id(p, id); + isl_id_free(id); + break; + case isl_ast_expr_int: + p = isl_printer_print_str(p, "val"); + p = isl_printer_yaml_next(p); + v = isl_ast_expr_get_val(expr); + p = isl_printer_print_val(p, v); + isl_val_free(v); + break; + } + p = isl_printer_yaml_end_mapping(p); + + return p; +} + +/* Print "expr" to "p". + * + * Only an isl and a C format are supported. + */ +__isl_give isl_printer *isl_printer_print_ast_expr(__isl_take isl_printer *p, + __isl_keep isl_ast_expr *expr) +{ + int format; + + if (!p) + return NULL; + + format = isl_printer_get_output_format(p); + switch (format) { + case ISL_FORMAT_ISL: + p = print_ast_expr_isl(p, expr); + break; + case ISL_FORMAT_C: + p = print_ast_expr_c(p, expr); + break; + default: + isl_die(isl_printer_get_ctx(p), isl_error_unsupported, + "output format not supported for ast_expr", + return isl_printer_free(p)); + } + + return p; +} + +static __isl_give isl_printer *print_ast_node_isl(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node); + +/* Print a YAML sequence containing the entries in "list" to "p". + */ +static __isl_give isl_printer *print_ast_node_list(__isl_take isl_printer *p, + __isl_keep isl_ast_node_list *list) +{ + int i, n; + + n = isl_ast_node_list_n_ast_node(list); + if (n < 0) + return isl_printer_free(p); + + p = isl_printer_yaml_start_sequence(p); + for (i = 0; i < n; ++i) { + isl_ast_node *node; + + node = isl_ast_node_list_get_ast_node(list, i); + p = print_ast_node_isl(p, node); + isl_ast_node_free(node); + p = isl_printer_yaml_next(p); + } + p = isl_printer_yaml_end_sequence(p); + + return p; +} + +/* Print "node" to "p" in "isl format". + * + * In particular, print the isl_ast_node as a YAML document. + */ +static __isl_give isl_printer *print_ast_node_isl(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node) +{ + switch (node->type) { + case isl_ast_node_for: + p = isl_printer_yaml_start_mapping(p); + p = isl_printer_print_str(p, "iterator"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_expr(p, node->u.f.iterator); + p = isl_printer_yaml_next(p); + if (node->u.f.degenerate) { + p = isl_printer_print_str(p, "value"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_expr(p, node->u.f.init); + p = isl_printer_yaml_next(p); + } else { + p = isl_printer_print_str(p, "init"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_expr(p, node->u.f.init); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "cond"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_expr(p, node->u.f.cond); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "inc"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_expr(p, node->u.f.inc); + p = isl_printer_yaml_next(p); + } + if (node->u.f.body) { + p = isl_printer_print_str(p, "body"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_node(p, node->u.f.body); + p = isl_printer_yaml_next(p); + } + p = isl_printer_yaml_end_mapping(p); + break; + case isl_ast_node_mark: + p = isl_printer_yaml_start_mapping(p); + p = isl_printer_print_str(p, "mark"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_id(p, node->u.m.mark); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "node"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_node(p, node->u.m.node); + p = isl_printer_yaml_end_mapping(p); + break; + case isl_ast_node_user: + p = isl_printer_yaml_start_mapping(p); + p = isl_printer_print_str(p, "user"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_expr(p, node->u.e.expr); + p = isl_printer_yaml_end_mapping(p); + break; + case isl_ast_node_if: + p = isl_printer_yaml_start_mapping(p); + p = isl_printer_print_str(p, "guard"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_expr(p, node->u.i.guard); + p = isl_printer_yaml_next(p); + if (node->u.i.then) { + p = isl_printer_print_str(p, "then"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_node(p, node->u.i.then); + p = isl_printer_yaml_next(p); + } + if (node->u.i.else_node) { + p = isl_printer_print_str(p, "else"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_ast_node(p, node->u.i.else_node); + } + p = isl_printer_yaml_end_mapping(p); + break; + case isl_ast_node_block: + p = print_ast_node_list(p, node->u.b.children); + break; + case isl_ast_node_error: + break; + } + return p; +} + +/* Do we need to print a block around the body "node" of a for or if node? + * + * If the node is a block, then we need to print a block. + * Also if the node is a degenerate for then we will print it as + * an assignment followed by the body of the for loop, so we need a block + * as well. + * If the node is an if node with an else, then we print a block + * to avoid spurious dangling else warnings emitted by some compilers. + * If the node is a mark, then in principle, we would have to check + * the child of the mark node. However, even if the child would not + * require us to print a block, for readability it is probably best + * to print a block anyway. + * If the ast_always_print_block option has been set, then we print a block. + */ +static int need_block(__isl_keep isl_ast_node *node) +{ + isl_ctx *ctx; + + if (node->type == isl_ast_node_block) + return 1; + if (node->type == isl_ast_node_for && node->u.f.degenerate) + return 1; + if (node->type == isl_ast_node_if && node->u.i.else_node) + return 1; + if (node->type == isl_ast_node_mark) + return 1; + + ctx = isl_ast_node_get_ctx(node); + return isl_options_get_ast_always_print_block(ctx); +} + +static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node, + __isl_keep isl_ast_print_options *options, int in_block, int in_list); +static __isl_give isl_printer *print_if_c(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node, + __isl_keep isl_ast_print_options *options, int new_line, + int force_block); + +/* Print the body "node" of a for or if node. + * If "else_node" is set, then it is printed as well. + * If "force_block" is set, then print out the body as a block. + * + * We first check if we need to print out a block. + * We always print out a block if there is an else node to make + * sure that the else node is matched to the correct if node. + * For consistency, the corresponding else node is also printed as a block. + * + * If the else node is itself an if, then we print it as + * + * } else if (..) { + * } + * + * Otherwise the else node is printed as + * + * } else { + * node + * } + */ +static __isl_give isl_printer *print_body_c(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node, __isl_keep isl_ast_node *else_node, + __isl_keep isl_ast_print_options *options, int force_block) +{ + if (!node) + return isl_printer_free(p); + + if (!force_block && !else_node && !need_block(node)) { + p = isl_printer_end_line(p); + p = isl_printer_indent(p, 2); + p = isl_ast_node_print(node, p, + isl_ast_print_options_copy(options)); + p = isl_printer_indent(p, -2); + return p; + } + + p = isl_printer_print_str(p, " {"); + p = isl_printer_end_line(p); + p = isl_printer_indent(p, 2); + p = print_ast_node_c(p, node, options, 1, 0); + p = isl_printer_indent(p, -2); + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "}"); + if (else_node) { + if (else_node->type == isl_ast_node_if) { + p = isl_printer_print_str(p, " else "); + p = print_if_c(p, else_node, options, 0, 1); + } else { + p = isl_printer_print_str(p, " else"); + p = print_body_c(p, else_node, NULL, options, 1); + } + } else + p = isl_printer_end_line(p); + + return p; +} + +/* Print the start of a compound statement. + */ +static __isl_give isl_printer *start_block(__isl_take isl_printer *p) +{ + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "{"); + p = isl_printer_end_line(p); + p = isl_printer_indent(p, 2); + + return p; +} + +/* Print the end of a compound statement. + */ +static __isl_give isl_printer *end_block(__isl_take isl_printer *p) +{ + p = isl_printer_indent(p, -2); + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "}"); + p = isl_printer_end_line(p); + + return p; +} + +/* Print the for node "node". + * + * If the for node is degenerate, it is printed as + * + * type iterator = init; + * body + * + * Otherwise, it is printed as + * + * for (type iterator = init; cond; iterator += inc) + * body + * + * "in_block" is set if we are currently inside a block. + * "in_list" is set if the current node is not alone in the block. + * If we are not in a block or if the current not is not alone in the block + * then we print a block around a degenerate for loop such that the variable + * declaration will not conflict with any potential other declaration + * of the same variable. + */ +static __isl_give isl_printer *print_for_c(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node, + __isl_keep isl_ast_print_options *options, int in_block, int in_list) +{ + isl_id *id; + const char *name; + const char *type; + + type = isl_options_get_ast_iterator_type(isl_printer_get_ctx(p)); + if (!node->u.f.degenerate) { + id = isl_ast_expr_get_id(node->u.f.iterator); + name = isl_id_get_name(id); + isl_id_free(id); + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "for ("); + p = isl_printer_print_str(p, type); + p = isl_printer_print_str(p, " "); + p = isl_printer_print_str(p, name); + p = isl_printer_print_str(p, " = "); + p = isl_printer_print_ast_expr(p, node->u.f.init); + p = isl_printer_print_str(p, "; "); + p = isl_printer_print_ast_expr(p, node->u.f.cond); + p = isl_printer_print_str(p, "; "); + p = isl_printer_print_str(p, name); + p = isl_printer_print_str(p, " += "); + p = isl_printer_print_ast_expr(p, node->u.f.inc); + p = isl_printer_print_str(p, ")"); + p = print_body_c(p, node->u.f.body, NULL, options, 0); + } else { + id = isl_ast_expr_get_id(node->u.f.iterator); + name = isl_id_get_name(id); + isl_id_free(id); + if (!in_block || in_list) + p = start_block(p); + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, type); + p = isl_printer_print_str(p, " "); + p = isl_printer_print_str(p, name); + p = isl_printer_print_str(p, " = "); + p = isl_printer_print_ast_expr(p, node->u.f.init); + p = isl_printer_print_str(p, ";"); + p = isl_printer_end_line(p); + p = print_ast_node_c(p, node->u.f.body, options, 1, 0); + if (!in_block || in_list) + p = end_block(p); + } + + return p; +} + +/* Print the if node "node". + * If "new_line" is set then the if node should be printed on a new line. + * If "force_block" is set, then print out the body as a block. + */ +static __isl_give isl_printer *print_if_c(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node, + __isl_keep isl_ast_print_options *options, int new_line, + int force_block) +{ + if (new_line) + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "if ("); + p = isl_printer_print_ast_expr(p, node->u.i.guard); + p = isl_printer_print_str(p, ")"); + p = print_body_c(p, node->u.i.then, node->u.i.else_node, options, + force_block); + + return p; +} + +/* Print the "node" to "p". + * + * "in_block" is set if we are currently inside a block. + * If so, we do not print a block around the children of a block node. + * We do this to avoid an extra block around the body of a degenerate + * for node. + * + * "in_list" is set if the current node is not alone in the block. + */ +static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node, + __isl_keep isl_ast_print_options *options, int in_block, int in_list) +{ + switch (node->type) { + case isl_ast_node_for: + if (options->print_for) + return options->print_for(p, + isl_ast_print_options_copy(options), + node, options->print_for_user); + p = print_for_c(p, node, options, in_block, in_list); + break; + case isl_ast_node_if: + p = print_if_c(p, node, options, 1, 0); + break; + case isl_ast_node_block: + if (!in_block) + p = start_block(p); + p = isl_ast_node_list_print(node->u.b.children, p, options); + if (!in_block) + p = end_block(p); + break; + case isl_ast_node_mark: + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "// "); + p = isl_printer_print_str(p, isl_id_get_name(node->u.m.mark)); + p = isl_printer_end_line(p); + p = print_ast_node_c(p, node->u.m.node, options, 0, in_list); + break; + case isl_ast_node_user: + if (options->print_user) + return options->print_user(p, + isl_ast_print_options_copy(options), + node, options->print_user_user); + p = isl_printer_start_line(p); + p = isl_printer_print_ast_expr(p, node->u.e.expr); + p = isl_printer_print_str(p, ";"); + p = isl_printer_end_line(p); + break; + case isl_ast_node_error: + break; + } + return p; +} + +/* Print the for node "node" to "p". + */ +__isl_give isl_printer *isl_ast_node_for_print(__isl_keep isl_ast_node *node, + __isl_take isl_printer *p, __isl_take isl_ast_print_options *options) +{ + if (!node || !options) + goto error; + if (node->type != isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not a for node", goto error); + p = print_for_c(p, node, options, 0, 0); + isl_ast_print_options_free(options); + return p; +error: + isl_ast_print_options_free(options); + isl_printer_free(p); + return NULL; +} + +/* Print the if node "node" to "p". + */ +__isl_give isl_printer *isl_ast_node_if_print(__isl_keep isl_ast_node *node, + __isl_take isl_printer *p, __isl_take isl_ast_print_options *options) +{ + if (!node || !options) + goto error; + if (node->type != isl_ast_node_if) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, + "not an if node", goto error); + p = print_if_c(p, node, options, 1, 0); + isl_ast_print_options_free(options); + return p; +error: + isl_ast_print_options_free(options); + isl_printer_free(p); + return NULL; +} + +/* Print "node" to "p". + */ +__isl_give isl_printer *isl_ast_node_print(__isl_keep isl_ast_node *node, + __isl_take isl_printer *p, __isl_take isl_ast_print_options *options) +{ + if (!options || !node) + goto error; + p = print_ast_node_c(p, node, options, 0, 0); + isl_ast_print_options_free(options); + return p; +error: + isl_ast_print_options_free(options); + isl_printer_free(p); + return NULL; +} + +/* Print "node" to "p". + */ +__isl_give isl_printer *isl_printer_print_ast_node(__isl_take isl_printer *p, + __isl_keep isl_ast_node *node) +{ + int format; + isl_ast_print_options *options; + + if (!p) + return NULL; + + format = isl_printer_get_output_format(p); + switch (format) { + case ISL_FORMAT_ISL: + p = print_ast_node_isl(p, node); + break; + case ISL_FORMAT_C: + options = isl_ast_print_options_alloc(isl_printer_get_ctx(p)); + p = isl_ast_node_print(node, p, options); + break; + default: + isl_die(isl_printer_get_ctx(p), isl_error_unsupported, + "output format not supported for ast_node", + return isl_printer_free(p)); + } + + return p; +} + +/* Print the list of nodes "list" to "p". + */ +__isl_give isl_printer *isl_ast_node_list_print( + __isl_keep isl_ast_node_list *list, __isl_take isl_printer *p, + __isl_keep isl_ast_print_options *options) +{ + int i; + + if (!p || !list || !options) + return isl_printer_free(p); + + for (i = 0; i < list->n; ++i) + p = print_ast_node_c(p, list->p[i], options, 1, 1); + + return p; +} + +#define ISL_AST_MACRO_FLOORD (1 << 0) +#define ISL_AST_MACRO_MIN (1 << 1) +#define ISL_AST_MACRO_MAX (1 << 2) +#define ISL_AST_MACRO_ALL (ISL_AST_MACRO_FLOORD | \ + ISL_AST_MACRO_MIN | \ + ISL_AST_MACRO_MAX) + +/* If "expr" contains an isl_ast_op_min, isl_ast_op_max or isl_ast_op_fdiv_q + * then set the corresponding bit in "macros". + */ +static int ast_expr_required_macros(__isl_keep isl_ast_expr *expr, int macros) +{ + int i; + + if (macros == ISL_AST_MACRO_ALL) + return macros; + + if (expr->type != isl_ast_expr_op) + return macros; + + if (expr->u.op.op == isl_ast_op_min) + macros |= ISL_AST_MACRO_MIN; + if (expr->u.op.op == isl_ast_op_max) + macros |= ISL_AST_MACRO_MAX; + if (expr->u.op.op == isl_ast_op_fdiv_q) + macros |= ISL_AST_MACRO_FLOORD; + + for (i = 0; i < expr->u.op.n_arg; ++i) + macros = ast_expr_required_macros(expr->u.op.args[i], macros); + + return macros; +} + +static int ast_node_list_required_macros(__isl_keep isl_ast_node_list *list, + int macros); + +/* If "node" contains an isl_ast_op_min, isl_ast_op_max or isl_ast_op_fdiv_q + * then set the corresponding bit in "macros". + */ +static int ast_node_required_macros(__isl_keep isl_ast_node *node, int macros) +{ + if (macros == ISL_AST_MACRO_ALL) + return macros; + + switch (node->type) { + case isl_ast_node_for: + macros = ast_expr_required_macros(node->u.f.init, macros); + if (!node->u.f.degenerate) { + macros = ast_expr_required_macros(node->u.f.cond, + macros); + macros = ast_expr_required_macros(node->u.f.inc, + macros); + } + macros = ast_node_required_macros(node->u.f.body, macros); + break; + case isl_ast_node_if: + macros = ast_expr_required_macros(node->u.i.guard, macros); + macros = ast_node_required_macros(node->u.i.then, macros); + if (node->u.i.else_node) + macros = ast_node_required_macros(node->u.i.else_node, + macros); + break; + case isl_ast_node_block: + macros = ast_node_list_required_macros(node->u.b.children, + macros); + break; + case isl_ast_node_mark: + macros = ast_node_required_macros(node->u.m.node, macros); + break; + case isl_ast_node_user: + macros = ast_expr_required_macros(node->u.e.expr, macros); + break; + case isl_ast_node_error: + break; + } + + return macros; +} + +/* If "list" contains an isl_ast_op_min, isl_ast_op_max or isl_ast_op_fdiv_q + * then set the corresponding bit in "macros". + */ +static int ast_node_list_required_macros(__isl_keep isl_ast_node_list *list, + int macros) +{ + int i; + + for (i = 0; i < list->n; ++i) + macros = ast_node_required_macros(list->p[i], macros); + + return macros; +} + +/* Data structure for keeping track of whether a macro definition + * for a given type has already been printed. + * The value is zero if no definition has been printed and non-zero otherwise. + */ +struct isl_ast_op_printed { + char printed[isl_ast_op_last + 1]; +}; + +/* Create an empty struct isl_ast_op_printed. + */ +static void *create_printed(isl_ctx *ctx) +{ + return isl_calloc_type(ctx, struct isl_ast_op_printed); +} + +/* Free a struct isl_ast_op_printed. + */ +static void free_printed(void *user) +{ + free(user); +} + +/* Ensure that "p" has an isl_ast_op_printed note identified by "id". + */ +static __isl_give isl_printer *alloc_printed(__isl_take isl_printer *p, + __isl_keep isl_id *id) +{ + return alloc_note(p, id, &create_printed, &free_printed); +} + +/* Create an identifier that is used to store + * an isl_ast_op_printed note. + */ +static __isl_give isl_id *printed_id(isl_ctx *ctx) +{ + return isl_id_alloc(ctx, "isl_ast_op_type_printed", NULL); +} + +/* Did the user specify that a macro definition should only be + * printed once and has a macro definition for "type" already + * been printed to "p"? + * If definitions should only be printed once, but a definition + * for "p" has not yet been printed, then mark it as having been + * printed so that it will not printed again. + * The actual printing is taken care of by the caller. + */ +static isl_bool already_printed_once(__isl_keep isl_printer *p, + enum isl_ast_op_type type) +{ + isl_ctx *ctx; + isl_id *id; + struct isl_ast_op_printed *printed; + + if (!p) + return isl_bool_error; + + ctx = isl_printer_get_ctx(p); + if (!isl_options_get_ast_print_macro_once(ctx)) + return isl_bool_false; + + if (type > isl_ast_op_last) + isl_die(isl_printer_get_ctx(p), isl_error_invalid, + "invalid type", return isl_bool_error); + + id = printed_id(isl_printer_get_ctx(p)); + p = alloc_printed(p, id); + printed = get_note(p, id); + isl_id_free(id); + if (!printed) + return isl_bool_error; + + if (printed->printed[type]) + return isl_bool_true; + + printed->printed[type] = 1; + return isl_bool_false; +} + +/* Print a macro definition for the operator "type". + * + * If the user has specified that a macro definition should + * only be printed once to any given printer and if the macro definition + * has already been printed to "p", then do not print the definition. + */ +__isl_give isl_printer *isl_ast_op_type_print_macro( + enum isl_ast_op_type type, __isl_take isl_printer *p) +{ + isl_bool skip; + + skip = already_printed_once(p, type); + if (skip < 0) + return isl_printer_free(p); + if (skip) + return p; + + switch (type) { + case isl_ast_op_min: + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "#define "); + p = isl_printer_print_str(p, get_op_str_c(p, type)); + p = isl_printer_print_str(p, + "(x,y) ((x) < (y) ? (x) : (y))"); + p = isl_printer_end_line(p); + break; + case isl_ast_op_max: + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "#define "); + p = isl_printer_print_str(p, get_op_str_c(p, type)); + p = isl_printer_print_str(p, + "(x,y) ((x) > (y) ? (x) : (y))"); + p = isl_printer_end_line(p); + break; + case isl_ast_op_fdiv_q: + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "#define "); + p = isl_printer_print_str(p, get_op_str_c(p, type)); + p = isl_printer_print_str(p, + "(n,d) " + "(((n)<0) ? -((-(n)+(d)-1)/(d)) : (n)/(d))"); + p = isl_printer_end_line(p); + break; + default: + break; + } + + return p; +} + +/* Call "fn" for each type of operation represented in the "macros" + * bit vector. + */ +static isl_stat foreach_ast_op_type(int macros, + isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user) +{ + if (macros & ISL_AST_MACRO_MIN && fn(isl_ast_op_min, user) < 0) + return isl_stat_error; + if (macros & ISL_AST_MACRO_MAX && fn(isl_ast_op_max, user) < 0) + return isl_stat_error; + if (macros & ISL_AST_MACRO_FLOORD && fn(isl_ast_op_fdiv_q, user) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Call "fn" for each type of operation that appears in "expr" + * and that requires a macro definition. + */ +isl_stat isl_ast_expr_foreach_ast_op_type(__isl_keep isl_ast_expr *expr, + isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user) +{ + int macros; + + if (!expr) + return isl_stat_error; + + macros = ast_expr_required_macros(expr, 0); + return foreach_ast_op_type(macros, fn, user); +} + +/* Call "fn" for each type of operation that appears in "node" + * and that requires a macro definition. + */ +isl_stat isl_ast_node_foreach_ast_op_type(__isl_keep isl_ast_node *node, + isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user) +{ + int macros; + + if (!node) + return isl_stat_error; + + macros = ast_node_required_macros(node, 0); + return foreach_ast_op_type(macros, fn, user); +} + +static isl_stat ast_op_type_print_macro(enum isl_ast_op_type type, void *user) +{ + isl_printer **p = user; + + *p = isl_ast_op_type_print_macro(type, *p); + + return isl_stat_ok; +} + +/* Print macro definitions for all the macros used in the result + * of printing "expr". + */ +__isl_give isl_printer *isl_ast_expr_print_macros( + __isl_keep isl_ast_expr *expr, __isl_take isl_printer *p) +{ + if (isl_ast_expr_foreach_ast_op_type(expr, + &ast_op_type_print_macro, &p) < 0) + return isl_printer_free(p); + return p; +} + +/* Print macro definitions for all the macros used in the result + * of printing "node". + */ +__isl_give isl_printer *isl_ast_node_print_macros( + __isl_keep isl_ast_node *node, __isl_take isl_printer *p) +{ + if (isl_ast_node_foreach_ast_op_type(node, + &ast_op_type_print_macro, &p) < 0) + return isl_printer_free(p); + return p; +} + +/* Return a string containing C code representing this isl_ast_expr. + */ +__isl_give char *isl_ast_expr_to_C_str(__isl_keep isl_ast_expr *expr) +{ + isl_printer *p; + char *str; + + if (!expr) + return NULL; + + p = isl_printer_to_str(isl_ast_expr_get_ctx(expr)); + p = isl_printer_set_output_format(p, ISL_FORMAT_C); + p = isl_printer_print_ast_expr(p, expr); + + str = isl_printer_get_str(p); + + isl_printer_free(p); + + return str; +} + +/* Return a string containing C code representing this isl_ast_node. + */ +__isl_give char *isl_ast_node_to_C_str(__isl_keep isl_ast_node *node) +{ + isl_printer *p; + char *str; + + if (!node) + return NULL; + + p = isl_printer_to_str(isl_ast_node_get_ctx(node)); + p = isl_printer_set_output_format(p, ISL_FORMAT_C); + p = isl_printer_print_ast_node(p, node); + + str = isl_printer_get_str(p); + + isl_printer_free(p); + + return str; +} Index: contrib/isl/isl_ast_build.c =================================================================== --- /dev/null +++ contrib/isl/isl_ast_build.c @@ -0,0 +1,2568 @@ +/* + * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Construct a map that isolates the current dimension. + * + * Essentially, the current dimension of "set" is moved to the single output + * dimension in the result, with the current dimension in the domain replaced + * by an unconstrained variable. + */ +__isl_give isl_map *isl_ast_build_map_to_iterator( + __isl_keep isl_ast_build *build, __isl_take isl_set *set) +{ + isl_map *map; + + map = isl_map_from_domain(set); + map = isl_map_add_dims(map, isl_dim_out, 1); + + if (!build) + return isl_map_free(map); + + map = isl_map_equate(map, isl_dim_in, build->depth, isl_dim_out, 0); + map = isl_map_eliminate(map, isl_dim_in, build->depth, 1); + + return map; +} + +/* Initialize the information derived during the AST generation to default + * values for a schedule domain in "space". + * + * We also check that the remaining fields are not NULL so that + * the calling functions don't have to perform this test. + */ +static __isl_give isl_ast_build *isl_ast_build_init_derived( + __isl_take isl_ast_build *build, __isl_take isl_space *space) +{ + isl_ctx *ctx; + isl_vec *strides; + + build = isl_ast_build_cow(build); + if (!build || !build->domain) + goto error; + + ctx = isl_ast_build_get_ctx(build); + strides = isl_vec_alloc(ctx, isl_space_dim(space, isl_dim_set)); + strides = isl_vec_set_si(strides, 1); + + isl_vec_free(build->strides); + build->strides = strides; + + space = isl_space_map_from_set(space); + isl_multi_aff_free(build->offsets); + build->offsets = isl_multi_aff_zero(isl_space_copy(space)); + isl_multi_aff_free(build->values); + build->values = isl_multi_aff_identity(isl_space_copy(space)); + isl_multi_aff_free(build->internal2input); + build->internal2input = isl_multi_aff_identity(space); + + if (!build->iterators || !build->domain || !build->generated || + !build->pending || !build->values || !build->internal2input || + !build->strides || !build->offsets || !build->options) + return isl_ast_build_free(build); + + return build; +error: + isl_space_free(space); + return isl_ast_build_free(build); +} + +/* Return an isl_id called "c%d", with "%d" set to "i". + * If an isl_id with such a name already appears among the parameters + * in build->domain, then adjust the name to "c%d_%d". + */ +static __isl_give isl_id *generate_name(isl_ctx *ctx, int i, + __isl_keep isl_ast_build *build) +{ + int j; + char name[16]; + isl_set *dom = build->domain; + + snprintf(name, sizeof(name), "c%d", i); + j = 0; + while (isl_set_find_dim_by_name(dom, isl_dim_param, name) >= 0) + snprintf(name, sizeof(name), "c%d_%d", i, j++); + return isl_id_alloc(ctx, name, NULL); +} + +/* Create an isl_ast_build with "set" as domain. + * + * The input set is usually a parameter domain, but we currently allow it to + * be any kind of set. We set the domain of the returned isl_ast_build + * to "set" and initialize all the other fields to default values. + */ +__isl_give isl_ast_build *isl_ast_build_from_context(__isl_take isl_set *set) +{ + int i, n; + isl_ctx *ctx; + isl_space *space; + isl_ast_build *build; + + set = isl_set_compute_divs(set); + if (!set) + return NULL; + + ctx = isl_set_get_ctx(set); + + build = isl_calloc_type(ctx, isl_ast_build); + if (!build) + goto error; + + build->ref = 1; + build->domain = set; + build->generated = isl_set_copy(build->domain); + build->pending = isl_set_universe(isl_set_get_space(build->domain)); + build->options = isl_union_map_empty(isl_space_params_alloc(ctx, 0)); + n = isl_set_dim(set, isl_dim_set); + build->depth = n; + build->iterators = isl_id_list_alloc(ctx, n); + for (i = 0; i < n; ++i) { + isl_id *id; + if (isl_set_has_dim_id(set, isl_dim_set, i)) + id = isl_set_get_dim_id(set, isl_dim_set, i); + else + id = generate_name(ctx, i, build); + build->iterators = isl_id_list_add(build->iterators, id); + } + space = isl_set_get_space(set); + if (isl_space_is_params(space)) + space = isl_space_set_from_params(space); + + return isl_ast_build_init_derived(build, space); +error: + isl_set_free(set); + return NULL; +} + +/* Create an isl_ast_build with a universe (parametric) context. + */ +__isl_give isl_ast_build *isl_ast_build_alloc(isl_ctx *ctx) +{ + isl_space *space; + isl_set *context; + + space = isl_space_params_alloc(ctx, 0); + context = isl_set_universe(space); + + return isl_ast_build_from_context(context); +} + +__isl_give isl_ast_build *isl_ast_build_copy(__isl_keep isl_ast_build *build) +{ + if (!build) + return NULL; + + build->ref++; + return build; +} + +__isl_give isl_ast_build *isl_ast_build_dup(__isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + isl_ast_build *dup; + + if (!build) + return NULL; + + ctx = isl_ast_build_get_ctx(build); + dup = isl_calloc_type(ctx, isl_ast_build); + if (!dup) + return NULL; + + dup->ref = 1; + dup->outer_pos = build->outer_pos; + dup->depth = build->depth; + dup->iterators = isl_id_list_copy(build->iterators); + dup->domain = isl_set_copy(build->domain); + dup->generated = isl_set_copy(build->generated); + dup->pending = isl_set_copy(build->pending); + dup->values = isl_multi_aff_copy(build->values); + dup->internal2input = isl_multi_aff_copy(build->internal2input); + dup->value = isl_pw_aff_copy(build->value); + dup->strides = isl_vec_copy(build->strides); + dup->offsets = isl_multi_aff_copy(build->offsets); + dup->executed = isl_union_map_copy(build->executed); + dup->single_valued = build->single_valued; + dup->options = isl_union_map_copy(build->options); + dup->at_each_domain = build->at_each_domain; + dup->at_each_domain_user = build->at_each_domain_user; + dup->before_each_for = build->before_each_for; + dup->before_each_for_user = build->before_each_for_user; + dup->after_each_for = build->after_each_for; + dup->after_each_for_user = build->after_each_for_user; + dup->before_each_mark = build->before_each_mark; + dup->before_each_mark_user = build->before_each_mark_user; + dup->after_each_mark = build->after_each_mark; + dup->after_each_mark_user = build->after_each_mark_user; + dup->create_leaf = build->create_leaf; + dup->create_leaf_user = build->create_leaf_user; + dup->node = isl_schedule_node_copy(build->node); + if (build->loop_type) { + int i; + + dup->n = build->n; + dup->loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, dup->n); + if (dup->n && !dup->loop_type) + return isl_ast_build_free(dup); + for (i = 0; i < dup->n; ++i) + dup->loop_type[i] = build->loop_type[i]; + } + + if (!dup->iterators || !dup->domain || !dup->generated || + !dup->pending || !dup->values || + !dup->strides || !dup->offsets || !dup->options || + (build->internal2input && !dup->internal2input) || + (build->executed && !dup->executed) || + (build->value && !dup->value) || + (build->node && !dup->node)) + return isl_ast_build_free(dup); + + return dup; +} + +/* Align the parameters of "build" to those of "model", introducing + * additional parameters if needed. + */ +__isl_give isl_ast_build *isl_ast_build_align_params( + __isl_take isl_ast_build *build, __isl_take isl_space *model) +{ + build = isl_ast_build_cow(build); + if (!build) + goto error; + + build->domain = isl_set_align_params(build->domain, + isl_space_copy(model)); + build->generated = isl_set_align_params(build->generated, + isl_space_copy(model)); + build->pending = isl_set_align_params(build->pending, + isl_space_copy(model)); + build->values = isl_multi_aff_align_params(build->values, + isl_space_copy(model)); + build->offsets = isl_multi_aff_align_params(build->offsets, + isl_space_copy(model)); + build->options = isl_union_map_align_params(build->options, + isl_space_copy(model)); + if (build->internal2input) { + build->internal2input = + isl_multi_aff_align_params(build->internal2input, + model); + if (!build->internal2input) + return isl_ast_build_free(build); + } else { + isl_space_free(model); + } + + if (!build->domain || !build->values || !build->offsets || + !build->options) + return isl_ast_build_free(build); + + return build; +error: + isl_space_free(model); + return NULL; +} + +__isl_give isl_ast_build *isl_ast_build_cow(__isl_take isl_ast_build *build) +{ + if (!build) + return NULL; + + if (build->ref == 1) + return build; + build->ref--; + return isl_ast_build_dup(build); +} + +__isl_null isl_ast_build *isl_ast_build_free( + __isl_take isl_ast_build *build) +{ + if (!build) + return NULL; + + if (--build->ref > 0) + return NULL; + + isl_id_list_free(build->iterators); + isl_set_free(build->domain); + isl_set_free(build->generated); + isl_set_free(build->pending); + isl_multi_aff_free(build->values); + isl_multi_aff_free(build->internal2input); + isl_pw_aff_free(build->value); + isl_vec_free(build->strides); + isl_multi_aff_free(build->offsets); + isl_multi_aff_free(build->schedule_map); + isl_union_map_free(build->executed); + isl_union_map_free(build->options); + isl_schedule_node_free(build->node); + free(build->loop_type); + isl_set_free(build->isolated); + + free(build); + + return NULL; +} + +isl_ctx *isl_ast_build_get_ctx(__isl_keep isl_ast_build *build) +{ + return build ? isl_set_get_ctx(build->domain) : NULL; +} + +/* Replace build->options by "options". + */ +__isl_give isl_ast_build *isl_ast_build_set_options( + __isl_take isl_ast_build *build, __isl_take isl_union_map *options) +{ + build = isl_ast_build_cow(build); + + if (!build || !options) + goto error; + + isl_union_map_free(build->options); + build->options = options; + + return build; +error: + isl_union_map_free(options); + return isl_ast_build_free(build); +} + +/* Set the iterators for the next code generation. + * + * If we still have some iterators left from the previous code generation + * (if any) or if iterators have already been set by a previous + * call to this function, then we remove them first. + */ +__isl_give isl_ast_build *isl_ast_build_set_iterators( + __isl_take isl_ast_build *build, __isl_take isl_id_list *iterators) +{ + int dim, n_it; + + build = isl_ast_build_cow(build); + if (!build) + goto error; + + dim = isl_set_dim(build->domain, isl_dim_set); + n_it = isl_id_list_n_id(build->iterators); + if (n_it < dim) + isl_die(isl_ast_build_get_ctx(build), isl_error_internal, + "isl_ast_build in inconsistent state", goto error); + if (n_it > dim) + build->iterators = isl_id_list_drop(build->iterators, + dim, n_it - dim); + build->iterators = isl_id_list_concat(build->iterators, iterators); + if (!build->iterators) + return isl_ast_build_free(build); + + return build; +error: + isl_id_list_free(iterators); + return isl_ast_build_free(build); +} + +/* Set the "at_each_domain" callback of "build" to "fn". + */ +__isl_give isl_ast_build *isl_ast_build_set_at_each_domain( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user), void *user) +{ + build = isl_ast_build_cow(build); + + if (!build) + return NULL; + + build->at_each_domain = fn; + build->at_each_domain_user = user; + + return build; +} + +/* Set the "before_each_for" callback of "build" to "fn". + */ +__isl_give isl_ast_build *isl_ast_build_set_before_each_for( + __isl_take isl_ast_build *build, + __isl_give isl_id *(*fn)(__isl_keep isl_ast_build *build, + void *user), void *user) +{ + build = isl_ast_build_cow(build); + + if (!build) + return NULL; + + build->before_each_for = fn; + build->before_each_for_user = user; + + return build; +} + +/* Set the "after_each_for" callback of "build" to "fn". + */ +__isl_give isl_ast_build *isl_ast_build_set_after_each_for( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user), void *user) +{ + build = isl_ast_build_cow(build); + + if (!build) + return NULL; + + build->after_each_for = fn; + build->after_each_for_user = user; + + return build; +} + +/* Set the "before_each_mark" callback of "build" to "fn". + */ +__isl_give isl_ast_build *isl_ast_build_set_before_each_mark( + __isl_take isl_ast_build *build, + isl_stat (*fn)(__isl_keep isl_id *mark, __isl_keep isl_ast_build *build, + void *user), void *user) +{ + build = isl_ast_build_cow(build); + + if (!build) + return NULL; + + build->before_each_mark = fn; + build->before_each_mark_user = user; + + return build; +} + +/* Set the "after_each_mark" callback of "build" to "fn". + */ +__isl_give isl_ast_build *isl_ast_build_set_after_each_mark( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user), void *user) +{ + build = isl_ast_build_cow(build); + + if (!build) + return NULL; + + build->after_each_mark = fn; + build->after_each_mark_user = user; + + return build; +} + +/* Set the "create_leaf" callback of "build" to "fn". + */ +__isl_give isl_ast_build *isl_ast_build_set_create_leaf( + __isl_take isl_ast_build *build, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_build *build, + void *user), void *user) +{ + build = isl_ast_build_cow(build); + + if (!build) + return NULL; + + build->create_leaf = fn; + build->create_leaf_user = user; + + return build; +} + +/* Clear all information that is specific to this code generation + * and that is (probably) not meaningful to any nested code generation. + */ +__isl_give isl_ast_build *isl_ast_build_clear_local_info( + __isl_take isl_ast_build *build) +{ + isl_space *space; + + build = isl_ast_build_cow(build); + if (!build) + return NULL; + + space = isl_union_map_get_space(build->options); + isl_union_map_free(build->options); + build->options = isl_union_map_empty(space); + + build->at_each_domain = NULL; + build->at_each_domain_user = NULL; + build->before_each_for = NULL; + build->before_each_for_user = NULL; + build->after_each_for = NULL; + build->after_each_for_user = NULL; + build->before_each_mark = NULL; + build->before_each_mark_user = NULL; + build->after_each_mark = NULL; + build->after_each_mark_user = NULL; + build->create_leaf = NULL; + build->create_leaf_user = NULL; + + if (!build->options) + return isl_ast_build_free(build); + + return build; +} + +/* Have any loops been eliminated? + * That is, do any of the original schedule dimensions have a fixed + * value that has been substituted? + */ +static int any_eliminated(isl_ast_build *build) +{ + int i; + + for (i = 0; i < build->depth; ++i) + if (isl_ast_build_has_affine_value(build, i)) + return 1; + + return 0; +} + +/* Clear build->schedule_map. + * This function should be called whenever anything that might affect + * the result of isl_ast_build_get_schedule_map_multi_aff changes. + * In particular, it should be called when the depth is changed or + * when an iterator is determined to have a fixed value. + */ +static void isl_ast_build_reset_schedule_map(__isl_keep isl_ast_build *build) +{ + if (!build) + return; + isl_multi_aff_free(build->schedule_map); + build->schedule_map = NULL; +} + +/* Do we need a (non-trivial) schedule map? + * That is, is the internal schedule space different from + * the external schedule space? + * + * The internal and external schedule spaces are only the same + * if code has been generated for the entire schedule and if none + * of the loops have been eliminated. + */ +__isl_give int isl_ast_build_need_schedule_map(__isl_keep isl_ast_build *build) +{ + int dim; + + if (!build) + return -1; + + dim = isl_set_dim(build->domain, isl_dim_set); + return build->depth != dim || any_eliminated(build); +} + +/* Return a mapping from the internal schedule space to the external + * schedule space in the form of an isl_multi_aff. + * The internal schedule space originally corresponds to that of the + * input schedule. This may change during the code generation if + * if isl_ast_build_insert_dim is ever called. + * The external schedule space corresponds to the + * loops that have been generated. + * + * Currently, the only difference between the internal schedule domain + * and the external schedule domain is that some dimensions are projected + * out in the external schedule domain. In particular, the dimensions + * for which no code has been generated yet and the dimensions that correspond + * to eliminated loops. + * + * We cache a copy of the schedule_map in build->schedule_map. + * The cache is cleared through isl_ast_build_reset_schedule_map + * whenever anything changes that might affect the result of this function. + */ +__isl_give isl_multi_aff *isl_ast_build_get_schedule_map_multi_aff( + __isl_keep isl_ast_build *build) +{ + isl_space *space; + isl_multi_aff *ma; + + if (!build) + return NULL; + if (build->schedule_map) + return isl_multi_aff_copy(build->schedule_map); + + space = isl_ast_build_get_space(build, 1); + space = isl_space_map_from_set(space); + ma = isl_multi_aff_identity(space); + if (isl_ast_build_need_schedule_map(build)) { + int i; + int dim = isl_set_dim(build->domain, isl_dim_set); + ma = isl_multi_aff_drop_dims(ma, isl_dim_out, + build->depth, dim - build->depth); + for (i = build->depth - 1; i >= 0; --i) + if (isl_ast_build_has_affine_value(build, i)) + ma = isl_multi_aff_drop_dims(ma, + isl_dim_out, i, 1); + } + + build->schedule_map = ma; + return isl_multi_aff_copy(build->schedule_map); +} + +/* Return a mapping from the internal schedule space to the external + * schedule space in the form of an isl_map. + */ +__isl_give isl_map *isl_ast_build_get_schedule_map( + __isl_keep isl_ast_build *build) +{ + isl_multi_aff *ma; + + ma = isl_ast_build_get_schedule_map_multi_aff(build); + return isl_map_from_multi_aff(ma); +} + +/* Return the position of the dimension in build->domain for which + * an AST node is currently being generated. + */ +int isl_ast_build_get_depth(__isl_keep isl_ast_build *build) +{ + return build ? build->depth : -1; +} + +/* Prepare for generating code for the next level. + * In particular, increase the depth and reset any information + * that is local to the current depth. + */ +__isl_give isl_ast_build *isl_ast_build_increase_depth( + __isl_take isl_ast_build *build) +{ + build = isl_ast_build_cow(build); + if (!build) + return NULL; + build->depth++; + isl_ast_build_reset_schedule_map(build); + build->value = isl_pw_aff_free(build->value); + return build; +} + +void isl_ast_build_dump(__isl_keep isl_ast_build *build) +{ + if (!build) + return; + + fprintf(stderr, "domain: "); + isl_set_dump(build->domain); + fprintf(stderr, "generated: "); + isl_set_dump(build->generated); + fprintf(stderr, "pending: "); + isl_set_dump(build->pending); + fprintf(stderr, "iterators: "); + isl_id_list_dump(build->iterators); + fprintf(stderr, "values: "); + isl_multi_aff_dump(build->values); + if (build->value) { + fprintf(stderr, "value: "); + isl_pw_aff_dump(build->value); + } + fprintf(stderr, "strides: "); + isl_vec_dump(build->strides); + fprintf(stderr, "offsets: "); + isl_multi_aff_dump(build->offsets); + fprintf(stderr, "internal2input: "); + isl_multi_aff_dump(build->internal2input); +} + +/* Initialize "build" for AST construction in schedule space "space" + * in the case that build->domain is a parameter set. + * + * build->iterators is assumed to have been updated already. + */ +static __isl_give isl_ast_build *isl_ast_build_init( + __isl_take isl_ast_build *build, __isl_take isl_space *space) +{ + isl_set *set; + + build = isl_ast_build_cow(build); + if (!build) + goto error; + + set = isl_set_universe(isl_space_copy(space)); + build->domain = isl_set_intersect_params(isl_set_copy(set), + build->domain); + build->pending = isl_set_intersect_params(isl_set_copy(set), + build->pending); + build->generated = isl_set_intersect_params(set, build->generated); + + return isl_ast_build_init_derived(build, space); +error: + isl_ast_build_free(build); + isl_space_free(space); + return NULL; +} + +/* Assign "aff" to *user and return -1, effectively extracting + * the first (and presumably only) affine expression in the isl_pw_aff + * on which this function is used. + */ +static isl_stat extract_single_piece(__isl_take isl_set *set, + __isl_take isl_aff *aff, void *user) +{ + isl_aff **p = user; + + *p = aff; + isl_set_free(set); + + return isl_stat_error; +} + +/* Intersect "set" with the stride constraint of "build", if any. + */ +static __isl_give isl_set *intersect_stride_constraint(__isl_take isl_set *set, + __isl_keep isl_ast_build *build) +{ + isl_set *stride; + + if (!build) + return isl_set_free(set); + if (!isl_ast_build_has_stride(build, build->depth)) + return set; + + stride = isl_ast_build_get_stride_constraint(build); + return isl_set_intersect(set, stride); +} + +/* Check if the given bounds on the current dimension (together with + * the stride constraint, if any) imply that + * this current dimension attains only a single value (in terms of + * parameters and outer dimensions). + * If so, we record it in build->value. + * If, moreover, this value can be represented as a single affine expression, + * then we also update build->values, effectively marking the current + * dimension as "eliminated". + * + * When computing the gist of the fixed value that can be represented + * as a single affine expression, it is important to only take into + * account the domain constraints in the original AST build and + * not the domain of the affine expression itself. + * Otherwise, a [i/3] is changed into a i/3 because we know that i + * is a multiple of 3, but then we end up not expressing anywhere + * in the context that i is a multiple of 3. + */ +static __isl_give isl_ast_build *update_values( + __isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds) +{ + int sv; + isl_pw_multi_aff *pma; + isl_aff *aff = NULL; + isl_map *it_map; + isl_set *set; + + set = isl_set_from_basic_set(bounds); + set = isl_set_intersect(set, isl_set_copy(build->domain)); + set = intersect_stride_constraint(set, build); + it_map = isl_ast_build_map_to_iterator(build, set); + + sv = isl_map_is_single_valued(it_map); + if (sv < 0) + build = isl_ast_build_free(build); + if (!build || !sv) { + isl_map_free(it_map); + return build; + } + + pma = isl_pw_multi_aff_from_map(it_map); + build->value = isl_pw_multi_aff_get_pw_aff(pma, 0); + build->value = isl_ast_build_compute_gist_pw_aff(build, build->value); + build->value = isl_pw_aff_coalesce(build->value); + isl_pw_multi_aff_free(pma); + + if (!build->value) + return isl_ast_build_free(build); + + if (isl_pw_aff_n_piece(build->value) != 1) + return build; + + isl_pw_aff_foreach_piece(build->value, &extract_single_piece, &aff); + + build->values = isl_multi_aff_set_aff(build->values, build->depth, aff); + if (!build->values) + return isl_ast_build_free(build); + isl_ast_build_reset_schedule_map(build); + return build; +} + +/* Update the AST build based on the given loop bounds for + * the current dimension and the stride information available in the build. + * + * We first make sure that the bounds do not refer to any iterators + * that have already been eliminated. + * Then, we check if the bounds imply that the current iterator + * has a fixed value. + * If they do and if this fixed value can be expressed as a single + * affine expression, we eliminate the iterators from the bounds. + * Note that we cannot simply plug in this single value using + * isl_basic_set_preimage_multi_aff as the single value may only + * be defined on a subset of the domain. Plugging in the value + * would restrict the build domain to this subset, while this + * restriction may not be reflected in the generated code. + * Finally, we intersect build->domain with the updated bounds. + * We also add the stride constraint unless we have been able + * to find a fixed value expressed as a single affine expression. + * + * Note that the check for a fixed value in update_values requires + * us to intersect the bounds with the current build domain. + * When we intersect build->domain with the updated bounds in + * the final step, we make sure that these updated bounds have + * not been intersected with the old build->domain. + * Otherwise, we would indirectly intersect the build domain with itself, + * which can lead to inefficiencies, in particular if the build domain + * contains any unknown divs. + * + * The pending and generated sets are not updated by this function to + * match the updated domain. + * The caller still needs to call isl_ast_build_set_pending_generated. + */ +__isl_give isl_ast_build *isl_ast_build_set_loop_bounds( + __isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds) +{ + isl_set *set; + + build = isl_ast_build_cow(build); + if (!build) + goto error; + + build = update_values(build, isl_basic_set_copy(bounds)); + if (!build) + goto error; + set = isl_set_from_basic_set(isl_basic_set_copy(bounds)); + if (isl_ast_build_has_affine_value(build, build->depth)) { + set = isl_set_eliminate(set, isl_dim_set, build->depth, 1); + set = isl_set_compute_divs(set); + build->pending = isl_set_intersect(build->pending, + isl_set_copy(set)); + build->domain = isl_set_intersect(build->domain, set); + } else { + build->domain = isl_set_intersect(build->domain, set); + build = isl_ast_build_include_stride(build); + if (!build) + goto error; + } + isl_basic_set_free(bounds); + + if (!build->domain || !build->pending || !build->generated) + return isl_ast_build_free(build); + + return build; +error: + isl_ast_build_free(build); + isl_basic_set_free(bounds); + return NULL; +} + +/* Update the pending and generated sets of "build" according to "bounds". + * If the build has an affine value at the current depth, + * then isl_ast_build_set_loop_bounds has already set the pending set. + * Otherwise, do it here. + */ +__isl_give isl_ast_build *isl_ast_build_set_pending_generated( + __isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds) +{ + isl_basic_set *generated, *pending; + + if (!build) + goto error; + + if (isl_ast_build_has_affine_value(build, build->depth)) { + isl_basic_set_free(bounds); + return build; + } + + build = isl_ast_build_cow(build); + if (!build) + goto error; + + pending = isl_basic_set_copy(bounds); + pending = isl_basic_set_drop_constraints_involving_dims(pending, + isl_dim_set, build->depth, 1); + build->pending = isl_set_intersect(build->pending, + isl_set_from_basic_set(pending)); + generated = bounds; + generated = isl_basic_set_drop_constraints_not_involving_dims( + generated, isl_dim_set, build->depth, 1); + build->generated = isl_set_intersect(build->generated, + isl_set_from_basic_set(generated)); + + if (!build->pending || !build->generated) + return isl_ast_build_free(build); + + return build; +error: + isl_ast_build_free(build); + isl_basic_set_free(bounds); + return NULL; +} + +/* Intersect build->domain with "set", where "set" is specified + * in terms of the internal schedule domain. + */ +static __isl_give isl_ast_build *isl_ast_build_restrict_internal( + __isl_take isl_ast_build *build, __isl_take isl_set *set) +{ + build = isl_ast_build_cow(build); + if (!build) + goto error; + + set = isl_set_compute_divs(set); + build->domain = isl_set_intersect(build->domain, set); + build->domain = isl_set_coalesce(build->domain); + + if (!build->domain) + return isl_ast_build_free(build); + + return build; +error: + isl_ast_build_free(build); + isl_set_free(set); + return NULL; +} + +/* Intersect build->generated and build->domain with "set", + * where "set" is specified in terms of the internal schedule domain. + */ +__isl_give isl_ast_build *isl_ast_build_restrict_generated( + __isl_take isl_ast_build *build, __isl_take isl_set *set) +{ + set = isl_set_compute_divs(set); + build = isl_ast_build_restrict_internal(build, isl_set_copy(set)); + build = isl_ast_build_cow(build); + if (!build) + goto error; + + build->generated = isl_set_intersect(build->generated, set); + build->generated = isl_set_coalesce(build->generated); + + if (!build->generated) + return isl_ast_build_free(build); + + return build; +error: + isl_ast_build_free(build); + isl_set_free(set); + return NULL; +} + +/* Replace the set of pending constraints by "guard", which is then + * no longer considered as pending. + * That is, add "guard" to the generated constraints and clear all pending + * constraints, making the domain equal to the generated constraints. + */ +__isl_give isl_ast_build *isl_ast_build_replace_pending_by_guard( + __isl_take isl_ast_build *build, __isl_take isl_set *guard) +{ + build = isl_ast_build_restrict_generated(build, guard); + build = isl_ast_build_cow(build); + if (!build) + return NULL; + + isl_set_free(build->domain); + build->domain = isl_set_copy(build->generated); + isl_set_free(build->pending); + build->pending = isl_set_universe(isl_set_get_space(build->domain)); + + if (!build->pending) + return isl_ast_build_free(build); + + return build; +} + +/* Intersect build->domain with "set", where "set" is specified + * in terms of the external schedule domain. + */ +__isl_give isl_ast_build *isl_ast_build_restrict( + __isl_take isl_ast_build *build, __isl_take isl_set *set) +{ + if (isl_set_is_params(set)) + return isl_ast_build_restrict_generated(build, set); + + if (isl_ast_build_need_schedule_map(build)) { + isl_multi_aff *ma; + ma = isl_ast_build_get_schedule_map_multi_aff(build); + set = isl_set_preimage_multi_aff(set, ma); + } + return isl_ast_build_restrict_generated(build, set); +} + +/* Replace build->executed by "executed". + */ +__isl_give isl_ast_build *isl_ast_build_set_executed( + __isl_take isl_ast_build *build, __isl_take isl_union_map *executed) +{ + build = isl_ast_build_cow(build); + if (!build) + goto error; + + isl_union_map_free(build->executed); + build->executed = executed; + + return build; +error: + isl_ast_build_free(build); + isl_union_map_free(executed); + return NULL; +} + +/* Does "build" point to a band node? + * That is, are we currently handling a band node inside a schedule tree? + */ +int isl_ast_build_has_schedule_node(__isl_keep isl_ast_build *build) +{ + if (!build) + return -1; + return build->node != NULL; +} + +/* Return a copy of the band node that "build" refers to. + */ +__isl_give isl_schedule_node *isl_ast_build_get_schedule_node( + __isl_keep isl_ast_build *build) +{ + if (!build) + return NULL; + return isl_schedule_node_copy(build->node); +} + +/* Extract the loop AST generation types for the members of build->node + * and store them in build->loop_type. + */ +static __isl_give isl_ast_build *extract_loop_types( + __isl_take isl_ast_build *build) +{ + int i; + isl_ctx *ctx; + isl_schedule_node *node; + + if (!build) + return NULL; + ctx = isl_ast_build_get_ctx(build); + if (!build->node) + isl_die(ctx, isl_error_internal, "missing AST node", + return isl_ast_build_free(build)); + + free(build->loop_type); + build->n = isl_schedule_node_band_n_member(build->node); + build->loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, build->n); + if (build->n && !build->loop_type) + return isl_ast_build_free(build); + node = build->node; + for (i = 0; i < build->n; ++i) + build->loop_type[i] = + isl_schedule_node_band_member_get_ast_loop_type(node, i); + + return build; +} + +/* Replace the band node that "build" refers to by "node" and + * extract the corresponding loop AST generation types. + */ +__isl_give isl_ast_build *isl_ast_build_set_schedule_node( + __isl_take isl_ast_build *build, + __isl_take isl_schedule_node *node) +{ + build = isl_ast_build_cow(build); + if (!build || !node) + goto error; + + isl_schedule_node_free(build->node); + build->node = node; + + build = extract_loop_types(build); + + return build; +error: + isl_ast_build_free(build); + isl_schedule_node_free(node); + return NULL; +} + +/* Remove any reference to a band node from "build". + */ +__isl_give isl_ast_build *isl_ast_build_reset_schedule_node( + __isl_take isl_ast_build *build) +{ + build = isl_ast_build_cow(build); + if (!build) + return NULL; + + isl_schedule_node_free(build->node); + build->node = NULL; + + return build; +} + +/* Return a copy of the current schedule domain. + */ +__isl_give isl_set *isl_ast_build_get_domain(__isl_keep isl_ast_build *build) +{ + return build ? isl_set_copy(build->domain) : NULL; +} + +/* Return a copy of the set of pending constraints. + */ +__isl_give isl_set *isl_ast_build_get_pending( + __isl_keep isl_ast_build *build) +{ + return build ? isl_set_copy(build->pending) : NULL; +} + +/* Return a copy of the set of generated constraints. + */ +__isl_give isl_set *isl_ast_build_get_generated( + __isl_keep isl_ast_build *build) +{ + return build ? isl_set_copy(build->generated) : NULL; +} + +/* Return a copy of the map from the internal schedule domain + * to the original input schedule domain. + */ +__isl_give isl_multi_aff *isl_ast_build_get_internal2input( + __isl_keep isl_ast_build *build) +{ + return build ? isl_multi_aff_copy(build->internal2input) : NULL; +} + +/* Return the number of variables of the given type + * in the (internal) schedule space. + */ +unsigned isl_ast_build_dim(__isl_keep isl_ast_build *build, + enum isl_dim_type type) +{ + if (!build) + return 0; + return isl_set_dim(build->domain, type); +} + +/* Return the (schedule) space of "build". + * + * If "internal" is set, then this space is the space of the internal + * representation of the entire schedule, including those parts for + * which no code has been generated yet. + * + * If "internal" is not set, then this space is the external representation + * of the loops generated so far. + */ +__isl_give isl_space *isl_ast_build_get_space(__isl_keep isl_ast_build *build, + int internal) +{ + int i; + int dim; + isl_space *space; + + if (!build) + return NULL; + + space = isl_set_get_space(build->domain); + if (internal) + return space; + + if (!isl_ast_build_need_schedule_map(build)) + return space; + + dim = isl_set_dim(build->domain, isl_dim_set); + space = isl_space_drop_dims(space, isl_dim_set, + build->depth, dim - build->depth); + for (i = build->depth - 1; i >= 0; --i) + if (isl_ast_build_has_affine_value(build, i)) + space = isl_space_drop_dims(space, isl_dim_set, i, 1); + + return space; +} + +/* Return the external representation of the schedule space of "build", + * i.e., a space with a dimension for each loop generated so far, + * with the names of the dimensions set to the loop iterators. + */ +__isl_give isl_space *isl_ast_build_get_schedule_space( + __isl_keep isl_ast_build *build) +{ + isl_space *space; + int i, skip; + + if (!build) + return NULL; + + space = isl_ast_build_get_space(build, 0); + + skip = 0; + for (i = 0; i < build->depth; ++i) { + isl_id *id; + + if (isl_ast_build_has_affine_value(build, i)) { + skip++; + continue; + } + + id = isl_ast_build_get_iterator_id(build, i); + space = isl_space_set_dim_id(space, isl_dim_set, i - skip, id); + } + + return space; +} + +/* Return the current schedule, as stored in build->executed, in terms + * of the external schedule domain. + */ +__isl_give isl_union_map *isl_ast_build_get_schedule( + __isl_keep isl_ast_build *build) +{ + isl_union_map *executed; + isl_union_map *schedule; + + if (!build) + return NULL; + + executed = isl_union_map_copy(build->executed); + if (isl_ast_build_need_schedule_map(build)) { + isl_map *proj = isl_ast_build_get_schedule_map(build); + executed = isl_union_map_apply_domain(executed, + isl_union_map_from_map(proj)); + } + schedule = isl_union_map_reverse(executed); + + return schedule; +} + +/* Return the iterator attached to the internal schedule dimension "pos". + */ +__isl_give isl_id *isl_ast_build_get_iterator_id( + __isl_keep isl_ast_build *build, int pos) +{ + if (!build) + return NULL; + + return isl_id_list_get_id(build->iterators, pos); +} + +/* Set the stride and offset of the current dimension to the given + * value and expression. + * + * If we had already found a stride before, then the two strides + * are combined into a single stride. + * + * In particular, if the new stride information is of the form + * + * i = f + s (...) + * + * and the old stride information is of the form + * + * i = f2 + s2 (...) + * + * then we compute the extended gcd of s and s2 + * + * a s + b s2 = g, + * + * with g = gcd(s,s2), multiply the first equation with t1 = b s2/g + * and the second with t2 = a s1/g. + * This results in + * + * i = (b s2 + a s1)/g i = t1 f + t2 f2 + (s s2)/g (...) + * + * so that t1 f + t2 f2 is the combined offset and (s s2)/g = lcm(s,s2) + * is the combined stride. + */ +static __isl_give isl_ast_build *set_stride(__isl_take isl_ast_build *build, + __isl_take isl_val *stride, __isl_take isl_aff *offset) +{ + int pos; + + build = isl_ast_build_cow(build); + if (!build || !stride || !offset) + goto error; + + pos = build->depth; + + if (isl_ast_build_has_stride(build, pos)) { + isl_val *stride2, *a, *b, *g; + isl_aff *offset2; + + stride2 = isl_vec_get_element_val(build->strides, pos); + g = isl_val_gcdext(isl_val_copy(stride), isl_val_copy(stride2), + &a, &b); + a = isl_val_mul(a, isl_val_copy(stride)); + a = isl_val_div(a, isl_val_copy(g)); + stride2 = isl_val_div(stride2, g); + b = isl_val_mul(b, isl_val_copy(stride2)); + stride = isl_val_mul(stride, stride2); + + offset2 = isl_multi_aff_get_aff(build->offsets, pos); + offset2 = isl_aff_scale_val(offset2, a); + offset = isl_aff_scale_val(offset, b); + offset = isl_aff_add(offset, offset2); + } + + build->strides = isl_vec_set_element_val(build->strides, pos, stride); + build->offsets = isl_multi_aff_set_aff(build->offsets, pos, offset); + if (!build->strides || !build->offsets) + return isl_ast_build_free(build); + + return build; +error: + isl_val_free(stride); + isl_aff_free(offset); + return isl_ast_build_free(build); +} + +/* Return a set expressing the stride constraint at the current depth. + * + * In particular, if the current iterator (i) is known to attain values + * + * f + s a + * + * where f is the offset and s is the stride, then the returned set + * expresses the constraint + * + * (f - i) mod s = 0 + */ +__isl_give isl_set *isl_ast_build_get_stride_constraint( + __isl_keep isl_ast_build *build) +{ + isl_aff *aff; + isl_set *set; + isl_val *stride; + int pos; + + if (!build) + return NULL; + + pos = build->depth; + + if (!isl_ast_build_has_stride(build, pos)) + return isl_set_universe(isl_ast_build_get_space(build, 1)); + + stride = isl_ast_build_get_stride(build, pos); + aff = isl_ast_build_get_offset(build, pos); + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, pos, -1); + aff = isl_aff_mod_val(aff, stride); + set = isl_set_from_basic_set(isl_aff_zero_basic_set(aff)); + + return set; +} + +/* Return the expansion implied by the stride and offset at the current + * depth. + * + * That is, return the mapping + * + * [i_0, ..., i_{d-1}, i_d, i_{d+1}, ...] + * -> [i_0, ..., i_{d-1}, s * i_d + offset(i), i_{d+1}, ...] + * + * where s is the stride at the current depth d and offset(i) is + * the corresponding offset. + */ +__isl_give isl_multi_aff *isl_ast_build_get_stride_expansion( + __isl_keep isl_ast_build *build) +{ + isl_space *space; + isl_multi_aff *ma; + int pos; + isl_aff *aff, *offset; + isl_val *stride; + + if (!build) + return NULL; + + pos = isl_ast_build_get_depth(build); + space = isl_ast_build_get_space(build, 1); + space = isl_space_map_from_set(space); + ma = isl_multi_aff_identity(space); + + if (!isl_ast_build_has_stride(build, pos)) + return ma; + + offset = isl_ast_build_get_offset(build, pos); + stride = isl_ast_build_get_stride(build, pos); + aff = isl_multi_aff_get_aff(ma, pos); + aff = isl_aff_scale_val(aff, stride); + aff = isl_aff_add(aff, offset); + ma = isl_multi_aff_set_aff(ma, pos, aff); + + return ma; +} + +/* Add constraints corresponding to any previously detected + * stride on the current dimension to build->domain. + */ +__isl_give isl_ast_build *isl_ast_build_include_stride( + __isl_take isl_ast_build *build) +{ + isl_set *set; + + if (!build) + return NULL; + if (!isl_ast_build_has_stride(build, build->depth)) + return build; + build = isl_ast_build_cow(build); + if (!build) + return NULL; + + set = isl_ast_build_get_stride_constraint(build); + + build->domain = isl_set_intersect(build->domain, isl_set_copy(set)); + build->generated = isl_set_intersect(build->generated, set); + if (!build->domain || !build->generated) + return isl_ast_build_free(build); + + return build; +} + +/* Information used inside detect_stride. + * + * "build" may be updated by detect_stride to include stride information. + * "pos" is equal to build->depth. + */ +struct isl_detect_stride_data { + isl_ast_build *build; + int pos; +}; + +/* Check if constraint "c" imposes any stride on dimension data->pos + * and, if so, update the stride information in data->build. + * + * In order to impose a stride on the dimension, "c" needs to be an equality + * and it needs to involve the dimension. Note that "c" may also be + * a div constraint and thus an inequality that we cannot use. + * + * Let c be of the form + * + * h(p) + g * v * i + g * stride * f(alpha) = 0 + * + * with h(p) an expression in terms of the parameters and outer dimensions + * and f(alpha) an expression in terms of the existentially quantified + * variables. Note that the inner dimensions have been eliminated so + * they do not appear in "c". + * + * If "stride" is not zero and not one, then it represents a non-trivial stride + * on "i". We compute a and b such that + * + * a v + b stride = 1 + * + * We have + * + * g v i = -h(p) + g stride f(alpha) + * + * a g v i = -a h(p) + g stride f(alpha) + * + * a g v i + b g stride i = -a h(p) + g stride * (...) + * + * g i = -a h(p) + g stride * (...) + * + * i = -a h(p)/g + stride * (...) + * + * The expression "-a h(p)/g" can therefore be used as offset. + */ +static isl_stat detect_stride(__isl_take isl_constraint *c, void *user) +{ + struct isl_detect_stride_data *data = user; + int i, n_div; + isl_ctx *ctx; + isl_val *v, *stride, *m; + + if (!isl_constraint_is_equality(c) || + !isl_constraint_involves_dims(c, isl_dim_set, data->pos, 1)) { + isl_constraint_free(c); + return isl_stat_ok; + } + + ctx = isl_constraint_get_ctx(c); + stride = isl_val_zero(ctx); + n_div = isl_constraint_dim(c, isl_dim_div); + for (i = 0; i < n_div; ++i) { + v = isl_constraint_get_coefficient_val(c, isl_dim_div, i); + stride = isl_val_gcd(stride, v); + } + + v = isl_constraint_get_coefficient_val(c, isl_dim_set, data->pos); + m = isl_val_gcd(isl_val_copy(stride), isl_val_copy(v)); + stride = isl_val_div(stride, isl_val_copy(m)); + v = isl_val_div(v, isl_val_copy(m)); + + if (!isl_val_is_zero(stride) && !isl_val_is_one(stride)) { + isl_aff *aff; + isl_val *gcd, *a, *b; + + gcd = isl_val_gcdext(v, isl_val_copy(stride), &a, &b); + isl_val_free(gcd); + isl_val_free(b); + + aff = isl_constraint_get_aff(c); + for (i = 0; i < n_div; ++i) + aff = isl_aff_set_coefficient_si(aff, + isl_dim_div, i, 0); + aff = isl_aff_set_coefficient_si(aff, isl_dim_in, data->pos, 0); + a = isl_val_neg(a); + aff = isl_aff_scale_val(aff, a); + aff = isl_aff_scale_down_val(aff, m); + data->build = set_stride(data->build, stride, aff); + } else { + isl_val_free(stride); + isl_val_free(m); + isl_val_free(v); + } + + isl_constraint_free(c); + return isl_stat_ok; +} + +/* Check if the constraints in "set" imply any stride on the current + * dimension and, if so, record the stride information in "build" + * and return the updated "build". + * + * We compute the affine hull and then check if any of the constraints + * in the hull imposes any stride on the current dimension. + * + * We assume that inner dimensions have been eliminated from "set" + * by the caller. This is needed because the common stride + * may be imposed by different inner dimensions on different parts of + * the domain. + */ +__isl_give isl_ast_build *isl_ast_build_detect_strides( + __isl_take isl_ast_build *build, __isl_take isl_set *set) +{ + isl_basic_set *hull; + struct isl_detect_stride_data data; + + if (!build) + goto error; + + data.build = build; + data.pos = isl_ast_build_get_depth(build); + hull = isl_set_affine_hull(set); + + if (isl_basic_set_foreach_constraint(hull, &detect_stride, &data) < 0) + data.build = isl_ast_build_free(data.build); + + isl_basic_set_free(hull); + return data.build; +error: + isl_set_free(set); + return NULL; +} + +struct isl_ast_build_involves_data { + int depth; + int involves; +}; + +/* Check if "map" involves the input dimension data->depth. + */ +static isl_stat involves_depth(__isl_take isl_map *map, void *user) +{ + struct isl_ast_build_involves_data *data = user; + + data->involves = isl_map_involves_dims(map, isl_dim_in, data->depth, 1); + isl_map_free(map); + + if (data->involves < 0 || data->involves) + return isl_stat_error; + return isl_stat_ok; +} + +/* Do any options depend on the value of the dimension at the current depth? + */ +int isl_ast_build_options_involve_depth(__isl_keep isl_ast_build *build) +{ + struct isl_ast_build_involves_data data; + + if (!build) + return -1; + + data.depth = build->depth; + data.involves = 0; + + if (isl_union_map_foreach_map(build->options, + &involves_depth, &data) < 0) { + if (data.involves < 0 || !data.involves) + return -1; + } + + return data.involves; +} + +/* Construct the map + * + * { [i] -> [i] : i < pos; [i] -> [i + 1] : i >= pos } + * + * with "space" the parameter space of the constructed map. + */ +static __isl_give isl_map *construct_insertion_map(__isl_take isl_space *space, + int pos) +{ + isl_constraint *c; + isl_basic_map *bmap1, *bmap2; + + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, 1); + space = isl_space_map_from_set(space); + c = isl_constraint_alloc_equality(isl_local_space_from_space(space)); + c = isl_constraint_set_coefficient_si(c, isl_dim_in, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_out, 0, -1); + bmap1 = isl_basic_map_from_constraint(isl_constraint_copy(c)); + c = isl_constraint_set_constant_si(c, 1); + bmap2 = isl_basic_map_from_constraint(c); + + bmap1 = isl_basic_map_upper_bound_si(bmap1, isl_dim_in, 0, pos - 1); + bmap2 = isl_basic_map_lower_bound_si(bmap2, isl_dim_in, 0, pos); + + return isl_basic_map_union(bmap1, bmap2); +} + +static const char *option_str[] = { + [isl_ast_loop_atomic] = "atomic", + [isl_ast_loop_unroll] = "unroll", + [isl_ast_loop_separate] = "separate" +}; + +/* Update the "options" to reflect the insertion of a dimension + * at position "pos" in the schedule domain space. + * "space" is the original domain space before the insertion and + * may be named and/or structured. + * + * The (relevant) input options all have "space" as domain, which + * has to be mapped to the extended space. + * The values of the ranges also refer to the schedule domain positions + * and they therefore also need to be adjusted. In particular, values + * smaller than pos do not need to change, while values greater than or + * equal to pos need to be incremented. + * That is, we need to apply the following map. + * + * { atomic[i] -> atomic[i] : i < pos; [i] -> [i + 1] : i >= pos; + * unroll[i] -> unroll[i] : i < pos; [i] -> [i + 1] : i >= pos; + * separate[i] -> separate[i] : i < pos; [i] -> [i + 1] : i >= pos; + * separation_class[[i] -> [c]] + * -> separation_class[[i] -> [c]] : i < pos; + * separation_class[[i] -> [c]] + * -> separation_class[[i + 1] -> [c]] : i >= pos } + */ +static __isl_give isl_union_map *options_insert_dim( + __isl_take isl_union_map *options, __isl_take isl_space *space, int pos) +{ + isl_map *map; + isl_union_map *insertion; + enum isl_ast_loop_type type; + const char *name = "separation_class"; + + space = isl_space_map_from_set(space); + map = isl_map_identity(space); + map = isl_map_insert_dims(map, isl_dim_out, pos, 1); + options = isl_union_map_apply_domain(options, + isl_union_map_from_map(map)); + + if (!options) + return NULL; + + map = construct_insertion_map(isl_union_map_get_space(options), pos); + + insertion = isl_union_map_empty(isl_union_map_get_space(options)); + + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + isl_map *map_type = isl_map_copy(map); + const char *name = option_str[type]; + map_type = isl_map_set_tuple_name(map_type, isl_dim_in, name); + map_type = isl_map_set_tuple_name(map_type, isl_dim_out, name); + insertion = isl_union_map_add_map(insertion, map_type); + } + + map = isl_map_product(map, isl_map_identity(isl_map_get_space(map))); + map = isl_map_set_tuple_name(map, isl_dim_in, name); + map = isl_map_set_tuple_name(map, isl_dim_out, name); + insertion = isl_union_map_add_map(insertion, map); + + options = isl_union_map_apply_range(options, insertion); + + return options; +} + +/* If we are generating an AST from a schedule tree (build->node is set), + * then update the loop AST generation types + * to reflect the insertion of a dimension at (global) position "pos" + * in the schedule domain space. + * We do not need to adjust any isolate option since we would not be inserting + * any dimensions if there were any isolate option. + */ +static __isl_give isl_ast_build *node_insert_dim( + __isl_take isl_ast_build *build, int pos) +{ + int i; + int local_pos; + enum isl_ast_loop_type *loop_type; + isl_ctx *ctx; + + build = isl_ast_build_cow(build); + if (!build) + return NULL; + if (!build->node) + return build; + + ctx = isl_ast_build_get_ctx(build); + local_pos = pos - build->outer_pos; + loop_type = isl_realloc_array(ctx, build->loop_type, + enum isl_ast_loop_type, build->n + 1); + if (!loop_type) + return isl_ast_build_free(build); + build->loop_type = loop_type; + for (i = build->n - 1; i >= local_pos; --i) + loop_type[i + 1] = loop_type[i]; + loop_type[local_pos] = isl_ast_loop_default; + build->n++; + + return build; +} + +/* Insert a single dimension in the schedule domain at position "pos". + * The new dimension is given an isl_id with the empty string as name. + * + * The main difficulty is updating build->options to reflect the + * extra dimension. This is handled in options_insert_dim. + * + * Note that because of the dimension manipulations, the resulting + * schedule domain space will always be unnamed and unstructured. + * However, the original schedule domain space may be named and/or + * structured, so we have to take this possibility into account + * while performing the transformations. + * + * Since the inserted schedule dimension is used by the caller + * to differentiate between different domain spaces, there is + * no longer a uniform mapping from the internal schedule space + * to the input schedule space. The internal2input mapping is + * therefore removed. + */ +__isl_give isl_ast_build *isl_ast_build_insert_dim( + __isl_take isl_ast_build *build, int pos) +{ + isl_ctx *ctx; + isl_space *space, *ma_space; + isl_id *id; + isl_multi_aff *ma; + + build = isl_ast_build_cow(build); + if (!build) + return NULL; + + ctx = isl_ast_build_get_ctx(build); + id = isl_id_alloc(ctx, "", NULL); + if (!build->node) + space = isl_ast_build_get_space(build, 1); + build->iterators = isl_id_list_insert(build->iterators, pos, id); + build->domain = isl_set_insert_dims(build->domain, + isl_dim_set, pos, 1); + build->generated = isl_set_insert_dims(build->generated, + isl_dim_set, pos, 1); + build->pending = isl_set_insert_dims(build->pending, + isl_dim_set, pos, 1); + build->strides = isl_vec_insert_els(build->strides, pos, 1); + build->strides = isl_vec_set_element_si(build->strides, pos, 1); + ma_space = isl_space_params(isl_multi_aff_get_space(build->offsets)); + ma_space = isl_space_set_from_params(ma_space); + ma_space = isl_space_add_dims(ma_space, isl_dim_set, 1); + ma_space = isl_space_map_from_set(ma_space); + ma = isl_multi_aff_zero(isl_space_copy(ma_space)); + build->offsets = isl_multi_aff_splice(build->offsets, pos, pos, ma); + ma = isl_multi_aff_identity(ma_space); + build->values = isl_multi_aff_splice(build->values, pos, pos, ma); + if (!build->node) + build->options = options_insert_dim(build->options, space, pos); + build->internal2input = isl_multi_aff_free(build->internal2input); + + if (!build->iterators || !build->domain || !build->generated || + !build->pending || !build->values || + !build->strides || !build->offsets || !build->options) + return isl_ast_build_free(build); + + build = node_insert_dim(build, pos); + + return build; +} + +/* Scale down the current dimension by a factor of "m". + * "umap" is an isl_union_map that implements the scaling down. + * That is, it is of the form + * + * { [.... i ....] -> [.... i' ....] : i = m i' } + * + * This function is called right after the strides have been + * detected, but before any constraints on the current dimension + * have been included in build->domain. + * We therefore only need to update stride, offset, the options and + * the mapping from internal schedule space to the original schedule + * space, if we are still keeping track of such a mapping. + * The latter mapping is updated by plugging in + * { [... i ...] -> [... m i ... ] }. + */ +__isl_give isl_ast_build *isl_ast_build_scale_down( + __isl_take isl_ast_build *build, __isl_take isl_val *m, + __isl_take isl_union_map *umap) +{ + isl_aff *aff; + isl_val *v; + int depth; + + build = isl_ast_build_cow(build); + if (!build || !umap || !m) + goto error; + + depth = build->depth; + + if (build->internal2input) { + isl_space *space; + isl_multi_aff *ma; + isl_aff *aff; + + space = isl_multi_aff_get_space(build->internal2input); + space = isl_space_map_from_set(isl_space_domain(space)); + ma = isl_multi_aff_identity(space); + aff = isl_multi_aff_get_aff(ma, depth); + aff = isl_aff_scale_val(aff, isl_val_copy(m)); + ma = isl_multi_aff_set_aff(ma, depth, aff); + build->internal2input = + isl_multi_aff_pullback_multi_aff(build->internal2input, ma); + if (!build->internal2input) + goto error; + } + + v = isl_vec_get_element_val(build->strides, depth); + v = isl_val_div(v, isl_val_copy(m)); + build->strides = isl_vec_set_element_val(build->strides, depth, v); + + aff = isl_multi_aff_get_aff(build->offsets, depth); + aff = isl_aff_scale_down_val(aff, m); + build->offsets = isl_multi_aff_set_aff(build->offsets, depth, aff); + build->options = isl_union_map_apply_domain(build->options, umap); + if (!build->strides || !build->offsets || !build->options) + return isl_ast_build_free(build); + + return build; +error: + isl_val_free(m); + isl_union_map_free(umap); + return isl_ast_build_free(build); +} + +/* Return a list of "n" isl_ids called "c%d", with "%d" starting at "first". + * If an isl_id with such a name already appears among the parameters + * in build->domain, then adjust the name to "c%d_%d". + */ +static __isl_give isl_id_list *generate_names(isl_ctx *ctx, int n, int first, + __isl_keep isl_ast_build *build) +{ + int i; + isl_id_list *names; + + names = isl_id_list_alloc(ctx, n); + for (i = 0; i < n; ++i) { + isl_id *id; + + id = generate_name(ctx, first + i, build); + names = isl_id_list_add(names, id); + } + + return names; +} + +/* Embed "options" into the given isl_ast_build space. + * + * This function is called from within a nested call to + * isl_ast_build_node_from_schedule_map. + * "options" refers to the additional schedule, + * while space refers to both the space of the outer isl_ast_build and + * that of the additional schedule. + * Specifically, space is of the form + * + * [I -> S] + * + * while options lives in the space(s) + * + * S -> * + * + * We compute + * + * [I -> S] -> S + * + * and compose this with options, to obtain the new options + * living in the space(s) + * + * [I -> S] -> * + */ +static __isl_give isl_union_map *embed_options( + __isl_take isl_union_map *options, __isl_take isl_space *space) +{ + isl_map *map; + + map = isl_map_universe(isl_space_unwrap(space)); + map = isl_map_range_map(map); + + options = isl_union_map_apply_range( + isl_union_map_from_map(map), options); + + return options; +} + +/* Update "build" for use in a (possibly nested) code generation. That is, + * extend "build" from an AST build on some domain O to an AST build + * on domain [O -> S], with S corresponding to "space". + * If the original domain is a parameter domain, then the new domain is + * simply S. + * "iterators" is a list of iterators for S, but the number of elements + * may be smaller or greater than the number of set dimensions of S. + * If "keep_iterators" is set, then any extra ids in build->iterators + * are reused for S. Otherwise, these extra ids are dropped. + * + * We first update build->outer_pos to the current depth. + * This depth is zero in case this is the outermost code generation. + * + * We then add additional ids such that the number of iterators is at least + * equal to the dimension of the new build domain. + * + * If the original domain is parametric, then we are constructing + * an isl_ast_build for the outer code generation and we pass control + * to isl_ast_build_init. + * + * Otherwise, we adjust the fields of "build" to include "space". + */ +__isl_give isl_ast_build *isl_ast_build_product( + __isl_take isl_ast_build *build, __isl_take isl_space *space) +{ + isl_ctx *ctx; + isl_vec *strides; + isl_set *set; + isl_multi_aff *embedding; + int dim, n_it; + + build = isl_ast_build_cow(build); + if (!build) + goto error; + + build->outer_pos = build->depth; + + ctx = isl_ast_build_get_ctx(build); + dim = isl_set_dim(build->domain, isl_dim_set); + dim += isl_space_dim(space, isl_dim_set); + n_it = isl_id_list_n_id(build->iterators); + if (n_it < dim) { + isl_id_list *l; + l = generate_names(ctx, dim - n_it, n_it, build); + build->iterators = isl_id_list_concat(build->iterators, l); + } + + if (isl_set_is_params(build->domain)) + return isl_ast_build_init(build, space); + + set = isl_set_universe(isl_space_copy(space)); + build->domain = isl_set_product(build->domain, isl_set_copy(set)); + build->pending = isl_set_product(build->pending, isl_set_copy(set)); + build->generated = isl_set_product(build->generated, set); + + strides = isl_vec_alloc(ctx, isl_space_dim(space, isl_dim_set)); + strides = isl_vec_set_si(strides, 1); + build->strides = isl_vec_concat(build->strides, strides); + + space = isl_space_map_from_set(space); + build->offsets = isl_multi_aff_align_params(build->offsets, + isl_space_copy(space)); + build->offsets = isl_multi_aff_product(build->offsets, + isl_multi_aff_zero(isl_space_copy(space))); + build->values = isl_multi_aff_align_params(build->values, + isl_space_copy(space)); + embedding = isl_multi_aff_identity(space); + build->values = isl_multi_aff_product(build->values, + isl_multi_aff_copy(embedding)); + if (build->internal2input) { + build->internal2input = + isl_multi_aff_product(build->internal2input, embedding); + build->internal2input = + isl_multi_aff_flatten_range(build->internal2input); + if (!build->internal2input) + return isl_ast_build_free(build); + } else { + isl_multi_aff_free(embedding); + } + + space = isl_ast_build_get_space(build, 1); + build->options = embed_options(build->options, space); + + if (!build->iterators || !build->domain || !build->generated || + !build->pending || !build->values || + !build->strides || !build->offsets || !build->options) + return isl_ast_build_free(build); + + return build; +error: + isl_ast_build_free(build); + isl_space_free(space); + return NULL; +} + +/* Does "aff" only attain non-negative values over build->domain? + * That is, does it not attain any negative values? + */ +int isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build, + __isl_keep isl_aff *aff) +{ + isl_set *test; + int empty; + + if (!build) + return -1; + + aff = isl_aff_copy(aff); + test = isl_set_from_basic_set(isl_aff_neg_basic_set(aff)); + test = isl_set_intersect(test, isl_set_copy(build->domain)); + empty = isl_set_is_empty(test); + isl_set_free(test); + + return empty; +} + +/* Does the dimension at (internal) position "pos" have a non-trivial stride? + */ +isl_bool isl_ast_build_has_stride(__isl_keep isl_ast_build *build, int pos) +{ + isl_val *v; + isl_bool has_stride; + + if (!build) + return isl_bool_error; + + v = isl_vec_get_element_val(build->strides, pos); + has_stride = isl_bool_not(isl_val_is_one(v)); + isl_val_free(v); + + return has_stride; +} + +/* Given that the dimension at position "pos" takes on values + * + * f + s a + * + * with a an integer, return s through *stride. + */ +__isl_give isl_val *isl_ast_build_get_stride(__isl_keep isl_ast_build *build, + int pos) +{ + if (!build) + return NULL; + + return isl_vec_get_element_val(build->strides, pos); +} + +/* Given that the dimension at position "pos" takes on values + * + * f + s a + * + * with a an integer, return f. + */ +__isl_give isl_aff *isl_ast_build_get_offset( + __isl_keep isl_ast_build *build, int pos) +{ + if (!build) + return NULL; + + return isl_multi_aff_get_aff(build->offsets, pos); +} + +/* Is the dimension at position "pos" known to attain only a single + * value that, moreover, can be described by a single affine expression + * in terms of the outer dimensions and parameters? + * + * If not, then the corresponding affine expression in build->values + * is set to be equal to the same input dimension. + * Otherwise, it is set to the requested expression in terms of + * outer dimensions and parameters. + */ +int isl_ast_build_has_affine_value(__isl_keep isl_ast_build *build, + int pos) +{ + isl_aff *aff; + int involves; + + if (!build) + return -1; + + aff = isl_multi_aff_get_aff(build->values, pos); + involves = isl_aff_involves_dims(aff, isl_dim_in, pos, 1); + isl_aff_free(aff); + + if (involves < 0) + return -1; + + return !involves; +} + +/* Plug in the known values (fixed affine expressions in terms of + * parameters and outer loop iterators) of all loop iterators + * in the domain of "umap". + * + * We simply precompose "umap" with build->values. + */ +__isl_give isl_union_map *isl_ast_build_substitute_values_union_map_domain( + __isl_keep isl_ast_build *build, __isl_take isl_union_map *umap) +{ + isl_multi_aff *values; + + if (!build) + return isl_union_map_free(umap); + + values = isl_multi_aff_copy(build->values); + umap = isl_union_map_preimage_domain_multi_aff(umap, values); + + return umap; +} + +/* Is the current dimension known to attain only a single value? + */ +int isl_ast_build_has_value(__isl_keep isl_ast_build *build) +{ + if (!build) + return -1; + + return build->value != NULL; +} + +/* Simplify the basic set "bset" based on what we know about + * the iterators of already generated loops. + * + * "bset" is assumed to live in the (internal) schedule domain. + */ +__isl_give isl_basic_set *isl_ast_build_compute_gist_basic_set( + __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset) +{ + if (!build) + goto error; + + bset = isl_basic_set_preimage_multi_aff(bset, + isl_multi_aff_copy(build->values)); + bset = isl_basic_set_gist(bset, + isl_set_simple_hull(isl_set_copy(build->domain))); + + return bset; +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Simplify the set "set" based on what we know about + * the iterators of already generated loops. + * + * "set" is assumed to live in the (internal) schedule domain. + */ +__isl_give isl_set *isl_ast_build_compute_gist( + __isl_keep isl_ast_build *build, __isl_take isl_set *set) +{ + if (!build) + goto error; + + if (!isl_set_is_params(set)) + set = isl_set_preimage_multi_aff(set, + isl_multi_aff_copy(build->values)); + set = isl_set_gist(set, isl_set_copy(build->domain)); + + return set; +error: + isl_set_free(set); + return NULL; +} + +/* Include information about what we know about the iterators of + * already generated loops to "set". + * + * We currently only plug in the known affine values of outer loop + * iterators. + * In principle we could also introduce equalities or even other + * constraints implied by the intersection of "set" and build->domain. + */ +__isl_give isl_set *isl_ast_build_specialize(__isl_keep isl_ast_build *build, + __isl_take isl_set *set) +{ + if (!build) + return isl_set_free(set); + + return isl_set_preimage_multi_aff(set, + isl_multi_aff_copy(build->values)); +} + +/* Plug in the known affine values of outer loop iterators in "bset". + */ +__isl_give isl_basic_set *isl_ast_build_specialize_basic_set( + __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset) +{ + if (!build) + return isl_basic_set_free(bset); + + return isl_basic_set_preimage_multi_aff(bset, + isl_multi_aff_copy(build->values)); +} + +/* Simplify the map "map" based on what we know about + * the iterators of already generated loops. + * + * The domain of "map" is assumed to live in the (internal) schedule domain. + */ +__isl_give isl_map *isl_ast_build_compute_gist_map_domain( + __isl_keep isl_ast_build *build, __isl_take isl_map *map) +{ + if (!build) + goto error; + + map = isl_map_gist_domain(map, isl_set_copy(build->domain)); + + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Simplify the affine expression "aff" based on what we know about + * the iterators of already generated loops. + * + * The domain of "aff" is assumed to live in the (internal) schedule domain. + */ +__isl_give isl_aff *isl_ast_build_compute_gist_aff( + __isl_keep isl_ast_build *build, __isl_take isl_aff *aff) +{ + if (!build) + goto error; + + aff = isl_aff_gist(aff, isl_set_copy(build->domain)); + + return aff; +error: + isl_aff_free(aff); + return NULL; +} + +/* Simplify the piecewise affine expression "aff" based on what we know about + * the iterators of already generated loops. + * + * The domain of "pa" is assumed to live in the (internal) schedule domain. + */ +__isl_give isl_pw_aff *isl_ast_build_compute_gist_pw_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa) +{ + if (!build) + goto error; + + if (!isl_set_is_params(build->domain)) + pa = isl_pw_aff_pullback_multi_aff(pa, + isl_multi_aff_copy(build->values)); + pa = isl_pw_aff_gist(pa, isl_set_copy(build->domain)); + + return pa; +error: + isl_pw_aff_free(pa); + return NULL; +} + +/* Simplify the piecewise multi-affine expression "aff" based on what + * we know about the iterators of already generated loops. + * + * The domain of "pma" is assumed to live in the (internal) schedule domain. + */ +__isl_give isl_pw_multi_aff *isl_ast_build_compute_gist_pw_multi_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma) +{ + if (!build) + goto error; + + pma = isl_pw_multi_aff_pullback_multi_aff(pma, + isl_multi_aff_copy(build->values)); + pma = isl_pw_multi_aff_gist(pma, isl_set_copy(build->domain)); + + return pma; +error: + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* Extract the schedule domain of the given type from build->options + * at the current depth. + * + * In particular, find the subset of build->options that is of + * the following form + * + * schedule_domain -> type[depth] + * + * and return the corresponding domain, after eliminating inner dimensions + * and divs that depend on the current dimension. + * + * Note that the domain of build->options has been reformulated + * in terms of the internal build space in embed_options, + * but the position is still that within the current code generation. + */ +__isl_give isl_set *isl_ast_build_get_option_domain( + __isl_keep isl_ast_build *build, enum isl_ast_loop_type type) +{ + const char *name; + isl_space *space; + isl_map *option; + isl_set *domain; + int local_pos; + + if (!build) + return NULL; + + name = option_str[type]; + local_pos = build->depth - build->outer_pos; + + space = isl_ast_build_get_space(build, 1); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, 1); + space = isl_space_set_tuple_name(space, isl_dim_out, name); + + option = isl_union_map_extract_map(build->options, space); + option = isl_map_fix_si(option, isl_dim_out, 0, local_pos); + + domain = isl_map_domain(option); + domain = isl_ast_build_eliminate(build, domain); + + return domain; +} + +/* How does the user want the current schedule dimension to be generated? + * These choices have been extracted from the schedule node + * in extract_loop_types and stored in build->loop_type. + * They have been updated to reflect any dimension insertion in + * node_insert_dim. + * Return isl_ast_domain_error on error. + * + * If "isolated" is set, then we get the loop AST generation type + * directly from the band node since node_insert_dim cannot have been + * called on a band with the isolate option. + */ +enum isl_ast_loop_type isl_ast_build_get_loop_type( + __isl_keep isl_ast_build *build, int isolated) +{ + int local_pos; + isl_ctx *ctx; + + if (!build) + return isl_ast_loop_error; + ctx = isl_ast_build_get_ctx(build); + if (!build->node) + isl_die(ctx, isl_error_internal, + "only works for schedule tree based AST generation", + return isl_ast_loop_error); + + local_pos = build->depth - build->outer_pos; + if (!isolated) + return build->loop_type[local_pos]; + return isl_schedule_node_band_member_get_isolate_ast_loop_type( + build->node, local_pos); +} + +/* Extract the isolated set from the isolate option, if any, + * and store in the build. + * If there is no isolate option, then the isolated set is + * set to the empty set. + * + * The isolate option is of the form + * + * isolate[[outer bands] -> current_band] + * + * We flatten this set and then map it back to the internal + * schedule space. + * + * If we have already extracted the isolated set + * or if internal2input is no longer set, then we do not + * need to do anything. In the latter case, we know + * that the current band cannot have any isolate option. + */ +__isl_give isl_ast_build *isl_ast_build_extract_isolated( + __isl_take isl_ast_build *build) +{ + isl_set *isolated; + + if (!build) + return NULL; + if (!build->internal2input) + return build; + if (build->isolated) + return build; + + build = isl_ast_build_cow(build); + if (!build) + return NULL; + + isolated = isl_schedule_node_band_get_ast_isolate_option(build->node); + isolated = isl_set_flatten(isolated); + isolated = isl_set_preimage_multi_aff(isolated, + isl_multi_aff_copy(build->internal2input)); + + build->isolated = isolated; + if (!build->isolated) + return isl_ast_build_free(build); + + return build; +} + +/* Does "build" have a non-empty isolated set? + * + * The caller is assumed to have called isl_ast_build_extract_isolated first. + */ +int isl_ast_build_has_isolated(__isl_keep isl_ast_build *build) +{ + int empty; + + if (!build) + return -1; + if (!build->internal2input) + return 0; + if (!build->isolated) + isl_die(isl_ast_build_get_ctx(build), isl_error_internal, + "isolated set not extracted yet", return -1); + + empty = isl_set_plain_is_empty(build->isolated); + return empty < 0 ? -1 : !empty; +} + +/* Return a copy of the isolated set of "build". + * + * The caller is assume to have called isl_ast_build_has_isolated first, + * with this function returning true. + * In particular, this function should not be called if we are no + * longer keeping track of internal2input (and there therefore could + * not possibly be any isolated set). + */ +__isl_give isl_set *isl_ast_build_get_isolated(__isl_keep isl_ast_build *build) +{ + if (!build) + return NULL; + if (!build->internal2input) + isl_die(isl_ast_build_get_ctx(build), isl_error_internal, + "build cannot have isolated set", return NULL); + + return isl_set_copy(build->isolated); +} + +/* Extract the separation class mapping at the current depth. + * + * In particular, find and return the subset of build->options that is of + * the following form + * + * schedule_domain -> separation_class[[depth] -> [class]] + * + * The caller is expected to eliminate inner dimensions from the domain. + * + * Note that the domain of build->options has been reformulated + * in terms of the internal build space in embed_options, + * but the position is still that within the current code generation. + */ +__isl_give isl_map *isl_ast_build_get_separation_class( + __isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + isl_space *space_sep, *space; + isl_map *res; + int local_pos; + + if (!build) + return NULL; + + local_pos = build->depth - build->outer_pos; + ctx = isl_ast_build_get_ctx(build); + space_sep = isl_space_alloc(ctx, 0, 1, 1); + space_sep = isl_space_wrap(space_sep); + space_sep = isl_space_set_tuple_name(space_sep, isl_dim_set, + "separation_class"); + space = isl_ast_build_get_space(build, 1); + space_sep = isl_space_align_params(space_sep, isl_space_copy(space)); + space = isl_space_map_from_domain_and_range(space, space_sep); + + res = isl_union_map_extract_map(build->options, space); + res = isl_map_fix_si(res, isl_dim_out, 0, local_pos); + res = isl_map_coalesce(res); + + return res; +} + +/* Eliminate dimensions inner to the current dimension. + */ +__isl_give isl_set *isl_ast_build_eliminate_inner( + __isl_keep isl_ast_build *build, __isl_take isl_set *set) +{ + int dim; + int depth; + + if (!build) + return isl_set_free(set); + + dim = isl_set_dim(set, isl_dim_set); + depth = build->depth; + set = isl_set_detect_equalities(set); + set = isl_set_eliminate(set, isl_dim_set, depth + 1, dim - (depth + 1)); + + return set; +} + +/* Eliminate unknown divs and divs that depend on the current dimension. + * + * Note that during the elimination of unknown divs, we may discover + * an explicit representation of some other unknown divs, which may + * depend on the current dimension. We therefore need to eliminate + * unknown divs first. + */ +__isl_give isl_set *isl_ast_build_eliminate_divs( + __isl_keep isl_ast_build *build, __isl_take isl_set *set) +{ + int depth; + + if (!build) + return isl_set_free(set); + + set = isl_set_remove_unknown_divs(set); + depth = build->depth; + set = isl_set_remove_divs_involving_dims(set, isl_dim_set, depth, 1); + + return set; +} + +/* Eliminate dimensions inner to the current dimension as well as + * unknown divs and divs that depend on the current dimension. + * The result then consists only of constraints that are independent + * of the current dimension and upper and lower bounds on the current + * dimension. + */ +__isl_give isl_set *isl_ast_build_eliminate( + __isl_keep isl_ast_build *build, __isl_take isl_set *domain) +{ + domain = isl_ast_build_eliminate_inner(build, domain); + domain = isl_ast_build_eliminate_divs(build, domain); + return domain; +} + +/* Replace build->single_valued by "sv". + */ +__isl_give isl_ast_build *isl_ast_build_set_single_valued( + __isl_take isl_ast_build *build, int sv) +{ + if (!build) + return build; + if (build->single_valued == sv) + return build; + build = isl_ast_build_cow(build); + if (!build) + return build; + build->single_valued = sv; + + return build; +} Index: contrib/isl/isl_ast_build_expr.h =================================================================== --- /dev/null +++ contrib/isl/isl_ast_build_expr.h @@ -0,0 +1,22 @@ +#ifndef ISL_AST_BUILD_EXPR_PRIVATE_H +#define ISL_AST_BUILD_EXPR_PRIVATE_H + +#include +#include + +__isl_give isl_ast_expr *isl_ast_build_expr_from_basic_set( + __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset); +__isl_give isl_ast_expr *isl_ast_build_expr_from_set_internal( + __isl_keep isl_ast_build *build, __isl_take isl_set *set); + +__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff_internal( + __isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa); +__isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, + __isl_keep isl_ast_build *build); +__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr, + int pos, __isl_take isl_ast_expr *arg); + +__isl_give isl_ast_node *isl_ast_build_call_from_executed( + __isl_keep isl_ast_build *build, __isl_take isl_map *executed); + +#endif Index: contrib/isl/isl_ast_build_expr.c =================================================================== --- /dev/null +++ contrib/isl/isl_ast_build_expr.c @@ -0,0 +1,2491 @@ +/* + * Copyright 2012-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Compute the "opposite" of the (numerator of the) argument of a div + * with denominator "d". + * + * In particular, compute + * + * -aff + (d - 1) + */ +static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *aff, + __isl_take isl_val *d) +{ + aff = isl_aff_neg(aff); + aff = isl_aff_add_constant_val(aff, d); + aff = isl_aff_add_constant_si(aff, -1); + + return aff; +} + +/* Internal data structure used inside isl_ast_expr_add_term. + * The domain of "build" is used to simplify the expressions. + * "build" needs to be set by the caller of isl_ast_expr_add_term. + * "cst" is the constant term of the expression in which the added term + * appears. It may be modified by isl_ast_expr_add_term. + * + * "v" is the coefficient of the term that is being constructed and + * is set internally by isl_ast_expr_add_term. + */ +struct isl_ast_add_term_data { + isl_ast_build *build; + isl_val *cst; + isl_val *v; +}; + +/* Given the numerator "aff" of the argument of an integer division + * with denominator "d", check if it can be made non-negative over + * data->build->domain by stealing part of the constant term of + * the expression in which the integer division appears. + * + * In particular, the outer expression is of the form + * + * v * floor(aff/d) + cst + * + * We already know that "aff" itself may attain negative values. + * Here we check if aff + d*floor(cst/v) is non-negative, such + * that we could rewrite the expression to + * + * v * floor((aff + d*floor(cst/v))/d) + cst - v*floor(cst/v) + * + * Note that aff + d*floor(cst/v) can only possibly be non-negative + * if data->cst and data->v have the same sign. + * Similarly, if floor(cst/v) is zero, then there is no point in + * checking again. + */ +static int is_non_neg_after_stealing(__isl_keep isl_aff *aff, + __isl_keep isl_val *d, struct isl_ast_add_term_data *data) +{ + isl_aff *shifted; + isl_val *shift; + int is_zero; + int non_neg; + + if (isl_val_sgn(data->cst) != isl_val_sgn(data->v)) + return 0; + + shift = isl_val_div(isl_val_copy(data->cst), isl_val_copy(data->v)); + shift = isl_val_floor(shift); + is_zero = isl_val_is_zero(shift); + if (is_zero < 0 || is_zero) { + isl_val_free(shift); + return is_zero < 0 ? -1 : 0; + } + shift = isl_val_mul(shift, isl_val_copy(d)); + shifted = isl_aff_copy(aff); + shifted = isl_aff_add_constant_val(shifted, shift); + non_neg = isl_ast_build_aff_is_nonneg(data->build, shifted); + isl_aff_free(shifted); + + return non_neg; +} + +/* Given the numerator "aff' of the argument of an integer division + * with denominator "d", steal part of the constant term of + * the expression in which the integer division appears to make it + * non-negative over data->build->domain. + * + * In particular, the outer expression is of the form + * + * v * floor(aff/d) + cst + * + * We know that "aff" itself may attain negative values, + * but that aff + d*floor(cst/v) is non-negative. + * Find the minimal positive value that we need to add to "aff" + * to make it positive and adjust data->cst accordingly. + * That is, compute the minimal value "m" of "aff" over + * data->build->domain and take + * + * s = ceil(m/d) + * + * such that + * + * aff + d * s >= 0 + * + * and rewrite the expression to + * + * v * floor((aff + s*d)/d) + (cst - v*s) + */ +static __isl_give isl_aff *steal_from_cst(__isl_take isl_aff *aff, + __isl_keep isl_val *d, struct isl_ast_add_term_data *data) +{ + isl_set *domain; + isl_val *shift, *t; + + domain = isl_ast_build_get_domain(data->build); + shift = isl_set_min_val(domain, aff); + isl_set_free(domain); + + shift = isl_val_neg(shift); + shift = isl_val_div(shift, isl_val_copy(d)); + shift = isl_val_ceil(shift); + + t = isl_val_copy(shift); + t = isl_val_mul(t, isl_val_copy(data->v)); + data->cst = isl_val_sub(data->cst, t); + + shift = isl_val_mul(shift, isl_val_copy(d)); + return isl_aff_add_constant_val(aff, shift); +} + +/* Create an isl_ast_expr evaluating the div at position "pos" in "ls". + * The result is simplified in terms of data->build->domain. + * This function may change (the sign of) data->v. + * + * "ls" is known to be non-NULL. + * + * Let the div be of the form floor(e/d). + * If the ast_build_prefer_pdiv option is set then we check if "e" + * is non-negative, so that we can generate + * + * (pdiv_q, expr(e), expr(d)) + * + * instead of + * + * (fdiv_q, expr(e), expr(d)) + * + * If the ast_build_prefer_pdiv option is set and + * if "e" is not non-negative, then we check if "-e + d - 1" is non-negative. + * If so, we can rewrite + * + * floor(e/d) = -ceil(-e/d) = -floor((-e + d - 1)/d) + * + * and still use pdiv_q, while changing the sign of data->v. + * + * Otherwise, we check if + * + * e + d*floor(cst/v) + * + * is non-negative and if so, replace floor(e/d) by + * + * floor((e + s*d)/d) - s + * + * with s the minimal shift that makes the argument non-negative. + */ +static __isl_give isl_ast_expr *var_div(struct isl_ast_add_term_data *data, + __isl_keep isl_local_space *ls, int pos) +{ + isl_ctx *ctx = isl_local_space_get_ctx(ls); + isl_aff *aff; + isl_ast_expr *num, *den; + isl_val *d; + enum isl_ast_op_type type; + + aff = isl_local_space_get_div(ls, pos); + d = isl_aff_get_denominator_val(aff); + aff = isl_aff_scale_val(aff, isl_val_copy(d)); + den = isl_ast_expr_from_val(isl_val_copy(d)); + + type = isl_ast_op_fdiv_q; + if (isl_options_get_ast_build_prefer_pdiv(ctx)) { + int non_neg = isl_ast_build_aff_is_nonneg(data->build, aff); + if (non_neg >= 0 && !non_neg) { + isl_aff *opp = oppose_div_arg(isl_aff_copy(aff), + isl_val_copy(d)); + non_neg = isl_ast_build_aff_is_nonneg(data->build, opp); + if (non_neg >= 0 && non_neg) { + data->v = isl_val_neg(data->v); + isl_aff_free(aff); + aff = opp; + } else + isl_aff_free(opp); + } + if (non_neg >= 0 && !non_neg) { + non_neg = is_non_neg_after_stealing(aff, d, data); + if (non_neg >= 0 && non_neg) + aff = steal_from_cst(aff, d, data); + } + if (non_neg < 0) + aff = isl_aff_free(aff); + else if (non_neg) + type = isl_ast_op_pdiv_q; + } + + isl_val_free(d); + num = isl_ast_expr_from_aff(aff, data->build); + return isl_ast_expr_alloc_binary(type, num, den); +} + +/* Create an isl_ast_expr evaluating the specified dimension of "ls". + * The result is simplified in terms of data->build->domain. + * This function may change (the sign of) data->v. + * + * The isl_ast_expr is constructed based on the type of the dimension. + * - divs are constructed by var_div + * - set variables are constructed from the iterator isl_ids in data->build + * - parameters are constructed from the isl_ids in "ls" + */ +static __isl_give isl_ast_expr *var(struct isl_ast_add_term_data *data, + __isl_keep isl_local_space *ls, enum isl_dim_type type, int pos) +{ + isl_ctx *ctx = isl_local_space_get_ctx(ls); + isl_id *id; + + if (type == isl_dim_div) + return var_div(data, ls, pos); + + if (type == isl_dim_set) { + id = isl_ast_build_get_iterator_id(data->build, pos); + return isl_ast_expr_from_id(id); + } + + if (!isl_local_space_has_dim_id(ls, type, pos)) + isl_die(ctx, isl_error_internal, "unnamed dimension", + return NULL); + id = isl_local_space_get_dim_id(ls, type, pos); + return isl_ast_expr_from_id(id); +} + +/* Does "expr" represent the zero integer? + */ +static int ast_expr_is_zero(__isl_keep isl_ast_expr *expr) +{ + if (!expr) + return -1; + if (expr->type != isl_ast_expr_int) + return 0; + return isl_val_is_zero(expr->u.v); +} + +/* Create an expression representing the sum of "expr1" and "expr2", + * provided neither of the two expressions is identically zero. + */ +static __isl_give isl_ast_expr *ast_expr_add(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + if (!expr1 || !expr2) + goto error; + + if (ast_expr_is_zero(expr1)) { + isl_ast_expr_free(expr1); + return expr2; + } + + if (ast_expr_is_zero(expr2)) { + isl_ast_expr_free(expr2); + return expr1; + } + + return isl_ast_expr_add(expr1, expr2); +error: + isl_ast_expr_free(expr1); + isl_ast_expr_free(expr2); + return NULL; +} + +/* Subtract expr2 from expr1. + * + * If expr2 is zero, we simply return expr1. + * If expr1 is zero, we return + * + * (isl_ast_op_minus, expr2) + * + * Otherwise, we return + * + * (isl_ast_op_sub, expr1, expr2) + */ +static __isl_give isl_ast_expr *ast_expr_sub(__isl_take isl_ast_expr *expr1, + __isl_take isl_ast_expr *expr2) +{ + if (!expr1 || !expr2) + goto error; + + if (ast_expr_is_zero(expr2)) { + isl_ast_expr_free(expr2); + return expr1; + } + + if (ast_expr_is_zero(expr1)) { + isl_ast_expr_free(expr1); + return isl_ast_expr_neg(expr2); + } + + return isl_ast_expr_sub(expr1, expr2); +error: + isl_ast_expr_free(expr1); + isl_ast_expr_free(expr2); + return NULL; +} + +/* Return an isl_ast_expr that represents + * + * v * (aff mod d) + * + * v is assumed to be non-negative. + * The result is simplified in terms of build->domain. + */ +static __isl_give isl_ast_expr *isl_ast_expr_mod(__isl_keep isl_val *v, + __isl_keep isl_aff *aff, __isl_keep isl_val *d, + __isl_keep isl_ast_build *build) +{ + isl_ast_expr *expr; + isl_ast_expr *c; + + if (!aff) + return NULL; + + expr = isl_ast_expr_from_aff(isl_aff_copy(aff), build); + + c = isl_ast_expr_from_val(isl_val_copy(d)); + expr = isl_ast_expr_alloc_binary(isl_ast_op_pdiv_r, expr, c); + + if (!isl_val_is_one(v)) { + c = isl_ast_expr_from_val(isl_val_copy(v)); + expr = isl_ast_expr_mul(c, expr); + } + + return expr; +} + +/* Create an isl_ast_expr that scales "expr" by "v". + * + * If v is 1, we simply return expr. + * If v is -1, we return + * + * (isl_ast_op_minus, expr) + * + * Otherwise, we return + * + * (isl_ast_op_mul, expr(v), expr) + */ +static __isl_give isl_ast_expr *scale(__isl_take isl_ast_expr *expr, + __isl_take isl_val *v) +{ + isl_ast_expr *c; + + if (!expr || !v) + goto error; + if (isl_val_is_one(v)) { + isl_val_free(v); + return expr; + } + + if (isl_val_is_negone(v)) { + isl_val_free(v); + expr = isl_ast_expr_neg(expr); + } else { + c = isl_ast_expr_from_val(v); + expr = isl_ast_expr_mul(c, expr); + } + + return expr; +error: + isl_val_free(v); + isl_ast_expr_free(expr); + return NULL; +} + +/* Add an expression for "*v" times the specified dimension of "ls" + * to expr. + * If the dimension is an integer division, then this function + * may modify data->cst in order to make the numerator non-negative. + * The result is simplified in terms of data->build->domain. + * + * Let e be the expression for the specified dimension, + * multiplied by the absolute value of "*v". + * If "*v" is negative, we create + * + * (isl_ast_op_sub, expr, e) + * + * except when expr is trivially zero, in which case we create + * + * (isl_ast_op_minus, e) + * + * instead. + * + * If "*v" is positive, we simply create + * + * (isl_ast_op_add, expr, e) + * + */ +static __isl_give isl_ast_expr *isl_ast_expr_add_term( + __isl_take isl_ast_expr *expr, + __isl_keep isl_local_space *ls, enum isl_dim_type type, int pos, + __isl_take isl_val *v, struct isl_ast_add_term_data *data) +{ + isl_ast_expr *term; + + if (!expr) + return NULL; + + data->v = v; + term = var(data, ls, type, pos); + v = data->v; + + if (isl_val_is_neg(v) && !ast_expr_is_zero(expr)) { + v = isl_val_neg(v); + term = scale(term, v); + return ast_expr_sub(expr, term); + } else { + term = scale(term, v); + return ast_expr_add(expr, term); + } +} + +/* Add an expression for "v" to expr. + */ +static __isl_give isl_ast_expr *isl_ast_expr_add_int( + __isl_take isl_ast_expr *expr, __isl_take isl_val *v) +{ + isl_ast_expr *expr_int; + + if (!expr || !v) + goto error; + + if (isl_val_is_zero(v)) { + isl_val_free(v); + return expr; + } + + if (isl_val_is_neg(v) && !ast_expr_is_zero(expr)) { + v = isl_val_neg(v); + expr_int = isl_ast_expr_from_val(v); + return ast_expr_sub(expr, expr_int); + } else { + expr_int = isl_ast_expr_from_val(v); + return ast_expr_add(expr, expr_int); + } +error: + isl_ast_expr_free(expr); + isl_val_free(v); + return NULL; +} + +/* Internal data structure used inside extract_modulos. + * + * If any modulo expressions are detected in "aff", then the + * expression is removed from "aff" and added to either "pos" or "neg" + * depending on the sign of the coefficient of the modulo expression + * inside "aff". + * + * "add" is an expression that needs to be added to "aff" at the end of + * the computation. It is NULL as long as no modulos have been extracted. + * + * "i" is the position in "aff" of the div under investigation + * "v" is the coefficient in "aff" of the div + * "div" is the argument of the div, with the denominator removed + * "d" is the original denominator of the argument of the div + * + * "nonneg" is an affine expression that is non-negative over "build" + * and that can be used to extract a modulo expression from "div". + * In particular, if "sign" is 1, then the coefficients of "nonneg" + * are equal to those of "div" modulo "d". If "sign" is -1, then + * the coefficients of "nonneg" are opposite to those of "div" modulo "d". + * If "sign" is 0, then no such affine expression has been found (yet). + */ +struct isl_extract_mod_data { + isl_ast_build *build; + isl_aff *aff; + + isl_ast_expr *pos; + isl_ast_expr *neg; + + isl_aff *add; + + int i; + isl_val *v; + isl_val *d; + isl_aff *div; + + isl_aff *nonneg; + int sign; +}; + +/* Given that data->v * div_i in data->aff is equal to + * + * f * (term - (arg mod d)) + * + * with data->d * f = data->v, add + * + * f * term + * + * to data->add and + * + * abs(f) * (arg mod d) + * + * to data->neg or data->pos depending on the sign of -f. + */ +static int extract_term_and_mod(struct isl_extract_mod_data *data, + __isl_take isl_aff *term, __isl_take isl_aff *arg) +{ + isl_ast_expr *expr; + int s; + + data->v = isl_val_div(data->v, isl_val_copy(data->d)); + s = isl_val_sgn(data->v); + data->v = isl_val_abs(data->v); + expr = isl_ast_expr_mod(data->v, arg, data->d, data->build); + isl_aff_free(arg); + if (s > 0) + data->neg = ast_expr_add(data->neg, expr); + else + data->pos = ast_expr_add(data->pos, expr); + data->aff = isl_aff_set_coefficient_si(data->aff, + isl_dim_div, data->i, 0); + if (s < 0) + data->v = isl_val_neg(data->v); + term = isl_aff_scale_val(term, isl_val_copy(data->v)); + + if (!data->add) + data->add = term; + else + data->add = isl_aff_add(data->add, term); + if (!data->add) + return -1; + + return 0; +} + +/* Given that data->v * div_i in data->aff is of the form + * + * f * d * floor(div/d) + * + * with div nonnegative on data->build, rewrite it as + * + * f * (div - (div mod d)) = f * div - f * (div mod d) + * + * and add + * + * f * div + * + * to data->add and + * + * abs(f) * (div mod d) + * + * to data->neg or data->pos depending on the sign of -f. + */ +static int extract_mod(struct isl_extract_mod_data *data) +{ + return extract_term_and_mod(data, isl_aff_copy(data->div), + isl_aff_copy(data->div)); +} + +/* Given that data->v * div_i in data->aff is of the form + * + * f * d * floor(div/d) (1) + * + * check if div is non-negative on data->build and, if so, + * extract the corresponding modulo from data->aff. + * If not, then check if + * + * -div + d - 1 + * + * is non-negative on data->build. If so, replace (1) by + * + * -f * d * floor((-div + d - 1)/d) + * + * and extract the corresponding modulo from data->aff. + * + * This function may modify data->div. + */ +static int extract_nonneg_mod(struct isl_extract_mod_data *data) +{ + int mod; + + mod = isl_ast_build_aff_is_nonneg(data->build, data->div); + if (mod < 0) + goto error; + if (mod) + return extract_mod(data); + + data->div = oppose_div_arg(data->div, isl_val_copy(data->d)); + mod = isl_ast_build_aff_is_nonneg(data->build, data->div); + if (mod < 0) + goto error; + if (mod) { + data->v = isl_val_neg(data->v); + return extract_mod(data); + } + + return 0; +error: + data->aff = isl_aff_free(data->aff); + return -1; +} + +/* Is the affine expression of constraint "c" "simpler" than data->nonneg + * for use in extracting a modulo expression? + * + * We currently only consider the constant term of the affine expression. + * In particular, we prefer the affine expression with the smallest constant + * term. + * This means that if there are two constraints, say x >= 0 and -x + 10 >= 0, + * then we would pick x >= 0 + * + * More detailed heuristics could be used if it turns out that there is a need. + */ +static int mod_constraint_is_simpler(struct isl_extract_mod_data *data, + __isl_keep isl_constraint *c) +{ + isl_val *v1, *v2; + int simpler; + + if (!data->nonneg) + return 1; + + v1 = isl_val_abs(isl_constraint_get_constant_val(c)); + v2 = isl_val_abs(isl_aff_get_constant_val(data->nonneg)); + simpler = isl_val_lt(v1, v2); + isl_val_free(v1); + isl_val_free(v2); + + return simpler; +} + +/* Check if the coefficients of "c" are either equal or opposite to those + * of data->div modulo data->d. If so, and if "c" is "simpler" than + * data->nonneg, then replace data->nonneg by the affine expression of "c" + * and set data->sign accordingly. + * + * Both "c" and data->div are assumed not to involve any integer divisions. + * + * Before we start the actual comparison, we first quickly check if + * "c" and data->div have the same non-zero coefficients. + * If not, then we assume that "c" is not of the desired form. + * Note that while the coefficients of data->div can be reasonably expected + * not to involve any coefficients that are multiples of d, "c" may + * very well involve such coefficients. This means that we may actually + * miss some cases. + * + * If the constant term is "too large", then the constraint is rejected, + * where "too large" is fairly arbitrarily set to 1 << 15. + * We do this to avoid picking up constraints that bound a variable + * by a very large number, say the largest or smallest possible + * variable in the representation of some integer type. + */ +static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c, + void *user) +{ + struct isl_extract_mod_data *data = user; + enum isl_dim_type c_type[2] = { isl_dim_param, isl_dim_set }; + enum isl_dim_type a_type[2] = { isl_dim_param, isl_dim_in }; + int i, t; + int n[2]; + int parallel = 1, opposite = 1; + + for (t = 0; t < 2; ++t) { + n[t] = isl_constraint_dim(c, c_type[t]); + for (i = 0; i < n[t]; ++i) { + int a, b; + + a = isl_constraint_involves_dims(c, c_type[t], i, 1); + b = isl_aff_involves_dims(data->div, a_type[t], i, 1); + if (a != b) + parallel = opposite = 0; + } + } + + if (parallel || opposite) { + isl_val *v; + + v = isl_val_abs(isl_constraint_get_constant_val(c)); + if (isl_val_cmp_si(v, 1 << 15) > 0) + parallel = opposite = 0; + isl_val_free(v); + } + + for (t = 0; t < 2; ++t) { + for (i = 0; i < n[t]; ++i) { + isl_val *v1, *v2; + + if (!parallel && !opposite) + break; + v1 = isl_constraint_get_coefficient_val(c, + c_type[t], i); + v2 = isl_aff_get_coefficient_val(data->div, + a_type[t], i); + if (parallel) { + v1 = isl_val_sub(v1, isl_val_copy(v2)); + parallel = isl_val_is_divisible_by(v1, data->d); + v1 = isl_val_add(v1, isl_val_copy(v2)); + } + if (opposite) { + v1 = isl_val_add(v1, isl_val_copy(v2)); + opposite = isl_val_is_divisible_by(v1, data->d); + } + isl_val_free(v1); + isl_val_free(v2); + } + } + + if ((parallel || opposite) && mod_constraint_is_simpler(data, c)) { + isl_aff_free(data->nonneg); + data->nonneg = isl_constraint_get_aff(c); + data->sign = parallel ? 1 : -1; + } + + isl_constraint_free(c); + + if (data->sign != 0 && data->nonneg == NULL) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Given that data->v * div_i in data->aff is of the form + * + * f * d * floor(div/d) (1) + * + * see if we can find an expression div' that is non-negative over data->build + * and that is related to div through + * + * div' = div + d * e + * + * or + * + * div' = -div + d - 1 + d * e + * + * with e some affine expression. + * If so, we write (1) as + * + * f * div + f * (div' mod d) + * + * or + * + * -f * (-div + d - 1) - f * (div' mod d) + * + * exploiting (in the second case) the fact that + * + * f * d * floor(div/d) = -f * d * floor((-div + d - 1)/d) + * + * + * We first try to find an appropriate expression for div' + * from the constraints of data->build->domain (which is therefore + * guaranteed to be non-negative on data->build), where we remove + * any integer divisions from the constraints and skip this step + * if "div" itself involves any integer divisions. + * If we cannot find an appropriate expression this way, then + * we pass control to extract_nonneg_mod where check + * if div or "-div + d -1" themselves happen to be + * non-negative on data->build. + * + * While looking for an appropriate constraint in data->build->domain, + * we ignore the constant term, so after finding such a constraint, + * we still need to fix up the constant term. + * In particular, if a is the constant term of "div" + * (or d - 1 - the constant term of "div" if data->sign < 0) + * and b is the constant term of the constraint, then we need to find + * a non-negative constant c such that + * + * b + c \equiv a mod d + * + * We therefore take + * + * c = (a - b) mod d + * + * and add it to b to obtain the constant term of div'. + * If this constant term is "too negative", then we add an appropriate + * multiple of d to make it positive. + * + * + * Note that the above is a only a very simple heuristic for finding an + * appropriate expression. We could try a bit harder by also considering + * sums of constraints that involve disjoint sets of variables or + * we could consider arbitrary linear combinations of constraints, + * although that could potentially be much more expensive as it involves + * the solution of an LP problem. + * + * In particular, if v_i is a column vector representing constraint i, + * w represents div and e_i is the i-th unit vector, then we are looking + * for a solution of the constraints + * + * \sum_i lambda_i v_i = w + \sum_i alpha_i d e_i + * + * with \lambda_i >= 0 and alpha_i of unrestricted sign. + * If we are not just interested in a non-negative expression, but + * also in one with a minimal range, then we don't just want + * c = \sum_i lambda_i v_i to be non-negative over the domain, + * but also beta - c = \sum_i mu_i v_i, where beta is a scalar + * that we want to minimize and we now also have to take into account + * the constant terms of the constraints. + * Alternatively, we could first compute the dual of the domain + * and plug in the constraints on the coefficients. + */ +static int try_extract_mod(struct isl_extract_mod_data *data) +{ + isl_basic_set *hull; + isl_val *v1, *v2; + int r, n; + + if (!data->build) + goto error; + + n = isl_aff_dim(data->div, isl_dim_div); + + if (isl_aff_involves_dims(data->div, isl_dim_div, 0, n)) + return extract_nonneg_mod(data); + + hull = isl_set_simple_hull(isl_set_copy(data->build->domain)); + hull = isl_basic_set_remove_divs(hull); + data->sign = 0; + data->nonneg = NULL; + r = isl_basic_set_foreach_constraint(hull, &check_parallel_or_opposite, + data); + isl_basic_set_free(hull); + + if (!data->sign || r < 0) { + isl_aff_free(data->nonneg); + if (r < 0) + goto error; + return extract_nonneg_mod(data); + } + + v1 = isl_aff_get_constant_val(data->div); + v2 = isl_aff_get_constant_val(data->nonneg); + if (data->sign < 0) { + v1 = isl_val_neg(v1); + v1 = isl_val_add(v1, isl_val_copy(data->d)); + v1 = isl_val_sub_ui(v1, 1); + } + v1 = isl_val_sub(v1, isl_val_copy(v2)); + v1 = isl_val_mod(v1, isl_val_copy(data->d)); + v1 = isl_val_add(v1, v2); + v2 = isl_val_div(isl_val_copy(v1), isl_val_copy(data->d)); + v2 = isl_val_ceil(v2); + if (isl_val_is_neg(v2)) { + v2 = isl_val_mul(v2, isl_val_copy(data->d)); + v1 = isl_val_sub(v1, isl_val_copy(v2)); + } + data->nonneg = isl_aff_set_constant_val(data->nonneg, v1); + isl_val_free(v2); + + if (data->sign < 0) { + data->div = oppose_div_arg(data->div, isl_val_copy(data->d)); + data->v = isl_val_neg(data->v); + } + + return extract_term_and_mod(data, + isl_aff_copy(data->div), data->nonneg); +error: + data->aff = isl_aff_free(data->aff); + return -1; +} + +/* Check if "data->aff" involves any (implicit) modulo computations based + * on div "data->i". + * If so, remove them from aff and add expressions corresponding + * to those modulo computations to data->pos and/or data->neg. + * + * "aff" is assumed to be an integer affine expression. + * + * In particular, check if (v * div_j) is of the form + * + * f * m * floor(a / m) + * + * and, if so, rewrite it as + * + * f * (a - (a mod m)) = f * a - f * (a mod m) + * + * and extract out -f * (a mod m). + * In particular, if f > 0, we add (f * (a mod m)) to *neg. + * If f < 0, we add ((-f) * (a mod m)) to *pos. + * + * Note that in order to represent "a mod m" as + * + * (isl_ast_op_pdiv_r, a, m) + * + * we need to make sure that a is non-negative. + * If not, we check if "-a + m - 1" is non-negative. + * If so, we can rewrite + * + * floor(a/m) = -ceil(-a/m) = -floor((-a + m - 1)/m) + * + * and still extract a modulo. + */ +static int extract_modulo(struct isl_extract_mod_data *data) +{ + data->div = isl_aff_get_div(data->aff, data->i); + data->d = isl_aff_get_denominator_val(data->div); + if (isl_val_is_divisible_by(data->v, data->d)) { + data->div = isl_aff_scale_val(data->div, isl_val_copy(data->d)); + if (try_extract_mod(data) < 0) + data->aff = isl_aff_free(data->aff); + } + isl_aff_free(data->div); + isl_val_free(data->d); + return 0; +} + +/* Check if "aff" involves any (implicit) modulo computations. + * If so, remove them from aff and add expressions corresponding + * to those modulo computations to *pos and/or *neg. + * We only do this if the option ast_build_prefer_pdiv is set. + * + * "aff" is assumed to be an integer affine expression. + * + * A modulo expression is of the form + * + * a mod m = a - m * floor(a / m) + * + * To detect them in aff, we look for terms of the form + * + * f * m * floor(a / m) + * + * rewrite them as + * + * f * (a - (a mod m)) = f * a - f * (a mod m) + * + * and extract out -f * (a mod m). + * In particular, if f > 0, we add (f * (a mod m)) to *neg. + * If f < 0, we add ((-f) * (a mod m)) to *pos. + */ +static __isl_give isl_aff *extract_modulos(__isl_take isl_aff *aff, + __isl_keep isl_ast_expr **pos, __isl_keep isl_ast_expr **neg, + __isl_keep isl_ast_build *build) +{ + struct isl_extract_mod_data data = { build, aff, *pos, *neg }; + isl_ctx *ctx; + int n; + + if (!aff) + return NULL; + + ctx = isl_aff_get_ctx(aff); + if (!isl_options_get_ast_build_prefer_pdiv(ctx)) + return aff; + + n = isl_aff_dim(data.aff, isl_dim_div); + for (data.i = 0; data.i < n; ++data.i) { + data.v = isl_aff_get_coefficient_val(data.aff, + isl_dim_div, data.i); + if (!data.v) + return isl_aff_free(aff); + if (isl_val_is_zero(data.v) || + isl_val_is_one(data.v) || isl_val_is_negone(data.v)) { + isl_val_free(data.v); + continue; + } + if (extract_modulo(&data) < 0) + data.aff = isl_aff_free(data.aff); + isl_val_free(data.v); + if (!data.aff) + break; + } + + if (data.add) + data.aff = isl_aff_add(data.aff, data.add); + + *pos = data.pos; + *neg = data.neg; + return data.aff; +} + +/* Check if aff involves any non-integer coefficients. + * If so, split aff into + * + * aff = aff1 + (aff2 / d) + * + * with both aff1 and aff2 having only integer coefficients. + * Return aff1 and add (aff2 / d) to *expr. + */ +static __isl_give isl_aff *extract_rational(__isl_take isl_aff *aff, + __isl_keep isl_ast_expr **expr, __isl_keep isl_ast_build *build) +{ + int i, j, n; + isl_aff *rat = NULL; + isl_local_space *ls = NULL; + isl_ast_expr *rat_expr; + isl_val *v, *d; + enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div }; + enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div }; + + if (!aff) + return NULL; + d = isl_aff_get_denominator_val(aff); + if (!d) + goto error; + if (isl_val_is_one(d)) { + isl_val_free(d); + return aff; + } + + aff = isl_aff_scale_val(aff, isl_val_copy(d)); + + ls = isl_aff_get_domain_local_space(aff); + rat = isl_aff_zero_on_domain(isl_local_space_copy(ls)); + + for (i = 0; i < 3; ++i) { + n = isl_aff_dim(aff, t[i]); + for (j = 0; j < n; ++j) { + isl_aff *rat_j; + + v = isl_aff_get_coefficient_val(aff, t[i], j); + if (!v) + goto error; + if (isl_val_is_divisible_by(v, d)) { + isl_val_free(v); + continue; + } + rat_j = isl_aff_var_on_domain(isl_local_space_copy(ls), + l[i], j); + rat_j = isl_aff_scale_val(rat_j, v); + rat = isl_aff_add(rat, rat_j); + } + } + + v = isl_aff_get_constant_val(aff); + if (isl_val_is_divisible_by(v, d)) { + isl_val_free(v); + } else { + isl_aff *rat_0; + + rat_0 = isl_aff_val_on_domain(isl_local_space_copy(ls), v); + rat = isl_aff_add(rat, rat_0); + } + + isl_local_space_free(ls); + + aff = isl_aff_sub(aff, isl_aff_copy(rat)); + aff = isl_aff_scale_down_val(aff, isl_val_copy(d)); + + rat_expr = isl_ast_expr_from_aff(rat, build); + rat_expr = isl_ast_expr_div(rat_expr, isl_ast_expr_from_val(d)); + *expr = ast_expr_add(*expr, rat_expr); + + return aff; +error: + isl_aff_free(rat); + isl_local_space_free(ls); + isl_aff_free(aff); + isl_val_free(d); + return NULL; +} + +/* Construct an isl_ast_expr that evaluates the affine expression "aff", + * The result is simplified in terms of build->domain. + * + * We first extract hidden modulo computations from the affine expression + * and then add terms for each variable with a non-zero coefficient. + * Finally, if the affine expression has a non-trivial denominator, + * we divide the resulting isl_ast_expr by this denominator. + */ +__isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, + __isl_keep isl_ast_build *build) +{ + int i, j; + int n; + isl_val *v; + isl_ctx *ctx = isl_aff_get_ctx(aff); + isl_ast_expr *expr, *expr_neg; + enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div }; + enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div }; + isl_local_space *ls; + struct isl_ast_add_term_data data; + + if (!aff) + return NULL; + + expr = isl_ast_expr_alloc_int_si(ctx, 0); + expr_neg = isl_ast_expr_alloc_int_si(ctx, 0); + + aff = extract_rational(aff, &expr, build); + + aff = extract_modulos(aff, &expr, &expr_neg, build); + expr = ast_expr_sub(expr, expr_neg); + + ls = isl_aff_get_domain_local_space(aff); + + data.build = build; + data.cst = isl_aff_get_constant_val(aff); + for (i = 0; i < 3; ++i) { + n = isl_aff_dim(aff, t[i]); + for (j = 0; j < n; ++j) { + v = isl_aff_get_coefficient_val(aff, t[i], j); + if (!v) + expr = isl_ast_expr_free(expr); + if (isl_val_is_zero(v)) { + isl_val_free(v); + continue; + } + expr = isl_ast_expr_add_term(expr, + ls, l[i], j, v, &data); + } + } + + expr = isl_ast_expr_add_int(expr, data.cst); + + isl_local_space_free(ls); + isl_aff_free(aff); + return expr; +} + +/* Add terms to "expr" for each variable in "aff" with a coefficient + * with sign equal to "sign". + * The result is simplified in terms of data->build->domain. + */ +static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr, + __isl_keep isl_aff *aff, int sign, struct isl_ast_add_term_data *data) +{ + int i, j; + isl_val *v; + enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div }; + enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div }; + isl_local_space *ls; + + ls = isl_aff_get_domain_local_space(aff); + + for (i = 0; i < 3; ++i) { + int n = isl_aff_dim(aff, t[i]); + for (j = 0; j < n; ++j) { + v = isl_aff_get_coefficient_val(aff, t[i], j); + if (sign * isl_val_sgn(v) <= 0) { + isl_val_free(v); + continue; + } + v = isl_val_abs(v); + expr = isl_ast_expr_add_term(expr, + ls, l[i], j, v, data); + } + } + + isl_local_space_free(ls); + + return expr; +} + +/* Should the constant term "v" be considered positive? + * + * A positive constant will be added to "pos" by the caller, + * while a negative constant will be added to "neg". + * If either "pos" or "neg" is exactly zero, then we prefer + * to add the constant "v" to that side, irrespective of the sign of "v". + * This results in slightly shorter expressions and may reduce the risk + * of overflows. + */ +static int constant_is_considered_positive(__isl_keep isl_val *v, + __isl_keep isl_ast_expr *pos, __isl_keep isl_ast_expr *neg) +{ + if (ast_expr_is_zero(pos)) + return 1; + if (ast_expr_is_zero(neg)) + return 0; + return isl_val_is_pos(v); +} + +/* Check if the equality + * + * aff = 0 + * + * represents a stride constraint on the integer division "pos". + * + * In particular, if the integer division "pos" is equal to + * + * floor(e/d) + * + * then check if aff is equal to + * + * e - d floor(e/d) + * + * or its opposite. + * + * If so, the equality is exactly + * + * e mod d = 0 + * + * Note that in principle we could also accept + * + * e - d floor(e'/d) + * + * where e and e' differ by a constant. + */ +static int is_stride_constraint(__isl_keep isl_aff *aff, int pos) +{ + isl_aff *div; + isl_val *c, *d; + int eq; + + div = isl_aff_get_div(aff, pos); + c = isl_aff_get_coefficient_val(aff, isl_dim_div, pos); + d = isl_aff_get_denominator_val(div); + eq = isl_val_abs_eq(c, d); + if (eq >= 0 && eq) { + aff = isl_aff_copy(aff); + aff = isl_aff_set_coefficient_si(aff, isl_dim_div, pos, 0); + div = isl_aff_scale_val(div, d); + if (isl_val_is_pos(c)) + div = isl_aff_neg(div); + eq = isl_aff_plain_is_equal(div, aff); + isl_aff_free(aff); + } else + isl_val_free(d); + isl_val_free(c); + isl_aff_free(div); + + return eq; +} + +/* Are all coefficients of "aff" (zero or) negative? + */ +static int all_negative_coefficients(__isl_keep isl_aff *aff) +{ + int i, n; + + if (!aff) + return 0; + + n = isl_aff_dim(aff, isl_dim_param); + for (i = 0; i < n; ++i) + if (isl_aff_coefficient_sgn(aff, isl_dim_param, i) > 0) + return 0; + + n = isl_aff_dim(aff, isl_dim_in); + for (i = 0; i < n; ++i) + if (isl_aff_coefficient_sgn(aff, isl_dim_in, i) > 0) + return 0; + + return 1; +} + +/* Give an equality of the form + * + * aff = e - d floor(e/d) = 0 + * + * or + * + * aff = -e + d floor(e/d) = 0 + * + * with the integer division "pos" equal to floor(e/d), + * construct the AST expression + * + * (isl_ast_op_eq, (isl_ast_op_zdiv_r, expr(e), expr(d)), expr(0)) + * + * If e only has negative coefficients, then construct + * + * (isl_ast_op_eq, (isl_ast_op_zdiv_r, expr(-e), expr(d)), expr(0)) + * + * instead. + */ +static __isl_give isl_ast_expr *extract_stride_constraint( + __isl_take isl_aff *aff, int pos, __isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + isl_val *c; + isl_ast_expr *expr, *cst; + + if (!aff) + return NULL; + + ctx = isl_aff_get_ctx(aff); + + c = isl_aff_get_coefficient_val(aff, isl_dim_div, pos); + aff = isl_aff_set_coefficient_si(aff, isl_dim_div, pos, 0); + + if (all_negative_coefficients(aff)) + aff = isl_aff_neg(aff); + + cst = isl_ast_expr_from_val(isl_val_abs(c)); + expr = isl_ast_expr_from_aff(aff, build); + + expr = isl_ast_expr_alloc_binary(isl_ast_op_zdiv_r, expr, cst); + cst = isl_ast_expr_alloc_int_si(ctx, 0); + expr = isl_ast_expr_alloc_binary(isl_ast_op_eq, expr, cst); + + return expr; +} + +/* Construct an isl_ast_expr that evaluates the condition "constraint", + * The result is simplified in terms of build->domain. + * + * We first check if the constraint is an equality of the form + * + * e - d floor(e/d) = 0 + * + * i.e., + * + * e mod d = 0 + * + * If so, we convert it to + * + * (isl_ast_op_eq, (isl_ast_op_zdiv_r, expr(e), expr(d)), expr(0)) + * + * Otherwise, let the constraint by either "a >= 0" or "a == 0". + * We first extract hidden modulo computations from "a" + * and then collect all the terms with a positive coefficient in cons_pos + * and the terms with a negative coefficient in cons_neg. + * + * The result is then of the form + * + * (isl_ast_op_ge, expr(pos), expr(-neg))) + * + * or + * + * (isl_ast_op_eq, expr(pos), expr(-neg))) + * + * However, if the first expression is an integer constant (and the second + * is not), then we swap the two expressions. This ensures that we construct, + * e.g., "i <= 5" rather than "5 >= i". + * + * Furthermore, is there are no terms with positive coefficients (or no terms + * with negative coefficients), then the constant term is added to "pos" + * (or "neg"), ignoring the sign of the constant term. + */ +static __isl_give isl_ast_expr *isl_ast_expr_from_constraint( + __isl_take isl_constraint *constraint, __isl_keep isl_ast_build *build) +{ + int i, n; + isl_ctx *ctx; + isl_ast_expr *expr_pos; + isl_ast_expr *expr_neg; + isl_ast_expr *expr; + isl_aff *aff; + int eq; + enum isl_ast_op_type type; + struct isl_ast_add_term_data data; + + if (!constraint) + return NULL; + + aff = isl_constraint_get_aff(constraint); + eq = isl_constraint_is_equality(constraint); + isl_constraint_free(constraint); + + n = isl_aff_dim(aff, isl_dim_div); + if (eq && n > 0) + for (i = 0; i < n; ++i) { + int is_stride; + is_stride = is_stride_constraint(aff, i); + if (is_stride < 0) + goto error; + if (is_stride) + return extract_stride_constraint(aff, i, build); + } + + ctx = isl_aff_get_ctx(aff); + expr_pos = isl_ast_expr_alloc_int_si(ctx, 0); + expr_neg = isl_ast_expr_alloc_int_si(ctx, 0); + + aff = extract_modulos(aff, &expr_pos, &expr_neg, build); + + data.build = build; + data.cst = isl_aff_get_constant_val(aff); + expr_pos = add_signed_terms(expr_pos, aff, 1, &data); + data.cst = isl_val_neg(data.cst); + expr_neg = add_signed_terms(expr_neg, aff, -1, &data); + data.cst = isl_val_neg(data.cst); + + if (constant_is_considered_positive(data.cst, expr_pos, expr_neg)) { + expr_pos = isl_ast_expr_add_int(expr_pos, data.cst); + } else { + data.cst = isl_val_neg(data.cst); + expr_neg = isl_ast_expr_add_int(expr_neg, data.cst); + } + + if (isl_ast_expr_get_type(expr_pos) == isl_ast_expr_int && + isl_ast_expr_get_type(expr_neg) != isl_ast_expr_int) { + type = eq ? isl_ast_op_eq : isl_ast_op_le; + expr = isl_ast_expr_alloc_binary(type, expr_neg, expr_pos); + } else { + type = eq ? isl_ast_op_eq : isl_ast_op_ge; + expr = isl_ast_expr_alloc_binary(type, expr_pos, expr_neg); + } + + isl_aff_free(aff); + return expr; +error: + isl_aff_free(aff); + return NULL; +} + +/* Wrapper around isl_constraint_cmp_last_non_zero for use + * as a callback to isl_constraint_list_sort. + * If isl_constraint_cmp_last_non_zero cannot tell the constraints + * apart, then use isl_constraint_plain_cmp instead. + */ +static int cmp_constraint(__isl_keep isl_constraint *a, + __isl_keep isl_constraint *b, void *user) +{ + int cmp; + + cmp = isl_constraint_cmp_last_non_zero(a, b); + if (cmp != 0) + return cmp; + return isl_constraint_plain_cmp(a, b); +} + +/* Construct an isl_ast_expr that evaluates the conditions defining "bset". + * The result is simplified in terms of build->domain. + * + * If "bset" is not bounded by any constraint, then we contruct + * the expression "1", i.e., "true". + * + * Otherwise, we sort the constraints, putting constraints that involve + * integer divisions after those that do not, and construct an "and" + * of the ast expressions of the individual constraints. + * + * Each constraint is added to the generated constraints of the build + * after it has been converted to an AST expression so that it can be used + * to simplify the following constraints. This may change the truth value + * of subsequent constraints that do not satisfy the earlier constraints, + * but this does not affect the outcome of the conjunction as it is + * only true if all the conjuncts are true (no matter in what order + * they are evaluated). In particular, the constraints that do not + * involve integer divisions may serve to simplify some constraints + * that do involve integer divisions. + */ +__isl_give isl_ast_expr *isl_ast_build_expr_from_basic_set( + __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset) +{ + int i, n; + isl_constraint *c; + isl_constraint_list *list; + isl_ast_expr *res; + isl_set *set; + + list = isl_basic_set_get_constraint_list(bset); + isl_basic_set_free(bset); + list = isl_constraint_list_sort(list, &cmp_constraint, NULL); + if (!list) + return NULL; + n = isl_constraint_list_n_constraint(list); + if (n == 0) { + isl_ctx *ctx = isl_constraint_list_get_ctx(list); + isl_constraint_list_free(list); + return isl_ast_expr_alloc_int_si(ctx, 1); + } + + build = isl_ast_build_copy(build); + + c = isl_constraint_list_get_constraint(list, 0); + bset = isl_basic_set_from_constraint(isl_constraint_copy(c)); + set = isl_set_from_basic_set(bset); + res = isl_ast_expr_from_constraint(c, build); + build = isl_ast_build_restrict_generated(build, set); + + for (i = 1; i < n; ++i) { + isl_ast_expr *expr; + + c = isl_constraint_list_get_constraint(list, i); + bset = isl_basic_set_from_constraint(isl_constraint_copy(c)); + set = isl_set_from_basic_set(bset); + expr = isl_ast_expr_from_constraint(c, build); + build = isl_ast_build_restrict_generated(build, set); + res = isl_ast_expr_and(res, expr); + } + + isl_constraint_list_free(list); + isl_ast_build_free(build); + return res; +} + +/* Construct an isl_ast_expr that evaluates the conditions defining "set". + * The result is simplified in terms of build->domain. + * + * If "set" is an (obviously) empty set, then return the expression "0". + * + * If there are multiple disjuncts in the description of the set, + * then subsequent disjuncts are simplified in a context where + * the previous disjuncts have been removed from build->domain. + * In particular, constraints that ensure that there is no overlap + * with these previous disjuncts, can be removed. + * This is mostly useful for disjuncts that are only defined by + * a single constraint (relative to the build domain) as the opposite + * of that single constraint can then be removed from the other disjuncts. + * In order not to increase the number of disjuncts in the build domain + * after subtracting the previous disjuncts of "set", the simple hull + * is computed after taking the difference with each of these disjuncts. + * This means that constraints that prevent overlap with a union + * of multiple previous disjuncts are not removed. + * + * "set" lives in the internal schedule space. + */ +__isl_give isl_ast_expr *isl_ast_build_expr_from_set_internal( + __isl_keep isl_ast_build *build, __isl_take isl_set *set) +{ + int i, n; + isl_basic_set *bset; + isl_basic_set_list *list; + isl_set *domain; + isl_ast_expr *res; + + list = isl_set_get_basic_set_list(set); + isl_set_free(set); + + if (!list) + return NULL; + n = isl_basic_set_list_n_basic_set(list); + if (n == 0) { + isl_ctx *ctx = isl_ast_build_get_ctx(build); + isl_basic_set_list_free(list); + return isl_ast_expr_from_val(isl_val_zero(ctx)); + } + + domain = isl_ast_build_get_domain(build); + + bset = isl_basic_set_list_get_basic_set(list, 0); + set = isl_set_from_basic_set(isl_basic_set_copy(bset)); + res = isl_ast_build_expr_from_basic_set(build, bset); + + for (i = 1; i < n; ++i) { + isl_ast_expr *expr; + isl_set *rest; + + rest = isl_set_subtract(isl_set_copy(domain), set); + rest = isl_set_from_basic_set(isl_set_simple_hull(rest)); + domain = isl_set_intersect(domain, rest); + bset = isl_basic_set_list_get_basic_set(list, i); + set = isl_set_from_basic_set(isl_basic_set_copy(bset)); + bset = isl_basic_set_gist(bset, + isl_set_simple_hull(isl_set_copy(domain))); + expr = isl_ast_build_expr_from_basic_set(build, bset); + res = isl_ast_expr_or(res, expr); + } + + isl_set_free(domain); + isl_set_free(set); + isl_basic_set_list_free(list); + return res; +} + +/* Construct an isl_ast_expr that evaluates the conditions defining "set". + * The result is simplified in terms of build->domain. + * + * If "set" is an (obviously) empty set, then return the expression "0". + * + * "set" lives in the external schedule space. + * + * The internal AST expression generation assumes that there are + * no unknown divs, so make sure an explicit representation is available. + * Since the set comes from the outside, it may have constraints that + * are redundant with respect to the build domain. Remove them first. + */ +__isl_give isl_ast_expr *isl_ast_build_expr_from_set( + __isl_keep isl_ast_build *build, __isl_take isl_set *set) +{ + if (isl_ast_build_need_schedule_map(build)) { + isl_multi_aff *ma; + ma = isl_ast_build_get_schedule_map_multi_aff(build); + set = isl_set_preimage_multi_aff(set, ma); + } + + set = isl_set_compute_divs(set); + set = isl_ast_build_compute_gist(build, set); + return isl_ast_build_expr_from_set_internal(build, set); +} + +/* State of data about previous pieces in + * isl_ast_build_expr_from_pw_aff_internal. + * + * isl_state_none: no data about previous pieces + * isl_state_single: data about a single previous piece + * isl_state_min: data represents minimum of several pieces + * isl_state_max: data represents maximum of several pieces + */ +enum isl_from_pw_aff_state { + isl_state_none, + isl_state_single, + isl_state_min, + isl_state_max +}; + +/* Internal date structure representing a single piece in the input of + * isl_ast_build_expr_from_pw_aff_internal. + * + * If "state" is isl_state_none, then "set_list" and "aff_list" are not used. + * If "state" is isl_state_single, then "set_list" and "aff_list" contain the + * single previous subpiece. + * If "state" is isl_state_min, then "set_list" and "aff_list" contain + * a sequence of several previous subpieces that are equal to the minimum + * of the entries in "aff_list" over the union of "set_list" + * If "state" is isl_state_max, then "set_list" and "aff_list" contain + * a sequence of several previous subpieces that are equal to the maximum + * of the entries in "aff_list" over the union of "set_list" + * + * During the construction of the pieces, "set" is NULL. + * After the construction, "set" is set to the union of the elements + * in "set_list", at which point "set_list" is set to NULL. + */ +struct isl_from_pw_aff_piece { + enum isl_from_pw_aff_state state; + isl_set *set; + isl_set_list *set_list; + isl_aff_list *aff_list; +}; + +/* Internal data structure for isl_ast_build_expr_from_pw_aff_internal. + * + * "build" specifies the domain against which the result is simplified. + * "dom" is the domain of the entire isl_pw_aff. + * + * "n" is the number of pieces constructed already. + * In particular, during the construction of the pieces, "n" points to + * the piece that is being constructed. After the construction of the + * pieces, "n" is set to the total number of pieces. + * "max" is the total number of allocated entries. + * "p" contains the individual pieces. + */ +struct isl_from_pw_aff_data { + isl_ast_build *build; + isl_set *dom; + + int n; + int max; + struct isl_from_pw_aff_piece *p; +}; + +/* Initialize "data" based on "build" and "pa". + */ +static isl_stat isl_from_pw_aff_data_init(struct isl_from_pw_aff_data *data, + __isl_keep isl_ast_build *build, __isl_keep isl_pw_aff *pa) +{ + int n; + isl_ctx *ctx; + + ctx = isl_pw_aff_get_ctx(pa); + n = isl_pw_aff_n_piece(pa); + if (n == 0) + isl_die(ctx, isl_error_invalid, + "cannot handle void expression", return isl_stat_error); + data->max = n; + data->p = isl_calloc_array(ctx, struct isl_from_pw_aff_piece, n); + if (!data->p) + return isl_stat_error; + data->build = build; + data->dom = isl_pw_aff_domain(isl_pw_aff_copy(pa)); + data->n = 0; + + return isl_stat_ok; +} + +/* Free all memory allocated for "data". + */ +static void isl_from_pw_aff_data_clear(struct isl_from_pw_aff_data *data) +{ + int i; + + isl_set_free(data->dom); + if (!data->p) + return; + + for (i = 0; i < data->max; ++i) { + isl_set_free(data->p[i].set); + isl_set_list_free(data->p[i].set_list); + isl_aff_list_free(data->p[i].aff_list); + } + free(data->p); +} + +/* Initialize the current entry of "data" to an unused piece. + */ +static void set_none(struct isl_from_pw_aff_data *data) +{ + data->p[data->n].state = isl_state_none; + data->p[data->n].set_list = NULL; + data->p[data->n].aff_list = NULL; +} + +/* Store "set" and "aff" in the current entry of "data" as a single subpiece. + */ +static void set_single(struct isl_from_pw_aff_data *data, + __isl_take isl_set *set, __isl_take isl_aff *aff) +{ + data->p[data->n].state = isl_state_single; + data->p[data->n].set_list = isl_set_list_from_set(set); + data->p[data->n].aff_list = isl_aff_list_from_aff(aff); +} + +/* Extend the current entry of "data" with "set" and "aff" + * as a minimum expression. + */ +static isl_stat extend_min(struct isl_from_pw_aff_data *data, + __isl_take isl_set *set, __isl_take isl_aff *aff) +{ + int n = data->n; + data->p[n].state = isl_state_min; + data->p[n].set_list = isl_set_list_add(data->p[n].set_list, set); + data->p[n].aff_list = isl_aff_list_add(data->p[n].aff_list, aff); + + if (!data->p[n].set_list || !data->p[n].aff_list) + return isl_stat_error; + return isl_stat_ok; +} + +/* Extend the current entry of "data" with "set" and "aff" + * as a maximum expression. + */ +static isl_stat extend_max(struct isl_from_pw_aff_data *data, + __isl_take isl_set *set, __isl_take isl_aff *aff) +{ + int n = data->n; + data->p[n].state = isl_state_max; + data->p[n].set_list = isl_set_list_add(data->p[n].set_list, set); + data->p[n].aff_list = isl_aff_list_add(data->p[n].aff_list, aff); + + if (!data->p[n].set_list || !data->p[n].aff_list) + return isl_stat_error; + return isl_stat_ok; +} + +/* Extend the domain of the current entry of "data", which is assumed + * to contain a single subpiece, with "set". If "replace" is set, + * then also replace the affine function by "aff". Otherwise, + * simply free "aff". + */ +static isl_stat extend_domain(struct isl_from_pw_aff_data *data, + __isl_take isl_set *set, __isl_take isl_aff *aff, int replace) +{ + int n = data->n; + isl_set *set_n; + + set_n = isl_set_list_get_set(data->p[n].set_list, 0); + set_n = isl_set_union(set_n, set); + data->p[n].set_list = + isl_set_list_set_set(data->p[n].set_list, 0, set_n); + + if (replace) + data->p[n].aff_list = + isl_aff_list_set_aff(data->p[n].aff_list, 0, aff); + else + isl_aff_free(aff); + + if (!data->p[n].set_list || !data->p[n].aff_list) + return isl_stat_error; + return isl_stat_ok; +} + +/* Construct an isl_ast_expr from "list" within "build". + * If "state" is isl_state_single, then "list" contains a single entry and + * an isl_ast_expr is constructed for that entry. + * Otherwise a min or max expression is constructed from "list" + * depending on "state". + */ +static __isl_give isl_ast_expr *ast_expr_from_aff_list( + __isl_take isl_aff_list *list, enum isl_from_pw_aff_state state, + __isl_keep isl_ast_build *build) +{ + int i, n; + isl_aff *aff; + isl_ast_expr *expr; + enum isl_ast_op_type op_type; + + if (state == isl_state_single) { + aff = isl_aff_list_get_aff(list, 0); + isl_aff_list_free(list); + return isl_ast_expr_from_aff(aff, build); + } + n = isl_aff_list_n_aff(list); + op_type = state == isl_state_min ? isl_ast_op_min : isl_ast_op_max; + expr = isl_ast_expr_alloc_op(isl_ast_build_get_ctx(build), op_type, n); + if (!expr) + goto error; + + for (i = 0; i < n; ++i) { + isl_ast_expr *expr_i; + + aff = isl_aff_list_get_aff(list, i); + expr_i = isl_ast_expr_from_aff(aff, build); + if (!expr_i) + goto error; + expr->u.op.args[i] = expr_i; + } + + isl_aff_list_free(list); + return expr; +error: + isl_aff_list_free(list); + isl_ast_expr_free(expr); + return NULL; +} + +/* Extend the expression in "next" to take into account + * the piece at position "pos" in "data", allowing for a further extension + * for the next piece(s). + * In particular, "next" is set to a select operation that selects + * an isl_ast_expr corresponding to data->aff_list on data->set and + * to an expression that will be filled in by later calls. + * Return a pointer to this location. + * Afterwards, the state of "data" is set to isl_state_none. + * + * The constraints of data->set are added to the generated + * constraints of the build such that they can be exploited to simplify + * the AST expression constructed from data->aff_list. + */ +static isl_ast_expr **add_intermediate_piece(struct isl_from_pw_aff_data *data, + int pos, isl_ast_expr **next) +{ + isl_ctx *ctx; + isl_ast_build *build; + isl_ast_expr *ternary, *arg; + isl_set *set, *gist; + + set = data->p[pos].set; + data->p[pos].set = NULL; + ctx = isl_ast_build_get_ctx(data->build); + ternary = isl_ast_expr_alloc_op(ctx, isl_ast_op_select, 3); + gist = isl_set_gist(isl_set_copy(set), isl_set_copy(data->dom)); + arg = isl_ast_build_expr_from_set_internal(data->build, gist); + ternary = isl_ast_expr_set_op_arg(ternary, 0, arg); + build = isl_ast_build_copy(data->build); + build = isl_ast_build_restrict_generated(build, set); + arg = ast_expr_from_aff_list(data->p[pos].aff_list, + data->p[pos].state, build); + data->p[pos].aff_list = NULL; + isl_ast_build_free(build); + ternary = isl_ast_expr_set_op_arg(ternary, 1, arg); + data->p[pos].state = isl_state_none; + if (!ternary) + return NULL; + + *next = ternary; + return &ternary->u.op.args[2]; +} + +/* Extend the expression in "next" to take into account + * the final piece, located at position "pos" in "data". + * In particular, "next" is set to evaluate data->aff_list + * and the domain is ignored. + * Return isl_stat_ok on success and isl_stat_error on failure. + * + * The constraints of data->set are however added to the generated + * constraints of the build such that they can be exploited to simplify + * the AST expression constructed from data->aff_list. + */ +static isl_stat add_last_piece(struct isl_from_pw_aff_data *data, + int pos, isl_ast_expr **next) +{ + isl_ast_build *build; + + if (data->p[pos].state == isl_state_none) + isl_die(isl_ast_build_get_ctx(data->build), isl_error_invalid, + "cannot handle void expression", return isl_stat_error); + + build = isl_ast_build_copy(data->build); + build = isl_ast_build_restrict_generated(build, data->p[pos].set); + data->p[pos].set = NULL; + *next = ast_expr_from_aff_list(data->p[pos].aff_list, + data->p[pos].state, build); + data->p[pos].aff_list = NULL; + isl_ast_build_free(build); + data->p[pos].state = isl_state_none; + if (!*next) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Return -1 if the piece "p1" should be sorted before "p2" + * and 1 if it should be sorted after "p2". + * Return 0 if they do not need to be sorted in a specific order. + * + * Pieces are sorted according to the number of disjuncts + * in their domains. + */ +static int sort_pieces_cmp(const void *p1, const void *p2, void *arg) +{ + const struct isl_from_pw_aff_piece *piece1 = p1; + const struct isl_from_pw_aff_piece *piece2 = p2; + int n1, n2; + + n1 = isl_set_n_basic_set(piece1->set); + n2 = isl_set_n_basic_set(piece2->set); + + return n1 - n2; +} + +/* Construct an isl_ast_expr from the pieces in "data". + * Return the result or NULL on failure. + * + * When this function is called, data->n points to the current piece. + * If this is an effective piece, then first increment data->n such + * that data->n contains the number of pieces. + * The "set_list" fields are subsequently replaced by the corresponding + * "set" fields, after which the pieces are sorted according to + * the number of disjuncts in these "set" fields. + * + * Construct intermediate AST expressions for the initial pieces and + * finish off with the final pieces. + */ +static isl_ast_expr *build_pieces(struct isl_from_pw_aff_data *data) +{ + int i; + isl_ast_expr *res = NULL; + isl_ast_expr **next = &res; + + if (data->p[data->n].state != isl_state_none) + data->n++; + if (data->n == 0) + isl_die(isl_ast_build_get_ctx(data->build), isl_error_invalid, + "cannot handle void expression", return NULL); + + for (i = 0; i < data->n; ++i) { + data->p[i].set = isl_set_list_union(data->p[i].set_list); + if (data->p[i].state != isl_state_single) + data->p[i].set = isl_set_coalesce(data->p[i].set); + data->p[i].set_list = NULL; + } + + if (isl_sort(data->p, data->n, sizeof(data->p[0]), + &sort_pieces_cmp, NULL) < 0) + return isl_ast_expr_free(res); + + for (i = 0; i + 1 < data->n; ++i) { + next = add_intermediate_piece(data, i, next); + if (!next) + return isl_ast_expr_free(res); + } + + if (add_last_piece(data, data->n - 1, next) < 0) + return isl_ast_expr_free(res); + + return res; +} + +/* Is the domain of the current entry of "data", which is assumed + * to contain a single subpiece, a subset of "set"? + */ +static isl_bool single_is_subset(struct isl_from_pw_aff_data *data, + __isl_keep isl_set *set) +{ + isl_bool subset; + isl_set *set_n; + + set_n = isl_set_list_get_set(data->p[data->n].set_list, 0); + subset = isl_set_is_subset(set_n, set); + isl_set_free(set_n); + + return subset; +} + +/* Is "aff" a rational expression, i.e., does it have a denominator + * different from one? + */ +static isl_bool aff_is_rational(__isl_keep isl_aff *aff) +{ + isl_bool rational; + isl_val *den; + + den = isl_aff_get_denominator_val(aff); + rational = isl_bool_not(isl_val_is_one(den)); + isl_val_free(den); + + return rational; +} + +/* Does "list" consist of a single rational affine expression? + */ +static isl_bool is_single_rational_aff(__isl_keep isl_aff_list *list) +{ + isl_bool rational; + isl_aff *aff; + + if (isl_aff_list_n_aff(list) != 1) + return isl_bool_false; + aff = isl_aff_list_get_aff(list, 0); + rational = aff_is_rational(aff); + isl_aff_free(aff); + + return rational; +} + +/* Can the list of subpieces in the last piece of "data" be extended with + * "set" and "aff" based on "test"? + * In particular, is it the case for each entry (set_i, aff_i) that + * + * test(aff, aff_i) holds on set_i, and + * test(aff_i, aff) holds on set? + * + * "test" returns the set of elements where the tests holds, meaning + * that test(aff_i, aff) holds on set if set is a subset of test(aff_i, aff). + * + * This function is used to detect min/max expressions. + * If the ast_build_detect_min_max option is turned off, then + * do not even try and perform any detection and return false instead. + * + * Rational affine expressions are not considered for min/max expressions + * since the combined expression will be defined on the union of the domains, + * while a rational expression may only yield integer values + * on its own definition domain. + */ +static isl_bool extends(struct isl_from_pw_aff_data *data, + __isl_keep isl_set *set, __isl_keep isl_aff *aff, + __isl_give isl_basic_set *(*test)(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2)) +{ + int i, n; + isl_bool is_rational; + isl_ctx *ctx; + isl_set *dom; + + is_rational = aff_is_rational(aff); + if (is_rational >= 0 && !is_rational) + is_rational = is_single_rational_aff(data->p[data->n].aff_list); + if (is_rational < 0 || is_rational) + return isl_bool_not(is_rational); + + ctx = isl_ast_build_get_ctx(data->build); + if (!isl_options_get_ast_build_detect_min_max(ctx)) + return isl_bool_false; + + dom = isl_ast_build_get_domain(data->build); + set = isl_set_intersect(dom, isl_set_copy(set)); + + n = isl_set_list_n_set(data->p[data->n].set_list); + for (i = 0; i < n ; ++i) { + isl_aff *aff_i; + isl_set *valid; + isl_set *dom, *required; + isl_bool is_valid; + + aff_i = isl_aff_list_get_aff(data->p[data->n].aff_list, i); + valid = isl_set_from_basic_set(test(isl_aff_copy(aff), aff_i)); + required = isl_set_list_get_set(data->p[data->n].set_list, i); + dom = isl_ast_build_get_domain(data->build); + required = isl_set_intersect(dom, required); + is_valid = isl_set_is_subset(required, valid); + isl_set_free(required); + isl_set_free(valid); + if (is_valid < 0 || !is_valid) { + isl_set_free(set); + return is_valid; + } + + aff_i = isl_aff_list_get_aff(data->p[data->n].aff_list, i); + valid = isl_set_from_basic_set(test(aff_i, isl_aff_copy(aff))); + is_valid = isl_set_is_subset(set, valid); + isl_set_free(valid); + if (is_valid < 0 || !is_valid) { + isl_set_free(set); + return is_valid; + } + } + + isl_set_free(set); + return isl_bool_true; +} + +/* Can the list of pieces in "data" be extended with "set" and "aff" + * to form/preserve a minimum expression? + * In particular, is it the case for each entry (set_i, aff_i) that + * + * aff >= aff_i on set_i, and + * aff_i >= aff on set? + */ +static isl_bool extends_min(struct isl_from_pw_aff_data *data, + __isl_keep isl_set *set, __isl_keep isl_aff *aff) +{ + return extends(data, set, aff, &isl_aff_ge_basic_set); +} + +/* Can the list of pieces in "data" be extended with "set" and "aff" + * to form/preserve a maximum expression? + * In particular, is it the case for each entry (set_i, aff_i) that + * + * aff <= aff_i on set_i, and + * aff_i <= aff on set? + */ +static isl_bool extends_max(struct isl_from_pw_aff_data *data, + __isl_keep isl_set *set, __isl_keep isl_aff *aff) +{ + return extends(data, set, aff, &isl_aff_le_basic_set); +} + +/* This function is called during the construction of an isl_ast_expr + * that evaluates an isl_pw_aff. + * If the last piece of "data" contains a single subpiece and + * if its affine function is equal to "aff" on a part of the domain + * that includes either "set" or the domain of that single subpiece, + * then extend the domain of that single subpiece with "set". + * If it was the original domain of the single subpiece where + * the two affine functions are equal, then also replace + * the affine function of the single subpiece by "aff". + * If the last piece of "data" contains either a single subpiece + * or a minimum, then check if this minimum expression can be extended + * with (set, aff). + * If so, extend the sequence and return. + * Perform the same operation for maximum expressions. + * If no such extension can be performed, then move to the next piece + * in "data" (if the current piece contains any data), and then store + * the current subpiece in the current piece of "data" for later handling. + */ +static isl_stat ast_expr_from_pw_aff(__isl_take isl_set *set, + __isl_take isl_aff *aff, void *user) +{ + struct isl_from_pw_aff_data *data = user; + isl_bool test; + enum isl_from_pw_aff_state state; + + state = data->p[data->n].state; + if (state == isl_state_single) { + isl_aff *aff0; + isl_set *eq; + isl_bool subset1, subset2 = isl_bool_false; + aff0 = isl_aff_list_get_aff(data->p[data->n].aff_list, 0); + eq = isl_aff_eq_set(isl_aff_copy(aff), aff0); + subset1 = isl_set_is_subset(set, eq); + if (subset1 >= 0 && !subset1) + subset2 = single_is_subset(data, eq); + isl_set_free(eq); + if (subset1 < 0 || subset2 < 0) + goto error; + if (subset1) + return extend_domain(data, set, aff, 0); + if (subset2) + return extend_domain(data, set, aff, 1); + } + if (state == isl_state_single || state == isl_state_min) { + test = extends_min(data, set, aff); + if (test < 0) + goto error; + if (test) + return extend_min(data, set, aff); + } + if (state == isl_state_single || state == isl_state_max) { + test = extends_max(data, set, aff); + if (test < 0) + goto error; + if (test) + return extend_max(data, set, aff); + } + if (state != isl_state_none) + data->n++; + set_single(data, set, aff); + + return isl_stat_ok; +error: + isl_set_free(set); + isl_aff_free(aff); + return isl_stat_error; +} + +/* Construct an isl_ast_expr that evaluates "pa". + * The result is simplified in terms of build->domain. + * + * The domain of "pa" lives in the internal schedule space. + */ +__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff_internal( + __isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa) +{ + struct isl_from_pw_aff_data data = { NULL }; + isl_ast_expr *res = NULL; + + pa = isl_ast_build_compute_gist_pw_aff(build, pa); + pa = isl_pw_aff_coalesce(pa); + if (!pa) + return NULL; + + if (isl_from_pw_aff_data_init(&data, build, pa) < 0) + goto error; + set_none(&data); + + if (isl_pw_aff_foreach_piece(pa, &ast_expr_from_pw_aff, &data) >= 0) + res = build_pieces(&data); + + isl_pw_aff_free(pa); + isl_from_pw_aff_data_clear(&data); + return res; +error: + isl_pw_aff_free(pa); + isl_from_pw_aff_data_clear(&data); + return NULL; +} + +/* Construct an isl_ast_expr that evaluates "pa". + * The result is simplified in terms of build->domain. + * + * The domain of "pa" lives in the external schedule space. + */ +__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa) +{ + isl_ast_expr *expr; + + if (isl_ast_build_need_schedule_map(build)) { + isl_multi_aff *ma; + ma = isl_ast_build_get_schedule_map_multi_aff(build); + pa = isl_pw_aff_pullback_multi_aff(pa, ma); + } + expr = isl_ast_build_expr_from_pw_aff_internal(build, pa); + return expr; +} + +/* Set the ids of the input dimensions of "mpa" to the iterator ids + * of "build". + * + * The domain of "mpa" is assumed to live in the internal schedule domain. + */ +static __isl_give isl_multi_pw_aff *set_iterator_names( + __isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa) +{ + int i, n; + + n = isl_multi_pw_aff_dim(mpa, isl_dim_in); + for (i = 0; i < n; ++i) { + isl_id *id; + + id = isl_ast_build_get_iterator_id(build, i); + mpa = isl_multi_pw_aff_set_dim_id(mpa, isl_dim_in, i, id); + } + + return mpa; +} + +/* Construct an isl_ast_expr of type "type" with as first argument "arg0" and + * the remaining arguments derived from "mpa". + * That is, construct a call or access expression that calls/accesses "arg0" + * with arguments/indices specified by "mpa". + */ +static __isl_give isl_ast_expr *isl_ast_build_with_arguments( + __isl_keep isl_ast_build *build, enum isl_ast_op_type type, + __isl_take isl_ast_expr *arg0, __isl_take isl_multi_pw_aff *mpa) +{ + int i, n; + isl_ctx *ctx; + isl_ast_expr *expr; + + ctx = isl_ast_build_get_ctx(build); + + n = isl_multi_pw_aff_dim(mpa, isl_dim_out); + expr = isl_ast_expr_alloc_op(ctx, type, 1 + n); + expr = isl_ast_expr_set_op_arg(expr, 0, arg0); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + isl_ast_expr *arg; + + pa = isl_multi_pw_aff_get_pw_aff(mpa, i); + arg = isl_ast_build_expr_from_pw_aff_internal(build, pa); + expr = isl_ast_expr_set_op_arg(expr, 1 + i, arg); + } + + isl_multi_pw_aff_free(mpa); + return expr; +} + +static __isl_give isl_ast_expr *isl_ast_build_from_multi_pw_aff_internal( + __isl_keep isl_ast_build *build, enum isl_ast_op_type type, + __isl_take isl_multi_pw_aff *mpa); + +/* Construct an isl_ast_expr that accesses the member specified by "mpa". + * The range of "mpa" is assumed to be wrapped relation. + * The domain of this wrapped relation specifies the structure being + * accessed, while the range of this wrapped relation spacifies the + * member of the structure being accessed. + * + * The domain of "mpa" is assumed to live in the internal schedule domain. + */ +static __isl_give isl_ast_expr *isl_ast_build_from_multi_pw_aff_member( + __isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa) +{ + isl_id *id; + isl_multi_pw_aff *domain; + isl_ast_expr *domain_expr, *expr; + enum isl_ast_op_type type = isl_ast_op_access; + + domain = isl_multi_pw_aff_copy(mpa); + domain = isl_multi_pw_aff_range_factor_domain(domain); + domain_expr = isl_ast_build_from_multi_pw_aff_internal(build, + type, domain); + mpa = isl_multi_pw_aff_range_factor_range(mpa); + if (!isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out)) + isl_die(isl_ast_build_get_ctx(build), isl_error_invalid, + "missing field name", goto error); + id = isl_multi_pw_aff_get_tuple_id(mpa, isl_dim_out); + expr = isl_ast_expr_from_id(id); + expr = isl_ast_expr_alloc_binary(isl_ast_op_member, domain_expr, expr); + return isl_ast_build_with_arguments(build, type, expr, mpa); +error: + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Construct an isl_ast_expr of type "type" that calls or accesses + * the element specified by "mpa". + * The first argument is obtained from the output tuple name. + * The remaining arguments are given by the piecewise affine expressions. + * + * If the range of "mpa" is a mapped relation, then we assume it + * represents an access to a member of a structure. + * + * The domain of "mpa" is assumed to live in the internal schedule domain. + */ +static __isl_give isl_ast_expr *isl_ast_build_from_multi_pw_aff_internal( + __isl_keep isl_ast_build *build, enum isl_ast_op_type type, + __isl_take isl_multi_pw_aff *mpa) +{ + isl_ctx *ctx; + isl_id *id; + isl_ast_expr *expr; + + if (!mpa) + goto error; + + if (type == isl_ast_op_access && + isl_multi_pw_aff_range_is_wrapping(mpa)) + return isl_ast_build_from_multi_pw_aff_member(build, mpa); + + mpa = set_iterator_names(build, mpa); + if (!build || !mpa) + goto error; + + ctx = isl_ast_build_get_ctx(build); + + if (isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out)) + id = isl_multi_pw_aff_get_tuple_id(mpa, isl_dim_out); + else + id = isl_id_alloc(ctx, "", NULL); + + expr = isl_ast_expr_from_id(id); + return isl_ast_build_with_arguments(build, type, expr, mpa); +error: + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Construct an isl_ast_expr of type "type" that calls or accesses + * the element specified by "pma". + * The first argument is obtained from the output tuple name. + * The remaining arguments are given by the piecewise affine expressions. + * + * The domain of "pma" is assumed to live in the internal schedule domain. + */ +static __isl_give isl_ast_expr *isl_ast_build_from_pw_multi_aff_internal( + __isl_keep isl_ast_build *build, enum isl_ast_op_type type, + __isl_take isl_pw_multi_aff *pma) +{ + isl_multi_pw_aff *mpa; + + mpa = isl_multi_pw_aff_from_pw_multi_aff(pma); + return isl_ast_build_from_multi_pw_aff_internal(build, type, mpa); +} + +/* Construct an isl_ast_expr of type "type" that calls or accesses + * the element specified by "mpa". + * The first argument is obtained from the output tuple name. + * The remaining arguments are given by the piecewise affine expressions. + * + * The domain of "mpa" is assumed to live in the external schedule domain. + */ +static __isl_give isl_ast_expr *isl_ast_build_from_multi_pw_aff( + __isl_keep isl_ast_build *build, enum isl_ast_op_type type, + __isl_take isl_multi_pw_aff *mpa) +{ + int is_domain; + isl_ast_expr *expr; + isl_space *space_build, *space_mpa; + + space_build = isl_ast_build_get_space(build, 0); + space_mpa = isl_multi_pw_aff_get_space(mpa); + is_domain = isl_space_tuple_is_equal(space_build, isl_dim_set, + space_mpa, isl_dim_in); + isl_space_free(space_build); + isl_space_free(space_mpa); + if (is_domain < 0) + goto error; + if (!is_domain) + isl_die(isl_ast_build_get_ctx(build), isl_error_invalid, + "spaces don't match", goto error); + + if (isl_ast_build_need_schedule_map(build)) { + isl_multi_aff *ma; + ma = isl_ast_build_get_schedule_map_multi_aff(build); + mpa = isl_multi_pw_aff_pullback_multi_aff(mpa, ma); + } + + expr = isl_ast_build_from_multi_pw_aff_internal(build, type, mpa); + return expr; +error: + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Construct an isl_ast_expr that calls the domain element specified by "mpa". + * The name of the function is obtained from the output tuple name. + * The arguments are given by the piecewise affine expressions. + * + * The domain of "mpa" is assumed to live in the external schedule domain. + */ +__isl_give isl_ast_expr *isl_ast_build_call_from_multi_pw_aff( + __isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa) +{ + return isl_ast_build_from_multi_pw_aff(build, isl_ast_op_call, mpa); +} + +/* Construct an isl_ast_expr that accesses the array element specified by "mpa". + * The name of the array is obtained from the output tuple name. + * The index expressions are given by the piecewise affine expressions. + * + * The domain of "mpa" is assumed to live in the external schedule domain. + */ +__isl_give isl_ast_expr *isl_ast_build_access_from_multi_pw_aff( + __isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa) +{ + return isl_ast_build_from_multi_pw_aff(build, isl_ast_op_access, mpa); +} + +/* Construct an isl_ast_expr of type "type" that calls or accesses + * the element specified by "pma". + * The first argument is obtained from the output tuple name. + * The remaining arguments are given by the piecewise affine expressions. + * + * The domain of "pma" is assumed to live in the external schedule domain. + */ +static __isl_give isl_ast_expr *isl_ast_build_from_pw_multi_aff( + __isl_keep isl_ast_build *build, enum isl_ast_op_type type, + __isl_take isl_pw_multi_aff *pma) +{ + isl_multi_pw_aff *mpa; + + mpa = isl_multi_pw_aff_from_pw_multi_aff(pma); + return isl_ast_build_from_multi_pw_aff(build, type, mpa); +} + +/* Construct an isl_ast_expr that calls the domain element specified by "pma". + * The name of the function is obtained from the output tuple name. + * The arguments are given by the piecewise affine expressions. + * + * The domain of "pma" is assumed to live in the external schedule domain. + */ +__isl_give isl_ast_expr *isl_ast_build_call_from_pw_multi_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma) +{ + return isl_ast_build_from_pw_multi_aff(build, isl_ast_op_call, pma); +} + +/* Construct an isl_ast_expr that accesses the array element specified by "pma". + * The name of the array is obtained from the output tuple name. + * The index expressions are given by the piecewise affine expressions. + * + * The domain of "pma" is assumed to live in the external schedule domain. + */ +__isl_give isl_ast_expr *isl_ast_build_access_from_pw_multi_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma) +{ + return isl_ast_build_from_pw_multi_aff(build, isl_ast_op_access, pma); +} + +/* Construct an isl_ast_expr that calls the domain element + * specified by "executed". + * + * "executed" is assumed to be single-valued, with a domain that lives + * in the internal schedule space. + */ +__isl_give isl_ast_node *isl_ast_build_call_from_executed( + __isl_keep isl_ast_build *build, __isl_take isl_map *executed) +{ + isl_pw_multi_aff *iteration; + isl_ast_expr *expr; + + iteration = isl_pw_multi_aff_from_map(executed); + iteration = isl_ast_build_compute_gist_pw_multi_aff(build, iteration); + iteration = isl_pw_multi_aff_intersect_domain(iteration, + isl_ast_build_get_domain(build)); + expr = isl_ast_build_from_pw_multi_aff_internal(build, isl_ast_op_call, + iteration); + return isl_ast_node_alloc_user(expr); +} Index: contrib/isl/isl_ast_build_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_ast_build_private.h @@ -0,0 +1,327 @@ +#ifndef ISL_AST_BUILD_PRIVATE_H +#define ISL_AST_BUILD_PRIVATE_H + +#include +#include +#include +#include +#include +#include + +/* An isl_ast_build represents the context in which AST is being + * generated. That is, it (mostly) contains information about outer + * loops that can be used to simplify inner loops. + * + * "domain" represents constraints on the internal schedule domain, + * corresponding to the context of the AST generation and the constraints + * implied by the loops that have already been generated. + * When an isl_ast_build is first created, outside any AST generation, + * the domain is typically a parameter set. It is only when a AST + * generation phase is initiated that the domain of the isl_ast_build + * is changed to refer to the internal schedule domain. + * The domain then lives in a space of the form + * + * S + * + * or + * + * [O -> S] + * + * O represents the loops generated in outer AST generations. + * S represents the loops (both generated and to be generated) + * of the current AST generation. + * Both include eliminated loops. + * "domain" is expected not to have any unknown divs because + * it is used as the context argument in a call to isl_basic_set_gist + * in isl_ast_build_compute_gist_basic_set. + * + * "depth" is equal to the number of loops that have already + * been generated (including those in outer AST generations). + * "outer_pos" is equal to the number of loops in outer AST generations. + * + * "generated" is a superset of "domain" corresponding to those + * constraints that were either given by the user or that have + * effectively been generated (as bounds on a for loop). + * + * "pending" is a superset of "domain" corresponding to the constraints + * that still need to be generated (as guards), but that may end up + * not getting generated if they are implied by any constraints + * enforced by inner loops. + * + * "strides" contains the stride of each loop. The number of elements + * is equal to the number of dimensions in "domain". + * "offsets" constains the offsets of strided loops. If s is the stride + * for a given dimension and f is the corresponding offset, then the + * dimension takes on values + * + * f + s a + * + * with a an integer. For non-strided loops, the offset is zero. + * + * "iterators" contains the loop iterators of both generated and + * to be generated loops. The number of elements is at least as + * large as the dimension of the internal schedule domain. The + * number may be larger, in which case the additional ids can be + * used in a nested AST generation should the schedule be non-injective. + * + * "values" lives in the space + * + * [O -> S] -> [O -> S] (or S -> S) + * + * and expresses (if possible) loop iterators in terms of parameters + * and outer loop iterators. If the value of a given loop iterator + * cannot be expressed as an affine expression (either because the iterator + * attains multiple values or because the single value is a piecewise + * affine expression), then it is expressed in "values" as being equal + * to itself. + * + * "value" is the value of the loop iterator at the current depth. + * It is NULL if it has not been computed yet or if the value of the + * given loop iterator cannot be expressed as a piecewise affine expression + * (because the iterator attains multiple values). + * + * "schedule_map" maps the internal schedule domain to the external schedule + * domain. It may be NULL if it hasn't been computed yet. + * See isl_ast_build_get_schedule_map_multi_aff. + * + * "internal2input" maps the internal schedule domain to the original + * input schedule domain. In case of a schedule tree input, the original + * input schedule domain consist of the flat product of all outer + * band node spaces, including the current band node. + * It may be NULL if there no longer is such a uniform mapping + * (because different iterations have been rescheduled differently). + * + * "options" contains the AST build options in case we are generating + * an AST from a flat schedule map. When creating an AST from a schedule + * tree, this field is ignored. + * + * The "create_leaf" callback is called for every leaf in the generated AST. + * The callback is responsible for creating the node to be placed at those + * leaves. If this callback is not set, then isl will generated user + * nodes with call expressions corresponding to an element of the domain. + * + * The "at_each_domain" callback is called on every node created to represent + * an element of the domain. Each of these nodes is a user node + * with as expression a call expression. + * + * The "before_each_for" callback is called on each for node before + * its children have been created. + * + * The "after_each_for" callback is called on each for node after + * its children have been created. + * + * The "before_each_mark" callback is called before we handle the subtree + * of an isl_schedule_node_mark node. + * + * The "after_each_mark" callback is called after we have handled the subtree + * of an isl_schedule_node_mark node. + * + * "executed" contains the inverse schedule at this point + * of the AST generation. + * It is currently only used in isl_ast_build_get_schedule, which is + * in turn only used by user code from within a callback. + * The value is set right before we may be calling such a callback. + * + * "single_valued" is set if the current inverse schedule (which may or may + * not be stored in "executed") is known to be single valued, specifically + * an inverse schedule that was not (appeared not to be) single valued + * is extended to a single valued inverse schedule. This is mainly used + * to avoid an infinite recursion when we fail to detect later on that + * the extended inverse schedule is single valued. + * + * "node" points to the current band node in case we are generating + * an AST from a schedule tree. It may be NULL if we are not generating + * an AST from a schedule tree or if we are not inside a band node. + * + * "loop_type" originally constains loop AST generation types for + * the "n" members of "node" and it is updated (along with "n") when + * a schedule dimension is inserted. + * It is NULL if "node" is NULL. + * + * "isolated" is the piece of the schedule domain isolated by the isolate + * option on the current band. This set may be NULL if we have not checked + * for the isolate option yet. + */ +struct isl_ast_build { + int ref; + + int outer_pos; + int depth; + + isl_id_list *iterators; + + isl_set *domain; + isl_set *generated; + isl_set *pending; + isl_multi_aff *values; + + isl_pw_aff *value; + + isl_vec *strides; + isl_multi_aff *offsets; + + isl_multi_aff *schedule_map; + isl_multi_aff *internal2input; + + isl_union_map *options; + + __isl_give isl_ast_node *(*at_each_domain)( + __isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user); + void *at_each_domain_user; + + __isl_give isl_id *(*before_each_for)( + __isl_keep isl_ast_build *context, void *user); + void *before_each_for_user; + __isl_give isl_ast_node *(*after_each_for)( + __isl_take isl_ast_node *node, + __isl_keep isl_ast_build *context, void *user); + void *after_each_for_user; + + isl_stat (*before_each_mark)(__isl_keep isl_id *mark, + __isl_keep isl_ast_build *build, void *user); + void *before_each_mark_user; + __isl_give isl_ast_node *(*after_each_mark)( + __isl_take isl_ast_node *node, + __isl_keep isl_ast_build *context, void *user); + void *after_each_mark_user; + + __isl_give isl_ast_node *(*create_leaf)( + __isl_take isl_ast_build *build, void *user); + void *create_leaf_user; + + isl_union_map *executed; + int single_valued; + + isl_schedule_node *node; + int n; + enum isl_ast_loop_type *loop_type; + isl_set *isolated; +}; + +__isl_give isl_ast_build *isl_ast_build_clear_local_info( + __isl_take isl_ast_build *build); +__isl_give isl_ast_build *isl_ast_build_increase_depth( + __isl_take isl_ast_build *build); +int isl_ast_build_get_depth(__isl_keep isl_ast_build *build); +unsigned isl_ast_build_dim(__isl_keep isl_ast_build *build, + enum isl_dim_type type); +__isl_give isl_space *isl_ast_build_get_space( + __isl_keep isl_ast_build *build, int internal); +__isl_give isl_ast_build *isl_ast_build_align_params( + __isl_take isl_ast_build *build, __isl_take isl_space *model); +__isl_give isl_ast_build *isl_ast_build_cow( + __isl_take isl_ast_build *build); +__isl_give isl_ast_build *isl_ast_build_insert_dim( + __isl_take isl_ast_build *build, int pos); +__isl_give isl_ast_build *isl_ast_build_scale_down( + __isl_take isl_ast_build *build, __isl_take isl_val *m, + __isl_take isl_union_map *umap); +__isl_give isl_ast_build *isl_ast_build_product( + __isl_take isl_ast_build *build, __isl_take isl_space *embedding); +__isl_give isl_ast_build *isl_ast_build_set_loop_bounds( + __isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds); +__isl_give isl_ast_build *isl_ast_build_set_pending_generated( + __isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds); +__isl_give isl_ast_build *isl_ast_build_detect_strides( + __isl_take isl_ast_build *build, __isl_take isl_set *set); +__isl_give isl_ast_build *isl_ast_build_include_stride( + __isl_take isl_ast_build *build); +__isl_give isl_ast_build *isl_ast_build_set_executed( + __isl_take isl_ast_build *build, + __isl_take isl_union_map *executed); +__isl_give isl_ast_build *isl_ast_build_set_single_valued( + __isl_take isl_ast_build *build, int sv); +__isl_give isl_multi_aff *isl_ast_build_get_internal2input( + __isl_keep isl_ast_build *build); +__isl_give isl_set *isl_ast_build_get_domain( + __isl_keep isl_ast_build *build); +__isl_give isl_set *isl_ast_build_get_pending( + __isl_keep isl_ast_build *build); +__isl_give isl_set *isl_ast_build_get_generated( + __isl_keep isl_ast_build *build); +__isl_give isl_ast_build *isl_ast_build_restrict_generated( + __isl_take isl_ast_build *build, __isl_take isl_set *set); +__isl_give isl_ast_build *isl_ast_build_replace_pending_by_guard( + __isl_take isl_ast_build *build, __isl_take isl_set *guard); +__isl_give int isl_ast_build_need_schedule_map( + __isl_keep isl_ast_build *build); +__isl_give isl_multi_aff *isl_ast_build_get_schedule_map_multi_aff( + __isl_keep isl_ast_build *build); +__isl_give isl_map *isl_ast_build_get_schedule_map( + __isl_keep isl_ast_build *build); +int isl_ast_build_has_affine_value(__isl_keep isl_ast_build *build, int pos); +int isl_ast_build_has_value(__isl_keep isl_ast_build *build); +__isl_give isl_id *isl_ast_build_get_iterator_id( + __isl_keep isl_ast_build *build, int pos); + +int isl_ast_build_has_schedule_node(__isl_keep isl_ast_build *build); +__isl_give isl_schedule_node *isl_ast_build_get_schedule_node( + __isl_keep isl_ast_build *build); +__isl_give isl_ast_build *isl_ast_build_set_schedule_node( + __isl_take isl_ast_build *build, + __isl_take isl_schedule_node *node); +__isl_give isl_ast_build *isl_ast_build_reset_schedule_node( + __isl_take isl_ast_build *build); + +__isl_give isl_ast_build *isl_ast_build_extract_isolated( + __isl_take isl_ast_build *build); +int isl_ast_build_has_isolated(__isl_keep isl_ast_build *build); +__isl_give isl_set *isl_ast_build_get_isolated( + __isl_keep isl_ast_build *build); + +__isl_give isl_basic_set *isl_ast_build_specialize_basic_set( + __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_ast_build_compute_gist_basic_set( + __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset); +__isl_give isl_set *isl_ast_build_specialize(__isl_keep isl_ast_build *build, + __isl_take isl_set *set); +__isl_give isl_set *isl_ast_build_compute_gist( + __isl_keep isl_ast_build *build, __isl_take isl_set *set); +__isl_give isl_map *isl_ast_build_compute_gist_map_domain( + __isl_keep isl_ast_build *build, __isl_take isl_map *map); +__isl_give isl_aff *isl_ast_build_compute_gist_aff( + __isl_keep isl_ast_build *build, __isl_take isl_aff *aff); +__isl_give isl_pw_aff *isl_ast_build_compute_gist_pw_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa); +__isl_give isl_pw_multi_aff *isl_ast_build_compute_gist_pw_multi_aff( + __isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma); + +__isl_give isl_union_map *isl_ast_build_substitute_values_union_map_domain( + __isl_keep isl_ast_build *build, __isl_take isl_union_map *umap); + +int isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build, + __isl_keep isl_aff *aff); + +isl_bool isl_ast_build_has_stride(__isl_keep isl_ast_build *build, int pos); +__isl_give isl_aff *isl_ast_build_get_offset(__isl_keep isl_ast_build *build, + int pos); +__isl_give isl_val *isl_ast_build_get_stride(__isl_keep isl_ast_build *build, + int pos); +__isl_give isl_set *isl_ast_build_get_stride_constraint( + __isl_keep isl_ast_build *build); +__isl_give isl_multi_aff *isl_ast_build_get_stride_expansion( + __isl_keep isl_ast_build *build); + +void isl_ast_build_dump(__isl_keep isl_ast_build *build); + +__isl_give isl_set *isl_ast_build_get_option_domain( + __isl_keep isl_ast_build *build, enum isl_ast_loop_type type); +__isl_give isl_map *isl_ast_build_get_separation_class( + __isl_keep isl_ast_build *build); +__isl_give isl_set *isl_ast_build_eliminate( + __isl_keep isl_ast_build *build, __isl_take isl_set *domain); +__isl_give isl_set *isl_ast_build_eliminate_inner( + __isl_keep isl_ast_build *build, __isl_take isl_set *set); +__isl_give isl_set *isl_ast_build_eliminate_divs( + __isl_keep isl_ast_build *build, __isl_take isl_set *set); + +enum isl_ast_loop_type isl_ast_build_get_loop_type( + __isl_keep isl_ast_build *build, int isolated); + +__isl_give isl_map *isl_ast_build_map_to_iterator( + __isl_keep isl_ast_build *build, __isl_take isl_set *set); + +int isl_ast_build_options_involve_depth(__isl_keep isl_ast_build *build); + +#endif Index: contrib/isl/isl_ast_codegen.c =================================================================== --- /dev/null +++ contrib/isl/isl_ast_codegen.c @@ -0,0 +1,5758 @@ +/* + * Copyright 2012-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Data used in generate_domain. + * + * "build" is the input build. + * "list" collects the results. + */ +struct isl_generate_domain_data { + isl_ast_build *build; + + isl_ast_graft_list *list; +}; + +static __isl_give isl_ast_graft_list *generate_next_level( + __isl_take isl_union_map *executed, + __isl_take isl_ast_build *build); +static __isl_give isl_ast_graft_list *generate_code( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build, + int internal); + +/* Generate an AST for a single domain based on + * the (non single valued) inverse schedule "executed". + * + * We extend the schedule with the iteration domain + * and continue generating through a call to generate_code. + * + * In particular, if executed has the form + * + * S -> D + * + * then we continue generating code on + * + * [S -> D] -> D + * + * The extended inverse schedule is clearly single valued + * ensuring that the nested generate_code will not reach this function, + * but will instead create calls to all elements of D that need + * to be executed from the current schedule domain. + */ +static isl_stat generate_non_single_valued(__isl_take isl_map *executed, + struct isl_generate_domain_data *data) +{ + isl_map *identity; + isl_ast_build *build; + isl_ast_graft_list *list; + + build = isl_ast_build_copy(data->build); + + identity = isl_set_identity(isl_map_range(isl_map_copy(executed))); + executed = isl_map_domain_product(executed, identity); + build = isl_ast_build_set_single_valued(build, 1); + + list = generate_code(isl_union_map_from_map(executed), build, 1); + + data->list = isl_ast_graft_list_concat(data->list, list); + + return isl_stat_ok; +} + +/* Call the at_each_domain callback, if requested by the user, + * after recording the current inverse schedule in the build. + */ +static __isl_give isl_ast_graft *at_each_domain(__isl_take isl_ast_graft *graft, + __isl_keep isl_map *executed, __isl_keep isl_ast_build *build) +{ + if (!graft || !build) + return isl_ast_graft_free(graft); + if (!build->at_each_domain) + return graft; + + build = isl_ast_build_copy(build); + build = isl_ast_build_set_executed(build, + isl_union_map_from_map(isl_map_copy(executed))); + if (!build) + return isl_ast_graft_free(graft); + + graft->node = build->at_each_domain(graft->node, + build, build->at_each_domain_user); + isl_ast_build_free(build); + + if (!graft->node) + graft = isl_ast_graft_free(graft); + + return graft; +} + +/* Generate a call expression for the single executed + * domain element "map" and put a guard around it based its (simplified) + * domain. "executed" is the original inverse schedule from which "map" + * has been derived. In particular, "map" is either identical to "executed" + * or it is the result of gisting "executed" with respect to the build domain. + * "executed" is only used if there is an at_each_domain callback. + * + * At this stage, any pending constraints in the build can no longer + * be simplified with respect to any enforced constraints since + * the call node does not have any enforced constraints. + * Since all pending constraints not covered by any enforced constraints + * will be added as a guard to the graft in create_node_scaled, + * even in the eliminated case, the pending constraints + * can be considered to have been generated by outer constructs. + * + * If the user has set an at_each_domain callback, it is called + * on the constructed call expression node. + */ +static isl_stat add_domain(__isl_take isl_map *executed, + __isl_take isl_map *map, struct isl_generate_domain_data *data) +{ + isl_ast_build *build; + isl_ast_graft *graft; + isl_ast_graft_list *list; + isl_set *guard, *pending; + + build = isl_ast_build_copy(data->build); + pending = isl_ast_build_get_pending(build); + build = isl_ast_build_replace_pending_by_guard(build, pending); + + guard = isl_map_domain(isl_map_copy(map)); + guard = isl_set_compute_divs(guard); + guard = isl_set_coalesce(guard); + guard = isl_set_gist(guard, isl_ast_build_get_generated(build)); + guard = isl_ast_build_specialize(build, guard); + + graft = isl_ast_graft_alloc_domain(map, build); + graft = at_each_domain(graft, executed, build); + isl_ast_build_free(build); + isl_map_free(executed); + graft = isl_ast_graft_add_guard(graft, guard, data->build); + + list = isl_ast_graft_list_from_ast_graft(graft); + data->list = isl_ast_graft_list_concat(data->list, list); + + return isl_stat_ok; +} + +/* Generate an AST for a single domain based on + * the inverse schedule "executed" and add it to data->list. + * + * If there is more than one domain element associated to the current + * schedule "time", then we need to continue the generation process + * in generate_non_single_valued. + * Note that the inverse schedule being single-valued may depend + * on constraints that are only available in the original context + * domain specified by the user. We therefore first introduce + * some of the constraints of data->build->domain. In particular, + * we intersect with a single-disjunct approximation of this set. + * We perform this approximation to avoid further splitting up + * the executed relation, possibly introducing a disjunctive guard + * on the statement. + * + * On the other hand, we only perform the test after having taken the gist + * of the domain as the resulting map is the one from which the call + * expression is constructed. Using this map to construct the call + * expression usually yields simpler results in cases where the original + * map is not obviously single-valued. + * If the original map is obviously single-valued, then the gist + * operation is skipped. + * + * Because we perform the single-valuedness test on the gisted map, + * we may in rare cases fail to recognize that the inverse schedule + * is single-valued. This becomes problematic if this happens + * from the recursive call through generate_non_single_valued + * as we would then end up in an infinite recursion. + * We therefore check if we are inside a call to generate_non_single_valued + * and revert to the ungisted map if the gisted map turns out not to be + * single-valued. + * + * Otherwise, call add_domain to generate a call expression (with guard) and + * to call the at_each_domain callback, if any. + */ +static isl_stat generate_domain(__isl_take isl_map *executed, void *user) +{ + struct isl_generate_domain_data *data = user; + isl_set *domain; + isl_map *map = NULL; + int empty, sv; + + domain = isl_ast_build_get_domain(data->build); + domain = isl_set_from_basic_set(isl_set_simple_hull(domain)); + executed = isl_map_intersect_domain(executed, domain); + empty = isl_map_is_empty(executed); + if (empty < 0) + goto error; + if (empty) { + isl_map_free(executed); + return isl_stat_ok; + } + + sv = isl_map_plain_is_single_valued(executed); + if (sv < 0) + goto error; + if (sv) + return add_domain(executed, isl_map_copy(executed), data); + + executed = isl_map_coalesce(executed); + map = isl_map_copy(executed); + map = isl_ast_build_compute_gist_map_domain(data->build, map); + sv = isl_map_is_single_valued(map); + if (sv < 0) + goto error; + if (!sv) { + isl_map_free(map); + if (data->build->single_valued) + map = isl_map_copy(executed); + else + return generate_non_single_valued(executed, data); + } + + return add_domain(executed, map, data); +error: + isl_map_free(map); + isl_map_free(executed); + return isl_stat_error; +} + +/* Call build->create_leaf to a create "leaf" node in the AST, + * encapsulate the result in an isl_ast_graft and return the result + * as a 1-element list. + * + * Note that the node returned by the user may be an entire tree. + * + * Since the node itself cannot enforce any constraints, we turn + * all pending constraints into guards and add them to the resulting + * graft to ensure that they will be generated. + * + * Before we pass control to the user, we first clear some information + * from the build that is (presumbably) only meaningful + * for the current code generation. + * This includes the create_leaf callback itself, so we make a copy + * of the build first. + */ +static __isl_give isl_ast_graft_list *call_create_leaf( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) +{ + isl_set *guard; + isl_ast_node *node; + isl_ast_graft *graft; + isl_ast_build *user_build; + + guard = isl_ast_build_get_pending(build); + user_build = isl_ast_build_copy(build); + user_build = isl_ast_build_replace_pending_by_guard(user_build, + isl_set_copy(guard)); + user_build = isl_ast_build_set_executed(user_build, executed); + user_build = isl_ast_build_clear_local_info(user_build); + if (!user_build) + node = NULL; + else + node = build->create_leaf(user_build, build->create_leaf_user); + graft = isl_ast_graft_alloc(node, build); + graft = isl_ast_graft_add_guard(graft, guard, build); + isl_ast_build_free(build); + return isl_ast_graft_list_from_ast_graft(graft); +} + +static __isl_give isl_ast_graft_list *build_ast_from_child( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed); + +/* Generate an AST after having handled the complete schedule + * of this call to the code generator or the complete band + * if we are generating an AST from a schedule tree. + * + * If we are inside a band node, then move on to the child of the band. + * + * If the user has specified a create_leaf callback, control + * is passed to the user in call_create_leaf. + * + * Otherwise, we generate one or more calls for each individual + * domain in generate_domain. + */ +static __isl_give isl_ast_graft_list *generate_inner_level( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) +{ + isl_ctx *ctx; + struct isl_generate_domain_data data = { build }; + + if (!build || !executed) + goto error; + + if (isl_ast_build_has_schedule_node(build)) { + isl_schedule_node *node; + node = isl_ast_build_get_schedule_node(build); + build = isl_ast_build_reset_schedule_node(build); + return build_ast_from_child(build, node, executed); + } + + if (build->create_leaf) + return call_create_leaf(executed, build); + + ctx = isl_union_map_get_ctx(executed); + data.list = isl_ast_graft_list_alloc(ctx, 0); + if (isl_union_map_foreach_map(executed, &generate_domain, &data) < 0) + data.list = isl_ast_graft_list_free(data.list); + + if (0) +error: data.list = NULL; + isl_ast_build_free(build); + isl_union_map_free(executed); + return data.list; +} + +/* Call the before_each_for callback, if requested by the user. + */ +static __isl_give isl_ast_node *before_each_for(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build) +{ + isl_id *id; + + if (!node || !build) + return isl_ast_node_free(node); + if (!build->before_each_for) + return node; + id = build->before_each_for(build, build->before_each_for_user); + node = isl_ast_node_set_annotation(node, id); + return node; +} + +/* Call the after_each_for callback, if requested by the user. + */ +static __isl_give isl_ast_graft *after_each_for(__isl_take isl_ast_graft *graft, + __isl_keep isl_ast_build *build) +{ + if (!graft || !build) + return isl_ast_graft_free(graft); + if (!build->after_each_for) + return graft; + graft->node = build->after_each_for(graft->node, build, + build->after_each_for_user); + if (!graft->node) + return isl_ast_graft_free(graft); + return graft; +} + +/* Plug in all the know values of the current and outer dimensions + * in the domain of "executed". In principle, we only need to plug + * in the known value of the current dimension since the values of + * outer dimensions have been plugged in already. + * However, it turns out to be easier to just plug in all known values. + */ +static __isl_give isl_union_map *plug_in_values( + __isl_take isl_union_map *executed, __isl_keep isl_ast_build *build) +{ + return isl_ast_build_substitute_values_union_map_domain(build, + executed); +} + +/* Check if the constraint "c" is a lower bound on dimension "pos", + * an upper bound, or independent of dimension "pos". + */ +static int constraint_type(isl_constraint *c, int pos) +{ + if (isl_constraint_is_lower_bound(c, isl_dim_set, pos)) + return 1; + if (isl_constraint_is_upper_bound(c, isl_dim_set, pos)) + return 2; + return 0; +} + +/* Compare the types of the constraints "a" and "b", + * resulting in constraints that are independent of "depth" + * to be sorted before the lower bounds on "depth", which in + * turn are sorted before the upper bounds on "depth". + */ +static int cmp_constraint(__isl_keep isl_constraint *a, + __isl_keep isl_constraint *b, void *user) +{ + int *depth = user; + int t1 = constraint_type(a, *depth); + int t2 = constraint_type(b, *depth); + + return t1 - t2; +} + +/* Extract a lower bound on dimension "pos" from constraint "c". + * + * If the constraint is of the form + * + * a x + f(...) >= 0 + * + * then we essentially return + * + * l = ceil(-f(...)/a) + * + * However, if the current dimension is strided, then we need to make + * sure that the lower bound we construct is of the form + * + * f + s a + * + * with f the offset and s the stride. + * We therefore compute + * + * f + s * ceil((l - f)/s) + */ +static __isl_give isl_aff *lower_bound(__isl_keep isl_constraint *c, + int pos, __isl_keep isl_ast_build *build) +{ + isl_aff *aff; + + aff = isl_constraint_get_bound(c, isl_dim_set, pos); + aff = isl_aff_ceil(aff); + + if (isl_ast_build_has_stride(build, pos)) { + isl_aff *offset; + isl_val *stride; + + offset = isl_ast_build_get_offset(build, pos); + stride = isl_ast_build_get_stride(build, pos); + + aff = isl_aff_sub(aff, isl_aff_copy(offset)); + aff = isl_aff_scale_down_val(aff, isl_val_copy(stride)); + aff = isl_aff_ceil(aff); + aff = isl_aff_scale_val(aff, stride); + aff = isl_aff_add(aff, offset); + } + + aff = isl_ast_build_compute_gist_aff(build, aff); + + return aff; +} + +/* Return the exact lower bound (or upper bound if "upper" is set) + * of "domain" as a piecewise affine expression. + * + * If we are computing a lower bound (of a strided dimension), then + * we need to make sure it is of the form + * + * f + s a + * + * where f is the offset and s is the stride. + * We therefore need to include the stride constraint before computing + * the minimum. + */ +static __isl_give isl_pw_aff *exact_bound(__isl_keep isl_set *domain, + __isl_keep isl_ast_build *build, int upper) +{ + isl_set *stride; + isl_map *it_map; + isl_pw_aff *pa; + isl_pw_multi_aff *pma; + + domain = isl_set_copy(domain); + if (!upper) { + stride = isl_ast_build_get_stride_constraint(build); + domain = isl_set_intersect(domain, stride); + } + it_map = isl_ast_build_map_to_iterator(build, domain); + if (upper) + pma = isl_map_lexmax_pw_multi_aff(it_map); + else + pma = isl_map_lexmin_pw_multi_aff(it_map); + pa = isl_pw_multi_aff_get_pw_aff(pma, 0); + isl_pw_multi_aff_free(pma); + pa = isl_ast_build_compute_gist_pw_aff(build, pa); + pa = isl_pw_aff_coalesce(pa); + + return pa; +} + +/* Callback for sorting the isl_pw_aff_list passed to reduce_list and + * remove_redundant_lower_bounds. + */ +static int reduce_list_cmp(__isl_keep isl_pw_aff *a, __isl_keep isl_pw_aff *b, + void *user) +{ + return isl_pw_aff_plain_cmp(a, b); +} + +/* Given a list of lower bounds "list", remove those that are redundant + * with respect to the other bounds in "list" and the domain of "build". + * + * We first sort the bounds in the same way as they would be sorted + * by set_for_node_expressions so that we can try and remove the last + * bounds first. + * + * For a lower bound to be effective, there needs to be at least + * one domain element for which it is larger than all other lower bounds. + * For each lower bound we therefore intersect the domain with + * the conditions that it is larger than all other bounds and + * check whether the result is empty. If so, the bound can be removed. + */ +static __isl_give isl_pw_aff_list *remove_redundant_lower_bounds( + __isl_take isl_pw_aff_list *list, __isl_keep isl_ast_build *build) +{ + int i, j, n; + isl_set *domain; + + list = isl_pw_aff_list_sort(list, &reduce_list_cmp, NULL); + if (!list) + return NULL; + + n = isl_pw_aff_list_n_pw_aff(list); + if (n <= 1) + return list; + + domain = isl_ast_build_get_domain(build); + + for (i = n - 1; i >= 0; --i) { + isl_pw_aff *pa_i; + isl_set *domain_i; + int empty; + + domain_i = isl_set_copy(domain); + pa_i = isl_pw_aff_list_get_pw_aff(list, i); + + for (j = 0; j < n; ++j) { + isl_pw_aff *pa_j; + isl_set *better; + + if (j == i) + continue; + + pa_j = isl_pw_aff_list_get_pw_aff(list, j); + better = isl_pw_aff_gt_set(isl_pw_aff_copy(pa_i), pa_j); + domain_i = isl_set_intersect(domain_i, better); + } + + empty = isl_set_is_empty(domain_i); + + isl_set_free(domain_i); + isl_pw_aff_free(pa_i); + + if (empty < 0) + goto error; + if (!empty) + continue; + list = isl_pw_aff_list_drop(list, i, 1); + n--; + } + + isl_set_free(domain); + + return list; +error: + isl_set_free(domain); + return isl_pw_aff_list_free(list); +} + +/* Extract a lower bound on dimension "pos" from each constraint + * in "constraints" and return the list of lower bounds. + * If "constraints" has zero elements, then we extract a lower bound + * from "domain" instead. + * + * If the current dimension is strided, then the lower bound + * is adjusted by lower_bound to match the stride information. + * This modification may make one or more lower bounds redundant + * with respect to the other lower bounds. We therefore check + * for this condition and remove the redundant lower bounds. + */ +static __isl_give isl_pw_aff_list *lower_bounds( + __isl_keep isl_constraint_list *constraints, int pos, + __isl_keep isl_set *domain, __isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + isl_pw_aff_list *list; + int i, n; + + if (!build) + return NULL; + + n = isl_constraint_list_n_constraint(constraints); + if (n == 0) { + isl_pw_aff *pa; + pa = exact_bound(domain, build, 0); + return isl_pw_aff_list_from_pw_aff(pa); + } + + ctx = isl_ast_build_get_ctx(build); + list = isl_pw_aff_list_alloc(ctx,n); + + for (i = 0; i < n; ++i) { + isl_aff *aff; + isl_constraint *c; + + c = isl_constraint_list_get_constraint(constraints, i); + aff = lower_bound(c, pos, build); + isl_constraint_free(c); + list = isl_pw_aff_list_add(list, isl_pw_aff_from_aff(aff)); + } + + if (isl_ast_build_has_stride(build, pos)) + list = remove_redundant_lower_bounds(list, build); + + return list; +} + +/* Extract an upper bound on dimension "pos" from each constraint + * in "constraints" and return the list of upper bounds. + * If "constraints" has zero elements, then we extract an upper bound + * from "domain" instead. + */ +static __isl_give isl_pw_aff_list *upper_bounds( + __isl_keep isl_constraint_list *constraints, int pos, + __isl_keep isl_set *domain, __isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + isl_pw_aff_list *list; + int i, n; + + n = isl_constraint_list_n_constraint(constraints); + if (n == 0) { + isl_pw_aff *pa; + pa = exact_bound(domain, build, 1); + return isl_pw_aff_list_from_pw_aff(pa); + } + + ctx = isl_ast_build_get_ctx(build); + list = isl_pw_aff_list_alloc(ctx,n); + + for (i = 0; i < n; ++i) { + isl_aff *aff; + isl_constraint *c; + + c = isl_constraint_list_get_constraint(constraints, i); + aff = isl_constraint_get_bound(c, isl_dim_set, pos); + isl_constraint_free(c); + aff = isl_aff_floor(aff); + list = isl_pw_aff_list_add(list, isl_pw_aff_from_aff(aff)); + } + + return list; +} + +/* Return an isl_ast_expr that performs the reduction of type "type" + * on AST expressions corresponding to the elements in "list". + * + * The list is assumed to contain at least one element. + * If the list contains exactly one element, then the returned isl_ast_expr + * simply computes that affine expression. + * If the list contains more than one element, then we sort it + * using a fairly abitrary but hopefully reasonably stable order. + */ +static __isl_give isl_ast_expr *reduce_list(enum isl_ast_op_type type, + __isl_keep isl_pw_aff_list *list, __isl_keep isl_ast_build *build) +{ + int i, n; + isl_ctx *ctx; + isl_ast_expr *expr; + + if (!list) + return NULL; + + n = isl_pw_aff_list_n_pw_aff(list); + + if (n == 1) + return isl_ast_build_expr_from_pw_aff_internal(build, + isl_pw_aff_list_get_pw_aff(list, 0)); + + ctx = isl_pw_aff_list_get_ctx(list); + expr = isl_ast_expr_alloc_op(ctx, type, n); + if (!expr) + return NULL; + + list = isl_pw_aff_list_copy(list); + list = isl_pw_aff_list_sort(list, &reduce_list_cmp, NULL); + if (!list) + return isl_ast_expr_free(expr); + + for (i = 0; i < n; ++i) { + isl_ast_expr *expr_i; + + expr_i = isl_ast_build_expr_from_pw_aff_internal(build, + isl_pw_aff_list_get_pw_aff(list, i)); + if (!expr_i) + goto error; + expr->u.op.args[i] = expr_i; + } + + isl_pw_aff_list_free(list); + return expr; +error: + isl_pw_aff_list_free(list); + isl_ast_expr_free(expr); + return NULL; +} + +/* Add guards implied by the "generated constraints", + * but not (necessarily) enforced by the generated AST to "guard". + * In particular, if there is any stride constraints, + * then add the guard implied by those constraints. + * If we have generated a degenerate loop, then add the guard + * implied by "bounds" on the outer dimensions, i.e., the guard + * that ensures that the single value actually exists. + * Since there may also be guards implied by a combination + * of these constraints, we first combine them before + * deriving the implied constraints. + */ +static __isl_give isl_set *add_implied_guards(__isl_take isl_set *guard, + int degenerate, __isl_keep isl_basic_set *bounds, + __isl_keep isl_ast_build *build) +{ + int depth, has_stride; + isl_space *space; + isl_set *dom, *set; + + depth = isl_ast_build_get_depth(build); + has_stride = isl_ast_build_has_stride(build, depth); + if (!has_stride && !degenerate) + return guard; + + space = isl_basic_set_get_space(bounds); + dom = isl_set_universe(space); + + if (degenerate) { + bounds = isl_basic_set_copy(bounds); + bounds = isl_basic_set_drop_constraints_not_involving_dims( + bounds, isl_dim_set, depth, 1); + set = isl_set_from_basic_set(bounds); + dom = isl_set_intersect(dom, set); + } + + if (has_stride) { + set = isl_ast_build_get_stride_constraint(build); + dom = isl_set_intersect(dom, set); + } + + dom = isl_set_eliminate(dom, isl_dim_set, depth, 1); + dom = isl_ast_build_compute_gist(build, dom); + guard = isl_set_intersect(guard, dom); + + return guard; +} + +/* Update "graft" based on "sub_build" for the degenerate case. + * + * "build" is the build in which graft->node was created + * "sub_build" contains information about the current level itself, + * including the single value attained. + * + * We set the initialization part of the for loop to the single + * value attained by the current dimension. + * The increment and condition are not strictly needed as the are known + * to be "1" and "iterator <= value" respectively. + */ +static __isl_give isl_ast_graft *refine_degenerate( + __isl_take isl_ast_graft *graft, __isl_keep isl_ast_build *build, + __isl_keep isl_ast_build *sub_build) +{ + isl_pw_aff *value; + + if (!graft || !sub_build) + return isl_ast_graft_free(graft); + + value = isl_pw_aff_copy(sub_build->value); + + graft->node->u.f.init = isl_ast_build_expr_from_pw_aff_internal(build, + value); + if (!graft->node->u.f.init) + return isl_ast_graft_free(graft); + + return graft; +} + +/* Return the intersection of constraints in "list" as a set. + */ +static __isl_give isl_set *intersect_constraints( + __isl_keep isl_constraint_list *list) +{ + int i, n; + isl_basic_set *bset; + + n = isl_constraint_list_n_constraint(list); + if (n < 1) + isl_die(isl_constraint_list_get_ctx(list), isl_error_internal, + "expecting at least one constraint", return NULL); + + bset = isl_basic_set_from_constraint( + isl_constraint_list_get_constraint(list, 0)); + for (i = 1; i < n; ++i) { + isl_basic_set *bset_i; + + bset_i = isl_basic_set_from_constraint( + isl_constraint_list_get_constraint(list, i)); + bset = isl_basic_set_intersect(bset, bset_i); + } + + return isl_set_from_basic_set(bset); +} + +/* Compute the constraints on the outer dimensions enforced by + * graft->node and add those constraints to graft->enforced, + * in case the upper bound is expressed as a set "upper". + * + * In particular, if l(...) is a lower bound in "lower", and + * + * -a i + f(...) >= 0 or a i <= f(...) + * + * is an upper bound ocnstraint on the current dimension i, + * then the for loop enforces the constraint + * + * -a l(...) + f(...) >= 0 or a l(...) <= f(...) + * + * We therefore simply take each lower bound in turn, plug it into + * the upper bounds and compute the intersection over all lower bounds. + * + * If a lower bound is a rational expression, then + * isl_basic_set_preimage_multi_aff will force this rational + * expression to have only integer values. However, the loop + * itself does not enforce this integrality constraint. We therefore + * use the ceil of the lower bounds instead of the lower bounds themselves. + * Other constraints will make sure that the for loop is only executed + * when each of the lower bounds attains an integral value. + * In particular, potentially rational values only occur in + * lower_bound if the offset is a (seemingly) rational expression, + * but then outer conditions will make sure that this rational expression + * only attains integer values. + */ +static __isl_give isl_ast_graft *set_enforced_from_set( + __isl_take isl_ast_graft *graft, + __isl_keep isl_pw_aff_list *lower, int pos, __isl_keep isl_set *upper) +{ + isl_space *space; + isl_basic_set *enforced; + isl_pw_multi_aff *pma; + int i, n; + + if (!graft || !lower) + return isl_ast_graft_free(graft); + + space = isl_set_get_space(upper); + enforced = isl_basic_set_universe(isl_space_copy(space)); + + space = isl_space_map_from_set(space); + pma = isl_pw_multi_aff_identity(space); + + n = isl_pw_aff_list_n_pw_aff(lower); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + isl_set *enforced_i; + isl_basic_set *hull; + isl_pw_multi_aff *pma_i; + + pa = isl_pw_aff_list_get_pw_aff(lower, i); + pa = isl_pw_aff_ceil(pa); + pma_i = isl_pw_multi_aff_copy(pma); + pma_i = isl_pw_multi_aff_set_pw_aff(pma_i, pos, pa); + enforced_i = isl_set_copy(upper); + enforced_i = isl_set_preimage_pw_multi_aff(enforced_i, pma_i); + hull = isl_set_simple_hull(enforced_i); + enforced = isl_basic_set_intersect(enforced, hull); + } + + isl_pw_multi_aff_free(pma); + + graft = isl_ast_graft_enforce(graft, enforced); + + return graft; +} + +/* Compute the constraints on the outer dimensions enforced by + * graft->node and add those constraints to graft->enforced, + * in case the upper bound is expressed as + * a list of affine expressions "upper". + * + * The enforced condition is that each lower bound expression is less + * than or equal to each upper bound expression. + */ +static __isl_give isl_ast_graft *set_enforced_from_list( + __isl_take isl_ast_graft *graft, + __isl_keep isl_pw_aff_list *lower, __isl_keep isl_pw_aff_list *upper) +{ + isl_set *cond; + isl_basic_set *enforced; + + lower = isl_pw_aff_list_copy(lower); + upper = isl_pw_aff_list_copy(upper); + cond = isl_pw_aff_list_le_set(lower, upper); + enforced = isl_set_simple_hull(cond); + graft = isl_ast_graft_enforce(graft, enforced); + + return graft; +} + +/* Does "aff" have a negative constant term? + */ +static isl_stat aff_constant_is_negative(__isl_take isl_set *set, + __isl_take isl_aff *aff, void *user) +{ + int *neg = user; + isl_val *v; + + v = isl_aff_get_constant_val(aff); + *neg = isl_val_is_neg(v); + isl_val_free(v); + isl_set_free(set); + isl_aff_free(aff); + + return *neg ? isl_stat_ok : isl_stat_error; +} + +/* Does "pa" have a negative constant term over its entire domain? + */ +static isl_stat pw_aff_constant_is_negative(__isl_take isl_pw_aff *pa, + void *user) +{ + isl_stat r; + int *neg = user; + + r = isl_pw_aff_foreach_piece(pa, &aff_constant_is_negative, user); + isl_pw_aff_free(pa); + + return (*neg && r >= 0) ? isl_stat_ok : isl_stat_error; +} + +/* Does each element in "list" have a negative constant term? + * + * The callback terminates the iteration as soon an element has been + * found that does not have a negative constant term. + */ +static int list_constant_is_negative(__isl_keep isl_pw_aff_list *list) +{ + int neg = 1; + + if (isl_pw_aff_list_foreach(list, + &pw_aff_constant_is_negative, &neg) < 0 && neg) + return -1; + + return neg; +} + +/* Add 1 to each of the elements in "list", where each of these elements + * is defined over the internal schedule space of "build". + */ +static __isl_give isl_pw_aff_list *list_add_one( + __isl_take isl_pw_aff_list *list, __isl_keep isl_ast_build *build) +{ + int i, n; + isl_space *space; + isl_aff *aff; + isl_pw_aff *one; + + space = isl_ast_build_get_space(build, 1); + aff = isl_aff_zero_on_domain(isl_local_space_from_space(space)); + aff = isl_aff_add_constant_si(aff, 1); + one = isl_pw_aff_from_aff(aff); + + n = isl_pw_aff_list_n_pw_aff(list); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + pa = isl_pw_aff_list_get_pw_aff(list, i); + pa = isl_pw_aff_add(pa, isl_pw_aff_copy(one)); + list = isl_pw_aff_list_set_pw_aff(list, i, pa); + } + + isl_pw_aff_free(one); + + return list; +} + +/* Set the condition part of the for node graft->node in case + * the upper bound is represented as a list of piecewise affine expressions. + * + * In particular, set the condition to + * + * iterator <= min(list of upper bounds) + * + * If each of the upper bounds has a negative constant term, then + * set the condition to + * + * iterator < min(list of (upper bound + 1)s) + * + */ +static __isl_give isl_ast_graft *set_for_cond_from_list( + __isl_take isl_ast_graft *graft, __isl_keep isl_pw_aff_list *list, + __isl_keep isl_ast_build *build) +{ + int neg; + isl_ast_expr *bound, *iterator, *cond; + enum isl_ast_op_type type = isl_ast_op_le; + + if (!graft || !list) + return isl_ast_graft_free(graft); + + neg = list_constant_is_negative(list); + if (neg < 0) + return isl_ast_graft_free(graft); + list = isl_pw_aff_list_copy(list); + if (neg) { + list = list_add_one(list, build); + type = isl_ast_op_lt; + } + + bound = reduce_list(isl_ast_op_min, list, build); + iterator = isl_ast_expr_copy(graft->node->u.f.iterator); + cond = isl_ast_expr_alloc_binary(type, iterator, bound); + graft->node->u.f.cond = cond; + + isl_pw_aff_list_free(list); + if (!graft->node->u.f.cond) + return isl_ast_graft_free(graft); + return graft; +} + +/* Set the condition part of the for node graft->node in case + * the upper bound is represented as a set. + */ +static __isl_give isl_ast_graft *set_for_cond_from_set( + __isl_take isl_ast_graft *graft, __isl_keep isl_set *set, + __isl_keep isl_ast_build *build) +{ + isl_ast_expr *cond; + + if (!graft) + return NULL; + + cond = isl_ast_build_expr_from_set_internal(build, isl_set_copy(set)); + graft->node->u.f.cond = cond; + if (!graft->node->u.f.cond) + return isl_ast_graft_free(graft); + return graft; +} + +/* Construct an isl_ast_expr for the increment (i.e., stride) of + * the current dimension. + */ +static __isl_give isl_ast_expr *for_inc(__isl_keep isl_ast_build *build) +{ + int depth; + isl_val *v; + isl_ctx *ctx; + + if (!build) + return NULL; + ctx = isl_ast_build_get_ctx(build); + depth = isl_ast_build_get_depth(build); + + if (!isl_ast_build_has_stride(build, depth)) + return isl_ast_expr_alloc_int_si(ctx, 1); + + v = isl_ast_build_get_stride(build, depth); + return isl_ast_expr_from_val(v); +} + +/* Should we express the loop condition as + * + * iterator <= min(list of upper bounds) + * + * or as a conjunction of constraints? + * + * The first is constructed from a list of upper bounds. + * The second is constructed from a set. + * + * If there are no upper bounds in "constraints", then this could mean + * that "domain" simply doesn't have an upper bound or that we didn't + * pick any upper bound. In the first case, we want to generate the + * loop condition as a(n empty) conjunction of constraints + * In the second case, we will compute + * a single upper bound from "domain" and so we use the list form. + * + * If there are upper bounds in "constraints", + * then we use the list form iff the atomic_upper_bound option is set. + */ +static int use_upper_bound_list(isl_ctx *ctx, int n_upper, + __isl_keep isl_set *domain, int depth) +{ + if (n_upper > 0) + return isl_options_get_ast_build_atomic_upper_bound(ctx); + else + return isl_set_dim_has_upper_bound(domain, isl_dim_set, depth); +} + +/* Fill in the expressions of the for node in graft->node. + * + * In particular, + * - set the initialization part of the loop to the maximum of the lower bounds + * - extract the increment from the stride of the current dimension + * - construct the for condition either based on a list of upper bounds + * or on a set of upper bound constraints. + */ +static __isl_give isl_ast_graft *set_for_node_expressions( + __isl_take isl_ast_graft *graft, __isl_keep isl_pw_aff_list *lower, + int use_list, __isl_keep isl_pw_aff_list *upper_list, + __isl_keep isl_set *upper_set, __isl_keep isl_ast_build *build) +{ + isl_ast_node *node; + + if (!graft) + return NULL; + + build = isl_ast_build_copy(build); + + node = graft->node; + node->u.f.init = reduce_list(isl_ast_op_max, lower, build); + node->u.f.inc = for_inc(build); + + if (!node->u.f.init || !node->u.f.inc) + graft = isl_ast_graft_free(graft); + + if (use_list) + graft = set_for_cond_from_list(graft, upper_list, build); + else + graft = set_for_cond_from_set(graft, upper_set, build); + + isl_ast_build_free(build); + + return graft; +} + +/* Update "graft" based on "bounds" and "domain" for the generic, + * non-degenerate, case. + * + * "c_lower" and "c_upper" contain the lower and upper bounds + * that the loop node should express. + * "domain" is the subset of the intersection of the constraints + * for which some code is executed. + * + * There may be zero lower bounds or zero upper bounds in "constraints" + * in case the list of constraints was created + * based on the atomic option or based on separation with explicit bounds. + * In that case, we use "domain" to derive lower and/or upper bounds. + * + * We first compute a list of one or more lower bounds. + * + * Then we decide if we want to express the condition as + * + * iterator <= min(list of upper bounds) + * + * or as a conjunction of constraints. + * + * The set of enforced constraints is then computed either based on + * a list of upper bounds or on a set of upper bound constraints. + * We do not compute any enforced constraints if we were forced + * to compute a lower or upper bound using exact_bound. The domains + * of the resulting expressions may imply some bounds on outer dimensions + * that we do not want to appear in the enforced constraints since + * they are not actually enforced by the corresponding code. + * + * Finally, we fill in the expressions of the for node. + */ +static __isl_give isl_ast_graft *refine_generic_bounds( + __isl_take isl_ast_graft *graft, + __isl_take isl_constraint_list *c_lower, + __isl_take isl_constraint_list *c_upper, + __isl_keep isl_set *domain, __isl_keep isl_ast_build *build) +{ + int depth; + isl_ctx *ctx; + isl_pw_aff_list *lower; + int use_list; + isl_set *upper_set = NULL; + isl_pw_aff_list *upper_list = NULL; + int n_lower, n_upper; + + if (!graft || !c_lower || !c_upper || !build) + goto error; + + depth = isl_ast_build_get_depth(build); + ctx = isl_ast_graft_get_ctx(graft); + + n_lower = isl_constraint_list_n_constraint(c_lower); + n_upper = isl_constraint_list_n_constraint(c_upper); + + use_list = use_upper_bound_list(ctx, n_upper, domain, depth); + + lower = lower_bounds(c_lower, depth, domain, build); + + if (use_list) + upper_list = upper_bounds(c_upper, depth, domain, build); + else if (n_upper > 0) + upper_set = intersect_constraints(c_upper); + else + upper_set = isl_set_universe(isl_set_get_space(domain)); + + if (n_lower == 0 || n_upper == 0) + ; + else if (use_list) + graft = set_enforced_from_list(graft, lower, upper_list); + else + graft = set_enforced_from_set(graft, lower, depth, upper_set); + + graft = set_for_node_expressions(graft, lower, use_list, upper_list, + upper_set, build); + + isl_pw_aff_list_free(lower); + isl_pw_aff_list_free(upper_list); + isl_set_free(upper_set); + isl_constraint_list_free(c_lower); + isl_constraint_list_free(c_upper); + + return graft; +error: + isl_constraint_list_free(c_lower); + isl_constraint_list_free(c_upper); + return isl_ast_graft_free(graft); +} + +/* Internal data structure used inside count_constraints to keep + * track of the number of constraints that are independent of dimension "pos", + * the lower bounds in "pos" and the upper bounds in "pos". + */ +struct isl_ast_count_constraints_data { + int pos; + + int n_indep; + int n_lower; + int n_upper; +}; + +/* Increment data->n_indep, data->lower or data->upper depending + * on whether "c" is independenct of dimensions data->pos, + * a lower bound or an upper bound. + */ +static isl_stat count_constraints(__isl_take isl_constraint *c, void *user) +{ + struct isl_ast_count_constraints_data *data = user; + + if (isl_constraint_is_lower_bound(c, isl_dim_set, data->pos)) + data->n_lower++; + else if (isl_constraint_is_upper_bound(c, isl_dim_set, data->pos)) + data->n_upper++; + else + data->n_indep++; + + isl_constraint_free(c); + + return isl_stat_ok; +} + +/* Update "graft" based on "bounds" and "domain" for the generic, + * non-degenerate, case. + * + * "list" respresent the list of bounds that need to be encoded by + * the for loop. Only the constraints that involve the iterator + * are relevant here. The other constraints are taken care of by + * the caller and are included in the generated constraints of "build". + * "domain" is the subset of the intersection of the constraints + * for which some code is executed. + * "build" is the build in which graft->node was created. + * + * We separate lower bounds, upper bounds and constraints that + * are independent of the loop iterator. + * + * The actual for loop bounds are generated in refine_generic_bounds. + */ +static __isl_give isl_ast_graft *refine_generic_split( + __isl_take isl_ast_graft *graft, __isl_take isl_constraint_list *list, + __isl_keep isl_set *domain, __isl_keep isl_ast_build *build) +{ + struct isl_ast_count_constraints_data data; + isl_constraint_list *lower; + isl_constraint_list *upper; + + if (!list) + return isl_ast_graft_free(graft); + + data.pos = isl_ast_build_get_depth(build); + + list = isl_constraint_list_sort(list, &cmp_constraint, &data.pos); + if (!list) + return isl_ast_graft_free(graft); + + data.n_indep = data.n_lower = data.n_upper = 0; + if (isl_constraint_list_foreach(list, &count_constraints, &data) < 0) { + isl_constraint_list_free(list); + return isl_ast_graft_free(graft); + } + + lower = isl_constraint_list_drop(list, 0, data.n_indep); + upper = isl_constraint_list_copy(lower); + lower = isl_constraint_list_drop(lower, data.n_lower, data.n_upper); + upper = isl_constraint_list_drop(upper, 0, data.n_lower); + + return refine_generic_bounds(graft, lower, upper, domain, build); +} + +/* Update "graft" based on "bounds" and "domain" for the generic, + * non-degenerate, case. + * + * "bounds" respresent the bounds that need to be encoded by + * the for loop (or a guard around the for loop). + * "domain" is the subset of "bounds" for which some code is executed. + * "build" is the build in which graft->node was created. + * + * We break up "bounds" into a list of constraints and continue with + * refine_generic_split. + */ +static __isl_give isl_ast_graft *refine_generic( + __isl_take isl_ast_graft *graft, + __isl_keep isl_basic_set *bounds, __isl_keep isl_set *domain, + __isl_keep isl_ast_build *build) +{ + isl_constraint_list *list; + + if (!build || !graft) + return isl_ast_graft_free(graft); + + list = isl_basic_set_get_constraint_list(bounds); + + graft = refine_generic_split(graft, list, domain, build); + + return graft; +} + +/* Create a for node for the current level. + * + * Mark the for node degenerate if "degenerate" is set. + */ +static __isl_give isl_ast_node *create_for(__isl_keep isl_ast_build *build, + int degenerate) +{ + int depth; + isl_id *id; + isl_ast_node *node; + + if (!build) + return NULL; + + depth = isl_ast_build_get_depth(build); + id = isl_ast_build_get_iterator_id(build, depth); + node = isl_ast_node_alloc_for(id); + if (degenerate) + node = isl_ast_node_for_mark_degenerate(node); + + return node; +} + +/* If the ast_build_exploit_nested_bounds option is set, then return + * the constraints enforced by all elements in "list". + * Otherwise, return the universe. + */ +static __isl_give isl_basic_set *extract_shared_enforced( + __isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + isl_space *space; + + if (!list) + return NULL; + + ctx = isl_ast_graft_list_get_ctx(list); + if (isl_options_get_ast_build_exploit_nested_bounds(ctx)) + return isl_ast_graft_list_extract_shared_enforced(list, build); + + space = isl_ast_build_get_space(build, 1); + return isl_basic_set_universe(space); +} + +/* Return the pending constraints of "build" that are not already taken + * care of (by a combination of "enforced" and the generated constraints + * of "build"). + */ +static __isl_give isl_set *extract_pending(__isl_keep isl_ast_build *build, + __isl_keep isl_basic_set *enforced) +{ + isl_set *guard, *context; + + guard = isl_ast_build_get_pending(build); + context = isl_set_from_basic_set(isl_basic_set_copy(enforced)); + context = isl_set_intersect(context, + isl_ast_build_get_generated(build)); + return isl_set_gist(guard, context); +} + +/* Create an AST node for the current dimension based on + * the schedule domain "bounds" and return the node encapsulated + * in an isl_ast_graft. + * + * "executed" is the current inverse schedule, taking into account + * the bounds in "bounds" + * "domain" is the domain of "executed", with inner dimensions projected out. + * It may be a strict subset of "bounds" in case "bounds" was created + * based on the atomic option or based on separation with explicit bounds. + * + * "domain" may satisfy additional equalities that result + * from intersecting "executed" with "bounds" in add_node. + * It may also satisfy some global constraints that were dropped out because + * we performed separation with explicit bounds. + * The very first step is then to copy these constraints to "bounds". + * + * Since we may be calling before_each_for and after_each_for + * callbacks, we record the current inverse schedule in the build. + * + * We consider three builds, + * "build" is the one in which the current level is created, + * "body_build" is the build in which the next level is created, + * "sub_build" is essentially the same as "body_build", except that + * the depth has not been increased yet. + * + * "build" already contains information (in strides and offsets) + * about the strides at the current level, but this information is not + * reflected in the build->domain. + * We first add this information and the "bounds" to the sub_build->domain. + * isl_ast_build_set_loop_bounds adds the stride information and + * checks whether the current dimension attains + * only a single value and whether this single value can be represented using + * a single affine expression. + * In the first case, the current level is considered "degenerate". + * In the second, sub-case, the current level is considered "eliminated". + * Eliminated levels don't need to be reflected in the AST since we can + * simply plug in the affine expression. For degenerate, but non-eliminated, + * levels, we do introduce a for node, but mark is as degenerate so that + * it can be printed as an assignment of the single value to the loop + * "iterator". + * + * If the current level is eliminated, we explicitly plug in the value + * for the current level found by isl_ast_build_set_loop_bounds in the + * inverse schedule. This ensures that if we are working on a slice + * of the domain based on information available in the inverse schedule + * and the build domain, that then this information is also reflected + * in the inverse schedule. This operation also eliminates the current + * dimension from the inverse schedule making sure no inner dimensions depend + * on the current dimension. Otherwise, we create a for node, marking + * it degenerate if appropriate. The initial for node is still incomplete + * and will be completed in either refine_degenerate or refine_generic. + * + * We then generate a sequence of grafts for the next level, + * create a surrounding graft for the current level and insert + * the for node we created (if the current level is not eliminated). + * Before creating a graft for the current level, we first extract + * hoistable constraints from the child guards and combine them + * with the pending constraints in the build. These constraints + * are used to simplify the child guards and then added to the guard + * of the current graft to ensure that they will be generated. + * If the hoisted guard is a disjunction, then we use it directly + * to gist the guards on the children before intersect it with the + * pending constraints. We do so because this disjunction is typically + * identical to the guards on the children such that these guards + * can be effectively removed completely. After the intersection, + * the gist operation would have a harder time figuring this out. + * + * Finally, we set the bounds of the for loop in either + * refine_degenerate or refine_generic. + * We do so in a context where the pending constraints of the build + * have been replaced by the guard of the current graft. + */ +static __isl_give isl_ast_graft *create_node_scaled( + __isl_take isl_union_map *executed, + __isl_take isl_basic_set *bounds, __isl_take isl_set *domain, + __isl_take isl_ast_build *build) +{ + int depth; + int degenerate, eliminated; + isl_basic_set *hull; + isl_basic_set *enforced; + isl_set *guard, *hoisted; + isl_ast_node *node = NULL; + isl_ast_graft *graft; + isl_ast_graft_list *children; + isl_ast_build *sub_build; + isl_ast_build *body_build; + + domain = isl_ast_build_eliminate_divs(build, domain); + domain = isl_set_detect_equalities(domain); + hull = isl_set_unshifted_simple_hull(isl_set_copy(domain)); + bounds = isl_basic_set_intersect(bounds, hull); + build = isl_ast_build_set_executed(build, isl_union_map_copy(executed)); + + depth = isl_ast_build_get_depth(build); + sub_build = isl_ast_build_copy(build); + bounds = isl_basic_set_remove_redundancies(bounds); + bounds = isl_ast_build_specialize_basic_set(sub_build, bounds); + sub_build = isl_ast_build_set_loop_bounds(sub_build, + isl_basic_set_copy(bounds)); + degenerate = isl_ast_build_has_value(sub_build); + eliminated = isl_ast_build_has_affine_value(sub_build, depth); + if (degenerate < 0 || eliminated < 0) + executed = isl_union_map_free(executed); + if (!degenerate) + bounds = isl_ast_build_compute_gist_basic_set(build, bounds); + sub_build = isl_ast_build_set_pending_generated(sub_build, + isl_basic_set_copy(bounds)); + if (eliminated) + executed = plug_in_values(executed, sub_build); + else + node = create_for(build, degenerate); + + body_build = isl_ast_build_copy(sub_build); + body_build = isl_ast_build_increase_depth(body_build); + if (!eliminated) + node = before_each_for(node, body_build); + children = generate_next_level(executed, + isl_ast_build_copy(body_build)); + + enforced = extract_shared_enforced(children, build); + guard = extract_pending(sub_build, enforced); + hoisted = isl_ast_graft_list_extract_hoistable_guard(children, build); + if (isl_set_n_basic_set(hoisted) > 1) + children = isl_ast_graft_list_gist_guards(children, + isl_set_copy(hoisted)); + guard = isl_set_intersect(guard, hoisted); + if (!eliminated) + guard = add_implied_guards(guard, degenerate, bounds, build); + + graft = isl_ast_graft_alloc_from_children(children, + isl_set_copy(guard), enforced, build, sub_build); + + if (!eliminated) { + isl_ast_build *for_build; + + graft = isl_ast_graft_insert_for(graft, node); + for_build = isl_ast_build_copy(build); + for_build = isl_ast_build_replace_pending_by_guard(for_build, + isl_set_copy(guard)); + if (degenerate) + graft = refine_degenerate(graft, for_build, sub_build); + else + graft = refine_generic(graft, bounds, + domain, for_build); + isl_ast_build_free(for_build); + } + isl_set_free(guard); + if (!eliminated) + graft = after_each_for(graft, body_build); + + isl_ast_build_free(body_build); + isl_ast_build_free(sub_build); + isl_ast_build_free(build); + isl_basic_set_free(bounds); + isl_set_free(domain); + + return graft; +} + +/* Internal data structure for checking if all constraints involving + * the input dimension "depth" are such that the other coefficients + * are multiples of "m", reducing "m" if they are not. + * If "m" is reduced all the way down to "1", then the check has failed + * and we break out of the iteration. + */ +struct isl_check_scaled_data { + int depth; + isl_val *m; +}; + +/* If constraint "c" involves the input dimension data->depth, + * then make sure that all the other coefficients are multiples of data->m, + * reducing data->m if needed. + * Break out of the iteration if data->m has become equal to "1". + */ +static isl_stat constraint_check_scaled(__isl_take isl_constraint *c, + void *user) +{ + struct isl_check_scaled_data *data = user; + int i, j, n; + enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_out, + isl_dim_div }; + + if (!isl_constraint_involves_dims(c, isl_dim_in, data->depth, 1)) { + isl_constraint_free(c); + return isl_stat_ok; + } + + for (i = 0; i < 4; ++i) { + n = isl_constraint_dim(c, t[i]); + for (j = 0; j < n; ++j) { + isl_val *d; + + if (t[i] == isl_dim_in && j == data->depth) + continue; + if (!isl_constraint_involves_dims(c, t[i], j, 1)) + continue; + d = isl_constraint_get_coefficient_val(c, t[i], j); + data->m = isl_val_gcd(data->m, d); + if (isl_val_is_one(data->m)) + break; + } + if (j < n) + break; + } + + isl_constraint_free(c); + + return i < 4 ? isl_stat_error : isl_stat_ok; +} + +/* For each constraint of "bmap" that involves the input dimension data->depth, + * make sure that all the other coefficients are multiples of data->m, + * reducing data->m if needed. + * Break out of the iteration if data->m has become equal to "1". + */ +static isl_stat basic_map_check_scaled(__isl_take isl_basic_map *bmap, + void *user) +{ + isl_stat r; + + r = isl_basic_map_foreach_constraint(bmap, + &constraint_check_scaled, user); + isl_basic_map_free(bmap); + + return r; +} + +/* For each constraint of "map" that involves the input dimension data->depth, + * make sure that all the other coefficients are multiples of data->m, + * reducing data->m if needed. + * Break out of the iteration if data->m has become equal to "1". + */ +static isl_stat map_check_scaled(__isl_take isl_map *map, void *user) +{ + isl_stat r; + + r = isl_map_foreach_basic_map(map, &basic_map_check_scaled, user); + isl_map_free(map); + + return r; +} + +/* Create an AST node for the current dimension based on + * the schedule domain "bounds" and return the node encapsulated + * in an isl_ast_graft. + * + * "executed" is the current inverse schedule, taking into account + * the bounds in "bounds" + * "domain" is the domain of "executed", with inner dimensions projected out. + * + * + * Before moving on to the actual AST node construction in create_node_scaled, + * we first check if the current dimension is strided and if we can scale + * down this stride. Note that we only do this if the ast_build_scale_strides + * option is set. + * + * In particular, let the current dimension take on values + * + * f + s a + * + * with a an integer. We check if we can find an integer m that (obviously) + * divides both f and s. + * + * If so, we check if the current dimension only appears in constraints + * where the coefficients of the other variables are multiples of m. + * We perform this extra check to avoid the risk of introducing + * divisions by scaling down the current dimension. + * + * If so, we scale the current dimension down by a factor of m. + * That is, we plug in + * + * i = m i' (1) + * + * Note that in principle we could always scale down strided loops + * by plugging in + * + * i = f + s i' + * + * but this may result in i' taking on larger values than the original i, + * due to the shift by "f". + * By constrast, the scaling in (1) can only reduce the (absolute) value "i". + */ +static __isl_give isl_ast_graft *create_node(__isl_take isl_union_map *executed, + __isl_take isl_basic_set *bounds, __isl_take isl_set *domain, + __isl_take isl_ast_build *build) +{ + struct isl_check_scaled_data data; + isl_ctx *ctx; + isl_aff *offset; + isl_val *d; + + ctx = isl_ast_build_get_ctx(build); + if (!isl_options_get_ast_build_scale_strides(ctx)) + return create_node_scaled(executed, bounds, domain, build); + + data.depth = isl_ast_build_get_depth(build); + if (!isl_ast_build_has_stride(build, data.depth)) + return create_node_scaled(executed, bounds, domain, build); + + offset = isl_ast_build_get_offset(build, data.depth); + data.m = isl_ast_build_get_stride(build, data.depth); + if (!data.m) + offset = isl_aff_free(offset); + offset = isl_aff_scale_down_val(offset, isl_val_copy(data.m)); + d = isl_aff_get_denominator_val(offset); + if (!d) + executed = isl_union_map_free(executed); + + if (executed && isl_val_is_divisible_by(data.m, d)) + data.m = isl_val_div(data.m, d); + else { + data.m = isl_val_set_si(data.m, 1); + isl_val_free(d); + } + + if (!isl_val_is_one(data.m)) { + if (isl_union_map_foreach_map(executed, &map_check_scaled, + &data) < 0 && + !isl_val_is_one(data.m)) + executed = isl_union_map_free(executed); + } + + if (!isl_val_is_one(data.m)) { + isl_space *space; + isl_multi_aff *ma; + isl_aff *aff; + isl_map *map; + isl_union_map *umap; + + space = isl_ast_build_get_space(build, 1); + space = isl_space_map_from_set(space); + ma = isl_multi_aff_identity(space); + aff = isl_multi_aff_get_aff(ma, data.depth); + aff = isl_aff_scale_val(aff, isl_val_copy(data.m)); + ma = isl_multi_aff_set_aff(ma, data.depth, aff); + + bounds = isl_basic_set_preimage_multi_aff(bounds, + isl_multi_aff_copy(ma)); + domain = isl_set_preimage_multi_aff(domain, + isl_multi_aff_copy(ma)); + map = isl_map_reverse(isl_map_from_multi_aff(ma)); + umap = isl_union_map_from_map(map); + executed = isl_union_map_apply_domain(executed, + isl_union_map_copy(umap)); + build = isl_ast_build_scale_down(build, isl_val_copy(data.m), + umap); + } + isl_aff_free(offset); + isl_val_free(data.m); + + return create_node_scaled(executed, bounds, domain, build); +} + +/* Add the basic set to the list that "user" points to. + */ +static isl_stat collect_basic_set(__isl_take isl_basic_set *bset, void *user) +{ + isl_basic_set_list **list = user; + + *list = isl_basic_set_list_add(*list, bset); + + return isl_stat_ok; +} + +/* Extract the basic sets of "set" and collect them in an isl_basic_set_list. + */ +static __isl_give isl_basic_set_list *isl_basic_set_list_from_set( + __isl_take isl_set *set) +{ + int n; + isl_ctx *ctx; + isl_basic_set_list *list; + + if (!set) + return NULL; + + ctx = isl_set_get_ctx(set); + + n = isl_set_n_basic_set(set); + list = isl_basic_set_list_alloc(ctx, n); + if (isl_set_foreach_basic_set(set, &collect_basic_set, &list) < 0) + list = isl_basic_set_list_free(list); + + isl_set_free(set); + return list; +} + +/* Generate code for the schedule domain "bounds" + * and add the result to "list". + * + * We mainly detect strides here and check if the bounds do not + * conflict with the current build domain + * and then pass over control to create_node. + * + * "bounds" reflects the bounds on the current dimension and possibly + * some extra conditions on outer dimensions. + * It does not, however, include any divs involving the current dimension, + * so it does not capture any stride constraints. + * We therefore need to compute that part of the schedule domain that + * intersects with "bounds" and derive the strides from the result. + */ +static __isl_give isl_ast_graft_list *add_node( + __isl_take isl_ast_graft_list *list, __isl_take isl_union_map *executed, + __isl_take isl_basic_set *bounds, __isl_take isl_ast_build *build) +{ + isl_ast_graft *graft; + isl_set *domain = NULL; + isl_union_set *uset; + int empty, disjoint; + + uset = isl_union_set_from_basic_set(isl_basic_set_copy(bounds)); + executed = isl_union_map_intersect_domain(executed, uset); + empty = isl_union_map_is_empty(executed); + if (empty < 0) + goto error; + if (empty) + goto done; + + uset = isl_union_map_domain(isl_union_map_copy(executed)); + domain = isl_set_from_union_set(uset); + domain = isl_ast_build_specialize(build, domain); + + domain = isl_set_compute_divs(domain); + domain = isl_ast_build_eliminate_inner(build, domain); + disjoint = isl_set_is_disjoint(domain, build->domain); + if (disjoint < 0) + goto error; + if (disjoint) + goto done; + + build = isl_ast_build_detect_strides(build, isl_set_copy(domain)); + + graft = create_node(executed, bounds, domain, + isl_ast_build_copy(build)); + list = isl_ast_graft_list_add(list, graft); + isl_ast_build_free(build); + return list; +error: + list = isl_ast_graft_list_free(list); +done: + isl_set_free(domain); + isl_basic_set_free(bounds); + isl_union_map_free(executed); + isl_ast_build_free(build); + return list; +} + +/* Does any element of i follow or coincide with any element of j + * at the current depth for equal values of the outer dimensions? + */ +static isl_bool domain_follows_at_depth(__isl_keep isl_basic_set *i, + __isl_keep isl_basic_set *j, void *user) +{ + int depth = *(int *) user; + isl_basic_map *test; + isl_bool empty; + int l; + + test = isl_basic_map_from_domain_and_range(isl_basic_set_copy(i), + isl_basic_set_copy(j)); + for (l = 0; l < depth; ++l) + test = isl_basic_map_equate(test, isl_dim_in, l, + isl_dim_out, l); + test = isl_basic_map_order_ge(test, isl_dim_in, depth, + isl_dim_out, depth); + empty = isl_basic_map_is_empty(test); + isl_basic_map_free(test); + + return empty < 0 ? isl_bool_error : !empty; +} + +/* Split up each element of "list" into a part that is related to "bset" + * according to "gt" and a part that is not. + * Return a list that consist of "bset" and all the pieces. + */ +static __isl_give isl_basic_set_list *add_split_on( + __isl_take isl_basic_set_list *list, __isl_take isl_basic_set *bset, + __isl_keep isl_basic_map *gt) +{ + int i, n; + isl_basic_set_list *res; + + if (!list) + bset = isl_basic_set_free(bset); + + gt = isl_basic_map_copy(gt); + gt = isl_basic_map_intersect_domain(gt, isl_basic_set_copy(bset)); + n = isl_basic_set_list_n_basic_set(list); + res = isl_basic_set_list_from_basic_set(bset); + for (i = 0; res && i < n; ++i) { + isl_basic_set *bset; + isl_set *set1, *set2; + isl_basic_map *bmap; + int empty; + + bset = isl_basic_set_list_get_basic_set(list, i); + bmap = isl_basic_map_copy(gt); + bmap = isl_basic_map_intersect_range(bmap, bset); + bset = isl_basic_map_range(bmap); + empty = isl_basic_set_is_empty(bset); + if (empty < 0) + res = isl_basic_set_list_free(res); + if (empty) { + isl_basic_set_free(bset); + bset = isl_basic_set_list_get_basic_set(list, i); + res = isl_basic_set_list_add(res, bset); + continue; + } + + res = isl_basic_set_list_add(res, isl_basic_set_copy(bset)); + set1 = isl_set_from_basic_set(bset); + bset = isl_basic_set_list_get_basic_set(list, i); + set2 = isl_set_from_basic_set(bset); + set1 = isl_set_subtract(set2, set1); + set1 = isl_set_make_disjoint(set1); + + res = isl_basic_set_list_concat(res, + isl_basic_set_list_from_set(set1)); + } + isl_basic_map_free(gt); + isl_basic_set_list_free(list); + return res; +} + +static __isl_give isl_ast_graft_list *generate_sorted_domains( + __isl_keep isl_basic_set_list *domain_list, + __isl_keep isl_union_map *executed, + __isl_keep isl_ast_build *build); + +/* Internal data structure for add_nodes. + * + * "executed" and "build" are extra arguments to be passed to add_node. + * "list" collects the results. + */ +struct isl_add_nodes_data { + isl_union_map *executed; + isl_ast_build *build; + + isl_ast_graft_list *list; +}; + +/* Generate code for the schedule domains in "scc" + * and add the results to "list". + * + * The domains in "scc" form a strongly connected component in the ordering. + * If the number of domains in "scc" is larger than 1, then this means + * that we cannot determine a valid ordering for the domains in the component. + * This should be fairly rare because the individual domains + * have been made disjoint first. + * The problem is that the domains may be integrally disjoint but not + * rationally disjoint. For example, we may have domains + * + * { [i,i] : 0 <= i <= 1 } and { [i,1-i] : 0 <= i <= 1 } + * + * These two domains have an empty intersection, but their rational + * relaxations do intersect. It is impossible to order these domains + * in the second dimension because the first should be ordered before + * the second for outer dimension equal to 0, while it should be ordered + * after for outer dimension equal to 1. + * + * This may happen in particular in case of unrolling since the domain + * of each slice is replaced by its simple hull. + * + * For each basic set i in "scc" and for each of the following basic sets j, + * we split off that part of the basic set i that shares the outer dimensions + * with j and lies before j in the current dimension. + * We collect all the pieces in a new list that replaces "scc". + * + * While the elements in "scc" should be disjoint, we double-check + * this property to avoid running into an infinite recursion in case + * they intersect due to some internal error. + */ +static isl_stat add_nodes(__isl_take isl_basic_set_list *scc, void *user) +{ + struct isl_add_nodes_data *data = user; + int i, n, depth; + isl_basic_set *bset, *first; + isl_basic_set_list *list; + isl_space *space; + isl_basic_map *gt; + + n = isl_basic_set_list_n_basic_set(scc); + bset = isl_basic_set_list_get_basic_set(scc, 0); + if (n == 1) { + isl_basic_set_list_free(scc); + data->list = add_node(data->list, + isl_union_map_copy(data->executed), bset, + isl_ast_build_copy(data->build)); + return data->list ? isl_stat_ok : isl_stat_error; + } + + depth = isl_ast_build_get_depth(data->build); + space = isl_basic_set_get_space(bset); + space = isl_space_map_from_set(space); + gt = isl_basic_map_universe(space); + for (i = 0; i < depth; ++i) + gt = isl_basic_map_equate(gt, isl_dim_in, i, isl_dim_out, i); + gt = isl_basic_map_order_gt(gt, isl_dim_in, depth, isl_dim_out, depth); + + first = isl_basic_set_copy(bset); + list = isl_basic_set_list_from_basic_set(bset); + for (i = 1; i < n; ++i) { + int disjoint; + + bset = isl_basic_set_list_get_basic_set(scc, i); + + disjoint = isl_basic_set_is_disjoint(bset, first); + if (disjoint < 0) + list = isl_basic_set_list_free(list); + else if (!disjoint) + isl_die(isl_basic_set_list_get_ctx(scc), + isl_error_internal, + "basic sets in scc are assumed to be disjoint", + list = isl_basic_set_list_free(list)); + + list = add_split_on(list, bset, gt); + } + isl_basic_set_free(first); + isl_basic_map_free(gt); + isl_basic_set_list_free(scc); + scc = list; + data->list = isl_ast_graft_list_concat(data->list, + generate_sorted_domains(scc, data->executed, data->build)); + isl_basic_set_list_free(scc); + + return data->list ? isl_stat_ok : isl_stat_error; +} + +/* Sort the domains in "domain_list" according to the execution order + * at the current depth (for equal values of the outer dimensions), + * generate code for each of them, collecting the results in a list. + * If no code is generated (because the intersection of the inverse schedule + * with the domains turns out to be empty), then an empty list is returned. + * + * The caller is responsible for ensuring that the basic sets in "domain_list" + * are pair-wise disjoint. It can, however, in principle happen that + * two basic sets should be ordered one way for one value of the outer + * dimensions and the other way for some other value of the outer dimensions. + * We therefore play safe and look for strongly connected components. + * The function add_nodes takes care of handling non-trivial components. + */ +static __isl_give isl_ast_graft_list *generate_sorted_domains( + __isl_keep isl_basic_set_list *domain_list, + __isl_keep isl_union_map *executed, __isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + struct isl_add_nodes_data data; + int depth; + int n; + + if (!domain_list) + return NULL; + + ctx = isl_basic_set_list_get_ctx(domain_list); + n = isl_basic_set_list_n_basic_set(domain_list); + data.list = isl_ast_graft_list_alloc(ctx, n); + if (n == 0) + return data.list; + if (n == 1) + return add_node(data.list, isl_union_map_copy(executed), + isl_basic_set_list_get_basic_set(domain_list, 0), + isl_ast_build_copy(build)); + + depth = isl_ast_build_get_depth(build); + data.executed = executed; + data.build = build; + if (isl_basic_set_list_foreach_scc(domain_list, + &domain_follows_at_depth, &depth, + &add_nodes, &data) < 0) + data.list = isl_ast_graft_list_free(data.list); + + return data.list; +} + +/* Do i and j share any values for the outer dimensions? + */ +static isl_bool shared_outer(__isl_keep isl_basic_set *i, + __isl_keep isl_basic_set *j, void *user) +{ + int depth = *(int *) user; + isl_basic_map *test; + isl_bool empty; + int l; + + test = isl_basic_map_from_domain_and_range(isl_basic_set_copy(i), + isl_basic_set_copy(j)); + for (l = 0; l < depth; ++l) + test = isl_basic_map_equate(test, isl_dim_in, l, + isl_dim_out, l); + empty = isl_basic_map_is_empty(test); + isl_basic_map_free(test); + + return empty < 0 ? isl_bool_error : !empty; +} + +/* Internal data structure for generate_sorted_domains_wrap. + * + * "n" is the total number of basic sets + * "executed" and "build" are extra arguments to be passed + * to generate_sorted_domains. + * + * "single" is set to 1 by generate_sorted_domains_wrap if there + * is only a single component. + * "list" collects the results. + */ +struct isl_ast_generate_parallel_domains_data { + int n; + isl_union_map *executed; + isl_ast_build *build; + + int single; + isl_ast_graft_list *list; +}; + +/* Call generate_sorted_domains on "scc", fuse the result into a list + * with either zero or one graft and collect the these single element + * lists into data->list. + * + * If there is only one component, i.e., if the number of basic sets + * in the current component is equal to the total number of basic sets, + * then data->single is set to 1 and the result of generate_sorted_domains + * is not fused. + */ +static isl_stat generate_sorted_domains_wrap(__isl_take isl_basic_set_list *scc, + void *user) +{ + struct isl_ast_generate_parallel_domains_data *data = user; + isl_ast_graft_list *list; + + list = generate_sorted_domains(scc, data->executed, data->build); + data->single = isl_basic_set_list_n_basic_set(scc) == data->n; + if (!data->single) + list = isl_ast_graft_list_fuse(list, data->build); + if (!data->list) + data->list = list; + else + data->list = isl_ast_graft_list_concat(data->list, list); + + isl_basic_set_list_free(scc); + if (!data->list) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Look for any (weakly connected) components in the "domain_list" + * of domains that share some values of the outer dimensions. + * That is, domains in different components do not share any values + * of the outer dimensions. This means that these components + * can be freely reordered. + * Within each of the components, we sort the domains according + * to the execution order at the current depth. + * + * If there is more than one component, then generate_sorted_domains_wrap + * fuses the result of each call to generate_sorted_domains + * into a list with either zero or one graft and collects these (at most) + * single element lists into a bigger list. This means that the elements of the + * final list can be freely reordered. In particular, we sort them + * according to an arbitrary but fixed ordering to ease merging of + * graft lists from different components. + */ +static __isl_give isl_ast_graft_list *generate_parallel_domains( + __isl_keep isl_basic_set_list *domain_list, + __isl_keep isl_union_map *executed, __isl_keep isl_ast_build *build) +{ + int depth; + struct isl_ast_generate_parallel_domains_data data; + + if (!domain_list) + return NULL; + + data.n = isl_basic_set_list_n_basic_set(domain_list); + if (data.n <= 1) + return generate_sorted_domains(domain_list, executed, build); + + depth = isl_ast_build_get_depth(build); + data.list = NULL; + data.executed = executed; + data.build = build; + data.single = 0; + if (isl_basic_set_list_foreach_scc(domain_list, &shared_outer, &depth, + &generate_sorted_domains_wrap, + &data) < 0) + data.list = isl_ast_graft_list_free(data.list); + + if (!data.single) + data.list = isl_ast_graft_list_sort_guard(data.list); + + return data.list; +} + +/* Internal data for separate_domain. + * + * "explicit" is set if we only want to use explicit bounds. + * + * "domain" collects the separated domains. + */ +struct isl_separate_domain_data { + isl_ast_build *build; + int explicit; + isl_set *domain; +}; + +/* Extract implicit bounds on the current dimension for the executed "map". + * + * The domain of "map" may involve inner dimensions, so we + * need to eliminate them. + */ +static __isl_give isl_set *implicit_bounds(__isl_take isl_map *map, + __isl_keep isl_ast_build *build) +{ + isl_set *domain; + + domain = isl_map_domain(map); + domain = isl_ast_build_eliminate(build, domain); + + return domain; +} + +/* Extract explicit bounds on the current dimension for the executed "map". + * + * Rather than eliminating the inner dimensions as in implicit_bounds, + * we simply drop any constraints involving those inner dimensions. + * The idea is that most bounds that are implied by constraints on the + * inner dimensions will be enforced by for loops and not by explicit guards. + * There is then no need to separate along those bounds. + */ +static __isl_give isl_set *explicit_bounds(__isl_take isl_map *map, + __isl_keep isl_ast_build *build) +{ + isl_set *domain; + int depth, dim; + + dim = isl_map_dim(map, isl_dim_out); + map = isl_map_drop_constraints_involving_dims(map, isl_dim_out, 0, dim); + + domain = isl_map_domain(map); + depth = isl_ast_build_get_depth(build); + dim = isl_set_dim(domain, isl_dim_set); + domain = isl_set_detect_equalities(domain); + domain = isl_set_drop_constraints_involving_dims(domain, + isl_dim_set, depth + 1, dim - (depth + 1)); + domain = isl_set_remove_divs_involving_dims(domain, + isl_dim_set, depth, 1); + domain = isl_set_remove_unknown_divs(domain); + + return domain; +} + +/* Split data->domain into pieces that intersect with the range of "map" + * and pieces that do not intersect with the range of "map" + * and then add that part of the range of "map" that does not intersect + * with data->domain. + */ +static isl_stat separate_domain(__isl_take isl_map *map, void *user) +{ + struct isl_separate_domain_data *data = user; + isl_set *domain; + isl_set *d1, *d2; + + if (data->explicit) + domain = explicit_bounds(map, data->build); + else + domain = implicit_bounds(map, data->build); + + domain = isl_set_coalesce(domain); + domain = isl_set_make_disjoint(domain); + d1 = isl_set_subtract(isl_set_copy(domain), isl_set_copy(data->domain)); + d2 = isl_set_subtract(isl_set_copy(data->domain), isl_set_copy(domain)); + data->domain = isl_set_intersect(data->domain, domain); + data->domain = isl_set_union(data->domain, d1); + data->domain = isl_set_union(data->domain, d2); + + return isl_stat_ok; +} + +/* Separate the schedule domains of "executed". + * + * That is, break up the domain of "executed" into basic sets, + * such that for each basic set S, every element in S is associated with + * the same domain spaces. + * + * "space" is the (single) domain space of "executed". + */ +static __isl_give isl_set *separate_schedule_domains( + __isl_take isl_space *space, __isl_take isl_union_map *executed, + __isl_keep isl_ast_build *build) +{ + struct isl_separate_domain_data data = { build }; + isl_ctx *ctx; + + ctx = isl_ast_build_get_ctx(build); + data.explicit = isl_options_get_ast_build_separation_bounds(ctx) == + ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT; + data.domain = isl_set_empty(space); + if (isl_union_map_foreach_map(executed, &separate_domain, &data) < 0) + data.domain = isl_set_free(data.domain); + + isl_union_map_free(executed); + return data.domain; +} + +/* Temporary data used during the search for a lower bound for unrolling. + * + * "build" is the build in which the unrolling will be performed + * "domain" is the original set for which to find a lower bound + * "depth" is the dimension for which to find a lower boudn + * "expansion" is the expansion that needs to be applied to "domain" + * in the unrolling that will be performed + * + * "lower" is the best lower bound found so far. It is NULL if we have not + * found any yet. + * "n" is the corresponding size. If lower is NULL, then the value of n + * is undefined. + * "n_div" is the maximal number of integer divisions in the first + * unrolled iteration (after expansion). It is set to -1 if it hasn't + * been computed yet. + */ +struct isl_find_unroll_data { + isl_ast_build *build; + isl_set *domain; + int depth; + isl_basic_map *expansion; + + isl_aff *lower; + int *n; + int n_div; +}; + +/* Return the constraint + * + * i_"depth" = aff + offset + */ +static __isl_give isl_constraint *at_offset(int depth, __isl_keep isl_aff *aff, + int offset) +{ + aff = isl_aff_copy(aff); + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, depth, -1); + aff = isl_aff_add_constant_si(aff, offset); + return isl_equality_from_aff(aff); +} + +/* Update *user to the number of integer divsions in the first element + * of "ma", if it is larger than the current value. + */ +static isl_stat update_n_div(__isl_take isl_set *set, + __isl_take isl_multi_aff *ma, void *user) +{ + isl_aff *aff; + int *n = user; + int n_div; + + aff = isl_multi_aff_get_aff(ma, 0); + n_div = isl_aff_dim(aff, isl_dim_div); + isl_aff_free(aff); + isl_multi_aff_free(ma); + isl_set_free(set); + + if (n_div > *n) + *n = n_div; + + return aff ? isl_stat_ok : isl_stat_error; +} + +/* Get the number of integer divisions in the expression for the iterator + * value at the first slice in the unrolling based on lower bound "lower", + * taking into account the expansion that needs to be performed on this slice. + */ +static int get_expanded_n_div(struct isl_find_unroll_data *data, + __isl_keep isl_aff *lower) +{ + isl_constraint *c; + isl_set *set; + isl_map *it_map, *expansion; + isl_pw_multi_aff *pma; + int n; + + c = at_offset(data->depth, lower, 0); + set = isl_set_copy(data->domain); + set = isl_set_add_constraint(set, c); + expansion = isl_map_from_basic_map(isl_basic_map_copy(data->expansion)); + set = isl_set_apply(set, expansion); + it_map = isl_ast_build_map_to_iterator(data->build, set); + pma = isl_pw_multi_aff_from_map(it_map); + n = 0; + if (isl_pw_multi_aff_foreach_piece(pma, &update_n_div, &n) < 0) + n = -1; + isl_pw_multi_aff_free(pma); + + return n; +} + +/* Is the lower bound "lower" with corresponding iteration count "n" + * better than the one stored in "data"? + * If there is no upper bound on the iteration count ("n" is infinity) or + * if the count is too large, then we cannot use this lower bound. + * Otherwise, if there was no previous lower bound or + * if the iteration count of the new lower bound is smaller than + * the iteration count of the previous lower bound, then we consider + * the new lower bound to be better. + * If the iteration count is the same, then compare the number + * of integer divisions that would be needed to express + * the iterator value at the first slice in the unrolling + * according to the lower bound. If we end up computing this + * number, then store the lowest value in data->n_div. + */ +static int is_better_lower_bound(struct isl_find_unroll_data *data, + __isl_keep isl_aff *lower, __isl_keep isl_val *n) +{ + int cmp; + int n_div; + + if (!n) + return -1; + if (isl_val_is_infty(n)) + return 0; + if (isl_val_cmp_si(n, INT_MAX) > 0) + return 0; + if (!data->lower) + return 1; + cmp = isl_val_cmp_si(n, *data->n); + if (cmp < 0) + return 1; + if (cmp > 0) + return 0; + if (data->n_div < 0) + data->n_div = get_expanded_n_div(data, data->lower); + if (data->n_div < 0) + return -1; + if (data->n_div == 0) + return 0; + n_div = get_expanded_n_div(data, lower); + if (n_div < 0) + return -1; + if (n_div >= data->n_div) + return 0; + data->n_div = n_div; + + return 1; +} + +/* Check if we can use "c" as a lower bound and if it is better than + * any previously found lower bound. + * + * If "c" does not involve the dimension at the current depth, + * then we cannot use it. + * Otherwise, let "c" be of the form + * + * i >= f(j)/a + * + * We compute the maximal value of + * + * -ceil(f(j)/a)) + i + 1 + * + * over the domain. If there is such a value "n", then we know + * + * -ceil(f(j)/a)) + i + 1 <= n + * + * or + * + * i < ceil(f(j)/a)) + n + * + * meaning that we can use ceil(f(j)/a)) as a lower bound for unrolling. + * We just need to check if we have found any lower bound before and + * if the new lower bound is better (smaller n or fewer integer divisions) + * than the previously found lower bounds. + */ +static isl_stat update_unrolling_lower_bound(struct isl_find_unroll_data *data, + __isl_keep isl_constraint *c) +{ + isl_aff *aff, *lower; + isl_val *max; + int better; + + if (!isl_constraint_is_lower_bound(c, isl_dim_set, data->depth)) + return isl_stat_ok; + + lower = isl_constraint_get_bound(c, isl_dim_set, data->depth); + lower = isl_aff_ceil(lower); + aff = isl_aff_copy(lower); + aff = isl_aff_neg(aff); + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, data->depth, 1); + aff = isl_aff_add_constant_si(aff, 1); + max = isl_set_max_val(data->domain, aff); + isl_aff_free(aff); + + better = is_better_lower_bound(data, lower, max); + if (better < 0 || !better) { + isl_val_free(max); + isl_aff_free(lower); + return better < 0 ? isl_stat_error : isl_stat_ok; + } + + isl_aff_free(data->lower); + data->lower = lower; + *data->n = isl_val_get_num_si(max); + isl_val_free(max); + + return isl_stat_ok; +} + +/* Check if we can use "c" as a lower bound and if it is better than + * any previously found lower bound. + */ +static isl_stat constraint_find_unroll(__isl_take isl_constraint *c, void *user) +{ + struct isl_find_unroll_data *data; + isl_stat r; + + data = (struct isl_find_unroll_data *) user; + r = update_unrolling_lower_bound(data, c); + isl_constraint_free(c); + + return r; +} + +/* Look for a lower bound l(i) on the dimension at "depth" + * and a size n such that "domain" is a subset of + * + * { [i] : l(i) <= i_d < l(i) + n } + * + * where d is "depth" and l(i) depends only on earlier dimensions. + * Furthermore, try and find a lower bound such that n is as small as possible. + * In particular, "n" needs to be finite. + * "build" is the build in which the unrolling will be performed. + * "expansion" is the expansion that needs to be applied to "domain" + * in the unrolling that will be performed. + * + * Inner dimensions have been eliminated from "domain" by the caller. + * + * We first construct a collection of lower bounds on the input set + * by computing its simple hull. We then iterate through them, + * discarding those that we cannot use (either because they do not + * involve the dimension at "depth" or because they have no corresponding + * upper bound, meaning that "n" would be unbounded) and pick out the + * best from the remaining ones. + * + * If we cannot find a suitable lower bound, then we consider that + * to be an error. + */ +static __isl_give isl_aff *find_unroll_lower_bound( + __isl_keep isl_ast_build *build, __isl_keep isl_set *domain, + int depth, __isl_keep isl_basic_map *expansion, int *n) +{ + struct isl_find_unroll_data data = + { build, domain, depth, expansion, NULL, n, -1 }; + isl_basic_set *hull; + + hull = isl_set_simple_hull(isl_set_copy(domain)); + + if (isl_basic_set_foreach_constraint(hull, + &constraint_find_unroll, &data) < 0) + goto error; + + isl_basic_set_free(hull); + + if (!data.lower) + isl_die(isl_set_get_ctx(domain), isl_error_invalid, + "cannot find lower bound for unrolling", return NULL); + + return data.lower; +error: + isl_basic_set_free(hull); + return isl_aff_free(data.lower); +} + +/* Call "fn" on each iteration of the current dimension of "domain". + * If "init" is not NULL, then it is called with the number of + * iterations before any call to "fn". + * Return -1 on failure. + * + * Since we are going to be iterating over the individual values, + * we first check if there are any strides on the current dimension. + * If there is, we rewrite the current dimension i as + * + * i = stride i' + offset + * + * and then iterate over individual values of i' instead. + * + * We then look for a lower bound on i' and a size such that the domain + * is a subset of + * + * { [j,i'] : l(j) <= i' < l(j) + n } + * + * and then take slices of the domain at values of i' + * between l(j) and l(j) + n - 1. + * + * We compute the unshifted simple hull of each slice to ensure that + * we have a single basic set per offset. The slicing constraint + * may get simplified away before the unshifted simple hull is taken + * and may therefore in some rare cases disappear from the result. + * We therefore explicitly add the constraint back after computing + * the unshifted simple hull to ensure that the basic sets + * remain disjoint. The constraints that are dropped by taking the hull + * will be taken into account at the next level, as in the case of the + * atomic option. + * + * Finally, we map i' back to i and call "fn". + */ +static int foreach_iteration(__isl_take isl_set *domain, + __isl_keep isl_ast_build *build, int (*init)(int n, void *user), + int (*fn)(__isl_take isl_basic_set *bset, void *user), void *user) +{ + int i, n; + int empty; + int depth; + isl_multi_aff *expansion; + isl_basic_map *bmap; + isl_aff *lower = NULL; + isl_ast_build *stride_build; + + depth = isl_ast_build_get_depth(build); + + domain = isl_ast_build_eliminate_inner(build, domain); + domain = isl_set_intersect(domain, isl_ast_build_get_domain(build)); + stride_build = isl_ast_build_copy(build); + stride_build = isl_ast_build_detect_strides(stride_build, + isl_set_copy(domain)); + expansion = isl_ast_build_get_stride_expansion(stride_build); + + domain = isl_set_preimage_multi_aff(domain, + isl_multi_aff_copy(expansion)); + domain = isl_ast_build_eliminate_divs(stride_build, domain); + isl_ast_build_free(stride_build); + + bmap = isl_basic_map_from_multi_aff(expansion); + + empty = isl_set_is_empty(domain); + if (empty < 0) { + n = -1; + } else if (empty) { + n = 0; + } else { + lower = find_unroll_lower_bound(build, domain, depth, bmap, &n); + if (!lower) + n = -1; + } + if (n >= 0 && init && init(n, user) < 0) + n = -1; + for (i = 0; i < n; ++i) { + isl_set *set; + isl_basic_set *bset; + isl_constraint *slice; + + slice = at_offset(depth, lower, i); + set = isl_set_copy(domain); + set = isl_set_add_constraint(set, isl_constraint_copy(slice)); + bset = isl_set_unshifted_simple_hull(set); + bset = isl_basic_set_add_constraint(bset, slice); + bset = isl_basic_set_apply(bset, isl_basic_map_copy(bmap)); + + if (fn(bset, user) < 0) + break; + } + + isl_aff_free(lower); + isl_set_free(domain); + isl_basic_map_free(bmap); + + return n < 0 || i < n ? -1 : 0; +} + +/* Data structure for storing the results and the intermediate objects + * of compute_domains. + * + * "list" is the main result of the function and contains a list + * of disjoint basic sets for which code should be generated. + * + * "executed" and "build" are inputs to compute_domains. + * "schedule_domain" is the domain of "executed". + * + * "option" constains the domains at the current depth that should by + * atomic, separated or unrolled. These domains are as specified by + * the user, except that inner dimensions have been eliminated and + * that they have been made pair-wise disjoint. + * + * "sep_class" contains the user-specified split into separation classes + * specialized to the current depth. + * "done" contains the union of the separation domains that have already + * been handled. + */ +struct isl_codegen_domains { + isl_basic_set_list *list; + + isl_union_map *executed; + isl_ast_build *build; + isl_set *schedule_domain; + + isl_set *option[4]; + + isl_map *sep_class; + isl_set *done; +}; + +/* Internal data structure for do_unroll. + * + * "domains" stores the results of compute_domains. + * "class_domain" is the original class domain passed to do_unroll. + * "unroll_domain" collects the unrolled iterations. + */ +struct isl_ast_unroll_data { + struct isl_codegen_domains *domains; + isl_set *class_domain; + isl_set *unroll_domain; +}; + +/* Given an iteration of an unrolled domain represented by "bset", + * add it to data->domains->list. + * Since we may have dropped some constraints, we intersect with + * the class domain again to ensure that each element in the list + * is disjoint from the other class domains. + */ +static int do_unroll_iteration(__isl_take isl_basic_set *bset, void *user) +{ + struct isl_ast_unroll_data *data = user; + isl_set *set; + isl_basic_set_list *list; + + set = isl_set_from_basic_set(bset); + data->unroll_domain = isl_set_union(data->unroll_domain, + isl_set_copy(set)); + set = isl_set_intersect(set, isl_set_copy(data->class_domain)); + set = isl_set_make_disjoint(set); + list = isl_basic_set_list_from_set(set); + data->domains->list = isl_basic_set_list_concat(data->domains->list, + list); + + return 0; +} + +/* Extend domains->list with a list of basic sets, one for each value + * of the current dimension in "domain" and remove the corresponding + * sets from the class domain. Return the updated class domain. + * The divs that involve the current dimension have not been projected out + * from this domain. + * + * We call foreach_iteration to iterate over the individual values and + * in do_unroll_iteration we collect the individual basic sets in + * domains->list and their union in data->unroll_domain, which is then + * used to update the class domain. + */ +static __isl_give isl_set *do_unroll(struct isl_codegen_domains *domains, + __isl_take isl_set *domain, __isl_take isl_set *class_domain) +{ + struct isl_ast_unroll_data data; + + if (!domain) + return isl_set_free(class_domain); + if (!class_domain) + return isl_set_free(domain); + + data.domains = domains; + data.class_domain = class_domain; + data.unroll_domain = isl_set_empty(isl_set_get_space(domain)); + + if (foreach_iteration(domain, domains->build, NULL, + &do_unroll_iteration, &data) < 0) + data.unroll_domain = isl_set_free(data.unroll_domain); + + class_domain = isl_set_subtract(class_domain, data.unroll_domain); + + return class_domain; +} + +/* Add domains to domains->list for each individual value of the current + * dimension, for that part of the schedule domain that lies in the + * intersection of the option domain and the class domain. + * Remove the corresponding sets from the class domain and + * return the updated class domain. + * + * We first break up the unroll option domain into individual pieces + * and then handle each of them separately. The unroll option domain + * has been made disjoint in compute_domains_init_options, + * + * Note that we actively want to combine different pieces of the + * schedule domain that have the same value at the current dimension. + * We therefore need to break up the unroll option domain before + * intersecting with class and schedule domain, hoping that the + * unroll option domain specified by the user is relatively simple. + */ +static __isl_give isl_set *compute_unroll_domains( + struct isl_codegen_domains *domains, __isl_take isl_set *class_domain) +{ + isl_set *unroll_domain; + isl_basic_set_list *unroll_list; + int i, n; + int empty; + + empty = isl_set_is_empty(domains->option[isl_ast_loop_unroll]); + if (empty < 0) + return isl_set_free(class_domain); + if (empty) + return class_domain; + + unroll_domain = isl_set_copy(domains->option[isl_ast_loop_unroll]); + unroll_list = isl_basic_set_list_from_set(unroll_domain); + + n = isl_basic_set_list_n_basic_set(unroll_list); + for (i = 0; i < n; ++i) { + isl_basic_set *bset; + + bset = isl_basic_set_list_get_basic_set(unroll_list, i); + unroll_domain = isl_set_from_basic_set(bset); + unroll_domain = isl_set_intersect(unroll_domain, + isl_set_copy(class_domain)); + unroll_domain = isl_set_intersect(unroll_domain, + isl_set_copy(domains->schedule_domain)); + + empty = isl_set_is_empty(unroll_domain); + if (empty >= 0 && empty) { + isl_set_free(unroll_domain); + continue; + } + + class_domain = do_unroll(domains, unroll_domain, class_domain); + } + + isl_basic_set_list_free(unroll_list); + + return class_domain; +} + +/* Try and construct a single basic set that includes the intersection of + * the schedule domain, the atomic option domain and the class domain. + * Add the resulting basic set(s) to domains->list and remove them + * from class_domain. Return the updated class domain. + * + * We construct a single domain rather than trying to combine + * the schedule domains of individual domains because we are working + * within a single component so that non-overlapping schedule domains + * should already have been separated. + * We do however need to make sure that this single domains is a subset + * of the class domain so that it would not intersect with any other + * class domains. This means that we may end up splitting up the atomic + * domain in case separation classes are being used. + * + * "domain" is the intersection of the schedule domain and the class domain, + * with inner dimensions projected out. + */ +static __isl_give isl_set *compute_atomic_domain( + struct isl_codegen_domains *domains, __isl_take isl_set *class_domain) +{ + isl_basic_set *bset; + isl_basic_set_list *list; + isl_set *domain, *atomic_domain; + int empty; + + domain = isl_set_copy(domains->option[isl_ast_loop_atomic]); + domain = isl_set_intersect(domain, isl_set_copy(class_domain)); + domain = isl_set_intersect(domain, + isl_set_copy(domains->schedule_domain)); + empty = isl_set_is_empty(domain); + if (empty < 0) + class_domain = isl_set_free(class_domain); + if (empty) { + isl_set_free(domain); + return class_domain; + } + + domain = isl_ast_build_eliminate(domains->build, domain); + domain = isl_set_coalesce(domain); + bset = isl_set_unshifted_simple_hull(domain); + domain = isl_set_from_basic_set(bset); + atomic_domain = isl_set_copy(domain); + domain = isl_set_intersect(domain, isl_set_copy(class_domain)); + class_domain = isl_set_subtract(class_domain, atomic_domain); + domain = isl_set_make_disjoint(domain); + list = isl_basic_set_list_from_set(domain); + domains->list = isl_basic_set_list_concat(domains->list, list); + + return class_domain; +} + +/* Split up the schedule domain into uniform basic sets, + * in the sense that each element in a basic set is associated to + * elements of the same domains, and add the result to domains->list. + * Do this for that part of the schedule domain that lies in the + * intersection of "class_domain" and the separate option domain. + * + * "class_domain" may or may not include the constraints + * of the schedule domain, but this does not make a difference + * since we are going to intersect it with the domain of the inverse schedule. + * If it includes schedule domain constraints, then they may involve + * inner dimensions, but we will eliminate them in separation_domain. + */ +static int compute_separate_domain(struct isl_codegen_domains *domains, + __isl_keep isl_set *class_domain) +{ + isl_space *space; + isl_set *domain; + isl_union_map *executed; + isl_basic_set_list *list; + int empty; + + domain = isl_set_copy(domains->option[isl_ast_loop_separate]); + domain = isl_set_intersect(domain, isl_set_copy(class_domain)); + executed = isl_union_map_copy(domains->executed); + executed = isl_union_map_intersect_domain(executed, + isl_union_set_from_set(domain)); + empty = isl_union_map_is_empty(executed); + if (empty < 0 || empty) { + isl_union_map_free(executed); + return empty < 0 ? -1 : 0; + } + + space = isl_set_get_space(class_domain); + domain = separate_schedule_domains(space, executed, domains->build); + + list = isl_basic_set_list_from_set(domain); + domains->list = isl_basic_set_list_concat(domains->list, list); + + return 0; +} + +/* Split up the domain at the current depth into disjoint + * basic sets for which code should be generated separately + * for the given separation class domain. + * + * If any separation classes have been defined, then "class_domain" + * is the domain of the current class and does not refer to inner dimensions. + * Otherwise, "class_domain" is the universe domain. + * + * We first make sure that the class domain is disjoint from + * previously considered class domains. + * + * The separate domains can be computed directly from the "class_domain". + * + * The unroll, atomic and remainder domains need the constraints + * from the schedule domain. + * + * For unrolling, the actual schedule domain is needed (with divs that + * may refer to the current dimension) so that stride detection can be + * performed. + * + * For atomic and remainder domains, inner dimensions and divs involving + * the current dimensions should be eliminated. + * In case we are working within a separation class, we need to intersect + * the result with the current "class_domain" to ensure that the domains + * are disjoint from those generated from other class domains. + * + * The domain that has been made atomic may be larger than specified + * by the user since it needs to be representable as a single basic set. + * This possibly larger domain is removed from class_domain by + * compute_atomic_domain. It is computed first so that the extended domain + * would not overlap with any domains computed before. + * Similary, the unrolled domains may have some constraints removed and + * may therefore also be larger than specified by the user. + * + * If anything is left after handling separate, unroll and atomic, + * we split it up into basic sets and append the basic sets to domains->list. + */ +static isl_stat compute_partial_domains(struct isl_codegen_domains *domains, + __isl_take isl_set *class_domain) +{ + isl_basic_set_list *list; + isl_set *domain; + + class_domain = isl_set_subtract(class_domain, + isl_set_copy(domains->done)); + domains->done = isl_set_union(domains->done, + isl_set_copy(class_domain)); + + class_domain = compute_atomic_domain(domains, class_domain); + class_domain = compute_unroll_domains(domains, class_domain); + + domain = isl_set_copy(class_domain); + + if (compute_separate_domain(domains, domain) < 0) + goto error; + domain = isl_set_subtract(domain, + isl_set_copy(domains->option[isl_ast_loop_separate])); + + domain = isl_set_intersect(domain, + isl_set_copy(domains->schedule_domain)); + + domain = isl_ast_build_eliminate(domains->build, domain); + domain = isl_set_intersect(domain, isl_set_copy(class_domain)); + + domain = isl_set_coalesce(domain); + domain = isl_set_make_disjoint(domain); + + list = isl_basic_set_list_from_set(domain); + domains->list = isl_basic_set_list_concat(domains->list, list); + + isl_set_free(class_domain); + + return isl_stat_ok; +error: + isl_set_free(domain); + isl_set_free(class_domain); + return isl_stat_error; +} + +/* Split up the domain at the current depth into disjoint + * basic sets for which code should be generated separately + * for the separation class identified by "pnt". + * + * We extract the corresponding class domain from domains->sep_class, + * eliminate inner dimensions and pass control to compute_partial_domains. + */ +static isl_stat compute_class_domains(__isl_take isl_point *pnt, void *user) +{ + struct isl_codegen_domains *domains = user; + isl_set *class_set; + isl_set *domain; + int disjoint; + + class_set = isl_set_from_point(pnt); + domain = isl_map_domain(isl_map_intersect_range( + isl_map_copy(domains->sep_class), class_set)); + domain = isl_ast_build_compute_gist(domains->build, domain); + domain = isl_ast_build_eliminate(domains->build, domain); + + disjoint = isl_set_plain_is_disjoint(domain, domains->schedule_domain); + if (disjoint < 0) + return isl_stat_error; + if (disjoint) { + isl_set_free(domain); + return isl_stat_ok; + } + + return compute_partial_domains(domains, domain); +} + +/* Extract the domains at the current depth that should be atomic, + * separated or unrolled and store them in option. + * + * The domains specified by the user might overlap, so we make + * them disjoint by subtracting earlier domains from later domains. + */ +static void compute_domains_init_options(isl_set *option[4], + __isl_keep isl_ast_build *build) +{ + enum isl_ast_loop_type type, type2; + isl_set *unroll; + + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + option[type] = isl_ast_build_get_option_domain(build, type); + for (type2 = isl_ast_loop_atomic; type2 < type; ++type2) + option[type] = isl_set_subtract(option[type], + isl_set_copy(option[type2])); + } + + unroll = option[isl_ast_loop_unroll]; + unroll = isl_set_coalesce(unroll); + unroll = isl_set_make_disjoint(unroll); + option[isl_ast_loop_unroll] = unroll; +} + +/* Split up the domain at the current depth into disjoint + * basic sets for which code should be generated separately, + * based on the user-specified options. + * Return the list of disjoint basic sets. + * + * There are three kinds of domains that we need to keep track of. + * - the "schedule domain" is the domain of "executed" + * - the "class domain" is the domain corresponding to the currrent + * separation class + * - the "option domain" is the domain corresponding to one of the options + * atomic, unroll or separate + * + * We first consider the individial values of the separation classes + * and split up the domain for each of them separately. + * Finally, we consider the remainder. If no separation classes were + * specified, then we call compute_partial_domains with the universe + * "class_domain". Otherwise, we take the "schedule_domain" as "class_domain", + * with inner dimensions removed. We do this because we want to + * avoid computing the complement of the class domains (i.e., the difference + * between the universe and domains->done). + */ +static __isl_give isl_basic_set_list *compute_domains( + __isl_keep isl_union_map *executed, __isl_keep isl_ast_build *build) +{ + struct isl_codegen_domains domains; + isl_ctx *ctx; + isl_set *domain; + isl_union_set *schedule_domain; + isl_set *classes; + isl_space *space; + int n_param; + enum isl_ast_loop_type type; + int empty; + + if (!executed) + return NULL; + + ctx = isl_union_map_get_ctx(executed); + domains.list = isl_basic_set_list_alloc(ctx, 0); + + schedule_domain = isl_union_map_domain(isl_union_map_copy(executed)); + domain = isl_set_from_union_set(schedule_domain); + + compute_domains_init_options(domains.option, build); + + domains.sep_class = isl_ast_build_get_separation_class(build); + classes = isl_map_range(isl_map_copy(domains.sep_class)); + n_param = isl_set_dim(classes, isl_dim_param); + classes = isl_set_project_out(classes, isl_dim_param, 0, n_param); + + space = isl_set_get_space(domain); + domains.build = build; + domains.schedule_domain = isl_set_copy(domain); + domains.executed = executed; + domains.done = isl_set_empty(space); + + if (isl_set_foreach_point(classes, &compute_class_domains, &domains) < 0) + domains.list = isl_basic_set_list_free(domains.list); + isl_set_free(classes); + + empty = isl_set_is_empty(domains.done); + if (empty < 0) { + domains.list = isl_basic_set_list_free(domains.list); + domain = isl_set_free(domain); + } else if (empty) { + isl_set_free(domain); + domain = isl_set_universe(isl_set_get_space(domains.done)); + } else { + domain = isl_ast_build_eliminate(build, domain); + } + if (compute_partial_domains(&domains, domain) < 0) + domains.list = isl_basic_set_list_free(domains.list); + + isl_set_free(domains.schedule_domain); + isl_set_free(domains.done); + isl_map_free(domains.sep_class); + for (type = isl_ast_loop_atomic; type <= isl_ast_loop_separate; ++type) + isl_set_free(domains.option[type]); + + return domains.list; +} + +/* Generate code for a single component, after shifting (if any) + * has been applied, in case the schedule was specified as a union map. + * + * We first split up the domain at the current depth into disjoint + * basic sets based on the user-specified options. + * Then we generated code for each of them and concatenate the results. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_flat( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) +{ + isl_basic_set_list *domain_list; + isl_ast_graft_list *list = NULL; + + domain_list = compute_domains(executed, build); + list = generate_parallel_domains(domain_list, executed, build); + + isl_basic_set_list_free(domain_list); + isl_union_map_free(executed); + isl_ast_build_free(build); + + return list; +} + +/* Generate code for a single component, after shifting (if any) + * has been applied, in case the schedule was specified as a schedule tree + * and the separate option was specified. + * + * We perform separation on the domain of "executed" and then generate + * an AST for each of the resulting disjoint basic sets. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_tree_separate( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) +{ + isl_space *space; + isl_set *domain; + isl_basic_set_list *domain_list; + isl_ast_graft_list *list; + + space = isl_ast_build_get_space(build, 1); + domain = separate_schedule_domains(space, + isl_union_map_copy(executed), build); + domain_list = isl_basic_set_list_from_set(domain); + + list = generate_parallel_domains(domain_list, executed, build); + + isl_basic_set_list_free(domain_list); + isl_union_map_free(executed); + isl_ast_build_free(build); + + return list; +} + +/* Internal data structure for generate_shifted_component_tree_unroll. + * + * "executed" and "build" are inputs to generate_shifted_component_tree_unroll. + * "list" collects the constructs grafts. + */ +struct isl_ast_unroll_tree_data { + isl_union_map *executed; + isl_ast_build *build; + isl_ast_graft_list *list; +}; + +/* Initialize data->list to a list of "n" elements. + */ +static int init_unroll_tree(int n, void *user) +{ + struct isl_ast_unroll_tree_data *data = user; + isl_ctx *ctx; + + ctx = isl_ast_build_get_ctx(data->build); + data->list = isl_ast_graft_list_alloc(ctx, n); + + return 0; +} + +/* Given an iteration of an unrolled domain represented by "bset", + * generate the corresponding AST and add the result to data->list. + */ +static int do_unroll_tree_iteration(__isl_take isl_basic_set *bset, void *user) +{ + struct isl_ast_unroll_tree_data *data = user; + + data->list = add_node(data->list, isl_union_map_copy(data->executed), + bset, isl_ast_build_copy(data->build)); + + return 0; +} + +/* Generate code for a single component, after shifting (if any) + * has been applied, in case the schedule was specified as a schedule tree + * and the unroll option was specified. + * + * We call foreach_iteration to iterate over the individual values and + * construct and collect the corresponding grafts in do_unroll_tree_iteration. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_tree_unroll( + __isl_take isl_union_map *executed, __isl_take isl_set *domain, + __isl_take isl_ast_build *build) +{ + struct isl_ast_unroll_tree_data data = { executed, build, NULL }; + + if (foreach_iteration(domain, build, &init_unroll_tree, + &do_unroll_tree_iteration, &data) < 0) + data.list = isl_ast_graft_list_free(data.list); + + isl_union_map_free(executed); + isl_ast_build_free(build); + + return data.list; +} + +/* Does "domain" involve a disjunction that is purely based on + * constraints involving only outer dimension? + * + * In particular, is there a disjunction such that the constraints + * involving the current and later dimensions are the same over + * all the disjuncts? + */ +static isl_bool has_pure_outer_disjunction(__isl_keep isl_set *domain, + __isl_keep isl_ast_build *build) +{ + isl_basic_set *hull; + isl_set *shared, *inner; + isl_bool equal; + int depth, dim; + + if (isl_set_n_basic_set(domain) <= 1) + return isl_bool_false; + + inner = isl_set_copy(domain); + depth = isl_ast_build_get_depth(build); + dim = isl_set_dim(inner, isl_dim_set); + inner = isl_set_drop_constraints_not_involving_dims(inner, + isl_dim_set, depth, dim - depth); + hull = isl_set_plain_unshifted_simple_hull(isl_set_copy(inner)); + shared = isl_set_from_basic_set(hull); + equal = isl_set_plain_is_equal(inner, shared); + isl_set_free(inner); + isl_set_free(shared); + + return equal; +} + +/* Generate code for a single component, after shifting (if any) + * has been applied, in case the schedule was specified as a schedule tree. + * In particular, handle the base case where there is either no isolated + * set or we are within the isolated set (in which case "isolated" is set) + * or the iterations that precede or follow the isolated set. + * + * The schedule domain is broken up or combined into basic sets + * according to the AST generation option specified in the current + * schedule node, which may be either atomic, separate, unroll or + * unspecified. If the option is unspecified, then we currently simply + * split the schedule domain into disjoint basic sets. + * + * In case the separate option is specified, the AST generation is + * handled by generate_shifted_component_tree_separate. + * In the other cases, we need the global schedule domain. + * In the unroll case, the AST generation is then handled by + * generate_shifted_component_tree_unroll which needs the actual + * schedule domain (with divs that may refer to the current dimension) + * so that stride detection can be performed. + * In the atomic or unspecified case, inner dimensions and divs involving + * the current dimensions should be eliminated. + * The result is then either combined into a single basic set or + * split up into disjoint basic sets. + * Finally an AST is generated for each basic set and the results are + * concatenated. + * + * If the schedule domain involves a disjunction that is purely based on + * constraints involving only outer dimension, then it is treated as + * if atomic was specified. This ensures that only a single loop + * is generated instead of a sequence of identical loops with + * different guards. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_tree_base( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build, + int isolated) +{ + isl_bool outer_disjunction; + isl_union_set *schedule_domain; + isl_set *domain; + isl_basic_set_list *domain_list; + isl_ast_graft_list *list; + enum isl_ast_loop_type type; + + type = isl_ast_build_get_loop_type(build, isolated); + if (type < 0) + goto error; + + if (type == isl_ast_loop_separate) + return generate_shifted_component_tree_separate(executed, + build); + + schedule_domain = isl_union_map_domain(isl_union_map_copy(executed)); + domain = isl_set_from_union_set(schedule_domain); + + if (type == isl_ast_loop_unroll) + return generate_shifted_component_tree_unroll(executed, domain, + build); + + domain = isl_ast_build_eliminate(build, domain); + domain = isl_set_coalesce(domain); + + outer_disjunction = has_pure_outer_disjunction(domain, build); + if (outer_disjunction < 0) + domain = isl_set_free(domain); + + if (outer_disjunction || type == isl_ast_loop_atomic) { + isl_basic_set *hull; + hull = isl_set_unshifted_simple_hull(domain); + domain_list = isl_basic_set_list_from_basic_set(hull); + } else { + domain = isl_set_make_disjoint(domain); + domain_list = isl_basic_set_list_from_set(domain); + } + + list = generate_parallel_domains(domain_list, executed, build); + + isl_basic_set_list_free(domain_list); + isl_union_map_free(executed); + isl_ast_build_free(build); + + return list; +error: + isl_union_map_free(executed); + isl_ast_build_free(build); + return NULL; +} + +/* Extract out the disjunction imposed by "domain" on the outer + * schedule dimensions. + * + * In particular, remove all inner dimensions from "domain" (including + * the current dimension) and then remove the constraints that are shared + * by all disjuncts in the result. + */ +static __isl_give isl_set *extract_disjunction(__isl_take isl_set *domain, + __isl_keep isl_ast_build *build) +{ + isl_set *hull; + int depth, dim; + + domain = isl_ast_build_specialize(build, domain); + depth = isl_ast_build_get_depth(build); + dim = isl_set_dim(domain, isl_dim_set); + domain = isl_set_eliminate(domain, isl_dim_set, depth, dim - depth); + domain = isl_set_remove_unknown_divs(domain); + hull = isl_set_copy(domain); + hull = isl_set_from_basic_set(isl_set_unshifted_simple_hull(hull)); + domain = isl_set_gist(domain, hull); + + return domain; +} + +/* Add "guard" to the grafts in "list". + * "build" is the outer AST build, while "sub_build" includes "guard" + * in its generated domain. + * + * First combine the grafts into a single graft and then add the guard. + * If the list is empty, or if some error occurred, then simply return + * the list. + */ +static __isl_give isl_ast_graft_list *list_add_guard( + __isl_take isl_ast_graft_list *list, __isl_keep isl_set *guard, + __isl_keep isl_ast_build *build, __isl_keep isl_ast_build *sub_build) +{ + isl_ast_graft *graft; + + list = isl_ast_graft_list_fuse(list, sub_build); + + if (isl_ast_graft_list_n_ast_graft(list) != 1) + return list; + + graft = isl_ast_graft_list_get_ast_graft(list, 0); + graft = isl_ast_graft_add_guard(graft, isl_set_copy(guard), build); + list = isl_ast_graft_list_set_ast_graft(list, 0, graft); + + return list; +} + +/* Generate code for a single component, after shifting (if any) + * has been applied, in case the schedule was specified as a schedule tree. + * In particular, do so for the specified subset of the schedule domain. + * + * If we are outside of the isolated part, then "domain" may include + * a disjunction. Explicitly generate this disjunction at this point + * instead of relying on the disjunction getting hoisted back up + * to this level. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_tree_part( + __isl_keep isl_union_map *executed, __isl_take isl_set *domain, + __isl_keep isl_ast_build *build, int isolated) +{ + isl_union_set *uset; + isl_ast_graft_list *list; + isl_ast_build *sub_build; + int empty; + + uset = isl_union_set_from_set(isl_set_copy(domain)); + executed = isl_union_map_copy(executed); + executed = isl_union_map_intersect_domain(executed, uset); + empty = isl_union_map_is_empty(executed); + if (empty < 0) + goto error; + if (empty) { + isl_ctx *ctx; + isl_union_map_free(executed); + isl_set_free(domain); + ctx = isl_ast_build_get_ctx(build); + return isl_ast_graft_list_alloc(ctx, 0); + } + + sub_build = isl_ast_build_copy(build); + if (!isolated) { + domain = extract_disjunction(domain, build); + sub_build = isl_ast_build_restrict_generated(sub_build, + isl_set_copy(domain)); + } + list = generate_shifted_component_tree_base(executed, + isl_ast_build_copy(sub_build), isolated); + if (!isolated) + list = list_add_guard(list, domain, build, sub_build); + isl_ast_build_free(sub_build); + isl_set_free(domain); + return list; +error: + isl_union_map_free(executed); + isl_set_free(domain); + return NULL; +} + +/* Generate code for a single component, after shifting (if any) + * has been applied, in case the schedule was specified as a schedule tree. + * In particular, do so for the specified sequence of subsets + * of the schedule domain, "before", "isolated", "after" and "other", + * where only the "isolated" part is considered to be isolated. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_parts( + __isl_take isl_union_map *executed, __isl_take isl_set *before, + __isl_take isl_set *isolated, __isl_take isl_set *after, + __isl_take isl_set *other, __isl_take isl_ast_build *build) +{ + isl_ast_graft_list *list, *res; + + res = generate_shifted_component_tree_part(executed, before, build, 0); + list = generate_shifted_component_tree_part(executed, isolated, + build, 1); + res = isl_ast_graft_list_concat(res, list); + list = generate_shifted_component_tree_part(executed, after, build, 0); + res = isl_ast_graft_list_concat(res, list); + list = generate_shifted_component_tree_part(executed, other, build, 0); + res = isl_ast_graft_list_concat(res, list); + + isl_union_map_free(executed); + isl_ast_build_free(build); + + return res; +} + +/* Does "set" intersect "first", but not "second"? + */ +static isl_bool only_intersects_first(__isl_keep isl_set *set, + __isl_keep isl_set *first, __isl_keep isl_set *second) +{ + isl_bool disjoint; + + disjoint = isl_set_is_disjoint(set, first); + if (disjoint < 0) + return isl_bool_error; + if (disjoint) + return isl_bool_false; + + return isl_set_is_disjoint(set, second); +} + +/* Generate code for a single component, after shifting (if any) + * has been applied, in case the schedule was specified as a schedule tree. + * In particular, do so in case of isolation where there is + * only an "isolated" part and an "after" part. + * "dead1" and "dead2" are freed by this function in order to simplify + * the caller. + * + * The "before" and "other" parts are set to empty sets. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_only_after( + __isl_take isl_union_map *executed, __isl_take isl_set *isolated, + __isl_take isl_set *after, __isl_take isl_ast_build *build, + __isl_take isl_set *dead1, __isl_take isl_set *dead2) +{ + isl_set *empty; + + empty = isl_set_empty(isl_set_get_space(after)); + isl_set_free(dead1); + isl_set_free(dead2); + return generate_shifted_component_parts(executed, isl_set_copy(empty), + isolated, after, empty, build); +} + +/* Generate code for a single component, after shifting (if any) + * has been applied, in case the schedule was specified as a schedule tree. + * + * We first check if the user has specified an isolated schedule domain + * and that we are not already outside of this isolated schedule domain. + * If so, we break up the schedule domain into iterations that + * precede the isolated domain, the isolated domain itself, + * the iterations that follow the isolated domain and + * the remaining iterations (those that are incomparable + * to the isolated domain). + * We generate an AST for each piece and concatenate the results. + * + * If the isolated domain is not convex, then it is replaced + * by a convex superset to ensure that the sets of preceding and + * following iterations are properly defined and, in particular, + * that there are no intermediate iterations that do not belong + * to the isolated domain. + * + * In the special case where at least one element of the schedule + * domain that does not belong to the isolated domain needs + * to be scheduled after this isolated domain, but none of those + * elements need to be scheduled before, break up the schedule domain + * in only two parts, the isolated domain, and a part that will be + * scheduled after the isolated domain. + * + * If no isolated set has been specified, then we generate an + * AST for the entire inverse schedule. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_tree( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) +{ + int i, depth; + int empty, has_isolate; + isl_space *space; + isl_union_set *schedule_domain; + isl_set *domain; + isl_basic_set *hull; + isl_set *isolated, *before, *after, *test; + isl_map *gt, *lt; + isl_bool pure; + + build = isl_ast_build_extract_isolated(build); + has_isolate = isl_ast_build_has_isolated(build); + if (has_isolate < 0) + executed = isl_union_map_free(executed); + else if (!has_isolate) + return generate_shifted_component_tree_base(executed, build, 0); + + schedule_domain = isl_union_map_domain(isl_union_map_copy(executed)); + domain = isl_set_from_union_set(schedule_domain); + + isolated = isl_ast_build_get_isolated(build); + isolated = isl_set_intersect(isolated, isl_set_copy(domain)); + test = isl_ast_build_specialize(build, isl_set_copy(isolated)); + empty = isl_set_is_empty(test); + isl_set_free(test); + if (empty < 0) + goto error; + if (empty) { + isl_set_free(isolated); + isl_set_free(domain); + return generate_shifted_component_tree_base(executed, build, 0); + } + isolated = isl_ast_build_eliminate(build, isolated); + hull = isl_set_unshifted_simple_hull(isolated); + isolated = isl_set_from_basic_set(hull); + + depth = isl_ast_build_get_depth(build); + space = isl_space_map_from_set(isl_set_get_space(isolated)); + gt = isl_map_universe(space); + for (i = 0; i < depth; ++i) + gt = isl_map_equate(gt, isl_dim_in, i, isl_dim_out, i); + gt = isl_map_order_gt(gt, isl_dim_in, depth, isl_dim_out, depth); + lt = isl_map_reverse(isl_map_copy(gt)); + before = isl_set_apply(isl_set_copy(isolated), gt); + after = isl_set_apply(isl_set_copy(isolated), lt); + + domain = isl_set_subtract(domain, isl_set_copy(isolated)); + pure = only_intersects_first(domain, after, before); + if (pure < 0) + executed = isl_union_map_free(executed); + else if (pure) + return generate_shifted_component_only_after(executed, isolated, + domain, build, before, after); + domain = isl_set_subtract(domain, isl_set_copy(before)); + domain = isl_set_subtract(domain, isl_set_copy(after)); + after = isl_set_subtract(after, isl_set_copy(isolated)); + after = isl_set_subtract(after, isl_set_copy(before)); + before = isl_set_subtract(before, isl_set_copy(isolated)); + + return generate_shifted_component_parts(executed, before, isolated, + after, domain, build); +error: + isl_set_free(domain); + isl_set_free(isolated); + isl_union_map_free(executed); + isl_ast_build_free(build); + return NULL; +} + +/* Generate code for a single component, after shifting (if any) + * has been applied. + * + * Call generate_shifted_component_tree or generate_shifted_component_flat + * depending on whether the schedule was specified as a schedule tree. + */ +static __isl_give isl_ast_graft_list *generate_shifted_component( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) +{ + if (isl_ast_build_has_schedule_node(build)) + return generate_shifted_component_tree(executed, build); + else + return generate_shifted_component_flat(executed, build); +} + +struct isl_set_map_pair { + isl_set *set; + isl_map *map; +}; + +/* Given an array "domain" of isl_set_map_pairs and an array "order" + * of indices into the "domain" array, + * return the union of the "map" fields of the elements + * indexed by the first "n" elements of "order". + */ +static __isl_give isl_union_map *construct_component_executed( + struct isl_set_map_pair *domain, int *order, int n) +{ + int i; + isl_map *map; + isl_union_map *executed; + + map = isl_map_copy(domain[order[0]].map); + executed = isl_union_map_from_map(map); + for (i = 1; i < n; ++i) { + map = isl_map_copy(domain[order[i]].map); + executed = isl_union_map_add_map(executed, map); + } + + return executed; +} + +/* Generate code for a single component, after shifting (if any) + * has been applied. + * + * The component inverse schedule is specified as the "map" fields + * of the elements of "domain" indexed by the first "n" elements of "order". + */ +static __isl_give isl_ast_graft_list *generate_shifted_component_from_list( + struct isl_set_map_pair *domain, int *order, int n, + __isl_take isl_ast_build *build) +{ + isl_union_map *executed; + + executed = construct_component_executed(domain, order, n); + return generate_shifted_component(executed, build); +} + +/* Does set dimension "pos" of "set" have an obviously fixed value? + */ +static int dim_is_fixed(__isl_keep isl_set *set, int pos) +{ + int fixed; + isl_val *v; + + v = isl_set_plain_get_val_if_fixed(set, isl_dim_set, pos); + if (!v) + return -1; + fixed = !isl_val_is_nan(v); + isl_val_free(v); + + return fixed; +} + +/* Given an array "domain" of isl_set_map_pairs and an array "order" + * of indices into the "domain" array, + * do all (except for at most one) of the "set" field of the elements + * indexed by the first "n" elements of "order" have a fixed value + * at position "depth"? + */ +static int at_most_one_non_fixed(struct isl_set_map_pair *domain, + int *order, int n, int depth) +{ + int i; + int non_fixed = -1; + + for (i = 0; i < n; ++i) { + int f; + + f = dim_is_fixed(domain[order[i]].set, depth); + if (f < 0) + return -1; + if (f) + continue; + if (non_fixed >= 0) + return 0; + non_fixed = i; + } + + return 1; +} + +/* Given an array "domain" of isl_set_map_pairs and an array "order" + * of indices into the "domain" array, + * eliminate the inner dimensions from the "set" field of the elements + * indexed by the first "n" elements of "order", provided the current + * dimension does not have a fixed value. + * + * Return the index of the first element in "order" with a corresponding + * "set" field that does not have an (obviously) fixed value. + */ +static int eliminate_non_fixed(struct isl_set_map_pair *domain, + int *order, int n, int depth, __isl_keep isl_ast_build *build) +{ + int i; + int base = -1; + + for (i = n - 1; i >= 0; --i) { + int f; + f = dim_is_fixed(domain[order[i]].set, depth); + if (f < 0) + return -1; + if (f) + continue; + domain[order[i]].set = isl_ast_build_eliminate_inner(build, + domain[order[i]].set); + base = i; + } + + return base; +} + +/* Given an array "domain" of isl_set_map_pairs and an array "order" + * of indices into the "domain" array, + * find the element of "domain" (amongst those indexed by the first "n" + * elements of "order") with the "set" field that has the smallest + * value for the current iterator. + * + * Note that the domain with the smallest value may depend on the parameters + * and/or outer loop dimension. Since the result of this function is only + * used as heuristic, we only make a reasonable attempt at finding the best + * domain, one that should work in case a single domain provides the smallest + * value for the current dimension over all values of the parameters + * and outer dimensions. + * + * In particular, we compute the smallest value of the first domain + * and replace it by that of any later domain if that later domain + * has a smallest value that is smaller for at least some value + * of the parameters and outer dimensions. + */ +static int first_offset(struct isl_set_map_pair *domain, int *order, int n, + __isl_keep isl_ast_build *build) +{ + int i; + isl_map *min_first; + int first = 0; + + min_first = isl_ast_build_map_to_iterator(build, + isl_set_copy(domain[order[0]].set)); + min_first = isl_map_lexmin(min_first); + + for (i = 1; i < n; ++i) { + isl_map *min, *test; + int empty; + + min = isl_ast_build_map_to_iterator(build, + isl_set_copy(domain[order[i]].set)); + min = isl_map_lexmin(min); + test = isl_map_copy(min); + test = isl_map_apply_domain(isl_map_copy(min_first), test); + test = isl_map_order_lt(test, isl_dim_in, 0, isl_dim_out, 0); + empty = isl_map_is_empty(test); + isl_map_free(test); + if (empty >= 0 && !empty) { + isl_map_free(min_first); + first = i; + min_first = min; + } else + isl_map_free(min); + + if (empty < 0) + break; + } + + isl_map_free(min_first); + + return i < n ? -1 : first; +} + +/* Construct a shifted inverse schedule based on the original inverse schedule, + * the stride and the offset. + * + * The original inverse schedule is specified as the "map" fields + * of the elements of "domain" indexed by the first "n" elements of "order". + * + * "stride" and "offset" are such that the difference + * between the values of the current dimension of domain "i" + * and the values of the current dimension for some reference domain are + * equal to + * + * stride * integer + offset[i] + * + * Moreover, 0 <= offset[i] < stride. + * + * For each domain, we create a map + * + * { [..., j, ...] -> [..., j - offset[i], offset[i], ....] } + * + * where j refers to the current dimension and the other dimensions are + * unchanged, and apply this map to the original schedule domain. + * + * For example, for the original schedule + * + * { A[i] -> [2i]: 0 <= i < 10; B[i] -> [2i+1] : 0 <= i < 10 } + * + * and assuming the offset is 0 for the A domain and 1 for the B domain, + * we apply the mapping + * + * { [j] -> [j, 0] } + * + * to the schedule of the "A" domain and the mapping + * + * { [j - 1] -> [j, 1] } + * + * to the schedule of the "B" domain. + * + * + * Note that after the transformation, the differences between pairs + * of values of the current dimension over all domains are multiples + * of stride and that we have therefore exposed the stride. + * + * + * To see that the mapping preserves the lexicographic order, + * first note that each of the individual maps above preserves the order. + * If the value of the current iterator is j1 in one domain and j2 in another, + * then if j1 = j2, we know that the same map is applied to both domains + * and the order is preserved. + * Otherwise, let us assume, without loss of generality, that j1 < j2. + * If c1 >= c2 (with c1 and c2 the corresponding offsets), then + * + * j1 - c1 < j2 - c2 + * + * and the order is preserved. + * If c1 < c2, then we know + * + * 0 <= c2 - c1 < s + * + * We also have + * + * j2 - j1 = n * s + r + * + * with n >= 0 and 0 <= r < s. + * In other words, r = c2 - c1. + * If n > 0, then + * + * j1 - c1 < j2 - c2 + * + * If n = 0, then + * + * j1 - c1 = j2 - c2 + * + * and so + * + * (j1 - c1, c1) << (j2 - c2, c2) + * + * with "<<" the lexicographic order, proving that the order is preserved + * in all cases. + */ +static __isl_give isl_union_map *contruct_shifted_executed( + struct isl_set_map_pair *domain, int *order, int n, + __isl_keep isl_val *stride, __isl_keep isl_multi_val *offset, + __isl_take isl_ast_build *build) +{ + int i; + isl_union_map *executed; + isl_space *space; + isl_map *map; + int depth; + isl_constraint *c; + + depth = isl_ast_build_get_depth(build); + space = isl_ast_build_get_space(build, 1); + executed = isl_union_map_empty(isl_space_copy(space)); + space = isl_space_map_from_set(space); + map = isl_map_identity(isl_space_copy(space)); + map = isl_map_eliminate(map, isl_dim_out, depth, 1); + map = isl_map_insert_dims(map, isl_dim_out, depth + 1, 1); + space = isl_space_insert_dims(space, isl_dim_out, depth + 1, 1); + + c = isl_constraint_alloc_equality(isl_local_space_from_space(space)); + c = isl_constraint_set_coefficient_si(c, isl_dim_in, depth, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_out, depth, -1); + + for (i = 0; i < n; ++i) { + isl_map *map_i; + isl_val *v; + + v = isl_multi_val_get_val(offset, i); + if (!v) + break; + map_i = isl_map_copy(map); + map_i = isl_map_fix_val(map_i, isl_dim_out, depth + 1, + isl_val_copy(v)); + v = isl_val_neg(v); + c = isl_constraint_set_constant_val(c, v); + map_i = isl_map_add_constraint(map_i, isl_constraint_copy(c)); + + map_i = isl_map_apply_domain(isl_map_copy(domain[order[i]].map), + map_i); + executed = isl_union_map_add_map(executed, map_i); + } + + isl_constraint_free(c); + isl_map_free(map); + + if (i < n) + executed = isl_union_map_free(executed); + + return executed; +} + +/* Generate code for a single component, after exposing the stride, + * given that the schedule domain is "shifted strided". + * + * The component inverse schedule is specified as the "map" fields + * of the elements of "domain" indexed by the first "n" elements of "order". + * + * The schedule domain being "shifted strided" means that the differences + * between the values of the current dimension of domain "i" + * and the values of the current dimension for some reference domain are + * equal to + * + * stride * integer + offset[i] + * + * We first look for the domain with the "smallest" value for the current + * dimension and adjust the offsets such that the offset of the "smallest" + * domain is equal to zero. The other offsets are reduced modulo stride. + * + * Based on this information, we construct a new inverse schedule in + * contruct_shifted_executed that exposes the stride. + * Since this involves the introduction of a new schedule dimension, + * the build needs to be changed accodingly. + * After computing the AST, the newly introduced dimension needs + * to be removed again from the list of grafts. We do this by plugging + * in a mapping that represents the new schedule domain in terms of the + * old schedule domain. + */ +static __isl_give isl_ast_graft_list *generate_shift_component( + struct isl_set_map_pair *domain, int *order, int n, + __isl_keep isl_val *stride, __isl_keep isl_multi_val *offset, + __isl_take isl_ast_build *build) +{ + isl_ast_graft_list *list; + int first; + int depth; + isl_val *val; + isl_multi_val *mv; + isl_space *space; + isl_multi_aff *ma, *zero; + isl_union_map *executed; + + depth = isl_ast_build_get_depth(build); + + first = first_offset(domain, order, n, build); + if (first < 0) + goto error; + + mv = isl_multi_val_copy(offset); + val = isl_multi_val_get_val(offset, first); + val = isl_val_neg(val); + mv = isl_multi_val_add_val(mv, val); + mv = isl_multi_val_mod_val(mv, isl_val_copy(stride)); + + executed = contruct_shifted_executed(domain, order, n, stride, mv, + build); + space = isl_ast_build_get_space(build, 1); + space = isl_space_map_from_set(space); + ma = isl_multi_aff_identity(isl_space_copy(space)); + space = isl_space_from_domain(isl_space_domain(space)); + space = isl_space_add_dims(space, isl_dim_out, 1); + zero = isl_multi_aff_zero(space); + ma = isl_multi_aff_range_splice(ma, depth + 1, zero); + build = isl_ast_build_insert_dim(build, depth + 1); + list = generate_shifted_component(executed, build); + + list = isl_ast_graft_list_preimage_multi_aff(list, ma); + + isl_multi_val_free(mv); + + return list; +error: + isl_ast_build_free(build); + return NULL; +} + +/* Does any node in the schedule tree rooted at the current schedule node + * of "build" depend on outer schedule nodes? + */ +static int has_anchored_subtree(__isl_keep isl_ast_build *build) +{ + isl_schedule_node *node; + int dependent = 0; + + node = isl_ast_build_get_schedule_node(build); + dependent = isl_schedule_node_is_subtree_anchored(node); + isl_schedule_node_free(node); + + return dependent; +} + +/* Generate code for a single component. + * + * The component inverse schedule is specified as the "map" fields + * of the elements of "domain" indexed by the first "n" elements of "order". + * + * This function may modify the "set" fields of "domain". + * + * Before proceeding with the actual code generation for the component, + * we first check if there are any "shifted" strides, meaning that + * the schedule domains of the individual domains are all strided, + * but that they have different offsets, resulting in the union + * of schedule domains not being strided anymore. + * + * The simplest example is the schedule + * + * { A[i] -> [2i]: 0 <= i < 10; B[i] -> [2i+1] : 0 <= i < 10 } + * + * Both schedule domains are strided, but their union is not. + * This function detects such cases and then rewrites the schedule to + * + * { A[i] -> [2i, 0]: 0 <= i < 10; B[i] -> [2i, 1] : 0 <= i < 10 } + * + * In the new schedule, the schedule domains have the same offset (modulo + * the stride), ensuring that the union of schedule domains is also strided. + * + * + * If there is only a single domain in the component, then there is + * nothing to do. Similarly, if the current schedule dimension has + * a fixed value for almost all domains then there is nothing to be done. + * In particular, we need at least two domains where the current schedule + * dimension does not have a fixed value. + * Finally, in case of a schedule map input, + * if any of the options refer to the current schedule dimension, + * then we bail out as well. It would be possible to reformulate the options + * in terms of the new schedule domain, but that would introduce constraints + * that separate the domains in the options and that is something we would + * like to avoid. + * In the case of a schedule tree input, we bail out if any of + * the descendants of the current schedule node refer to outer + * schedule nodes in any way. + * + * + * To see if there is any shifted stride, we look at the differences + * between the values of the current dimension in pairs of domains + * for equal values of outer dimensions. These differences should be + * of the form + * + * m x + r + * + * with "m" the stride and "r" a constant. Note that we cannot perform + * this analysis on individual domains as the lower bound in each domain + * may depend on parameters or outer dimensions and so the current dimension + * itself may not have a fixed remainder on division by the stride. + * + * In particular, we compare the first domain that does not have an + * obviously fixed value for the current dimension to itself and all + * other domains and collect the offsets and the gcd of the strides. + * If the gcd becomes one, then we failed to find shifted strides. + * If the gcd is zero, then the differences were all fixed, meaning + * that some domains had non-obviously fixed values for the current dimension. + * If all the offsets are the same (for those domains that do not have + * an obviously fixed value for the current dimension), then we do not + * apply the transformation. + * If none of the domains were skipped, then there is nothing to do. + * If some of them were skipped, then if we apply separation, the schedule + * domain should get split in pieces with a (non-shifted) stride. + * + * Otherwise, we apply a shift to expose the stride in + * generate_shift_component. + */ +static __isl_give isl_ast_graft_list *generate_component( + struct isl_set_map_pair *domain, int *order, int n, + __isl_take isl_ast_build *build) +{ + int i, d; + int depth; + isl_ctx *ctx; + isl_map *map; + isl_set *deltas; + isl_val *gcd = NULL; + isl_multi_val *mv; + int fixed, skip; + int base; + isl_ast_graft_list *list; + int res = 0; + + depth = isl_ast_build_get_depth(build); + + skip = n == 1; + if (skip >= 0 && !skip) + skip = at_most_one_non_fixed(domain, order, n, depth); + if (skip >= 0 && !skip) { + if (isl_ast_build_has_schedule_node(build)) + skip = has_anchored_subtree(build); + else + skip = isl_ast_build_options_involve_depth(build); + } + if (skip < 0) + goto error; + if (skip) + return generate_shifted_component_from_list(domain, + order, n, build); + + base = eliminate_non_fixed(domain, order, n, depth, build); + if (base < 0) + goto error; + + ctx = isl_ast_build_get_ctx(build); + + mv = isl_multi_val_zero(isl_space_set_alloc(ctx, 0, n)); + + fixed = 1; + for (i = 0; i < n; ++i) { + isl_val *r, *m; + + map = isl_map_from_domain_and_range( + isl_set_copy(domain[order[base]].set), + isl_set_copy(domain[order[i]].set)); + for (d = 0; d < depth; ++d) + map = isl_map_equate(map, isl_dim_in, d, + isl_dim_out, d); + deltas = isl_map_deltas(map); + res = isl_set_dim_residue_class_val(deltas, depth, &m, &r); + isl_set_free(deltas); + if (res < 0) + break; + + if (i == 0) + gcd = m; + else + gcd = isl_val_gcd(gcd, m); + if (isl_val_is_one(gcd)) { + isl_val_free(r); + break; + } + mv = isl_multi_val_set_val(mv, i, r); + + res = dim_is_fixed(domain[order[i]].set, depth); + if (res < 0) + break; + if (res) + continue; + + if (fixed && i > base) { + isl_val *a, *b; + a = isl_multi_val_get_val(mv, i); + b = isl_multi_val_get_val(mv, base); + if (isl_val_ne(a, b)) + fixed = 0; + isl_val_free(a); + isl_val_free(b); + } + } + + if (res < 0 || !gcd) { + isl_ast_build_free(build); + list = NULL; + } else if (i < n || fixed || isl_val_is_zero(gcd)) { + list = generate_shifted_component_from_list(domain, + order, n, build); + } else { + list = generate_shift_component(domain, order, n, gcd, mv, + build); + } + + isl_val_free(gcd); + isl_multi_val_free(mv); + + return list; +error: + isl_ast_build_free(build); + return NULL; +} + +/* Store both "map" itself and its domain in the + * structure pointed to by *next and advance to the next array element. + */ +static isl_stat extract_domain(__isl_take isl_map *map, void *user) +{ + struct isl_set_map_pair **next = user; + + (*next)->map = isl_map_copy(map); + (*next)->set = isl_map_domain(map); + (*next)++; + + return isl_stat_ok; +} + +static int after_in_tree(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node); + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at + * the child of "node"? + */ +static int after_in_child(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + isl_schedule_node *child; + int after; + + child = isl_schedule_node_get_child(node, 0); + after = after_in_tree(umap, child); + isl_schedule_node_free(child); + + return after; +} + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at + * the band node "node"? + * + * We first check if any domain element is scheduled after any + * of the corresponding image elements by the band node itself. + * If not, we restrict "map" to those pairs of element that + * are scheduled together by the band node and continue with + * the child of the band node. + * If there are no such pairs then the map passed to after_in_child + * will be empty causing it to return 0. + */ +static int after_in_band(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + isl_multi_union_pw_aff *mupa; + isl_union_map *partial, *test, *gt, *universe, *umap1, *umap2; + isl_union_set *domain, *range; + isl_space *space; + int empty; + int after; + + if (isl_schedule_node_band_n_member(node) == 0) + return after_in_child(umap, node); + + mupa = isl_schedule_node_band_get_partial_schedule(node); + space = isl_multi_union_pw_aff_get_space(mupa); + partial = isl_union_map_from_multi_union_pw_aff(mupa); + test = isl_union_map_copy(umap); + test = isl_union_map_apply_domain(test, isl_union_map_copy(partial)); + test = isl_union_map_apply_range(test, isl_union_map_copy(partial)); + gt = isl_union_map_from_map(isl_map_lex_gt(space)); + test = isl_union_map_intersect(test, gt); + empty = isl_union_map_is_empty(test); + isl_union_map_free(test); + + if (empty < 0 || !empty) { + isl_union_map_free(partial); + return empty < 0 ? -1 : 1; + } + + universe = isl_union_map_universe(isl_union_map_copy(umap)); + domain = isl_union_map_domain(isl_union_map_copy(universe)); + range = isl_union_map_range(universe); + umap1 = isl_union_map_copy(partial); + umap1 = isl_union_map_intersect_domain(umap1, domain); + umap2 = isl_union_map_intersect_domain(partial, range); + test = isl_union_map_apply_range(umap1, isl_union_map_reverse(umap2)); + test = isl_union_map_intersect(test, isl_union_map_copy(umap)); + after = after_in_child(test, node); + isl_union_map_free(test); + return after; +} + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at + * the context node "node"? + * + * The context constraints apply to the schedule domain, + * so we cannot apply them directly to "umap", which contains + * pairs of statement instances. Instead, we add them + * to the range of the prefix schedule for both domain and + * range of "umap". + */ +static int after_in_context(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + isl_union_map *prefix, *universe, *umap1, *umap2; + isl_union_set *domain, *range; + isl_set *context; + int after; + + umap = isl_union_map_copy(umap); + context = isl_schedule_node_context_get_context(node); + prefix = isl_schedule_node_get_prefix_schedule_union_map(node); + universe = isl_union_map_universe(isl_union_map_copy(umap)); + domain = isl_union_map_domain(isl_union_map_copy(universe)); + range = isl_union_map_range(universe); + umap1 = isl_union_map_copy(prefix); + umap1 = isl_union_map_intersect_domain(umap1, domain); + umap2 = isl_union_map_intersect_domain(prefix, range); + umap1 = isl_union_map_intersect_range(umap1, + isl_union_set_from_set(context)); + umap1 = isl_union_map_apply_range(umap1, isl_union_map_reverse(umap2)); + umap = isl_union_map_intersect(umap, umap1); + + after = after_in_child(umap, node); + + isl_union_map_free(umap); + + return after; +} + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at + * the expansion node "node"? + * + * We apply the expansion to domain and range of "umap" and + * continue with its child. + */ +static int after_in_expansion(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + isl_union_map *expansion; + int after; + + expansion = isl_schedule_node_expansion_get_expansion(node); + umap = isl_union_map_copy(umap); + umap = isl_union_map_apply_domain(umap, isl_union_map_copy(expansion)); + umap = isl_union_map_apply_range(umap, expansion); + + after = after_in_child(umap, node); + + isl_union_map_free(umap); + + return after; +} + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at + * the extension node "node"? + * + * Since the extension node may add statement instances before or + * after the pairs of statement instances in "umap", we return 1 + * to ensure that these pairs are not broken up. + */ +static int after_in_extension(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + return 1; +} + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at + * the filter node "node"? + * + * We intersect domain and range of "umap" with the filter and + * continue with its child. + */ +static int after_in_filter(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + isl_union_set *filter; + int after; + + umap = isl_union_map_copy(umap); + filter = isl_schedule_node_filter_get_filter(node); + umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(filter)); + umap = isl_union_map_intersect_range(umap, filter); + + after = after_in_child(umap, node); + + isl_union_map_free(umap); + + return after; +} + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at + * the set node "node"? + * + * This is only the case if this condition holds in any + * of the (filter) children of the set node. + * In particular, if the domain and the range of "umap" + * are contained in different children, then the condition + * does not hold. + */ +static int after_in_set(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + int i, n; + + n = isl_schedule_node_n_children(node); + for (i = 0; i < n; ++i) { + isl_schedule_node *child; + int after; + + child = isl_schedule_node_get_child(node, i); + after = after_in_tree(umap, child); + isl_schedule_node_free(child); + + if (after < 0 || after) + return after; + } + + return 0; +} + +/* Return the filter of child "i" of "node". + */ +static __isl_give isl_union_set *child_filter( + __isl_keep isl_schedule_node *node, int i) +{ + isl_schedule_node *child; + isl_union_set *filter; + + child = isl_schedule_node_get_child(node, i); + filter = isl_schedule_node_filter_get_filter(child); + isl_schedule_node_free(child); + + return filter; +} + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at + * the sequence node "node"? + * + * This happens in particular if any domain element is + * contained in a later child than one containing a range element or + * if the condition holds within a given child in the sequence. + * The later part of the condition is checked by after_in_set. + */ +static int after_in_sequence(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + int i, j, n; + isl_union_map *umap_i; + int empty, after = 0; + + n = isl_schedule_node_n_children(node); + for (i = 1; i < n; ++i) { + isl_union_set *filter_i; + + umap_i = isl_union_map_copy(umap); + filter_i = child_filter(node, i); + umap_i = isl_union_map_intersect_domain(umap_i, filter_i); + empty = isl_union_map_is_empty(umap_i); + if (empty < 0) + goto error; + if (empty) { + isl_union_map_free(umap_i); + continue; + } + + for (j = 0; j < i; ++j) { + isl_union_set *filter_j; + isl_union_map *umap_ij; + + umap_ij = isl_union_map_copy(umap_i); + filter_j = child_filter(node, j); + umap_ij = isl_union_map_intersect_range(umap_ij, + filter_j); + empty = isl_union_map_is_empty(umap_ij); + isl_union_map_free(umap_ij); + + if (empty < 0) + goto error; + if (!empty) + after = 1; + if (after) + break; + } + + isl_union_map_free(umap_i); + if (after) + break; + } + + if (after < 0 || after) + return after; + + return after_in_set(umap, node); +error: + isl_union_map_free(umap_i); + return -1; +} + +/* Is any domain element of "umap" scheduled after any of + * the corresponding image elements by the tree rooted at "node"? + * + * If "umap" is empty, then clearly there is no such element. + * Otherwise, consider the different types of nodes separately. + */ +static int after_in_tree(__isl_keep isl_union_map *umap, + __isl_keep isl_schedule_node *node) +{ + int empty; + enum isl_schedule_node_type type; + + empty = isl_union_map_is_empty(umap); + if (empty < 0) + return -1; + if (empty) + return 0; + if (!node) + return -1; + + type = isl_schedule_node_get_type(node); + switch (type) { + case isl_schedule_node_error: + return -1; + case isl_schedule_node_leaf: + return 0; + case isl_schedule_node_band: + return after_in_band(umap, node); + case isl_schedule_node_domain: + isl_die(isl_schedule_node_get_ctx(node), isl_error_internal, + "unexpected internal domain node", return -1); + case isl_schedule_node_context: + return after_in_context(umap, node); + case isl_schedule_node_expansion: + return after_in_expansion(umap, node); + case isl_schedule_node_extension: + return after_in_extension(umap, node); + case isl_schedule_node_filter: + return after_in_filter(umap, node); + case isl_schedule_node_guard: + case isl_schedule_node_mark: + return after_in_child(umap, node); + case isl_schedule_node_set: + return after_in_set(umap, node); + case isl_schedule_node_sequence: + return after_in_sequence(umap, node); + } + + return 1; +} + +/* Is any domain element of "map1" scheduled after any domain + * element of "map2" by the subtree underneath the current band node, + * while at the same time being scheduled together by the current + * band node, i.e., by "map1" and "map2? + * + * If the child of the current band node is a leaf, then + * no element can be scheduled after any other element. + * + * Otherwise, we construct a relation between domain elements + * of "map1" and domain elements of "map2" that are scheduled + * together and then check if the subtree underneath the current + * band node determines their relative order. + */ +static int after_in_subtree(__isl_keep isl_ast_build *build, + __isl_keep isl_map *map1, __isl_keep isl_map *map2) +{ + isl_schedule_node *node; + isl_map *map; + isl_union_map *umap; + int after; + + node = isl_ast_build_get_schedule_node(build); + if (!node) + return -1; + node = isl_schedule_node_child(node, 0); + if (isl_schedule_node_get_type(node) == isl_schedule_node_leaf) { + isl_schedule_node_free(node); + return 0; + } + map = isl_map_copy(map2); + map = isl_map_apply_domain(map, isl_map_copy(map1)); + umap = isl_union_map_from_map(map); + after = after_in_tree(umap, node); + isl_union_map_free(umap); + isl_schedule_node_free(node); + return after; +} + +/* Internal data for any_scheduled_after. + * + * "build" is the build in which the AST is constructed. + * "depth" is the number of loops that have already been generated + * "group_coscheduled" is a local copy of options->ast_build_group_coscheduled + * "domain" is an array of set-map pairs corresponding to the different + * iteration domains. The set is the schedule domain, i.e., the domain + * of the inverse schedule, while the map is the inverse schedule itself. + */ +struct isl_any_scheduled_after_data { + isl_ast_build *build; + int depth; + int group_coscheduled; + struct isl_set_map_pair *domain; +}; + +/* Is any element of domain "i" scheduled after any element of domain "j" + * (for a common iteration of the first data->depth loops)? + * + * data->domain[i].set contains the domain of the inverse schedule + * for domain "i", i.e., elements in the schedule domain. + * + * If we are inside a band of a schedule tree and there is a pair + * of elements in the two domains that is schedule together by + * the current band, then we check if any element of "i" may be schedule + * after element of "j" by the descendants of the band node. + * + * If data->group_coscheduled is set, then we also return 1 if there + * is any pair of elements in the two domains that are scheduled together. + */ +static isl_bool any_scheduled_after(int i, int j, void *user) +{ + struct isl_any_scheduled_after_data *data = user; + int dim = isl_set_dim(data->domain[i].set, isl_dim_set); + int pos; + + for (pos = data->depth; pos < dim; ++pos) { + int follows; + + follows = isl_set_follows_at(data->domain[i].set, + data->domain[j].set, pos); + + if (follows < -1) + return isl_bool_error; + if (follows > 0) + return isl_bool_true; + if (follows < 0) + return isl_bool_false; + } + + if (isl_ast_build_has_schedule_node(data->build)) { + int after; + + after = after_in_subtree(data->build, data->domain[i].map, + data->domain[j].map); + if (after < 0 || after) + return after; + } + + return data->group_coscheduled; +} + +/* Look for independent components at the current depth and generate code + * for each component separately. The resulting lists of grafts are + * merged in an attempt to combine grafts with identical guards. + * + * Code for two domains can be generated separately if all the elements + * of one domain are scheduled before (or together with) all the elements + * of the other domain. We therefore consider the graph with as nodes + * the domains and an edge between two nodes if any element of the first + * node is scheduled after any element of the second node. + * If the ast_build_group_coscheduled is set, then we also add an edge if + * there is any pair of elements in the two domains that are scheduled + * together. + * Code is then generated (by generate_component) + * for each of the strongly connected components in this graph + * in their topological order. + * + * Since the test is performed on the domain of the inverse schedules of + * the different domains, we precompute these domains and store + * them in data.domain. + */ +static __isl_give isl_ast_graft_list *generate_components( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) +{ + int i; + isl_ctx *ctx = isl_ast_build_get_ctx(build); + int n = isl_union_map_n_map(executed); + struct isl_any_scheduled_after_data data; + struct isl_set_map_pair *next; + struct isl_tarjan_graph *g = NULL; + isl_ast_graft_list *list = NULL; + int n_domain = 0; + + data.domain = isl_calloc_array(ctx, struct isl_set_map_pair, n); + if (!data.domain) + goto error; + n_domain = n; + + next = data.domain; + if (isl_union_map_foreach_map(executed, &extract_domain, &next) < 0) + goto error; + + if (!build) + goto error; + data.build = build; + data.depth = isl_ast_build_get_depth(build); + data.group_coscheduled = isl_options_get_ast_build_group_coscheduled(ctx); + g = isl_tarjan_graph_init(ctx, n, &any_scheduled_after, &data); + if (!g) + goto error; + + list = isl_ast_graft_list_alloc(ctx, 0); + + i = 0; + while (list && n) { + isl_ast_graft_list *list_c; + int first = i; + + if (g->order[i] == -1) + isl_die(ctx, isl_error_internal, "cannot happen", + goto error); + ++i; --n; + while (g->order[i] != -1) { + ++i; --n; + } + + list_c = generate_component(data.domain, + g->order + first, i - first, + isl_ast_build_copy(build)); + list = isl_ast_graft_list_merge(list, list_c, build); + + ++i; + } + + if (0) +error: list = isl_ast_graft_list_free(list); + isl_tarjan_graph_free(g); + for (i = 0; i < n_domain; ++i) { + isl_map_free(data.domain[i].map); + isl_set_free(data.domain[i].set); + } + free(data.domain); + isl_union_map_free(executed); + isl_ast_build_free(build); + + return list; +} + +/* Generate code for the next level (and all inner levels). + * + * If "executed" is empty, i.e., no code needs to be generated, + * then we return an empty list. + * + * If we have already generated code for all loop levels, then we pass + * control to generate_inner_level. + * + * If "executed" lives in a single space, i.e., if code needs to be + * generated for a single domain, then there can only be a single + * component and we go directly to generate_shifted_component. + * Otherwise, we call generate_components to detect the components + * and to call generate_component on each of them separately. + */ +static __isl_give isl_ast_graft_list *generate_next_level( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) +{ + int depth; + + if (!build || !executed) + goto error; + + if (isl_union_map_is_empty(executed)) { + isl_ctx *ctx = isl_ast_build_get_ctx(build); + isl_union_map_free(executed); + isl_ast_build_free(build); + return isl_ast_graft_list_alloc(ctx, 0); + } + + depth = isl_ast_build_get_depth(build); + if (depth >= isl_ast_build_dim(build, isl_dim_set)) + return generate_inner_level(executed, build); + + if (isl_union_map_n_map(executed) == 1) + return generate_shifted_component(executed, build); + + return generate_components(executed, build); +error: + isl_union_map_free(executed); + isl_ast_build_free(build); + return NULL; +} + +/* Internal data structure used by isl_ast_build_node_from_schedule_map. + * internal, executed and build are the inputs to generate_code. + * list collects the output. + */ +struct isl_generate_code_data { + int internal; + isl_union_map *executed; + isl_ast_build *build; + + isl_ast_graft_list *list; +}; + +/* Given an inverse schedule in terms of the external build schedule, i.e., + * + * [E -> S] -> D + * + * with E the external build schedule and S the additional schedule "space", + * reformulate the inverse schedule in terms of the internal schedule domain, + * i.e., return + * + * [I -> S] -> D + * + * We first obtain a mapping + * + * I -> E + * + * take the inverse and the product with S -> S, resulting in + * + * [I -> S] -> [E -> S] + * + * Applying the map to the input produces the desired result. + */ +static __isl_give isl_union_map *internal_executed( + __isl_take isl_union_map *executed, __isl_keep isl_space *space, + __isl_keep isl_ast_build *build) +{ + isl_map *id, *proj; + + proj = isl_ast_build_get_schedule_map(build); + proj = isl_map_reverse(proj); + space = isl_space_map_from_set(isl_space_copy(space)); + id = isl_map_identity(space); + proj = isl_map_product(proj, id); + executed = isl_union_map_apply_domain(executed, + isl_union_map_from_map(proj)); + return executed; +} + +/* Generate an AST that visits the elements in the range of data->executed + * in the relative order specified by the corresponding domain element(s) + * for those domain elements that belong to "set". + * Add the result to data->list. + * + * The caller ensures that "set" is a universe domain. + * "space" is the space of the additional part of the schedule. + * It is equal to the space of "set" if build->domain is parametric. + * Otherwise, it is equal to the range of the wrapped space of "set". + * + * If the build space is not parametric and + * if isl_ast_build_node_from_schedule_map + * was called from an outside user (data->internal not set), then + * the (inverse) schedule refers to the external build domain and needs to + * be transformed to refer to the internal build domain. + * + * If the build space is parametric, then we add some of the parameter + * constraints to the executed relation. Adding these constraints + * allows for an earlier detection of conflicts in some cases. + * However, we do not want to divide the executed relation into + * more disjuncts than necessary. We therefore approximate + * the constraints on the parameters by a single disjunct set. + * + * The build is extended to include the additional part of the schedule. + * If the original build space was not parametric, then the options + * in data->build refer only to the additional part of the schedule + * and they need to be adjusted to refer to the complete AST build + * domain. + * + * After having adjusted inverse schedule and build, we start generating + * code with the outer loop of the current code generation + * in generate_next_level. + * + * If the original build space was not parametric, we undo the embedding + * on the resulting isl_ast_node_list so that it can be used within + * the outer AST build. + */ +static isl_stat generate_code_in_space(struct isl_generate_code_data *data, + __isl_take isl_set *set, __isl_take isl_space *space) +{ + isl_union_map *executed; + isl_ast_build *build; + isl_ast_graft_list *list; + int embed; + + executed = isl_union_map_copy(data->executed); + executed = isl_union_map_intersect_domain(executed, + isl_union_set_from_set(set)); + + embed = !isl_set_is_params(data->build->domain); + if (embed && !data->internal) + executed = internal_executed(executed, space, data->build); + if (!embed) { + isl_set *domain; + domain = isl_ast_build_get_domain(data->build); + domain = isl_set_from_basic_set(isl_set_simple_hull(domain)); + executed = isl_union_map_intersect_params(executed, domain); + } + + build = isl_ast_build_copy(data->build); + build = isl_ast_build_product(build, space); + + list = generate_next_level(executed, build); + + list = isl_ast_graft_list_unembed(list, embed); + + data->list = isl_ast_graft_list_concat(data->list, list); + + return isl_stat_ok; +} + +/* Generate an AST that visits the elements in the range of data->executed + * in the relative order specified by the corresponding domain element(s) + * for those domain elements that belong to "set". + * Add the result to data->list. + * + * The caller ensures that "set" is a universe domain. + * + * If the build space S is not parametric, then the space of "set" + * need to be a wrapped relation with S as domain. That is, it needs + * to be of the form + * + * [S -> T] + * + * Check this property and pass control to generate_code_in_space + * passing along T. + * If the build space is not parametric, then T is the space of "set". + */ +static isl_stat generate_code_set(__isl_take isl_set *set, void *user) +{ + struct isl_generate_code_data *data = user; + isl_space *space, *build_space; + int is_domain; + + space = isl_set_get_space(set); + + if (isl_set_is_params(data->build->domain)) + return generate_code_in_space(data, set, space); + + build_space = isl_ast_build_get_space(data->build, data->internal); + space = isl_space_unwrap(space); + is_domain = isl_space_is_domain(build_space, space); + isl_space_free(build_space); + space = isl_space_range(space); + + if (is_domain < 0) + goto error; + if (!is_domain) + isl_die(isl_set_get_ctx(set), isl_error_invalid, + "invalid nested schedule space", goto error); + + return generate_code_in_space(data, set, space); +error: + isl_set_free(set); + isl_space_free(space); + return isl_stat_error; +} + +/* Generate an AST that visits the elements in the range of "executed" + * in the relative order specified by the corresponding domain element(s). + * + * "build" is an isl_ast_build that has either been constructed by + * isl_ast_build_from_context or passed to a callback set by + * isl_ast_build_set_create_leaf. + * In the first case, the space of the isl_ast_build is typically + * a parametric space, although this is currently not enforced. + * In the second case, the space is never a parametric space. + * If the space S is not parametric, then the domain space(s) of "executed" + * need to be wrapped relations with S as domain. + * + * If the domain of "executed" consists of several spaces, then an AST + * is generated for each of them (in arbitrary order) and the results + * are concatenated. + * + * If "internal" is set, then the domain "S" above refers to the internal + * schedule domain representation. Otherwise, it refers to the external + * representation, as returned by isl_ast_build_get_schedule_space. + * + * We essentially run over all the spaces in the domain of "executed" + * and call generate_code_set on each of them. + */ +static __isl_give isl_ast_graft_list *generate_code( + __isl_take isl_union_map *executed, __isl_take isl_ast_build *build, + int internal) +{ + isl_ctx *ctx; + struct isl_generate_code_data data = { 0 }; + isl_space *space; + isl_union_set *schedule_domain; + isl_union_map *universe; + + if (!build) + goto error; + space = isl_ast_build_get_space(build, 1); + space = isl_space_align_params(space, + isl_union_map_get_space(executed)); + space = isl_space_align_params(space, + isl_union_map_get_space(build->options)); + build = isl_ast_build_align_params(build, isl_space_copy(space)); + executed = isl_union_map_align_params(executed, space); + if (!executed || !build) + goto error; + + ctx = isl_ast_build_get_ctx(build); + + data.internal = internal; + data.executed = executed; + data.build = build; + data.list = isl_ast_graft_list_alloc(ctx, 0); + + universe = isl_union_map_universe(isl_union_map_copy(executed)); + schedule_domain = isl_union_map_domain(universe); + if (isl_union_set_foreach_set(schedule_domain, &generate_code_set, + &data) < 0) + data.list = isl_ast_graft_list_free(data.list); + + isl_union_set_free(schedule_domain); + isl_union_map_free(executed); + + isl_ast_build_free(build); + return data.list; +error: + isl_union_map_free(executed); + isl_ast_build_free(build); + return NULL; +} + +/* Generate an AST that visits the elements in the domain of "schedule" + * in the relative order specified by the corresponding image element(s). + * + * "build" is an isl_ast_build that has either been constructed by + * isl_ast_build_from_context or passed to a callback set by + * isl_ast_build_set_create_leaf. + * In the first case, the space of the isl_ast_build is typically + * a parametric space, although this is currently not enforced. + * In the second case, the space is never a parametric space. + * If the space S is not parametric, then the range space(s) of "schedule" + * need to be wrapped relations with S as domain. + * + * If the range of "schedule" consists of several spaces, then an AST + * is generated for each of them (in arbitrary order) and the results + * are concatenated. + * + * We first initialize the local copies of the relevant options. + * We do this here rather than when the isl_ast_build is created + * because the options may have changed between the construction + * of the isl_ast_build and the call to isl_generate_code. + * + * The main computation is performed on an inverse schedule (with + * the schedule domain in the domain and the elements to be executed + * in the range) called "executed". + */ +__isl_give isl_ast_node *isl_ast_build_node_from_schedule_map( + __isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule) +{ + isl_ast_graft_list *list; + isl_ast_node *node; + isl_union_map *executed; + + build = isl_ast_build_copy(build); + build = isl_ast_build_set_single_valued(build, 0); + schedule = isl_union_map_coalesce(schedule); + schedule = isl_union_map_remove_redundancies(schedule); + executed = isl_union_map_reverse(schedule); + list = generate_code(executed, isl_ast_build_copy(build), 0); + node = isl_ast_node_from_graft_list(list, build); + isl_ast_build_free(build); + + return node; +} + +/* The old name for isl_ast_build_node_from_schedule_map. + * It is being kept for backward compatibility, but + * it will be removed in the future. + */ +__isl_give isl_ast_node *isl_ast_build_ast_from_schedule( + __isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule) +{ + return isl_ast_build_node_from_schedule_map(build, schedule); +} + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the band node "node" and its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * If the band is empty, we continue with its descendants. + * Otherwise, we extend the build and the inverse schedule with + * the additional space/partial schedule and continue generating + * an AST in generate_next_level. + * As soon as we have extended the inverse schedule with the additional + * partial schedule, we look for equalities that may exists between + * the old and the new part. + */ +static __isl_give isl_ast_graft_list *build_ast_from_band( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + isl_space *space; + isl_multi_union_pw_aff *extra; + isl_union_map *extra_umap; + isl_ast_graft_list *list; + unsigned n1, n2; + + if (!build || !node || !executed) + goto error; + + if (isl_schedule_node_band_n_member(node) == 0) + return build_ast_from_child(build, node, executed); + + extra = isl_schedule_node_band_get_partial_schedule(node); + extra = isl_multi_union_pw_aff_align_params(extra, + isl_ast_build_get_space(build, 1)); + space = isl_multi_union_pw_aff_get_space(extra); + + extra_umap = isl_union_map_from_multi_union_pw_aff(extra); + extra_umap = isl_union_map_reverse(extra_umap); + + executed = isl_union_map_domain_product(executed, extra_umap); + executed = isl_union_map_detect_equalities(executed); + + n1 = isl_ast_build_dim(build, isl_dim_param); + build = isl_ast_build_product(build, space); + n2 = isl_ast_build_dim(build, isl_dim_param); + if (n2 > n1) + isl_die(isl_ast_build_get_ctx(build), isl_error_invalid, + "band node is not allowed to introduce new parameters", + build = isl_ast_build_free(build)); + build = isl_ast_build_set_schedule_node(build, node); + + list = generate_next_level(executed, build); + + list = isl_ast_graft_list_unembed(list, 1); + + return list; +error: + isl_schedule_node_free(node); + isl_union_map_free(executed); + isl_ast_build_free(build); + return NULL; +} + +/* Hoist a list of grafts (in practice containing a single graft) + * from "sub_build" (which includes extra context information) + * to "build". + * + * In particular, project out all additional parameters introduced + * by the context node from the enforced constraints and the guard + * of the single graft. + */ +static __isl_give isl_ast_graft_list *hoist_out_of_context( + __isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build, + __isl_keep isl_ast_build *sub_build) +{ + isl_ast_graft *graft; + isl_basic_set *enforced; + isl_set *guard; + unsigned n_param, extra_param; + + if (!build || !sub_build) + return isl_ast_graft_list_free(list); + + n_param = isl_ast_build_dim(build, isl_dim_param); + extra_param = isl_ast_build_dim(sub_build, isl_dim_param); + + if (extra_param == n_param) + return list; + + extra_param -= n_param; + enforced = isl_ast_graft_list_extract_shared_enforced(list, sub_build); + enforced = isl_basic_set_project_out(enforced, isl_dim_param, + n_param, extra_param); + enforced = isl_basic_set_remove_unknown_divs(enforced); + guard = isl_ast_graft_list_extract_hoistable_guard(list, sub_build); + guard = isl_set_remove_divs_involving_dims(guard, isl_dim_param, + n_param, extra_param); + guard = isl_set_project_out(guard, isl_dim_param, n_param, extra_param); + guard = isl_set_compute_divs(guard); + graft = isl_ast_graft_alloc_from_children(list, guard, enforced, + build, sub_build); + list = isl_ast_graft_list_from_ast_graft(graft); + + return list; +} + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the context node "node" + * and its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * The context node may introduce additional parameters as well as + * constraints on the outer schedule dimenions or original parameters. + * + * We add the extra parameters to a new build and the context + * constraints to both the build and (as a single disjunct) + * to the domain of "executed". Since the context constraints + * are specified in terms of the input schedule, we first need + * to map them to the internal schedule domain. + * + * After constructing the AST from the descendants of "node", + * we combine the list of grafts into a single graft within + * the new build, in order to be able to exploit the additional + * context constraints during this combination. + * + * Additionally, if the current node is the outermost node in + * the schedule tree (apart from the root domain node), we generate + * all pending guards, again to be able to exploit the additional + * context constraints. We currently do not do this for internal + * context nodes since we may still want to hoist conditions + * to outer AST nodes. + * + * If the context node introduced any new parameters, then they + * are removed from the set of enforced constraints and guard + * in hoist_out_of_context. + */ +static __isl_give isl_ast_graft_list *build_ast_from_context( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + isl_set *context; + isl_space *space; + isl_multi_aff *internal2input; + isl_ast_build *sub_build; + isl_ast_graft_list *list; + int n, depth; + + depth = isl_schedule_node_get_tree_depth(node); + space = isl_ast_build_get_space(build, 1); + context = isl_schedule_node_context_get_context(node); + context = isl_set_align_params(context, space); + sub_build = isl_ast_build_copy(build); + space = isl_set_get_space(context); + sub_build = isl_ast_build_align_params(sub_build, space); + internal2input = isl_ast_build_get_internal2input(sub_build); + context = isl_set_preimage_multi_aff(context, internal2input); + sub_build = isl_ast_build_restrict_generated(sub_build, + isl_set_copy(context)); + context = isl_set_from_basic_set(isl_set_simple_hull(context)); + executed = isl_union_map_intersect_domain(executed, + isl_union_set_from_set(context)); + + list = build_ast_from_child(isl_ast_build_copy(sub_build), + node, executed); + n = isl_ast_graft_list_n_ast_graft(list); + if (n < 0) + list = isl_ast_graft_list_free(list); + + list = isl_ast_graft_list_fuse(list, sub_build); + if (depth == 1) + list = isl_ast_graft_list_insert_pending_guard_nodes(list, + sub_build); + if (n >= 1) + list = hoist_out_of_context(list, build, sub_build); + + isl_ast_build_free(build); + isl_ast_build_free(sub_build); + + return list; +} + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the expansion node "node" and + * its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * We expand the domain elements by the expansion and + * continue with the descendants of the node. + */ +static __isl_give isl_ast_graft_list *build_ast_from_expansion( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + isl_union_map *expansion; + unsigned n1, n2; + + expansion = isl_schedule_node_expansion_get_expansion(node); + expansion = isl_union_map_align_params(expansion, + isl_union_map_get_space(executed)); + + n1 = isl_union_map_dim(executed, isl_dim_param); + executed = isl_union_map_apply_range(executed, expansion); + n2 = isl_union_map_dim(executed, isl_dim_param); + if (n2 > n1) + isl_die(isl_ast_build_get_ctx(build), isl_error_invalid, + "expansion node is not allowed to introduce " + "new parameters", goto error); + + return build_ast_from_child(build, node, executed); +error: + isl_ast_build_free(build); + isl_schedule_node_free(node); + isl_union_map_free(executed); + return NULL; +} + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the extension node "node" and + * its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * Extend the inverse schedule with the extension applied to current + * set of generated constraints. Since the extension if formulated + * in terms of the input schedule, it first needs to be transformed + * to refer to the internal schedule. + */ +static __isl_give isl_ast_graft_list *build_ast_from_extension( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + isl_union_set *schedule_domain; + isl_union_map *extension; + isl_set *set; + + set = isl_ast_build_get_generated(build); + set = isl_set_from_basic_set(isl_set_simple_hull(set)); + schedule_domain = isl_union_set_from_set(set); + + extension = isl_schedule_node_extension_get_extension(node); + + extension = isl_union_map_preimage_domain_multi_aff(extension, + isl_multi_aff_copy(build->internal2input)); + extension = isl_union_map_intersect_domain(extension, schedule_domain); + extension = isl_ast_build_substitute_values_union_map_domain(build, + extension); + executed = isl_union_map_union(executed, extension); + + return build_ast_from_child(build, node, executed); +} + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the filter node "node" and + * its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * We simply intersect the iteration domain (i.e., the range of "executed") + * with the filter and continue with the descendants of the node, + * unless the resulting inverse schedule is empty, in which + * case we return an empty list. + * + * If the result of the intersection is equal to the original "executed" + * relation, then keep the original representation since the intersection + * may have unnecessarily broken up the relation into a greater number + * of disjuncts. + */ +static __isl_give isl_ast_graft_list *build_ast_from_filter( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + isl_ctx *ctx; + isl_union_set *filter; + isl_union_map *orig; + isl_ast_graft_list *list; + int empty; + isl_bool unchanged; + unsigned n1, n2; + + orig = isl_union_map_copy(executed); + if (!build || !node || !executed) + goto error; + + filter = isl_schedule_node_filter_get_filter(node); + filter = isl_union_set_align_params(filter, + isl_union_map_get_space(executed)); + n1 = isl_union_map_dim(executed, isl_dim_param); + executed = isl_union_map_intersect_range(executed, filter); + n2 = isl_union_map_dim(executed, isl_dim_param); + if (n2 > n1) + isl_die(isl_ast_build_get_ctx(build), isl_error_invalid, + "filter node is not allowed to introduce " + "new parameters", goto error); + + unchanged = isl_union_map_is_subset(orig, executed); + empty = isl_union_map_is_empty(executed); + if (unchanged < 0 || empty < 0) + goto error; + if (unchanged) { + isl_union_map_free(executed); + return build_ast_from_child(build, node, orig); + } + isl_union_map_free(orig); + if (!empty) + return build_ast_from_child(build, node, executed); + + ctx = isl_ast_build_get_ctx(build); + list = isl_ast_graft_list_alloc(ctx, 0); + isl_ast_build_free(build); + isl_schedule_node_free(node); + isl_union_map_free(executed); + return list; +error: + isl_ast_build_free(build); + isl_schedule_node_free(node); + isl_union_map_free(executed); + isl_union_map_free(orig); + return NULL; +} + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the guard node "node" and + * its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * Ensure that the associated guard is enforced by the outer AST + * constructs by adding it to the guard of the graft. + * Since we know that we will enforce the guard, we can also include it + * in the generated constraints used to construct an AST for + * the descendant nodes. + */ +static __isl_give isl_ast_graft_list *build_ast_from_guard( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + isl_space *space; + isl_set *guard, *hoisted; + isl_basic_set *enforced; + isl_ast_build *sub_build; + isl_ast_graft *graft; + isl_ast_graft_list *list; + unsigned n1, n2; + + space = isl_ast_build_get_space(build, 1); + guard = isl_schedule_node_guard_get_guard(node); + n1 = isl_space_dim(space, isl_dim_param); + guard = isl_set_align_params(guard, space); + n2 = isl_set_dim(guard, isl_dim_param); + if (n2 > n1) + isl_die(isl_ast_build_get_ctx(build), isl_error_invalid, + "guard node is not allowed to introduce " + "new parameters", guard = isl_set_free(guard)); + guard = isl_set_preimage_multi_aff(guard, + isl_multi_aff_copy(build->internal2input)); + guard = isl_ast_build_specialize(build, guard); + guard = isl_set_gist(guard, isl_set_copy(build->generated)); + + sub_build = isl_ast_build_copy(build); + sub_build = isl_ast_build_restrict_generated(sub_build, + isl_set_copy(guard)); + + list = build_ast_from_child(isl_ast_build_copy(sub_build), + node, executed); + + hoisted = isl_ast_graft_list_extract_hoistable_guard(list, sub_build); + if (isl_set_n_basic_set(hoisted) > 1) + list = isl_ast_graft_list_gist_guards(list, + isl_set_copy(hoisted)); + guard = isl_set_intersect(guard, hoisted); + enforced = extract_shared_enforced(list, build); + graft = isl_ast_graft_alloc_from_children(list, guard, enforced, + build, sub_build); + + isl_ast_build_free(sub_build); + isl_ast_build_free(build); + return isl_ast_graft_list_from_ast_graft(graft); +} + +/* Call the before_each_mark callback, if requested by the user. + * + * Return 0 on success and -1 on error. + * + * The caller is responsible for recording the current inverse schedule + * in "build". + */ +static isl_stat before_each_mark(__isl_keep isl_id *mark, + __isl_keep isl_ast_build *build) +{ + if (!build) + return isl_stat_error; + if (!build->before_each_mark) + return isl_stat_ok; + return build->before_each_mark(mark, build, + build->before_each_mark_user); +} + +/* Call the after_each_mark callback, if requested by the user. + * + * The caller is responsible for recording the current inverse schedule + * in "build". + */ +static __isl_give isl_ast_graft *after_each_mark( + __isl_take isl_ast_graft *graft, __isl_keep isl_ast_build *build) +{ + if (!graft || !build) + return isl_ast_graft_free(graft); + if (!build->after_each_mark) + return graft; + graft->node = build->after_each_mark(graft->node, build, + build->after_each_mark_user); + if (!graft->node) + return isl_ast_graft_free(graft); + return graft; +} + + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the mark node "node" and + * its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + + * Since we may be calling before_each_mark and after_each_mark + * callbacks, we record the current inverse schedule in the build. + * + * We generate an AST for the child of the mark node, combine + * the graft list into a single graft and then insert the mark + * in the AST of that single graft. + */ +static __isl_give isl_ast_graft_list *build_ast_from_mark( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + isl_id *mark; + isl_ast_graft *graft; + isl_ast_graft_list *list; + int n; + + build = isl_ast_build_set_executed(build, isl_union_map_copy(executed)); + + mark = isl_schedule_node_mark_get_id(node); + if (before_each_mark(mark, build) < 0) + node = isl_schedule_node_free(node); + + list = build_ast_from_child(isl_ast_build_copy(build), node, executed); + list = isl_ast_graft_list_fuse(list, build); + n = isl_ast_graft_list_n_ast_graft(list); + if (n < 0) + list = isl_ast_graft_list_free(list); + if (n == 0) { + isl_id_free(mark); + } else { + graft = isl_ast_graft_list_get_ast_graft(list, 0); + graft = isl_ast_graft_insert_mark(graft, mark); + graft = after_each_mark(graft, build); + list = isl_ast_graft_list_set_ast_graft(list, 0, graft); + } + isl_ast_build_free(build); + + return list; +} + +static __isl_give isl_ast_graft_list *build_ast_from_schedule_node( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed); + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the sequence (or set) node "node" and + * its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * We simply generate an AST for each of the children and concatenate + * the results. + */ +static __isl_give isl_ast_graft_list *build_ast_from_sequence( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + int i, n; + isl_ctx *ctx; + isl_ast_graft_list *list; + + ctx = isl_ast_build_get_ctx(build); + list = isl_ast_graft_list_alloc(ctx, 0); + + n = isl_schedule_node_n_children(node); + for (i = 0; i < n; ++i) { + isl_schedule_node *child; + isl_ast_graft_list *list_i; + + child = isl_schedule_node_get_child(node, i); + list_i = build_ast_from_schedule_node(isl_ast_build_copy(build), + child, isl_union_map_copy(executed)); + list = isl_ast_graft_list_concat(list, list_i); + } + isl_ast_build_free(build); + isl_schedule_node_free(node); + isl_union_map_free(executed); + + return list; +} + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the node "node" and its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * If the node is a leaf, then we pass control to generate_inner_level. + * Note that the current build does not refer to any band node, so + * that generate_inner_level will not try to visit the child of + * the leaf node. + * + * The other node types are handled in separate functions. + * Set nodes are currently treated in the same way as sequence nodes. + * The children of a set node may be executed in any order, + * including the order of the children. + */ +static __isl_give isl_ast_graft_list *build_ast_from_schedule_node( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + enum isl_schedule_node_type type; + + type = isl_schedule_node_get_type(node); + + switch (type) { + case isl_schedule_node_error: + goto error; + case isl_schedule_node_leaf: + isl_schedule_node_free(node); + return generate_inner_level(executed, build); + case isl_schedule_node_band: + return build_ast_from_band(build, node, executed); + case isl_schedule_node_context: + return build_ast_from_context(build, node, executed); + case isl_schedule_node_domain: + isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported, + "unexpected internal domain node", goto error); + case isl_schedule_node_expansion: + return build_ast_from_expansion(build, node, executed); + case isl_schedule_node_extension: + return build_ast_from_extension(build, node, executed); + case isl_schedule_node_filter: + return build_ast_from_filter(build, node, executed); + case isl_schedule_node_guard: + return build_ast_from_guard(build, node, executed); + case isl_schedule_node_mark: + return build_ast_from_mark(build, node, executed); + case isl_schedule_node_sequence: + case isl_schedule_node_set: + return build_ast_from_sequence(build, node, executed); + } + + isl_die(isl_ast_build_get_ctx(build), isl_error_internal, + "unhandled type", goto error); +error: + isl_union_map_free(executed); + isl_schedule_node_free(node); + isl_ast_build_free(build); + + return NULL; +} + +/* Generate an AST that visits the elements in the domain of "executed" + * in the relative order specified by the (single) child of "node" and + * its descendants. + * + * The relation "executed" maps the outer generated loop iterators + * to the domain elements executed by those iterations. + * + * This function is never called on a leaf, set or sequence node, + * so the node always has exactly one child. + */ +static __isl_give isl_ast_graft_list *build_ast_from_child( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node, + __isl_take isl_union_map *executed) +{ + node = isl_schedule_node_child(node, 0); + return build_ast_from_schedule_node(build, node, executed); +} + +/* Generate an AST that visits the elements in the domain of the domain + * node "node" in the relative order specified by its descendants. + * + * An initial inverse schedule is created that maps a zero-dimensional + * schedule space to the node domain. + * The input "build" is assumed to have a parametric domain and + * is replaced by the same zero-dimensional schedule space. + * + * We also add some of the parameter constraints in the build domain + * to the executed relation. Adding these constraints + * allows for an earlier detection of conflicts in some cases. + * However, we do not want to divide the executed relation into + * more disjuncts than necessary. We therefore approximate + * the constraints on the parameters by a single disjunct set. + */ +static __isl_give isl_ast_node *build_ast_from_domain( + __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node) +{ + isl_ctx *ctx; + isl_union_set *domain, *schedule_domain; + isl_union_map *executed; + isl_space *space; + isl_set *set; + isl_ast_graft_list *list; + isl_ast_node *ast; + int is_params; + + if (!build) + goto error; + + ctx = isl_ast_build_get_ctx(build); + space = isl_ast_build_get_space(build, 1); + is_params = isl_space_is_params(space); + isl_space_free(space); + if (is_params < 0) + goto error; + if (!is_params) + isl_die(ctx, isl_error_unsupported, + "expecting parametric initial context", goto error); + + domain = isl_schedule_node_domain_get_domain(node); + domain = isl_union_set_coalesce(domain); + + space = isl_union_set_get_space(domain); + space = isl_space_set_from_params(space); + build = isl_ast_build_product(build, space); + + set = isl_ast_build_get_domain(build); + set = isl_set_from_basic_set(isl_set_simple_hull(set)); + schedule_domain = isl_union_set_from_set(set); + + executed = isl_union_map_from_domain_and_range(schedule_domain, domain); + list = build_ast_from_child(isl_ast_build_copy(build), node, executed); + ast = isl_ast_node_from_graft_list(list, build); + isl_ast_build_free(build); + + return ast; +error: + isl_schedule_node_free(node); + isl_ast_build_free(build); + return NULL; +} + +/* Generate an AST that visits the elements in the domain of "schedule" + * in the relative order specified by the schedule tree. + * + * "build" is an isl_ast_build that has been created using + * isl_ast_build_alloc or isl_ast_build_from_context based + * on a parametric set. + * + * The construction starts at the root node of the schedule, + * which is assumed to be a domain node. + */ +__isl_give isl_ast_node *isl_ast_build_node_from_schedule( + __isl_keep isl_ast_build *build, __isl_take isl_schedule *schedule) +{ + isl_ctx *ctx; + isl_schedule_node *node; + + if (!build || !schedule) + goto error; + + ctx = isl_ast_build_get_ctx(build); + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + + build = isl_ast_build_copy(build); + build = isl_ast_build_set_single_valued(build, 0); + if (isl_schedule_node_get_type(node) != isl_schedule_node_domain) + isl_die(ctx, isl_error_unsupported, + "expecting root domain node", + build = isl_ast_build_free(build)); + return build_ast_from_domain(build, node); +error: + isl_schedule_free(schedule); + return NULL; +} Index: contrib/isl/isl_ast_graft.c =================================================================== --- /dev/null +++ contrib/isl/isl_ast_graft.c @@ -0,0 +1,1297 @@ +/* + * Copyright 2012 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include + +static __isl_give isl_ast_graft *isl_ast_graft_copy( + __isl_keep isl_ast_graft *graft); + +#undef BASE +#define BASE ast_graft + +#include + +#undef BASE +#define BASE ast_graft +#include + +isl_ctx *isl_ast_graft_get_ctx(__isl_keep isl_ast_graft *graft) +{ + if (!graft) + return NULL; + return isl_basic_set_get_ctx(graft->enforced); +} + +__isl_give isl_ast_node *isl_ast_graft_get_node( + __isl_keep isl_ast_graft *graft) +{ + return graft ? isl_ast_node_copy(graft->node) : NULL; +} + +/* Create a graft for "node" with no guards and no enforced conditions. + */ +__isl_give isl_ast_graft *isl_ast_graft_alloc( + __isl_take isl_ast_node *node, __isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + isl_space *space; + isl_ast_graft *graft; + + if (!node) + return NULL; + + ctx = isl_ast_node_get_ctx(node); + graft = isl_calloc_type(ctx, isl_ast_graft); + if (!graft) + goto error; + + space = isl_ast_build_get_space(build, 1); + + graft->ref = 1; + graft->node = node; + graft->guard = isl_set_universe(isl_space_copy(space)); + graft->enforced = isl_basic_set_universe(space); + + if (!graft->guard || !graft->enforced) + return isl_ast_graft_free(graft); + + return graft; +error: + isl_ast_node_free(node); + return NULL; +} + +/* Create a graft with no guards and no enforced conditions + * encapsulating a call to the domain element specified by "executed". + * "executed" is assumed to be single-valued. + */ +__isl_give isl_ast_graft *isl_ast_graft_alloc_domain( + __isl_take isl_map *executed, __isl_keep isl_ast_build *build) +{ + isl_ast_node *node; + + node = isl_ast_build_call_from_executed(build, executed); + + return isl_ast_graft_alloc(node, build); +} + +static __isl_give isl_ast_graft *isl_ast_graft_copy( + __isl_keep isl_ast_graft *graft) +{ + if (!graft) + return NULL; + + graft->ref++; + return graft; +} + +/* Do all the grafts in "list" have the same guard and is this guard + * independent of the current depth? + */ +static int equal_independent_guards(__isl_keep isl_ast_graft_list *list, + __isl_keep isl_ast_build *build) +{ + int i, n; + int depth; + isl_ast_graft *graft_0; + int equal = 1; + int skip; + + graft_0 = isl_ast_graft_list_get_ast_graft(list, 0); + if (!graft_0) + return -1; + + depth = isl_ast_build_get_depth(build); + if (isl_set_dim(graft_0->guard, isl_dim_set) <= depth) + skip = 0; + else + skip = isl_set_involves_dims(graft_0->guard, + isl_dim_set, depth, 1); + if (skip < 0 || skip) { + isl_ast_graft_free(graft_0); + return skip < 0 ? -1 : 0; + } + + n = isl_ast_graft_list_n_ast_graft(list); + for (i = 1; i < n; ++i) { + isl_ast_graft *graft; + graft = isl_ast_graft_list_get_ast_graft(list, i); + if (!graft) + equal = -1; + else + equal = isl_set_is_equal(graft_0->guard, graft->guard); + isl_ast_graft_free(graft); + if (equal < 0 || !equal) + break; + } + + isl_ast_graft_free(graft_0); + + return equal; +} + +/* Hoist "guard" out of the current level (given by "build"). + * + * In particular, eliminate the dimension corresponding to the current depth. + */ +static __isl_give isl_set *hoist_guard(__isl_take isl_set *guard, + __isl_keep isl_ast_build *build) +{ + int depth; + + depth = isl_ast_build_get_depth(build); + if (depth < isl_set_dim(guard, isl_dim_set)) { + guard = isl_set_remove_divs_involving_dims(guard, + isl_dim_set, depth, 1); + guard = isl_set_eliminate(guard, isl_dim_set, depth, 1); + guard = isl_set_compute_divs(guard); + } + + return guard; +} + +/* Extract a common guard from the grafts in "list" that can be hoisted + * out of the current level. If no such guard can be found, then return + * a universal set. + * + * If all the grafts in the list have the same guard and if this guard + * is independent of the current level, then it can be hoisted out. + * If there is only one graft in the list and if its guard + * depends on the current level, then we eliminate this level and + * return the result. + * + * Otherwise, we return the unshifted simple hull of the guards. + * In order to be able to hoist as many constraints as possible, + * but at the same time avoid hoisting constraints that did not + * appear in the guards in the first place, we intersect the guards + * with all the information that is available (i.e., the domain + * from the build and the enforced constraints of the graft) and + * compute the unshifted hull of the result using only constraints + * from the original guards. + * In particular, intersecting the guards with other known information + * allows us to hoist guards that are only explicit is some of + * the grafts and implicit in the others. + * + * The special case for equal guards is needed in case those guards + * are non-convex. Taking the simple hull would remove information + * and would not allow for these guards to be hoisted completely. + */ +__isl_give isl_set *isl_ast_graft_list_extract_hoistable_guard( + __isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build) +{ + int i, n; + int equal; + isl_ctx *ctx; + isl_set *guard; + isl_set_list *set_list; + isl_basic_set *hull; + + if (!list || !build) + return NULL; + + n = isl_ast_graft_list_n_ast_graft(list); + if (n == 0) + return isl_set_universe(isl_ast_build_get_space(build, 1)); + + equal = equal_independent_guards(list, build); + if (equal < 0) + return NULL; + + if (equal || n == 1) { + isl_ast_graft *graft_0; + + graft_0 = isl_ast_graft_list_get_ast_graft(list, 0); + if (!graft_0) + return NULL; + guard = isl_set_copy(graft_0->guard); + if (!equal) + guard = hoist_guard(guard, build); + isl_ast_graft_free(graft_0); + return guard; + } + + ctx = isl_ast_build_get_ctx(build); + set_list = isl_set_list_alloc(ctx, n); + guard = isl_set_empty(isl_ast_build_get_space(build, 1)); + for (i = 0; i < n; ++i) { + isl_ast_graft *graft; + isl_basic_set *enforced; + isl_set *guard_i; + + graft = isl_ast_graft_list_get_ast_graft(list, i); + enforced = isl_ast_graft_get_enforced(graft); + guard_i = isl_set_copy(graft->guard); + isl_ast_graft_free(graft); + set_list = isl_set_list_add(set_list, isl_set_copy(guard_i)); + guard_i = isl_set_intersect(guard_i, + isl_set_from_basic_set(enforced)); + guard_i = isl_set_intersect(guard_i, + isl_ast_build_get_domain(build)); + guard = isl_set_union(guard, guard_i); + } + hull = isl_set_unshifted_simple_hull_from_set_list(guard, set_list); + guard = isl_set_from_basic_set(hull); + return hoist_guard(guard, build); +} + +/* Internal data structure used inside insert_if. + * + * list is the list of guarded nodes created by each call to insert_if. + * node is the original node that is guarded by insert_if. + * build is the build in which the AST is constructed. + */ +struct isl_insert_if_data { + isl_ast_node_list *list; + isl_ast_node *node; + isl_ast_build *build; +}; + +static isl_stat insert_if(__isl_take isl_basic_set *bset, void *user); + +/* Insert an if node around "node" testing the condition encoded + * in guard "guard". + * + * If the user does not want any disjunctions in the if conditions + * and if "guard" does involve a disjunction, then we make the different + * disjuncts disjoint and insert an if node corresponding to each disjunct + * around a copy of "node". The result is then a block node containing + * this sequence of guarded copies of "node". + */ +static __isl_give isl_ast_node *ast_node_insert_if( + __isl_take isl_ast_node *node, __isl_take isl_set *guard, + __isl_keep isl_ast_build *build) +{ + struct isl_insert_if_data data; + isl_ctx *ctx; + + ctx = isl_ast_build_get_ctx(build); + if (isl_options_get_ast_build_allow_or(ctx) || + isl_set_n_basic_set(guard) <= 1) { + isl_ast_node *if_node; + isl_ast_expr *expr; + + expr = isl_ast_build_expr_from_set_internal(build, guard); + + if_node = isl_ast_node_alloc_if(expr); + return isl_ast_node_if_set_then(if_node, node); + } + + guard = isl_set_make_disjoint(guard); + + data.list = isl_ast_node_list_alloc(ctx, 0); + data.node = node; + data.build = build; + if (isl_set_foreach_basic_set(guard, &insert_if, &data) < 0) + data.list = isl_ast_node_list_free(data.list); + + isl_set_free(guard); + isl_ast_node_free(data.node); + return isl_ast_node_alloc_block(data.list); +} + +/* Insert an if node around a copy of "data->node" testing the condition + * encoded in guard "bset" and add the result to data->list. + */ +static isl_stat insert_if(__isl_take isl_basic_set *bset, void *user) +{ + struct isl_insert_if_data *data = user; + isl_ast_node *node; + isl_set *set; + + set = isl_set_from_basic_set(bset); + node = isl_ast_node_copy(data->node); + node = ast_node_insert_if(node, set, data->build); + data->list = isl_ast_node_list_add(data->list, node); + + return isl_stat_ok; +} + +/* Insert an if node around graft->node testing the condition encoded + * in guard "guard", assuming guard involves any conditions. + */ +static __isl_give isl_ast_graft *insert_if_node( + __isl_take isl_ast_graft *graft, __isl_take isl_set *guard, + __isl_keep isl_ast_build *build) +{ + int univ; + + if (!graft) + goto error; + + univ = isl_set_plain_is_universe(guard); + if (univ < 0) + goto error; + if (univ) { + isl_set_free(guard); + return graft; + } + + build = isl_ast_build_copy(build); + graft->node = ast_node_insert_if(graft->node, guard, build); + isl_ast_build_free(build); + + if (!graft->node) + return isl_ast_graft_free(graft); + + return graft; +error: + isl_set_free(guard); + return isl_ast_graft_free(graft); +} + +/* Insert an if node around graft->node testing the condition encoded + * in graft->guard, assuming graft->guard involves any conditions. + */ +static __isl_give isl_ast_graft *insert_pending_guard_node( + __isl_take isl_ast_graft *graft, __isl_keep isl_ast_build *build) +{ + if (!graft) + return NULL; + + return insert_if_node(graft, isl_set_copy(graft->guard), build); +} + +/* Replace graft->enforced by "enforced". + */ +__isl_give isl_ast_graft *isl_ast_graft_set_enforced( + __isl_take isl_ast_graft *graft, __isl_take isl_basic_set *enforced) +{ + if (!graft || !enforced) + goto error; + + isl_basic_set_free(graft->enforced); + graft->enforced = enforced; + + return graft; +error: + isl_basic_set_free(enforced); + return isl_ast_graft_free(graft); +} + +/* Update "enforced" such that it only involves constraints that are + * also enforced by "graft". + */ +static __isl_give isl_basic_set *update_enforced( + __isl_take isl_basic_set *enforced, __isl_keep isl_ast_graft *graft, + int depth) +{ + isl_basic_set *enforced_g; + + enforced_g = isl_ast_graft_get_enforced(graft); + if (depth < isl_basic_set_dim(enforced_g, isl_dim_set)) + enforced_g = isl_basic_set_eliminate(enforced_g, + isl_dim_set, depth, 1); + enforced_g = isl_basic_set_remove_unknown_divs(enforced_g); + enforced_g = isl_basic_set_align_params(enforced_g, + isl_basic_set_get_space(enforced)); + enforced = isl_basic_set_align_params(enforced, + isl_basic_set_get_space(enforced_g)); + enforced = isl_set_simple_hull(isl_basic_set_union(enforced, + enforced_g)); + + return enforced; +} + +/* Extend the node at *body with node. + * + * If body points to the else branch, then *body may still be NULL. + * If so, we simply attach node to this else branch. + * Otherwise, we attach a list containing the statements already + * attached at *body followed by node. + */ +static void extend_body(__isl_keep isl_ast_node **body, + __isl_take isl_ast_node *node) +{ + isl_ast_node_list *list; + + if (!*body) { + *body = node; + return; + } + + if ((*body)->type == isl_ast_node_block) { + list = isl_ast_node_block_get_children(*body); + isl_ast_node_free(*body); + } else + list = isl_ast_node_list_from_ast_node(*body); + list = isl_ast_node_list_add(list, node); + *body = isl_ast_node_alloc_block(list); +} + +/* Merge "graft" into the last graft of "list". + * body points to the then or else branch of an if node in that last graft. + * + * We attach graft->node to this branch and update the enforced + * set of the last graft of "list" to take into account the enforced + * set of "graft". + */ +static __isl_give isl_ast_graft_list *graft_extend_body( + __isl_take isl_ast_graft_list *list, + __isl_keep isl_ast_node **body, __isl_take isl_ast_graft *graft, + __isl_keep isl_ast_build *build) +{ + int n; + int depth; + isl_ast_graft *last; + isl_space *space; + isl_basic_set *enforced; + + if (!list || !graft) + goto error; + extend_body(body, isl_ast_node_copy(graft->node)); + if (!*body) + goto error; + + n = isl_ast_graft_list_n_ast_graft(list); + last = isl_ast_graft_list_get_ast_graft(list, n - 1); + + depth = isl_ast_build_get_depth(build); + space = isl_ast_build_get_space(build, 1); + enforced = isl_basic_set_empty(space); + enforced = update_enforced(enforced, last, depth); + enforced = update_enforced(enforced, graft, depth); + last = isl_ast_graft_set_enforced(last, enforced); + + list = isl_ast_graft_list_set_ast_graft(list, n - 1, last); + isl_ast_graft_free(graft); + return list; +error: + isl_ast_graft_free(graft); + return isl_ast_graft_list_free(list); +} + +/* Merge "graft" into the last graft of "list", attaching graft->node + * to the then branch of "last_if". + */ +static __isl_give isl_ast_graft_list *extend_then( + __isl_take isl_ast_graft_list *list, + __isl_keep isl_ast_node *last_if, __isl_take isl_ast_graft *graft, + __isl_keep isl_ast_build *build) +{ + return graft_extend_body(list, &last_if->u.i.then, graft, build); +} + +/* Merge "graft" into the last graft of "list", attaching graft->node + * to the else branch of "last_if". + */ +static __isl_give isl_ast_graft_list *extend_else( + __isl_take isl_ast_graft_list *list, + __isl_keep isl_ast_node *last_if, __isl_take isl_ast_graft *graft, + __isl_keep isl_ast_build *build) +{ + return graft_extend_body(list, &last_if->u.i.else_node, graft, build); +} + +/* This data structure keeps track of an if node. + * + * "node" is the actual if-node + * "guard" is the original, non-simplified guard of the node + * "complement" is the complement of "guard" in the context of outer if nodes + */ +struct isl_if_node { + isl_ast_node *node; + isl_set *guard; + isl_set *complement; +}; + +/* Given a list of "n" if nodes, clear those starting at "first" + * and return "first" (i.e., the updated size of the array). + */ +static int clear_if_nodes(struct isl_if_node *if_node, int first, int n) +{ + int i; + + for (i = first; i < n; ++i) { + isl_set_free(if_node[i].guard); + isl_set_free(if_node[i].complement); + } + + return first; +} + +/* For each graft in "list", + * insert an if node around graft->node testing the condition encoded + * in graft->guard, assuming graft->guard involves any conditions. + * + * We keep track of a list of generated if nodes that can be extended + * without changing the order of the elements in "list". + * If the guard of a graft is a subset of either the guard or its complement + * of one of those if nodes, then the node + * of the new graft is inserted into the then or else branch of the last graft + * and the current graft is discarded. + * The guard of the node is then simplified based on the conditions + * enforced at that then or else branch. + * Otherwise, the current graft is appended to the list. + * + * We only construct else branches if allowed by the user. + */ +static __isl_give isl_ast_graft_list *insert_pending_guard_nodes( + __isl_take isl_ast_graft_list *list, + __isl_keep isl_ast_build *build) +{ + int i, j, n, n_if; + int allow_else; + isl_ctx *ctx; + isl_ast_graft_list *res; + struct isl_if_node *if_node = NULL; + + if (!build || !list) + return isl_ast_graft_list_free(list); + + ctx = isl_ast_build_get_ctx(build); + n = isl_ast_graft_list_n_ast_graft(list); + + allow_else = isl_options_get_ast_build_allow_else(ctx); + + n_if = 0; + if (n > 1) { + if_node = isl_alloc_array(ctx, struct isl_if_node, n - 1); + if (!if_node) + return isl_ast_graft_list_free(list); + } + + res = isl_ast_graft_list_alloc(ctx, n); + + for (i = 0; i < n; ++i) { + isl_set *guard; + isl_ast_graft *graft; + int subset, found_then, found_else; + isl_ast_node *node; + + graft = isl_ast_graft_list_get_ast_graft(list, i); + if (!graft) + break; + subset = 0; + found_then = found_else = -1; + if (n_if > 0) { + isl_set *test; + test = isl_set_copy(graft->guard); + test = isl_set_intersect(test, + isl_set_copy(build->domain)); + for (j = n_if - 1; j >= 0; --j) { + subset = isl_set_is_subset(test, + if_node[j].guard); + if (subset < 0 || subset) { + found_then = j; + break; + } + if (!allow_else) + continue; + subset = isl_set_is_subset(test, + if_node[j].complement); + if (subset < 0 || subset) { + found_else = j; + break; + } + } + n_if = clear_if_nodes(if_node, j + 1, n_if); + isl_set_free(test); + } + if (subset < 0) { + graft = isl_ast_graft_free(graft); + break; + } + + guard = isl_set_copy(graft->guard); + if (found_then >= 0) + graft->guard = isl_set_gist(graft->guard, + isl_set_copy(if_node[found_then].guard)); + else if (found_else >= 0) + graft->guard = isl_set_gist(graft->guard, + isl_set_copy(if_node[found_else].complement)); + + node = graft->node; + if (!graft->guard) + graft = isl_ast_graft_free(graft); + graft = insert_pending_guard_node(graft, build); + if (graft && graft->node != node && i != n - 1) { + isl_set *set; + if_node[n_if].node = graft->node; + if_node[n_if].guard = guard; + if (found_then >= 0) + set = if_node[found_then].guard; + else if (found_else >= 0) + set = if_node[found_else].complement; + else + set = build->domain; + set = isl_set_copy(set); + set = isl_set_subtract(set, isl_set_copy(guard)); + if_node[n_if].complement = set; + n_if++; + } else + isl_set_free(guard); + if (!graft) + break; + + if (found_then >= 0) + res = extend_then(res, if_node[found_then].node, + graft, build); + else if (found_else >= 0) + res = extend_else(res, if_node[found_else].node, + graft, build); + else + res = isl_ast_graft_list_add(res, graft); + } + if (i < n) + res = isl_ast_graft_list_free(res); + + isl_ast_graft_list_free(list); + clear_if_nodes(if_node, 0, n_if); + free(if_node); + return res; +} + +/* For each graft in "list", + * insert an if node around graft->node testing the condition encoded + * in graft->guard, assuming graft->guard involves any conditions. + * Subsequently remove the guards from the grafts. + */ +__isl_give isl_ast_graft_list *isl_ast_graft_list_insert_pending_guard_nodes( + __isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build) +{ + int i, n; + isl_set *universe; + + list = insert_pending_guard_nodes(list, build); + if (!list) + return NULL; + + universe = isl_set_universe(isl_ast_build_get_space(build, 1)); + n = isl_ast_graft_list_n_ast_graft(list); + for (i = 0; i < n; ++i) { + isl_ast_graft *graft; + + graft = isl_ast_graft_list_get_ast_graft(list, i); + if (!graft) + break; + isl_set_free(graft->guard); + graft->guard = isl_set_copy(universe); + if (!graft->guard) + graft = isl_ast_graft_free(graft); + list = isl_ast_graft_list_set_ast_graft(list, i, graft); + } + isl_set_free(universe); + if (i < n) + return isl_ast_graft_list_free(list); + + return list; +} + +/* Collect the nodes contained in the grafts in "list" in a node list. + */ +static __isl_give isl_ast_node_list *extract_node_list( + __isl_keep isl_ast_graft_list *list) +{ + int i, n; + isl_ctx *ctx; + isl_ast_node_list *node_list; + + if (!list) + return NULL; + ctx = isl_ast_graft_list_get_ctx(list); + n = isl_ast_graft_list_n_ast_graft(list); + node_list = isl_ast_node_list_alloc(ctx, n); + for (i = 0; i < n; ++i) { + isl_ast_node *node; + isl_ast_graft *graft; + + graft = isl_ast_graft_list_get_ast_graft(list, i); + node = isl_ast_graft_get_node(graft); + node_list = isl_ast_node_list_add(node_list, node); + isl_ast_graft_free(graft); + } + + return node_list; +} + +/* Look for shared enforced constraints by all the elements in "list" + * on outer loops (with respect to the current depth) and return the result. + * + * If there are no elements in "list", then return the empty set. + */ +__isl_give isl_basic_set *isl_ast_graft_list_extract_shared_enforced( + __isl_keep isl_ast_graft_list *list, + __isl_keep isl_ast_build *build) +{ + int i, n; + int depth; + isl_space *space; + isl_basic_set *enforced; + + if (!list) + return NULL; + + space = isl_ast_build_get_space(build, 1); + enforced = isl_basic_set_empty(space); + + depth = isl_ast_build_get_depth(build); + n = isl_ast_graft_list_n_ast_graft(list); + for (i = 0; i < n; ++i) { + isl_ast_graft *graft; + + graft = isl_ast_graft_list_get_ast_graft(list, i); + enforced = update_enforced(enforced, graft, depth); + isl_ast_graft_free(graft); + } + + return enforced; +} + +/* Record "guard" in "graft" so that it will be enforced somewhere + * up the tree. If the graft already has a guard, then it may be partially + * redundant in combination with the new guard and in the context + * the generated constraints of "build". In fact, the new guard + * may in itself have some redundant constraints. + * We therefore (re)compute the gist of the intersection + * and coalesce the result. + */ +static __isl_give isl_ast_graft *store_guard(__isl_take isl_ast_graft *graft, + __isl_take isl_set *guard, __isl_keep isl_ast_build *build) +{ + int is_universe; + + if (!graft) + goto error; + + is_universe = isl_set_plain_is_universe(guard); + if (is_universe < 0) + goto error; + if (is_universe) { + isl_set_free(guard); + return graft; + } + + graft->guard = isl_set_intersect(graft->guard, guard); + graft->guard = isl_set_gist(graft->guard, + isl_ast_build_get_generated(build)); + graft->guard = isl_set_coalesce(graft->guard); + if (!graft->guard) + return isl_ast_graft_free(graft); + + return graft; +error: + isl_set_free(guard); + return isl_ast_graft_free(graft); +} + +/* For each graft in "list", replace its guard with the gist with + * respect to "context". + */ +static __isl_give isl_ast_graft_list *gist_guards( + __isl_take isl_ast_graft_list *list, __isl_keep isl_set *context) +{ + int i, n; + + if (!list) + return NULL; + + n = isl_ast_graft_list_n_ast_graft(list); + for (i = 0; i < n; ++i) { + isl_ast_graft *graft; + + graft = isl_ast_graft_list_get_ast_graft(list, i); + if (!graft) + break; + graft->guard = isl_set_gist(graft->guard, + isl_set_copy(context)); + if (!graft->guard) + graft = isl_ast_graft_free(graft); + list = isl_ast_graft_list_set_ast_graft(list, i, graft); + } + if (i < n) + return isl_ast_graft_list_free(list); + + return list; +} + +/* For each graft in "list", replace its guard with the gist with + * respect to "context". + */ +__isl_give isl_ast_graft_list *isl_ast_graft_list_gist_guards( + __isl_take isl_ast_graft_list *list, __isl_take isl_set *context) +{ + list = gist_guards(list, context); + isl_set_free(context); + + return list; +} + +/* Allocate a graft in "build" based on the list of grafts in "sub_build". + * "guard" and "enforced" are the guard and enforced constraints + * of the allocated graft. The guard is used to simplify the guards + * of the elements in "list". + * + * The node is initialized to either a block containing the nodes of "children" + * or, if there is only a single child, the node of that child. + * If the current level requires a for node, it should be inserted by + * a subsequent call to isl_ast_graft_insert_for. + */ +__isl_give isl_ast_graft *isl_ast_graft_alloc_from_children( + __isl_take isl_ast_graft_list *list, __isl_take isl_set *guard, + __isl_take isl_basic_set *enforced, __isl_keep isl_ast_build *build, + __isl_keep isl_ast_build *sub_build) +{ + isl_ast_build *guard_build; + isl_ast_node *node; + isl_ast_node_list *node_list; + isl_ast_graft *graft; + + guard_build = isl_ast_build_copy(sub_build); + guard_build = isl_ast_build_replace_pending_by_guard(guard_build, + isl_set_copy(guard)); + list = gist_guards(list, guard); + list = insert_pending_guard_nodes(list, guard_build); + isl_ast_build_free(guard_build); + + node_list = extract_node_list(list); + node = isl_ast_node_from_ast_node_list(node_list); + isl_ast_graft_list_free(list); + + graft = isl_ast_graft_alloc(node, build); + graft = store_guard(graft, guard, build); + graft = isl_ast_graft_enforce(graft, enforced); + + return graft; +} + +/* Combine the grafts in the list into a single graft. + * + * The guard is initialized to the shared guard of the list elements (if any), + * provided it does not depend on the current dimension. + * The guards in the elements are then simplified with respect to the + * hoisted guard and materialized as if nodes around the contained AST nodes + * in the context of "sub_build". + * + * The enforced set is initialized to the simple hull of the enforced sets + * of the elements, provided the ast_build_exploit_nested_bounds option is set + * or the new graft will be used at the same level. + * + * The node is initialized to either a block containing the nodes of "list" + * or, if there is only a single element, the node of that element. + */ +static __isl_give isl_ast_graft *ast_graft_list_fuse( + __isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build) +{ + isl_ast_graft *graft; + isl_basic_set *enforced; + isl_set *guard; + + if (!list) + return NULL; + + enforced = isl_ast_graft_list_extract_shared_enforced(list, build); + guard = isl_ast_graft_list_extract_hoistable_guard(list, build); + graft = isl_ast_graft_alloc_from_children(list, guard, enforced, + build, build); + + return graft; +} + +/* Combine the grafts in the list into a single graft. + * Return a list containing this single graft. + * If the original list is empty, then return an empty list. + */ +__isl_give isl_ast_graft_list *isl_ast_graft_list_fuse( + __isl_take isl_ast_graft_list *list, + __isl_keep isl_ast_build *build) +{ + isl_ast_graft *graft; + + if (!list) + return NULL; + if (isl_ast_graft_list_n_ast_graft(list) <= 1) + return list; + graft = ast_graft_list_fuse(list, build); + return isl_ast_graft_list_from_ast_graft(graft); +} + +/* Combine the two grafts into a single graft. + * Return a list containing this single graft. + */ +static __isl_give isl_ast_graft *isl_ast_graft_fuse( + __isl_take isl_ast_graft *graft1, __isl_take isl_ast_graft *graft2, + __isl_keep isl_ast_build *build) +{ + isl_ctx *ctx; + isl_ast_graft_list *list; + + ctx = isl_ast_build_get_ctx(build); + + list = isl_ast_graft_list_alloc(ctx, 2); + list = isl_ast_graft_list_add(list, graft1); + list = isl_ast_graft_list_add(list, graft2); + + return ast_graft_list_fuse(list, build); +} + +/* Insert a for node enclosing the current graft->node. + */ +__isl_give isl_ast_graft *isl_ast_graft_insert_for( + __isl_take isl_ast_graft *graft, __isl_take isl_ast_node *node) +{ + if (!graft) + goto error; + + graft->node = isl_ast_node_for_set_body(node, graft->node); + if (!graft->node) + return isl_ast_graft_free(graft); + + return graft; +error: + isl_ast_node_free(node); + isl_ast_graft_free(graft); + return NULL; +} + +/* Insert a mark governing the current graft->node. + */ +__isl_give isl_ast_graft *isl_ast_graft_insert_mark( + __isl_take isl_ast_graft *graft, __isl_take isl_id *mark) +{ + if (!graft) + goto error; + + graft->node = isl_ast_node_alloc_mark(mark, graft->node); + if (!graft->node) + return isl_ast_graft_free(graft); + + return graft; +error: + isl_id_free(mark); + isl_ast_graft_free(graft); + return NULL; +} + +/* Represent the graft list as an AST node. + * This operation drops the information about guards in the grafts, so + * if there are any pending guards, then they are materialized as if nodes. + */ +__isl_give isl_ast_node *isl_ast_node_from_graft_list( + __isl_take isl_ast_graft_list *list, + __isl_keep isl_ast_build *build) +{ + isl_ast_node_list *node_list; + + list = insert_pending_guard_nodes(list, build); + node_list = extract_node_list(list); + isl_ast_graft_list_free(list); + + return isl_ast_node_from_ast_node_list(node_list); +} + +void *isl_ast_graft_free(__isl_take isl_ast_graft *graft) +{ + if (!graft) + return NULL; + + if (--graft->ref > 0) + return NULL; + + isl_ast_node_free(graft->node); + isl_set_free(graft->guard); + isl_basic_set_free(graft->enforced); + free(graft); + + return NULL; +} + +/* Record that the grafted tree enforces + * "enforced" by intersecting graft->enforced with "enforced". + */ +__isl_give isl_ast_graft *isl_ast_graft_enforce( + __isl_take isl_ast_graft *graft, __isl_take isl_basic_set *enforced) +{ + if (!graft || !enforced) + goto error; + + enforced = isl_basic_set_align_params(enforced, + isl_basic_set_get_space(graft->enforced)); + graft->enforced = isl_basic_set_align_params(graft->enforced, + isl_basic_set_get_space(enforced)); + graft->enforced = isl_basic_set_intersect(graft->enforced, enforced); + if (!graft->enforced) + return isl_ast_graft_free(graft); + + return graft; +error: + isl_basic_set_free(enforced); + return isl_ast_graft_free(graft); +} + +__isl_give isl_basic_set *isl_ast_graft_get_enforced( + __isl_keep isl_ast_graft *graft) +{ + return graft ? isl_basic_set_copy(graft->enforced) : NULL; +} + +__isl_give isl_set *isl_ast_graft_get_guard(__isl_keep isl_ast_graft *graft) +{ + return graft ? isl_set_copy(graft->guard) : NULL; +} + +/* Record that "guard" needs to be inserted in "graft". + */ +__isl_give isl_ast_graft *isl_ast_graft_add_guard( + __isl_take isl_ast_graft *graft, + __isl_take isl_set *guard, __isl_keep isl_ast_build *build) +{ + return store_guard(graft, guard, build); +} + +/* Reformulate the "graft", which was generated in the context + * of an inner code generation, in terms of the outer code generation + * AST build. + * + * If "product" is set, then the domain of the inner code generation build is + * + * [O -> S] + * + * with O the domain of the outer code generation build. + * We essentially need to project out S. + * + * If "product" is not set, then we need to project the domains onto + * their parameter spaces. + */ +__isl_give isl_ast_graft *isl_ast_graft_unembed(__isl_take isl_ast_graft *graft, + int product) +{ + isl_basic_set *enforced; + + if (!graft) + return NULL; + + if (product) { + enforced = graft->enforced; + enforced = isl_basic_map_domain(isl_basic_set_unwrap(enforced)); + graft->enforced = enforced; + graft->guard = isl_map_domain(isl_set_unwrap(graft->guard)); + } else { + graft->enforced = isl_basic_set_params(graft->enforced); + graft->guard = isl_set_params(graft->guard); + } + graft->guard = isl_set_compute_divs(graft->guard); + + if (!graft->enforced || !graft->guard) + return isl_ast_graft_free(graft); + + return graft; +} + +/* Reformulate the grafts in "list", which were generated in the context + * of an inner code generation, in terms of the outer code generation + * AST build. + */ +__isl_give isl_ast_graft_list *isl_ast_graft_list_unembed( + __isl_take isl_ast_graft_list *list, int product) +{ + int i, n; + + n = isl_ast_graft_list_n_ast_graft(list); + for (i = 0; i < n; ++i) { + isl_ast_graft *graft; + + graft = isl_ast_graft_list_get_ast_graft(list, i); + graft = isl_ast_graft_unembed(graft, product); + list = isl_ast_graft_list_set_ast_graft(list, i, graft); + } + + return list; +} + +/* Compute the preimage of "graft" under the function represented by "ma". + * In other words, plug in "ma" in "enforced" and "guard" fields of "graft". + */ +__isl_give isl_ast_graft *isl_ast_graft_preimage_multi_aff( + __isl_take isl_ast_graft *graft, __isl_take isl_multi_aff *ma) +{ + isl_basic_set *enforced; + + if (!graft) + return NULL; + + enforced = graft->enforced; + graft->enforced = isl_basic_set_preimage_multi_aff(enforced, + isl_multi_aff_copy(ma)); + graft->guard = isl_set_preimage_multi_aff(graft->guard, ma); + + if (!graft->enforced || !graft->guard) + return isl_ast_graft_free(graft); + + return graft; +} + +/* Compute the preimage of all the grafts in "list" under + * the function represented by "ma". + */ +__isl_give isl_ast_graft_list *isl_ast_graft_list_preimage_multi_aff( + __isl_take isl_ast_graft_list *list, __isl_take isl_multi_aff *ma) +{ + int i, n; + + n = isl_ast_graft_list_n_ast_graft(list); + for (i = 0; i < n; ++i) { + isl_ast_graft *graft; + + graft = isl_ast_graft_list_get_ast_graft(list, i); + graft = isl_ast_graft_preimage_multi_aff(graft, + isl_multi_aff_copy(ma)); + list = isl_ast_graft_list_set_ast_graft(list, i, graft); + } + + isl_multi_aff_free(ma); + return list; +} + +/* Compare two grafts based on their guards. + */ +static int cmp_graft(__isl_keep isl_ast_graft *a, __isl_keep isl_ast_graft *b, + void *user) +{ + return isl_set_plain_cmp(a->guard, b->guard); +} + +/* Order the elements in "list" based on their guards. + */ +__isl_give isl_ast_graft_list *isl_ast_graft_list_sort_guard( + __isl_take isl_ast_graft_list *list) +{ + return isl_ast_graft_list_sort(list, &cmp_graft, NULL); +} + +/* Merge the given two lists into a single list of grafts, + * merging grafts with the same guard into a single graft. + * + * "list2" has been sorted using isl_ast_graft_list_sort. + * "list1" may be the result of a previous call to isl_ast_graft_list_merge + * and may therefore not be completely sorted. + * + * The elements in "list2" need to be executed after those in "list1", + * but if the guard of a graft in "list2" is disjoint from the guards + * of some final elements in "list1", then it can be moved up to before + * those final elements. + * + * In particular, we look at each element g of "list2" in turn + * and move it up beyond elements of "list1" that would be sorted + * after g as long as each of these elements has a guard that is disjoint + * from that of g. + * + * We do not allow the second or any later element of "list2" to be moved + * before a previous elements of "list2" even if the reason that + * that element didn't move up further was that its guard was not disjoint + * from that of the previous element in "list1". + */ +__isl_give isl_ast_graft_list *isl_ast_graft_list_merge( + __isl_take isl_ast_graft_list *list1, + __isl_take isl_ast_graft_list *list2, + __isl_keep isl_ast_build *build) +{ + int i, j, first; + + if (!list1 || !list2 || !build) + goto error; + if (list2->n == 0) { + isl_ast_graft_list_free(list2); + return list1; + } + if (list1->n == 0) { + isl_ast_graft_list_free(list1); + return list2; + } + + first = 0; + for (i = 0; i < list2->n; ++i) { + isl_ast_graft *graft; + graft = isl_ast_graft_list_get_ast_graft(list2, i); + if (!graft) + break; + + for (j = list1->n; j >= 0; --j) { + int cmp, disjoint; + isl_ast_graft *graft_j; + + if (j == first) + cmp = -1; + else + cmp = isl_set_plain_cmp(list1->p[j - 1]->guard, + graft->guard); + if (cmp > 0) { + disjoint = isl_set_is_disjoint(graft->guard, + list1->p[j - 1]->guard); + if (disjoint < 0) { + list1 = isl_ast_graft_list_free(list1); + break; + } + if (!disjoint) + cmp = -1; + } + if (cmp > 0) + continue; + if (cmp < 0) { + list1 = isl_ast_graft_list_insert(list1, j, + graft); + break; + } + + --j; + + graft_j = isl_ast_graft_list_get_ast_graft(list1, j); + graft_j = isl_ast_graft_fuse(graft_j, graft, build); + list1 = isl_ast_graft_list_set_ast_graft(list1, j, + graft_j); + break; + } + + if (j < 0) + isl_die(isl_ast_build_get_ctx(build), + isl_error_internal, + "element failed to get inserted", break); + + first = j + 1; + if (!list1) + break; + } + if (i < list2->n) + list1 = isl_ast_graft_list_free(list1); + isl_ast_graft_list_free(list2); + + return list1; +error: + isl_ast_graft_list_free(list1); + isl_ast_graft_list_free(list2); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_ast_graft(__isl_take isl_printer *p, + __isl_keep isl_ast_graft *graft) +{ + if (!p) + return NULL; + if (!graft) + return isl_printer_free(p); + + p = isl_printer_print_str(p, "("); + p = isl_printer_print_str(p, "guard: "); + p = isl_printer_print_set(p, graft->guard); + p = isl_printer_print_str(p, ", "); + p = isl_printer_print_str(p, "enforced: "); + p = isl_printer_print_basic_set(p, graft->enforced); + p = isl_printer_print_str(p, ", "); + p = isl_printer_print_str(p, "node: "); + p = isl_printer_print_ast_node(p, graft->node); + p = isl_printer_print_str(p, ")"); + + return p; +} Index: contrib/isl/isl_ast_graft_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_ast_graft_private.h @@ -0,0 +1,102 @@ +#ifndef ISL_AST_GRAFT_PRIVATE_H +#define ISL_AST_GRAFT_PRIVATE_H + +#include +#include +#include +#include + +struct isl_ast_graft; +typedef struct isl_ast_graft isl_ast_graft; + +/* Representation of part of an AST ("node") with some additional polyhedral + * information about the tree. + * + * "guard" contains conditions that should still be enforced by + * some ancestor of the current tree. In particular, the already + * generated tree assumes that these conditions hold, but may not + * have enforced them itself. + * The guard should not contain any unknown divs as it will be used + * to generate an if condition. + * + * "enforced" expresses constraints that are already enforced by the for + * nodes in the current tree and that therefore do not need to be enforced + * by any ancestor. + * The constraints only involve outer loop iterators. + */ +struct isl_ast_graft { + int ref; + + isl_ast_node *node; + + isl_set *guard; + isl_basic_set *enforced; +}; + +ISL_DECLARE_LIST(ast_graft) + +#undef EL +#define EL isl_ast_graft + +#include + +isl_ctx *isl_ast_graft_get_ctx(__isl_keep isl_ast_graft *graft); + +__isl_give isl_ast_graft *isl_ast_graft_alloc( + __isl_take isl_ast_node *node, __isl_keep isl_ast_build *build); +__isl_give isl_ast_graft *isl_ast_graft_alloc_from_children( + __isl_take isl_ast_graft_list *list, __isl_take isl_set *guard, + __isl_take isl_basic_set *enforced, __isl_keep isl_ast_build *build, + __isl_keep isl_ast_build *sub_build); +__isl_give isl_ast_graft_list *isl_ast_graft_list_fuse( + __isl_take isl_ast_graft_list *children, + __isl_keep isl_ast_build *build); +__isl_give isl_ast_graft *isl_ast_graft_alloc_domain( + __isl_take isl_map *schedule, __isl_keep isl_ast_build *build); +void *isl_ast_graft_free(__isl_take isl_ast_graft *graft); +__isl_give isl_ast_graft_list *isl_ast_graft_list_sort_guard( + __isl_take isl_ast_graft_list *list); + +__isl_give isl_ast_graft_list *isl_ast_graft_list_merge( + __isl_take isl_ast_graft_list *list1, + __isl_take isl_ast_graft_list *list2, + __isl_keep isl_ast_build *build); + +__isl_give isl_ast_node *isl_ast_graft_get_node( + __isl_keep isl_ast_graft *graft); +__isl_give isl_basic_set *isl_ast_graft_get_enforced( + __isl_keep isl_ast_graft *graft); +__isl_give isl_set *isl_ast_graft_get_guard(__isl_keep isl_ast_graft *graft); + +__isl_give isl_ast_graft *isl_ast_graft_insert_for( + __isl_take isl_ast_graft *graft, __isl_take isl_ast_node *node); +__isl_give isl_ast_graft *isl_ast_graft_add_guard( + __isl_take isl_ast_graft *graft, + __isl_take isl_set *guard, __isl_keep isl_ast_build *build); +__isl_give isl_ast_graft *isl_ast_graft_enforce( + __isl_take isl_ast_graft *graft, __isl_take isl_basic_set *enforced); + +__isl_give isl_ast_graft *isl_ast_graft_insert_mark( + __isl_take isl_ast_graft *graft, __isl_take isl_id *mark); + +__isl_give isl_ast_graft_list *isl_ast_graft_list_unembed( + __isl_take isl_ast_graft_list *list, int product); +__isl_give isl_ast_graft_list *isl_ast_graft_list_preimage_multi_aff( + __isl_take isl_ast_graft_list *list, __isl_take isl_multi_aff *ma); +__isl_give isl_ast_graft_list *isl_ast_graft_list_insert_pending_guard_nodes( + __isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build); + +__isl_give isl_ast_node *isl_ast_node_from_graft_list( + __isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build); + +__isl_give isl_basic_set *isl_ast_graft_list_extract_shared_enforced( + __isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build); +__isl_give isl_set *isl_ast_graft_list_extract_hoistable_guard( + __isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build); +__isl_give isl_ast_graft_list *isl_ast_graft_list_gist_guards( + __isl_take isl_ast_graft_list *list, __isl_take isl_set *context); + +__isl_give isl_printer *isl_printer_print_ast_graft(__isl_take isl_printer *p, + __isl_keep isl_ast_graft *graft); + +#endif Index: contrib/isl/isl_ast_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_ast_private.h @@ -0,0 +1,121 @@ +#ifndef ISL_AST_PRIVATE_H +#define ISL_AST_PRIVATE_H + +#include +#include +#include +#include +#include +#include + +/* An expression is either an integer, an identifier or an operation + * with zero or more arguments. + */ +struct isl_ast_expr { + int ref; + + isl_ctx *ctx; + + enum isl_ast_expr_type type; + + union { + isl_val *v; + isl_id *id; + struct { + enum isl_ast_op_type op; + unsigned n_arg; + isl_ast_expr **args; + } op; + } u; +}; + +#undef EL +#define EL isl_ast_expr + +#include + +__isl_give isl_ast_expr *isl_ast_expr_alloc_int_si(isl_ctx *ctx, int i); +__isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx, + enum isl_ast_op_type op, int n_arg); +__isl_give isl_ast_expr *isl_ast_expr_alloc_binary(enum isl_ast_op_type type, + __isl_take isl_ast_expr *expr1, __isl_take isl_ast_expr *expr2); + +#undef EL +#define EL isl_ast_node + +#include + +/* A node is either a block, an if, a for, a user node or a mark node. + * "else_node" is NULL if the if node does not have an else branch. + * "cond" and "inc" are NULL for degenerate for nodes. + * In case of a mark node, "mark" is the mark and "node" is the marked node. + */ +struct isl_ast_node { + int ref; + + isl_ctx *ctx; + enum isl_ast_node_type type; + + union { + struct { + isl_ast_node_list *children; + } b; + struct { + isl_ast_expr *guard; + isl_ast_node *then; + isl_ast_node *else_node; + } i; + struct { + unsigned degenerate : 1; + isl_ast_expr *iterator; + isl_ast_expr *init; + isl_ast_expr *cond; + isl_ast_expr *inc; + isl_ast_node *body; + } f; + struct { + isl_ast_expr *expr; + } e; + struct { + isl_id *mark; + isl_ast_node *node; + } m; + } u; + + isl_id *annotation; +}; + +__isl_give isl_ast_node *isl_ast_node_alloc_for(__isl_take isl_id *id); +__isl_give isl_ast_node *isl_ast_node_for_mark_degenerate( + __isl_take isl_ast_node *node); +__isl_give isl_ast_node *isl_ast_node_alloc_if(__isl_take isl_ast_expr *guard); +__isl_give isl_ast_node *isl_ast_node_alloc_block( + __isl_take isl_ast_node_list *list); +__isl_give isl_ast_node *isl_ast_node_alloc_mark(__isl_take isl_id *id, + __isl_take isl_ast_node *node); +__isl_give isl_ast_node *isl_ast_node_from_ast_node_list( + __isl_take isl_ast_node_list *list); +__isl_give isl_ast_node *isl_ast_node_for_set_body( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *body); +__isl_give isl_ast_node *isl_ast_node_if_set_then( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *child); + +struct isl_ast_print_options { + int ref; + isl_ctx *ctx; + + __isl_give isl_printer *(*print_for)(__isl_take isl_printer *p, + __isl_take isl_ast_print_options *options, + __isl_keep isl_ast_node *node, void *user); + void *print_for_user; + __isl_give isl_printer *(*print_user)(__isl_take isl_printer *p, + __isl_take isl_ast_print_options *options, + __isl_keep isl_ast_node *node, void *user); + void *print_user_user; +}; + +__isl_give isl_printer *isl_ast_node_list_print( + __isl_keep isl_ast_node_list *list, __isl_take isl_printer *p, + __isl_keep isl_ast_print_options *options); + +#endif Index: contrib/isl/isl_basis_reduction.h =================================================================== --- /dev/null +++ contrib/isl/isl_basis_reduction.h @@ -0,0 +1,27 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_BASIS_REDUCTION_H +#define ISL_BASIS_REDUCTION_H + +#include +#include +#include "isl_tab.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_tab *isl_tab_compute_reduced_basis(struct isl_tab *tab); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/isl_bernstein.h =================================================================== --- /dev/null +++ contrib/isl/isl_bernstein.h @@ -0,0 +1,5 @@ +#include + +isl_stat isl_qpolynomial_bound_on_domain_bernstein( + __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly, + struct isl_bound *bound); Index: contrib/isl/isl_bernstein.c =================================================================== --- /dev/null +++ contrib/isl/isl_bernstein.c @@ -0,0 +1,558 @@ +/* + * Copyright 2006-2007 Universiteit Leiden + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science, + * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands + * and 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bernstein_data { + enum isl_fold type; + isl_qpolynomial *poly; + int check_tight; + + isl_cell *cell; + + isl_qpolynomial_fold *fold; + isl_qpolynomial_fold *fold_tight; + isl_pw_qpolynomial_fold *pwf; + isl_pw_qpolynomial_fold *pwf_tight; +}; + +static int vertex_is_integral(__isl_keep isl_basic_set *vertex) +{ + unsigned nvar; + unsigned nparam; + int i; + + nvar = isl_basic_set_dim(vertex, isl_dim_set); + nparam = isl_basic_set_dim(vertex, isl_dim_param); + for (i = 0; i < nvar; ++i) { + int r = nvar - 1 - i; + if (!isl_int_is_one(vertex->eq[r][1 + nparam + i]) && + !isl_int_is_negone(vertex->eq[r][1 + nparam + i])) + return 0; + } + + return 1; +} + +static __isl_give isl_qpolynomial *vertex_coordinate( + __isl_keep isl_basic_set *vertex, int i, __isl_take isl_space *dim) +{ + unsigned nvar; + unsigned nparam; + int r; + isl_int denom; + isl_qpolynomial *v; + + nvar = isl_basic_set_dim(vertex, isl_dim_set); + nparam = isl_basic_set_dim(vertex, isl_dim_param); + r = nvar - 1 - i; + + isl_int_init(denom); + isl_int_set(denom, vertex->eq[r][1 + nparam + i]); + isl_assert(vertex->ctx, !isl_int_is_zero(denom), goto error); + + if (isl_int_is_pos(denom)) + isl_seq_neg(vertex->eq[r], vertex->eq[r], + 1 + isl_basic_set_total_dim(vertex)); + else + isl_int_neg(denom, denom); + + v = isl_qpolynomial_from_affine(dim, vertex->eq[r], denom); + isl_int_clear(denom); + + return v; +error: + isl_space_free(dim); + isl_int_clear(denom); + return NULL; +} + +/* Check whether the bound associated to the selection "k" is tight, + * which is the case if we select exactly one vertex and if that vertex + * is integral for all values of the parameters. + */ +static int is_tight(int *k, int n, int d, isl_cell *cell) +{ + int i; + + for (i = 0; i < n; ++i) { + int v; + if (k[i] != d) { + if (k[i]) + return 0; + continue; + } + v = cell->ids[n - 1 - i]; + return vertex_is_integral(cell->vertices->v[v].vertex); + } + + return 0; +} + +static void add_fold(__isl_take isl_qpolynomial *b, __isl_keep isl_set *dom, + int *k, int n, int d, struct bernstein_data *data) +{ + isl_qpolynomial_fold *fold; + + fold = isl_qpolynomial_fold_alloc(data->type, b); + + if (data->check_tight && is_tight(k, n, d, data->cell)) + data->fold_tight = isl_qpolynomial_fold_fold_on_domain(dom, + data->fold_tight, fold); + else + data->fold = isl_qpolynomial_fold_fold_on_domain(dom, + data->fold, fold); +} + +/* Extract the coefficients of the Bernstein base polynomials and store + * them in data->fold and data->fold_tight. + * + * In particular, the coefficient of each monomial + * of multi-degree (k[0], k[1], ..., k[n-1]) is divided by the corresponding + * multinomial coefficient d!/k[0]! k[1]! ... k[n-1]! + * + * c[i] contains the coefficient of the selected powers of the first i+1 vars. + * multinom[i] contains the partial multinomial coefficient. + */ +static void extract_coefficients(isl_qpolynomial *poly, + __isl_keep isl_set *dom, struct bernstein_data *data) +{ + int i; + int d; + int n; + isl_ctx *ctx; + isl_qpolynomial **c = NULL; + int *k = NULL; + int *left = NULL; + isl_vec *multinom = NULL; + + if (!poly) + return; + + ctx = isl_qpolynomial_get_ctx(poly); + n = isl_qpolynomial_dim(poly, isl_dim_in); + d = isl_qpolynomial_degree(poly); + isl_assert(ctx, n >= 2, return); + + c = isl_calloc_array(ctx, isl_qpolynomial *, n); + k = isl_alloc_array(ctx, int, n); + left = isl_alloc_array(ctx, int, n); + multinom = isl_vec_alloc(ctx, n); + if (!c || !k || !left || !multinom) + goto error; + + isl_int_set_si(multinom->el[0], 1); + for (k[0] = d; k[0] >= 0; --k[0]) { + int i = 1; + isl_qpolynomial_free(c[0]); + c[0] = isl_qpolynomial_coeff(poly, isl_dim_in, n - 1, k[0]); + left[0] = d - k[0]; + k[1] = -1; + isl_int_set(multinom->el[1], multinom->el[0]); + while (i > 0) { + if (i == n - 1) { + int j; + isl_space *dim; + isl_qpolynomial *b; + isl_qpolynomial *f; + for (j = 2; j <= left[i - 1]; ++j) + isl_int_divexact_ui(multinom->el[i], + multinom->el[i], j); + b = isl_qpolynomial_coeff(c[i - 1], isl_dim_in, + n - 1 - i, left[i - 1]); + b = isl_qpolynomial_project_domain_on_params(b); + dim = isl_qpolynomial_get_domain_space(b); + f = isl_qpolynomial_rat_cst_on_domain(dim, ctx->one, + multinom->el[i]); + b = isl_qpolynomial_mul(b, f); + k[n - 1] = left[n - 2]; + add_fold(b, dom, k, n, d, data); + --i; + continue; + } + if (k[i] >= left[i - 1]) { + --i; + continue; + } + ++k[i]; + if (k[i]) + isl_int_divexact_ui(multinom->el[i], + multinom->el[i], k[i]); + isl_qpolynomial_free(c[i]); + c[i] = isl_qpolynomial_coeff(c[i - 1], isl_dim_in, + n - 1 - i, k[i]); + left[i] = left[i - 1] - k[i]; + k[i + 1] = -1; + isl_int_set(multinom->el[i + 1], multinom->el[i]); + ++i; + } + isl_int_mul_ui(multinom->el[0], multinom->el[0], k[0]); + } + + for (i = 0; i < n; ++i) + isl_qpolynomial_free(c[i]); + + isl_vec_free(multinom); + free(left); + free(k); + free(c); + return; +error: + isl_vec_free(multinom); + free(left); + free(k); + if (c) + for (i = 0; i < n; ++i) + isl_qpolynomial_free(c[i]); + free(c); + return; +} + +/* Perform bernstein expansion on the parametric vertices that are active + * on "cell". + * + * data->poly has been homogenized in the calling function. + * + * We plug in the barycentric coordinates for the set variables + * + * \vec x = \sum_i \alpha_i v_i(\vec p) + * + * and the constant "1 = \sum_i \alpha_i" for the homogeneous dimension. + * Next, we extract the coefficients of the Bernstein base polynomials. + */ +static isl_stat bernstein_coefficients_cell(__isl_take isl_cell *cell, + void *user) +{ + int i, j; + struct bernstein_data *data = (struct bernstein_data *)user; + isl_space *dim_param; + isl_space *dim_dst; + isl_qpolynomial *poly = data->poly; + unsigned nvar; + int n_vertices; + isl_qpolynomial **subs; + isl_pw_qpolynomial_fold *pwf; + isl_set *dom; + isl_ctx *ctx; + + if (!poly) + goto error; + + nvar = isl_qpolynomial_dim(poly, isl_dim_in) - 1; + n_vertices = cell->n_vertices; + + ctx = isl_qpolynomial_get_ctx(poly); + if (n_vertices > nvar + 1 && ctx->opt->bernstein_triangulate) + return isl_cell_foreach_simplex(cell, + &bernstein_coefficients_cell, user); + + subs = isl_alloc_array(ctx, isl_qpolynomial *, 1 + nvar); + if (!subs) + goto error; + + dim_param = isl_basic_set_get_space(cell->dom); + dim_dst = isl_qpolynomial_get_domain_space(poly); + dim_dst = isl_space_add_dims(dim_dst, isl_dim_set, n_vertices); + + for (i = 0; i < 1 + nvar; ++i) + subs[i] = isl_qpolynomial_zero_on_domain(isl_space_copy(dim_dst)); + + for (i = 0; i < n_vertices; ++i) { + isl_qpolynomial *c; + c = isl_qpolynomial_var_on_domain(isl_space_copy(dim_dst), isl_dim_set, + 1 + nvar + i); + for (j = 0; j < nvar; ++j) { + int k = cell->ids[i]; + isl_qpolynomial *v; + v = vertex_coordinate(cell->vertices->v[k].vertex, j, + isl_space_copy(dim_param)); + v = isl_qpolynomial_add_dims(v, isl_dim_in, + 1 + nvar + n_vertices); + v = isl_qpolynomial_mul(v, isl_qpolynomial_copy(c)); + subs[1 + j] = isl_qpolynomial_add(subs[1 + j], v); + } + subs[0] = isl_qpolynomial_add(subs[0], c); + } + isl_space_free(dim_dst); + + poly = isl_qpolynomial_copy(poly); + + poly = isl_qpolynomial_add_dims(poly, isl_dim_in, n_vertices); + poly = isl_qpolynomial_substitute(poly, isl_dim_in, 0, 1 + nvar, subs); + poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, 0, 1 + nvar); + + data->cell = cell; + dom = isl_set_from_basic_set(isl_basic_set_copy(cell->dom)); + data->fold = isl_qpolynomial_fold_empty(data->type, isl_space_copy(dim_param)); + data->fold_tight = isl_qpolynomial_fold_empty(data->type, dim_param); + extract_coefficients(poly, dom, data); + + pwf = isl_pw_qpolynomial_fold_alloc(data->type, isl_set_copy(dom), + data->fold); + data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, pwf); + pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, data->fold_tight); + data->pwf_tight = isl_pw_qpolynomial_fold_fold(data->pwf_tight, pwf); + + isl_qpolynomial_free(poly); + isl_cell_free(cell); + for (i = 0; i < 1 + nvar; ++i) + isl_qpolynomial_free(subs[i]); + free(subs); + return isl_stat_ok; +error: + isl_cell_free(cell); + return isl_stat_error; +} + +/* Base case of applying bernstein expansion. + * + * We compute the chamber decomposition of the parametric polytope "bset" + * and then perform bernstein expansion on the parametric vertices + * that are active on each chamber. + */ +static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_base( + __isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight) +{ + unsigned nvar; + isl_space *dim; + isl_pw_qpolynomial_fold *pwf; + isl_vertices *vertices; + int covers; + + nvar = isl_basic_set_dim(bset, isl_dim_set); + if (nvar == 0) { + isl_set *dom; + isl_qpolynomial_fold *fold; + + fold = isl_qpolynomial_fold_alloc(data->type, poly); + dom = isl_set_from_basic_set(bset); + if (tight) + *tight = 1; + pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, fold); + return isl_pw_qpolynomial_fold_project_domain_on_params(pwf); + } + + if (isl_qpolynomial_is_zero(poly)) { + isl_set *dom; + isl_qpolynomial_fold *fold; + fold = isl_qpolynomial_fold_alloc(data->type, poly); + dom = isl_set_from_basic_set(bset); + pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, fold); + if (tight) + *tight = 1; + return isl_pw_qpolynomial_fold_project_domain_on_params(pwf); + } + + dim = isl_basic_set_get_space(bset); + dim = isl_space_params(dim); + dim = isl_space_from_domain(dim); + dim = isl_space_add_dims(dim, isl_dim_set, 1); + data->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(dim), data->type); + data->pwf_tight = isl_pw_qpolynomial_fold_zero(dim, data->type); + data->poly = isl_qpolynomial_homogenize(isl_qpolynomial_copy(poly)); + vertices = isl_basic_set_compute_vertices(bset); + if (isl_vertices_foreach_disjoint_cell(vertices, + &bernstein_coefficients_cell, data) < 0) + data->pwf = isl_pw_qpolynomial_fold_free(data->pwf); + isl_vertices_free(vertices); + isl_qpolynomial_free(data->poly); + + isl_basic_set_free(bset); + isl_qpolynomial_free(poly); + + covers = isl_pw_qpolynomial_fold_covers(data->pwf_tight, data->pwf); + if (covers < 0) + goto error; + + if (tight) + *tight = covers; + + if (covers) { + isl_pw_qpolynomial_fold_free(data->pwf); + return data->pwf_tight; + } + + data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, data->pwf_tight); + + return data->pwf; +error: + isl_pw_qpolynomial_fold_free(data->pwf_tight); + isl_pw_qpolynomial_fold_free(data->pwf); + return NULL; +} + +/* Apply bernstein expansion recursively by working in on len[i] + * set variables at a time, with i ranging from n_group - 1 to 0. + */ +static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_recursive( + __isl_take isl_pw_qpolynomial *pwqp, + int n_group, int *len, struct bernstein_data *data, int *tight) +{ + int i; + unsigned nparam; + unsigned nvar; + isl_pw_qpolynomial_fold *pwf; + + if (!pwqp) + return NULL; + + nparam = isl_pw_qpolynomial_dim(pwqp, isl_dim_param); + nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_in); + + pwqp = isl_pw_qpolynomial_move_dims(pwqp, isl_dim_param, nparam, + isl_dim_in, 0, nvar - len[n_group - 1]); + pwf = isl_pw_qpolynomial_bound(pwqp, data->type, tight); + + for (i = n_group - 2; i >= 0; --i) { + nparam = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_param); + pwf = isl_pw_qpolynomial_fold_move_dims(pwf, isl_dim_in, 0, + isl_dim_param, nparam - len[i], len[i]); + if (tight && !*tight) + tight = NULL; + pwf = isl_pw_qpolynomial_fold_bound(pwf, tight); + } + + return pwf; +} + +static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_factors( + __isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight) +{ + isl_factorizer *f; + isl_set *set; + isl_pw_qpolynomial *pwqp; + isl_pw_qpolynomial_fold *pwf; + + f = isl_basic_set_factorizer(bset); + if (!f) + goto error; + if (f->n_group == 0) { + isl_factorizer_free(f); + return bernstein_coefficients_base(bset, poly, data, tight); + } + + set = isl_set_from_basic_set(bset); + pwqp = isl_pw_qpolynomial_alloc(set, poly); + pwqp = isl_pw_qpolynomial_morph_domain(pwqp, isl_morph_copy(f->morph)); + + pwf = bernstein_coefficients_recursive(pwqp, f->n_group, f->len, data, + tight); + + isl_factorizer_free(f); + + return pwf; +error: + isl_basic_set_free(bset); + isl_qpolynomial_free(poly); + return NULL; +} + +static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_full_recursive( + __isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight) +{ + int i; + int *len; + unsigned nvar; + isl_pw_qpolynomial_fold *pwf; + isl_set *set; + isl_pw_qpolynomial *pwqp; + + if (!bset || !poly) + goto error; + + nvar = isl_basic_set_dim(bset, isl_dim_set); + + len = isl_alloc_array(bset->ctx, int, nvar); + if (nvar && !len) + goto error; + + for (i = 0; i < nvar; ++i) + len[i] = 1; + + set = isl_set_from_basic_set(bset); + pwqp = isl_pw_qpolynomial_alloc(set, poly); + + pwf = bernstein_coefficients_recursive(pwqp, nvar, len, data, tight); + + free(len); + + return pwf; +error: + isl_basic_set_free(bset); + isl_qpolynomial_free(poly); + return NULL; +} + +/* Compute a bound on the polynomial defined over the parametric polytope + * using bernstein expansion and store the result + * in bound->pwf and bound->pwf_tight. + * + * If bernstein_recurse is set to ISL_BERNSTEIN_FACTORS, we check if + * the polytope can be factorized and apply bernstein expansion recursively + * on the factors. + * If bernstein_recurse is set to ISL_BERNSTEIN_INTERVALS, we apply + * bernstein expansion recursively on each dimension. + * Otherwise, we apply bernstein expansion on the entire polytope. + */ +isl_stat isl_qpolynomial_bound_on_domain_bernstein( + __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly, + struct isl_bound *bound) +{ + struct bernstein_data data; + isl_pw_qpolynomial_fold *pwf; + unsigned nvar; + int tight = 0; + int *tp = bound->check_tight ? &tight : NULL; + + if (!bset || !poly) + goto error; + + data.type = bound->type; + data.check_tight = bound->check_tight; + + nvar = isl_basic_set_dim(bset, isl_dim_set); + + if (bset->ctx->opt->bernstein_recurse & ISL_BERNSTEIN_FACTORS) + pwf = bernstein_coefficients_factors(bset, poly, &data, tp); + else if (nvar > 1 && + (bset->ctx->opt->bernstein_recurse & ISL_BERNSTEIN_INTERVALS)) + pwf = bernstein_coefficients_full_recursive(bset, poly, &data, tp); + else + pwf = bernstein_coefficients_base(bset, poly, &data, tp); + + if (tight) + bound->pwf_tight = isl_pw_qpolynomial_fold_fold(bound->pwf_tight, pwf); + else + bound->pwf = isl_pw_qpolynomial_fold_fold(bound->pwf, pwf); + + return isl_stat_ok; +error: + isl_basic_set_free(bset); + isl_qpolynomial_free(poly); + return isl_stat_error; +} Index: contrib/isl/isl_blk.h =================================================================== --- /dev/null +++ contrib/isl/isl_blk.h @@ -0,0 +1,40 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_BLK_H +#define ISL_BLK_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_blk { + size_t size; + isl_int *data; +}; + +#define ISL_BLK_CACHE_SIZE 20 + +struct isl_ctx; + +struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n); +struct isl_blk isl_blk_empty(void); +int isl_blk_is_error(struct isl_blk block); +struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block, + size_t new_n); +void isl_blk_free(struct isl_ctx *ctx, struct isl_blk block); +void isl_blk_clear_cache(struct isl_ctx *ctx); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/isl_blk.c =================================================================== --- /dev/null +++ contrib/isl/isl_blk.c @@ -0,0 +1,134 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include + +/* 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; + block.size = 0; + block.data = NULL; + return block; +} + +static int isl_blk_is_empty(struct isl_blk block) +{ + return block.size == 0 && block.data == NULL; +} + +static struct isl_blk isl_blk_error() +{ + struct isl_blk block; + block.size = -1; + block.data = NULL; + return block; +} + +int isl_blk_is_error(struct isl_blk block) +{ + return block.size == -1 && block.data == NULL; +} + +static void isl_blk_free_force(struct isl_ctx *ctx, struct isl_blk block) +{ + int i; + + for (i = 0; i < block.size; ++i) + isl_int_clear(block.data[i]); + free(block.data); +} + +static struct isl_blk extend(struct isl_ctx *ctx, struct isl_blk block, + size_t new_n) +{ + int i; + isl_int *p; + + if (block.size >= new_n) + return block; + + p = isl_realloc_array(ctx, block.data, isl_int, new_n); + if (!p) { + isl_blk_free_force(ctx, block); + return isl_blk_error(); + } + block.data = p; + + for (i = block.size; i < new_n; ++i) + isl_int_init(block.data[i]); + block.size = new_n; + + return block; +} + +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)) + return; + + if (ctx->n_cached < ISL_BLK_CACHE_SIZE) + ctx->cache[ctx->n_cached++] = block; + else + isl_blk_free_force(ctx, block); +} + +void isl_blk_clear_cache(struct isl_ctx *ctx) +{ + int i; + + for (i = 0; i < ctx->n_cached; ++i) + isl_blk_free_force(ctx, ctx->cache[i]); + ctx->n_cached = 0; +} Index: contrib/isl/isl_bound.h =================================================================== --- /dev/null +++ contrib/isl/isl_bound.h @@ -0,0 +1,20 @@ +#ifndef ISL_BOUND_H +#define ISL_BOUND_H + +#include + +struct isl_bound { + /* input */ + int check_tight; + int wrapping; + enum isl_fold type; + isl_space *dim; + isl_basic_set *bset; + isl_qpolynomial_fold *fold; + + /* output */ + isl_pw_qpolynomial_fold *pwf; + isl_pw_qpolynomial_fold *pwf_tight; +}; + +#endif Index: contrib/isl/isl_bound.c =================================================================== --- /dev/null +++ contrib/isl/isl_bound.c @@ -0,0 +1,331 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Compute a bound on the polynomial defined over the parametric polytope + * using either range propagation or bernstein expansion and + * store the result in bound->pwf and bound->pwf_tight. + * Since bernstein expansion requires bounded domains, we apply + * range propagation on unbounded domains. Otherwise, we respect the choice + * of the user. + */ +static isl_stat compressed_guarded_poly_bound(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, void *user) +{ + struct isl_bound *bound = (struct isl_bound *)user; + int bounded; + + if (!bset || !poly) + goto error; + + if (bset->ctx->opt->bound == ISL_BOUND_RANGE) + return isl_qpolynomial_bound_on_domain_range(bset, poly, bound); + + bounded = isl_basic_set_is_bounded(bset); + if (bounded < 0) + goto error; + if (bounded) + return isl_qpolynomial_bound_on_domain_bernstein(bset, poly, bound); + else + return isl_qpolynomial_bound_on_domain_range(bset, poly, bound); +error: + isl_basic_set_free(bset); + isl_qpolynomial_free(poly); + return -1; +} + +static isl_stat unwrapped_guarded_poly_bound(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, void *user) +{ + struct isl_bound *bound = (struct isl_bound *)user; + isl_pw_qpolynomial_fold *top_pwf; + isl_pw_qpolynomial_fold *top_pwf_tight; + isl_space *dim; + isl_morph *morph; + isl_stat r; + + bset = isl_basic_set_detect_equalities(bset); + + if (!bset) + goto error; + + if (bset->n_eq == 0) + return compressed_guarded_poly_bound(bset, poly, user); + + morph = isl_basic_set_full_compression(bset); + + bset = isl_morph_basic_set(isl_morph_copy(morph), bset); + poly = isl_qpolynomial_morph_domain(poly, isl_morph_copy(morph)); + + dim = isl_morph_get_ran_space(morph); + dim = isl_space_params(dim); + + top_pwf = bound->pwf; + top_pwf_tight = bound->pwf_tight; + + dim = isl_space_from_domain(dim); + dim = isl_space_add_dims(dim, isl_dim_out, 1); + bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(dim), + bound->type); + bound->pwf_tight = isl_pw_qpolynomial_fold_zero(dim, bound->type); + + r = compressed_guarded_poly_bound(bset, poly, user); + + morph = isl_morph_dom_params(morph); + morph = isl_morph_ran_params(morph); + morph = isl_morph_inverse(morph); + + bound->pwf = isl_pw_qpolynomial_fold_morph_domain(bound->pwf, + isl_morph_copy(morph)); + bound->pwf_tight = isl_pw_qpolynomial_fold_morph_domain( + bound->pwf_tight, morph); + + bound->pwf = isl_pw_qpolynomial_fold_fold(top_pwf, bound->pwf); + bound->pwf_tight = isl_pw_qpolynomial_fold_fold(top_pwf_tight, + bound->pwf_tight); + + return r; +error: + isl_basic_set_free(bset); + isl_qpolynomial_free(poly); + return isl_stat_error; +} + +static isl_stat guarded_poly_bound(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, void *user) +{ + struct isl_bound *bound = (struct isl_bound *)user; + isl_space *dim; + isl_pw_qpolynomial_fold *top_pwf; + isl_pw_qpolynomial_fold *top_pwf_tight; + int nparam; + int n_in; + isl_stat r; + + if (!bound->wrapping) + return unwrapped_guarded_poly_bound(bset, poly, user); + + nparam = isl_space_dim(bound->dim, isl_dim_param); + n_in = isl_space_dim(bound->dim, isl_dim_in); + + bset = isl_basic_set_move_dims(bset, isl_dim_param, nparam, + isl_dim_set, 0, n_in); + poly = isl_qpolynomial_move_dims(poly, isl_dim_param, nparam, + isl_dim_in, 0, n_in); + + dim = isl_basic_set_get_space(bset); + dim = isl_space_params(dim); + + top_pwf = bound->pwf; + top_pwf_tight = bound->pwf_tight; + + dim = isl_space_from_domain(dim); + dim = isl_space_add_dims(dim, isl_dim_out, 1); + bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(dim), + bound->type); + bound->pwf_tight = isl_pw_qpolynomial_fold_zero(dim, bound->type); + + r = unwrapped_guarded_poly_bound(bset, poly, user); + + bound->pwf = isl_pw_qpolynomial_fold_reset_space(bound->pwf, + isl_space_copy(bound->dim)); + bound->pwf_tight = isl_pw_qpolynomial_fold_reset_space(bound->pwf_tight, + isl_space_copy(bound->dim)); + + bound->pwf = isl_pw_qpolynomial_fold_fold(top_pwf, bound->pwf); + bound->pwf_tight = isl_pw_qpolynomial_fold_fold(top_pwf_tight, + bound->pwf_tight); + + return r; +} + +static isl_stat guarded_qp(__isl_take isl_qpolynomial *qp, void *user) +{ + struct isl_bound *bound = (struct isl_bound *)user; + isl_stat r; + + r = isl_qpolynomial_as_polynomial_on_domain(qp, bound->bset, + &guarded_poly_bound, user); + isl_qpolynomial_free(qp); + return r; +} + +static isl_stat basic_guarded_fold(__isl_take isl_basic_set *bset, void *user) +{ + struct isl_bound *bound = (struct isl_bound *)user; + isl_stat r; + + bound->bset = bset; + r = isl_qpolynomial_fold_foreach_qpolynomial(bound->fold, + &guarded_qp, user); + isl_basic_set_free(bset); + return r; +} + +static isl_stat guarded_fold(__isl_take isl_set *set, + __isl_take isl_qpolynomial_fold *fold, void *user) +{ + struct isl_bound *bound = (struct isl_bound *)user; + + if (!set || !fold) + goto error; + + set = isl_set_make_disjoint(set); + + bound->fold = fold; + bound->type = isl_qpolynomial_fold_get_type(fold); + + if (isl_set_foreach_basic_set(set, &basic_guarded_fold, bound) < 0) + goto error; + + isl_set_free(set); + isl_qpolynomial_fold_free(fold); + + return isl_stat_ok; +error: + isl_set_free(set); + isl_qpolynomial_fold_free(fold); + return isl_stat_error; +} + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_bound( + __isl_take isl_pw_qpolynomial_fold *pwf, int *tight) +{ + unsigned nvar; + struct isl_bound bound; + int covers; + + if (!pwf) + return NULL; + + bound.dim = isl_pw_qpolynomial_fold_get_domain_space(pwf); + + bound.wrapping = isl_space_is_wrapping(bound.dim); + if (bound.wrapping) + bound.dim = isl_space_unwrap(bound.dim); + nvar = isl_space_dim(bound.dim, isl_dim_out); + bound.dim = isl_space_domain(bound.dim); + bound.dim = isl_space_from_domain(bound.dim); + bound.dim = isl_space_add_dims(bound.dim, isl_dim_out, 1); + + if (nvar == 0) { + if (tight) + *tight = 1; + return isl_pw_qpolynomial_fold_reset_space(pwf, bound.dim); + } + + if (isl_pw_qpolynomial_fold_is_zero(pwf)) { + enum isl_fold type = pwf->type; + isl_pw_qpolynomial_fold_free(pwf); + if (tight) + *tight = 1; + return isl_pw_qpolynomial_fold_zero(bound.dim, type); + } + + bound.pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim), + pwf->type); + bound.pwf_tight = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim), + pwf->type); + bound.check_tight = !!tight; + + if (isl_pw_qpolynomial_fold_foreach_lifted_piece(pwf, + guarded_fold, &bound) < 0) + goto error; + + covers = isl_pw_qpolynomial_fold_covers(bound.pwf_tight, bound.pwf); + if (covers < 0) + goto error; + + if (tight) + *tight = covers; + + isl_space_free(bound.dim); + isl_pw_qpolynomial_fold_free(pwf); + + if (covers) { + isl_pw_qpolynomial_fold_free(bound.pwf); + return bound.pwf_tight; + } + + bound.pwf = isl_pw_qpolynomial_fold_fold(bound.pwf, bound.pwf_tight); + + return bound.pwf; +error: + isl_pw_qpolynomial_fold_free(bound.pwf_tight); + isl_pw_qpolynomial_fold_free(bound.pwf); + isl_pw_qpolynomial_fold_free(pwf); + isl_space_free(bound.dim); + return NULL; +} + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_bound( + __isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type, int *tight) +{ + isl_pw_qpolynomial_fold *pwf; + + pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(type, pwqp); + return isl_pw_qpolynomial_fold_bound(pwf, tight); +} + +struct isl_union_bound_data { + enum isl_fold type; + int tight; + isl_union_pw_qpolynomial_fold *res; +}; + +static isl_stat bound_pw(__isl_take isl_pw_qpolynomial *pwqp, void *user) +{ + struct isl_union_bound_data *data = user; + isl_pw_qpolynomial_fold *pwf; + + pwf = isl_pw_qpolynomial_bound(pwqp, data->type, + data->tight ? &data->tight : NULL); + data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( + data->res, pwf); + + return isl_stat_ok; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_bound( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_fold type, int *tight) +{ + isl_space *dim; + struct isl_union_bound_data data = { type, 1, NULL }; + + if (!upwqp) + return NULL; + + if (!tight) + data.tight = 0; + + dim = isl_union_pw_qpolynomial_get_space(upwqp); + data.res = isl_union_pw_qpolynomial_fold_zero(dim, type); + if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, + &bound_pw, &data) < 0) + goto error; + + isl_union_pw_qpolynomial_free(upwqp); + if (tight) + *tight = data.tight; + + return data.res; +error: + isl_union_pw_qpolynomial_free(upwqp); + isl_union_pw_qpolynomial_fold_free(data.res); + return NULL; +} Index: contrib/isl/isl_coalesce.c =================================================================== --- /dev/null +++ contrib/isl/isl_coalesce.c @@ -0,0 +1,3927 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * Copyright 2016 INRIA Paris + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12, + * CS 42112, 75589 Paris Cedex 12, France + */ + +#include +#include "isl_map_private.h" +#include +#include +#include "isl_tab.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define STATUS_ERROR -1 +#define STATUS_REDUNDANT 1 +#define STATUS_VALID 2 +#define STATUS_SEPARATE 3 +#define STATUS_CUT 4 +#define STATUS_ADJ_EQ 5 +#define STATUS_ADJ_INEQ 6 + +static int status_in(isl_int *ineq, struct isl_tab *tab) +{ + enum isl_ineq_type type = isl_tab_ineq_type(tab, ineq); + switch (type) { + default: + case isl_ineq_error: return STATUS_ERROR; + case isl_ineq_redundant: return STATUS_VALID; + case isl_ineq_separate: return STATUS_SEPARATE; + case isl_ineq_cut: return STATUS_CUT; + case isl_ineq_adj_eq: return STATUS_ADJ_EQ; + case isl_ineq_adj_ineq: return STATUS_ADJ_INEQ; + } +} + +/* Compute the position of the equalities of basic map "bmap_i" + * with respect to the basic map represented by "tab_j". + * The resulting array has twice as many entries as the number + * of equalities corresponding to the two inequalities to which + * each equality corresponds. + */ +static int *eq_status_in(__isl_keep isl_basic_map *bmap_i, + struct isl_tab *tab_j) +{ + int k, l; + int *eq = isl_calloc_array(bmap_i->ctx, int, 2 * bmap_i->n_eq); + unsigned dim; + + if (!eq) + return NULL; + + dim = isl_basic_map_total_dim(bmap_i); + for (k = 0; k < bmap_i->n_eq; ++k) { + for (l = 0; l < 2; ++l) { + isl_seq_neg(bmap_i->eq[k], bmap_i->eq[k], 1+dim); + eq[2 * k + l] = status_in(bmap_i->eq[k], tab_j); + if (eq[2 * k + l] == STATUS_ERROR) + goto error; + } + } + + return eq; +error: + free(eq); + return NULL; +} + +/* Compute the position of the inequalities of basic map "bmap_i" + * (also represented by "tab_i", if not NULL) with respect to the basic map + * represented by "tab_j". + */ +static int *ineq_status_in(__isl_keep isl_basic_map *bmap_i, + struct isl_tab *tab_i, struct isl_tab *tab_j) +{ + int k; + unsigned n_eq = bmap_i->n_eq; + int *ineq = isl_calloc_array(bmap_i->ctx, int, bmap_i->n_ineq); + + if (!ineq) + return NULL; + + for (k = 0; k < bmap_i->n_ineq; ++k) { + if (tab_i && isl_tab_is_redundant(tab_i, n_eq + k)) { + ineq[k] = STATUS_REDUNDANT; + continue; + } + ineq[k] = status_in(bmap_i->ineq[k], tab_j); + if (ineq[k] == STATUS_ERROR) + goto error; + if (ineq[k] == STATUS_SEPARATE) + break; + } + + return ineq; +error: + free(ineq); + return NULL; +} + +static int any(int *con, unsigned len, int status) +{ + int i; + + for (i = 0; i < len ; ++i) + if (con[i] == status) + return 1; + return 0; +} + +/* Return the first position of "status" in the list "con" of length "len". + * Return -1 if there is no such entry. + */ +static int find(int *con, unsigned len, int status) +{ + int i; + + for (i = 0; i < len ; ++i) + if (con[i] == status) + return i; + return -1; +} + +static int count(int *con, unsigned len, int status) +{ + int i; + int c = 0; + + for (i = 0; i < len ; ++i) + if (con[i] == status) + c++; + return c; +} + +static int all(int *con, unsigned len, int status) +{ + int i; + + for (i = 0; i < len ; ++i) { + if (con[i] == STATUS_REDUNDANT) + continue; + if (con[i] != status) + return 0; + } + return 1; +} + +/* Internal information associated to a basic map in a map + * that is to be coalesced by isl_map_coalesce. + * + * "bmap" is the basic map itself (or NULL if "removed" is set) + * "tab" is the corresponding tableau (or NULL if "removed" is set) + * "hull_hash" identifies the affine space in which "bmap" lives. + * "removed" is set if this basic map has been removed from the map + * "simplify" is set if this basic map may have some unknown integer + * divisions that were not present in the input basic maps. The basic + * map should then be simplified such that we may be able to find + * a definition among the constraints. + * + * "eq" and "ineq" are only set if we are currently trying to coalesce + * this basic map with another basic map, in which case they represent + * the position of the inequalities of this basic map with respect to + * the other basic map. The number of elements in the "eq" array + * is twice the number of equalities in the "bmap", corresponding + * to the two inequalities that make up each equality. + */ +struct isl_coalesce_info { + isl_basic_map *bmap; + struct isl_tab *tab; + uint32_t hull_hash; + int removed; + int simplify; + int *eq; + int *ineq; +}; + +/* Is there any (half of an) equality constraint in the description + * of the basic map represented by "info" that + * has position "status" with respect to the other basic map? + */ +static int any_eq(struct isl_coalesce_info *info, int status) +{ + unsigned n_eq; + + n_eq = isl_basic_map_n_equality(info->bmap); + return any(info->eq, 2 * n_eq, status); +} + +/* Is there any inequality constraint in the description + * of the basic map represented by "info" that + * has position "status" with respect to the other basic map? + */ +static int any_ineq(struct isl_coalesce_info *info, int status) +{ + unsigned n_ineq; + + n_ineq = isl_basic_map_n_inequality(info->bmap); + return any(info->ineq, n_ineq, status); +} + +/* Return the position of the first half on an equality constraint + * in the description of the basic map represented by "info" that + * has position "status" with respect to the other basic map. + * The returned value is twice the position of the equality constraint + * plus zero for the negative half and plus one for the positive half. + * Return -1 if there is no such entry. + */ +static int find_eq(struct isl_coalesce_info *info, int status) +{ + unsigned n_eq; + + n_eq = isl_basic_map_n_equality(info->bmap); + return find(info->eq, 2 * n_eq, status); +} + +/* Return the position of the first inequality constraint in the description + * of the basic map represented by "info" that + * has position "status" with respect to the other basic map. + * Return -1 if there is no such entry. + */ +static int find_ineq(struct isl_coalesce_info *info, int status) +{ + unsigned n_ineq; + + n_ineq = isl_basic_map_n_inequality(info->bmap); + return find(info->ineq, n_ineq, status); +} + +/* Return the number of (halves of) equality constraints in the description + * of the basic map represented by "info" that + * have position "status" with respect to the other basic map. + */ +static int count_eq(struct isl_coalesce_info *info, int status) +{ + unsigned n_eq; + + n_eq = isl_basic_map_n_equality(info->bmap); + return count(info->eq, 2 * n_eq, status); +} + +/* Return the number of inequality constraints in the description + * of the basic map represented by "info" that + * have position "status" with respect to the other basic map. + */ +static int count_ineq(struct isl_coalesce_info *info, int status) +{ + unsigned n_ineq; + + n_ineq = isl_basic_map_n_inequality(info->bmap); + return count(info->ineq, n_ineq, status); +} + +/* Are all non-redundant constraints of the basic map represented by "info" + * either valid or cut constraints with respect to the other basic map? + */ +static int all_valid_or_cut(struct isl_coalesce_info *info) +{ + int i; + + for (i = 0; i < 2 * info->bmap->n_eq; ++i) { + if (info->eq[i] == STATUS_REDUNDANT) + continue; + if (info->eq[i] == STATUS_VALID) + continue; + if (info->eq[i] == STATUS_CUT) + continue; + return 0; + } + + for (i = 0; i < info->bmap->n_ineq; ++i) { + if (info->ineq[i] == STATUS_REDUNDANT) + continue; + if (info->ineq[i] == STATUS_VALID) + continue; + if (info->ineq[i] == STATUS_CUT) + continue; + return 0; + } + + return 1; +} + +/* Compute the hash of the (apparent) affine hull of info->bmap (with + * the existentially quantified variables removed) and store it + * in info->hash. + */ +static int coalesce_info_set_hull_hash(struct isl_coalesce_info *info) +{ + isl_basic_map *hull; + unsigned n_div; + + hull = isl_basic_map_copy(info->bmap); + hull = isl_basic_map_plain_affine_hull(hull); + n_div = isl_basic_map_dim(hull, isl_dim_div); + hull = isl_basic_map_drop_constraints_involving_dims(hull, + isl_dim_div, 0, n_div); + info->hull_hash = isl_basic_map_get_hash(hull); + isl_basic_map_free(hull); + + return hull ? 0 : -1; +} + +/* Free all the allocated memory in an array + * of "n" isl_coalesce_info elements. + */ +static void clear_coalesce_info(int n, struct isl_coalesce_info *info) +{ + int i; + + if (!info) + return; + + for (i = 0; i < n; ++i) { + isl_basic_map_free(info[i].bmap); + isl_tab_free(info[i].tab); + } + + free(info); +} + +/* Drop the basic map represented by "info". + * That is, clear the memory associated to the entry and + * mark it as having been removed. + */ +static void drop(struct isl_coalesce_info *info) +{ + info->bmap = isl_basic_map_free(info->bmap); + isl_tab_free(info->tab); + info->tab = NULL; + info->removed = 1; +} + +/* Exchange the information in "info1" with that in "info2". + */ +static void exchange(struct isl_coalesce_info *info1, + struct isl_coalesce_info *info2) +{ + struct isl_coalesce_info info; + + info = *info1; + *info1 = *info2; + *info2 = info; +} + +/* This type represents the kind of change that has been performed + * while trying to coalesce two basic maps. + * + * isl_change_none: nothing was changed + * isl_change_drop_first: the first basic map was removed + * isl_change_drop_second: the second basic map was removed + * isl_change_fuse: the two basic maps were replaced by a new basic map. + */ +enum isl_change { + isl_change_error = -1, + isl_change_none = 0, + isl_change_drop_first, + isl_change_drop_second, + isl_change_fuse, +}; + +/* Update "change" based on an interchange of the first and the second + * basic map. That is, interchange isl_change_drop_first and + * isl_change_drop_second. + */ +static enum isl_change invert_change(enum isl_change change) +{ + switch (change) { + case isl_change_error: + return isl_change_error; + case isl_change_none: + return isl_change_none; + case isl_change_drop_first: + return isl_change_drop_second; + case isl_change_drop_second: + return isl_change_drop_first; + case isl_change_fuse: + return isl_change_fuse; + } + + return isl_change_error; +} + +/* Add the valid constraints of the basic map represented by "info" + * to "bmap". "len" is the size of the constraints. + * If only one of the pair of inequalities that make up an equality + * is valid, then add that inequality. + */ +static __isl_give isl_basic_map *add_valid_constraints( + __isl_take isl_basic_map *bmap, struct isl_coalesce_info *info, + unsigned len) +{ + int k, l; + + if (!bmap) + return NULL; + + for (k = 0; k < info->bmap->n_eq; ++k) { + if (info->eq[2 * k] == STATUS_VALID && + info->eq[2 * k + 1] == STATUS_VALID) { + l = isl_basic_map_alloc_equality(bmap); + if (l < 0) + return isl_basic_map_free(bmap); + isl_seq_cpy(bmap->eq[l], info->bmap->eq[k], len); + } else if (info->eq[2 * k] == STATUS_VALID) { + l = isl_basic_map_alloc_inequality(bmap); + if (l < 0) + return isl_basic_map_free(bmap); + isl_seq_neg(bmap->ineq[l], info->bmap->eq[k], len); + } else if (info->eq[2 * k + 1] == STATUS_VALID) { + l = isl_basic_map_alloc_inequality(bmap); + if (l < 0) + return isl_basic_map_free(bmap); + isl_seq_cpy(bmap->ineq[l], info->bmap->eq[k], len); + } + } + + for (k = 0; k < info->bmap->n_ineq; ++k) { + if (info->ineq[k] != STATUS_VALID) + continue; + l = isl_basic_map_alloc_inequality(bmap); + if (l < 0) + return isl_basic_map_free(bmap); + isl_seq_cpy(bmap->ineq[l], info->bmap->ineq[k], len); + } + + return bmap; +} + +/* Is "bmap" defined by a number of (non-redundant) constraints that + * is greater than the number of constraints of basic maps i and j combined? + * Equalities are counted as two inequalities. + */ +static int number_of_constraints_increases(int i, int j, + struct isl_coalesce_info *info, + __isl_keep isl_basic_map *bmap, struct isl_tab *tab) +{ + int k, n_old, n_new; + + n_old = 2 * info[i].bmap->n_eq + info[i].bmap->n_ineq; + n_old += 2 * info[j].bmap->n_eq + info[j].bmap->n_ineq; + + n_new = 2 * bmap->n_eq; + for (k = 0; k < bmap->n_ineq; ++k) + if (!isl_tab_is_redundant(tab, bmap->n_eq + k)) + ++n_new; + + return n_new > n_old; +} + +/* Replace the pair of basic maps i and j by the basic map bounded + * by the valid constraints in both basic maps and the constraints + * in extra (if not NULL). + * Place the fused basic map in the position that is the smallest of i and j. + * + * If "detect_equalities" is set, then look for equalities encoded + * as pairs of inequalities. + * If "check_number" is set, then the original basic maps are only + * replaced if the total number of constraints does not increase. + * While the number of integer divisions in the two basic maps + * is assumed to be the same, the actual definitions may be different. + * We only copy the definition from one of the basic map if it is + * the same as that of the other basic map. Otherwise, we mark + * the integer division as unknown and simplify the basic map + * in an attempt to recover the integer division definition. + */ +static enum isl_change fuse(int i, int j, struct isl_coalesce_info *info, + __isl_keep isl_mat *extra, int detect_equalities, int check_number) +{ + int k, l; + struct isl_basic_map *fused = NULL; + struct isl_tab *fused_tab = NULL; + unsigned total = isl_basic_map_total_dim(info[i].bmap); + unsigned extra_rows = extra ? extra->n_row : 0; + unsigned n_eq, n_ineq; + int simplify = 0; + + if (j < i) + return fuse(j, i, info, extra, detect_equalities, check_number); + + n_eq = info[i].bmap->n_eq + info[j].bmap->n_eq; + n_ineq = info[i].bmap->n_ineq + info[j].bmap->n_ineq; + fused = isl_basic_map_alloc_space(isl_space_copy(info[i].bmap->dim), + info[i].bmap->n_div, n_eq, n_eq + n_ineq + extra_rows); + fused = add_valid_constraints(fused, &info[i], 1 + total); + fused = add_valid_constraints(fused, &info[j], 1 + total); + if (!fused) + goto error; + if (ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_RATIONAL) && + ISL_F_ISSET(info[j].bmap, ISL_BASIC_MAP_RATIONAL)) + ISL_F_SET(fused, ISL_BASIC_MAP_RATIONAL); + + for (k = 0; k < info[i].bmap->n_div; ++k) { + int l = isl_basic_map_alloc_div(fused); + if (l < 0) + goto error; + if (isl_seq_eq(info[i].bmap->div[k], info[j].bmap->div[k], + 1 + 1 + total)) { + isl_seq_cpy(fused->div[l], info[i].bmap->div[k], + 1 + 1 + total); + } else { + isl_int_set_si(fused->div[l][0], 0); + simplify = 1; + } + } + + for (k = 0; k < extra_rows; ++k) { + l = isl_basic_map_alloc_inequality(fused); + if (l < 0) + goto error; + isl_seq_cpy(fused->ineq[l], extra->row[k], 1 + total); + } + + if (detect_equalities) + fused = isl_basic_map_detect_inequality_pairs(fused, NULL); + fused = isl_basic_map_gauss(fused, NULL); + if (simplify || info[j].simplify) { + fused = isl_basic_map_simplify(fused); + info[i].simplify = 0; + } + fused = isl_basic_map_finalize(fused); + + fused_tab = isl_tab_from_basic_map(fused, 0); + if (isl_tab_detect_redundant(fused_tab) < 0) + goto error; + + if (check_number && + number_of_constraints_increases(i, j, info, fused, fused_tab)) { + isl_tab_free(fused_tab); + isl_basic_map_free(fused); + return isl_change_none; + } + + isl_basic_map_free(info[i].bmap); + info[i].bmap = fused; + isl_tab_free(info[i].tab); + info[i].tab = fused_tab; + drop(&info[j]); + + return isl_change_fuse; +error: + isl_tab_free(fused_tab); + isl_basic_map_free(fused); + return isl_change_error; +} + +/* Given a pair of basic maps i and j such that all constraints are either + * "valid" or "cut", check if the facets corresponding to the "cut" + * constraints of i lie entirely within basic map j. + * If so, replace the pair by the basic map consisting of the valid + * constraints in both basic maps. + * Checking whether the facet lies entirely within basic map j + * is performed by checking whether the constraints of basic map j + * are valid for the facet. These tests are performed on a rational + * tableau to avoid the theoretical possibility that a constraint + * that was considered to be a cut constraint for the entire basic map i + * happens to be considered to be a valid constraint for the facet, + * even though it cuts off the same rational points. + * + * To see that we are not introducing any extra points, call the + * two basic maps A and B and the resulting map U and let x + * be an element of U \setminus ( A \cup B ). + * A line connecting x with an element of A \cup B meets a facet F + * of either A or B. Assume it is a facet of B and let c_1 be + * the corresponding facet constraint. We have c_1(x) < 0 and + * so c_1 is a cut constraint. This implies that there is some + * (possibly rational) point x' satisfying the constraints of A + * and the opposite of c_1 as otherwise c_1 would have been marked + * valid for A. The line connecting x and x' meets a facet of A + * in a (possibly rational) point that also violates c_1, but this + * is impossible since all cut constraints of B are valid for all + * cut facets of A. + * In case F is a facet of A rather than B, then we can apply the + * above reasoning to find a facet of B separating x from A \cup B first. + */ +static enum isl_change check_facets(int i, int j, + struct isl_coalesce_info *info) +{ + int k, l; + struct isl_tab_undo *snap, *snap2; + unsigned n_eq = info[i].bmap->n_eq; + + snap = isl_tab_snap(info[i].tab); + if (isl_tab_mark_rational(info[i].tab) < 0) + return isl_change_error; + snap2 = isl_tab_snap(info[i].tab); + + for (k = 0; k < info[i].bmap->n_ineq; ++k) { + if (info[i].ineq[k] != STATUS_CUT) + continue; + if (isl_tab_select_facet(info[i].tab, n_eq + k) < 0) + return isl_change_error; + for (l = 0; l < info[j].bmap->n_ineq; ++l) { + int stat; + if (info[j].ineq[l] != STATUS_CUT) + continue; + stat = status_in(info[j].bmap->ineq[l], info[i].tab); + if (stat < 0) + return isl_change_error; + if (stat != STATUS_VALID) + break; + } + if (isl_tab_rollback(info[i].tab, snap2) < 0) + return isl_change_error; + if (l < info[j].bmap->n_ineq) + break; + } + + if (k < info[i].bmap->n_ineq) { + if (isl_tab_rollback(info[i].tab, snap) < 0) + return isl_change_error; + return isl_change_none; + } + return fuse(i, j, info, NULL, 0, 0); +} + +/* Check if info->bmap contains the basic map represented + * by the tableau "tab". + * For each equality, we check both the constraint itself + * (as an inequality) and its negation. Make sure the + * equality is returned to its original state before returning. + */ +static isl_bool contains(struct isl_coalesce_info *info, struct isl_tab *tab) +{ + int k; + unsigned dim; + isl_basic_map *bmap = info->bmap; + + dim = isl_basic_map_total_dim(bmap); + for (k = 0; k < bmap->n_eq; ++k) { + int stat; + isl_seq_neg(bmap->eq[k], bmap->eq[k], 1 + dim); + stat = status_in(bmap->eq[k], tab); + isl_seq_neg(bmap->eq[k], bmap->eq[k], 1 + dim); + if (stat < 0) + return isl_bool_error; + if (stat != STATUS_VALID) + return isl_bool_false; + stat = status_in(bmap->eq[k], tab); + if (stat < 0) + return isl_bool_error; + if (stat != STATUS_VALID) + return isl_bool_false; + } + + for (k = 0; k < bmap->n_ineq; ++k) { + int stat; + if (info->ineq[k] == STATUS_REDUNDANT) + continue; + stat = status_in(bmap->ineq[k], tab); + if (stat < 0) + return isl_bool_error; + if (stat != STATUS_VALID) + return isl_bool_false; + } + return isl_bool_true; +} + +/* Basic map "i" has an inequality (say "k") that is adjacent + * to some inequality of basic map "j". All the other inequalities + * are valid for "j". + * Check if basic map "j" forms an extension of basic map "i". + * + * Note that this function is only called if some of the equalities or + * inequalities of basic map "j" do cut basic map "i". The function is + * correct even if there are no such cut constraints, but in that case + * the additional checks performed by this function are overkill. + * + * In particular, we replace constraint k, say f >= 0, by constraint + * f <= -1, add the inequalities of "j" that are valid for "i" + * and check if the result is a subset of basic map "j". + * To improve the chances of the subset relation being detected, + * any variable that only attains a single integer value + * in the tableau of "i" is first fixed to that value. + * If the result is a subset, then we know that this result is exactly equal + * to basic map "j" since all its constraints are valid for basic map "j". + * By combining the valid constraints of "i" (all equalities and all + * inequalities except "k") and the valid constraints of "j" we therefore + * obtain a basic map that is equal to their union. + * In this case, there is no need to perform a rollback of the tableau + * since it is going to be destroyed in fuse(). + * + * + * |\__ |\__ + * | \__ | \__ + * | \_ => | \__ + * |_______| _ |_________\ + * + * + * |\ |\ + * | \ | \ + * | \ | \ + * | | | \ + * | ||\ => | \ + * | || \ | \ + * | || | | | + * |__||_/ |_____/ + */ +static enum isl_change is_adj_ineq_extension(int i, int j, + struct isl_coalesce_info *info) +{ + int k; + struct isl_tab_undo *snap; + unsigned n_eq = info[i].bmap->n_eq; + unsigned total = isl_basic_map_total_dim(info[i].bmap); + isl_stat r; + isl_bool super; + + if (isl_tab_extend_cons(info[i].tab, 1 + info[j].bmap->n_ineq) < 0) + return isl_change_error; + + k = find_ineq(&info[i], STATUS_ADJ_INEQ); + if (k < 0) + isl_die(isl_basic_map_get_ctx(info[i].bmap), isl_error_internal, + "info[i].ineq should have exactly one STATUS_ADJ_INEQ", + return isl_change_error); + + snap = isl_tab_snap(info[i].tab); + + if (isl_tab_unrestrict(info[i].tab, n_eq + k) < 0) + return isl_change_error; + + isl_seq_neg(info[i].bmap->ineq[k], info[i].bmap->ineq[k], 1 + total); + isl_int_sub_ui(info[i].bmap->ineq[k][0], info[i].bmap->ineq[k][0], 1); + r = isl_tab_add_ineq(info[i].tab, info[i].bmap->ineq[k]); + isl_seq_neg(info[i].bmap->ineq[k], info[i].bmap->ineq[k], 1 + total); + isl_int_sub_ui(info[i].bmap->ineq[k][0], info[i].bmap->ineq[k][0], 1); + if (r < 0) + return isl_change_error; + + for (k = 0; k < info[j].bmap->n_ineq; ++k) { + if (info[j].ineq[k] != STATUS_VALID) + continue; + if (isl_tab_add_ineq(info[i].tab, info[j].bmap->ineq[k]) < 0) + return isl_change_error; + } + if (isl_tab_detect_constants(info[i].tab) < 0) + return isl_change_error; + + super = contains(&info[j], info[i].tab); + if (super < 0) + return isl_change_error; + if (super) + return fuse(i, j, info, NULL, 0, 0); + + if (isl_tab_rollback(info[i].tab, snap) < 0) + return isl_change_error; + + return isl_change_none; +} + + +/* Both basic maps have at least one inequality with and adjacent + * (but opposite) inequality in the other basic map. + * Check that there are no cut constraints and that there is only + * a single pair of adjacent inequalities. + * If so, we can replace the pair by a single basic map described + * by all but the pair of adjacent inequalities. + * Any additional points introduced lie strictly between the two + * adjacent hyperplanes and can therefore be integral. + * + * ____ _____ + * / ||\ / \ + * / || \ / \ + * \ || \ => \ \ + * \ || / \ / + * \___||_/ \_____/ + * + * The test for a single pair of adjancent inequalities is important + * for avoiding the combination of two basic maps like the following + * + * /| + * / | + * /__| + * _____ + * | | + * | | + * |___| + * + * If there are some cut constraints on one side, then we may + * still be able to fuse the two basic maps, but we need to perform + * some additional checks in is_adj_ineq_extension. + */ +static enum isl_change check_adj_ineq(int i, int j, + struct isl_coalesce_info *info) +{ + int count_i, count_j; + int cut_i, cut_j; + + count_i = count_ineq(&info[i], STATUS_ADJ_INEQ); + count_j = count_ineq(&info[j], STATUS_ADJ_INEQ); + + if (count_i != 1 && count_j != 1) + return isl_change_none; + + cut_i = any_eq(&info[i], STATUS_CUT) || any_ineq(&info[i], STATUS_CUT); + cut_j = any_eq(&info[j], STATUS_CUT) || any_ineq(&info[j], STATUS_CUT); + + if (!cut_i && !cut_j && count_i == 1 && count_j == 1) + return fuse(i, j, info, NULL, 0, 0); + + if (count_i == 1 && !cut_i) + return is_adj_ineq_extension(i, j, info); + + if (count_j == 1 && !cut_j) + return is_adj_ineq_extension(j, i, info); + + return isl_change_none; +} + +/* Given an affine transformation matrix "T", does row "row" represent + * anything other than a unit vector (possibly shifted by a constant) + * that is not involved in any of the other rows? + * + * That is, if a constraint involves the variable corresponding to + * the row, then could its preimage by "T" have any coefficients + * that are different from those in the original constraint? + */ +static int not_unique_unit_row(__isl_keep isl_mat *T, int row) +{ + int i, j; + int len = T->n_col - 1; + + i = isl_seq_first_non_zero(T->row[row] + 1, len); + if (i < 0) + return 1; + if (!isl_int_is_one(T->row[row][1 + i]) && + !isl_int_is_negone(T->row[row][1 + i])) + return 1; + + j = isl_seq_first_non_zero(T->row[row] + 1 + i + 1, len - (i + 1)); + if (j >= 0) + return 1; + + for (j = 1; j < T->n_row; ++j) { + if (j == row) + continue; + if (!isl_int_is_zero(T->row[j][1 + i])) + return 1; + } + + return 0; +} + +/* Does inequality constraint "ineq" of "bmap" involve any of + * the variables marked in "affected"? + * "total" is the total number of variables, i.e., the number + * of entries in "affected". + */ +static isl_bool is_affected(__isl_keep isl_basic_map *bmap, int ineq, + int *affected, int total) +{ + int i; + + for (i = 0; i < total; ++i) { + if (!affected[i]) + continue; + if (!isl_int_is_zero(bmap->ineq[ineq][1 + i])) + return isl_bool_true; + } + + return isl_bool_false; +} + +/* Given the compressed version of inequality constraint "ineq" + * of info->bmap in "v", check if the constraint can be tightened, + * where the compression is based on an equality constraint valid + * for info->tab. + * If so, add the tightened version of the inequality constraint + * to info->tab. "v" may be modified by this function. + * + * That is, if the compressed constraint is of the form + * + * m f() + c >= 0 + * + * with 0 < c < m, then it is equivalent to + * + * f() >= 0 + * + * This means that c can also be subtracted from the original, + * uncompressed constraint without affecting the integer points + * in info->tab. Add this tightened constraint as an extra row + * to info->tab to make this information explicitly available. + */ +static __isl_give isl_vec *try_tightening(struct isl_coalesce_info *info, + int ineq, __isl_take isl_vec *v) +{ + isl_ctx *ctx; + isl_stat r; + + if (!v) + return NULL; + + ctx = isl_vec_get_ctx(v); + isl_seq_gcd(v->el + 1, v->size - 1, &ctx->normalize_gcd); + if (isl_int_is_zero(ctx->normalize_gcd) || + isl_int_is_one(ctx->normalize_gcd)) { + return v; + } + + v = isl_vec_cow(v); + if (!v) + return NULL; + + isl_int_fdiv_r(v->el[0], v->el[0], ctx->normalize_gcd); + if (isl_int_is_zero(v->el[0])) + return v; + + if (isl_tab_extend_cons(info->tab, 1) < 0) + return isl_vec_free(v); + + isl_int_sub(info->bmap->ineq[ineq][0], + info->bmap->ineq[ineq][0], v->el[0]); + r = isl_tab_add_ineq(info->tab, info->bmap->ineq[ineq]); + isl_int_add(info->bmap->ineq[ineq][0], + info->bmap->ineq[ineq][0], v->el[0]); + + if (r < 0) + return isl_vec_free(v); + + return v; +} + +/* Tighten the (non-redundant) constraints on the facet represented + * by info->tab. + * In particular, on input, info->tab represents the result + * of relaxing the "n" inequality constraints of info->bmap in "relaxed" + * by one, i.e., replacing f_i >= 0 by f_i + 1 >= 0, and then + * replacing the one at index "l" by the corresponding equality, + * i.e., f_k + 1 = 0, with k = relaxed[l]. + * + * Compute a variable compression from the equality constraint f_k + 1 = 0 + * and use it to tighten the other constraints of info->bmap + * (that is, all constraints that have not been relaxed), + * updating info->tab (and leaving info->bmap untouched). + * The compression handles essentially two cases, one where a variable + * is assigned a fixed value and can therefore be eliminated, and one + * where one variable is a shifted multiple of some other variable and + * can therefore be replaced by that multiple. + * Gaussian elimination would also work for the first case, but for + * the second case, the effectiveness would depend on the order + * of the variables. + * After compression, some of the constraints may have coefficients + * with a common divisor. If this divisor does not divide the constant + * term, then the constraint can be tightened. + * The tightening is performed on the tableau info->tab by introducing + * extra (temporary) constraints. + * + * Only constraints that are possibly affected by the compression are + * considered. In particular, if the constraint only involves variables + * that are directly mapped to a distinct set of other variables, then + * no common divisor can be introduced and no tightening can occur. + * + * It is important to only consider the non-redundant constraints + * since the facet constraint has been relaxed prior to the call + * to this function, meaning that the constraints that were redundant + * prior to the relaxation may no longer be redundant. + * These constraints will be ignored in the fused result, so + * the fusion detection should not exploit them. + */ +static isl_stat tighten_on_relaxed_facet(struct isl_coalesce_info *info, + int n, int *relaxed, int l) +{ + unsigned total; + isl_ctx *ctx; + isl_vec *v = NULL; + isl_mat *T; + int i; + int k; + int *affected; + + k = relaxed[l]; + ctx = isl_basic_map_get_ctx(info->bmap); + total = isl_basic_map_total_dim(info->bmap); + isl_int_add_ui(info->bmap->ineq[k][0], info->bmap->ineq[k][0], 1); + T = isl_mat_sub_alloc6(ctx, info->bmap->ineq, k, 1, 0, 1 + total); + T = isl_mat_variable_compression(T, NULL); + isl_int_sub_ui(info->bmap->ineq[k][0], info->bmap->ineq[k][0], 1); + if (!T) + return isl_stat_error; + if (T->n_col == 0) { + isl_mat_free(T); + return isl_stat_ok; + } + + affected = isl_alloc_array(ctx, int, total); + if (!affected) + goto error; + + for (i = 0; i < total; ++i) + affected[i] = not_unique_unit_row(T, 1 + i); + + for (i = 0; i < info->bmap->n_ineq; ++i) { + isl_bool handle; + if (any(relaxed, n, i)) + continue; + if (info->ineq[i] == STATUS_REDUNDANT) + continue; + handle = is_affected(info->bmap, i, affected, total); + if (handle < 0) + goto error; + if (!handle) + continue; + v = isl_vec_alloc(ctx, 1 + total); + if (!v) + goto error; + isl_seq_cpy(v->el, info->bmap->ineq[i], 1 + total); + v = isl_vec_mat_product(v, isl_mat_copy(T)); + v = try_tightening(info, i, v); + isl_vec_free(v); + if (!v) + goto error; + } + + isl_mat_free(T); + free(affected); + return isl_stat_ok; +error: + isl_mat_free(T); + free(affected); + return isl_stat_error; +} + +/* Replace the basic maps "i" and "j" by an extension of "i" + * along the "n" inequality constraints in "relax" by one. + * The tableau info[i].tab has already been extended. + * Extend info[i].bmap accordingly by relaxing all constraints in "relax" + * by one. + * Each integer division that does not have exactly the same + * definition in "i" and "j" is marked unknown and the basic map + * is scheduled to be simplified in an attempt to recover + * the integer division definition. + * Place the extension in the position that is the smallest of i and j. + */ +static enum isl_change extend(int i, int j, int n, int *relax, + struct isl_coalesce_info *info) +{ + int l; + unsigned total; + + info[i].bmap = isl_basic_map_cow(info[i].bmap); + if (!info[i].bmap) + return isl_change_error; + total = isl_basic_map_total_dim(info[i].bmap); + for (l = 0; l < info[i].bmap->n_div; ++l) + if (!isl_seq_eq(info[i].bmap->div[l], + info[j].bmap->div[l], 1 + 1 + total)) { + isl_int_set_si(info[i].bmap->div[l][0], 0); + info[i].simplify = 1; + } + for (l = 0; l < n; ++l) + isl_int_add_ui(info[i].bmap->ineq[relax[l]][0], + info[i].bmap->ineq[relax[l]][0], 1); + ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_FINAL); + drop(&info[j]); + if (j < i) + exchange(&info[i], &info[j]); + return isl_change_fuse; +} + +/* Basic map "i" has "n" inequality constraints (collected in "relax") + * that are such that they include basic map "j" if they are relaxed + * by one. All the other inequalities are valid for "j". + * Check if basic map "j" forms an extension of basic map "i". + * + * In particular, relax the constraints in "relax", compute the corresponding + * facets one by one and check whether each of these is included + * in the other basic map. + * Before testing for inclusion, the constraints on each facet + * are tightened to increase the chance of an inclusion being detected. + * (Adding the valid constraints of "j" to the tableau of "i", as is done + * in is_adj_ineq_extension, may further increase those chances, but this + * is not currently done.) + * If each facet is included, we know that relaxing the constraints extends + * the basic map with exactly the other basic map (we already know that this + * other basic map is included in the extension, because all other + * inequality constraints are valid of "j") and we can replace the + * two basic maps by this extension. + * + * If any of the relaxed constraints turn out to be redundant, then bail out. + * isl_tab_select_facet refuses to handle such constraints. It may be + * possible to handle them anyway by making a distinction between + * redundant constraints with a corresponding facet that still intersects + * the set (allowing isl_tab_select_facet to handle them) and + * those where the facet does not intersect the set (which can be ignored + * because the empty facet is trivially included in the other disjunct). + * However, relaxed constraints that turn out to be redundant should + * be fairly rare and no such instance has been reported where + * coalescing would be successful. + * ____ _____ + * / || / | + * / || / | + * \ || => \ | + * \ || \ | + * \___|| \____| + * + * + * \ |\ + * |\\ | \ + * | \\ | \ + * | | => | / + * | / | / + * |/ |/ + */ +static enum isl_change is_relaxed_extension(int i, int j, int n, int *relax, + struct isl_coalesce_info *info) +{ + int l; + isl_bool super; + struct isl_tab_undo *snap, *snap2; + unsigned n_eq = info[i].bmap->n_eq; + + for (l = 0; l < n; ++l) + if (isl_tab_is_equality(info[i].tab, n_eq + relax[l])) + return isl_change_none; + + snap = isl_tab_snap(info[i].tab); + for (l = 0; l < n; ++l) + if (isl_tab_relax(info[i].tab, n_eq + relax[l]) < 0) + return isl_change_error; + for (l = 0; l < n; ++l) { + if (!isl_tab_is_redundant(info[i].tab, n_eq + relax[l])) + continue; + if (isl_tab_rollback(info[i].tab, snap) < 0) + return isl_change_error; + return isl_change_none; + } + snap2 = isl_tab_snap(info[i].tab); + for (l = 0; l < n; ++l) { + if (isl_tab_rollback(info[i].tab, snap2) < 0) + return isl_change_error; + if (isl_tab_select_facet(info[i].tab, n_eq + relax[l]) < 0) + return isl_change_error; + if (tighten_on_relaxed_facet(&info[i], n, relax, l) < 0) + return isl_change_error; + super = contains(&info[j], info[i].tab); + if (super < 0) + return isl_change_error; + if (super) + continue; + if (isl_tab_rollback(info[i].tab, snap) < 0) + return isl_change_error; + return isl_change_none; + } + + if (isl_tab_rollback(info[i].tab, snap2) < 0) + return isl_change_error; + return extend(i, j, n, relax, info); +} + +/* Data structure that keeps track of the wrapping constraints + * and of information to bound the coefficients of those constraints. + * + * bound is set if we want to apply a bound on the coefficients + * mat contains the wrapping constraints + * max is the bound on the coefficients (if bound is set) + */ +struct isl_wraps { + int bound; + isl_mat *mat; + isl_int max; +}; + +/* Update wraps->max to be greater than or equal to the coefficients + * in the equalities and inequalities of info->bmap that can be removed + * if we end up applying wrapping. + */ +static isl_stat wraps_update_max(struct isl_wraps *wraps, + struct isl_coalesce_info *info) +{ + int k; + isl_int max_k; + unsigned total = isl_basic_map_total_dim(info->bmap); + + isl_int_init(max_k); + + for (k = 0; k < info->bmap->n_eq; ++k) { + if (info->eq[2 * k] == STATUS_VALID && + info->eq[2 * k + 1] == STATUS_VALID) + continue; + isl_seq_abs_max(info->bmap->eq[k] + 1, total, &max_k); + if (isl_int_abs_gt(max_k, wraps->max)) + isl_int_set(wraps->max, max_k); + } + + for (k = 0; k < info->bmap->n_ineq; ++k) { + if (info->ineq[k] == STATUS_VALID || + info->ineq[k] == STATUS_REDUNDANT) + continue; + isl_seq_abs_max(info->bmap->ineq[k] + 1, total, &max_k); + if (isl_int_abs_gt(max_k, wraps->max)) + isl_int_set(wraps->max, max_k); + } + + isl_int_clear(max_k); + + return isl_stat_ok; +} + +/* Initialize the isl_wraps data structure. + * If we want to bound the coefficients of the wrapping constraints, + * we set wraps->max to the largest coefficient + * in the equalities and inequalities that can be removed if we end up + * applying wrapping. + */ +static isl_stat wraps_init(struct isl_wraps *wraps, __isl_take isl_mat *mat, + struct isl_coalesce_info *info, int i, int j) +{ + isl_ctx *ctx; + + wraps->bound = 0; + wraps->mat = mat; + if (!mat) + return isl_stat_error; + ctx = isl_mat_get_ctx(mat); + wraps->bound = isl_options_get_coalesce_bounded_wrapping(ctx); + if (!wraps->bound) + return isl_stat_ok; + isl_int_init(wraps->max); + isl_int_set_si(wraps->max, 0); + if (wraps_update_max(wraps, &info[i]) < 0) + return isl_stat_error; + if (wraps_update_max(wraps, &info[j]) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Free the contents of the isl_wraps data structure. + */ +static void wraps_free(struct isl_wraps *wraps) +{ + isl_mat_free(wraps->mat); + if (wraps->bound) + isl_int_clear(wraps->max); +} + +/* Is the wrapping constraint in row "row" allowed? + * + * If wraps->bound is set, we check that none of the coefficients + * is greater than wraps->max. + */ +static int allow_wrap(struct isl_wraps *wraps, int row) +{ + int i; + + if (!wraps->bound) + return 1; + + for (i = 1; i < wraps->mat->n_col; ++i) + if (isl_int_abs_gt(wraps->mat->row[row][i], wraps->max)) + return 0; + + return 1; +} + +/* Wrap "ineq" (or its opposite if "negate" is set) around "bound" + * to include "set" and add the result in position "w" of "wraps". + * "len" is the total number of coefficients in "bound" and "ineq". + * Return 1 on success, 0 on failure and -1 on error. + * Wrapping can fail if the result of wrapping is equal to "bound" + * or if we want to bound the sizes of the coefficients and + * the wrapped constraint does not satisfy this bound. + */ +static int add_wrap(struct isl_wraps *wraps, int w, isl_int *bound, + isl_int *ineq, unsigned len, __isl_keep isl_set *set, int negate) +{ + isl_seq_cpy(wraps->mat->row[w], bound, len); + if (negate) { + isl_seq_neg(wraps->mat->row[w + 1], ineq, len); + ineq = wraps->mat->row[w + 1]; + } + if (!isl_set_wrap_facet(set, wraps->mat->row[w], ineq)) + return -1; + if (isl_seq_eq(wraps->mat->row[w], bound, len)) + return 0; + if (!allow_wrap(wraps, w)) + return 0; + return 1; +} + +/* For each constraint in info->bmap that is not redundant (as determined + * by info->tab) and that is not a valid constraint for the other basic map, + * wrap the constraint around "bound" such that it includes the whole + * set "set" and append the resulting constraint to "wraps". + * Note that the constraints that are valid for the other basic map + * will be added to the combined basic map by default, so there is + * no need to wrap them. + * The caller wrap_in_facets even relies on this function not wrapping + * any constraints that are already valid. + * "wraps" is assumed to have been pre-allocated to the appropriate size. + * wraps->n_row is the number of actual wrapped constraints that have + * been added. + * If any of the wrapping problems results in a constraint that is + * identical to "bound", then this means that "set" is unbounded in such + * way that no wrapping is possible. If this happens then wraps->n_row + * is reset to zero. + * Similarly, if we want to bound the coefficients of the wrapping + * constraints and a newly added wrapping constraint does not + * satisfy the bound, then wraps->n_row is also reset to zero. + */ +static isl_stat add_wraps(struct isl_wraps *wraps, + struct isl_coalesce_info *info, isl_int *bound, __isl_keep isl_set *set) +{ + int l, m; + int w; + int added; + isl_basic_map *bmap = info->bmap; + unsigned len = 1 + isl_basic_map_total_dim(bmap); + + w = wraps->mat->n_row; + + for (l = 0; l < bmap->n_ineq; ++l) { + if (info->ineq[l] == STATUS_VALID || + info->ineq[l] == STATUS_REDUNDANT) + continue; + if (isl_seq_is_neg(bound, bmap->ineq[l], len)) + continue; + if (isl_seq_eq(bound, bmap->ineq[l], len)) + continue; + if (isl_tab_is_redundant(info->tab, bmap->n_eq + l)) + continue; + + added = add_wrap(wraps, w, bound, bmap->ineq[l], len, set, 0); + if (added < 0) + return isl_stat_error; + if (!added) + goto unbounded; + ++w; + } + for (l = 0; l < bmap->n_eq; ++l) { + if (isl_seq_is_neg(bound, bmap->eq[l], len)) + continue; + if (isl_seq_eq(bound, bmap->eq[l], len)) + continue; + + for (m = 0; m < 2; ++m) { + if (info->eq[2 * l + m] == STATUS_VALID) + continue; + added = add_wrap(wraps, w, bound, bmap->eq[l], len, + set, !m); + if (added < 0) + return isl_stat_error; + if (!added) + goto unbounded; + ++w; + } + } + + wraps->mat->n_row = w; + return isl_stat_ok; +unbounded: + wraps->mat->n_row = 0; + return isl_stat_ok; +} + +/* Check if the constraints in "wraps" from "first" until the last + * are all valid for the basic set represented by "tab". + * If not, wraps->n_row is set to zero. + */ +static int check_wraps(__isl_keep isl_mat *wraps, int first, + struct isl_tab *tab) +{ + int i; + + for (i = first; i < wraps->n_row; ++i) { + enum isl_ineq_type type; + type = isl_tab_ineq_type(tab, wraps->row[i]); + if (type == isl_ineq_error) + return -1; + if (type == isl_ineq_redundant) + continue; + wraps->n_row = 0; + return 0; + } + + return 0; +} + +/* Return a set that corresponds to the non-redundant constraints + * (as recorded in tab) of bmap. + * + * It's important to remove the redundant constraints as some + * of the other constraints may have been modified after the + * constraints were marked redundant. + * In particular, a constraint may have been relaxed. + * Redundant constraints are ignored when a constraint is relaxed + * and should therefore continue to be ignored ever after. + * Otherwise, the relaxation might be thwarted by some of + * these constraints. + * + * Update the underlying set to ensure that the dimension doesn't change. + * Otherwise the integer divisions could get dropped if the tab + * turns out to be empty. + */ +static __isl_give isl_set *set_from_updated_bmap(__isl_keep isl_basic_map *bmap, + struct isl_tab *tab) +{ + isl_basic_set *bset; + + bmap = isl_basic_map_copy(bmap); + bset = isl_basic_map_underlying_set(bmap); + bset = isl_basic_set_cow(bset); + bset = isl_basic_set_update_from_tab(bset, tab); + return isl_set_from_basic_set(bset); +} + +/* Wrap the constraints of info->bmap that bound the facet defined + * by inequality "k" around (the opposite of) this inequality to + * include "set". "bound" may be used to store the negated inequality. + * Since the wrapped constraints are not guaranteed to contain the whole + * of info->bmap, we check them in check_wraps. + * If any of the wrapped constraints turn out to be invalid, then + * check_wraps will reset wrap->n_row to zero. + */ +static isl_stat add_wraps_around_facet(struct isl_wraps *wraps, + struct isl_coalesce_info *info, int k, isl_int *bound, + __isl_keep isl_set *set) +{ + struct isl_tab_undo *snap; + int n; + unsigned total = isl_basic_map_total_dim(info->bmap); + + snap = isl_tab_snap(info->tab); + + if (isl_tab_select_facet(info->tab, info->bmap->n_eq + k) < 0) + return isl_stat_error; + if (isl_tab_detect_redundant(info->tab) < 0) + return isl_stat_error; + + isl_seq_neg(bound, info->bmap->ineq[k], 1 + total); + + n = wraps->mat->n_row; + if (add_wraps(wraps, info, bound, set) < 0) + return isl_stat_error; + + if (isl_tab_rollback(info->tab, snap) < 0) + return isl_stat_error; + if (check_wraps(wraps->mat, n, info->tab) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Given a basic set i with a constraint k that is adjacent to + * basic set j, check if we can wrap + * both the facet corresponding to k (if "wrap_facet" is set) and basic map j + * (always) around their ridges to include the other set. + * If so, replace the pair of basic sets by their union. + * + * All constraints of i (except k) are assumed to be valid or + * cut constraints for j. + * Wrapping the cut constraints to include basic map j may result + * in constraints that are no longer valid of basic map i + * we have to check that the resulting wrapping constraints are valid for i. + * If "wrap_facet" is not set, then all constraints of i (except k) + * are assumed to be valid for j. + * ____ _____ + * / | / \ + * / || / | + * \ || => \ | + * \ || \ | + * \___|| \____| + * + */ +static enum isl_change can_wrap_in_facet(int i, int j, int k, + struct isl_coalesce_info *info, int wrap_facet) +{ + enum isl_change change = isl_change_none; + struct isl_wraps wraps; + isl_ctx *ctx; + isl_mat *mat; + struct isl_set *set_i = NULL; + struct isl_set *set_j = NULL; + struct isl_vec *bound = NULL; + unsigned total = isl_basic_map_total_dim(info[i].bmap); + + set_i = set_from_updated_bmap(info[i].bmap, info[i].tab); + set_j = set_from_updated_bmap(info[j].bmap, info[j].tab); + ctx = isl_basic_map_get_ctx(info[i].bmap); + mat = isl_mat_alloc(ctx, 2 * (info[i].bmap->n_eq + info[j].bmap->n_eq) + + info[i].bmap->n_ineq + info[j].bmap->n_ineq, + 1 + total); + if (wraps_init(&wraps, mat, info, i, j) < 0) + goto error; + bound = isl_vec_alloc(ctx, 1 + total); + if (!set_i || !set_j || !bound) + goto error; + + isl_seq_cpy(bound->el, info[i].bmap->ineq[k], 1 + total); + isl_int_add_ui(bound->el[0], bound->el[0], 1); + + isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total); + wraps.mat->n_row = 1; + + if (add_wraps(&wraps, &info[j], bound->el, set_i) < 0) + goto error; + if (!wraps.mat->n_row) + goto unbounded; + + if (wrap_facet) { + if (add_wraps_around_facet(&wraps, &info[i], k, + bound->el, set_j) < 0) + goto error; + if (!wraps.mat->n_row) + goto unbounded; + } + + change = fuse(i, j, info, wraps.mat, 0, 0); + +unbounded: + wraps_free(&wraps); + + isl_set_free(set_i); + isl_set_free(set_j); + + isl_vec_free(bound); + + return change; +error: + wraps_free(&wraps); + isl_vec_free(bound); + isl_set_free(set_i); + isl_set_free(set_j); + return isl_change_error; +} + +/* Given a cut constraint t(x) >= 0 of basic map i, stored in row "w" + * of wrap.mat, replace it by its relaxed version t(x) + 1 >= 0, and + * add wrapping constraints to wrap.mat for all constraints + * of basic map j that bound the part of basic map j that sticks out + * of the cut constraint. + * "set_i" is the underlying set of basic map i. + * If any wrapping fails, then wraps->mat.n_row is reset to zero. + * + * In particular, we first intersect basic map j with t(x) + 1 = 0. + * If the result is empty, then t(x) >= 0 was actually a valid constraint + * (with respect to the integer points), so we add t(x) >= 0 instead. + * Otherwise, we wrap the constraints of basic map j that are not + * redundant in this intersection and that are not already valid + * for basic map i over basic map i. + * Note that it is sufficient to wrap the constraints to include + * basic map i, because we will only wrap the constraints that do + * not include basic map i already. The wrapped constraint will + * therefore be more relaxed compared to the original constraint. + * Since the original constraint is valid for basic map j, so is + * the wrapped constraint. + */ +static isl_stat wrap_in_facet(struct isl_wraps *wraps, int w, + struct isl_coalesce_info *info_j, __isl_keep isl_set *set_i, + struct isl_tab_undo *snap) +{ + isl_int_add_ui(wraps->mat->row[w][0], wraps->mat->row[w][0], 1); + if (isl_tab_add_eq(info_j->tab, wraps->mat->row[w]) < 0) + return isl_stat_error; + if (isl_tab_detect_redundant(info_j->tab) < 0) + return isl_stat_error; + + if (info_j->tab->empty) + isl_int_sub_ui(wraps->mat->row[w][0], wraps->mat->row[w][0], 1); + else if (add_wraps(wraps, info_j, wraps->mat->row[w], set_i) < 0) + return isl_stat_error; + + if (isl_tab_rollback(info_j->tab, snap) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Given a pair of basic maps i and j such that j sticks out + * of i at n cut constraints, each time by at most one, + * try to compute wrapping constraints and replace the two + * basic maps by a single basic map. + * The other constraints of i are assumed to be valid for j. + * "set_i" is the underlying set of basic map i. + * "wraps" has been initialized to be of the right size. + * + * For each cut constraint t(x) >= 0 of i, we add the relaxed version + * t(x) + 1 >= 0, along with wrapping constraints for all constraints + * of basic map j that bound the part of basic map j that sticks out + * of the cut constraint. + * + * If any wrapping fails, i.e., if we cannot wrap to touch + * the union, then we give up. + * Otherwise, the pair of basic maps is replaced by their union. + */ +static enum isl_change try_wrap_in_facets(int i, int j, + struct isl_coalesce_info *info, struct isl_wraps *wraps, + __isl_keep isl_set *set_i) +{ + int k, l, w; + unsigned total; + struct isl_tab_undo *snap; + + total = isl_basic_map_total_dim(info[i].bmap); + + snap = isl_tab_snap(info[j].tab); + + wraps->mat->n_row = 0; + + for (k = 0; k < info[i].bmap->n_eq; ++k) { + for (l = 0; l < 2; ++l) { + if (info[i].eq[2 * k + l] != STATUS_CUT) + continue; + w = wraps->mat->n_row++; + if (l == 0) + isl_seq_neg(wraps->mat->row[w], + info[i].bmap->eq[k], 1 + total); + else + isl_seq_cpy(wraps->mat->row[w], + info[i].bmap->eq[k], 1 + total); + if (wrap_in_facet(wraps, w, &info[j], set_i, snap) < 0) + return isl_change_error; + + if (!wraps->mat->n_row) + return isl_change_none; + } + } + + for (k = 0; k < info[i].bmap->n_ineq; ++k) { + if (info[i].ineq[k] != STATUS_CUT) + continue; + w = wraps->mat->n_row++; + isl_seq_cpy(wraps->mat->row[w], + info[i].bmap->ineq[k], 1 + total); + if (wrap_in_facet(wraps, w, &info[j], set_i, snap) < 0) + return isl_change_error; + + if (!wraps->mat->n_row) + return isl_change_none; + } + + return fuse(i, j, info, wraps->mat, 0, 1); +} + +/* Given a pair of basic maps i and j such that j sticks out + * of i at n cut constraints, each time by at most one, + * try to compute wrapping constraints and replace the two + * basic maps by a single basic map. + * The other constraints of i are assumed to be valid for j. + * + * The core computation is performed by try_wrap_in_facets. + * This function simply extracts an underlying set representation + * of basic map i and initializes the data structure for keeping + * track of wrapping constraints. + */ +static enum isl_change wrap_in_facets(int i, int j, int n, + struct isl_coalesce_info *info) +{ + enum isl_change change = isl_change_none; + struct isl_wraps wraps; + isl_ctx *ctx; + isl_mat *mat; + isl_set *set_i = NULL; + unsigned total = isl_basic_map_total_dim(info[i].bmap); + int max_wrap; + + if (isl_tab_extend_cons(info[j].tab, 1) < 0) + return isl_change_error; + + max_wrap = 1 + 2 * info[j].bmap->n_eq + info[j].bmap->n_ineq; + max_wrap *= n; + + set_i = set_from_updated_bmap(info[i].bmap, info[i].tab); + ctx = isl_basic_map_get_ctx(info[i].bmap); + mat = isl_mat_alloc(ctx, max_wrap, 1 + total); + if (wraps_init(&wraps, mat, info, i, j) < 0) + goto error; + if (!set_i) + goto error; + + change = try_wrap_in_facets(i, j, info, &wraps, set_i); + + wraps_free(&wraps); + isl_set_free(set_i); + + return change; +error: + wraps_free(&wraps); + isl_set_free(set_i); + return isl_change_error; +} + +/* Return the effect of inequality "ineq" on the tableau "tab", + * after relaxing the constant term of "ineq" by one. + */ +static enum isl_ineq_type type_of_relaxed(struct isl_tab *tab, isl_int *ineq) +{ + enum isl_ineq_type type; + + isl_int_add_ui(ineq[0], ineq[0], 1); + type = isl_tab_ineq_type(tab, ineq); + isl_int_sub_ui(ineq[0], ineq[0], 1); + + return type; +} + +/* Given two basic sets i and j, + * check if relaxing all the cut constraints of i by one turns + * them into valid constraint for j and check if we can wrap in + * the bits that are sticking out. + * If so, replace the pair by their union. + * + * We first check if all relaxed cut inequalities of i are valid for j + * and then try to wrap in the intersections of the relaxed cut inequalities + * with j. + * + * During this wrapping, we consider the points of j that lie at a distance + * of exactly 1 from i. In particular, we ignore the points that lie in + * between this lower-dimensional space and the basic map i. + * We can therefore only apply this to integer maps. + * ____ _____ + * / ___|_ / \ + * / | | / | + * \ | | => \ | + * \|____| \ | + * \___| \____/ + * + * _____ ______ + * | ____|_ | \ + * | | | | | + * | | | => | | + * |_| | | | + * |_____| \______| + * + * _______ + * | | + * | |\ | + * | | \ | + * | | \ | + * | | \| + * | | \ + * | |_____\ + * | | + * |_______| + * + * Wrapping can fail if the result of wrapping one of the facets + * around its edges does not produce any new facet constraint. + * In particular, this happens when we try to wrap in unbounded sets. + * + * _______________________________________________________________________ + * | + * | ___ + * | | | + * |_| |_________________________________________________________________ + * |___| + * + * The following is not an acceptable result of coalescing the above two + * sets as it includes extra integer points. + * _______________________________________________________________________ + * | + * | + * | + * | + * \______________________________________________________________________ + */ +static enum isl_change can_wrap_in_set(int i, int j, + struct isl_coalesce_info *info) +{ + int k, l; + int n; + unsigned total; + + if (ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_RATIONAL) || + ISL_F_ISSET(info[j].bmap, ISL_BASIC_MAP_RATIONAL)) + return isl_change_none; + + n = count_eq(&info[i], STATUS_CUT) + count_ineq(&info[i], STATUS_CUT); + if (n == 0) + return isl_change_none; + + total = isl_basic_map_total_dim(info[i].bmap); + for (k = 0; k < info[i].bmap->n_eq; ++k) { + for (l = 0; l < 2; ++l) { + enum isl_ineq_type type; + + if (info[i].eq[2 * k + l] != STATUS_CUT) + continue; + + if (l == 0) + isl_seq_neg(info[i].bmap->eq[k], + info[i].bmap->eq[k], 1 + total); + type = type_of_relaxed(info[j].tab, + info[i].bmap->eq[k]); + if (l == 0) + isl_seq_neg(info[i].bmap->eq[k], + info[i].bmap->eq[k], 1 + total); + if (type == isl_ineq_error) + return isl_change_error; + if (type != isl_ineq_redundant) + return isl_change_none; + } + } + + for (k = 0; k < info[i].bmap->n_ineq; ++k) { + enum isl_ineq_type type; + + if (info[i].ineq[k] != STATUS_CUT) + continue; + + type = type_of_relaxed(info[j].tab, info[i].bmap->ineq[k]); + if (type == isl_ineq_error) + return isl_change_error; + if (type != isl_ineq_redundant) + return isl_change_none; + } + + return wrap_in_facets(i, j, n, info); +} + +/* Check if either i or j has only cut constraints that can + * be used to wrap in (a facet of) the other basic set. + * if so, replace the pair by their union. + */ +static enum isl_change check_wrap(int i, int j, struct isl_coalesce_info *info) +{ + enum isl_change change = isl_change_none; + + change = can_wrap_in_set(i, j, info); + if (change != isl_change_none) + return change; + + change = can_wrap_in_set(j, i, info); + return change; +} + +/* Check if all inequality constraints of "i" that cut "j" cease + * to be cut constraints if they are relaxed by one. + * If so, collect the cut constraints in "list". + * The caller is responsible for allocating "list". + */ +static isl_bool all_cut_by_one(int i, int j, struct isl_coalesce_info *info, + int *list) +{ + int l, n; + + n = 0; + for (l = 0; l < info[i].bmap->n_ineq; ++l) { + enum isl_ineq_type type; + + if (info[i].ineq[l] != STATUS_CUT) + continue; + type = type_of_relaxed(info[j].tab, info[i].bmap->ineq[l]); + if (type == isl_ineq_error) + return isl_bool_error; + if (type != isl_ineq_redundant) + return isl_bool_false; + list[n++] = l; + } + + return isl_bool_true; +} + +/* Given two basic maps such that "j" has at least one equality constraint + * that is adjacent to an inequality constraint of "i" and such that "i" has + * exactly one inequality constraint that is adjacent to an equality + * constraint of "j", check whether "i" can be extended to include "j" or + * whether "j" can be wrapped into "i". + * All remaining constraints of "i" and "j" are assumed to be valid + * or cut constraints of the other basic map. + * However, none of the equality constraints of "i" are cut constraints. + * + * If "i" has any "cut" inequality constraints, then check if relaxing + * each of them by one is sufficient for them to become valid. + * If so, check if the inequality constraint adjacent to an equality + * constraint of "j" along with all these cut constraints + * can be relaxed by one to contain exactly "j". + * Otherwise, or if this fails, check if "j" can be wrapped into "i". + */ +static enum isl_change check_single_adj_eq(int i, int j, + struct isl_coalesce_info *info) +{ + enum isl_change change = isl_change_none; + int k; + int n_cut; + int *relax; + isl_ctx *ctx; + isl_bool try_relax; + + n_cut = count_ineq(&info[i], STATUS_CUT); + + k = find_ineq(&info[i], STATUS_ADJ_EQ); + + if (n_cut > 0) { + ctx = isl_basic_map_get_ctx(info[i].bmap); + relax = isl_calloc_array(ctx, int, 1 + n_cut); + if (!relax) + return isl_change_error; + relax[0] = k; + try_relax = all_cut_by_one(i, j, info, relax + 1); + if (try_relax < 0) + change = isl_change_error; + } else { + try_relax = isl_bool_true; + relax = &k; + } + if (try_relax && change == isl_change_none) + change = is_relaxed_extension(i, j, 1 + n_cut, relax, info); + if (n_cut > 0) + free(relax); + if (change != isl_change_none) + return change; + + change = can_wrap_in_facet(i, j, k, info, n_cut > 0); + + return change; +} + +/* At least one of the basic maps has an equality that is adjacent + * to an inequality. Make sure that only one of the basic maps has + * such an equality and that the other basic map has exactly one + * inequality adjacent to an equality. + * If the other basic map does not have such an inequality, then + * check if all its constraints are either valid or cut constraints + * and, if so, try wrapping in the first map into the second. + * Otherwise, try to extend one basic map with the other or + * wrap one basic map in the other. + */ +static enum isl_change check_adj_eq(int i, int j, + struct isl_coalesce_info *info) +{ + if (any_eq(&info[i], STATUS_ADJ_INEQ) && + any_eq(&info[j], STATUS_ADJ_INEQ)) + /* ADJ EQ TOO MANY */ + return isl_change_none; + + if (any_eq(&info[i], STATUS_ADJ_INEQ)) + return check_adj_eq(j, i, info); + + /* j has an equality adjacent to an inequality in i */ + + if (count_ineq(&info[i], STATUS_ADJ_EQ) != 1) { + if (all_valid_or_cut(&info[i])) + return can_wrap_in_set(i, j, info); + return isl_change_none; + } + if (any_eq(&info[i], STATUS_CUT)) + return isl_change_none; + if (any_ineq(&info[j], STATUS_ADJ_EQ) || + any_ineq(&info[i], STATUS_ADJ_INEQ) || + any_ineq(&info[j], STATUS_ADJ_INEQ)) + /* ADJ EQ TOO MANY */ + return isl_change_none; + + return check_single_adj_eq(i, j, info); +} + +/* Disjunct "j" lies on a hyperplane that is adjacent to disjunct "i". + * In particular, disjunct "i" has an inequality constraint that is adjacent + * to a (combination of) equality constraint(s) of disjunct "j", + * but disjunct "j" has no explicit equality constraint adjacent + * to an inequality constraint of disjunct "i". + * + * Disjunct "i" is already known not to have any equality constraints + * that are adjacent to an equality or inequality constraint. + * Check that, other than the inequality constraint mentioned above, + * all other constraints of disjunct "i" are valid for disjunct "j". + * If so, try and wrap in disjunct "j". + */ +static enum isl_change check_ineq_adj_eq(int i, int j, + struct isl_coalesce_info *info) +{ + int k; + + if (any_eq(&info[i], STATUS_CUT)) + return isl_change_none; + if (any_ineq(&info[i], STATUS_CUT)) + return isl_change_none; + if (any_ineq(&info[i], STATUS_ADJ_INEQ)) + return isl_change_none; + if (count_ineq(&info[i], STATUS_ADJ_EQ) != 1) + return isl_change_none; + + k = find_ineq(&info[i], STATUS_ADJ_EQ); + + return can_wrap_in_facet(i, j, k, info, 0); +} + +/* The two basic maps lie on adjacent hyperplanes. In particular, + * basic map "i" has an equality that lies parallel to basic map "j". + * Check if we can wrap the facets around the parallel hyperplanes + * to include the other set. + * + * We perform basically the same operations as can_wrap_in_facet, + * except that we don't need to select a facet of one of the sets. + * _ + * \\ \\ + * \\ => \\ + * \ \| + * + * If there is more than one equality of "i" adjacent to an equality of "j", + * then the result will satisfy one or more equalities that are a linear + * combination of these equalities. These will be encoded as pairs + * of inequalities in the wrapping constraints and need to be made + * explicit. + */ +static enum isl_change check_eq_adj_eq(int i, int j, + struct isl_coalesce_info *info) +{ + int k; + enum isl_change change = isl_change_none; + int detect_equalities = 0; + struct isl_wraps wraps; + isl_ctx *ctx; + isl_mat *mat; + struct isl_set *set_i = NULL; + struct isl_set *set_j = NULL; + struct isl_vec *bound = NULL; + unsigned total = isl_basic_map_total_dim(info[i].bmap); + + if (count_eq(&info[i], STATUS_ADJ_EQ) != 1) + detect_equalities = 1; + + k = find_eq(&info[i], STATUS_ADJ_EQ); + + set_i = set_from_updated_bmap(info[i].bmap, info[i].tab); + set_j = set_from_updated_bmap(info[j].bmap, info[j].tab); + ctx = isl_basic_map_get_ctx(info[i].bmap); + mat = isl_mat_alloc(ctx, 2 * (info[i].bmap->n_eq + info[j].bmap->n_eq) + + info[i].bmap->n_ineq + info[j].bmap->n_ineq, + 1 + total); + if (wraps_init(&wraps, mat, info, i, j) < 0) + goto error; + bound = isl_vec_alloc(ctx, 1 + total); + if (!set_i || !set_j || !bound) + goto error; + + if (k % 2 == 0) + isl_seq_neg(bound->el, info[i].bmap->eq[k / 2], 1 + total); + else + isl_seq_cpy(bound->el, info[i].bmap->eq[k / 2], 1 + total); + isl_int_add_ui(bound->el[0], bound->el[0], 1); + + isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total); + wraps.mat->n_row = 1; + + if (add_wraps(&wraps, &info[j], bound->el, set_i) < 0) + goto error; + if (!wraps.mat->n_row) + goto unbounded; + + isl_int_sub_ui(bound->el[0], bound->el[0], 1); + isl_seq_neg(bound->el, bound->el, 1 + total); + + isl_seq_cpy(wraps.mat->row[wraps.mat->n_row], bound->el, 1 + total); + wraps.mat->n_row++; + + if (add_wraps(&wraps, &info[i], bound->el, set_j) < 0) + goto error; + if (!wraps.mat->n_row) + goto unbounded; + + change = fuse(i, j, info, wraps.mat, detect_equalities, 0); + + if (0) { +error: change = isl_change_error; + } +unbounded: + + wraps_free(&wraps); + isl_set_free(set_i); + isl_set_free(set_j); + isl_vec_free(bound); + + return change; +} + +/* Initialize the "eq" and "ineq" fields of "info". + */ +static void init_status(struct isl_coalesce_info *info) +{ + info->eq = info->ineq = NULL; +} + +/* Set info->eq to the positions of the equalities of info->bmap + * with respect to the basic map represented by "tab". + * If info->eq has already been computed, then do not compute it again. + */ +static void set_eq_status_in(struct isl_coalesce_info *info, + struct isl_tab *tab) +{ + if (info->eq) + return; + info->eq = eq_status_in(info->bmap, tab); +} + +/* Set info->ineq to the positions of the inequalities of info->bmap + * with respect to the basic map represented by "tab". + * If info->ineq has already been computed, then do not compute it again. + */ +static void set_ineq_status_in(struct isl_coalesce_info *info, + struct isl_tab *tab) +{ + if (info->ineq) + return; + info->ineq = ineq_status_in(info->bmap, info->tab, tab); +} + +/* Free the memory allocated by the "eq" and "ineq" fields of "info". + * This function assumes that init_status has been called on "info" first, + * after which the "eq" and "ineq" fields may or may not have been + * assigned a newly allocated array. + */ +static void clear_status(struct isl_coalesce_info *info) +{ + free(info->eq); + free(info->ineq); +} + +/* Are all inequality constraints of the basic map represented by "info" + * valid for the other basic map, except for a single constraint + * that is adjacent to an inequality constraint of the other basic map? + */ +static int all_ineq_valid_or_single_adj_ineq(struct isl_coalesce_info *info) +{ + int i; + int k = -1; + + for (i = 0; i < info->bmap->n_ineq; ++i) { + if (info->ineq[i] == STATUS_REDUNDANT) + continue; + if (info->ineq[i] == STATUS_VALID) + continue; + if (info->ineq[i] != STATUS_ADJ_INEQ) + return 0; + if (k != -1) + return 0; + k = i; + } + + return k != -1; +} + +/* Basic map "i" has one or more equality constraints that separate it + * from basic map "j". Check if it happens to be an extension + * of basic map "j". + * In particular, check that all constraints of "j" are valid for "i", + * except for one inequality constraint that is adjacent + * to an inequality constraints of "i". + * If so, check for "i" being an extension of "j" by calling + * is_adj_ineq_extension. + * + * Clean up the memory allocated for keeping track of the status + * of the constraints before returning. + */ +static enum isl_change separating_equality(int i, int j, + struct isl_coalesce_info *info) +{ + enum isl_change change = isl_change_none; + + if (all(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_VALID) && + all_ineq_valid_or_single_adj_ineq(&info[j])) + change = is_adj_ineq_extension(j, i, info); + + clear_status(&info[i]); + clear_status(&info[j]); + return change; +} + +/* Check if the union of the given pair of basic maps + * can be represented by a single basic map. + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. + * The two basic maps are assumed to live in the same local space. + * The "eq" and "ineq" fields of info[i] and info[j] are assumed + * to have been initialized by the caller, either to NULL or + * to valid information. + * + * We first check the effect of each constraint of one basic map + * on the other basic map. + * The constraint may be + * redundant the constraint is redundant in its own + * basic map and should be ignore and removed + * in the end + * valid all (integer) points of the other basic map + * satisfy the constraint + * separate no (integer) point of the other basic map + * satisfies the constraint + * cut some but not all points of the other basic map + * satisfy the constraint + * adj_eq the given constraint is adjacent (on the outside) + * to an equality of the other basic map + * adj_ineq the given constraint is adjacent (on the outside) + * to an inequality of the other basic map + * + * We consider seven cases in which we can replace the pair by a single + * basic map. We ignore all "redundant" constraints. + * + * 1. all constraints of one basic map are valid + * => the other basic map is a subset and can be removed + * + * 2. all constraints of both basic maps are either "valid" or "cut" + * and the facets corresponding to the "cut" constraints + * of one of the basic maps lies entirely inside the other basic map + * => the pair can be replaced by a basic map consisting + * of the valid constraints in both basic maps + * + * 3. there is a single pair of adjacent inequalities + * (all other constraints are "valid") + * => the pair can be replaced by a basic map consisting + * of the valid constraints in both basic maps + * + * 4. one basic map has a single adjacent inequality, while the other + * constraints are "valid". The other basic map has some + * "cut" constraints, but replacing the adjacent inequality by + * its opposite and adding the valid constraints of the other + * basic map results in a subset of the other basic map + * => the pair can be replaced by a basic map consisting + * of the valid constraints in both basic maps + * + * 5. there is a single adjacent pair of an inequality and an equality, + * the other constraints of the basic map containing the inequality are + * "valid". Moreover, if the inequality the basic map is relaxed + * and then turned into an equality, then resulting facet lies + * entirely inside the other basic map + * => the pair can be replaced by the basic map containing + * the inequality, with the inequality relaxed. + * + * 6. there is a single inequality adjacent to an equality, + * the other constraints of the basic map containing the inequality are + * "valid". Moreover, the facets corresponding to both + * the inequality and the equality can be wrapped around their + * ridges to include the other basic map + * => the pair can be replaced by a basic map consisting + * of the valid constraints in both basic maps together + * with all wrapping constraints + * + * 7. one of the basic maps extends beyond the other by at most one. + * Moreover, the facets corresponding to the cut constraints and + * the pieces of the other basic map at offset one from these cut + * constraints can be wrapped around their ridges to include + * the union of the two basic maps + * => the pair can be replaced by a basic map consisting + * of the valid constraints in both basic maps together + * with all wrapping constraints + * + * 8. the two basic maps live in adjacent hyperplanes. In principle + * such sets can always be combined through wrapping, but we impose + * that there is only one such pair, to avoid overeager coalescing. + * + * Throughout the computation, we maintain a collection of tableaus + * corresponding to the basic maps. When the basic maps are dropped + * or combined, the tableaus are modified accordingly. + */ +static enum isl_change coalesce_local_pair_reuse(int i, int j, + struct isl_coalesce_info *info) +{ + enum isl_change change = isl_change_none; + + set_ineq_status_in(&info[i], info[j].tab); + if (info[i].bmap->n_ineq && !info[i].ineq) + goto error; + if (any_ineq(&info[i], STATUS_ERROR)) + goto error; + if (any_ineq(&info[i], STATUS_SEPARATE)) + goto done; + + set_ineq_status_in(&info[j], info[i].tab); + if (info[j].bmap->n_ineq && !info[j].ineq) + goto error; + if (any_ineq(&info[j], STATUS_ERROR)) + goto error; + if (any_ineq(&info[j], STATUS_SEPARATE)) + goto done; + + set_eq_status_in(&info[i], info[j].tab); + if (info[i].bmap->n_eq && !info[i].eq) + goto error; + if (any_eq(&info[i], STATUS_ERROR)) + goto error; + + set_eq_status_in(&info[j], info[i].tab); + if (info[j].bmap->n_eq && !info[j].eq) + goto error; + if (any_eq(&info[j], STATUS_ERROR)) + goto error; + + if (any_eq(&info[i], STATUS_SEPARATE)) + return separating_equality(i, j, info); + if (any_eq(&info[j], STATUS_SEPARATE)) + return separating_equality(j, i, info); + + if (all(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_VALID) && + all(info[i].ineq, info[i].bmap->n_ineq, STATUS_VALID)) { + drop(&info[j]); + change = isl_change_drop_second; + } else if (all(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_VALID) && + all(info[j].ineq, info[j].bmap->n_ineq, STATUS_VALID)) { + drop(&info[i]); + change = isl_change_drop_first; + } else if (any_eq(&info[i], STATUS_ADJ_EQ)) { + change = check_eq_adj_eq(i, j, info); + } else if (any_eq(&info[j], STATUS_ADJ_EQ)) { + change = check_eq_adj_eq(j, i, info); + } else if (any_eq(&info[i], STATUS_ADJ_INEQ) || + any_eq(&info[j], STATUS_ADJ_INEQ)) { + change = check_adj_eq(i, j, info); + } else if (any_ineq(&info[i], STATUS_ADJ_EQ)) { + change = check_ineq_adj_eq(i, j, info); + } else if (any_ineq(&info[j], STATUS_ADJ_EQ)) { + change = check_ineq_adj_eq(j, i, info); + } else if (any_ineq(&info[i], STATUS_ADJ_INEQ) || + any_ineq(&info[j], STATUS_ADJ_INEQ)) { + change = check_adj_ineq(i, j, info); + } else { + if (!any_eq(&info[i], STATUS_CUT) && + !any_eq(&info[j], STATUS_CUT)) + change = check_facets(i, j, info); + if (change == isl_change_none) + change = check_wrap(i, j, info); + } + +done: + clear_status(&info[i]); + clear_status(&info[j]); + return change; +error: + clear_status(&info[i]); + clear_status(&info[j]); + return isl_change_error; +} + +/* Check if the union of the given pair of basic maps + * can be represented by a single basic map. + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. + * The two basic maps are assumed to live in the same local space. + */ +static enum isl_change coalesce_local_pair(int i, int j, + struct isl_coalesce_info *info) +{ + init_status(&info[i]); + init_status(&info[j]); + return coalesce_local_pair_reuse(i, j, info); +} + +/* Shift the integer division at position "div" of the basic map + * represented by "info" by "shift". + * + * That is, if the integer division has the form + * + * floor(f(x)/d) + * + * then replace it by + * + * floor((f(x) + shift * d)/d) - shift + */ +static isl_stat shift_div(struct isl_coalesce_info *info, int div, + isl_int shift) +{ + unsigned total; + + info->bmap = isl_basic_map_shift_div(info->bmap, div, 0, shift); + if (!info->bmap) + return isl_stat_error; + + total = isl_basic_map_dim(info->bmap, isl_dim_all); + total -= isl_basic_map_dim(info->bmap, isl_dim_div); + if (isl_tab_shift_var(info->tab, total + div, shift) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* If the integer division at position "div" is defined by an equality, + * i.e., a stride constraint, then change the integer division expression + * to have a constant term equal to zero. + * + * Let the equality constraint be + * + * c + f + m a = 0 + * + * The integer division expression is then of the form + * + * a = floor((-f - c')/m) + * + * The integer division is first shifted by t = floor(c/m), + * turning the equality constraint into + * + * c - m floor(c/m) + f + m a' = 0 + * + * i.e., + * + * (c mod m) + f + m a' = 0 + * + * That is, + * + * a' = (-f - (c mod m))/m = floor((-f)/m) + * + * because a' is an integer and 0 <= (c mod m) < m. + * The constant term of a' can therefore be zeroed out. + */ +static isl_stat normalize_stride_div(struct isl_coalesce_info *info, int div) +{ + isl_bool defined; + isl_stat r; + isl_constraint *c; + isl_int shift, stride; + + defined = isl_basic_map_has_defining_equality(info->bmap, isl_dim_div, + div, &c); + if (defined < 0) + return isl_stat_error; + if (!defined) + return isl_stat_ok; + if (!c) + return isl_stat_error; + isl_int_init(shift); + isl_int_init(stride); + isl_constraint_get_constant(c, &shift); + isl_constraint_get_coefficient(c, isl_dim_div, div, &stride); + isl_int_fdiv_q(shift, shift, stride); + r = shift_div(info, div, shift); + isl_int_clear(stride); + isl_int_clear(shift); + isl_constraint_free(c); + if (r < 0) + return isl_stat_error; + info->bmap = isl_basic_map_set_div_expr_constant_num_si_inplace( + info->bmap, div, 0); + if (!info->bmap) + return isl_stat_error; + return isl_stat_ok; +} + +/* The basic maps represented by "info1" and "info2" are known + * to have the same number of integer divisions. + * Check if pairs of integer divisions are equal to each other + * despite the fact that they differ by a rational constant. + * + * In particular, look for any pair of integer divisions that + * only differ in their constant terms. + * If either of these integer divisions is defined + * by stride constraints, then modify it to have a zero constant term. + * If both are defined by stride constraints then in the end they will have + * the same (zero) constant term. + */ +static isl_stat harmonize_stride_divs(struct isl_coalesce_info *info1, + struct isl_coalesce_info *info2) +{ + int i, n; + + n = isl_basic_map_dim(info1->bmap, isl_dim_div); + for (i = 0; i < n; ++i) { + isl_bool known, harmonize; + + known = isl_basic_map_div_is_known(info1->bmap, i); + if (known >= 0 && known) + known = isl_basic_map_div_is_known(info2->bmap, i); + if (known < 0) + return isl_stat_error; + if (!known) + continue; + harmonize = isl_basic_map_equal_div_expr_except_constant( + info1->bmap, i, info2->bmap, i); + if (harmonize < 0) + return isl_stat_error; + if (!harmonize) + continue; + if (normalize_stride_div(info1, i) < 0) + return isl_stat_error; + if (normalize_stride_div(info2, i) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* If "shift" is an integer constant, then shift the integer division + * at position "div" of the basic map represented by "info" by "shift". + * If "shift" is not an integer constant, then do nothing. + * If "shift" is equal to zero, then no shift needs to be performed either. + * + * That is, if the integer division has the form + * + * floor(f(x)/d) + * + * then replace it by + * + * floor((f(x) + shift * d)/d) - shift + */ +static isl_stat shift_if_cst_int(struct isl_coalesce_info *info, int div, + __isl_keep isl_aff *shift) +{ + isl_bool cst; + isl_stat r; + isl_int d; + isl_val *c; + + cst = isl_aff_is_cst(shift); + if (cst < 0 || !cst) + return cst < 0 ? isl_stat_error : isl_stat_ok; + + c = isl_aff_get_constant_val(shift); + cst = isl_val_is_int(c); + if (cst >= 0 && cst) + cst = isl_bool_not(isl_val_is_zero(c)); + if (cst < 0 || !cst) { + isl_val_free(c); + return cst < 0 ? isl_stat_error : isl_stat_ok; + } + + isl_int_init(d); + r = isl_val_get_num_isl_int(c, &d); + if (r >= 0) + r = shift_div(info, div, d); + isl_int_clear(d); + + isl_val_free(c); + + return r; +} + +/* Check if some of the divs in the basic map represented by "info1" + * are shifts of the corresponding divs in the basic map represented + * by "info2", taking into account the equality constraints "eq1" of "info1" + * and "eq2" of "info2". If so, align them with those of "info2". + * "info1" and "info2" are assumed to have the same number + * of integer divisions. + * + * An integer division is considered to be a shift of another integer + * division if, after simplification with respect to the equality + * constraints of the other basic map, one is equal to the other + * plus a constant. + * + * In particular, for each pair of integer divisions, if both are known, + * have the same denominator and are not already equal to each other, + * simplify each with respect to the equality constraints + * of the other basic map. If the difference is an integer constant, + * then move this difference outside. + * That is, if, after simplification, one integer division is of the form + * + * floor((f(x) + c_1)/d) + * + * while the other is of the form + * + * floor((f(x) + c_2)/d) + * + * and n = (c_2 - c_1)/d is an integer, then replace the first + * integer division by + * + * floor((f_1(x) + c_1 + n * d)/d) - n, + * + * where floor((f_1(x) + c_1 + n * d)/d) = floor((f2(x) + c_2)/d) + * after simplification with respect to the equality constraints. + */ +static isl_stat harmonize_divs_with_hulls(struct isl_coalesce_info *info1, + struct isl_coalesce_info *info2, __isl_keep isl_basic_set *eq1, + __isl_keep isl_basic_set *eq2) +{ + int i; + int total; + isl_local_space *ls1, *ls2; + + total = isl_basic_map_total_dim(info1->bmap); + ls1 = isl_local_space_wrap(isl_basic_map_get_local_space(info1->bmap)); + ls2 = isl_local_space_wrap(isl_basic_map_get_local_space(info2->bmap)); + for (i = 0; i < info1->bmap->n_div; ++i) { + isl_stat r; + isl_aff *div1, *div2; + + if (!isl_local_space_div_is_known(ls1, i) || + !isl_local_space_div_is_known(ls2, i)) + continue; + if (isl_int_ne(info1->bmap->div[i][0], info2->bmap->div[i][0])) + continue; + if (isl_seq_eq(info1->bmap->div[i] + 1, + info2->bmap->div[i] + 1, 1 + total)) + continue; + div1 = isl_local_space_get_div(ls1, i); + div2 = isl_local_space_get_div(ls2, i); + div1 = isl_aff_substitute_equalities(div1, + isl_basic_set_copy(eq2)); + div2 = isl_aff_substitute_equalities(div2, + isl_basic_set_copy(eq1)); + div2 = isl_aff_sub(div2, div1); + r = shift_if_cst_int(info1, i, div2); + isl_aff_free(div2); + if (r < 0) + break; + } + isl_local_space_free(ls1); + isl_local_space_free(ls2); + + if (i < info1->bmap->n_div) + return isl_stat_error; + return isl_stat_ok; +} + +/* Check if some of the divs in the basic map represented by "info1" + * are shifts of the corresponding divs in the basic map represented + * by "info2". If so, align them with those of "info2". + * Only do this if "info1" and "info2" have the same number + * of integer divisions. + * + * An integer division is considered to be a shift of another integer + * division if, after simplification with respect to the equality + * constraints of the other basic map, one is equal to the other + * plus a constant. + * + * First check if pairs of integer divisions are equal to each other + * despite the fact that they differ by a rational constant. + * If so, try and arrange for them to have the same constant term. + * + * Then, extract the equality constraints and continue with + * harmonize_divs_with_hulls. + * + * If the equality constraints of both basic maps are the same, + * then there is no need to perform any shifting since + * the coefficients of the integer divisions should have been + * reduced in the same way. + */ +static isl_stat harmonize_divs(struct isl_coalesce_info *info1, + struct isl_coalesce_info *info2) +{ + isl_bool equal; + isl_basic_map *bmap1, *bmap2; + isl_basic_set *eq1, *eq2; + isl_stat r; + + if (!info1->bmap || !info2->bmap) + return isl_stat_error; + + if (info1->bmap->n_div != info2->bmap->n_div) + return isl_stat_ok; + if (info1->bmap->n_div == 0) + return isl_stat_ok; + + if (harmonize_stride_divs(info1, info2) < 0) + return isl_stat_error; + + bmap1 = isl_basic_map_copy(info1->bmap); + bmap2 = isl_basic_map_copy(info2->bmap); + eq1 = isl_basic_map_wrap(isl_basic_map_plain_affine_hull(bmap1)); + eq2 = isl_basic_map_wrap(isl_basic_map_plain_affine_hull(bmap2)); + equal = isl_basic_set_plain_is_equal(eq1, eq2); + if (equal < 0) + r = isl_stat_error; + else if (equal) + r = isl_stat_ok; + else + r = harmonize_divs_with_hulls(info1, info2, eq1, eq2); + isl_basic_set_free(eq1); + isl_basic_set_free(eq2); + + return r; +} + +/* Do the two basic maps live in the same local space, i.e., + * do they have the same (known) divs? + * If either basic map has any unknown divs, then we can only assume + * that they do not live in the same local space. + */ +static isl_bool same_divs(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2) +{ + int i; + isl_bool known; + int total; + + if (!bmap1 || !bmap2) + return isl_bool_error; + if (bmap1->n_div != bmap2->n_div) + return isl_bool_false; + + if (bmap1->n_div == 0) + return isl_bool_true; + + known = isl_basic_map_divs_known(bmap1); + if (known < 0 || !known) + return known; + known = isl_basic_map_divs_known(bmap2); + if (known < 0 || !known) + return known; + + total = isl_basic_map_total_dim(bmap1); + for (i = 0; i < bmap1->n_div; ++i) + if (!isl_seq_eq(bmap1->div[i], bmap2->div[i], 2 + total)) + return 0; + + return 1; +} + +/* Assuming that "tab" contains the equality constraints and + * the initial inequality constraints of "bmap", copy the remaining + * inequality constraints of "bmap" to "Tab". + */ +static isl_stat copy_ineq(struct isl_tab *tab, __isl_keep isl_basic_map *bmap) +{ + int i, n_ineq; + + if (!bmap) + return isl_stat_error; + + n_ineq = tab->n_con - tab->n_eq; + for (i = n_ineq; i < bmap->n_ineq; ++i) + if (isl_tab_add_ineq(tab, bmap->ineq[i]) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Description of an integer division that is added + * during an expansion. + * "pos" is the position of the corresponding variable. + * "cst" indicates whether this integer division has a fixed value. + * "val" contains the fixed value, if the value is fixed. + */ +struct isl_expanded { + int pos; + isl_bool cst; + isl_int val; +}; + +/* For each of the "n" integer division variables "expanded", + * if the variable has a fixed value, then add two inequality + * constraints expressing the fixed value. + * Otherwise, add the corresponding div constraints. + * The caller is responsible for removing the div constraints + * that it added for all these "n" integer divisions. + * + * The div constraints and the pair of inequality constraints + * forcing the fixed value cannot both be added for a given variable + * as the combination may render some of the original constraints redundant. + * These would then be ignored during the coalescing detection, + * while they could remain in the fused result. + * + * The two added inequality constraints are + * + * -a + v >= 0 + * a - v >= 0 + * + * with "a" the variable and "v" its fixed value. + * The facet corresponding to one of these two constraints is selected + * in the tableau to ensure that the pair of inequality constraints + * is treated as an equality constraint. + * + * The information in info->ineq is thrown away because it was + * computed in terms of div constraints, while some of those + * have now been replaced by these pairs of inequality constraints. + */ +static isl_stat fix_constant_divs(struct isl_coalesce_info *info, + int n, struct isl_expanded *expanded) +{ + unsigned o_div; + int i; + isl_vec *ineq; + + o_div = isl_basic_map_offset(info->bmap, isl_dim_div) - 1; + ineq = isl_vec_alloc(isl_tab_get_ctx(info->tab), 1 + info->tab->n_var); + if (!ineq) + return isl_stat_error; + isl_seq_clr(ineq->el + 1, info->tab->n_var); + + for (i = 0; i < n; ++i) { + if (!expanded[i].cst) { + info->bmap = isl_basic_map_extend_constraints( + info->bmap, 0, 2); + if (isl_basic_map_add_div_constraints(info->bmap, + expanded[i].pos - o_div) < 0) + break; + } else { + isl_int_set_si(ineq->el[1 + expanded[i].pos], -1); + isl_int_set(ineq->el[0], expanded[i].val); + info->bmap = isl_basic_map_add_ineq(info->bmap, + ineq->el); + isl_int_set_si(ineq->el[1 + expanded[i].pos], 1); + isl_int_neg(ineq->el[0], expanded[i].val); + info->bmap = isl_basic_map_add_ineq(info->bmap, + ineq->el); + isl_int_set_si(ineq->el[1 + expanded[i].pos], 0); + } + if (copy_ineq(info->tab, info->bmap) < 0) + break; + if (expanded[i].cst && + isl_tab_select_facet(info->tab, info->tab->n_con - 1) < 0) + break; + } + + isl_vec_free(ineq); + + clear_status(info); + init_status(info); + + return i < n ? isl_stat_error : isl_stat_ok; +} + +/* Insert the "n" integer division variables "expanded" + * into info->tab and info->bmap and + * update info->ineq with respect to the redundant constraints + * in the resulting tableau. + * "bmap" contains the result of this insertion in info->bmap, + * while info->bmap is the original version + * of "bmap", i.e., the one that corresponds to the current + * state of info->tab. The number of constraints in info->bmap + * is assumed to be the same as the number of constraints + * in info->tab. This is required to be able to detect + * the extra constraints in "bmap". + * + * In particular, introduce extra variables corresponding + * to the extra integer divisions and add the div constraints + * that were added to "bmap" after info->tab was created + * from info->bmap. + * Furthermore, check if these extra integer divisions happen + * to attain a fixed integer value in info->tab. + * If so, replace the corresponding div constraints by pairs + * of inequality constraints that fix these + * integer divisions to their single integer values. + * Replace info->bmap by "bmap" to match the changes to info->tab. + * info->ineq was computed without a tableau and therefore + * does not take into account the redundant constraints + * in the tableau. Mark them here. + * There is no need to check the newly added div constraints + * since they cannot be redundant. + * The redundancy check is not performed when constants have been discovered + * since info->ineq is completely thrown away in this case. + */ +static isl_stat tab_insert_divs(struct isl_coalesce_info *info, + int n, struct isl_expanded *expanded, __isl_take isl_basic_map *bmap) +{ + int i, n_ineq; + unsigned n_eq; + struct isl_tab_undo *snap; + int any; + + if (!bmap) + return isl_stat_error; + if (info->bmap->n_eq + info->bmap->n_ineq != info->tab->n_con) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_internal, + "original tableau does not correspond " + "to original basic map", goto error); + + if (isl_tab_extend_vars(info->tab, n) < 0) + goto error; + if (isl_tab_extend_cons(info->tab, 2 * n) < 0) + goto error; + + for (i = 0; i < n; ++i) { + if (isl_tab_insert_var(info->tab, expanded[i].pos) < 0) + goto error; + } + + snap = isl_tab_snap(info->tab); + + n_ineq = info->tab->n_con - info->tab->n_eq; + if (copy_ineq(info->tab, bmap) < 0) + goto error; + + isl_basic_map_free(info->bmap); + info->bmap = bmap; + + any = 0; + for (i = 0; i < n; ++i) { + expanded[i].cst = isl_tab_is_constant(info->tab, + expanded[i].pos, &expanded[i].val); + if (expanded[i].cst < 0) + return isl_stat_error; + if (expanded[i].cst) + any = 1; + } + + if (any) { + if (isl_tab_rollback(info->tab, snap) < 0) + return isl_stat_error; + info->bmap = isl_basic_map_cow(info->bmap); + if (isl_basic_map_free_inequality(info->bmap, 2 * n) < 0) + return isl_stat_error; + + return fix_constant_divs(info, n, expanded); + } + + n_eq = info->bmap->n_eq; + for (i = 0; i < n_ineq; ++i) { + if (isl_tab_is_redundant(info->tab, n_eq + i)) + info->ineq[i] = STATUS_REDUNDANT; + } + + return isl_stat_ok; +error: + isl_basic_map_free(bmap); + return isl_stat_error; +} + +/* Expand info->tab and info->bmap in the same way "bmap" was expanded + * in isl_basic_map_expand_divs using the expansion "exp" and + * update info->ineq with respect to the redundant constraints + * in the resulting tableau. info->bmap is the original version + * of "bmap", i.e., the one that corresponds to the current + * state of info->tab. The number of constraints in info->bmap + * is assumed to be the same as the number of constraints + * in info->tab. This is required to be able to detect + * the extra constraints in "bmap". + * + * Extract the positions where extra local variables are introduced + * from "exp" and call tab_insert_divs. + */ +static isl_stat expand_tab(struct isl_coalesce_info *info, int *exp, + __isl_take isl_basic_map *bmap) +{ + isl_ctx *ctx; + struct isl_expanded *expanded; + int i, j, k, n; + int extra_var; + unsigned total, pos, n_div; + isl_stat r; + + total = isl_basic_map_dim(bmap, isl_dim_all); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + pos = total - n_div; + extra_var = total - info->tab->n_var; + n = n_div - extra_var; + + ctx = isl_basic_map_get_ctx(bmap); + expanded = isl_calloc_array(ctx, struct isl_expanded, extra_var); + if (extra_var && !expanded) + goto error; + + i = 0; + k = 0; + for (j = 0; j < n_div; ++j) { + if (i < n && exp[i] == j) { + ++i; + continue; + } + expanded[k++].pos = pos + j; + } + + for (k = 0; k < extra_var; ++k) + isl_int_init(expanded[k].val); + + r = tab_insert_divs(info, extra_var, expanded, bmap); + + for (k = 0; k < extra_var; ++k) + isl_int_clear(expanded[k].val); + free(expanded); + + return r; +error: + isl_basic_map_free(bmap); + return isl_stat_error; +} + +/* Check if the union of the basic maps represented by info[i] and info[j] + * can be represented by a single basic map, + * after expanding the divs of info[i] to match those of info[j]. + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. + * + * The caller has already checked for info[j] being a subset of info[i]. + * If some of the divs of info[j] are unknown, then the expanded info[i] + * will not have the corresponding div constraints. The other patterns + * therefore cannot apply. Skip the computation in this case. + * + * The expansion is performed using the divs "div" and expansion "exp" + * computed by the caller. + * info[i].bmap has already been expanded and the result is passed in + * as "bmap". + * The "eq" and "ineq" fields of info[i] reflect the status of + * the constraints of the expanded "bmap" with respect to info[j].tab. + * However, inequality constraints that are redundant in info[i].tab + * have not yet been marked as such because no tableau was available. + * + * Replace info[i].bmap by "bmap" and expand info[i].tab as well, + * updating info[i].ineq with respect to the redundant constraints. + * Then try and coalesce the expanded info[i] with info[j], + * reusing the information in info[i].eq and info[i].ineq. + * If this does not result in any coalescing or if it results in info[j] + * getting dropped (which should not happen in practice, since the case + * of info[j] being a subset of info[i] has already been checked by + * the caller), then revert info[i] to its original state. + */ +static enum isl_change coalesce_expand_tab_divs(__isl_take isl_basic_map *bmap, + int i, int j, struct isl_coalesce_info *info, __isl_keep isl_mat *div, + int *exp) +{ + isl_bool known; + isl_basic_map *bmap_i; + struct isl_tab_undo *snap; + enum isl_change change = isl_change_none; + + known = isl_basic_map_divs_known(info[j].bmap); + if (known < 0 || !known) { + clear_status(&info[i]); + isl_basic_map_free(bmap); + return known < 0 ? isl_change_error : isl_change_none; + } + + bmap_i = isl_basic_map_copy(info[i].bmap); + snap = isl_tab_snap(info[i].tab); + if (expand_tab(&info[i], exp, bmap) < 0) + change = isl_change_error; + + init_status(&info[j]); + if (change == isl_change_none) + change = coalesce_local_pair_reuse(i, j, info); + else + clear_status(&info[i]); + if (change != isl_change_none && change != isl_change_drop_second) { + isl_basic_map_free(bmap_i); + } else { + isl_basic_map_free(info[i].bmap); + info[i].bmap = bmap_i; + + if (isl_tab_rollback(info[i].tab, snap) < 0) + change = isl_change_error; + } + + return change; +} + +/* Check if the union of "bmap" and the basic map represented by info[j] + * can be represented by a single basic map, + * after expanding the divs of "bmap" to match those of info[j]. + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. + * + * In particular, check if the expanded "bmap" contains the basic map + * represented by the tableau info[j].tab. + * The expansion is performed using the divs "div" and expansion "exp" + * computed by the caller. + * Then we check if all constraints of the expanded "bmap" are valid for + * info[j].tab. + * + * If "i" is not equal to -1, then "bmap" is equal to info[i].bmap. + * In this case, the positions of the constraints of info[i].bmap + * with respect to the basic map represented by info[j] are stored + * in info[i]. + * + * If the expanded "bmap" does not contain the basic map + * represented by the tableau info[j].tab and if "i" is not -1, + * i.e., if the original "bmap" is info[i].bmap, then expand info[i].tab + * as well and check if that results in coalescing. + */ +static enum isl_change coalesce_with_expanded_divs( + __isl_keep isl_basic_map *bmap, int i, int j, + struct isl_coalesce_info *info, __isl_keep isl_mat *div, int *exp) +{ + enum isl_change change = isl_change_none; + struct isl_coalesce_info info_local, *info_i; + + info_i = i >= 0 ? &info[i] : &info_local; + init_status(info_i); + bmap = isl_basic_map_copy(bmap); + bmap = isl_basic_map_expand_divs(bmap, isl_mat_copy(div), exp); + bmap = isl_basic_map_mark_final(bmap); + + if (!bmap) + goto error; + + info_local.bmap = bmap; + info_i->eq = eq_status_in(bmap, info[j].tab); + if (bmap->n_eq && !info_i->eq) + goto error; + if (any_eq(info_i, STATUS_ERROR)) + goto error; + if (any_eq(info_i, STATUS_SEPARATE)) + goto done; + + info_i->ineq = ineq_status_in(bmap, NULL, info[j].tab); + if (bmap->n_ineq && !info_i->ineq) + goto error; + if (any_ineq(info_i, STATUS_ERROR)) + goto error; + if (any_ineq(info_i, STATUS_SEPARATE)) + goto done; + + if (all(info_i->eq, 2 * bmap->n_eq, STATUS_VALID) && + all(info_i->ineq, bmap->n_ineq, STATUS_VALID)) { + drop(&info[j]); + change = isl_change_drop_second; + } + + if (change == isl_change_none && i != -1) + return coalesce_expand_tab_divs(bmap, i, j, info, div, exp); + +done: + isl_basic_map_free(bmap); + clear_status(info_i); + return change; +error: + isl_basic_map_free(bmap); + clear_status(info_i); + return isl_change_error; +} + +/* Check if the union of "bmap_i" and the basic map represented by info[j] + * can be represented by a single basic map, + * after aligning the divs of "bmap_i" to match those of info[j]. + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. + * + * In particular, check if "bmap_i" contains the basic map represented by + * info[j] after aligning the divs of "bmap_i" to those of info[j]. + * Note that this can only succeed if the number of divs of "bmap_i" + * is smaller than (or equal to) the number of divs of info[j]. + * + * We first check if the divs of "bmap_i" are all known and form a subset + * of those of info[j].bmap. If so, we pass control over to + * coalesce_with_expanded_divs. + * + * If "i" is not equal to -1, then "bmap" is equal to info[i].bmap. + */ +static enum isl_change coalesce_after_aligning_divs( + __isl_keep isl_basic_map *bmap_i, int i, int j, + struct isl_coalesce_info *info) +{ + int known; + isl_mat *div_i, *div_j, *div; + int *exp1 = NULL; + int *exp2 = NULL; + isl_ctx *ctx; + enum isl_change change; + + known = isl_basic_map_divs_known(bmap_i); + if (known < 0 || !known) + return known; + + ctx = isl_basic_map_get_ctx(bmap_i); + + div_i = isl_basic_map_get_divs(bmap_i); + div_j = isl_basic_map_get_divs(info[j].bmap); + + if (!div_i || !div_j) + goto error; + + exp1 = isl_alloc_array(ctx, int, div_i->n_row); + exp2 = isl_alloc_array(ctx, int, div_j->n_row); + if ((div_i->n_row && !exp1) || (div_j->n_row && !exp2)) + goto error; + + div = isl_merge_divs(div_i, div_j, exp1, exp2); + if (!div) + goto error; + + if (div->n_row == div_j->n_row) + change = coalesce_with_expanded_divs(bmap_i, + i, j, info, div, exp1); + else + change = isl_change_none; + + isl_mat_free(div); + + isl_mat_free(div_i); + isl_mat_free(div_j); + + free(exp2); + free(exp1); + + return change; +error: + isl_mat_free(div_i); + isl_mat_free(div_j); + free(exp1); + free(exp2); + return isl_change_error; +} + +/* Check if basic map "j" is a subset of basic map "i" after + * exploiting the extra equalities of "j" to simplify the divs of "i". + * If so, remove basic map "j" and return isl_change_drop_second. + * + * If "j" does not have any equalities or if they are the same + * as those of "i", then we cannot exploit them to simplify the divs. + * Similarly, if there are no divs in "i", then they cannot be simplified. + * If, on the other hand, the affine hulls of "i" and "j" do not intersect, + * then "j" cannot be a subset of "i". + * + * Otherwise, we intersect "i" with the affine hull of "j" and then + * check if "j" is a subset of the result after aligning the divs. + * If so, then "j" is definitely a subset of "i" and can be removed. + * Note that if after intersection with the affine hull of "j". + * "i" still has more divs than "j", then there is no way we can + * align the divs of "i" to those of "j". + */ +static enum isl_change coalesce_subset_with_equalities(int i, int j, + struct isl_coalesce_info *info) +{ + isl_basic_map *hull_i, *hull_j, *bmap_i; + int equal, empty; + enum isl_change change; + + if (info[j].bmap->n_eq == 0) + return isl_change_none; + if (info[i].bmap->n_div == 0) + return isl_change_none; + + hull_i = isl_basic_map_copy(info[i].bmap); + hull_i = isl_basic_map_plain_affine_hull(hull_i); + hull_j = isl_basic_map_copy(info[j].bmap); + hull_j = isl_basic_map_plain_affine_hull(hull_j); + + hull_j = isl_basic_map_intersect(hull_j, isl_basic_map_copy(hull_i)); + equal = isl_basic_map_plain_is_equal(hull_i, hull_j); + empty = isl_basic_map_plain_is_empty(hull_j); + isl_basic_map_free(hull_i); + + if (equal < 0 || equal || empty < 0 || empty) { + isl_basic_map_free(hull_j); + if (equal < 0 || empty < 0) + return isl_change_error; + return isl_change_none; + } + + bmap_i = isl_basic_map_copy(info[i].bmap); + bmap_i = isl_basic_map_intersect(bmap_i, hull_j); + if (!bmap_i) + return isl_change_error; + + if (bmap_i->n_div > info[j].bmap->n_div) { + isl_basic_map_free(bmap_i); + return isl_change_none; + } + + change = coalesce_after_aligning_divs(bmap_i, -1, j, info); + + isl_basic_map_free(bmap_i); + + return change; +} + +/* Check if the union of and the basic maps represented by info[i] and info[j] + * can be represented by a single basic map, by aligning or equating + * their integer divisions. + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. + * + * Note that we only perform any test if the number of divs is different + * in the two basic maps. In case the number of divs is the same, + * we have already established that the divs are different + * in the two basic maps. + * In particular, if the number of divs of basic map i is smaller than + * the number of divs of basic map j, then we check if j is a subset of i + * and vice versa. + */ +static enum isl_change coalesce_divs(int i, int j, + struct isl_coalesce_info *info) +{ + enum isl_change change = isl_change_none; + + if (info[i].bmap->n_div < info[j].bmap->n_div) + change = coalesce_after_aligning_divs(info[i].bmap, i, j, info); + if (change != isl_change_none) + return change; + + if (info[j].bmap->n_div < info[i].bmap->n_div) + change = coalesce_after_aligning_divs(info[j].bmap, j, i, info); + if (change != isl_change_none) + return invert_change(change); + + change = coalesce_subset_with_equalities(i, j, info); + if (change != isl_change_none) + return change; + + change = coalesce_subset_with_equalities(j, i, info); + if (change != isl_change_none) + return invert_change(change); + + return isl_change_none; +} + +/* Does "bmap" involve any divs that themselves refer to divs? + */ +static isl_bool has_nested_div(__isl_keep isl_basic_map *bmap) +{ + int i; + unsigned total; + unsigned n_div; + + total = isl_basic_map_dim(bmap, isl_dim_all); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + total -= n_div; + + for (i = 0; i < n_div; ++i) + if (isl_seq_first_non_zero(bmap->div[i] + 2 + total, + n_div) != -1) + return isl_bool_true; + + return isl_bool_false; +} + +/* Return a list of affine expressions, one for each integer division + * in "bmap_i". For each integer division that also appears in "bmap_j", + * the affine expression is set to NaN. The number of NaNs in the list + * is equal to the number of integer divisions in "bmap_j". + * For the other integer divisions of "bmap_i", the corresponding + * element in the list is a purely affine expression equal to the integer + * division in "hull". + * If no such list can be constructed, then the number of elements + * in the returned list is smaller than the number of integer divisions + * in "bmap_i". + */ +static __isl_give isl_aff_list *set_up_substitutions( + __isl_keep isl_basic_map *bmap_i, __isl_keep isl_basic_map *bmap_j, + __isl_take isl_basic_map *hull) +{ + unsigned n_div_i, n_div_j, total; + isl_ctx *ctx; + isl_local_space *ls; + isl_basic_set *wrap_hull; + isl_aff *aff_nan; + isl_aff_list *list; + int i, j; + + if (!hull) + return NULL; + + ctx = isl_basic_map_get_ctx(hull); + + n_div_i = isl_basic_map_dim(bmap_i, isl_dim_div); + n_div_j = isl_basic_map_dim(bmap_j, isl_dim_div); + total = isl_basic_map_total_dim(bmap_i) - n_div_i; + + ls = isl_basic_map_get_local_space(bmap_i); + ls = isl_local_space_wrap(ls); + wrap_hull = isl_basic_map_wrap(hull); + + aff_nan = isl_aff_nan_on_domain(isl_local_space_copy(ls)); + list = isl_aff_list_alloc(ctx, n_div_i); + + j = 0; + for (i = 0; i < n_div_i; ++i) { + isl_aff *aff; + + if (j < n_div_j && + isl_basic_map_equal_div_expr_part(bmap_i, i, bmap_j, j, + 0, 2 + total)) { + ++j; + list = isl_aff_list_add(list, isl_aff_copy(aff_nan)); + continue; + } + if (n_div_i - i <= n_div_j - j) + break; + + aff = isl_local_space_get_div(ls, i); + aff = isl_aff_substitute_equalities(aff, + isl_basic_set_copy(wrap_hull)); + aff = isl_aff_floor(aff); + if (!aff) + goto error; + if (isl_aff_dim(aff, isl_dim_div) != 0) { + isl_aff_free(aff); + break; + } + + list = isl_aff_list_add(list, aff); + } + + isl_aff_free(aff_nan); + isl_local_space_free(ls); + isl_basic_set_free(wrap_hull); + + return list; +error: + isl_aff_free(aff_nan); + isl_local_space_free(ls); + isl_basic_set_free(wrap_hull); + isl_aff_list_free(list); + return NULL; +} + +/* Add variables to info->bmap and info->tab corresponding to the elements + * in "list" that are not set to NaN. + * "extra_var" is the number of these elements. + * "dim" is the offset in the variables of "tab" where we should + * start considering the elements in "list". + * When this function returns, the total number of variables in "tab" + * is equal to "dim" plus the number of elements in "list". + * + * The newly added existentially quantified variables are not given + * an explicit representation because the corresponding div constraints + * do not appear in info->bmap. These constraints are not added + * to info->bmap because for internal consistency, they would need to + * be added to info->tab as well, where they could combine with the equality + * that is added later to result in constraints that do not hold + * in the original input. + */ +static isl_stat add_sub_vars(struct isl_coalesce_info *info, + __isl_keep isl_aff_list *list, int dim, int extra_var) +{ + int i, j, n, d; + isl_space *space; + + space = isl_basic_map_get_space(info->bmap); + info->bmap = isl_basic_map_cow(info->bmap); + info->bmap = isl_basic_map_extend_space(info->bmap, space, + extra_var, 0, 0); + if (!info->bmap) + return isl_stat_error; + n = isl_aff_list_n_aff(list); + for (i = 0; i < n; ++i) { + int is_nan; + isl_aff *aff; + + aff = isl_aff_list_get_aff(list, i); + is_nan = isl_aff_is_nan(aff); + isl_aff_free(aff); + if (is_nan < 0) + return isl_stat_error; + if (is_nan) + continue; + + if (isl_tab_insert_var(info->tab, dim + i) < 0) + return isl_stat_error; + d = isl_basic_map_alloc_div(info->bmap); + if (d < 0) + return isl_stat_error; + info->bmap = isl_basic_map_mark_div_unknown(info->bmap, d); + if (!info->bmap) + return isl_stat_error; + for (j = d; j > i; --j) + isl_basic_map_swap_div(info->bmap, j - 1, j); + } + + return isl_stat_ok; +} + +/* For each element in "list" that is not set to NaN, fix the corresponding + * variable in "tab" to the purely affine expression defined by the element. + * "dim" is the offset in the variables of "tab" where we should + * start considering the elements in "list". + * + * This function assumes that a sufficient number of rows and + * elements in the constraint array are available in the tableau. + */ +static int add_sub_equalities(struct isl_tab *tab, + __isl_keep isl_aff_list *list, int dim) +{ + int i, n; + isl_ctx *ctx; + isl_vec *sub; + isl_aff *aff; + + n = isl_aff_list_n_aff(list); + + ctx = isl_tab_get_ctx(tab); + sub = isl_vec_alloc(ctx, 1 + dim + n); + if (!sub) + return -1; + isl_seq_clr(sub->el + 1 + dim, n); + + for (i = 0; i < n; ++i) { + aff = isl_aff_list_get_aff(list, i); + if (!aff) + goto error; + if (isl_aff_is_nan(aff)) { + isl_aff_free(aff); + continue; + } + isl_seq_cpy(sub->el, aff->v->el + 1, 1 + dim); + isl_int_neg(sub->el[1 + dim + i], aff->v->el[0]); + if (isl_tab_add_eq(tab, sub->el) < 0) + goto error; + isl_int_set_si(sub->el[1 + dim + i], 0); + isl_aff_free(aff); + } + + isl_vec_free(sub); + return 0; +error: + isl_aff_free(aff); + isl_vec_free(sub); + return -1; +} + +/* Add variables to info->tab and info->bmap corresponding to the elements + * in "list" that are not set to NaN. The value of the added variable + * in info->tab is fixed to the purely affine expression defined by the element. + * "dim" is the offset in the variables of info->tab where we should + * start considering the elements in "list". + * When this function returns, the total number of variables in info->tab + * is equal to "dim" plus the number of elements in "list". + */ +static int add_subs(struct isl_coalesce_info *info, + __isl_keep isl_aff_list *list, int dim) +{ + int extra_var; + int n; + + if (!list) + return -1; + + n = isl_aff_list_n_aff(list); + extra_var = n - (info->tab->n_var - dim); + + if (isl_tab_extend_vars(info->tab, extra_var) < 0) + return -1; + if (isl_tab_extend_cons(info->tab, 2 * extra_var) < 0) + return -1; + if (add_sub_vars(info, list, dim, extra_var) < 0) + return -1; + + return add_sub_equalities(info->tab, list, dim); +} + +/* Coalesce basic map "j" into basic map "i" after adding the extra integer + * divisions in "i" but not in "j" to basic map "j", with values + * specified by "list". The total number of elements in "list" + * is equal to the number of integer divisions in "i", while the number + * of NaN elements in the list is equal to the number of integer divisions + * in "j". + * + * If no coalescing can be performed, then we need to revert basic map "j" + * to its original state. We do the same if basic map "i" gets dropped + * during the coalescing, even though this should not happen in practice + * since we have already checked for "j" being a subset of "i" + * before we reach this stage. + */ +static enum isl_change coalesce_with_subs(int i, int j, + struct isl_coalesce_info *info, __isl_keep isl_aff_list *list) +{ + isl_basic_map *bmap_j; + struct isl_tab_undo *snap; + unsigned dim; + enum isl_change change; + + bmap_j = isl_basic_map_copy(info[j].bmap); + snap = isl_tab_snap(info[j].tab); + + dim = isl_basic_map_dim(bmap_j, isl_dim_all); + dim -= isl_basic_map_dim(bmap_j, isl_dim_div); + if (add_subs(&info[j], list, dim) < 0) + goto error; + + change = coalesce_local_pair(i, j, info); + if (change != isl_change_none && change != isl_change_drop_first) { + isl_basic_map_free(bmap_j); + } else { + isl_basic_map_free(info[j].bmap); + info[j].bmap = bmap_j; + + if (isl_tab_rollback(info[j].tab, snap) < 0) + return isl_change_error; + } + + return change; +error: + isl_basic_map_free(bmap_j); + return isl_change_error; +} + +/* Check if we can coalesce basic map "j" into basic map "i" after copying + * those extra integer divisions in "i" that can be simplified away + * using the extra equalities in "j". + * All divs are assumed to be known and not contain any nested divs. + * + * We first check if there are any extra equalities in "j" that we + * can exploit. Then we check if every integer division in "i" + * either already appears in "j" or can be simplified using the + * extra equalities to a purely affine expression. + * If these tests succeed, then we try to coalesce the two basic maps + * by introducing extra dimensions in "j" corresponding to + * the extra integer divsisions "i" fixed to the corresponding + * purely affine expression. + */ +static enum isl_change check_coalesce_into_eq(int i, int j, + struct isl_coalesce_info *info) +{ + unsigned n_div_i, n_div_j; + isl_basic_map *hull_i, *hull_j; + int equal, empty; + isl_aff_list *list; + enum isl_change change; + + n_div_i = isl_basic_map_dim(info[i].bmap, isl_dim_div); + n_div_j = isl_basic_map_dim(info[j].bmap, isl_dim_div); + if (n_div_i <= n_div_j) + return isl_change_none; + if (info[j].bmap->n_eq == 0) + return isl_change_none; + + hull_i = isl_basic_map_copy(info[i].bmap); + hull_i = isl_basic_map_plain_affine_hull(hull_i); + hull_j = isl_basic_map_copy(info[j].bmap); + hull_j = isl_basic_map_plain_affine_hull(hull_j); + + hull_j = isl_basic_map_intersect(hull_j, isl_basic_map_copy(hull_i)); + equal = isl_basic_map_plain_is_equal(hull_i, hull_j); + empty = isl_basic_map_plain_is_empty(hull_j); + isl_basic_map_free(hull_i); + + if (equal < 0 || empty < 0) + goto error; + if (equal || empty) { + isl_basic_map_free(hull_j); + return isl_change_none; + } + + list = set_up_substitutions(info[i].bmap, info[j].bmap, hull_j); + if (!list) + return isl_change_error; + if (isl_aff_list_n_aff(list) < n_div_i) + change = isl_change_none; + else + change = coalesce_with_subs(i, j, info, list); + + isl_aff_list_free(list); + + return change; +error: + isl_basic_map_free(hull_j); + return isl_change_error; +} + +/* Check if we can coalesce basic maps "i" and "j" after copying + * those extra integer divisions in one of the basic maps that can + * be simplified away using the extra equalities in the other basic map. + * We require all divs to be known in both basic maps. + * Furthermore, to simplify the comparison of div expressions, + * we do not allow any nested integer divisions. + */ +static enum isl_change check_coalesce_eq(int i, int j, + struct isl_coalesce_info *info) +{ + isl_bool known, nested; + enum isl_change change; + + known = isl_basic_map_divs_known(info[i].bmap); + if (known < 0 || !known) + return known < 0 ? isl_change_error : isl_change_none; + known = isl_basic_map_divs_known(info[j].bmap); + if (known < 0 || !known) + return known < 0 ? isl_change_error : isl_change_none; + nested = has_nested_div(info[i].bmap); + if (nested < 0 || nested) + return nested < 0 ? isl_change_error : isl_change_none; + nested = has_nested_div(info[j].bmap); + if (nested < 0 || nested) + return nested < 0 ? isl_change_error : isl_change_none; + + change = check_coalesce_into_eq(i, j, info); + if (change != isl_change_none) + return change; + change = check_coalesce_into_eq(j, i, info); + if (change != isl_change_none) + return invert_change(change); + + return isl_change_none; +} + +/* Check if the union of the given pair of basic maps + * can be represented by a single basic map. + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. + * + * We first check if the two basic maps live in the same local space, + * after aligning the divs that differ by only an integer constant. + * If so, we do the complete check. Otherwise, we check if they have + * the same number of integer divisions and can be coalesced, if one is + * an obvious subset of the other or if the extra integer divisions + * of one basic map can be simplified away using the extra equalities + * of the other basic map. + */ +static enum isl_change coalesce_pair(int i, int j, + struct isl_coalesce_info *info) +{ + isl_bool same; + enum isl_change change; + + if (harmonize_divs(&info[i], &info[j]) < 0) + return isl_change_error; + same = same_divs(info[i].bmap, info[j].bmap); + if (same < 0) + return isl_change_error; + if (same) + return coalesce_local_pair(i, j, info); + + if (info[i].bmap->n_div == info[j].bmap->n_div) { + change = coalesce_local_pair(i, j, info); + if (change != isl_change_none) + return change; + } + + change = coalesce_divs(i, j, info); + if (change != isl_change_none) + return change; + + return check_coalesce_eq(i, j, info); +} + +/* Return the maximum of "a" and "b". + */ +static int isl_max(int a, int b) +{ + return a > b ? a : b; +} + +/* Pairwise coalesce the basic maps in the range [start1, end1[ of "info" + * with those in the range [start2, end2[, skipping basic maps + * that have been removed (either before or within this function). + * + * For each basic map i in the first range, we check if it can be coalesced + * with respect to any previously considered basic map j in the second range. + * If i gets dropped (because it was a subset of some j), then + * we can move on to the next basic map. + * If j gets dropped, we need to continue checking against the other + * previously considered basic maps. + * If the two basic maps got fused, then we recheck the fused basic map + * against the previously considered basic maps, starting at i + 1 + * (even if start2 is greater than i + 1). + */ +static int coalesce_range(isl_ctx *ctx, struct isl_coalesce_info *info, + int start1, int end1, int start2, int end2) +{ + int i, j; + + for (i = end1 - 1; i >= start1; --i) { + if (info[i].removed) + continue; + for (j = isl_max(i + 1, start2); j < end2; ++j) { + enum isl_change changed; + + if (info[j].removed) + continue; + if (info[i].removed) + isl_die(ctx, isl_error_internal, + "basic map unexpectedly removed", + return -1); + changed = coalesce_pair(i, j, info); + switch (changed) { + case isl_change_error: + return -1; + case isl_change_none: + case isl_change_drop_second: + continue; + case isl_change_drop_first: + j = end2; + break; + case isl_change_fuse: + j = i; + break; + } + } + } + + return 0; +} + +/* Pairwise coalesce the basic maps described by the "n" elements of "info". + * + * We consider groups of basic maps that live in the same apparent + * affine hull and we first coalesce within such a group before we + * coalesce the elements in the group with elements of previously + * considered groups. If a fuse happens during the second phase, + * then we also reconsider the elements within the group. + */ +static int coalesce(isl_ctx *ctx, int n, struct isl_coalesce_info *info) +{ + int start, end; + + for (end = n; end > 0; end = start) { + start = end - 1; + while (start >= 1 && + info[start - 1].hull_hash == info[start].hull_hash) + start--; + if (coalesce_range(ctx, info, start, end, start, end) < 0) + return -1; + if (coalesce_range(ctx, info, start, end, end, n) < 0) + return -1; + } + + return 0; +} + +/* Update the basic maps in "map" based on the information in "info". + * In particular, remove the basic maps that have been marked removed and + * update the others based on the information in the corresponding tableau. + * Since we detected implicit equalities without calling + * isl_basic_map_gauss, we need to do it now. + * Also call isl_basic_map_simplify if we may have lost the definition + * of one or more integer divisions. + */ +static __isl_give isl_map *update_basic_maps(__isl_take isl_map *map, + int n, struct isl_coalesce_info *info) +{ + int i; + + if (!map) + return NULL; + + for (i = n - 1; i >= 0; --i) { + if (info[i].removed) { + isl_basic_map_free(map->p[i]); + if (i != map->n - 1) + map->p[i] = map->p[map->n - 1]; + map->n--; + continue; + } + + info[i].bmap = isl_basic_map_update_from_tab(info[i].bmap, + info[i].tab); + info[i].bmap = isl_basic_map_gauss(info[i].bmap, NULL); + if (info[i].simplify) + info[i].bmap = isl_basic_map_simplify(info[i].bmap); + info[i].bmap = isl_basic_map_finalize(info[i].bmap); + if (!info[i].bmap) + return isl_map_free(map); + ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_NO_IMPLICIT); + ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT); + isl_basic_map_free(map->p[i]); + map->p[i] = info[i].bmap; + info[i].bmap = NULL; + } + + return map; +} + +/* For each pair of basic maps in the map, check if the union of the two + * can be represented by a single basic map. + * If so, replace the pair by the single basic map and start over. + * + * We factor out any (hidden) common factor from the constraint + * coefficients to improve the detection of adjacent constraints. + * + * Since we are constructing the tableaus of the basic maps anyway, + * we exploit them to detect implicit equalities and redundant constraints. + * This also helps the coalescing as it can ignore the redundant constraints. + * In order to avoid confusion, we make all implicit equalities explicit + * in the basic maps. We don't call isl_basic_map_gauss, though, + * as that may affect the number of constraints. + * This means that we have to call isl_basic_map_gauss at the end + * of the computation (in update_basic_maps) to ensure that + * the basic maps are not left in an unexpected state. + * For each basic map, we also compute the hash of the apparent affine hull + * for use in coalesce. + */ +__isl_give isl_map *isl_map_coalesce(__isl_take isl_map *map) +{ + int i; + unsigned n; + isl_ctx *ctx; + struct isl_coalesce_info *info = NULL; + + map = isl_map_remove_empty_parts(map); + if (!map) + return NULL; + + if (map->n <= 1) + return map; + + ctx = isl_map_get_ctx(map); + map = isl_map_sort_divs(map); + map = isl_map_cow(map); + + if (!map) + return NULL; + + n = map->n; + + info = isl_calloc_array(map->ctx, struct isl_coalesce_info, n); + if (!info) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_reduce_coefficients(map->p[i]); + if (!map->p[i]) + goto error; + info[i].bmap = isl_basic_map_copy(map->p[i]); + info[i].tab = isl_tab_from_basic_map(info[i].bmap, 0); + if (!info[i].tab) + goto error; + if (!ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_NO_IMPLICIT)) + if (isl_tab_detect_implicit_equalities(info[i].tab) < 0) + goto error; + info[i].bmap = isl_tab_make_equalities_explicit(info[i].tab, + info[i].bmap); + if (!info[i].bmap) + goto error; + if (!ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT)) + if (isl_tab_detect_redundant(info[i].tab) < 0) + goto error; + if (coalesce_info_set_hull_hash(&info[i]) < 0) + goto error; + } + for (i = map->n - 1; i >= 0; --i) + if (info[i].tab->empty) + drop(&info[i]); + + if (coalesce(ctx, n, info) < 0) + goto error; + + map = update_basic_maps(map, n, info); + + clear_coalesce_info(n, info); + + return map; +error: + clear_coalesce_info(n, info); + isl_map_free(map); + return NULL; +} + +/* For each pair of basic sets in the set, check if the union of the two + * can be represented by a single basic set. + * If so, replace the pair by the single basic set and start over. + */ +struct isl_set *isl_set_coalesce(struct isl_set *set) +{ + return set_from_map(isl_map_coalesce(set_to_map(set))); +} Index: contrib/isl/isl_config_post.h =================================================================== --- /dev/null +++ contrib/isl/isl_config_post.h @@ -0,0 +1,38 @@ +#ifndef HAVE___ATTRIBUTE__ +#define __attribute__(x) +#endif + +#if HAVE_DECL_FFS +#include +#endif + +#if (HAVE_DECL_FFS==0) && (HAVE_DECL___BUILTIN_FFS==1) +#define ffs __builtin_ffs +#endif + +#if !HAVE_DECL_FFS && !HAVE_DECL___BUILTIN_FFS && HAVE_DECL__BITSCANFORWARD +int isl_ffs(int i); +#define ffs isl_ffs +#endif + +#if HAVE_DECL_STRCASECMP || HAVE_DECL_STRNCASECMP +#include +#endif + +#if !HAVE_DECL_STRCASECMP && HAVE_DECL__STRICMP +#define strcasecmp _stricmp +#endif + +#if !HAVE_DECL_STRNCASECMP && HAVE_DECL__STRNICMP +#define strncasecmp _strnicmp +#endif + +#if !HAVE_DECL_SNPRINTF && HAVE_DECL__SNPRINTF +#define snprintf _snprintf +#endif + +#ifdef GCC_WARN_UNUSED_RESULT +#define WARN_UNUSED GCC_WARN_UNUSED_RESULT +#else +#define WARN_UNUSED +#endif Index: contrib/isl/isl_constraint.c =================================================================== --- /dev/null +++ contrib/isl/isl_constraint.c @@ -0,0 +1,1394 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef BASE +#define BASE constraint + +#include + +isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c) +{ + return c ? isl_local_space_get_ctx(c->ls) : NULL; +} + +static unsigned n(struct isl_constraint *c, enum isl_dim_type type) +{ + return isl_local_space_dim(c->ls, type); +} + +static unsigned offset(struct isl_constraint *c, enum isl_dim_type type) +{ + return isl_local_space_offset(c->ls, type); +} + +static unsigned basic_map_offset(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type) +{ + return type == isl_dim_div ? 1 + isl_space_dim(bmap->dim, isl_dim_all) + : 1 + isl_space_offset(bmap->dim, type); +} + +static unsigned basic_set_offset(struct isl_basic_set *bset, + enum isl_dim_type type) +{ + isl_space *dim = bset->dim; + switch (type) { + 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; + } +} + +__isl_give isl_constraint *isl_constraint_alloc_vec(int eq, + __isl_take isl_local_space *ls, __isl_take isl_vec *v) +{ + isl_constraint *constraint; + + if (!ls || !v) + goto error; + + constraint = isl_alloc_type(isl_vec_get_ctx(v), isl_constraint); + if (!constraint) + goto error; + + constraint->ref = 1; + constraint->eq = eq; + constraint->ls = ls; + constraint->v = v; + + return constraint; +error: + isl_local_space_free(ls); + isl_vec_free(v); + return NULL; +} + +__isl_give isl_constraint *isl_constraint_alloc(int eq, + __isl_take isl_local_space *ls) +{ + isl_ctx *ctx; + isl_vec *v; + + if (!ls) + return NULL; + + ctx = isl_local_space_get_ctx(ls); + v = isl_vec_alloc(ctx, 1 + isl_local_space_dim(ls, isl_dim_all)); + v = isl_vec_clr(v); + return isl_constraint_alloc_vec(eq, ls, v); +} + +struct isl_constraint *isl_basic_map_constraint(struct isl_basic_map *bmap, + isl_int **line) +{ + int eq; + isl_ctx *ctx; + isl_vec *v; + isl_local_space *ls = NULL; + isl_constraint *constraint; + + if (!bmap || !line) + goto error; + + eq = line >= bmap->eq; + + ctx = isl_basic_map_get_ctx(bmap); + ls = isl_basic_map_get_local_space(bmap); + v = isl_vec_alloc(ctx, 1 + isl_local_space_dim(ls, isl_dim_all)); + if (!v) + goto error; + isl_seq_cpy(v->el, line[0], v->size); + constraint = isl_constraint_alloc_vec(eq, ls, v); + + isl_basic_map_free(bmap); + return constraint; +error: + isl_local_space_free(ls); + isl_basic_map_free(bmap); + return NULL; +} + +struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset, + isl_int **line) +{ + return isl_basic_map_constraint(bset_to_bmap(bset), line); +} + +__isl_give isl_constraint *isl_constraint_alloc_equality( + __isl_take isl_local_space *ls) +{ + return isl_constraint_alloc(1, ls); +} + +__isl_give isl_constraint *isl_constraint_alloc_inequality( + __isl_take isl_local_space *ls) +{ + return isl_constraint_alloc(0, ls); +} + +struct isl_constraint *isl_constraint_dup(struct isl_constraint *c) +{ + if (!c) + return NULL; + + return isl_constraint_alloc_vec(c->eq, isl_local_space_copy(c->ls), + isl_vec_copy(c->v)); +} + +struct isl_constraint *isl_constraint_cow(struct isl_constraint *c) +{ + if (!c) + return NULL; + + if (c->ref == 1) + return c; + c->ref--; + return isl_constraint_dup(c); +} + +struct isl_constraint *isl_constraint_copy(struct isl_constraint *constraint) +{ + if (!constraint) + return NULL; + + constraint->ref++; + return constraint; +} + +__isl_null isl_constraint *isl_constraint_free(__isl_take isl_constraint *c) +{ + if (!c) + return NULL; + + if (--c->ref > 0) + return NULL; + + isl_local_space_free(c->ls); + isl_vec_free(c->v); + free(c); + + return NULL; +} + +/* Return the number of constraints in "bmap", i.e., the + * number of times isl_basic_map_foreach_constraint will + * call the callback. + */ +int isl_basic_map_n_constraint(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return -1; + + return bmap->n_eq + bmap->n_ineq; +} + +/* Return the number of constraints in "bset", i.e., the + * number of times isl_basic_set_foreach_constraint will + * call the callback. + */ +int isl_basic_set_n_constraint(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_n_constraint(bset); +} + +isl_stat isl_basic_map_foreach_constraint(__isl_keep isl_basic_map *bmap, + isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user) +{ + int i; + struct isl_constraint *c; + + if (!bmap) + return isl_stat_error; + + isl_assert(bmap->ctx, ISL_F_ISSET(bmap, ISL_BASIC_MAP_FINAL), + return isl_stat_error); + + for (i = 0; i < bmap->n_eq; ++i) { + c = isl_basic_map_constraint(isl_basic_map_copy(bmap), + &bmap->eq[i]); + if (!c) + return isl_stat_error; + if (fn(c, user) < 0) + return isl_stat_error; + } + + for (i = 0; i < bmap->n_ineq; ++i) { + c = isl_basic_map_constraint(isl_basic_map_copy(bmap), + &bmap->ineq[i]); + if (!c) + return isl_stat_error; + if (fn(c, user) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +isl_stat isl_basic_set_foreach_constraint(__isl_keep isl_basic_set *bset, + isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user) +{ + return isl_basic_map_foreach_constraint(bset_to_bmap(bset), fn, user); +} + +/* Add the constraint to the list that "user" points to, if it is not + * a div constraint. + */ +static isl_stat collect_constraint(__isl_take isl_constraint *constraint, + void *user) +{ + isl_constraint_list **list = user; + + if (isl_constraint_is_div_constraint(constraint)) + isl_constraint_free(constraint); + else + *list = isl_constraint_list_add(*list, constraint); + + return isl_stat_ok; +} + +/* Return a list of constraints that, when combined, are equivalent + * to "bmap". The input is required to have only known divs. + * + * There is no need to include the div constraints as they are + * implied by the div expressions. + */ +__isl_give isl_constraint_list *isl_basic_map_get_constraint_list( + __isl_keep isl_basic_map *bmap) +{ + int n; + int known; + isl_ctx *ctx; + isl_constraint_list *list; + + known = isl_basic_map_divs_known(bmap); + if (known < 0) + return NULL; + ctx = isl_basic_map_get_ctx(bmap); + if (!known) + isl_die(ctx, isl_error_invalid, + "input involves unknown divs", return NULL); + + n = isl_basic_map_n_constraint(bmap); + list = isl_constraint_list_alloc(ctx, n); + if (isl_basic_map_foreach_constraint(bmap, + &collect_constraint, &list) < 0) + list = isl_constraint_list_free(list); + + return list; +} + +/* Return a list of constraints that, when combined, are equivalent + * to "bset". The input is required to have only known divs. + */ +__isl_give isl_constraint_list *isl_basic_set_get_constraint_list( + __isl_keep isl_basic_set *bset) +{ + return isl_basic_map_get_constraint_list(bset); +} + +int isl_constraint_is_equal(struct isl_constraint *constraint1, + struct isl_constraint *constraint2) +{ + int equal; + + if (!constraint1 || !constraint2) + return 0; + if (constraint1->eq != constraint2->eq) + return 0; + equal = isl_local_space_is_equal(constraint1->ls, constraint2->ls); + if (equal < 0 || !equal) + return equal; + return isl_vec_is_equal(constraint1->v, constraint2->v); +} + +struct isl_basic_map *isl_basic_map_add_constraint( + struct isl_basic_map *bmap, struct isl_constraint *constraint) +{ + isl_ctx *ctx; + isl_space *dim; + int equal_space; + + if (!bmap || !constraint) + goto error; + + ctx = isl_constraint_get_ctx(constraint); + dim = isl_constraint_get_space(constraint); + equal_space = isl_space_is_equal(bmap->dim, dim); + isl_space_free(dim); + isl_assert(ctx, equal_space, goto error); + + bmap = isl_basic_map_intersect(bmap, + isl_basic_map_from_constraint(constraint)); + return bmap; +error: + isl_basic_map_free(bmap); + isl_constraint_free(constraint); + return NULL; +} + +struct isl_basic_set *isl_basic_set_add_constraint( + struct isl_basic_set *bset, struct isl_constraint *constraint) +{ + return bset_from_bmap(isl_basic_map_add_constraint(bset_to_bmap(bset), + 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); +} + +__isl_give isl_space *isl_constraint_get_space( + __isl_keep isl_constraint *constraint) +{ + return constraint ? isl_local_space_get_space(constraint->ls) : NULL; +} + +__isl_give isl_local_space *isl_constraint_get_local_space( + __isl_keep isl_constraint *constraint) +{ + return constraint ? isl_local_space_copy(constraint->ls) : NULL; +} + +int isl_constraint_dim(struct isl_constraint *constraint, + enum isl_dim_type type) +{ + if (!constraint) + return -1; + return n(constraint, type); +} + +isl_bool isl_constraint_involves_dims(__isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + isl_ctx *ctx; + int *active = NULL; + isl_bool involves = isl_bool_false; + + if (!constraint) + return isl_bool_error; + if (n == 0) + return isl_bool_false; + + ctx = isl_constraint_get_ctx(constraint); + if (first + n > isl_constraint_dim(constraint, type)) + isl_die(ctx, isl_error_invalid, + "range out of bounds", return isl_bool_error); + + active = isl_local_space_get_active(constraint->ls, + constraint->v->el + 1); + if (!active) + goto error; + + first += isl_local_space_offset(constraint->ls, type) - 1; + for (i = 0; i < n; ++i) + if (active[first + i]) { + involves = isl_bool_true; + break; + } + + free(active); + + return involves; +error: + free(active); + return isl_bool_error; +} + +/* Does the given constraint represent a lower bound on the given + * dimension? + */ +isl_bool isl_constraint_is_lower_bound(__isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned pos) +{ + if (!constraint) + return isl_bool_error; + + if (pos >= isl_local_space_dim(constraint->ls, type)) + isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid, + "position out of bounds", return isl_bool_error); + + pos += isl_local_space_offset(constraint->ls, type); + return isl_int_is_pos(constraint->v->el[pos]); +} + +/* Does the given constraint represent an upper bound on the given + * dimension? + */ +isl_bool isl_constraint_is_upper_bound(__isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned pos) +{ + if (!constraint) + return isl_bool_error; + + if (pos >= isl_local_space_dim(constraint->ls, type)) + isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid, + "position out of bounds", return isl_bool_error); + + pos += isl_local_space_offset(constraint->ls, type); + return isl_int_is_neg(constraint->v->el[pos]); +} + +const char *isl_constraint_get_dim_name(__isl_keep isl_constraint *constraint, + enum isl_dim_type type, unsigned pos) +{ + return constraint ? + isl_local_space_get_dim_name(constraint->ls, type, pos) : NULL; +} + +void isl_constraint_get_constant(__isl_keep isl_constraint *constraint, + isl_int *v) +{ + if (!constraint) + return; + isl_int_set(*v, constraint->v->el[0]); +} + +/* Return the constant term of "constraint". + */ +__isl_give isl_val *isl_constraint_get_constant_val( + __isl_keep isl_constraint *constraint) +{ + isl_ctx *ctx; + + if (!constraint) + return NULL; + + ctx = isl_constraint_get_ctx(constraint); + return isl_val_int_from_isl_int(ctx, constraint->v->el[0]); +} + +void isl_constraint_get_coefficient(struct isl_constraint *constraint, + enum isl_dim_type type, int pos, isl_int *v) +{ + if (!constraint) + return; + + if (pos >= isl_local_space_dim(constraint->ls, type)) + isl_die(constraint->v->ctx, isl_error_invalid, + "position out of bounds", return); + + pos += isl_local_space_offset(constraint->ls, type); + isl_int_set(*v, constraint->v->el[pos]); +} + +/* Return the coefficient of the variable of type "type" at position "pos" + * of "constraint". + */ +__isl_give isl_val *isl_constraint_get_coefficient_val( + __isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos) +{ + isl_ctx *ctx; + + if (!constraint) + return NULL; + + ctx = isl_constraint_get_ctx(constraint); + if (pos < 0 || pos >= isl_local_space_dim(constraint->ls, type)) + isl_die(ctx, isl_error_invalid, + "position out of bounds", return NULL); + + pos += isl_local_space_offset(constraint->ls, type); + return isl_val_int_from_isl_int(ctx, constraint->v->el[pos]); +} + +__isl_give isl_aff *isl_constraint_get_div(__isl_keep isl_constraint *constraint, + int pos) +{ + if (!constraint) + return NULL; + + return isl_local_space_get_div(constraint->ls, pos); +} + +__isl_give isl_constraint *isl_constraint_set_constant( + __isl_take isl_constraint *constraint, isl_int v) +{ + constraint = isl_constraint_cow(constraint); + if (!constraint) + return NULL; + + constraint->v = isl_vec_cow(constraint->v); + if (!constraint->v) + return isl_constraint_free(constraint); + + isl_int_set(constraint->v->el[0], v); + return constraint; +} + +/* Replace the constant term of "constraint" by "v". + */ +__isl_give isl_constraint *isl_constraint_set_constant_val( + __isl_take isl_constraint *constraint, __isl_take isl_val *v) +{ + constraint = isl_constraint_cow(constraint); + if (!constraint || !v) + goto error; + if (!isl_val_is_int(v)) + isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid, + "expecting integer value", goto error); + constraint->v = isl_vec_set_element_val(constraint->v, 0, v); + if (!constraint->v) + constraint = isl_constraint_free(constraint); + return constraint; +error: + isl_val_free(v); + return isl_constraint_free(constraint); +} + +__isl_give isl_constraint *isl_constraint_set_constant_si( + __isl_take isl_constraint *constraint, int v) +{ + constraint = isl_constraint_cow(constraint); + if (!constraint) + return NULL; + + constraint->v = isl_vec_cow(constraint->v); + if (!constraint->v) + return isl_constraint_free(constraint); + + isl_int_set_si(constraint->v->el[0], v); + return constraint; +} + +__isl_give isl_constraint *isl_constraint_set_coefficient( + __isl_take isl_constraint *constraint, + enum isl_dim_type type, int pos, isl_int v) +{ + constraint = isl_constraint_cow(constraint); + if (!constraint) + return NULL; + + if (pos >= isl_local_space_dim(constraint->ls, type)) + isl_die(constraint->v->ctx, isl_error_invalid, + "position out of bounds", + return isl_constraint_free(constraint)); + + constraint = isl_constraint_cow(constraint); + if (!constraint) + return NULL; + + constraint->v = isl_vec_cow(constraint->v); + if (!constraint->v) + return isl_constraint_free(constraint); + + pos += isl_local_space_offset(constraint->ls, type); + isl_int_set(constraint->v->el[pos], v); + + return constraint; +} + +/* Replace the coefficient of the variable of type "type" at position "pos" + * of "constraint" by "v". + */ +__isl_give isl_constraint *isl_constraint_set_coefficient_val( + __isl_take isl_constraint *constraint, + enum isl_dim_type type, int pos, __isl_take isl_val *v) +{ + constraint = isl_constraint_cow(constraint); + if (!constraint || !v) + goto error; + if (!isl_val_is_int(v)) + isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid, + "expecting integer value", goto error); + + if (pos >= isl_local_space_dim(constraint->ls, type)) + isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid, + "position out of bounds", goto error); + + pos += isl_local_space_offset(constraint->ls, type); + constraint->v = isl_vec_set_element_val(constraint->v, pos, v); + if (!constraint->v) + constraint = isl_constraint_free(constraint); + return constraint; +error: + isl_val_free(v); + return isl_constraint_free(constraint); +} + +__isl_give isl_constraint *isl_constraint_set_coefficient_si( + __isl_take isl_constraint *constraint, + enum isl_dim_type type, int pos, int v) +{ + constraint = isl_constraint_cow(constraint); + if (!constraint) + return NULL; + + if (pos >= isl_local_space_dim(constraint->ls, type)) + isl_die(constraint->v->ctx, isl_error_invalid, + "position out of bounds", + return isl_constraint_free(constraint)); + + constraint = isl_constraint_cow(constraint); + if (!constraint) + return NULL; + + constraint->v = isl_vec_cow(constraint->v); + if (!constraint->v) + return isl_constraint_free(constraint); + + pos += isl_local_space_offset(constraint->ls, type); + isl_int_set_si(constraint->v->el[pos], v); + + return constraint; +} + +struct isl_constraint *isl_constraint_negate(struct isl_constraint *constraint) +{ + isl_ctx *ctx; + + constraint = isl_constraint_cow(constraint); + if (!constraint) + return NULL; + + ctx = isl_constraint_get_ctx(constraint); + if (isl_constraint_is_equality(constraint)) + isl_die(ctx, isl_error_invalid, "cannot negate equality", + return isl_constraint_free(constraint)); + constraint->v = isl_vec_neg(constraint->v); + constraint->v = isl_vec_cow(constraint->v); + if (!constraint->v) + return isl_constraint_free(constraint); + isl_int_sub_ui(constraint->v->el[0], constraint->v->el[0], 1); + return constraint; +} + +isl_bool isl_constraint_is_equality(struct isl_constraint *constraint) +{ + if (!constraint) + return isl_bool_error; + return constraint->eq; +} + +int isl_constraint_is_div_constraint(__isl_keep isl_constraint *constraint) +{ + int i; + int n_div; + + if (!constraint) + return -1; + if (isl_constraint_is_equality(constraint)) + return 0; + n_div = isl_constraint_dim(constraint, isl_dim_div); + for (i = 0; i < n_div; ++i) { + isl_bool is_div; + is_div = isl_local_space_is_div_constraint(constraint->ls, + constraint->v->el, i); + if (is_div < 0 || is_div) + return is_div; + } + + return 0; +} + +/* We manually set ISL_BASIC_SET_FINAL instead of calling + * isl_basic_map_finalize because we want to keep the position + * of the divs and we therefore do not want to throw away redundant divs. + * This is arguably a bit fragile. + */ +__isl_give isl_basic_map *isl_basic_map_from_constraint( + __isl_take isl_constraint *constraint) +{ + int k; + isl_local_space *ls; + struct isl_basic_map *bmap; + isl_int *c; + unsigned total; + + if (!constraint) + return NULL; + + ls = isl_local_space_copy(constraint->ls); + bmap = isl_basic_map_from_local_space(ls); + bmap = isl_basic_map_extend_constraints(bmap, 1, 1); + if (isl_constraint_is_equality(constraint)) { + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + c = bmap->eq[k]; + } + else { + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + c = bmap->ineq[k]; + } + total = isl_basic_map_total_dim(bmap); + isl_seq_cpy(c, constraint->v->el, 1 + total); + isl_constraint_free(constraint); + if (bmap) + ISL_F_SET(bmap, ISL_BASIC_SET_FINAL); + return bmap; +error: + isl_constraint_free(constraint); + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_from_constraint( + __isl_take isl_constraint *constraint) +{ + if (!constraint) + return NULL; + + if (isl_constraint_dim(constraint, isl_dim_in) != 0) + isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid, + "not a set constraint", goto error); + return bset_from_bmap(isl_basic_map_from_constraint(constraint)); +error: + isl_constraint_free(constraint); + return NULL; +} + +/* Is the variable of "type" at position "pos" of "bmap" defined + * in terms of earlier dimensions through an equality? + * + * If so, and if c is not NULL, then return a copy of this equality in *c. + */ +isl_bool isl_basic_map_has_defining_equality( + __isl_keep isl_basic_map *bmap, enum isl_dim_type type, int pos, + __isl_give isl_constraint **c) +{ + int i; + unsigned offset; + unsigned total; + + if (!bmap) + return isl_bool_error; + offset = basic_map_offset(bmap, type); + total = isl_basic_map_total_dim(bmap); + if (pos >= isl_basic_map_dim(bmap, type)) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "invalid position", return isl_bool_error); + for (i = 0; i < bmap->n_eq; ++i) { + if (isl_int_is_zero(bmap->eq[i][offset + pos]) || + isl_seq_first_non_zero(bmap->eq[i]+offset+pos+1, + 1+total-offset-pos-1) != -1) + continue; + if (c) + *c = isl_basic_map_constraint(isl_basic_map_copy(bmap), + &bmap->eq[i]); + return isl_bool_true; + } + return isl_bool_false; +} + +/* Is the variable of "type" at position "pos" of "bset" defined + * in terms of earlier dimensions through an equality? + * + * If so, and if c is not NULL, then return a copy of this equality in *c. + */ +isl_bool isl_basic_set_has_defining_equality( + __isl_keep isl_basic_set *bset, enum isl_dim_type type, int pos, + __isl_give isl_constraint **c) +{ + return isl_basic_map_has_defining_equality(bset_to_bmap(bset), + type, pos, c); +} + +isl_bool isl_basic_set_has_defining_inequalities( + struct isl_basic_set *bset, enum isl_dim_type type, int pos, + struct isl_constraint **lower, + struct isl_constraint **upper) +{ + int i, j; + unsigned offset; + unsigned total; + isl_int m; + isl_int **lower_line, **upper_line; + + if (!bset) + return isl_bool_error; + offset = basic_set_offset(bset, type); + total = isl_basic_set_total_dim(bset); + if (pos >= isl_basic_set_dim(bset, type)) + isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, + "invalid position", return isl_bool_error); + isl_int_init(m); + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_int_is_zero(bset->ineq[i][offset + pos])) + continue; + if (isl_int_is_one(bset->ineq[i][offset + pos])) + continue; + if (isl_int_is_negone(bset->ineq[i][offset + pos])) + continue; + if (isl_seq_first_non_zero(bset->ineq[i]+offset+pos+1, + 1+total-offset-pos-1) != -1) + continue; + for (j = i + 1; j < bset->n_ineq; ++j) { + if (!isl_seq_is_neg(bset->ineq[i]+1, bset->ineq[j]+1, + total)) + continue; + isl_int_add(m, bset->ineq[i][0], bset->ineq[j][0]); + if (isl_int_abs_ge(m, bset->ineq[i][offset+pos])) + continue; + + if (isl_int_is_pos(bset->ineq[i][offset+pos])) { + lower_line = &bset->ineq[i]; + upper_line = &bset->ineq[j]; + } else { + lower_line = &bset->ineq[j]; + upper_line = &bset->ineq[i]; + } + *lower = isl_basic_set_constraint( + isl_basic_set_copy(bset), lower_line); + *upper = isl_basic_set_constraint( + isl_basic_set_copy(bset), upper_line); + isl_int_clear(m); + return isl_bool_true; + } + } + *lower = NULL; + *upper = NULL; + isl_int_clear(m); + return isl_bool_false; +} + +/* Given two constraints "a" and "b" on the variable at position "abs_pos" + * (in "a" and "b"), add a constraint to "bset" that ensures that the + * bound implied by "a" is (strictly) larger than the bound implied by "b". + * + * If both constraints imply lower bounds, then this means that "a" is + * active in the result. + * If both constraints imply upper bounds, then this means that "b" is + * active in the result. + */ +static __isl_give isl_basic_set *add_larger_bound_constraint( + __isl_take isl_basic_set *bset, isl_int *a, isl_int *b, + unsigned abs_pos, int strict) +{ + int k; + isl_int t; + unsigned total; + + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + + total = isl_basic_set_dim(bset, isl_dim_all); + + isl_int_init(t); + isl_int_neg(t, b[1 + abs_pos]); + + isl_seq_combine(bset->ineq[k], t, a, a[1 + abs_pos], b, 1 + abs_pos); + isl_seq_combine(bset->ineq[k] + 1 + abs_pos, + t, a + 1 + abs_pos + 1, a[1 + abs_pos], b + 1 + abs_pos + 1, + total - abs_pos); + + if (strict) + isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1); + + isl_int_clear(t); + + return bset; +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Add constraints to "context" that ensure that "u" is the smallest + * (and therefore active) upper bound on "abs_pos" in "bset" and return + * the resulting basic set. + */ +static __isl_give isl_basic_set *set_smallest_upper_bound( + __isl_keep isl_basic_set *context, + __isl_keep isl_basic_set *bset, unsigned abs_pos, int n_upper, int u) +{ + int j; + + context = isl_basic_set_copy(context); + context = isl_basic_set_cow(context); + + context = isl_basic_set_extend_constraints(context, 0, n_upper - 1); + + for (j = 0; j < bset->n_ineq; ++j) { + if (j == u) + continue; + if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos])) + continue; + context = add_larger_bound_constraint(context, + bset->ineq[j], bset->ineq[u], abs_pos, j > u); + } + + context = isl_basic_set_simplify(context); + context = isl_basic_set_finalize(context); + + return context; +} + +/* Add constraints to "context" that ensure that "u" is the largest + * (and therefore active) upper bound on "abs_pos" in "bset" and return + * the resulting basic set. + */ +static __isl_give isl_basic_set *set_largest_lower_bound( + __isl_keep isl_basic_set *context, + __isl_keep isl_basic_set *bset, unsigned abs_pos, int n_lower, int l) +{ + int j; + + context = isl_basic_set_copy(context); + context = isl_basic_set_cow(context); + + context = isl_basic_set_extend_constraints(context, 0, n_lower - 1); + + for (j = 0; j < bset->n_ineq; ++j) { + if (j == l) + continue; + if (!isl_int_is_pos(bset->ineq[j][1 + abs_pos])) + continue; + context = add_larger_bound_constraint(context, + bset->ineq[l], bset->ineq[j], abs_pos, j > l); + } + + context = isl_basic_set_simplify(context); + context = isl_basic_set_finalize(context); + + return context; +} + +static isl_stat foreach_upper_bound(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned abs_pos, + __isl_take isl_basic_set *context, int n_upper, + isl_stat (*fn)(__isl_take isl_constraint *lower, + __isl_take isl_constraint *upper, + __isl_take isl_basic_set *bset, void *user), void *user) +{ + isl_basic_set *context_i; + isl_constraint *upper = NULL; + int i; + + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_int_is_zero(bset->ineq[i][1 + abs_pos])) + continue; + + context_i = set_smallest_upper_bound(context, bset, + abs_pos, n_upper, i); + if (isl_basic_set_is_empty(context_i)) { + isl_basic_set_free(context_i); + continue; + } + upper = isl_basic_set_constraint(isl_basic_set_copy(bset), + &bset->ineq[i]); + if (!upper || !context_i) + goto error; + if (fn(NULL, upper, context_i, user) < 0) + break; + } + + isl_basic_set_free(context); + + if (i < bset->n_ineq) + return isl_stat_error; + + return isl_stat_ok; +error: + isl_constraint_free(upper); + isl_basic_set_free(context_i); + isl_basic_set_free(context); + return isl_stat_error; +} + +static isl_stat foreach_lower_bound(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned abs_pos, + __isl_take isl_basic_set *context, int n_lower, + isl_stat (*fn)(__isl_take isl_constraint *lower, + __isl_take isl_constraint *upper, + __isl_take isl_basic_set *bset, void *user), void *user) +{ + isl_basic_set *context_i; + isl_constraint *lower = NULL; + int i; + + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_int_is_zero(bset->ineq[i][1 + abs_pos])) + continue; + + context_i = set_largest_lower_bound(context, bset, + abs_pos, n_lower, i); + if (isl_basic_set_is_empty(context_i)) { + isl_basic_set_free(context_i); + continue; + } + lower = isl_basic_set_constraint(isl_basic_set_copy(bset), + &bset->ineq[i]); + if (!lower || !context_i) + goto error; + if (fn(lower, NULL, context_i, user) < 0) + break; + } + + isl_basic_set_free(context); + + if (i < bset->n_ineq) + return isl_stat_error; + + return isl_stat_ok; +error: + isl_constraint_free(lower); + isl_basic_set_free(context_i); + isl_basic_set_free(context); + return isl_stat_error; +} + +static isl_stat foreach_bound_pair(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned abs_pos, + __isl_take isl_basic_set *context, int n_lower, int n_upper, + isl_stat (*fn)(__isl_take isl_constraint *lower, + __isl_take isl_constraint *upper, + __isl_take isl_basic_set *bset, void *user), void *user) +{ + isl_basic_set *context_i, *context_j; + isl_constraint *lower = NULL; + isl_constraint *upper = NULL; + int i, j; + + for (i = 0; i < bset->n_ineq; ++i) { + if (!isl_int_is_pos(bset->ineq[i][1 + abs_pos])) + continue; + + context_i = set_largest_lower_bound(context, bset, + abs_pos, n_lower, i); + if (isl_basic_set_is_empty(context_i)) { + isl_basic_set_free(context_i); + continue; + } + + for (j = 0; j < bset->n_ineq; ++j) { + if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos])) + continue; + + context_j = set_smallest_upper_bound(context_i, bset, + abs_pos, n_upper, j); + context_j = isl_basic_set_extend_constraints(context_j, + 0, 1); + context_j = add_larger_bound_constraint(context_j, + bset->ineq[i], bset->ineq[j], abs_pos, 0); + context_j = isl_basic_set_simplify(context_j); + context_j = isl_basic_set_finalize(context_j); + if (isl_basic_set_is_empty(context_j)) { + isl_basic_set_free(context_j); + continue; + } + lower = isl_basic_set_constraint(isl_basic_set_copy(bset), + &bset->ineq[i]); + upper = isl_basic_set_constraint(isl_basic_set_copy(bset), + &bset->ineq[j]); + if (!lower || !upper || !context_j) + goto error; + if (fn(lower, upper, context_j, user) < 0) + break; + } + + isl_basic_set_free(context_i); + + if (j < bset->n_ineq) + break; + } + + isl_basic_set_free(context); + + if (i < bset->n_ineq) + return isl_stat_error; + + return isl_stat_ok; +error: + isl_constraint_free(lower); + isl_constraint_free(upper); + isl_basic_set_free(context_i); + isl_basic_set_free(context_j); + isl_basic_set_free(context); + return isl_stat_error; +} + +/* For each pair of lower and upper bounds on the variable "pos" + * of type "type", call "fn" with these lower and upper bounds and the + * set of constraints on the remaining variables where these bounds + * are active, i.e., (stricly) larger/smaller than the other lower/upper bounds. + * + * If the designated variable is equal to an affine combination of the + * other variables then fn is called with both lower and upper + * set to the corresponding equality. + * + * If there is no lower (or upper) bound, then NULL is passed + * as the corresponding bound. + * + * We first check if the variable is involved in any equality. + * If not, we count the number of lower and upper bounds and + * act accordingly. + */ +isl_stat isl_basic_set_foreach_bound_pair(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, + isl_stat (*fn)(__isl_take isl_constraint *lower, + __isl_take isl_constraint *upper, + __isl_take isl_basic_set *bset, void *user), void *user) +{ + int i; + isl_constraint *lower = NULL; + isl_constraint *upper = NULL; + isl_basic_set *context = NULL; + unsigned abs_pos; + int n_lower, n_upper; + + if (!bset) + return isl_stat_error; + isl_assert(bset->ctx, pos < isl_basic_set_dim(bset, type), + return isl_stat_error); + isl_assert(bset->ctx, type == isl_dim_param || type == isl_dim_set, + return isl_stat_error); + + abs_pos = pos; + if (type == isl_dim_set) + abs_pos += isl_basic_set_dim(bset, isl_dim_param); + + for (i = 0; i < bset->n_eq; ++i) { + if (isl_int_is_zero(bset->eq[i][1 + abs_pos])) + continue; + + lower = isl_basic_set_constraint(isl_basic_set_copy(bset), + &bset->eq[i]); + upper = isl_constraint_copy(lower); + context = isl_basic_set_remove_dims(isl_basic_set_copy(bset), + type, pos, 1); + if (!lower || !upper || !context) + goto error; + return fn(lower, upper, context, user); + } + + n_lower = 0; + n_upper = 0; + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_int_is_pos(bset->ineq[i][1 + abs_pos])) + n_lower++; + else if (isl_int_is_neg(bset->ineq[i][1 + abs_pos])) + n_upper++; + } + + context = isl_basic_set_copy(bset); + context = isl_basic_set_cow(context); + if (!context) + goto error; + for (i = context->n_ineq - 1; i >= 0; --i) + if (!isl_int_is_zero(context->ineq[i][1 + abs_pos])) + isl_basic_set_drop_inequality(context, i); + + context = isl_basic_set_drop(context, type, pos, 1); + if (!n_lower && !n_upper) + return fn(NULL, NULL, context, user); + if (!n_lower) + return foreach_upper_bound(bset, type, abs_pos, context, n_upper, + fn, user); + if (!n_upper) + return foreach_lower_bound(bset, type, abs_pos, context, n_lower, + fn, user); + return foreach_bound_pair(bset, type, abs_pos, context, n_lower, n_upper, + fn, user); +error: + isl_constraint_free(lower); + isl_constraint_free(upper); + 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_ctx *ctx; + + if (!constraint) + return NULL; + ctx = isl_constraint_get_ctx(constraint); + if (pos >= isl_constraint_dim(constraint, type)) + isl_die(ctx, isl_error_invalid, + "index out of bounds", return NULL); + if (isl_constraint_dim(constraint, isl_dim_in) != 0) + isl_die(ctx, isl_error_invalid, + "not a set constraint", return NULL); + + pos += offset(constraint, type); + if (isl_int_is_zero(constraint->v->el[pos])) + isl_die(ctx, isl_error_invalid, + "constraint does not define a bound on given dimension", + return NULL); + + aff = isl_aff_alloc(isl_local_space_copy(constraint->ls)); + if (!aff) + return NULL; + + if (isl_int_is_neg(constraint->v->el[pos])) + isl_seq_cpy(aff->v->el + 1, constraint->v->el, aff->v->size - 1); + else + isl_seq_neg(aff->v->el + 1, constraint->v->el, aff->v->size - 1); + isl_int_set_si(aff->v->el[1 + pos], 0); + isl_int_abs(aff->v->el[0], constraint->v->el[pos]); + + return aff; +} + +/* For an inequality constraint + * + * f >= 0 + * + * or an equality constraint + * + * f = 0 + * + * return the affine expression f. + */ +__isl_give isl_aff *isl_constraint_get_aff( + __isl_keep isl_constraint *constraint) +{ + isl_aff *aff; + + if (!constraint) + return NULL; + + aff = isl_aff_alloc(isl_local_space_copy(constraint->ls)); + if (!aff) + return NULL; + + isl_seq_cpy(aff->v->el + 1, constraint->v->el, aff->v->size - 1); + isl_int_set_si(aff->v->el[0], 1); + + return aff; +} + +/* Construct an inequality (eq = 0) or equality (eq = 1) constraint from "aff". + * In particular, construct aff >= 0 or aff = 0. + * + * The denominator of "aff" can be ignored. + */ +static __isl_give isl_constraint *isl_constraint_alloc_aff(int eq, + __isl_take isl_aff *aff) +{ + isl_local_space *ls; + isl_vec *v; + + if (!aff) + return NULL; + ls = isl_aff_get_domain_local_space(aff); + v = isl_vec_drop_els(isl_vec_copy(aff->v), 0, 1); + isl_aff_free(aff); + + return isl_constraint_alloc_vec(eq, ls, v); +} + +/* Construct an equality constraint equating the given affine expression + * to zero. + */ +__isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff) +{ + return isl_constraint_alloc_aff(1, aff); +} + +/* Construct an inequality constraint enforcing the given affine expression + * to be non-negative. + */ +__isl_give isl_constraint *isl_inequality_from_aff(__isl_take isl_aff *aff) +{ + return isl_constraint_alloc_aff(0, aff); +} + +/* Compare two isl_constraints. + * + * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater" + * than "c2" and 0 if they are equal. + * + * The order is fairly arbitrary. We do consider constraints that only involve + * earlier dimensions as "smaller". + */ +int isl_constraint_plain_cmp(__isl_keep isl_constraint *c1, + __isl_keep isl_constraint *c2) +{ + int cmp; + int last1, last2; + + if (c1 == c2) + return 0; + if (!c1) + return -1; + if (!c2) + return 1; + cmp = isl_local_space_cmp(c1->ls, c2->ls); + if (cmp != 0) + return cmp; + + last1 = isl_seq_last_non_zero(c1->v->el + 1, c1->v->size - 1); + last2 = isl_seq_last_non_zero(c2->v->el + 1, c1->v->size - 1); + if (last1 != last2) + return last1 - last2; + + return isl_seq_cmp(c1->v->el, c2->v->el, c1->v->size); +} + +/* Compare two constraints based on their final (non-zero) coefficients. + * In particular, the constraint that involves later variables or + * that has a larger coefficient for a shared latest variable + * is considered "greater" than the other constraint. + * + * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater" + * than "c2" and 0 if they are equal. + * + * If the constraints live in different local spaces, then we cannot + * really compare the constraints so we compare the local spaces instead. + */ +int isl_constraint_cmp_last_non_zero(__isl_keep isl_constraint *c1, + __isl_keep isl_constraint *c2) +{ + int cmp; + int last1, last2; + + if (c1 == c2) + return 0; + if (!c1) + return -1; + if (!c2) + return 1; + cmp = isl_local_space_cmp(c1->ls, c2->ls); + if (cmp != 0) + return cmp; + + last1 = isl_seq_last_non_zero(c1->v->el + 1, c1->v->size - 1); + last2 = isl_seq_last_non_zero(c2->v->el + 1, c1->v->size - 1); + if (last1 != last2) + return last1 - last2; + if (last1 == -1) + return 0; + return isl_int_abs_cmp(c1->v->el[1 + last1], c2->v->el[1 + last2]); +} Index: contrib/isl/isl_constraint_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_constraint_private.h @@ -0,0 +1,29 @@ +#ifndef ISL_CONSTRAINT_PRIVATE_H +#define ISL_CONSTRAINT_PRIVATE_H + +#include +#include +#include + +struct isl_constraint { + int ref; + + int eq; + isl_local_space *ls; + isl_vec *v; +}; + +#undef EL +#define EL isl_constraint + +#include + +struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset, + isl_int **line); + +void isl_constraint_get_constant(__isl_keep isl_constraint *constraint, + isl_int *v); +void isl_constraint_get_coefficient(__isl_keep isl_constraint *constraint, + enum isl_dim_type type, int pos, isl_int *v); + +#endif Index: contrib/isl/isl_convex_hull.c =================================================================== --- /dev/null +++ contrib/isl/isl_convex_hull.c @@ -0,0 +1,3063 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "isl_equalities.h" +#include "isl_tab.h" +#include + +#include +#include +#include + +static __isl_give isl_basic_set *uset_convex_hull_wrap_bounded( + __isl_take isl_set *set); + +/* Remove redundant + * constraints. If the minimal value along the normal of a constraint + * is the same if the constraint is removed, then the constraint is redundant. + * + * Since some constraints may be mutually redundant, sort the constraints + * first such that constraints that involve existentially quantified + * variables are considered for removal before those that do not. + * The sorting is also needed for the use in map_simple_hull. + * + * Note that isl_tab_detect_implicit_equalities may also end up + * marking some constraints as redundant. Make sure the constraints + * are preserved and undo those marking such that isl_tab_detect_redundant + * can consider the constraints in the sorted order. + * + * Alternatively, we could have intersected the basic map with the + * corresponding equality and then checked if the dimension was that + * of a facet. + */ +__isl_give isl_basic_map *isl_basic_map_remove_redundancies( + __isl_take isl_basic_map *bmap) +{ + struct isl_tab *tab; + + if (!bmap) + return NULL; + + bmap = isl_basic_map_gauss(bmap, NULL); + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) + return bmap; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NO_REDUNDANT)) + return bmap; + if (bmap->n_ineq <= 1) + return bmap; + + bmap = isl_basic_map_sort_constraints(bmap); + tab = isl_tab_from_basic_map(bmap, 0); + if (!tab) + goto error; + tab->preserve = 1; + if (isl_tab_detect_implicit_equalities(tab) < 0) + goto error; + if (isl_tab_restore_redundant(tab) < 0) + goto error; + tab->preserve = 0; + if (isl_tab_detect_redundant(tab) < 0) + goto error; + bmap = isl_basic_map_update_from_tab(bmap, tab); + isl_tab_free(tab); + if (!bmap) + return NULL; + ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT); + ISL_F_SET(bmap, ISL_BASIC_MAP_NO_REDUNDANT); + return bmap; +error: + isl_tab_free(tab); + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_remove_redundancies( + __isl_take isl_basic_set *bset) +{ + return bset_from_bmap( + isl_basic_map_remove_redundancies(bset_to_bmap(bset))); +} + +/* Remove redundant constraints in each of the basic maps. + */ +__isl_give isl_map *isl_map_remove_redundancies(__isl_take isl_map *map) +{ + return isl_map_inline_foreach_basic_map(map, + &isl_basic_map_remove_redundancies); +} + +__isl_give isl_set *isl_set_remove_redundancies(__isl_take isl_set *set) +{ + return isl_map_remove_redundancies(set); +} + +/* Check if the set set is bound in the direction of the affine + * constraint c and if so, set the constant term such that the + * resulting constraint is a bounding constraint for the set. + */ +static int uset_is_bound(__isl_keep isl_set *set, isl_int *c, unsigned len) +{ + int first; + int j; + isl_int opt; + isl_int opt_denom; + + isl_int_init(opt); + isl_int_init(opt_denom); + first = 1; + for (j = 0; j < set->n; ++j) { + enum isl_lp_result res; + + if (ISL_F_ISSET(set->p[j], ISL_BASIC_SET_EMPTY)) + continue; + + res = isl_basic_set_solve_lp(set->p[j], + 0, c, set->ctx->one, &opt, &opt_denom, NULL); + if (res == isl_lp_unbounded) + break; + if (res == isl_lp_error) + goto error; + if (res == isl_lp_empty) { + set->p[j] = isl_basic_set_set_to_empty(set->p[j]); + if (!set->p[j]) + goto error; + continue; + } + if (first || isl_int_is_neg(opt)) { + if (!isl_int_is_one(opt_denom)) + isl_seq_scale(c, c, opt_denom, len); + isl_int_sub(c[0], c[0], opt); + } + first = 0; + } + isl_int_clear(opt); + isl_int_clear(opt_denom); + return j >= set->n; +error: + isl_int_clear(opt); + isl_int_clear(opt_denom); + return -1; +} + +static struct isl_basic_set *isl_basic_set_add_equality( + struct isl_basic_set *bset, isl_int *c) +{ + int i; + unsigned dim; + + if (!bset) + return NULL; + + if (ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY)) + return bset; + + isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error); + isl_assert(bset->ctx, bset->n_div == 0, goto error); + dim = isl_basic_set_n_dim(bset); + bset = isl_basic_set_cow(bset); + bset = isl_basic_set_extend(bset, 0, dim, 0, 1, 0); + i = isl_basic_set_alloc_equality(bset); + if (i < 0) + goto error; + isl_seq_cpy(bset->eq[i], c, 1 + dim); + return bset; +error: + isl_basic_set_free(bset); + return NULL; +} + +static __isl_give isl_set *isl_set_add_basic_set_equality( + __isl_take isl_set *set, isl_int *c) +{ + int i; + + set = isl_set_cow(set); + if (!set) + return NULL; + for (i = 0; i < set->n; ++i) { + set->p[i] = isl_basic_set_add_equality(set->p[i], c); + if (!set->p[i]) + goto error; + } + return set; +error: + isl_set_free(set); + return NULL; +} + +/* Given a union of basic sets, construct the constraints for wrapping + * a facet around one of its ridges. + * In particular, if each of n the d-dimensional basic sets i in "set" + * contains the origin, satisfies the constraints x_1 >= 0 and x_2 >= 0 + * and is defined by the constraints + * [ 1 ] + * A_i [ x ] >= 0 + * + * then the resulting set is of dimension n*(1+d) and has as constraints + * + * [ a_i ] + * A_i [ x_i ] >= 0 + * + * a_i >= 0 + * + * \sum_i x_{i,1} = 1 + */ +static __isl_give isl_basic_set *wrap_constraints(__isl_keep isl_set *set) +{ + struct isl_basic_set *lp; + unsigned n_eq; + unsigned n_ineq; + int i, j, k; + unsigned dim, lp_dim; + + if (!set) + return NULL; + + dim = 1 + isl_set_n_dim(set); + n_eq = 1; + n_ineq = set->n; + for (i = 0; i < set->n; ++i) { + n_eq += set->p[i]->n_eq; + n_ineq += set->p[i]->n_ineq; + } + lp = isl_basic_set_alloc(set->ctx, 0, dim * set->n, 0, n_eq, n_ineq); + lp = isl_basic_set_set_rational(lp); + if (!lp) + return NULL; + lp_dim = isl_basic_set_n_dim(lp); + k = isl_basic_set_alloc_equality(lp); + isl_int_set_si(lp->eq[k][0], -1); + for (i = 0; i < set->n; ++i) { + isl_int_set_si(lp->eq[k][1+dim*i], 0); + isl_int_set_si(lp->eq[k][1+dim*i+1], 1); + isl_seq_clr(lp->eq[k]+1+dim*i+2, dim-2); + } + for (i = 0; i < set->n; ++i) { + k = isl_basic_set_alloc_inequality(lp); + isl_seq_clr(lp->ineq[k], 1+lp_dim); + isl_int_set_si(lp->ineq[k][1+dim*i], 1); + + for (j = 0; j < set->p[i]->n_eq; ++j) { + k = isl_basic_set_alloc_equality(lp); + isl_seq_clr(lp->eq[k], 1+dim*i); + isl_seq_cpy(lp->eq[k]+1+dim*i, set->p[i]->eq[j], dim); + isl_seq_clr(lp->eq[k]+1+dim*(i+1), dim*(set->n-i-1)); + } + + for (j = 0; j < set->p[i]->n_ineq; ++j) { + k = isl_basic_set_alloc_inequality(lp); + isl_seq_clr(lp->ineq[k], 1+dim*i); + isl_seq_cpy(lp->ineq[k]+1+dim*i, set->p[i]->ineq[j], dim); + isl_seq_clr(lp->ineq[k]+1+dim*(i+1), dim*(set->n-i-1)); + } + } + return lp; +} + +/* Given a facet "facet" of the convex hull of "set" and a facet "ridge" + * of that facet, compute the other facet of the convex hull that contains + * the ridge. + * + * We first transform the set such that the facet constraint becomes + * + * x_1 >= 0 + * + * I.e., the facet lies in + * + * x_1 = 0 + * + * and on that facet, the constraint that defines the ridge is + * + * x_2 >= 0 + * + * (This transformation is not strictly needed, all that is needed is + * that the ridge contains the origin.) + * + * Since the ridge contains the origin, the cone of the convex hull + * will be of the form + * + * x_1 >= 0 + * x_2 >= a x_1 + * + * with this second constraint defining the new facet. + * The constant a is obtained by settting x_1 in the cone of the + * convex hull to 1 and minimizing x_2. + * Now, each element in the cone of the convex hull is the sum + * of elements in the cones of the basic sets. + * If a_i is the dilation factor of basic set i, then the problem + * we need to solve is + * + * min \sum_i x_{i,2} + * st + * \sum_i x_{i,1} = 1 + * a_i >= 0 + * [ a_i ] + * A [ x_i ] >= 0 + * + * with + * [ 1 ] + * A_i [ x_i ] >= 0 + * + * the constraints of each (transformed) basic set. + * If a = n/d, then the constraint defining the new facet (in the transformed + * space) is + * + * -n x_1 + d x_2 >= 0 + * + * In the original space, we need to take the same combination of the + * corresponding constraints "facet" and "ridge". + * + * If a = -infty = "-1/0", then we just return the original facet constraint. + * This means that the facet is unbounded, but has a bounded intersection + * with the union of sets. + */ +isl_int *isl_set_wrap_facet(__isl_keep isl_set *set, + isl_int *facet, isl_int *ridge) +{ + int i; + isl_ctx *ctx; + struct isl_mat *T = NULL; + struct isl_basic_set *lp = NULL; + struct isl_vec *obj; + enum isl_lp_result res; + isl_int num, den; + unsigned dim; + + if (!set) + return NULL; + ctx = set->ctx; + set = isl_set_copy(set); + set = isl_set_set_rational(set); + + dim = 1 + isl_set_n_dim(set); + T = isl_mat_alloc(ctx, 3, dim); + if (!T) + goto error; + isl_int_set_si(T->row[0][0], 1); + isl_seq_clr(T->row[0]+1, dim - 1); + isl_seq_cpy(T->row[1], facet, dim); + isl_seq_cpy(T->row[2], ridge, dim); + T = isl_mat_right_inverse(T); + set = isl_set_preimage(set, T); + T = NULL; + if (!set) + goto error; + lp = wrap_constraints(set); + obj = isl_vec_alloc(ctx, 1 + dim*set->n); + if (!obj) + goto error; + isl_int_set_si(obj->block.data[0], 0); + for (i = 0; i < set->n; ++i) { + isl_seq_clr(obj->block.data + 1 + dim*i, 2); + isl_int_set_si(obj->block.data[1 + dim*i+2], 1); + isl_seq_clr(obj->block.data + 1 + dim*i+3, dim-3); + } + isl_int_init(num); + isl_int_init(den); + res = isl_basic_set_solve_lp(lp, 0, + obj->block.data, ctx->one, &num, &den, NULL); + if (res == isl_lp_ok) { + isl_int_neg(num, num); + isl_seq_combine(facet, num, facet, den, ridge, dim); + isl_seq_normalize(ctx, facet, dim); + } + isl_int_clear(num); + isl_int_clear(den); + isl_vec_free(obj); + isl_basic_set_free(lp); + isl_set_free(set); + if (res == isl_lp_error) + return NULL; + isl_assert(ctx, res == isl_lp_ok || res == isl_lp_unbounded, + return NULL); + return facet; +error: + isl_basic_set_free(lp); + isl_mat_free(T); + isl_set_free(set); + return NULL; +} + +/* Compute the constraint of a facet of "set". + * + * We first compute the intersection with a bounding constraint + * that is orthogonal to one of the coordinate axes. + * If the affine hull of this intersection has only one equality, + * we have found a facet. + * Otherwise, we wrap the current bounding constraint around + * one of the equalities of the face (one that is not equal to + * the current bounding constraint). + * This process continues until we have found a facet. + * The dimension of the intersection increases by at least + * one on each iteration, so termination is guaranteed. + */ +static __isl_give isl_mat *initial_facet_constraint(__isl_keep isl_set *set) +{ + struct isl_set *slice = NULL; + struct isl_basic_set *face = NULL; + int i; + unsigned dim = isl_set_n_dim(set); + int is_bound; + isl_mat *bounds = NULL; + + isl_assert(set->ctx, set->n > 0, goto error); + bounds = isl_mat_alloc(set->ctx, 1, 1 + dim); + if (!bounds) + return NULL; + + isl_seq_clr(bounds->row[0], dim); + isl_int_set_si(bounds->row[0][1 + dim - 1], 1); + is_bound = uset_is_bound(set, bounds->row[0], 1 + dim); + if (is_bound < 0) + goto error; + isl_assert(set->ctx, is_bound, goto error); + isl_seq_normalize(set->ctx, bounds->row[0], 1 + dim); + bounds->n_row = 1; + + for (;;) { + slice = isl_set_copy(set); + slice = isl_set_add_basic_set_equality(slice, bounds->row[0]); + face = isl_set_affine_hull(slice); + if (!face) + goto error; + if (face->n_eq == 1) { + isl_basic_set_free(face); + break; + } + for (i = 0; i < face->n_eq; ++i) + if (!isl_seq_eq(bounds->row[0], face->eq[i], 1 + dim) && + !isl_seq_is_neg(bounds->row[0], + face->eq[i], 1 + dim)) + break; + isl_assert(set->ctx, i < face->n_eq, goto error); + if (!isl_set_wrap_facet(set, bounds->row[0], face->eq[i])) + goto error; + isl_seq_normalize(set->ctx, bounds->row[0], bounds->n_col); + isl_basic_set_free(face); + } + + return bounds; +error: + isl_basic_set_free(face); + isl_mat_free(bounds); + return NULL; +} + +/* Given the bounding constraint "c" of a facet of the convex hull of "set", + * compute a hyperplane description of the facet, i.e., compute the facets + * of the facet. + * + * We compute an affine transformation that transforms the constraint + * + * [ 1 ] + * c [ x ] = 0 + * + * to the constraint + * + * z_1 = 0 + * + * by computing the right inverse U of a matrix that starts with the rows + * + * [ 1 0 ] + * [ c ] + * + * Then + * [ 1 ] [ 1 ] + * [ x ] = U [ z ] + * and + * [ 1 ] [ 1 ] + * [ z ] = Q [ x ] + * + * with Q = U^{-1} + * Since z_1 is zero, we can drop this variable as well as the corresponding + * column of U to obtain + * + * [ 1 ] [ 1 ] + * [ x ] = U' [ z' ] + * and + * [ 1 ] [ 1 ] + * [ z' ] = Q' [ x ] + * + * with Q' equal to Q, but without the corresponding row. + * After computing the facets of the facet in the z' space, + * we convert them back to the x space through Q. + */ +static __isl_give isl_basic_set *compute_facet(__isl_keep isl_set *set, + isl_int *c) +{ + struct isl_mat *m, *U, *Q; + struct isl_basic_set *facet = NULL; + struct isl_ctx *ctx; + unsigned dim; + + ctx = set->ctx; + set = isl_set_copy(set); + dim = isl_set_n_dim(set); + m = isl_mat_alloc(set->ctx, 2, 1 + dim); + if (!m) + goto error; + isl_int_set_si(m->row[0][0], 1); + isl_seq_clr(m->row[0]+1, dim); + isl_seq_cpy(m->row[1], c, 1+dim); + U = isl_mat_right_inverse(m); + Q = isl_mat_right_inverse(isl_mat_copy(U)); + U = isl_mat_drop_cols(U, 1, 1); + Q = isl_mat_drop_rows(Q, 1, 1); + set = isl_set_preimage(set, U); + facet = uset_convex_hull_wrap_bounded(set); + facet = isl_basic_set_preimage(facet, Q); + if (facet && facet->n_eq != 0) + isl_die(ctx, isl_error_internal, "unexpected equality", + return isl_basic_set_free(facet)); + return facet; +error: + isl_basic_set_free(facet); + isl_set_free(set); + return NULL; +} + +/* Given an initial facet constraint, compute the remaining facets. + * We do this by running through all facets found so far and computing + * the adjacent facets through wrapping, adding those facets that we + * hadn't already found before. + * + * For each facet we have found so far, we first compute its facets + * in the resulting convex hull. That is, we compute the ridges + * of the resulting convex hull contained in the facet. + * We also compute the corresponding facet in the current approximation + * of the convex hull. There is no need to wrap around the ridges + * in this facet since that would result in a facet that is already + * present in the current approximation. + * + * This function can still be significantly optimized by checking which of + * the facets of the basic sets are also facets of the convex hull and + * using all the facets so far to help in constructing the facets of the + * facets + * and/or + * using the technique in section "3.1 Ridge Generation" of + * "Extended Convex Hull" by Fukuda et al. + */ +static __isl_give isl_basic_set *extend(__isl_take isl_basic_set *hull, + __isl_keep isl_set *set) +{ + int i, j, f; + int k; + struct isl_basic_set *facet = NULL; + struct isl_basic_set *hull_facet = NULL; + unsigned dim; + + if (!hull) + return NULL; + + isl_assert(set->ctx, set->n > 0, goto error); + + dim = isl_set_n_dim(set); + + for (i = 0; i < hull->n_ineq; ++i) { + facet = compute_facet(set, hull->ineq[i]); + facet = isl_basic_set_add_equality(facet, hull->ineq[i]); + facet = isl_basic_set_gauss(facet, NULL); + facet = isl_basic_set_normalize_constraints(facet); + hull_facet = isl_basic_set_copy(hull); + hull_facet = isl_basic_set_add_equality(hull_facet, hull->ineq[i]); + hull_facet = isl_basic_set_gauss(hull_facet, NULL); + hull_facet = isl_basic_set_normalize_constraints(hull_facet); + if (!facet || !hull_facet) + goto error; + hull = isl_basic_set_cow(hull); + hull = isl_basic_set_extend_space(hull, + isl_space_copy(hull->dim), 0, 0, facet->n_ineq); + if (!hull) + goto error; + for (j = 0; j < facet->n_ineq; ++j) { + for (f = 0; f < hull_facet->n_ineq; ++f) + if (isl_seq_eq(facet->ineq[j], + hull_facet->ineq[f], 1 + dim)) + break; + if (f < hull_facet->n_ineq) + continue; + k = isl_basic_set_alloc_inequality(hull); + if (k < 0) + goto error; + isl_seq_cpy(hull->ineq[k], hull->ineq[i], 1+dim); + if (!isl_set_wrap_facet(set, hull->ineq[k], facet->ineq[j])) + goto error; + } + isl_basic_set_free(hull_facet); + isl_basic_set_free(facet); + } + hull = isl_basic_set_simplify(hull); + hull = isl_basic_set_finalize(hull); + return hull; +error: + isl_basic_set_free(hull_facet); + isl_basic_set_free(facet); + isl_basic_set_free(hull); + return NULL; +} + +/* Special case for computing the convex hull of a one dimensional set. + * We simply collect the lower and upper bounds of each basic set + * and the biggest of those. + */ +static __isl_give isl_basic_set *convex_hull_1d(__isl_take isl_set *set) +{ + struct isl_mat *c = NULL; + isl_int *lower = NULL; + isl_int *upper = NULL; + int i, j, k; + isl_int a, b; + struct isl_basic_set *hull; + + for (i = 0; i < set->n; ++i) { + set->p[i] = isl_basic_set_simplify(set->p[i]); + if (!set->p[i]) + goto error; + } + set = isl_set_remove_empty_parts(set); + if (!set) + goto error; + isl_assert(set->ctx, set->n > 0, goto error); + c = isl_mat_alloc(set->ctx, 2, 2); + if (!c) + goto error; + + if (set->p[0]->n_eq > 0) { + isl_assert(set->ctx, set->p[0]->n_eq == 1, goto error); + lower = c->row[0]; + upper = c->row[1]; + if (isl_int_is_pos(set->p[0]->eq[0][1])) { + isl_seq_cpy(lower, set->p[0]->eq[0], 2); + isl_seq_neg(upper, set->p[0]->eq[0], 2); + } else { + isl_seq_neg(lower, set->p[0]->eq[0], 2); + isl_seq_cpy(upper, set->p[0]->eq[0], 2); + } + } else { + for (j = 0; j < set->p[0]->n_ineq; ++j) { + if (isl_int_is_pos(set->p[0]->ineq[j][1])) { + lower = c->row[0]; + isl_seq_cpy(lower, set->p[0]->ineq[j], 2); + } else { + upper = c->row[1]; + isl_seq_cpy(upper, set->p[0]->ineq[j], 2); + } + } + } + + isl_int_init(a); + isl_int_init(b); + for (i = 0; i < set->n; ++i) { + struct isl_basic_set *bset = set->p[i]; + int has_lower = 0; + int has_upper = 0; + + for (j = 0; j < bset->n_eq; ++j) { + has_lower = 1; + has_upper = 1; + if (lower) { + isl_int_mul(a, lower[0], bset->eq[j][1]); + isl_int_mul(b, lower[1], bset->eq[j][0]); + if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1])) + isl_seq_cpy(lower, bset->eq[j], 2); + if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1])) + isl_seq_neg(lower, bset->eq[j], 2); + } + if (upper) { + isl_int_mul(a, upper[0], bset->eq[j][1]); + isl_int_mul(b, upper[1], bset->eq[j][0]); + if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1])) + isl_seq_neg(upper, bset->eq[j], 2); + if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1])) + isl_seq_cpy(upper, bset->eq[j], 2); + } + } + for (j = 0; j < bset->n_ineq; ++j) { + if (isl_int_is_pos(bset->ineq[j][1])) + has_lower = 1; + if (isl_int_is_neg(bset->ineq[j][1])) + has_upper = 1; + if (lower && isl_int_is_pos(bset->ineq[j][1])) { + isl_int_mul(a, lower[0], bset->ineq[j][1]); + isl_int_mul(b, lower[1], bset->ineq[j][0]); + if (isl_int_lt(a, b)) + isl_seq_cpy(lower, bset->ineq[j], 2); + } + if (upper && isl_int_is_neg(bset->ineq[j][1])) { + isl_int_mul(a, upper[0], bset->ineq[j][1]); + isl_int_mul(b, upper[1], bset->ineq[j][0]); + if (isl_int_gt(a, b)) + isl_seq_cpy(upper, bset->ineq[j], 2); + } + } + if (!has_lower) + lower = NULL; + if (!has_upper) + upper = NULL; + } + isl_int_clear(a); + isl_int_clear(b); + + hull = isl_basic_set_alloc(set->ctx, 0, 1, 0, 0, 2); + hull = isl_basic_set_set_rational(hull); + if (!hull) + goto error; + if (lower) { + k = isl_basic_set_alloc_inequality(hull); + isl_seq_cpy(hull->ineq[k], lower, 2); + } + if (upper) { + k = isl_basic_set_alloc_inequality(hull); + isl_seq_cpy(hull->ineq[k], upper, 2); + } + hull = isl_basic_set_finalize(hull); + isl_set_free(set); + isl_mat_free(c); + return hull; +error: + isl_set_free(set); + isl_mat_free(c); + return NULL; +} + +static __isl_give isl_basic_set *convex_hull_0d(__isl_take isl_set *set) +{ + struct isl_basic_set *convex_hull; + + if (!set) + return NULL; + + if (isl_set_is_empty(set)) + convex_hull = isl_basic_set_empty(isl_space_copy(set->dim)); + else + convex_hull = isl_basic_set_universe(isl_space_copy(set->dim)); + isl_set_free(set); + return convex_hull; +} + +/* Compute the convex hull of a pair of basic sets without any parameters or + * integer divisions using Fourier-Motzkin elimination. + * The convex hull is the set of all points that can be written as + * the sum of points from both basic sets (in homogeneous coordinates). + * We set up the constraints in a space with dimensions for each of + * the three sets and then project out the dimensions corresponding + * to the two original basic sets, retaining only those corresponding + * to the convex hull. + */ +static __isl_give isl_basic_set *convex_hull_pair_elim( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + int i, j, k; + struct isl_basic_set *bset[2]; + struct isl_basic_set *hull = NULL; + unsigned dim; + + if (!bset1 || !bset2) + goto error; + + dim = isl_basic_set_n_dim(bset1); + hull = isl_basic_set_alloc(bset1->ctx, 0, 2 + 3 * dim, 0, + 1 + dim + bset1->n_eq + bset2->n_eq, + 2 + bset1->n_ineq + bset2->n_ineq); + bset[0] = bset1; + bset[1] = bset2; + for (i = 0; i < 2; ++i) { + for (j = 0; j < bset[i]->n_eq; ++j) { + k = isl_basic_set_alloc_equality(hull); + if (k < 0) + goto error; + isl_seq_clr(hull->eq[k], (i+1) * (1+dim)); + isl_seq_clr(hull->eq[k]+(i+2)*(1+dim), (1-i)*(1+dim)); + isl_seq_cpy(hull->eq[k]+(i+1)*(1+dim), bset[i]->eq[j], + 1+dim); + } + for (j = 0; j < bset[i]->n_ineq; ++j) { + k = isl_basic_set_alloc_inequality(hull); + if (k < 0) + goto error; + isl_seq_clr(hull->ineq[k], (i+1) * (1+dim)); + isl_seq_clr(hull->ineq[k]+(i+2)*(1+dim), (1-i)*(1+dim)); + isl_seq_cpy(hull->ineq[k]+(i+1)*(1+dim), + bset[i]->ineq[j], 1+dim); + } + k = isl_basic_set_alloc_inequality(hull); + if (k < 0) + goto error; + isl_seq_clr(hull->ineq[k], 1+2+3*dim); + isl_int_set_si(hull->ineq[k][(i+1)*(1+dim)], 1); + } + for (j = 0; j < 1+dim; ++j) { + k = isl_basic_set_alloc_equality(hull); + if (k < 0) + goto error; + isl_seq_clr(hull->eq[k], 1+2+3*dim); + isl_int_set_si(hull->eq[k][j], -1); + isl_int_set_si(hull->eq[k][1+dim+j], 1); + isl_int_set_si(hull->eq[k][2*(1+dim)+j], 1); + } + hull = isl_basic_set_set_rational(hull); + hull = isl_basic_set_remove_dims(hull, isl_dim_set, dim, 2*(1+dim)); + hull = isl_basic_set_remove_redundancies(hull); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return hull; +error: + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + isl_basic_set_free(hull); + return NULL; +} + +/* Is the set bounded for each value of the parameters? + */ +isl_bool isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset) +{ + struct isl_tab *tab; + isl_bool bounded; + + if (!bset) + return isl_bool_error; + if (isl_basic_set_plain_is_empty(bset)) + return isl_bool_true; + + tab = isl_tab_from_recession_cone(bset, 1); + bounded = isl_tab_cone_is_bounded(tab); + isl_tab_free(tab); + return bounded; +} + +/* Is the image bounded for each value of the parameters and + * the domain variables? + */ +isl_bool isl_basic_map_image_is_bounded(__isl_keep isl_basic_map *bmap) +{ + unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param); + unsigned n_in = isl_basic_map_dim(bmap, isl_dim_in); + isl_bool bounded; + + bmap = isl_basic_map_copy(bmap); + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_move_dims(bmap, isl_dim_param, nparam, + isl_dim_in, 0, n_in); + bounded = isl_basic_set_is_bounded(bset_from_bmap(bmap)); + isl_basic_map_free(bmap); + + return bounded; +} + +/* Is the set bounded for each value of the parameters? + */ +isl_bool isl_set_is_bounded(__isl_keep isl_set *set) +{ + int i; + + if (!set) + return isl_bool_error; + + for (i = 0; i < set->n; ++i) { + isl_bool bounded = isl_basic_set_is_bounded(set->p[i]); + if (!bounded || bounded < 0) + return bounded; + } + return isl_bool_true; +} + +/* Compute the lineality space of the convex hull of bset1 and bset2. + * + * We first compute the intersection of the recession cone of bset1 + * with the negative of the recession cone of bset2 and then compute + * the linear hull of the resulting cone. + */ +static __isl_give isl_basic_set *induced_lineality_space( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + int i, k; + struct isl_basic_set *lin = NULL; + unsigned dim; + + if (!bset1 || !bset2) + goto error; + + dim = isl_basic_set_total_dim(bset1); + lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset1), 0, + bset1->n_eq + bset2->n_eq, + bset1->n_ineq + bset2->n_ineq); + lin = isl_basic_set_set_rational(lin); + if (!lin) + goto error; + for (i = 0; i < bset1->n_eq; ++i) { + k = isl_basic_set_alloc_equality(lin); + if (k < 0) + goto error; + isl_int_set_si(lin->eq[k][0], 0); + isl_seq_cpy(lin->eq[k] + 1, bset1->eq[i] + 1, dim); + } + for (i = 0; i < bset1->n_ineq; ++i) { + k = isl_basic_set_alloc_inequality(lin); + if (k < 0) + goto error; + isl_int_set_si(lin->ineq[k][0], 0); + isl_seq_cpy(lin->ineq[k] + 1, bset1->ineq[i] + 1, dim); + } + for (i = 0; i < bset2->n_eq; ++i) { + k = isl_basic_set_alloc_equality(lin); + if (k < 0) + goto error; + isl_int_set_si(lin->eq[k][0], 0); + isl_seq_neg(lin->eq[k] + 1, bset2->eq[i] + 1, dim); + } + for (i = 0; i < bset2->n_ineq; ++i) { + k = isl_basic_set_alloc_inequality(lin); + if (k < 0) + goto error; + isl_int_set_si(lin->ineq[k][0], 0); + isl_seq_neg(lin->ineq[k] + 1, bset2->ineq[i] + 1, dim); + } + + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return isl_basic_set_affine_hull(lin); +error: + isl_basic_set_free(lin); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return NULL; +} + +static __isl_give isl_basic_set *uset_convex_hull(__isl_take isl_set *set); + +/* Given a set and a linear space "lin" of dimension n > 0, + * project the linear space from the set, compute the convex hull + * and then map the set back to the original space. + * + * Let + * + * M x = 0 + * + * describe the linear space. We first compute the Hermite normal + * form H = M U of M = H Q, to obtain + * + * H Q x = 0 + * + * The last n rows of H will be zero, so the last n variables of x' = Q x + * are the one we want to project out. We do this by transforming each + * basic set A x >= b to A U x' >= b and then removing the last n dimensions. + * After computing the convex hull in x'_1, i.e., A' x'_1 >= b', + * we transform the hull back to the original space as A' Q_1 x >= b', + * with Q_1 all but the last n rows of Q. + */ +static __isl_give isl_basic_set *modulo_lineality(__isl_take isl_set *set, + __isl_take isl_basic_set *lin) +{ + unsigned total = isl_basic_set_total_dim(lin); + unsigned lin_dim; + struct isl_basic_set *hull; + struct isl_mat *M, *U, *Q; + + if (!set || !lin) + goto error; + lin_dim = total - lin->n_eq; + 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; + isl_mat_free(M); + isl_basic_set_free(lin); + + Q = isl_mat_drop_rows(Q, Q->n_row - lin_dim, lin_dim); + + U = isl_mat_lin_to_aff(U); + Q = isl_mat_lin_to_aff(Q); + + set = isl_set_preimage(set, U); + set = isl_set_remove_dims(set, isl_dim_set, total - lin_dim, lin_dim); + hull = uset_convex_hull(set); + hull = isl_basic_set_preimage(hull, Q); + + return hull; +error: + isl_basic_set_free(lin); + isl_set_free(set); + return NULL; +} + +/* Given two polyhedra with as constraints h_{ij} x >= 0 in homegeneous space, + * set up an LP for solving + * + * \sum_j \alpha_{1j} h_{1j} = \sum_j \alpha_{2j} h_{2j} + * + * \alpha{i0} corresponds to the (implicit) positivity constraint 1 >= 0 + * The next \alpha{ij} correspond to the equalities and come in pairs. + * The final \alpha{ij} correspond to the inequalities. + */ +static __isl_give isl_basic_set *valid_direction_lp( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + isl_space *dim; + struct isl_basic_set *lp; + unsigned d; + int n; + int i, j, k; + + if (!bset1 || !bset2) + goto error; + d = 1 + isl_basic_set_total_dim(bset1); + n = 2 + + 2 * bset1->n_eq + bset1->n_ineq + 2 * bset2->n_eq + bset2->n_ineq; + dim = isl_space_set_alloc(bset1->ctx, 0, n); + lp = isl_basic_set_alloc_space(dim, 0, d, n); + if (!lp) + goto error; + for (i = 0; i < n; ++i) { + k = isl_basic_set_alloc_inequality(lp); + if (k < 0) + goto error; + isl_seq_clr(lp->ineq[k] + 1, n); + isl_int_set_si(lp->ineq[k][0], -1); + isl_int_set_si(lp->ineq[k][1 + i], 1); + } + for (i = 0; i < d; ++i) { + k = isl_basic_set_alloc_equality(lp); + if (k < 0) + goto error; + n = 0; + isl_int_set_si(lp->eq[k][n], 0); n++; + /* positivity constraint 1 >= 0 */ + isl_int_set_si(lp->eq[k][n], i == 0); n++; + for (j = 0; j < bset1->n_eq; ++j) { + isl_int_set(lp->eq[k][n], bset1->eq[j][i]); n++; + isl_int_neg(lp->eq[k][n], bset1->eq[j][i]); n++; + } + for (j = 0; j < bset1->n_ineq; ++j) { + isl_int_set(lp->eq[k][n], bset1->ineq[j][i]); n++; + } + /* positivity constraint 1 >= 0 */ + isl_int_set_si(lp->eq[k][n], -(i == 0)); n++; + for (j = 0; j < bset2->n_eq; ++j) { + isl_int_neg(lp->eq[k][n], bset2->eq[j][i]); n++; + isl_int_set(lp->eq[k][n], bset2->eq[j][i]); n++; + } + for (j = 0; j < bset2->n_ineq; ++j) { + isl_int_neg(lp->eq[k][n], bset2->ineq[j][i]); n++; + } + } + lp = isl_basic_set_gauss(lp, NULL); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return lp; +error: + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return NULL; +} + +/* Compute a vector s in the homogeneous space such that > 0 + * for all rays in the homogeneous space of the two cones that correspond + * to the input polyhedra bset1 and bset2. + * + * We compute s as a vector that satisfies + * + * s = \sum_j \alpha_{ij} h_{ij} for i = 1,2 (*) + * + * with h_{ij} the normals of the facets of polyhedron i + * (including the "positivity constraint" 1 >= 0) and \alpha_{ij} + * strictly positive numbers. For simplicity we impose \alpha_{ij} >= 1. + * We first set up an LP with as variables the \alpha{ij}. + * In this formulation, for each polyhedron i, + * the first constraint is the positivity constraint, followed by pairs + * of variables for the equalities, followed by variables for the inequalities. + * We then simply pick a feasible solution and compute s using (*). + * + * Note that we simply pick any valid direction and make no attempt + * to pick a "good" or even the "best" valid direction. + */ +static __isl_give isl_vec *valid_direction( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + struct isl_basic_set *lp; + struct isl_tab *tab; + struct isl_vec *sample = NULL; + struct isl_vec *dir; + unsigned d; + int i; + int n; + + if (!bset1 || !bset2) + goto error; + lp = valid_direction_lp(isl_basic_set_copy(bset1), + isl_basic_set_copy(bset2)); + tab = isl_tab_from_basic_set(lp, 0); + sample = isl_tab_get_sample_value(tab); + isl_tab_free(tab); + isl_basic_set_free(lp); + if (!sample) + goto error; + d = isl_basic_set_total_dim(bset1); + dir = isl_vec_alloc(bset1->ctx, 1 + d); + if (!dir) + goto error; + isl_seq_clr(dir->block.data + 1, dir->size - 1); + n = 1; + /* positivity constraint 1 >= 0 */ + isl_int_set(dir->block.data[0], sample->block.data[n]); n++; + for (i = 0; i < bset1->n_eq; ++i) { + isl_int_sub(sample->block.data[n], + sample->block.data[n], sample->block.data[n+1]); + isl_seq_combine(dir->block.data, + bset1->ctx->one, dir->block.data, + sample->block.data[n], bset1->eq[i], 1 + d); + + n += 2; + } + for (i = 0; i < bset1->n_ineq; ++i) + isl_seq_combine(dir->block.data, + bset1->ctx->one, dir->block.data, + sample->block.data[n++], bset1->ineq[i], 1 + d); + isl_vec_free(sample); + isl_seq_normalize(bset1->ctx, dir->el, dir->size); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return dir; +error: + isl_vec_free(sample); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return NULL; +} + +/* Given a polyhedron b_i + A_i x >= 0 and a map T = S^{-1}, + * compute b_i' + A_i' x' >= 0, with + * + * [ b_i A_i ] [ y' ] [ y' ] + * [ 1 0 ] S^{-1} [ x' ] >= 0 or [ b_i' A_i' ] [ x' ] >= 0 + * + * In particular, add the "positivity constraint" and then perform + * the mapping. + */ +static __isl_give isl_basic_set *homogeneous_map(__isl_take isl_basic_set *bset, + __isl_take isl_mat *T) +{ + int k; + + if (!bset) + goto error; + bset = isl_basic_set_extend_constraints(bset, 0, 1); + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_clr(bset->ineq[k] + 1, isl_basic_set_total_dim(bset)); + isl_int_set_si(bset->ineq[k][0], 1); + bset = isl_basic_set_preimage(bset, T); + return bset; +error: + isl_mat_free(T); + isl_basic_set_free(bset); + return NULL; +} + +/* Compute the convex hull of a pair of basic sets without any parameters or + * integer divisions, where the convex hull is known to be pointed, + * but the basic sets may be unbounded. + * + * We turn this problem into the computation of a convex hull of a pair + * _bounded_ polyhedra by "changing the direction of the homogeneous + * dimension". This idea is due to Matthias Koeppe. + * + * Consider the cones in homogeneous space that correspond to the + * input polyhedra. The rays of these cones are also rays of the + * polyhedra if the coordinate that corresponds to the homogeneous + * dimension is zero. That is, if the inner product of the rays + * with the homogeneous direction is zero. + * The cones in the homogeneous space can also be considered to + * correspond to other pairs of polyhedra by chosing a different + * homogeneous direction. To ensure that both of these polyhedra + * are bounded, we need to make sure that all rays of the cones + * correspond to vertices and not to rays. + * Let s be a direction such that > 0 for all rays r of both cones. + * Then using s as a homogeneous direction, we obtain a pair of polytopes. + * The vector s is computed in valid_direction. + * + * Note that we need to consider _all_ rays of the cones and not just + * the rays that correspond to rays in the polyhedra. If we were to + * only consider those rays and turn them into vertices, then we + * may inadvertently turn some vertices into rays. + * + * The standard homogeneous direction is the unit vector in the 0th coordinate. + * We therefore transform the two polyhedra such that the selected + * direction is mapped onto this standard direction and then proceed + * with the normal computation. + * Let S be a non-singular square matrix with s as its first row, + * then we want to map the polyhedra to the space + * + * [ y' ] [ y ] [ y ] [ y' ] + * [ x' ] = S [ x ] i.e., [ x ] = S^{-1} [ x' ] + * + * We take S to be the unimodular completion of s to limit the growth + * of the coefficients in the following computations. + * + * Let b_i + A_i x >= 0 be the constraints of polyhedron i. + * We first move to the homogeneous dimension + * + * b_i y + A_i x >= 0 [ b_i A_i ] [ y ] [ 0 ] + * y >= 0 or [ 1 0 ] [ x ] >= [ 0 ] + * + * Then we change directoin + * + * [ b_i A_i ] [ y' ] [ y' ] + * [ 1 0 ] S^{-1} [ x' ] >= 0 or [ b_i' A_i' ] [ x' ] >= 0 + * + * Then we compute the convex hull of the polytopes b_i' + A_i' x' >= 0 + * resulting in b' + A' x' >= 0, which we then convert back + * + * [ y ] [ y ] + * [ b' A' ] S [ x ] >= 0 or [ b A ] [ x ] >= 0 + * + * The polyhedron b + A x >= 0 is then the convex hull of the input polyhedra. + */ +static __isl_give isl_basic_set *convex_hull_pair_pointed( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + struct isl_ctx *ctx = NULL; + struct isl_vec *dir = NULL; + struct isl_mat *T = NULL; + struct isl_mat *T2 = NULL; + struct isl_basic_set *hull; + struct isl_set *set; + + if (!bset1 || !bset2) + goto error; + ctx = isl_basic_set_get_ctx(bset1); + dir = valid_direction(isl_basic_set_copy(bset1), + isl_basic_set_copy(bset2)); + if (!dir) + goto error; + T = isl_mat_alloc(ctx, dir->size, dir->size); + if (!T) + goto error; + isl_seq_cpy(T->row[0], dir->block.data, dir->size); + T = isl_mat_unimodular_complete(T, 1); + T2 = isl_mat_right_inverse(isl_mat_copy(T)); + + bset1 = homogeneous_map(bset1, isl_mat_copy(T2)); + bset2 = homogeneous_map(bset2, T2); + set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0); + set = isl_set_add_basic_set(set, bset1); + set = isl_set_add_basic_set(set, bset2); + hull = uset_convex_hull(set); + hull = isl_basic_set_preimage(hull, T); + + isl_vec_free(dir); + + return hull; +error: + isl_vec_free(dir); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return NULL; +} + +static __isl_give isl_basic_set *uset_convex_hull_wrap(__isl_take isl_set *set); +static __isl_give isl_basic_set *modulo_affine_hull( + __isl_take isl_set *set, __isl_take isl_basic_set *affine_hull); + +/* Compute the convex hull of a pair of basic sets without any parameters or + * integer divisions. + * + * This function is called from uset_convex_hull_unbounded, which + * means that the complete convex hull is unbounded. Some pairs + * of basic sets may still be bounded, though. + * They may even lie inside a lower dimensional space, in which + * case they need to be handled inside their affine hull since + * the main algorithm assumes that the result is full-dimensional. + * + * If the convex hull of the two basic sets would have a non-trivial + * lineality space, we first project out this lineality space. + */ +static __isl_give isl_basic_set *convex_hull_pair( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + isl_basic_set *lin, *aff; + int bounded1, bounded2; + + if (bset1->ctx->opt->convex == ISL_CONVEX_HULL_FM) + return convex_hull_pair_elim(bset1, bset2); + + aff = isl_set_affine_hull(isl_basic_set_union(isl_basic_set_copy(bset1), + isl_basic_set_copy(bset2))); + if (!aff) + goto error; + if (aff->n_eq != 0) + return modulo_affine_hull(isl_basic_set_union(bset1, bset2), aff); + isl_basic_set_free(aff); + + bounded1 = isl_basic_set_is_bounded(bset1); + bounded2 = isl_basic_set_is_bounded(bset2); + + if (bounded1 < 0 || bounded2 < 0) + goto error; + + if (bounded1 && bounded2) + return uset_convex_hull_wrap(isl_basic_set_union(bset1, bset2)); + + if (bounded1 || bounded2) + return convex_hull_pair_pointed(bset1, bset2); + + lin = induced_lineality_space(isl_basic_set_copy(bset1), + isl_basic_set_copy(bset2)); + if (!lin) + goto error; + if (isl_basic_set_plain_is_universe(lin)) { + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return lin; + } + if (lin->n_eq < isl_basic_set_total_dim(lin)) { + struct isl_set *set; + set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0); + set = isl_set_add_basic_set(set, bset1); + set = isl_set_add_basic_set(set, bset2); + return modulo_lineality(set, lin); + } + isl_basic_set_free(lin); + + return convex_hull_pair_pointed(bset1, bset2); +error: + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + return NULL; +} + +/* Compute the lineality space of a basic set. + * We basically just drop the constants and turn every inequality + * into an equality. + * Any explicit representations of local variables are removed + * because they may no longer be valid representations + * in the lineality space. + */ +__isl_give isl_basic_set *isl_basic_set_lineality_space( + __isl_take isl_basic_set *bset) +{ + int i, k; + struct isl_basic_set *lin = NULL; + unsigned n_div, dim; + + if (!bset) + goto error; + n_div = isl_basic_set_dim(bset, isl_dim_div); + dim = isl_basic_set_total_dim(bset); + + lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset), + n_div, dim, 0); + for (i = 0; i < n_div; ++i) + if (isl_basic_set_alloc_div(lin) < 0) + goto error; + if (!lin) + goto error; + for (i = 0; i < bset->n_eq; ++i) { + k = isl_basic_set_alloc_equality(lin); + if (k < 0) + goto error; + isl_int_set_si(lin->eq[k][0], 0); + isl_seq_cpy(lin->eq[k] + 1, bset->eq[i] + 1, dim); + } + lin = isl_basic_set_gauss(lin, NULL); + if (!lin) + goto error; + for (i = 0; i < bset->n_ineq && lin->n_eq < dim; ++i) { + k = isl_basic_set_alloc_equality(lin); + if (k < 0) + goto error; + isl_int_set_si(lin->eq[k][0], 0); + isl_seq_cpy(lin->eq[k] + 1, bset->ineq[i] + 1, dim); + lin = isl_basic_set_gauss(lin, NULL); + if (!lin) + goto error; + } + isl_basic_set_free(bset); + return lin; +error: + isl_basic_set_free(lin); + isl_basic_set_free(bset); + return NULL; +} + +/* Compute the (linear) hull of the lineality spaces of the basic sets in the + * set "set". + */ +__isl_give isl_basic_set *isl_set_combined_lineality_space( + __isl_take isl_set *set) +{ + int i; + struct isl_set *lin = NULL; + + if (!set) + return NULL; + if (set->n == 0) { + isl_space *space = isl_set_get_space(set); + isl_set_free(set); + return isl_basic_set_empty(space); + } + + lin = isl_set_alloc_space(isl_set_get_space(set), set->n, 0); + for (i = 0; i < set->n; ++i) + lin = isl_set_add_basic_set(lin, + isl_basic_set_lineality_space(isl_basic_set_copy(set->p[i]))); + isl_set_free(set); + return isl_set_affine_hull(lin); +} + +/* Compute the convex hull of a set without any parameters or + * integer divisions. + * In each step, we combined two basic sets until only one + * basic set is left. + * The input basic sets are assumed not to have a non-trivial + * lineality space. If any of the intermediate results has + * a non-trivial lineality space, it is projected out. + */ +static __isl_give isl_basic_set *uset_convex_hull_unbounded( + __isl_take isl_set *set) +{ + isl_basic_set_list *list; + + list = isl_set_get_basic_set_list(set); + isl_set_free(set); + + while (list) { + int n; + struct isl_basic_set *t; + isl_basic_set *bset1, *bset2; + + n = isl_basic_set_list_n_basic_set(list); + if (n < 2) + isl_die(isl_basic_set_list_get_ctx(list), + isl_error_internal, + "expecting at least two elements", goto error); + bset1 = isl_basic_set_list_get_basic_set(list, n - 1); + bset2 = isl_basic_set_list_get_basic_set(list, n - 2); + bset1 = convex_hull_pair(bset1, bset2); + if (n == 2) { + isl_basic_set_list_free(list); + return bset1; + } + bset1 = isl_basic_set_underlying_set(bset1); + list = isl_basic_set_list_drop(list, n - 2, 2); + list = isl_basic_set_list_add(list, bset1); + + t = isl_basic_set_list_get_basic_set(list, n - 2); + t = isl_basic_set_lineality_space(t); + if (!t) + goto error; + if (isl_basic_set_plain_is_universe(t)) { + isl_basic_set_list_free(list); + return t; + } + if (t->n_eq < isl_basic_set_total_dim(t)) { + set = isl_basic_set_list_union(list); + return modulo_lineality(set, t); + } + isl_basic_set_free(t); + } + + return NULL; +error: + isl_basic_set_list_free(list); + return NULL; +} + +/* Compute an initial hull for wrapping containing a single initial + * facet. + * This function assumes that the given set is bounded. + */ +static __isl_give isl_basic_set *initial_hull(__isl_take isl_basic_set *hull, + __isl_keep isl_set *set) +{ + struct isl_mat *bounds = NULL; + unsigned dim; + int k; + + if (!hull) + goto error; + bounds = initial_facet_constraint(set); + if (!bounds) + goto error; + k = isl_basic_set_alloc_inequality(hull); + if (k < 0) + goto error; + dim = isl_set_n_dim(set); + isl_assert(set->ctx, 1 + dim == bounds->n_col, goto error); + isl_seq_cpy(hull->ineq[k], bounds->row[0], bounds->n_col); + isl_mat_free(bounds); + + return hull; +error: + isl_basic_set_free(hull); + isl_mat_free(bounds); + return NULL; +} + +struct max_constraint { + struct isl_mat *c; + int count; + int ineq; +}; + +static int max_constraint_equal(const void *entry, const void *val) +{ + struct max_constraint *a = (struct max_constraint *)entry; + isl_int *b = (isl_int *)val; + + return isl_seq_eq(a->c->row[0] + 1, b, a->c->n_col - 1); +} + +static void update_constraint(struct isl_ctx *ctx, struct isl_hash_table *table, + isl_int *con, unsigned len, int n, int ineq) +{ + struct isl_hash_table_entry *entry; + struct max_constraint *c; + uint32_t c_hash; + + c_hash = isl_seq_get_hash(con + 1, len); + entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal, + con + 1, 0); + if (!entry) + return; + c = entry->data; + if (c->count < n) { + isl_hash_table_remove(ctx, table, entry); + return; + } + c->count++; + if (isl_int_gt(c->c->row[0][0], con[0])) + return; + if (isl_int_eq(c->c->row[0][0], con[0])) { + if (ineq) + c->ineq = ineq; + return; + } + c->c = isl_mat_cow(c->c); + isl_int_set(c->c->row[0][0], con[0]); + c->ineq = ineq; +} + +/* Check whether the constraint hash table "table" constains the constraint + * "con". + */ +static int has_constraint(struct isl_ctx *ctx, struct isl_hash_table *table, + isl_int *con, unsigned len, int n) +{ + struct isl_hash_table_entry *entry; + struct max_constraint *c; + uint32_t c_hash; + + c_hash = isl_seq_get_hash(con + 1, len); + entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal, + con + 1, 0); + if (!entry) + return 0; + c = entry->data; + if (c->count < n) + return 0; + return isl_int_eq(c->c->row[0][0], con[0]); +} + +/* Check for inequality constraints of a basic set without equalities + * such that the same or more stringent copies of the constraint appear + * in all of the basic sets. Such constraints are necessarily facet + * constraints of the convex hull. + * + * If the resulting basic set is by chance identical to one of + * the basic sets in "set", then we know that this basic set contains + * all other basic sets and is therefore the convex hull of set. + * In this case we set *is_hull to 1. + */ +static __isl_give isl_basic_set *common_constraints( + __isl_take isl_basic_set *hull, __isl_keep isl_set *set, int *is_hull) +{ + int i, j, s, n; + int min_constraints; + int best; + struct max_constraint *constraints = NULL; + struct isl_hash_table *table = NULL; + unsigned total; + + *is_hull = 0; + + for (i = 0; i < set->n; ++i) + if (set->p[i]->n_eq == 0) + break; + if (i >= set->n) + return hull; + min_constraints = set->p[i]->n_ineq; + best = i; + for (i = best + 1; i < set->n; ++i) { + if (set->p[i]->n_eq != 0) + continue; + if (set->p[i]->n_ineq >= min_constraints) + continue; + min_constraints = set->p[i]->n_ineq; + best = i; + } + constraints = isl_calloc_array(hull->ctx, struct max_constraint, + min_constraints); + if (!constraints) + return hull; + table = isl_alloc_type(hull->ctx, struct isl_hash_table); + if (isl_hash_table_init(hull->ctx, table, min_constraints)) + goto error; + + total = isl_space_dim(set->dim, isl_dim_all); + for (i = 0; i < set->p[best]->n_ineq; ++i) { + 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; + constraints[i].ineq = 1; + } + for (i = 0; i < min_constraints; ++i) { + struct isl_hash_table_entry *entry; + uint32_t c_hash; + c_hash = isl_seq_get_hash(constraints[i].c->row[0] + 1, total); + entry = isl_hash_table_find(hull->ctx, table, c_hash, + max_constraint_equal, constraints[i].c->row[0] + 1, 1); + if (!entry) + goto error; + isl_assert(hull->ctx, !entry->data, goto error); + entry->data = &constraints[i]; + } + + n = 0; + for (s = 0; s < set->n; ++s) { + if (s == best) + continue; + + for (i = 0; i < set->p[s]->n_eq; ++i) { + isl_int *eq = set->p[s]->eq[i]; + for (j = 0; j < 2; ++j) { + isl_seq_neg(eq, eq, 1 + total); + update_constraint(hull->ctx, table, + eq, total, n, 0); + } + } + for (i = 0; i < set->p[s]->n_ineq; ++i) { + isl_int *ineq = set->p[s]->ineq[i]; + update_constraint(hull->ctx, table, ineq, total, n, + set->p[s]->n_eq == 0); + } + ++n; + } + + for (i = 0; i < min_constraints; ++i) { + if (constraints[i].count < n) + continue; + if (!constraints[i].ineq) + continue; + j = isl_basic_set_alloc_inequality(hull); + if (j < 0) + goto error; + isl_seq_cpy(hull->ineq[j], constraints[i].c->row[0], 1 + total); + } + + for (s = 0; s < set->n; ++s) { + if (set->p[s]->n_eq) + continue; + if (set->p[s]->n_ineq != hull->n_ineq) + continue; + for (i = 0; i < set->p[s]->n_ineq; ++i) { + isl_int *ineq = set->p[s]->ineq[i]; + if (!has_constraint(hull->ctx, table, ineq, total, n)) + break; + } + if (i == set->p[s]->n_ineq) + *is_hull = 1; + } + + isl_hash_table_clear(table); + for (i = 0; i < min_constraints; ++i) + isl_mat_free(constraints[i].c); + free(constraints); + free(table); + return hull; +error: + isl_hash_table_clear(table); + free(table); + if (constraints) + for (i = 0; i < min_constraints; ++i) + isl_mat_free(constraints[i].c); + free(constraints); + return hull; +} + +/* Create a template for the convex hull of "set" and fill it up + * obvious facet constraints, if any. If the result happens to + * be the convex hull of "set" then *is_hull is set to 1. + */ +static __isl_give isl_basic_set *proto_hull(__isl_keep isl_set *set, + int *is_hull) +{ + struct isl_basic_set *hull; + unsigned n_ineq; + int i; + + n_ineq = 1; + for (i = 0; i < set->n; ++i) { + n_ineq += set->p[i]->n_eq; + n_ineq += set->p[i]->n_ineq; + } + hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq); + hull = isl_basic_set_set_rational(hull); + if (!hull) + return NULL; + return common_constraints(hull, set, is_hull); +} + +static __isl_give isl_basic_set *uset_convex_hull_wrap(__isl_take isl_set *set) +{ + struct isl_basic_set *hull; + int is_hull; + + hull = proto_hull(set, &is_hull); + if (hull && !is_hull) { + if (hull->n_ineq == 0) + hull = initial_hull(hull, set); + hull = extend(hull, set); + } + isl_set_free(set); + + return hull; +} + +/* Compute the convex hull of a set without any parameters or + * integer divisions. Depending on whether the set is bounded, + * we pass control to the wrapping based convex hull or + * the Fourier-Motzkin elimination based convex hull. + * We also handle a few special cases before checking the boundedness. + */ +static __isl_give isl_basic_set *uset_convex_hull(__isl_take isl_set *set) +{ + isl_bool bounded; + struct isl_basic_set *convex_hull = NULL; + struct isl_basic_set *lin; + + if (isl_set_n_dim(set) == 0) + return convex_hull_0d(set); + + set = isl_set_coalesce(set); + set = isl_set_set_rational(set); + + if (!set) + return NULL; + if (set->n == 1) { + convex_hull = isl_basic_set_copy(set->p[0]); + isl_set_free(set); + return convex_hull; + } + if (isl_set_n_dim(set) == 1) + return convex_hull_1d(set); + + bounded = isl_set_is_bounded(set); + if (bounded < 0) + goto error; + if (bounded && set->ctx->opt->convex == ISL_CONVEX_HULL_WRAP) + return uset_convex_hull_wrap(set); + + lin = isl_set_combined_lineality_space(isl_set_copy(set)); + if (!lin) + goto error; + if (isl_basic_set_plain_is_universe(lin)) { + isl_set_free(set); + return lin; + } + if (lin->n_eq < isl_basic_set_total_dim(lin)) + return modulo_lineality(set, lin); + isl_basic_set_free(lin); + + return uset_convex_hull_unbounded(set); +error: + isl_set_free(set); + isl_basic_set_free(convex_hull); + return NULL; +} + +/* This is the core procedure, where "set" is a "pure" set, i.e., + * without parameters or divs and where the convex hull of set is + * known to be full-dimensional. + */ +static __isl_give isl_basic_set *uset_convex_hull_wrap_bounded( + __isl_take isl_set *set) +{ + struct isl_basic_set *convex_hull = NULL; + + if (!set) + goto error; + + if (isl_set_n_dim(set) == 0) { + convex_hull = isl_basic_set_universe(isl_space_copy(set->dim)); + isl_set_free(set); + convex_hull = isl_basic_set_set_rational(convex_hull); + return convex_hull; + } + + set = isl_set_set_rational(set); + set = isl_set_coalesce(set); + if (!set) + goto error; + if (set->n == 1) { + convex_hull = isl_basic_set_copy(set->p[0]); + isl_set_free(set); + convex_hull = isl_basic_map_remove_redundancies(convex_hull); + return convex_hull; + } + if (isl_set_n_dim(set) == 1) + return convex_hull_1d(set); + + return uset_convex_hull_wrap(set); +error: + isl_set_free(set); + return NULL; +} + +/* Compute the convex hull of set "set" with affine hull "affine_hull", + * We first remove the equalities (transforming the set), compute the + * convex hull of the transformed set and then add the equalities back + * (after performing the inverse transformation. + */ +static __isl_give isl_basic_set *modulo_affine_hull( + __isl_take isl_set *set, __isl_take isl_basic_set *affine_hull) +{ + struct isl_mat *T; + struct isl_mat *T2; + struct isl_basic_set *dummy; + struct isl_basic_set *convex_hull; + + dummy = isl_basic_set_remove_equalities( + isl_basic_set_copy(affine_hull), &T, &T2); + if (!dummy) + goto error; + isl_basic_set_free(dummy); + set = isl_set_preimage(set, T); + convex_hull = uset_convex_hull(set); + convex_hull = isl_basic_set_preimage(convex_hull, T2); + convex_hull = isl_basic_set_intersect(convex_hull, affine_hull); + return convex_hull; +error: + isl_mat_free(T); + isl_mat_free(T2); + isl_basic_set_free(affine_hull); + isl_set_free(set); + return NULL; +} + +/* Return an empty basic map living in the same space as "map". + */ +static __isl_give isl_basic_map *replace_map_by_empty_basic_map( + __isl_take isl_map *map) +{ + isl_space *space; + + space = isl_map_get_space(map); + isl_map_free(map); + return isl_basic_map_empty(space); +} + +/* Compute the convex hull of a map. + * + * The implementation was inspired by "Extended Convex Hull" by Fukuda et al., + * specifically, the wrapping of facets to obtain new facets. + */ +__isl_give isl_basic_map *isl_map_convex_hull(__isl_take isl_map *map) +{ + struct isl_basic_set *bset; + struct isl_basic_map *model = NULL; + struct isl_basic_set *affine_hull = NULL; + struct isl_basic_map *convex_hull = NULL; + struct isl_set *set = NULL; + + map = isl_map_detect_equalities(map); + map = isl_map_align_divs_internal(map); + if (!map) + goto error; + + if (map->n == 0) + return replace_map_by_empty_basic_map(map); + + model = isl_basic_map_copy(map->p[0]); + set = isl_map_underlying_set(map); + if (!set) + goto error; + + affine_hull = isl_set_affine_hull(isl_set_copy(set)); + if (!affine_hull) + goto error; + if (affine_hull->n_eq != 0) + bset = modulo_affine_hull(set, affine_hull); + else { + isl_basic_set_free(affine_hull); + bset = uset_convex_hull(set); + } + + convex_hull = isl_basic_map_overlying_set(bset, model); + if (!convex_hull) + return NULL; + + ISL_F_SET(convex_hull, ISL_BASIC_MAP_NO_IMPLICIT); + ISL_F_SET(convex_hull, ISL_BASIC_MAP_ALL_EQUALITIES); + ISL_F_CLR(convex_hull, ISL_BASIC_MAP_RATIONAL); + return convex_hull; +error: + isl_set_free(set); + isl_basic_map_free(model); + return NULL; +} + +struct isl_basic_set *isl_set_convex_hull(struct isl_set *set) +{ + return bset_from_bmap(isl_map_convex_hull(set_to_map(set))); +} + +__isl_give isl_basic_map *isl_map_polyhedral_hull(__isl_take isl_map *map) +{ + isl_basic_map *hull; + + hull = isl_map_convex_hull(map); + return isl_basic_map_remove_divs(hull); +} + +__isl_give isl_basic_set *isl_set_polyhedral_hull(__isl_take isl_set *set) +{ + return bset_from_bmap(isl_map_polyhedral_hull(set_to_map(set))); +} + +struct sh_data_entry { + struct isl_hash_table *table; + struct isl_tab *tab; +}; + +/* Holds the data needed during the simple hull computation. + * In particular, + * n the number of basic sets in the original set + * hull_table a hash table of already computed constraints + * in the simple hull + * p for each basic set, + * table a hash table of the constraints + * tab the tableau corresponding to the basic set + */ +struct sh_data { + struct isl_ctx *ctx; + unsigned n; + struct isl_hash_table *hull_table; + struct sh_data_entry p[1]; +}; + +static void sh_data_free(struct sh_data *data) +{ + int i; + + if (!data) + return; + isl_hash_table_free(data->ctx, data->hull_table); + for (i = 0; i < data->n; ++i) { + isl_hash_table_free(data->ctx, data->p[i].table); + isl_tab_free(data->p[i].tab); + } + free(data); +} + +struct ineq_cmp_data { + unsigned len; + isl_int *p; +}; + +static int has_ineq(const void *entry, const void *val) +{ + isl_int *row = (isl_int *)entry; + struct ineq_cmp_data *v = (struct ineq_cmp_data *)val; + + return isl_seq_eq(row + 1, v->p + 1, v->len) || + isl_seq_is_neg(row + 1, v->p + 1, v->len); +} + +static int hash_ineq(struct isl_ctx *ctx, struct isl_hash_table *table, + isl_int *ineq, unsigned len) +{ + uint32_t c_hash; + struct ineq_cmp_data v; + struct isl_hash_table_entry *entry; + + v.len = len; + v.p = ineq; + c_hash = isl_seq_get_hash(ineq + 1, len); + entry = isl_hash_table_find(ctx, table, c_hash, has_ineq, &v, 1); + if (!entry) + return - 1; + entry->data = ineq; + return 0; +} + +/* Fill hash table "table" with the constraints of "bset". + * Equalities are added as two inequalities. + * The value in the hash table is a pointer to the (in)equality of "bset". + */ +static int hash_basic_set(struct isl_hash_table *table, + __isl_keep isl_basic_set *bset) +{ + int i, j; + unsigned dim = isl_basic_set_total_dim(bset); + + for (i = 0; i < bset->n_eq; ++i) { + for (j = 0; j < 2; ++j) { + isl_seq_neg(bset->eq[i], bset->eq[i], 1 + dim); + if (hash_ineq(bset->ctx, table, bset->eq[i], dim) < 0) + return -1; + } + } + for (i = 0; i < bset->n_ineq; ++i) { + if (hash_ineq(bset->ctx, table, bset->ineq[i], dim) < 0) + return -1; + } + return 0; +} + +static struct sh_data *sh_data_alloc(__isl_keep isl_set *set, unsigned n_ineq) +{ + struct sh_data *data; + int i; + + data = isl_calloc(set->ctx, struct sh_data, + sizeof(struct sh_data) + + (set->n - 1) * sizeof(struct sh_data_entry)); + if (!data) + return NULL; + data->ctx = set->ctx; + data->n = set->n; + data->hull_table = isl_hash_table_alloc(set->ctx, n_ineq); + if (!data->hull_table) + goto error; + for (i = 0; i < set->n; ++i) { + data->p[i].table = isl_hash_table_alloc(set->ctx, + 2 * set->p[i]->n_eq + set->p[i]->n_ineq); + if (!data->p[i].table) + goto error; + if (hash_basic_set(data->p[i].table, set->p[i]) < 0) + goto error; + } + return data; +error: + sh_data_free(data); + return NULL; +} + +/* Check if inequality "ineq" is a bound for basic set "j" or if + * it can be relaxed (by increasing the constant term) to become + * a bound for that basic set. In the latter case, the constant + * term is updated. + * Relaxation of the constant term is only allowed if "shift" is set. + * + * Return 1 if "ineq" is a bound + * 0 if "ineq" may attain arbitrarily small values on basic set "j" + * -1 if some error occurred + */ +static int is_bound(struct sh_data *data, __isl_keep isl_set *set, int j, + isl_int *ineq, int shift) +{ + enum isl_lp_result res; + isl_int opt; + + if (!data->p[j].tab) { + data->p[j].tab = isl_tab_from_basic_set(set->p[j], 0); + if (!data->p[j].tab) + return -1; + } + + isl_int_init(opt); + + res = isl_tab_min(data->p[j].tab, ineq, data->ctx->one, + &opt, NULL, 0); + if (res == isl_lp_ok && isl_int_is_neg(opt)) { + if (shift) + isl_int_sub(ineq[0], ineq[0], opt); + else + res = isl_lp_unbounded; + } + + isl_int_clear(opt); + + return (res == isl_lp_ok || res == isl_lp_empty) ? 1 : + res == isl_lp_unbounded ? 0 : -1; +} + +/* Set the constant term of "ineq" to the maximum of those of the constraints + * in the basic sets of "set" following "i" that are parallel to "ineq". + * That is, if any of the basic sets of "set" following "i" have a more + * relaxed copy of "ineq", then replace "ineq" by the most relaxed copy. + * "c_hash" is the hash value of the linear part of "ineq". + * "v" has been set up for use by has_ineq. + * + * Note that the two inequality constraints corresponding to an equality are + * represented by the same inequality constraint in data->p[j].table + * (but with different hash values). This means the constraint (or at + * least its constant term) may need to be temporarily negated to get + * the actually hashed constraint. + */ +static void set_max_constant_term(struct sh_data *data, __isl_keep isl_set *set, + int i, isl_int *ineq, uint32_t c_hash, struct ineq_cmp_data *v) +{ + int j; + isl_ctx *ctx; + struct isl_hash_table_entry *entry; + + ctx = isl_set_get_ctx(set); + for (j = i + 1; j < set->n; ++j) { + int neg; + isl_int *ineq_j; + + entry = isl_hash_table_find(ctx, data->p[j].table, + c_hash, &has_ineq, v, 0); + if (!entry) + continue; + + ineq_j = entry->data; + neg = isl_seq_is_neg(ineq_j + 1, ineq + 1, v->len); + if (neg) + isl_int_neg(ineq_j[0], ineq_j[0]); + if (isl_int_gt(ineq_j[0], ineq[0])) + isl_int_set(ineq[0], ineq_j[0]); + if (neg) + isl_int_neg(ineq_j[0], ineq_j[0]); + } +} + +/* Check if inequality "ineq" from basic set "i" is or can be relaxed to + * become a bound on the whole set. If so, add the (relaxed) inequality + * to "hull". Relaxation is only allowed if "shift" is set. + * + * We first check if "hull" already contains a translate of the inequality. + * If so, we are done. + * Then, we check if any of the previous basic sets contains a translate + * of the inequality. If so, then we have already considered this + * inequality and we are done. + * Otherwise, for each basic set other than "i", we check if the inequality + * is a bound on the basic set, but first replace the constant term + * by the maximal value of any translate of the inequality in any + * of the following basic sets. + * For previous basic sets, we know that they do not contain a translate + * of the inequality, so we directly call is_bound. + * For following basic sets, we first check if a translate of the + * inequality appears in its description. If so, the constant term + * of the inequality has already been updated with respect to this + * translate and the inequality is therefore known to be a bound + * of this basic set. + */ +static __isl_give isl_basic_set *add_bound(__isl_take isl_basic_set *hull, + struct sh_data *data, __isl_keep isl_set *set, int i, isl_int *ineq, + int shift) +{ + uint32_t c_hash; + struct ineq_cmp_data v; + struct isl_hash_table_entry *entry; + int j, k; + + if (!hull) + return NULL; + + v.len = isl_basic_set_total_dim(hull); + v.p = ineq; + c_hash = isl_seq_get_hash(ineq + 1, v.len); + + entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash, + has_ineq, &v, 0); + if (entry) + return hull; + + for (j = 0; j < i; ++j) { + entry = isl_hash_table_find(hull->ctx, data->p[j].table, + c_hash, has_ineq, &v, 0); + if (entry) + break; + } + if (j < i) + return hull; + + k = isl_basic_set_alloc_inequality(hull); + if (k < 0) + goto error; + isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len); + + set_max_constant_term(data, set, i, hull->ineq[k], c_hash, &v); + for (j = 0; j < i; ++j) { + int bound; + bound = is_bound(data, set, j, hull->ineq[k], shift); + if (bound < 0) + goto error; + if (!bound) + break; + } + if (j < i) { + isl_basic_set_free_inequality(hull, 1); + return hull; + } + + for (j = i + 1; j < set->n; ++j) { + int bound; + entry = isl_hash_table_find(hull->ctx, data->p[j].table, + c_hash, has_ineq, &v, 0); + if (entry) + continue; + bound = is_bound(data, set, j, hull->ineq[k], shift); + if (bound < 0) + goto error; + if (!bound) + break; + } + if (j < set->n) { + isl_basic_set_free_inequality(hull, 1); + return hull; + } + + entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash, + has_ineq, &v, 1); + if (!entry) + goto error; + entry->data = hull->ineq[k]; + + return hull; +error: + isl_basic_set_free(hull); + return NULL; +} + +/* Check if any inequality from basic set "i" is or can be relaxed to + * become a bound on the whole set. If so, add the (relaxed) inequality + * to "hull". Relaxation is only allowed if "shift" is set. + */ +static __isl_give isl_basic_set *add_bounds(__isl_take isl_basic_set *bset, + struct sh_data *data, __isl_keep isl_set *set, int i, int shift) +{ + int j, k; + unsigned dim = isl_basic_set_total_dim(bset); + + for (j = 0; j < set->p[i]->n_eq; ++j) { + for (k = 0; k < 2; ++k) { + isl_seq_neg(set->p[i]->eq[j], set->p[i]->eq[j], 1+dim); + bset = add_bound(bset, data, set, i, set->p[i]->eq[j], + shift); + } + } + for (j = 0; j < set->p[i]->n_ineq; ++j) + bset = add_bound(bset, data, set, i, set->p[i]->ineq[j], shift); + return bset; +} + +/* Compute a superset of the convex hull of set that is described + * by only (translates of) the constraints in the constituents of set. + * Translation is only allowed if "shift" is set. + */ +static __isl_give isl_basic_set *uset_simple_hull(__isl_take isl_set *set, + int shift) +{ + struct sh_data *data = NULL; + struct isl_basic_set *hull = NULL; + unsigned n_ineq; + int i; + + if (!set) + return NULL; + + n_ineq = 0; + for (i = 0; i < set->n; ++i) { + if (!set->p[i]) + goto error; + n_ineq += 2 * set->p[i]->n_eq + set->p[i]->n_ineq; + } + + hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq); + if (!hull) + goto error; + + data = sh_data_alloc(set, n_ineq); + if (!data) + goto error; + + for (i = 0; i < set->n; ++i) + hull = add_bounds(hull, data, set, i, shift); + + sh_data_free(data); + isl_set_free(set); + + return hull; +error: + sh_data_free(data); + isl_basic_set_free(hull); + isl_set_free(set); + return NULL; +} + +/* Compute a superset of the convex hull of map that is described + * by only (translates of) the constraints in the constituents of map. + * Handle trivial cases where map is NULL or contains at most one disjunct. + */ +static __isl_give isl_basic_map *map_simple_hull_trivial( + __isl_take isl_map *map) +{ + isl_basic_map *hull; + + if (!map) + return NULL; + if (map->n == 0) + return replace_map_by_empty_basic_map(map); + + hull = isl_basic_map_copy(map->p[0]); + isl_map_free(map); + return hull; +} + +/* Return a copy of the simple hull cached inside "map". + * "shift" determines whether to return the cached unshifted or shifted + * simple hull. + */ +static __isl_give isl_basic_map *cached_simple_hull(__isl_take isl_map *map, + int shift) +{ + isl_basic_map *hull; + + hull = isl_basic_map_copy(map->cached_simple_hull[shift]); + isl_map_free(map); + + return hull; +} + +/* Compute a superset of the convex hull of map that is described + * by only (translates of) the constraints in the constituents of map. + * Translation is only allowed if "shift" is set. + * + * The constraints are sorted while removing redundant constraints + * in order to indicate a preference of which constraints should + * be preserved. In particular, pairs of constraints that are + * sorted together are preferred to either both be preserved + * or both be removed. The sorting is performed inside + * isl_basic_map_remove_redundancies. + * + * The result of the computation is stored in map->cached_simple_hull[shift] + * such that it can be reused in subsequent calls. The cache is cleared + * whenever the map is modified (in isl_map_cow). + * Note that the results need to be stored in the input map for there + * to be any chance that they may get reused. In particular, they + * are stored in a copy of the input map that is saved before + * the integer division alignment. + */ +static __isl_give isl_basic_map *map_simple_hull(__isl_take isl_map *map, + int shift) +{ + struct isl_set *set = NULL; + struct isl_basic_map *model = NULL; + struct isl_basic_map *hull; + struct isl_basic_map *affine_hull; + struct isl_basic_set *bset = NULL; + isl_map *input; + + if (!map || map->n <= 1) + return map_simple_hull_trivial(map); + + if (map->cached_simple_hull[shift]) + return cached_simple_hull(map, shift); + + map = isl_map_detect_equalities(map); + if (!map || map->n <= 1) + return map_simple_hull_trivial(map); + affine_hull = isl_map_affine_hull(isl_map_copy(map)); + input = isl_map_copy(map); + map = isl_map_align_divs_internal(map); + model = map ? isl_basic_map_copy(map->p[0]) : NULL; + + set = isl_map_underlying_set(map); + + bset = uset_simple_hull(set, shift); + + hull = isl_basic_map_overlying_set(bset, model); + + hull = isl_basic_map_intersect(hull, affine_hull); + hull = isl_basic_map_remove_redundancies(hull); + + if (hull) { + ISL_F_SET(hull, ISL_BASIC_MAP_NO_IMPLICIT); + ISL_F_SET(hull, ISL_BASIC_MAP_ALL_EQUALITIES); + } + + hull = isl_basic_map_finalize(hull); + if (input) + input->cached_simple_hull[shift] = isl_basic_map_copy(hull); + isl_map_free(input); + + return hull; +} + +/* Compute a superset of the convex hull of map that is described + * by only translates of the constraints in the constituents of map. + */ +__isl_give isl_basic_map *isl_map_simple_hull(__isl_take isl_map *map) +{ + return map_simple_hull(map, 1); +} + +struct isl_basic_set *isl_set_simple_hull(struct isl_set *set) +{ + return bset_from_bmap(isl_map_simple_hull(set_to_map(set))); +} + +/* Compute a superset of the convex hull of map that is described + * by only the constraints in the constituents of map. + */ +__isl_give isl_basic_map *isl_map_unshifted_simple_hull( + __isl_take isl_map *map) +{ + return map_simple_hull(map, 0); +} + +__isl_give isl_basic_set *isl_set_unshifted_simple_hull( + __isl_take isl_set *set) +{ + return isl_map_unshifted_simple_hull(set); +} + +/* Drop all inequalities from "bmap1" that do not also appear in "bmap2". + * A constraint that appears with different constant terms + * in "bmap1" and "bmap2" is also kept, with the least restrictive + * (i.e., greatest) constant term. + * "bmap1" and "bmap2" are assumed to have the same (known) + * integer divisions. + * The constraints of both "bmap1" and "bmap2" are assumed + * to have been sorted using isl_basic_map_sort_constraints. + * + * Run through the inequality constraints of "bmap1" and "bmap2" + * in sorted order. + * Each constraint of "bmap1" without a matching constraint in "bmap2" + * is removed. + * If a match is found, the constraint is kept. If needed, the constant + * term of the constraint is adjusted. + */ +static __isl_give isl_basic_map *select_shared_inequalities( + __isl_take isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2) +{ + int i1, i2; + + bmap1 = isl_basic_map_cow(bmap1); + if (!bmap1 || !bmap2) + return isl_basic_map_free(bmap1); + + i1 = bmap1->n_ineq - 1; + i2 = bmap2->n_ineq - 1; + while (bmap1 && i1 >= 0 && i2 >= 0) { + int cmp; + + cmp = isl_basic_map_constraint_cmp(bmap1, bmap1->ineq[i1], + bmap2->ineq[i2]); + if (cmp < 0) { + --i2; + continue; + } + if (cmp > 0) { + if (isl_basic_map_drop_inequality(bmap1, i1) < 0) + bmap1 = isl_basic_map_free(bmap1); + --i1; + continue; + } + if (isl_int_lt(bmap1->ineq[i1][0], bmap2->ineq[i2][0])) + isl_int_set(bmap1->ineq[i1][0], bmap2->ineq[i2][0]); + --i1; + --i2; + } + for (; i1 >= 0; --i1) + if (isl_basic_map_drop_inequality(bmap1, i1) < 0) + bmap1 = isl_basic_map_free(bmap1); + + return bmap1; +} + +/* Drop all equalities from "bmap1" that do not also appear in "bmap2". + * "bmap1" and "bmap2" are assumed to have the same (known) + * integer divisions. + * + * Run through the equality constraints of "bmap1" and "bmap2". + * Each constraint of "bmap1" without a matching constraint in "bmap2" + * is removed. + */ +static __isl_give isl_basic_map *select_shared_equalities( + __isl_take isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2) +{ + int i1, i2; + unsigned total; + + bmap1 = isl_basic_map_cow(bmap1); + if (!bmap1 || !bmap2) + return isl_basic_map_free(bmap1); + + total = isl_basic_map_total_dim(bmap1); + + i1 = bmap1->n_eq - 1; + i2 = bmap2->n_eq - 1; + while (bmap1 && i1 >= 0 && i2 >= 0) { + int last1, last2; + + last1 = isl_seq_last_non_zero(bmap1->eq[i1] + 1, total); + last2 = isl_seq_last_non_zero(bmap2->eq[i2] + 1, total); + if (last1 > last2) { + --i2; + continue; + } + if (last1 < last2) { + if (isl_basic_map_drop_equality(bmap1, i1) < 0) + bmap1 = isl_basic_map_free(bmap1); + --i1; + continue; + } + if (!isl_seq_eq(bmap1->eq[i1], bmap2->eq[i2], 1 + total)) { + if (isl_basic_map_drop_equality(bmap1, i1) < 0) + bmap1 = isl_basic_map_free(bmap1); + } + --i1; + --i2; + } + for (; i1 >= 0; --i1) + if (isl_basic_map_drop_equality(bmap1, i1) < 0) + bmap1 = isl_basic_map_free(bmap1); + + return bmap1; +} + +/* Compute a superset of "bmap1" and "bmap2" that is described + * by only the constraints that appear in both "bmap1" and "bmap2". + * + * First drop constraints that involve unknown integer divisions + * since it is not trivial to check whether two such integer divisions + * in different basic maps are the same. + * Then align the remaining (known) divs and sort the constraints. + * Finally drop all inequalities and equalities from "bmap1" that + * do not also appear in "bmap2". + */ +__isl_give isl_basic_map *isl_basic_map_plain_unshifted_simple_hull( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) +{ + bmap1 = isl_basic_map_drop_constraint_involving_unknown_divs(bmap1); + bmap2 = isl_basic_map_drop_constraint_involving_unknown_divs(bmap2); + bmap2 = isl_basic_map_align_divs(bmap2, bmap1); + bmap1 = isl_basic_map_align_divs(bmap1, bmap2); + bmap1 = isl_basic_map_gauss(bmap1, NULL); + bmap2 = isl_basic_map_gauss(bmap2, NULL); + bmap1 = isl_basic_map_sort_constraints(bmap1); + bmap2 = isl_basic_map_sort_constraints(bmap2); + + bmap1 = select_shared_inequalities(bmap1, bmap2); + bmap1 = select_shared_equalities(bmap1, bmap2); + + isl_basic_map_free(bmap2); + bmap1 = isl_basic_map_finalize(bmap1); + return bmap1; +} + +/* Compute a superset of the convex hull of "map" that is described + * by only the constraints in the constituents of "map". + * In particular, the result is composed of constraints that appear + * in each of the basic maps of "map" + * + * Constraints that involve unknown integer divisions are dropped + * since it is not trivial to check whether two such integer divisions + * in different basic maps are the same. + * + * The hull is initialized from the first basic map and then + * updated with respect to the other basic maps in turn. + */ +__isl_give isl_basic_map *isl_map_plain_unshifted_simple_hull( + __isl_take isl_map *map) +{ + int i; + isl_basic_map *hull; + + if (!map) + return NULL; + if (map->n <= 1) + return map_simple_hull_trivial(map); + map = isl_map_drop_constraint_involving_unknown_divs(map); + hull = isl_basic_map_copy(map->p[0]); + for (i = 1; i < map->n; ++i) { + isl_basic_map *bmap_i; + + bmap_i = isl_basic_map_copy(map->p[i]); + hull = isl_basic_map_plain_unshifted_simple_hull(hull, bmap_i); + } + + isl_map_free(map); + return hull; +} + +/* Compute a superset of the convex hull of "set" that is described + * by only the constraints in the constituents of "set". + * In particular, the result is composed of constraints that appear + * in each of the basic sets of "set" + */ +__isl_give isl_basic_set *isl_set_plain_unshifted_simple_hull( + __isl_take isl_set *set) +{ + return isl_map_plain_unshifted_simple_hull(set); +} + +/* Check if "ineq" is a bound on "set" and, if so, add it to "hull". + * + * For each basic set in "set", we first check if the basic set + * contains a translate of "ineq". If this translate is more relaxed, + * then we assume that "ineq" is not a bound on this basic set. + * Otherwise, we know that it is a bound. + * If the basic set does not contain a translate of "ineq", then + * we call is_bound to perform the test. + */ +static __isl_give isl_basic_set *add_bound_from_constraint( + __isl_take isl_basic_set *hull, struct sh_data *data, + __isl_keep isl_set *set, isl_int *ineq) +{ + int i, k; + isl_ctx *ctx; + uint32_t c_hash; + struct ineq_cmp_data v; + + if (!hull || !set) + return isl_basic_set_free(hull); + + v.len = isl_basic_set_total_dim(hull); + v.p = ineq; + c_hash = isl_seq_get_hash(ineq + 1, v.len); + + ctx = isl_basic_set_get_ctx(hull); + for (i = 0; i < set->n; ++i) { + int bound; + struct isl_hash_table_entry *entry; + + entry = isl_hash_table_find(ctx, data->p[i].table, + c_hash, &has_ineq, &v, 0); + if (entry) { + isl_int *ineq_i = entry->data; + int neg, more_relaxed; + + neg = isl_seq_is_neg(ineq_i + 1, ineq + 1, v.len); + if (neg) + isl_int_neg(ineq_i[0], ineq_i[0]); + more_relaxed = isl_int_gt(ineq_i[0], ineq[0]); + if (neg) + isl_int_neg(ineq_i[0], ineq_i[0]); + if (more_relaxed) + break; + else + continue; + } + bound = is_bound(data, set, i, ineq, 0); + if (bound < 0) + return isl_basic_set_free(hull); + if (!bound) + break; + } + if (i < set->n) + return hull; + + k = isl_basic_set_alloc_inequality(hull); + if (k < 0) + return isl_basic_set_free(hull); + isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len); + + return hull; +} + +/* Compute a superset of the convex hull of "set" that is described + * by only some of the "n_ineq" constraints in the list "ineq", where "set" + * has no parameters or integer divisions. + * + * The inequalities in "ineq" are assumed to have been sorted such + * that constraints with the same linear part appear together and + * that among constraints with the same linear part, those with + * smaller constant term appear first. + * + * We reuse the same data structure that is used by uset_simple_hull, + * but we do not need the hull table since we will not consider the + * same constraint more than once. We therefore allocate it with zero size. + * + * We run through the constraints and try to add them one by one, + * skipping identical constraints. If we have added a constraint and + * the next constraint is a more relaxed translate, then we skip this + * next constraint as well. + */ +static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_constraints( + __isl_take isl_set *set, int n_ineq, isl_int **ineq) +{ + int i; + int last_added = 0; + struct sh_data *data = NULL; + isl_basic_set *hull = NULL; + unsigned dim; + + hull = isl_basic_set_alloc_space(isl_set_get_space(set), 0, 0, n_ineq); + if (!hull) + goto error; + + data = sh_data_alloc(set, 0); + if (!data) + goto error; + + dim = isl_set_dim(set, isl_dim_set); + for (i = 0; i < n_ineq; ++i) { + int hull_n_ineq = hull->n_ineq; + int parallel; + + parallel = i > 0 && isl_seq_eq(ineq[i - 1] + 1, ineq[i] + 1, + dim); + if (parallel && + (last_added || isl_int_eq(ineq[i - 1][0], ineq[i][0]))) + continue; + hull = add_bound_from_constraint(hull, data, set, ineq[i]); + if (!hull) + goto error; + last_added = hull->n_ineq > hull_n_ineq; + } + + sh_data_free(data); + isl_set_free(set); + return hull; +error: + sh_data_free(data); + isl_set_free(set); + isl_basic_set_free(hull); + return NULL; +} + +/* Collect pointers to all the inequalities in the elements of "list" + * in "ineq". For equalities, store both a pointer to the equality and + * a pointer to its opposite, which is first copied to "mat". + * "ineq" and "mat" are assumed to have been preallocated to the right size + * (the number of inequalities + 2 times the number of equalites and + * the number of equalities, respectively). + */ +static __isl_give isl_mat *collect_inequalities(__isl_take isl_mat *mat, + __isl_keep isl_basic_set_list *list, isl_int **ineq) +{ + int i, j, n, n_eq, n_ineq; + + if (!mat) + return NULL; + + n_eq = 0; + n_ineq = 0; + n = isl_basic_set_list_n_basic_set(list); + for (i = 0; i < n; ++i) { + isl_basic_set *bset; + bset = isl_basic_set_list_get_basic_set(list, i); + if (!bset) + return isl_mat_free(mat); + for (j = 0; j < bset->n_eq; ++j) { + ineq[n_ineq++] = mat->row[n_eq]; + ineq[n_ineq++] = bset->eq[j]; + isl_seq_neg(mat->row[n_eq++], bset->eq[j], mat->n_col); + } + for (j = 0; j < bset->n_ineq; ++j) + ineq[n_ineq++] = bset->ineq[j]; + isl_basic_set_free(bset); + } + + return mat; +} + +/* Comparison routine for use as an isl_sort callback. + * + * Constraints with the same linear part are sorted together and + * among constraints with the same linear part, those with smaller + * constant term are sorted first. + */ +static int cmp_ineq(const void *a, const void *b, void *arg) +{ + unsigned dim = *(unsigned *) arg; + isl_int * const *ineq1 = a; + isl_int * const *ineq2 = b; + int cmp; + + cmp = isl_seq_cmp((*ineq1) + 1, (*ineq2) + 1, dim); + if (cmp != 0) + return cmp; + return isl_int_cmp((*ineq1)[0], (*ineq2)[0]); +} + +/* Compute a superset of the convex hull of "set" that is described + * by only constraints in the elements of "list", where "set" has + * no parameters or integer divisions. + * + * We collect all the constraints in those elements and then + * sort the constraints such that constraints with the same linear part + * are sorted together and that those with smaller constant term are + * sorted first. + */ +static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_basic_set_list( + __isl_take isl_set *set, __isl_take isl_basic_set_list *list) +{ + int i, n, n_eq, n_ineq; + unsigned dim; + isl_ctx *ctx; + isl_mat *mat = NULL; + isl_int **ineq = NULL; + isl_basic_set *hull; + + if (!set) + goto error; + ctx = isl_set_get_ctx(set); + + n_eq = 0; + n_ineq = 0; + n = isl_basic_set_list_n_basic_set(list); + for (i = 0; i < n; ++i) { + isl_basic_set *bset; + bset = isl_basic_set_list_get_basic_set(list, i); + if (!bset) + goto error; + n_eq += bset->n_eq; + n_ineq += 2 * bset->n_eq + bset->n_ineq; + isl_basic_set_free(bset); + } + + ineq = isl_alloc_array(ctx, isl_int *, n_ineq); + if (n_ineq > 0 && !ineq) + goto error; + + dim = isl_set_dim(set, isl_dim_set); + mat = isl_mat_alloc(ctx, n_eq, 1 + dim); + mat = collect_inequalities(mat, list, ineq); + if (!mat) + goto error; + + if (isl_sort(ineq, n_ineq, sizeof(ineq[0]), &cmp_ineq, &dim) < 0) + goto error; + + hull = uset_unshifted_simple_hull_from_constraints(set, n_ineq, ineq); + + isl_mat_free(mat); + free(ineq); + isl_basic_set_list_free(list); + return hull; +error: + isl_mat_free(mat); + free(ineq); + isl_set_free(set); + isl_basic_set_list_free(list); + return NULL; +} + +/* Compute a superset of the convex hull of "map" that is described + * by only constraints in the elements of "list". + * + * If the list is empty, then we can only describe the universe set. + * If the input map is empty, then all constraints are valid, so + * we return the intersection of the elements in "list". + * + * Otherwise, we align all divs and temporarily treat them + * as regular variables, computing the unshifted simple hull in + * uset_unshifted_simple_hull_from_basic_set_list. + */ +static __isl_give isl_basic_map *map_unshifted_simple_hull_from_basic_map_list( + __isl_take isl_map *map, __isl_take isl_basic_map_list *list) +{ + isl_basic_map *model; + isl_basic_map *hull; + isl_set *set; + isl_basic_set_list *bset_list; + + if (!map || !list) + goto error; + + if (isl_basic_map_list_n_basic_map(list) == 0) { + isl_space *space; + + space = isl_map_get_space(map); + isl_map_free(map); + isl_basic_map_list_free(list); + return isl_basic_map_universe(space); + } + if (isl_map_plain_is_empty(map)) { + isl_map_free(map); + return isl_basic_map_list_intersect(list); + } + + map = isl_map_align_divs_to_basic_map_list(map, list); + if (!map) + goto error; + list = isl_basic_map_list_align_divs_to_basic_map(list, map->p[0]); + + model = isl_basic_map_list_get_basic_map(list, 0); + + set = isl_map_underlying_set(map); + bset_list = isl_basic_map_list_underlying_set(list); + + hull = uset_unshifted_simple_hull_from_basic_set_list(set, bset_list); + hull = isl_basic_map_overlying_set(hull, model); + + return hull; +error: + isl_map_free(map); + isl_basic_map_list_free(list); + return NULL; +} + +/* Return a sequence of the basic maps that make up the maps in "list". + */ +static __isl_give isl_basic_map_list *collect_basic_maps( + __isl_take isl_map_list *list) +{ + int i, n; + isl_ctx *ctx; + isl_basic_map_list *bmap_list; + + if (!list) + return NULL; + n = isl_map_list_n_map(list); + ctx = isl_map_list_get_ctx(list); + bmap_list = isl_basic_map_list_alloc(ctx, 0); + + for (i = 0; i < n; ++i) { + isl_map *map; + isl_basic_map_list *list_i; + + map = isl_map_list_get_map(list, i); + map = isl_map_compute_divs(map); + list_i = isl_map_get_basic_map_list(map); + isl_map_free(map); + bmap_list = isl_basic_map_list_concat(bmap_list, list_i); + } + + isl_map_list_free(list); + return bmap_list; +} + +/* Compute a superset of the convex hull of "map" that is described + * by only constraints in the elements of "list". + * + * If "map" is the universe, then the convex hull (and therefore + * any superset of the convexhull) is the universe as well. + * + * Otherwise, we collect all the basic maps in the map list and + * continue with map_unshifted_simple_hull_from_basic_map_list. + */ +__isl_give isl_basic_map *isl_map_unshifted_simple_hull_from_map_list( + __isl_take isl_map *map, __isl_take isl_map_list *list) +{ + isl_basic_map_list *bmap_list; + int is_universe; + + is_universe = isl_map_plain_is_universe(map); + if (is_universe < 0) + map = isl_map_free(map); + if (is_universe < 0 || is_universe) { + isl_map_list_free(list); + return isl_map_unshifted_simple_hull(map); + } + + bmap_list = collect_basic_maps(list); + return map_unshifted_simple_hull_from_basic_map_list(map, bmap_list); +} + +/* Compute a superset of the convex hull of "set" that is described + * by only constraints in the elements of "list". + */ +__isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list( + __isl_take isl_set *set, __isl_take isl_set_list *list) +{ + return isl_map_unshifted_simple_hull_from_map_list(set, list); +} + +/* Given a set "set", return parametric bounds on the dimension "dim". + */ +static struct isl_basic_set *set_bounds(struct isl_set *set, int dim) +{ + unsigned set_dim = isl_set_dim(set, isl_dim_set); + set = isl_set_copy(set); + set = isl_set_eliminate_dims(set, dim + 1, set_dim - (dim + 1)); + set = isl_set_eliminate_dims(set, 0, dim); + return isl_set_convex_hull(set); +} + +/* Computes a "simple hull" and then check if each dimension in the + * resulting hull is bounded by a symbolic constant. If not, the + * hull is intersected with the corresponding bounds on the whole set. + */ +__isl_give isl_basic_set *isl_set_bounded_simple_hull(__isl_take isl_set *set) +{ + int i, j; + struct isl_basic_set *hull; + unsigned nparam, left; + int removed_divs = 0; + + hull = isl_set_simple_hull(isl_set_copy(set)); + if (!hull) + goto error; + + nparam = isl_basic_set_dim(hull, isl_dim_param); + for (i = 0; i < isl_basic_set_dim(hull, isl_dim_set); ++i) { + int lower = 0, upper = 0; + struct isl_basic_set *bounds; + + left = isl_basic_set_total_dim(hull) - nparam - i - 1; + for (j = 0; j < hull->n_eq; ++j) { + if (isl_int_is_zero(hull->eq[j][1 + nparam + i])) + continue; + if (isl_seq_first_non_zero(hull->eq[j]+1+nparam+i+1, + left) == -1) + break; + } + if (j < hull->n_eq) + continue; + + for (j = 0; j < hull->n_ineq; ++j) { + if (isl_int_is_zero(hull->ineq[j][1 + nparam + i])) + continue; + if (isl_seq_first_non_zero(hull->ineq[j]+1+nparam+i+1, + left) != -1 || + isl_seq_first_non_zero(hull->ineq[j]+1+nparam, + i) != -1) + continue; + if (isl_int_is_pos(hull->ineq[j][1 + nparam + i])) + lower = 1; + else + upper = 1; + if (lower && upper) + break; + } + + if (lower && upper) + continue; + + if (!removed_divs) { + set = isl_set_remove_divs(set); + if (!set) + goto error; + removed_divs = 1; + } + bounds = set_bounds(set, i); + hull = isl_basic_set_intersect(hull, bounds); + if (!hull) + goto error; + } + + isl_set_free(set); + return hull; +error: + isl_set_free(set); + isl_basic_set_free(hull); + return NULL; +} Index: contrib/isl/isl_ctx.c =================================================================== --- /dev/null +++ contrib/isl/isl_ctx.c @@ -0,0 +1,342 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include + +#define __isl_calloc(type,size) ((type *)calloc(1, size)) +#define __isl_calloc_type(type) __isl_calloc(type,sizeof(type)) + +/* Return the negation of "b", where the negation of isl_bool_error + * is isl_bool_error again. + */ +isl_bool isl_bool_not(isl_bool b) +{ + return b < 0 ? isl_bool_error : !b; +} + +/* Check that the result of an allocation ("p") is not NULL and + * complain if it is. + * The only exception is when allocation size ("size") is equal to zero. + */ +static void *check_non_null(isl_ctx *ctx, void *p, size_t size) +{ + if (p || size == 0) + return p; + isl_die(ctx, isl_error_alloc, "allocation failure", return NULL); +} + +/* Prepare for performing the next "operation" in the context. + * Return 0 if we are allowed to perform this operation and + * return -1 if we should abort the computation. + * + * In particular, we should stop if the user has explicitly aborted + * the computation or if the maximal number of operations has been exceeded. + */ +int isl_ctx_next_operation(isl_ctx *ctx) +{ + if (!ctx) + return -1; + if (ctx->abort) { + isl_ctx_set_error(ctx, isl_error_abort); + return -1; + } + if (ctx->max_operations && ctx->operations >= ctx->max_operations) + isl_die(ctx, isl_error_quota, + "maximal number of operations exceeded", return -1); + ctx->operations++; + return 0; +} + +/* Call malloc and complain if it fails. + * If ctx is NULL, then return NULL. + */ +void *isl_malloc_or_die(isl_ctx *ctx, size_t size) +{ + if (isl_ctx_next_operation(ctx) < 0) + return NULL; + return ctx ? check_non_null(ctx, malloc(size), size) : NULL; +} + +/* Call calloc and complain if it fails. + * If ctx is NULL, then return NULL. + */ +void *isl_calloc_or_die(isl_ctx *ctx, size_t nmemb, size_t size) +{ + if (isl_ctx_next_operation(ctx) < 0) + return NULL; + return ctx ? check_non_null(ctx, calloc(nmemb, size), nmemb) : NULL; +} + +/* Call realloc and complain if it fails. + * If ctx is NULL, then return NULL. + */ +void *isl_realloc_or_die(isl_ctx *ctx, void *ptr, size_t size) +{ + if (isl_ctx_next_operation(ctx) < 0) + return NULL; + return ctx ? check_non_null(ctx, realloc(ptr, size), size) : NULL; +} + +void isl_handle_error(isl_ctx *ctx, enum isl_error error, const char *msg, + const char *file, int line) +{ + if (!ctx) + return; + + isl_ctx_set_error(ctx, error); + + switch (ctx->opt->on_error) { + case ISL_ON_ERROR_WARN: + fprintf(stderr, "%s:%d: %s\n", file, line, msg); + return; + case ISL_ON_ERROR_CONTINUE: + return; + case ISL_ON_ERROR_ABORT: + fprintf(stderr, "%s:%d: %s\n", file, line, msg); + abort(); + return; + } +} + +static struct isl_options *find_nested_options(struct isl_args *args, + void *opt, struct isl_args *wanted) +{ + int i; + struct isl_options *options; + + if (args == wanted) + return opt; + + for (i = 0; args->args[i].type != isl_arg_end; ++i) { + struct isl_arg *arg = &args->args[i]; + void *child; + + if (arg->type != isl_arg_child) + continue; + + if (arg->offset == (size_t) -1) + child = opt; + else + child = *(void **)(((char *)opt) + arg->offset); + + options = find_nested_options(arg->u.child.child, + child, wanted); + if (options) + return options; + } + + return NULL; +} + +static struct isl_options *find_nested_isl_options(struct isl_args *args, + void *opt) +{ + return find_nested_options(args, opt, &isl_options_args); +} + +void *isl_ctx_peek_options(isl_ctx *ctx, struct isl_args *args) +{ + if (!ctx) + return NULL; + if (args == &isl_options_args) + return ctx->opt; + return find_nested_options(ctx->user_args, ctx->user_opt, args); +} + +isl_ctx *isl_ctx_alloc_with_options(struct isl_args *args, void *user_opt) +{ + struct isl_ctx *ctx = NULL; + struct isl_options *opt = NULL; + int opt_allocated = 0; + + if (!user_opt) + return NULL; + + opt = find_nested_isl_options(args, user_opt); + if (!opt) { + opt = isl_options_new_with_defaults(); + if (!opt) + goto error; + opt_allocated = 1; + } + + ctx = __isl_calloc_type(struct isl_ctx); + if (!ctx) + goto error; + + if (isl_hash_table_init(ctx, &ctx->id_table, 0)) + goto error; + + ctx->stats = isl_calloc_type(ctx, struct isl_stats); + if (!ctx->stats) + goto error; + + ctx->user_args = args; + ctx->user_opt = user_opt; + ctx->opt_allocated = opt_allocated; + ctx->opt = opt; + ctx->ref = 0; + + isl_int_init(ctx->zero); + isl_int_set_si(ctx->zero, 0); + + isl_int_init(ctx->one); + isl_int_set_si(ctx->one, 1); + + isl_int_init(ctx->two); + isl_int_set_si(ctx->two, 2); + + isl_int_init(ctx->negone); + isl_int_set_si(ctx->negone, -1); + + isl_int_init(ctx->normalize_gcd); + + ctx->n_cached = 0; + ctx->n_miss = 0; + + ctx->error = isl_error_none; + + ctx->operations = 0; + isl_ctx_set_max_operations(ctx, ctx->opt->max_operations); + + return ctx; +error: + isl_args_free(args, user_opt); + if (opt_allocated) + isl_options_free(opt); + free(ctx); + return NULL; +} + +struct isl_ctx *isl_ctx_alloc() +{ + struct isl_options *opt; + + opt = isl_options_new_with_defaults(); + + return isl_ctx_alloc_with_options(&isl_options_args, opt); +} + +void isl_ctx_ref(struct isl_ctx *ctx) +{ + ctx->ref++; +} + +void isl_ctx_deref(struct isl_ctx *ctx) +{ + isl_assert(ctx, ctx->ref > 0, return); + ctx->ref--; +} + +/* Print statistics on usage. + */ +static void print_stats(isl_ctx *ctx) +{ + fprintf(stderr, "operations: %lu\n", ctx->operations); +} + +void isl_ctx_free(struct isl_ctx *ctx) +{ + if (!ctx) + return; + if (ctx->ref != 0) + isl_die(ctx, isl_error_invalid, + "isl_ctx freed, but some objects still reference it", + return); + + if (ctx->opt->print_stats) + print_stats(ctx); + + isl_hash_table_clear(&ctx->id_table); + isl_blk_clear_cache(ctx); + isl_int_clear(ctx->zero); + isl_int_clear(ctx->one); + isl_int_clear(ctx->two); + isl_int_clear(ctx->negone); + isl_int_clear(ctx->normalize_gcd); + isl_args_free(ctx->user_args, ctx->user_opt); + if (ctx->opt_allocated) + isl_options_free(ctx->opt); + free(ctx->stats); + free(ctx); +} + +struct isl_options *isl_ctx_options(isl_ctx *ctx) +{ + if (!ctx) + return NULL; + return ctx->opt; +} + +enum isl_error isl_ctx_last_error(isl_ctx *ctx) +{ + return ctx->error; +} + +void isl_ctx_reset_error(isl_ctx *ctx) +{ + ctx->error = isl_error_none; +} + +void isl_ctx_set_error(isl_ctx *ctx, enum isl_error error) +{ + if (ctx) + ctx->error = error; +} + +void isl_ctx_abort(isl_ctx *ctx) +{ + if (ctx) + ctx->abort = 1; +} + +void isl_ctx_resume(isl_ctx *ctx) +{ + if (ctx) + ctx->abort = 0; +} + +int isl_ctx_aborted(isl_ctx *ctx) +{ + return ctx ? ctx->abort : -1; +} + +int isl_ctx_parse_options(isl_ctx *ctx, int argc, char **argv, unsigned flags) +{ + if (!ctx) + return -1; + return isl_args_parse(ctx->user_args, argc, argv, ctx->user_opt, flags); +} + +/* Set the maximal number of iterations of "ctx" to "max_operations". + */ +void isl_ctx_set_max_operations(isl_ctx *ctx, unsigned long max_operations) +{ + if (!ctx) + return; + ctx->max_operations = max_operations; +} + +/* Return the maximal number of iterations of "ctx". + */ +unsigned long isl_ctx_get_max_operations(isl_ctx *ctx) +{ + return ctx ? ctx->max_operations : 0; +} + +/* Reset the number of operations performed by "ctx". + */ +void isl_ctx_reset_operations(isl_ctx *ctx) +{ + if (!ctx) + return; + ctx->operations = 0; +} Index: contrib/isl/isl_ctx_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_ctx_private.h @@ -0,0 +1,34 @@ +#include +#include + +struct isl_ctx { + int ref; + + struct isl_stats *stats; + + int opt_allocated; + struct isl_options *opt; + void *user_opt; + struct isl_args *user_args; + + isl_int zero; + isl_int one; + isl_int two; + isl_int negone; + + isl_int normalize_gcd; + + int n_cached; + int n_miss; + struct isl_blk cache[ISL_BLK_CACHE_SIZE]; + struct isl_hash_table id_table; + + enum isl_error error; + + int abort; + + unsigned long operations; + unsigned long max_operations; +}; + +int isl_ctx_next_operation(isl_ctx *ctx); Index: contrib/isl/isl_deprecated.c =================================================================== --- /dev/null +++ contrib/isl/isl_deprecated.c @@ -0,0 +1,25 @@ +#include +#include + +/* This function was never documented and has been replaced by + * isl_basic_set_add_dims. + */ +__isl_give isl_basic_set *isl_basic_set_add(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned n) +{ + return isl_basic_set_add_dims(bset, type, n); +} + +/* This function was replaced by isl_constraint_alloc_equality. + */ +__isl_give isl_constraint *isl_equality_alloc(__isl_take isl_local_space *ls) +{ + return isl_constraint_alloc_equality(ls); +} + +/* This function was replaced by isl_constraint_alloc_inequality. + */ +__isl_give isl_constraint *isl_inequality_alloc(__isl_take isl_local_space *ls) +{ + return isl_constraint_alloc_inequality(ls); +} Index: contrib/isl/isl_dim_map.h =================================================================== --- /dev/null +++ contrib/isl/isl_dim_map.h @@ -0,0 +1,36 @@ +#ifndef ISL_DIM_MAP_H +#define ISL_DIM_MAP_H + +#include +#include +#include +#include + +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, int dst_stride, unsigned src_pos, int src_stride, + unsigned n, int sign); +void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map, + isl_space *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_space *dim, + enum isl_dim_type type, unsigned dst_pos); +void isl_dim_map_div(__isl_keep isl_dim_map *dim_map, + __isl_keep isl_basic_map *bmap, unsigned dst_pos); +__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map( + __isl_take isl_basic_set *dst, __isl_take isl_basic_set *src, + __isl_take isl_dim_map *dim_map); +__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map( + __isl_take isl_basic_map *dst, __isl_take isl_basic_map *src, + __isl_take isl_dim_map *dim_map); + +__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map, + __isl_keep isl_basic_map *bmap); + +__isl_give isl_dim_map *isl_dim_map_from_reordering( + __isl_keep isl_reordering *exp); + +#endif Index: contrib/isl/isl_dim_map.c =================================================================== --- /dev/null +++ contrib/isl/isl_dim_map.c @@ -0,0 +1,235 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010-2011 INRIA Saclay + * + * Use of this software is governed by the MIT 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 +#include +#include +#include + +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, int dst_stride, unsigned src_pos, int 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, + __isl_keep isl_space *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_space_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_space *dim, + enum isl_dim_type type, unsigned dst_pos) +{ + isl_dim_map_dim_range(dim_map, dim, type, + 0, isl_space_dim(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_space_dim(bmap->dim, isl_dim_all); + 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; + + if (!dim_map) + return NULL; + + 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_space_get_ctx(exp->dim); + dim_map = isl_dim_map_alloc(ctx, isl_space_dim(exp->dim, isl_dim_all)); + 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; +} Index: contrib/isl/isl_equalities.h =================================================================== --- /dev/null +++ contrib/isl/isl_equalities.h @@ -0,0 +1,35 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_EQUALITIES_H +#define ISL_EQUALITIES_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_mat *isl_mat_final_variable_compression(__isl_take isl_mat *B, + int first, __isl_give isl_mat **T2); +__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B, + __isl_give isl_mat **T2); +__isl_give isl_mat *isl_mat_parameter_compression(__isl_take isl_mat *B, + __isl_take isl_vec *d); +__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B, + __isl_take isl_mat *A); +struct isl_basic_set *isl_basic_set_remove_equalities( + struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/isl_equalities.c =================================================================== --- /dev/null +++ contrib/isl/isl_equalities.c @@ -0,0 +1,896 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT 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 +#include +#include +#include "isl_map_private.h" +#include "isl_equalities.h" +#include + +/* Given a set of modulo constraints + * + * c + A y = 0 mod d + * + * this function computes a particular solution y_0 + * + * The input is given as a matrix B = [ c A ] and a vector d. + * + * The output is matrix containing the solution y_0 or + * a zero-column matrix if the constraints admit no integer solution. + * + * The given set of constrains is equivalent to + * + * c + A y = -D x + * + * with D = diag d and x a fresh set of variables. + * Reducing both c and A modulo d does not change the + * value of y in the solution and may lead to smaller coefficients. + * Let M = [ D A ] and [ H 0 ] = M U, the Hermite normal form of M. + * Then + * [ x ] + * M [ y ] = - c + * and so + * [ x ] + * [ H 0 ] U^{-1} [ y ] = - c + * Let + * [ A ] [ x ] + * [ B ] = U^{-1} [ y ] + * then + * H A + 0 B = -c + * + * so B may be chosen arbitrarily, e.g., B = 0, and then + * + * [ x ] = [ -c ] + * U^{-1} [ y ] = [ 0 ] + * or + * [ x ] [ -c ] + * [ y ] = U [ 0 ] + * specifically, + * + * y = U_{2,1} (-c) + * + * If any of the coordinates of this y are non-integer + * then the constraints admit no integer solution and + * a zero-column matrix is returned. + */ +static struct isl_mat *particular_solution(struct isl_mat *B, struct isl_vec *d) +{ + int i, j; + struct isl_mat *M = NULL; + struct isl_mat *C = NULL; + struct isl_mat *U = NULL; + struct isl_mat *H = NULL; + struct isl_mat *cst = NULL; + struct isl_mat *T = NULL; + + M = isl_mat_alloc(B->ctx, B->n_row, B->n_row + B->n_col - 1); + C = isl_mat_alloc(B->ctx, 1 + B->n_row, 1); + if (!M || !C) + goto error; + isl_int_set_si(C->row[0][0], 1); + for (i = 0; i < B->n_row; ++i) { + isl_seq_clr(M->row[i], B->n_row); + isl_int_set(M->row[i][i], d->block.data[i]); + isl_int_neg(C->row[1 + i][0], B->row[i][0]); + isl_int_fdiv_r(C->row[1+i][0], C->row[1+i][0], M->row[i][i]); + for (j = 0; j < B->n_col - 1; ++j) + isl_int_fdiv_r(M->row[i][B->n_row + j], + B->row[i][1 + j], M->row[i][i]); + } + M = isl_mat_left_hermite(M, 0, &U, NULL); + if (!M || !U) + goto error; + 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) + goto error; + for (i = 0; i < B->n_row; ++i) { + if (!isl_int_is_divisible_by(C->row[1+i][0], C->row[0][0])) + break; + isl_int_divexact(C->row[1+i][0], C->row[1+i][0], C->row[0][0]); + } + if (i < B->n_row) + cst = isl_mat_alloc(B->ctx, B->n_row, 0); + else + 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); + isl_mat_free(U); + return cst; +error: + isl_mat_free(M); + isl_mat_free(C); + isl_mat_free(U); + return NULL; +} + +/* Compute and return the matrix + * + * U_1^{-1} diag(d_1, 1, ..., 1) + * + * with U_1 the unimodular completion of the first (and only) row of B. + * The columns of this matrix generate the lattice that satisfies + * the single (linear) modulo constraint. + */ +static struct isl_mat *parameter_compression_1( + struct isl_mat *B, struct isl_vec *d) +{ + struct isl_mat *U; + + U = isl_mat_alloc(B->ctx, B->n_col - 1, B->n_col - 1); + if (!U) + return NULL; + isl_seq_cpy(U->row[0], B->row[0] + 1, B->n_col - 1); + U = isl_mat_unimodular_complete(U, 1); + U = isl_mat_right_inverse(U); + if (!U) + return NULL; + isl_mat_col_mul(U, 0, d->block.data[0], 0); + U = isl_mat_lin_to_aff(U); + return U; +} + +/* Compute a common lattice of solutions to the linear modulo + * constraints specified by B and d. + * See also the documentation of isl_mat_parameter_compression. + * We put the matrix + * + * A = [ L_1^{-T} L_2^{-T} ... L_k^{-T} ] + * + * on a common denominator. This denominator D is the lcm of modulos d. + * Since L_i = U_i^{-1} diag(d_i, 1, ... 1), we have + * L_i^{-T} = U_i^T diag(d_i, 1, ... 1)^{-T} = U_i^T diag(1/d_i, 1, ..., 1). + * Putting this on the common denominator, we have + * D * L_i^{-T} = U_i^T diag(D/d_i, D, ..., D). + */ +static struct isl_mat *parameter_compression_multi( + struct isl_mat *B, struct isl_vec *d) +{ + int i, j, k; + isl_int D; + struct isl_mat *A = NULL, *U = NULL; + struct isl_mat *T; + unsigned size; + + isl_int_init(D); + + isl_vec_lcm(d, &D); + + size = B->n_col - 1; + A = isl_mat_alloc(B->ctx, size, B->n_row * size); + U = isl_mat_alloc(B->ctx, size, size); + if (!U || !A) + goto error; + for (i = 0; i < B->n_row; ++i) { + isl_seq_cpy(U->row[0], B->row[i] + 1, size); + U = isl_mat_unimodular_complete(U, 1); + if (!U) + goto error; + isl_int_divexact(D, D, d->block.data[i]); + for (k = 0; k < U->n_col; ++k) + isl_int_mul(A->row[k][i*size+0], D, U->row[0][k]); + isl_int_mul(D, D, d->block.data[i]); + for (j = 1; j < U->n_row; ++j) + for (k = 0; k < U->n_col; ++k) + isl_int_mul(A->row[k][i*size+j], + D, U->row[j][k]); + } + A = isl_mat_left_hermite(A, 0, NULL, NULL); + 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; + isl_int_set(T->row[0][0], D); + T = isl_mat_right_inverse(T); + if (!T) + goto error; + isl_assert(T->ctx, isl_int_is_one(T->row[0][0]), goto error); + T = isl_mat_transpose(T); + isl_mat_free(A); + isl_mat_free(U); + + isl_int_clear(D); + return T; +error: + isl_mat_free(A); + isl_mat_free(U); + isl_int_clear(D); + return NULL; +} + +/* Given a set of modulo constraints + * + * c + A y = 0 mod d + * + * this function returns an affine transformation T, + * + * y = T y' + * + * that bijectively maps the integer vectors y' to integer + * vectors y that satisfy the modulo constraints. + * + * This function is inspired by Section 2.5.3 + * of B. Meister, "Stating and Manipulating Periodicity in the Polytope + * Model. Applications to Program Analysis and Optimization". + * However, the implementation only follows the algorithm of that + * section for computing a particular solution and not for computing + * a general homogeneous solution. The latter is incomplete and + * may remove some valid solutions. + * Instead, we use an adaptation of the algorithm in Section 7 of + * B. Meister, S. Verdoolaege, "Polynomial Approximations in the Polytope + * Model: Bringing the Power of Quasi-Polynomials to the Masses". + * + * The input is given as a matrix B = [ c A ] and a vector d. + * Each element of the vector d corresponds to a row in B. + * The output is a lower triangular matrix. + * If no integer vector y satisfies the given constraints then + * a matrix with zero columns is returned. + * + * We first compute a particular solution y_0 to the given set of + * modulo constraints in particular_solution. If no such solution + * exists, then we return a zero-columned transformation matrix. + * Otherwise, we compute the generic solution to + * + * A y = 0 mod d + * + * That is we want to compute G such that + * + * y = G y'' + * + * with y'' integer, describes the set of solutions. + * + * We first remove the common factors of each row. + * In particular if gcd(A_i,d_i) != 1, then we divide the whole + * row i (including d_i) by this common factor. If afterwards gcd(A_i) != 1, + * then we divide this row of A by the common factor, unless gcd(A_i) = 0. + * In the later case, we simply drop the row (in both A and d). + * + * If there are no rows left in A, then G is the identity matrix. Otherwise, + * for each row i, we now determine the lattice of integer vectors + * that satisfies this row. Let U_i be the unimodular extension of the + * row A_i. This unimodular extension exists because gcd(A_i) = 1. + * The first component of + * + * y' = U_i y + * + * needs to be a multiple of d_i. Let y' = diag(d_i, 1, ..., 1) y''. + * Then, + * + * y = U_i^{-1} diag(d_i, 1, ..., 1) y'' + * + * for arbitrary integer vectors y''. That is, y belongs to the lattice + * generated by the columns of L_i = U_i^{-1} diag(d_i, 1, ..., 1). + * If there is only one row, then G = L_1. + * + * If there is more than one row left, we need to compute the intersection + * of the lattices. That is, we need to compute an L such that + * + * L = L_i L_i' for all i + * + * with L_i' some integer matrices. Let A be constructed as follows + * + * A = [ L_1^{-T} L_2^{-T} ... L_k^{-T} ] + * + * and computed the Hermite Normal Form of A = [ H 0 ] U + * Then, + * + * L_i^{-T} = H U_{1,i} + * + * or + * + * H^{-T} = L_i U_{1,i}^T + * + * In other words G = L = H^{-T}. + * To ensure that G is lower triangular, we compute and use its Hermite + * normal form. + * + * The affine transformation matrix returned is then + * + * [ 1 0 ] + * [ y_0 G ] + * + * as any y = y_0 + G y' with y' integer is a solution to the original + * modulo constraints. + */ +__isl_give isl_mat *isl_mat_parameter_compression(__isl_take isl_mat *B, + __isl_take isl_vec *d) +{ + int i; + struct isl_mat *cst = NULL; + struct isl_mat *T = NULL; + isl_int D; + + if (!B || !d) + goto error; + isl_assert(B->ctx, B->n_row == d->size, goto error); + cst = particular_solution(B, d); + if (!cst) + goto error; + if (cst->n_col == 0) { + T = isl_mat_alloc(B->ctx, B->n_col, 0); + isl_mat_free(cst); + isl_mat_free(B); + isl_vec_free(d); + return T; + } + isl_int_init(D); + /* Replace a*g*row = 0 mod g*m by row = 0 mod m */ + for (i = 0; i < B->n_row; ++i) { + isl_seq_gcd(B->row[i] + 1, B->n_col - 1, &D); + if (isl_int_is_one(D)) + continue; + if (isl_int_is_zero(D)) { + B = isl_mat_drop_rows(B, i, 1); + d = isl_vec_cow(d); + if (!B || !d) + goto error2; + isl_seq_cpy(d->block.data+i, d->block.data+i+1, + d->size - (i+1)); + d->size--; + i--; + continue; + } + B = isl_mat_cow(B); + if (!B) + goto error2; + isl_seq_scale_down(B->row[i] + 1, B->row[i] + 1, D, B->n_col-1); + isl_int_gcd(D, D, d->block.data[i]); + d = isl_vec_cow(d); + if (!d) + goto error2; + isl_int_divexact(d->block.data[i], d->block.data[i], D); + } + isl_int_clear(D); + if (B->n_row == 0) + T = isl_mat_identity(B->ctx, B->n_col); + else if (B->n_row == 1) + T = parameter_compression_1(B, d); + else + T = parameter_compression_multi(B, d); + T = isl_mat_left_hermite(T, 0, NULL, NULL); + if (!T) + goto error; + isl_mat_sub_copy(T->ctx, T->row + 1, cst->row, cst->n_row, 0, 0, 1); + isl_mat_free(cst); + isl_mat_free(B); + isl_vec_free(d); + return T; +error2: + isl_int_clear(D); +error: + isl_mat_free(cst); + isl_mat_free(B); + isl_vec_free(d); + return NULL; +} + +/* Given a set of equalities + * + * B(y) + A x = 0 (*) + * + * compute and return an affine transformation T, + * + * y = T y' + * + * that bijectively maps the integer vectors y' to integer + * vectors y that satisfy the modulo constraints for some value of x. + * + * Let [H 0] be the Hermite Normal Form of A, i.e., + * + * A = [H 0] Q + * + * Then y is a solution of (*) iff + * + * H^-1 B(y) (= - [I 0] Q x) + * + * is an integer vector. Let d be the common denominator of H^-1. + * We impose + * + * d H^-1 B(y) = 0 mod d + * + * and compute the solution using isl_mat_parameter_compression. + */ +__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B, + __isl_take isl_mat *A) +{ + isl_ctx *ctx; + isl_vec *d; + int n_row, n_col; + + if (!A) + return isl_mat_free(B); + + ctx = isl_mat_get_ctx(A); + n_row = A->n_row; + n_col = A->n_col; + A = isl_mat_left_hermite(A, 0, NULL, NULL); + A = isl_mat_drop_cols(A, n_row, n_col - n_row); + A = isl_mat_lin_to_aff(A); + A = isl_mat_right_inverse(A); + d = isl_vec_alloc(ctx, n_row); + if (A) + d = isl_vec_set(d, A->row[0][0]); + A = isl_mat_drop_rows(A, 0, 1); + A = isl_mat_drop_cols(A, 0, 1); + B = isl_mat_product(A, B); + + return isl_mat_parameter_compression(B, d); +} + +/* Return a compression matrix that indicates that there are no solutions + * to the original constraints. In particular, return a zero-column + * matrix with 1 + dim rows. If "T2" is not NULL, then assign *T2 + * the inverse of this matrix. *T2 may already have been assigned + * matrix, so free it first. + * "free1", "free2" and "free3" are temporary matrices that are + * not useful when an empty compression is returned. They are + * simply freed. + */ +static __isl_give isl_mat *empty_compression(isl_ctx *ctx, unsigned dim, + __isl_give isl_mat **T2, __isl_take isl_mat *free1, + __isl_take isl_mat *free2, __isl_take isl_mat *free3) +{ + isl_mat_free(free1); + isl_mat_free(free2); + isl_mat_free(free3); + if (T2) { + isl_mat_free(*T2); + *T2 = isl_mat_alloc(ctx, 0, 1 + dim); + } + return isl_mat_alloc(ctx, 1 + dim, 0); +} + +/* Given a matrix that maps a (possibly) parametric domain to + * a parametric domain, add in rows that map the "nparam" parameters onto + * themselves. + */ +static __isl_give isl_mat *insert_parameter_rows(__isl_take isl_mat *mat, + unsigned nparam) +{ + int i; + + if (nparam == 0) + return mat; + if (!mat) + return NULL; + + mat = isl_mat_insert_rows(mat, 1, nparam); + if (!mat) + return NULL; + + for (i = 0; i < nparam; ++i) { + isl_seq_clr(mat->row[1 + i], mat->n_col); + isl_int_set(mat->row[1 + i][1 + i], mat->row[0][0]); + } + + return mat; +} + +/* Given a set of equalities + * + * -C(y) + M x = 0 + * + * this function computes a unimodular transformation from a lower-dimensional + * space to the original space that bijectively maps the integer points x' + * in the lower-dimensional space to the integer points x in the original + * space that satisfy the equalities. + * + * The input is given as a matrix B = [ -C M ] and the output is a + * matrix that maps [1 x'] to [1 x]. + * The number of equality constraints in B is assumed to be smaller than + * or equal to the number of variables x. + * "first" is the position of the first x variable. + * The preceding variables are considered to be y-variables. + * If T2 is not NULL, then *T2 is set to a matrix mapping [1 x] to [1 x']. + * + * First compute the (left) Hermite normal form of M, + * + * M [U1 U2] = M U = H = [H1 0] + * or + * M = H Q = [H1 0] [Q1] + * [Q2] + * + * with U, Q unimodular, Q = U^{-1} (and H lower triangular). + * Define the transformed variables as + * + * x = [U1 U2] [ x1' ] = [U1 U2] [Q1] x + * [ x2' ] [Q2] + * + * The equalities then become + * + * -C(y) + H1 x1' = 0 or x1' = H1^{-1} C(y) = C'(y) + * + * If the denominator of the constant term does not divide the + * the common denominator of the coefficients of y, then every + * integer point is mapped to a non-integer point and then the original set + * has no integer solutions (since the x' are a unimodular transformation + * of the x). In this case, a zero-column matrix is returned. + * Otherwise, the transformation is given by + * + * x = U1 H1^{-1} C(y) + U2 x2' + * + * The inverse transformation is simply + * + * x2' = Q2 x + */ +__isl_give isl_mat *isl_mat_final_variable_compression(__isl_take isl_mat *B, + int first, __isl_give isl_mat **T2) +{ + int i, n; + isl_ctx *ctx; + isl_mat *H = NULL, *C, *H1, *U = NULL, *U1, *U2; + unsigned dim; + + if (T2) + *T2 = NULL; + if (!B) + goto error; + + ctx = isl_mat_get_ctx(B); + dim = B->n_col - 1; + n = dim - first; + if (n < B->n_row) + isl_die(ctx, isl_error_invalid, "too many equality constraints", + goto error); + H = isl_mat_sub_alloc(B, 0, B->n_row, 1 + first, n); + H = isl_mat_left_hermite(H, 0, &U, T2); + if (!H || !U || (T2 && !*T2)) + goto error; + if (T2) { + *T2 = isl_mat_drop_rows(*T2, 0, B->n_row); + *T2 = isl_mat_diagonal(isl_mat_identity(ctx, 1 + first), *T2); + if (!*T2) + goto error; + } + C = isl_mat_alloc(ctx, 1 + B->n_row, 1 + first); + if (!C) + goto error; + isl_int_set_si(C->row[0][0], 1); + isl_seq_clr(C->row[0] + 1, first); + isl_mat_sub_neg(ctx, C->row + 1, B->row, B->n_row, 0, 0, 1 + first); + 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) + goto error; + isl_mat_free(H); + if (!isl_int_is_one(C->row[0][0])) { + isl_int g; + + isl_int_init(g); + for (i = 0; i < B->n_row; ++i) { + isl_seq_gcd(C->row[1 + i] + 1, first, &g); + isl_int_gcd(g, g, C->row[0][0]); + if (!isl_int_is_divisible_by(C->row[1 + i][0], g)) + break; + } + isl_int_clear(g); + + if (i < B->n_row) + return empty_compression(ctx, dim, T2, B, C, U); + C = isl_mat_normalize(C); + } + 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, 0, U->n_row, B->n_row, U->n_row - B->n_row); + U2 = isl_mat_lin_to_aff(U2); + isl_mat_free(U); + C = isl_mat_product(U1, C); + C = isl_mat_aff_direct_sum(C, U2); + C = insert_parameter_rows(C, first); + + isl_mat_free(B); + + return C; +error: + isl_mat_free(B); + isl_mat_free(H); + isl_mat_free(U); + if (T2) { + isl_mat_free(*T2); + *T2 = NULL; + } + return NULL; +} + +/* Given a set of equalities + * + * M x - c = 0 + * + * this function computes a unimodular transformation from a lower-dimensional + * space to the original space that bijectively maps the integer points x' + * in the lower-dimensional space to the integer points x in the original + * space that satisfy the equalities. + * + * The input is given as a matrix B = [ -c M ] and the output is a + * matrix that maps [1 x'] to [1 x]. + * The number of equality constraints in B is assumed to be smaller than + * or equal to the number of variables x. + * If T2 is not NULL, then *T2 is set to a matrix mapping [1 x] to [1 x']. + */ +__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B, + __isl_give isl_mat **T2) +{ + return isl_mat_final_variable_compression(B, 0, T2); +} + +/* Return "bset" and set *T and *T2 to the identity transformation + * on "bset" (provided T and T2 are not NULL). + */ +static __isl_give isl_basic_set *return_with_identity( + __isl_take isl_basic_set *bset, __isl_give isl_mat **T, + __isl_give isl_mat **T2) +{ + unsigned dim; + isl_mat *id; + + if (!bset) + return NULL; + if (!T && !T2) + return bset; + + dim = isl_basic_set_dim(bset, isl_dim_set); + id = isl_mat_identity(isl_basic_map_get_ctx(bset), 1 + dim); + if (T) + *T = isl_mat_copy(id); + if (T2) + *T2 = isl_mat_copy(id); + isl_mat_free(id); + + return bset; +} + +/* Use the n equalities of bset to unimodularly transform the + * variables x such that n transformed variables x1' have a constant value + * and rewrite the constraints of bset in terms of the remaining + * transformed variables x2'. The matrix pointed to by T maps + * the new variables x2' back to the original variables x, while T2 + * maps the original variables to the new variables. + */ +static struct isl_basic_set *compress_variables( + struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2) +{ + struct isl_mat *B, *TC; + unsigned dim; + + if (T) + *T = NULL; + if (T2) + *T2 = NULL; + if (!bset) + goto error; + isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error); + isl_assert(bset->ctx, bset->n_div == 0, goto error); + dim = isl_basic_set_n_dim(bset); + isl_assert(bset->ctx, bset->n_eq <= dim, goto error); + if (bset->n_eq == 0) + return return_with_identity(bset, T, T2); + + 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 (TC->n_col == 0) { + isl_mat_free(TC); + if (T2) { + isl_mat_free(*T2); + *T2 = NULL; + } + bset = isl_basic_set_set_to_empty(bset); + return return_with_identity(bset, T, T2); + } + + bset = isl_basic_set_preimage(bset, T ? isl_mat_copy(TC) : TC); + if (T) + *T = TC; + return bset; +error: + isl_basic_set_free(bset); + return NULL; +} + +struct isl_basic_set *isl_basic_set_remove_equalities( + struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2) +{ + if (T) + *T = NULL; + if (T2) + *T2 = NULL; + if (!bset) + return NULL; + isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error); + bset = isl_basic_set_gauss(bset, NULL); + if (ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY)) + return return_with_identity(bset, T, T2); + bset = compress_variables(bset, T, T2); + return bset; +error: + isl_basic_set_free(bset); + *T = NULL; + return NULL; +} + +/* Check if dimension dim belongs to a residue class + * i_dim \equiv r mod m + * with m != 1 and if so return m in *modulo and r in *residue. + * As a special case, when i_dim has a fixed value v, then + * *modulo is set to 0 and *residue to v. + * + * If i_dim does not belong to such a residue class, then *modulo + * is set to 1 and *residue is set to 0. + */ +isl_stat isl_basic_set_dim_residue_class(__isl_keep isl_basic_set *bset, + int pos, isl_int *modulo, isl_int *residue) +{ + isl_bool fixed; + struct isl_ctx *ctx; + struct isl_mat *H = NULL, *U = NULL, *C, *H1, *U1; + unsigned total; + unsigned nparam; + + if (!bset || !modulo || !residue) + return isl_stat_error; + + fixed = isl_basic_set_plain_dim_is_fixed(bset, pos, residue); + if (fixed < 0) + return isl_stat_error; + if (fixed) { + isl_int_set_si(*modulo, 0); + return isl_stat_ok; + } + + ctx = isl_basic_set_get_ctx(bset); + total = isl_basic_set_total_dim(bset); + nparam = isl_basic_set_n_param(bset); + H = isl_mat_sub_alloc6(ctx, bset->eq, 0, bset->n_eq, 1, total); + H = isl_mat_left_hermite(H, 0, &U, NULL); + if (!H) + return isl_stat_error; + + isl_seq_gcd(U->row[nparam + pos]+bset->n_eq, + total-bset->n_eq, modulo); + if (isl_int_is_zero(*modulo)) + isl_int_set_si(*modulo, 1); + if (isl_int_is_one(*modulo)) { + isl_int_set_si(*residue, 0); + isl_mat_free(H); + isl_mat_free(U); + return isl_stat_ok; + } + + C = isl_mat_alloc(ctx, 1 + bset->n_eq, 1); + if (!C) + goto error; + isl_int_set_si(C->row[0][0], 1); + isl_mat_sub_neg(ctx, C->row + 1, bset->eq, bset->n_eq, 0, 0, 1); + 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, nparam+pos, 1, 0, bset->n_eq); + U1 = isl_mat_lin_to_aff(U1); + isl_mat_free(U); + C = isl_mat_product(U1, C); + if (!C) + return isl_stat_error; + if (!isl_int_is_divisible_by(C->row[1][0], C->row[0][0])) { + bset = isl_basic_set_copy(bset); + bset = isl_basic_set_set_to_empty(bset); + isl_basic_set_free(bset); + isl_int_set_si(*modulo, 1); + isl_int_set_si(*residue, 0); + return isl_stat_ok; + } + isl_int_divexact(*residue, C->row[1][0], C->row[0][0]); + isl_int_fdiv_r(*residue, *residue, *modulo); + isl_mat_free(C); + return isl_stat_ok; +error: + isl_mat_free(H); + isl_mat_free(U); + return isl_stat_error; +} + +/* Check if dimension dim belongs to a residue class + * i_dim \equiv r mod m + * with m != 1 and if so return m in *modulo and r in *residue. + * As a special case, when i_dim has a fixed value v, then + * *modulo is set to 0 and *residue to v. + * + * If i_dim does not belong to such a residue class, then *modulo + * is set to 1 and *residue is set to 0. + */ +isl_stat isl_set_dim_residue_class(__isl_keep isl_set *set, + int pos, isl_int *modulo, isl_int *residue) +{ + isl_int m; + isl_int r; + int i; + + if (!set || !modulo || !residue) + return isl_stat_error; + + if (set->n == 0) { + isl_int_set_si(*modulo, 0); + isl_int_set_si(*residue, 0); + return isl_stat_ok; + } + + if (isl_basic_set_dim_residue_class(set->p[0], pos, modulo, residue)<0) + return isl_stat_error; + + if (set->n == 1) + return isl_stat_ok; + + if (isl_int_is_one(*modulo)) + return isl_stat_ok; + + isl_int_init(m); + isl_int_init(r); + + for (i = 1; i < set->n; ++i) { + if (isl_basic_set_dim_residue_class(set->p[i], pos, &m, &r) < 0) + goto error; + isl_int_gcd(*modulo, *modulo, m); + isl_int_sub(m, *residue, r); + isl_int_gcd(*modulo, *modulo, m); + if (!isl_int_is_zero(*modulo)) + isl_int_fdiv_r(*residue, *residue, *modulo); + if (isl_int_is_one(*modulo)) + break; + } + + isl_int_clear(m); + isl_int_clear(r); + + return isl_stat_ok; +error: + isl_int_clear(m); + isl_int_clear(r); + return isl_stat_error; +} + +/* Check if dimension "dim" belongs to a residue class + * i_dim \equiv r mod m + * with m != 1 and if so return m in *modulo and r in *residue. + * As a special case, when i_dim has a fixed value v, then + * *modulo is set to 0 and *residue to v. + * + * If i_dim does not belong to such a residue class, then *modulo + * is set to 1 and *residue is set to 0. + */ +isl_stat isl_set_dim_residue_class_val(__isl_keep isl_set *set, + int pos, __isl_give isl_val **modulo, __isl_give isl_val **residue) +{ + *modulo = NULL; + *residue = NULL; + if (!set) + return isl_stat_error; + *modulo = isl_val_alloc(isl_set_get_ctx(set)); + *residue = isl_val_alloc(isl_set_get_ctx(set)); + if (!*modulo || !*residue) + goto error; + if (isl_set_dim_residue_class(set, pos, + &(*modulo)->n, &(*residue)->n) < 0) + goto error; + isl_int_set_si((*modulo)->d, 1); + isl_int_set_si((*residue)->d, 1); + return isl_stat_ok; +error: + isl_val_free(*modulo); + isl_val_free(*residue); + return isl_stat_error; +} Index: contrib/isl/isl_factorization.h =================================================================== --- /dev/null +++ contrib/isl/isl_factorization.h @@ -0,0 +1,34 @@ +#ifndef ISL_FACTORIZATION_H +#define ISL_FACTORIZATION_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Data for factorizing a particular basic set. + * After applying "morph" to the basic set, there are "n_group" + * groups of consecutive set variables, each of length "len[i]", + * with 0 <= i < n_group. + * If no factorization is possible, then "n_group" is set to 0. + */ +struct isl_factorizer { + isl_morph *morph; + int n_group; + int *len; +}; +typedef struct isl_factorizer isl_factorizer; + +__isl_give isl_factorizer *isl_basic_set_factorizer( + __isl_keep isl_basic_set *bset); + +void isl_factorizer_free(__isl_take isl_factorizer *f); +void isl_factorizer_dump(__isl_take isl_factorizer *f); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/isl_factorization.c =================================================================== --- /dev/null +++ contrib/isl/isl_factorization.c @@ -0,0 +1,331 @@ +/* + * Copyright 2005-2007 Universiteit Leiden + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science, + * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands + * and 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 +#include +#include +#include + +static __isl_give isl_factorizer *isl_factorizer_alloc( + __isl_take isl_morph *morph, int n_group) +{ + isl_factorizer *f = NULL; + int *len = NULL; + + if (!morph) + return NULL; + + if (n_group > 0) { + len = isl_alloc_array(morph->dom->ctx, int, n_group); + if (!len) + goto error; + } + + f = isl_alloc_type(morph->dom->ctx, struct isl_factorizer); + if (!f) + goto error; + + f->morph = morph; + f->n_group = n_group; + f->len = len; + + return f; +error: + free(len); + isl_morph_free(morph); + return NULL; +} + +void isl_factorizer_free(__isl_take isl_factorizer *f) +{ + if (!f) + return; + + isl_morph_free(f->morph); + free(f->len); + free(f); +} + +void isl_factorizer_dump(__isl_take isl_factorizer *f) +{ + int i; + + if (!f) + return; + + isl_morph_print_internal(f->morph, stderr); + fprintf(stderr, "["); + for (i = 0; i < f->n_group; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "%d", f->len[i]); + } + fprintf(stderr, "]\n"); +} + +__isl_give isl_factorizer *isl_factorizer_identity(__isl_keep isl_basic_set *bset) +{ + return isl_factorizer_alloc(isl_morph_identity(bset), 0); +} + +__isl_give isl_factorizer *isl_factorizer_groups(__isl_keep isl_basic_set *bset, + __isl_take isl_mat *Q, __isl_take isl_mat *U, int n, int *len) +{ + int i; + unsigned nvar; + unsigned ovar; + isl_space *dim; + isl_basic_set *dom; + isl_basic_set *ran; + isl_morph *morph; + isl_factorizer *f; + isl_mat *id; + + if (!bset || !Q || !U) + goto error; + + ovar = 1 + isl_space_offset(bset->dim, isl_dim_set); + id = isl_mat_identity(bset->ctx, ovar); + Q = isl_mat_diagonal(isl_mat_copy(id), Q); + U = isl_mat_diagonal(id, U); + + nvar = isl_basic_set_dim(bset, isl_dim_set); + dim = isl_basic_set_get_space(bset); + dom = isl_basic_set_universe(isl_space_copy(dim)); + dim = isl_space_drop_dims(dim, isl_dim_set, 0, nvar); + dim = isl_space_add_dims(dim, isl_dim_set, nvar); + ran = isl_basic_set_universe(dim); + morph = isl_morph_alloc(dom, ran, Q, U); + f = isl_factorizer_alloc(morph, n); + if (!f) + return NULL; + for (i = 0; i < n; ++i) + f->len[i] = len[i]; + return f; +error: + isl_mat_free(Q); + isl_mat_free(U); + return NULL; +} + +struct isl_factor_groups { + int *pos; /* for each column: row position of pivot */ + int *group; /* group to which a column belongs */ + int *cnt; /* number of columns in the group */ + int *rowgroup; /* group to which a constraint belongs */ +}; + +/* Initialize isl_factor_groups structure: find pivot row positions, + * each column initially belongs to its own group and the groups + * of the constraints are still unknown. + */ +static int init_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H) +{ + int i, j; + + if (!H) + return -1; + + g->pos = isl_alloc_array(H->ctx, int, H->n_col); + g->group = isl_alloc_array(H->ctx, int, H->n_col); + g->cnt = isl_alloc_array(H->ctx, int, H->n_col); + g->rowgroup = isl_alloc_array(H->ctx, int, H->n_row); + + if (!g->pos || !g->group || !g->cnt || !g->rowgroup) + return -1; + + for (i = 0; i < H->n_row; ++i) + g->rowgroup[i] = -1; + for (i = 0, j = 0; i < H->n_col; ++i) { + for ( ; j < H->n_row; ++j) + if (!isl_int_is_zero(H->row[j][i])) + break; + g->pos[i] = j; + } + for (i = 0; i < H->n_col; ++i) { + g->group[i] = i; + g->cnt[i] = 1; + } + + return 0; +} + +/* Update group[k] to the group column k belongs to. + * When merging two groups, only the group of the current + * group leader is changed. Here we change the group of + * the other members to also point to the group that the + * old group leader now points to. + */ +static void update_group(struct isl_factor_groups *g, int k) +{ + int p = g->group[k]; + while (g->cnt[p] == 0) + p = g->group[p]; + g->group[k] = p; +} + +/* Merge group i with all groups of the subsequent columns + * with non-zero coefficients in row j of H. + * (The previous columns are all zero; otherwise we would have handled + * the row before.) + */ +static int update_group_i_with_row_j(struct isl_factor_groups *g, int i, int j, + __isl_keep isl_mat *H) +{ + int k; + + g->rowgroup[j] = g->group[i]; + for (k = i + 1; k < H->n_col && j >= g->pos[k]; ++k) { + update_group(g, k); + update_group(g, i); + if (g->group[k] != g->group[i] && + !isl_int_is_zero(H->row[j][k])) { + isl_assert(H->ctx, g->cnt[g->group[k]] != 0, return -1); + isl_assert(H->ctx, g->cnt[g->group[i]] != 0, return -1); + if (g->group[i] < g->group[k]) { + g->cnt[g->group[i]] += g->cnt[g->group[k]]; + g->cnt[g->group[k]] = 0; + g->group[g->group[k]] = g->group[i]; + } else { + g->cnt[g->group[k]] += g->cnt[g->group[i]]; + g->cnt[g->group[i]] = 0; + g->group[g->group[i]] = g->group[k]; + } + } + } + + return 0; +} + +/* Update the group information based on the constraint matrix. + */ +static int update_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H) +{ + int i, j; + + for (i = 0; i < H->n_col && g->cnt[0] < H->n_col; ++i) { + if (g->pos[i] == H->n_row) + continue; /* A line direction */ + if (g->rowgroup[g->pos[i]] == -1) + g->rowgroup[g->pos[i]] = i; + for (j = g->pos[i] + 1; j < H->n_row; ++j) { + if (isl_int_is_zero(H->row[j][i])) + continue; + if (g->rowgroup[j] != -1) + continue; + if (update_group_i_with_row_j(g, i, j, H) < 0) + return -1; + } + } + for (i = 1; i < H->n_col; ++i) + update_group(g, i); + + return 0; +} + +static void clear_groups(struct isl_factor_groups *g) +{ + if (!g) + return; + free(g->pos); + free(g->group); + free(g->cnt); + free(g->rowgroup); +} + +/* Determine if the set variables of the basic set can be factorized and + * return the results in an isl_factorizer. + * + * The algorithm works by first computing the Hermite normal form + * and then grouping columns linked by one or more constraints together, + * where a constraints "links" two or more columns if the constraint + * has nonzero coefficients in the columns. + */ +__isl_give isl_factorizer *isl_basic_set_factorizer( + __isl_keep isl_basic_set *bset) +{ + int i, j, n, done; + isl_mat *H, *U, *Q; + unsigned nvar; + struct isl_factor_groups g = { 0 }; + isl_factorizer *f; + + if (!bset) + return NULL; + + isl_assert(bset->ctx, isl_basic_set_dim(bset, isl_dim_div) == 0, + return NULL); + + nvar = isl_basic_set_dim(bset, isl_dim_set); + if (nvar <= 1) + return isl_factorizer_identity(bset); + + H = isl_mat_alloc(bset->ctx, bset->n_eq + bset->n_ineq, nvar); + if (!H) + return NULL; + isl_mat_sub_copy(bset->ctx, H->row, bset->eq, bset->n_eq, + 0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar); + isl_mat_sub_copy(bset->ctx, H->row + bset->n_eq, bset->ineq, bset->n_ineq, + 0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar); + H = isl_mat_left_hermite(H, 0, &U, &Q); + + if (init_groups(&g, H) < 0) + goto error; + if (update_groups(&g, H) < 0) + goto error; + + if (g.cnt[0] == nvar) { + isl_mat_free(H); + isl_mat_free(U); + isl_mat_free(Q); + clear_groups(&g); + + return isl_factorizer_identity(bset); + } + + done = 0; + n = 0; + while (done != nvar) { + int group = g.group[done]; + for (i = 1; i < g.cnt[group]; ++i) { + if (g.group[done + i] == group) + continue; + for (j = done + g.cnt[group]; j < nvar; ++j) + if (g.group[j] == group) + break; + if (j == nvar) + isl_die(bset->ctx, isl_error_internal, + "internal error", goto error); + g.group[j] = g.group[done + i]; + Q = isl_mat_swap_rows(Q, done + i, j); + U = isl_mat_swap_cols(U, done + i, j); + } + done += g.cnt[group]; + g.pos[n++] = g.cnt[group]; + } + + f = isl_factorizer_groups(bset, Q, U, n, g.pos); + + isl_mat_free(H); + clear_groups(&g); + + return f; +error: + isl_mat_free(H); + isl_mat_free(U); + isl_mat_free(Q); + clear_groups(&g); + return NULL; +} Index: contrib/isl/isl_farkas.c =================================================================== --- /dev/null +++ contrib/isl/isl_farkas.c @@ -0,0 +1,421 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#include +#include +#include +#include + +/* + * 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. + * + * 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_space *isl_space_prefix(__isl_take isl_space *dim, + const char *prefix) +{ + int i; + isl_ctx *ctx; + unsigned nvar; + size_t prefix_len = strlen(prefix); + + if (!dim) + return NULL; + + ctx = isl_space_get_ctx(dim); + nvar = isl_space_dim(dim, isl_dim_set); + + for (i = 0; i < nvar; ++i) { + const char *name; + char *prefix_name; + + name = isl_space_get_dim_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_space_set_dim_name(dim, isl_dim_set, i, prefix_name); + free(prefix_name); + } + + return dim; +error: + isl_space_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_space *isl_space_coefficients(__isl_take isl_space *dim) +{ + isl_space *dim_param; + unsigned nvar; + unsigned nparam; + + nvar = isl_space_dim(dim, isl_dim_set); + nparam = isl_space_dim(dim, isl_dim_param); + dim_param = isl_space_copy(dim); + dim_param = isl_space_drop_dims(dim_param, isl_dim_set, 0, nvar); + dim_param = isl_space_move_dims(dim_param, isl_dim_set, 0, + isl_dim_param, 0, nparam); + dim_param = isl_space_prefix(dim_param, "c_"); + dim_param = isl_space_insert_dims(dim_param, isl_dim_set, 0, 1); + dim_param = isl_space_set_dim_name(dim_param, isl_dim_set, 0, "c_cst"); + dim = isl_space_drop_dims(dim, isl_dim_param, 0, nparam); + dim = isl_space_prefix(dim, "c_"); + dim = isl_space_join(isl_space_from_domain(dim_param), + isl_space_from_range(dim)); + dim = isl_space_wrap(dim); + dim = isl_space_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_space *isl_space_unprefix(__isl_take isl_space *dim, + enum isl_dim_type type, const char *prefix) +{ + int i; + unsigned n; + size_t prefix_len = strlen(prefix); + + n = isl_space_dim(dim, type); + + for (i = 0; i < n; ++i) { + const char *name; + + name = isl_space_get_dim_name(dim, type, i); + if (!name) + continue; + if (strncmp(name, prefix, prefix_len)) + continue; + + dim = isl_space_set_dim_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_space *isl_space_solutions(__isl_take isl_space *dim) +{ + unsigned nparam; + + dim = isl_space_unwrap(dim); + dim = isl_space_drop_dims(dim, isl_dim_in, 0, 1); + dim = isl_space_unprefix(dim, isl_dim_in, "c_"); + dim = isl_space_unprefix(dim, isl_dim_out, "c_"); + nparam = isl_space_dim(dim, isl_dim_in); + dim = isl_space_move_dims(dim, isl_dim_param, 0, isl_dim_in, 0, nparam); + dim = isl_space_range(dim); + + return dim; +} + +/* Return the rational universe basic set in the given space. + */ +static __isl_give isl_basic_set *rational_universe(__isl_take isl_space *space) +{ + isl_basic_set *bset; + + bset = isl_basic_set_universe(space); + bset = isl_basic_set_set_rational(bset); + + return bset; +} + +/* 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. + * + * If "bset" is (obviously) empty, then the way this emptiness + * is represented by the constraints does not allow for the application + * of the standard farkas algorithm. We therefore handle this case + * specifically and return the universe basic set. + */ +static __isl_give isl_basic_set *farkas(__isl_take isl_space *space, + __isl_take isl_basic_set *bset, int shift) +{ + int i, j, k; + isl_basic_set *dual = NULL; + unsigned total; + + if (isl_basic_set_plain_is_empty(bset)) { + isl_basic_set_free(bset); + return rational_universe(space); + } + + total = isl_basic_set_total_dim(bset); + + dual = isl_basic_set_alloc_space(space, 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); + dual = isl_basic_set_simplify(dual); + 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_space *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_space(bset); + dim = isl_space_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_space *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_space(bset); + dim = isl_space_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_space *space = isl_set_get_space(set); + space = isl_space_coefficients(space); + isl_set_free(set); + return rational_universe(space); + } + + 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; +} + +/* Wrapper around isl_basic_set_coefficients for use + * as a isl_basic_set_list_map callback. + */ +static __isl_give isl_basic_set *coefficients_wrap( + __isl_take isl_basic_set *bset, void *user) +{ + return isl_basic_set_coefficients(bset); +} + +/* Replace the elements of "list" by the result of applying + * isl_basic_set_coefficients to them. + */ +__isl_give isl_basic_set_list *isl_basic_set_list_coefficients( + __isl_take isl_basic_set_list *list) +{ + return isl_basic_set_list_map(list, &coefficients_wrap, NULL); +} + +/* 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_space *space = isl_set_get_space(set); + space = isl_space_solutions(space); + isl_set_free(set); + return rational_universe(space); + } + + sol = isl_basic_set_solutions(isl_basic_set_copy(set->p[0])); + + for (i = 1; i < set->n; ++i) { + isl_basic_set *bset, *sol_i; + bset = isl_basic_set_copy(set->p[i]); + sol_i = isl_basic_set_solutions(bset); + sol = isl_basic_set_intersect(sol, sol_i); + } + + isl_set_free(set); + return sol; +} Index: contrib/isl/isl_ffs.c =================================================================== --- /dev/null +++ contrib/isl/isl_ffs.c @@ -0,0 +1,24 @@ +#include + +#if !HAVE_DECL_FFS && !HAVE_DECL___BUILTIN_FFS && HAVE_DECL__BITSCANFORWARD +#include + +/* Implementation of ffs in terms of _BitScanForward. + * + * ffs returns the position of the least significant bit set in i, + * with the least significant bit is position 1, or 0 if not bits are set. + * + * _BitScanForward returns 1 if mask is non-zero and sets index + * to the position of the least significant bit set in i, + * with the least significant bit is position 0. + */ +int isl_ffs(int i) +{ + unsigned char non_zero; + unsigned long index, mask = i; + + non_zero = _BitScanForward(&index, mask); + + return non_zero ? 1 + index : 0; +} +#endif Index: contrib/isl/isl_flow.c =================================================================== --- /dev/null +++ contrib/isl/isl_flow.c @@ -0,0 +1,3309 @@ +/* + * Copyright 2005-2007 Universiteit Leiden + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2012 Universiteit Leiden + * Copyright 2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science, + * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands + * and 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 + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum isl_restriction_type { + isl_restriction_type_empty, + isl_restriction_type_none, + isl_restriction_type_input, + isl_restriction_type_output +}; + +struct isl_restriction { + enum isl_restriction_type type; + + isl_set *source; + isl_set *sink; +}; + +/* Create a restriction of the given type. + */ +static __isl_give isl_restriction *isl_restriction_alloc( + __isl_take isl_map *source_map, enum isl_restriction_type type) +{ + isl_ctx *ctx; + isl_restriction *restr; + + if (!source_map) + return NULL; + + ctx = isl_map_get_ctx(source_map); + restr = isl_calloc_type(ctx, struct isl_restriction); + if (!restr) + goto error; + + restr->type = type; + + isl_map_free(source_map); + return restr; +error: + isl_map_free(source_map); + return NULL; +} + +/* Create a restriction that doesn't restrict anything. + */ +__isl_give isl_restriction *isl_restriction_none(__isl_take isl_map *source_map) +{ + return isl_restriction_alloc(source_map, isl_restriction_type_none); +} + +/* Create a restriction that removes everything. + */ +__isl_give isl_restriction *isl_restriction_empty( + __isl_take isl_map *source_map) +{ + return isl_restriction_alloc(source_map, isl_restriction_type_empty); +} + +/* Create a restriction on the input of the maximization problem + * based on the given source and sink restrictions. + */ +__isl_give isl_restriction *isl_restriction_input( + __isl_take isl_set *source_restr, __isl_take isl_set *sink_restr) +{ + isl_ctx *ctx; + isl_restriction *restr; + + if (!source_restr || !sink_restr) + goto error; + + ctx = isl_set_get_ctx(source_restr); + restr = isl_calloc_type(ctx, struct isl_restriction); + if (!restr) + goto error; + + restr->type = isl_restriction_type_input; + restr->source = source_restr; + restr->sink = sink_restr; + + return restr; +error: + isl_set_free(source_restr); + isl_set_free(sink_restr); + return NULL; +} + +/* Create a restriction on the output of the maximization problem + * based on the given source restriction. + */ +__isl_give isl_restriction *isl_restriction_output( + __isl_take isl_set *source_restr) +{ + isl_ctx *ctx; + isl_restriction *restr; + + if (!source_restr) + return NULL; + + ctx = isl_set_get_ctx(source_restr); + restr = isl_calloc_type(ctx, struct isl_restriction); + if (!restr) + goto error; + + restr->type = isl_restriction_type_output; + restr->source = source_restr; + + return restr; +error: + isl_set_free(source_restr); + return NULL; +} + +__isl_null isl_restriction *isl_restriction_free( + __isl_take isl_restriction *restr) +{ + if (!restr) + return NULL; + + isl_set_free(restr->source); + isl_set_free(restr->sink); + free(restr); + return NULL; +} + +isl_ctx *isl_restriction_get_ctx(__isl_keep isl_restriction *restr) +{ + return restr ? isl_set_get_ctx(restr->source) : NULL; +} + +/* A private structure to keep track of a mapping together with + * a user-specified identifier and a boolean indicating whether + * the map represents a must or may access/dependence. + */ +struct isl_labeled_map { + struct isl_map *map; + void *data; + int must; +}; + +typedef int (*isl_access_coscheduled)(void *first, void *second); + +/* A structure containing the input for dependence analysis: + * - a sink + * - n_must + n_may (<= max_source) sources + * - a function for determining the relative order of sources and sink + * - an optional function "coscheduled" for determining whether sources + * may be coscheduled. If "coscheduled" is NULL, then the sources + * are assumed not to be coscheduled. + * The must sources are placed before the may sources. + * + * domain_map is an auxiliary map that maps the sink access relation + * to the domain of this access relation. + * This field is only needed when restrict_fn is set and + * the field itself is set by isl_access_info_compute_flow. + * + * restrict_fn is a callback that (if not NULL) will be called + * right before any lexicographical maximization. + */ +struct isl_access_info { + isl_map *domain_map; + struct isl_labeled_map sink; + isl_access_level_before level_before; + isl_access_coscheduled coscheduled; + + isl_access_restrict restrict_fn; + void *restrict_user; + + int max_source; + int n_must; + int n_may; + struct isl_labeled_map source[1]; +}; + +/* A structure containing the output of dependence analysis: + * - n_source dependences + * - a wrapped subset of the sink for which definitely no source could be found + * - a wrapped subset of the sink for which possibly no source could be found + */ +struct isl_flow { + isl_set *must_no_source; + isl_set *may_no_source; + int n_source; + struct isl_labeled_map *dep; +}; + +/* Construct an isl_access_info structure and fill it up with + * the given data. The number of sources is set to 0. + */ +__isl_give isl_access_info *isl_access_info_alloc(__isl_take isl_map *sink, + void *sink_user, isl_access_level_before fn, int max_source) +{ + isl_ctx *ctx; + struct isl_access_info *acc; + + if (!sink) + return NULL; + + ctx = isl_map_get_ctx(sink); + isl_assert(ctx, max_source >= 0, goto error); + + acc = isl_calloc(ctx, struct isl_access_info, + sizeof(struct isl_access_info) + + (max_source - 1) * sizeof(struct isl_labeled_map)); + if (!acc) + goto error; + + acc->sink.map = sink; + acc->sink.data = sink_user; + acc->level_before = fn; + acc->max_source = max_source; + acc->n_must = 0; + acc->n_may = 0; + + return acc; +error: + isl_map_free(sink); + return NULL; +} + +/* Free the given isl_access_info structure. + */ +__isl_null isl_access_info *isl_access_info_free( + __isl_take isl_access_info *acc) +{ + int i; + + if (!acc) + return NULL; + isl_map_free(acc->domain_map); + isl_map_free(acc->sink.map); + for (i = 0; i < acc->n_must + acc->n_may; ++i) + isl_map_free(acc->source[i].map); + free(acc); + return NULL; +} + +isl_ctx *isl_access_info_get_ctx(__isl_keep isl_access_info *acc) +{ + return acc ? isl_map_get_ctx(acc->sink.map) : NULL; +} + +__isl_give isl_access_info *isl_access_info_set_restrict( + __isl_take isl_access_info *acc, isl_access_restrict fn, void *user) +{ + if (!acc) + return NULL; + acc->restrict_fn = fn; + acc->restrict_user = user; + return acc; +} + +/* Add another source to an isl_access_info structure, making + * sure the "must" sources are placed before the "may" sources. + * This function may be called at most max_source times on a + * given isl_access_info structure, with max_source as specified + * in the call to isl_access_info_alloc that constructed the structure. + */ +__isl_give isl_access_info *isl_access_info_add_source( + __isl_take isl_access_info *acc, __isl_take isl_map *source, + int must, void *source_user) +{ + isl_ctx *ctx; + + if (!acc) + goto error; + ctx = isl_map_get_ctx(acc->sink.map); + isl_assert(ctx, acc->n_must + acc->n_may < acc->max_source, goto error); + + if (must) { + if (acc->n_may) + acc->source[acc->n_must + acc->n_may] = + acc->source[acc->n_must]; + acc->source[acc->n_must].map = source; + acc->source[acc->n_must].data = source_user; + acc->source[acc->n_must].must = 1; + acc->n_must++; + } else { + acc->source[acc->n_must + acc->n_may].map = source; + acc->source[acc->n_must + acc->n_may].data = source_user; + acc->source[acc->n_must + acc->n_may].must = 0; + acc->n_may++; + } + + return acc; +error: + isl_map_free(source); + isl_access_info_free(acc); + return NULL; +} + +/* A helper struct carrying the isl_access_info and an error condition. + */ +struct access_sort_info { + isl_access_info *access_info; + int error; +}; + +/* Return -n, 0 or n (with n a positive value), depending on whether + * the source access identified by p1 should be sorted before, together + * or after that identified by p2. + * + * If p1 appears before p2, then it should be sorted first. + * For more generic initial schedules, it is possible that neither + * p1 nor p2 appears before the other, or at least not in any obvious way. + * We therefore also check if p2 appears before p1, in which case p2 + * should be sorted first. + * If not, we try to order the two statements based on the description + * of the iteration domains. This results in an arbitrary, but fairly + * stable ordering. + * + * In case of an error, sort_info.error is set to true and all elements are + * reported to be equal. + */ +static int access_sort_cmp(const void *p1, const void *p2, void *user) +{ + struct access_sort_info *sort_info = user; + isl_access_info *acc = sort_info->access_info; + + if (sort_info->error) + return 0; + + const struct isl_labeled_map *i1, *i2; + int level1, level2; + uint32_t h1, h2; + i1 = (const struct isl_labeled_map *) p1; + i2 = (const struct isl_labeled_map *) p2; + + level1 = acc->level_before(i1->data, i2->data); + if (level1 < 0) + goto error; + if (level1 % 2) + return -1; + + level2 = acc->level_before(i2->data, i1->data); + if (level2 < 0) + goto error; + if (level2 % 2) + return 1; + + h1 = isl_map_get_hash(i1->map); + h2 = isl_map_get_hash(i2->map); + return h1 > h2 ? 1 : h1 < h2 ? -1 : 0; +error: + sort_info->error = 1; + return 0; +} + +/* Sort the must source accesses in their textual order. + */ +static __isl_give isl_access_info *isl_access_info_sort_sources( + __isl_take isl_access_info *acc) +{ + struct access_sort_info sort_info; + + sort_info.access_info = acc; + sort_info.error = 0; + + if (!acc) + return NULL; + if (acc->n_must <= 1) + return acc; + + if (isl_sort(acc->source, acc->n_must, sizeof(struct isl_labeled_map), + access_sort_cmp, &sort_info) < 0) + return isl_access_info_free(acc); + if (sort_info.error) + return isl_access_info_free(acc); + + return acc; +} + +/* Align the parameters of the two spaces if needed and then call + * isl_space_join. + */ +static __isl_give isl_space *space_align_and_join(__isl_take isl_space *left, + __isl_take isl_space *right) +{ + isl_bool equal_params; + + equal_params = isl_space_has_equal_params(left, right); + if (equal_params < 0) + goto error; + if (equal_params) + return isl_space_join(left, right); + + left = isl_space_align_params(left, isl_space_copy(right)); + right = isl_space_align_params(right, isl_space_copy(left)); + return isl_space_join(left, right); +error: + isl_space_free(left); + isl_space_free(right); + return NULL; +} + +/* Initialize an empty isl_flow structure corresponding to a given + * isl_access_info structure. + * For each must access, two dependences are created (initialized + * to the empty relation), one for the resulting must dependences + * and one for the resulting may dependences. May accesses can + * only lead to may dependences, so only one dependence is created + * for each of them. + * This function is private as isl_flow structures are only supposed + * to be created by isl_access_info_compute_flow. + */ +static __isl_give isl_flow *isl_flow_alloc(__isl_keep isl_access_info *acc) +{ + int i, n; + struct isl_ctx *ctx; + struct isl_flow *dep; + + if (!acc) + return NULL; + + ctx = isl_map_get_ctx(acc->sink.map); + dep = isl_calloc_type(ctx, struct isl_flow); + if (!dep) + return NULL; + + n = 2 * acc->n_must + acc->n_may; + dep->dep = isl_calloc_array(ctx, struct isl_labeled_map, n); + if (n && !dep->dep) + goto error; + + dep->n_source = n; + for (i = 0; i < acc->n_must; ++i) { + isl_space *dim; + dim = space_align_and_join( + isl_map_get_space(acc->source[i].map), + isl_space_reverse(isl_map_get_space(acc->sink.map))); + dep->dep[2 * i].map = isl_map_empty(dim); + dep->dep[2 * i + 1].map = isl_map_copy(dep->dep[2 * i].map); + dep->dep[2 * i].data = acc->source[i].data; + dep->dep[2 * i + 1].data = acc->source[i].data; + dep->dep[2 * i].must = 1; + dep->dep[2 * i + 1].must = 0; + if (!dep->dep[2 * i].map || !dep->dep[2 * i + 1].map) + goto error; + } + for (i = acc->n_must; i < acc->n_must + acc->n_may; ++i) { + isl_space *dim; + dim = space_align_and_join( + isl_map_get_space(acc->source[i].map), + isl_space_reverse(isl_map_get_space(acc->sink.map))); + dep->dep[acc->n_must + i].map = isl_map_empty(dim); + dep->dep[acc->n_must + i].data = acc->source[i].data; + dep->dep[acc->n_must + i].must = 0; + if (!dep->dep[acc->n_must + i].map) + goto error; + } + + return dep; +error: + isl_flow_free(dep); + return NULL; +} + +/* Iterate over all sources and for each resulting flow dependence + * that is not empty, call the user specfied function. + * The second argument in this function call identifies the source, + * while the third argument correspond to the final argument of + * the isl_flow_foreach call. + */ +isl_stat isl_flow_foreach(__isl_keep isl_flow *deps, + isl_stat (*fn)(__isl_take isl_map *dep, int must, void *dep_user, + void *user), + void *user) +{ + int i; + + if (!deps) + return isl_stat_error; + + for (i = 0; i < deps->n_source; ++i) { + 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) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Return a copy of the subset of the sink for which no source could be found. + */ +__isl_give isl_map *isl_flow_get_no_source(__isl_keep isl_flow *deps, int must) +{ + if (!deps) + return NULL; + + if (must) + return isl_set_unwrap(isl_set_copy(deps->must_no_source)); + else + return isl_set_unwrap(isl_set_copy(deps->may_no_source)); +} + +void isl_flow_free(__isl_take isl_flow *deps) +{ + int i; + + if (!deps) + return; + isl_set_free(deps->must_no_source); + isl_set_free(deps->may_no_source); + if (deps->dep) { + for (i = 0; i < deps->n_source; ++i) + isl_map_free(deps->dep[i].map); + free(deps->dep); + } + free(deps); +} + +isl_ctx *isl_flow_get_ctx(__isl_keep isl_flow *deps) +{ + return deps ? isl_set_get_ctx(deps->must_no_source) : NULL; +} + +/* Return a map that enforces that the domain iteration occurs after + * the range iteration at the given level. + * If level is odd, then the domain iteration should occur after + * the target iteration in their shared level/2 outermost loops. + * In this case we simply need to enforce that these outermost + * loop iterations are the same. + * If level is even, then the loop iterator of the domain should + * be greater than the loop iterator of the range at the last + * of the level/2 shared loops, i.e., loop level/2 - 1. + */ +static __isl_give isl_map *after_at_level(__isl_take isl_space *dim, int level) +{ + struct isl_basic_map *bmap; + + if (level % 2) + bmap = isl_basic_map_equal(dim, level/2); + else + bmap = isl_basic_map_more_at(dim, level/2 - 1); + + return isl_map_from_basic_map(bmap); +} + +/* Compute the partial lexicographic maximum of "dep" on domain "sink", + * but first check if the user has set acc->restrict_fn and if so + * update either the input or the output of the maximization problem + * with respect to the resulting restriction. + * + * Since the user expects a mapping from sink iterations to source iterations, + * whereas the domain of "dep" is a wrapped map, mapping sink iterations + * to accessed array elements, we first need to project out the accessed + * sink array elements by applying acc->domain_map. + * Similarly, the sink restriction specified by the user needs to be + * converted back to the wrapped map. + */ +static __isl_give isl_map *restricted_partial_lexmax( + __isl_keep isl_access_info *acc, __isl_take isl_map *dep, + int source, __isl_take isl_set *sink, __isl_give isl_set **empty) +{ + isl_map *source_map; + isl_restriction *restr; + isl_set *sink_domain; + isl_set *sink_restr; + isl_map *res; + + if (!acc->restrict_fn) + return isl_map_partial_lexmax(dep, sink, empty); + + source_map = isl_map_copy(dep); + source_map = isl_map_apply_domain(source_map, + isl_map_copy(acc->domain_map)); + sink_domain = isl_set_copy(sink); + sink_domain = isl_set_apply(sink_domain, isl_map_copy(acc->domain_map)); + restr = acc->restrict_fn(source_map, sink_domain, + acc->source[source].data, acc->restrict_user); + isl_set_free(sink_domain); + isl_map_free(source_map); + + if (!restr) + goto error; + if (restr->type == isl_restriction_type_input) { + dep = isl_map_intersect_range(dep, isl_set_copy(restr->source)); + sink_restr = isl_set_copy(restr->sink); + sink_restr = isl_set_apply(sink_restr, + isl_map_reverse(isl_map_copy(acc->domain_map))); + sink = isl_set_intersect(sink, sink_restr); + } else if (restr->type == isl_restriction_type_empty) { + isl_space *space = isl_map_get_space(dep); + isl_map_free(dep); + dep = isl_map_empty(space); + } + + res = isl_map_partial_lexmax(dep, sink, empty); + + if (restr->type == isl_restriction_type_output) + res = isl_map_intersect_range(res, isl_set_copy(restr->source)); + + isl_restriction_free(restr); + return res; +error: + isl_map_free(dep); + isl_set_free(sink); + *empty = NULL; + return NULL; +} + +/* Compute the last iteration of must source j that precedes the sink + * at the given level for sink iterations in set_C. + * The subset of set_C for which no such iteration can be found is returned + * in *empty. + */ +static struct isl_map *last_source(struct isl_access_info *acc, + struct isl_set *set_C, + int j, int level, struct isl_set **empty) +{ + struct isl_map *read_map; + struct isl_map *write_map; + struct isl_map *dep_map; + struct isl_map *after; + struct isl_map *result; + + read_map = isl_map_copy(acc->sink.map); + write_map = isl_map_copy(acc->source[j].map); + write_map = isl_map_reverse(write_map); + dep_map = isl_map_apply_range(read_map, write_map); + after = after_at_level(isl_map_get_space(dep_map), level); + dep_map = isl_map_intersect(dep_map, after); + result = restricted_partial_lexmax(acc, dep_map, j, set_C, empty); + result = isl_map_reverse(result); + + return result; +} + +/* For a given mapping between iterations of must source j and iterations + * of the sink, compute the last iteration of must source k preceding + * the sink at level before_level for any of the sink iterations, + * but following the corresponding iteration of must source j at level + * after_level. + */ +static struct isl_map *last_later_source(struct isl_access_info *acc, + struct isl_map *old_map, + int j, int before_level, + int k, int after_level, + struct isl_set **empty) +{ + isl_space *dim; + struct isl_set *set_C; + struct isl_map *read_map; + struct isl_map *write_map; + struct isl_map *dep_map; + struct isl_map *after_write; + struct isl_map *before_read; + struct isl_map *result; + + set_C = isl_map_range(isl_map_copy(old_map)); + read_map = isl_map_copy(acc->sink.map); + write_map = isl_map_copy(acc->source[k].map); + + write_map = isl_map_reverse(write_map); + dep_map = isl_map_apply_range(read_map, write_map); + dim = space_align_and_join(isl_map_get_space(acc->source[k].map), + isl_space_reverse(isl_map_get_space(acc->source[j].map))); + after_write = after_at_level(dim, after_level); + after_write = isl_map_apply_range(after_write, old_map); + after_write = isl_map_reverse(after_write); + dep_map = isl_map_intersect(dep_map, after_write); + before_read = after_at_level(isl_map_get_space(dep_map), before_level); + dep_map = isl_map_intersect(dep_map, before_read); + result = restricted_partial_lexmax(acc, dep_map, k, set_C, empty); + result = isl_map_reverse(result); + + return result; +} + +/* Given a shared_level between two accesses, return 1 if the + * the first can precede the second at the requested target_level. + * If the target level is odd, i.e., refers to a statement level + * dimension, then first needs to precede second at the requested + * level, i.e., shared_level must be equal to target_level. + * If the target level is odd, then the two loops should share + * at least the requested number of outer loops. + */ +static int can_precede_at_level(int shared_level, int target_level) +{ + if (shared_level < target_level) + return 0; + if ((target_level % 2) && shared_level > target_level) + return 0; + return 1; +} + +/* Given a possible flow dependence temp_rel[j] between source j and the sink + * at level sink_level, remove those elements for which + * there is an iteration of another source k < j that is closer to the sink. + * The flow dependences temp_rel[k] are updated with the improved sources. + * Any improved source needs to precede the sink at the same level + * and needs to follow source j at the same or a deeper level. + * The lower this level, the later the execution date of source k. + * We therefore consider lower levels first. + * + * If temp_rel[j] is empty, then there can be no improvement and + * we return immediately. + * + * This function returns isl_stat_ok in case it was executed successfully and + * isl_stat_error in case of errors during the execution of this function. + */ +static isl_stat intermediate_sources(__isl_keep isl_access_info *acc, + struct isl_map **temp_rel, int j, int sink_level) +{ + int k, level; + int depth = 2 * isl_map_dim(acc->source[j].map, isl_dim_in) + 1; + + if (isl_map_plain_is_empty(temp_rel[j])) + return isl_stat_ok; + + for (k = j - 1; k >= 0; --k) { + int plevel, plevel2; + plevel = acc->level_before(acc->source[k].data, acc->sink.data); + if (plevel < 0) + return isl_stat_error; + if (!can_precede_at_level(plevel, sink_level)) + continue; + + plevel2 = acc->level_before(acc->source[j].data, + acc->source[k].data); + if (plevel2 < 0) + return isl_stat_error; + + for (level = sink_level; level <= depth; ++level) { + struct isl_map *T; + struct isl_set *trest; + struct isl_map *copy; + + if (!can_precede_at_level(plevel2, level)) + continue; + + copy = isl_map_copy(temp_rel[j]); + T = last_later_source(acc, copy, j, sink_level, k, + level, &trest); + if (isl_map_plain_is_empty(T)) { + isl_set_free(trest); + isl_map_free(T); + continue; + } + temp_rel[j] = isl_map_intersect_range(temp_rel[j], trest); + temp_rel[k] = isl_map_union_disjoint(temp_rel[k], T); + } + } + + return isl_stat_ok; +} + +/* Compute all iterations of may source j that precedes the sink at the given + * level for sink iterations in set_C. + */ +static __isl_give isl_map *all_sources(__isl_keep isl_access_info *acc, + __isl_take isl_set *set_C, int j, int level) +{ + isl_map *read_map; + isl_map *write_map; + isl_map *dep_map; + isl_map *after; + + read_map = isl_map_copy(acc->sink.map); + read_map = isl_map_intersect_domain(read_map, set_C); + write_map = isl_map_copy(acc->source[acc->n_must + j].map); + write_map = isl_map_reverse(write_map); + dep_map = isl_map_apply_range(read_map, write_map); + after = after_at_level(isl_map_get_space(dep_map), level); + dep_map = isl_map_intersect(dep_map, after); + + return isl_map_reverse(dep_map); +} + +/* For a given mapping between iterations of must source k and iterations + * of the sink, compute all iterations of may source j preceding + * the sink at level before_level for any of the sink iterations, + * but following the corresponding iteration of must source k at level + * after_level. + */ +static __isl_give isl_map *all_later_sources(__isl_keep isl_access_info *acc, + __isl_take isl_map *old_map, + int j, int before_level, int k, int after_level) +{ + isl_space *dim; + isl_set *set_C; + isl_map *read_map; + isl_map *write_map; + isl_map *dep_map; + isl_map *after_write; + isl_map *before_read; + + set_C = isl_map_range(isl_map_copy(old_map)); + read_map = isl_map_copy(acc->sink.map); + read_map = isl_map_intersect_domain(read_map, set_C); + write_map = isl_map_copy(acc->source[acc->n_must + j].map); + + write_map = isl_map_reverse(write_map); + dep_map = isl_map_apply_range(read_map, write_map); + dim = isl_space_join(isl_map_get_space(acc->source[acc->n_must + j].map), + isl_space_reverse(isl_map_get_space(acc->source[k].map))); + after_write = after_at_level(dim, after_level); + after_write = isl_map_apply_range(after_write, old_map); + after_write = isl_map_reverse(after_write); + dep_map = isl_map_intersect(dep_map, after_write); + before_read = after_at_level(isl_map_get_space(dep_map), before_level); + dep_map = isl_map_intersect(dep_map, before_read); + return isl_map_reverse(dep_map); +} + +/* Given the must and may dependence relations for the must accesses + * for level sink_level, check if there are any accesses of may access j + * that occur in between and return their union. + * If some of these accesses are intermediate with respect to + * (previously thought to be) must dependences, then these + * must dependences are turned into may dependences. + */ +static __isl_give isl_map *all_intermediate_sources( + __isl_keep isl_access_info *acc, __isl_take isl_map *map, + struct isl_map **must_rel, struct isl_map **may_rel, + int j, int sink_level) +{ + int k, level; + int depth = 2 * isl_map_dim(acc->source[acc->n_must + j].map, + isl_dim_in) + 1; + + for (k = 0; k < acc->n_must; ++k) { + int plevel; + + 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, + acc->source[acc->n_must + j].data); + if (plevel < 0) + return isl_map_free(map); + + for (level = sink_level; level <= depth; ++level) { + isl_map *T; + isl_map *copy; + isl_set *ran; + + if (!can_precede_at_level(plevel, level)) + continue; + + copy = isl_map_copy(may_rel[k]); + T = all_later_sources(acc, copy, j, sink_level, k, level); + map = isl_map_union(map, T); + + copy = isl_map_copy(must_rel[k]); + T = all_later_sources(acc, copy, j, sink_level, k, level); + ran = isl_map_range(isl_map_copy(T)); + map = isl_map_union(map, T); + may_rel[k] = isl_map_union_disjoint(may_rel[k], + isl_map_intersect_range(isl_map_copy(must_rel[k]), + isl_set_copy(ran))); + T = isl_map_from_domain_and_range( + isl_set_universe( + isl_space_domain(isl_map_get_space(must_rel[k]))), + ran); + must_rel[k] = isl_map_subtract(must_rel[k], T); + } + } + + return map; +} + +/* Given a dependence relation "old_map" between a must-source and the sink, + * return a subset of the dependences, augmented with instances + * of the source at position "pos" in "acc" that are coscheduled + * with the must-source and that access the same element. + * That is, if the input lives in a space T -> K, then the output + * lives in the space [T -> S] -> K, with S the space of source "pos", and + * the domain factor of the domain product is a subset of the input. + * The sources are considered to be coscheduled if they have the same values + * for the initial "depth" coordinates. + * + * First construct a dependence relation S -> K and a mapping + * between coscheduled sources T -> S. + * The second is combined with the original dependence relation T -> K + * to form a relation in T -> [S -> K], which is subsequently + * uncurried to [T -> S] -> K. + * This result is then intersected with the dependence relation S -> K + * to form the output. + * + * In case a negative depth is given, NULL is returned to indicate an error. + */ +static __isl_give isl_map *coscheduled_source(__isl_keep isl_access_info *acc, + __isl_keep isl_map *old_map, int pos, int depth) +{ + isl_space *space; + isl_set *set_C; + isl_map *read_map; + isl_map *write_map; + isl_map *dep_map; + isl_map *equal; + isl_map *map; + + if (depth < 0) + return NULL; + + set_C = isl_map_range(isl_map_copy(old_map)); + read_map = isl_map_copy(acc->sink.map); + read_map = isl_map_intersect_domain(read_map, set_C); + write_map = isl_map_copy(acc->source[pos].map); + dep_map = isl_map_domain_product(write_map, read_map); + dep_map = isl_set_unwrap(isl_map_domain(dep_map)); + space = isl_space_join(isl_map_get_space(old_map), + isl_space_reverse(isl_map_get_space(dep_map))); + equal = isl_map_from_basic_map(isl_basic_map_equal(space, depth)); + map = isl_map_range_product(equal, isl_map_copy(old_map)); + map = isl_map_uncurry(map); + map = isl_map_intersect_domain_factor_range(map, dep_map); + + return map; +} + +/* After the dependences derived from a must-source have been computed + * at a certain level, check if any of the sources of the must-dependences + * may be coscheduled with other sources. + * If they are any such sources, then there is no way of determining + * which of the sources actually comes last and the must-dependences + * need to be turned into may-dependences, while dependences from + * the other sources need to be added to the may-dependences as well. + * "acc" describes the sources and a callback for checking whether + * two sources may be coscheduled. If acc->coscheduled is NULL then + * the sources are assumed not to be coscheduled. + * "must_rel" and "may_rel" describe the must and may-dependence relations + * computed at the current level for the must-sources. Some of the dependences + * may be moved from "must_rel" to "may_rel". + * "flow" contains all dependences computed so far (apart from those + * in "must_rel" and "may_rel") and may be updated with additional + * dependences derived from may-sources. + * + * In particular, consider all the must-sources with a non-empty + * dependence relation in "must_rel". They are considered in reverse + * order because that is the order in which they are considered in the caller. + * If any of the must-sources are coscheduled, then the last one + * is the one that will have a corresponding dependence relation. + * For each must-source i, consider both all the previous must-sources + * and all the may-sources. If any of those may be coscheduled with + * must-source i, then compute the coscheduled instances that access + * the same memory elements. The result is a relation [T -> S] -> K. + * The projection onto T -> K is a subset of the must-dependence relation + * that needs to be turned into may-dependences. + * The projection onto S -> K needs to be added to the may-dependences + * of source S. + * Since a given must-source instance may be coscheduled with several + * other source instances, the dependences that need to be turned + * into may-dependences are first collected and only actually removed + * from the must-dependences after all other sources have been considered. + */ +static __isl_give isl_flow *handle_coscheduled(__isl_keep isl_access_info *acc, + __isl_keep isl_map **must_rel, __isl_keep isl_map **may_rel, + __isl_take isl_flow *flow) +{ + int i, j; + + if (!acc->coscheduled) + return flow; + for (i = acc->n_must - 1; i >= 0; --i) { + isl_map *move; + + if (isl_map_plain_is_empty(must_rel[i])) + continue; + move = isl_map_empty(isl_map_get_space(must_rel[i])); + for (j = i - 1; j >= 0; --j) { + int depth; + isl_map *map, *factor; + + if (!acc->coscheduled(acc->source[i].data, + acc->source[j].data)) + continue; + depth = acc->level_before(acc->source[i].data, + acc->source[j].data) / 2; + map = coscheduled_source(acc, must_rel[i], j, depth); + factor = isl_map_domain_factor_range(isl_map_copy(map)); + may_rel[j] = isl_map_union(may_rel[j], factor); + map = isl_map_domain_factor_domain(map); + move = isl_map_union(move, map); + } + for (j = 0; j < acc->n_may; ++j) { + int depth, pos; + isl_map *map, *factor; + + pos = acc->n_must + j; + if (!acc->coscheduled(acc->source[i].data, + acc->source[pos].data)) + continue; + depth = acc->level_before(acc->source[i].data, + acc->source[pos].data) / 2; + map = coscheduled_source(acc, must_rel[i], pos, depth); + factor = isl_map_domain_factor_range(isl_map_copy(map)); + pos = 2 * acc->n_must + j; + flow->dep[pos].map = isl_map_union(flow->dep[pos].map, + factor); + map = isl_map_domain_factor_domain(map); + move = isl_map_union(move, map); + } + must_rel[i] = isl_map_subtract(must_rel[i], isl_map_copy(move)); + may_rel[i] = isl_map_union(may_rel[i], move); + } + + return flow; +} + +/* Compute dependences for the case where all accesses are "may" + * accesses, which boils down to computing memory based dependences. + * The generic algorithm would also work in this case, but it would + * be overkill to use it. + */ +static __isl_give isl_flow *compute_mem_based_dependences( + __isl_keep isl_access_info *acc) +{ + int i; + isl_set *mustdo; + isl_set *maydo; + isl_flow *res; + + res = isl_flow_alloc(acc); + if (!res) + return NULL; + + mustdo = isl_map_domain(isl_map_copy(acc->sink.map)); + maydo = isl_set_copy(mustdo); + + for (i = 0; i < acc->n_may; ++i) { + int plevel; + int is_before; + isl_space *dim; + isl_map *before; + isl_map *dep; + + plevel = acc->level_before(acc->source[i].data, acc->sink.data); + if (plevel < 0) + goto error; + + is_before = plevel & 1; + plevel >>= 1; + + dim = isl_map_get_space(res->dep[i].map); + if (is_before) + before = isl_map_lex_le_first(dim, plevel); + else + before = isl_map_lex_lt_first(dim, plevel); + dep = isl_map_apply_range(isl_map_copy(acc->source[i].map), + isl_map_reverse(isl_map_copy(acc->sink.map))); + dep = isl_map_intersect(dep, before); + mustdo = isl_set_subtract(mustdo, + isl_map_range(isl_map_copy(dep))); + res->dep[i].map = isl_map_union(res->dep[i].map, dep); + } + + res->may_no_source = isl_set_subtract(maydo, isl_set_copy(mustdo)); + res->must_no_source = mustdo; + + return res; +error: + isl_set_free(mustdo); + isl_set_free(maydo); + isl_flow_free(res); + return NULL; +} + +/* Compute dependences for the case where there is at least one + * "must" access. + * + * The core algorithm considers all levels in which a source may precede + * the sink, where a level may either be a statement level or a loop level. + * The outermost statement level is 1, the first loop level is 2, etc... + * The algorithm basically does the following: + * for all levels l of the read access from innermost to outermost + * for all sources w that may precede the sink access at that level + * compute the last iteration of the source that precedes the sink access + * at that level + * add result to possible last accesses at level l of source w + * for all sources w2 that we haven't considered yet at this level that may + * also precede the sink access + * for all levels l2 of w from l to innermost + * for all possible last accesses dep of w at l + * compute last iteration of w2 between the source and sink + * of dep + * add result to possible last accesses at level l of write w2 + * and replace possible last accesses dep by the remainder + * + * + * The above algorithm is applied to the must access. During the course + * of the algorithm, we keep track of sink iterations that still + * need to be considered. These iterations are split into those that + * haven't been matched to any source access (mustdo) and those that have only + * been matched to may accesses (maydo). + * At the end of each level, must-sources and may-sources that are coscheduled + * with the sources of the must-dependences at that level are considered. + * If any coscheduled instances are found, then corresponding may-dependences + * are added and the original must-dependences are turned into may-dependences. + * Afterwards, the may accesses that occur after must-dependence sources + * are considered. + * In particular, we consider may accesses that precede the remaining + * sink iterations, moving elements from mustdo to maydo when appropriate, + * and may accesses that occur between a must source and a sink of any + * dependences found at the current level, turning must dependences into + * may dependences when appropriate. + * + */ +static __isl_give isl_flow *compute_val_based_dependences( + __isl_keep isl_access_info *acc) +{ + isl_ctx *ctx; + isl_flow *res; + isl_set *mustdo = NULL; + isl_set *maydo = NULL; + int level, j; + int depth; + isl_map **must_rel = NULL; + isl_map **may_rel = NULL; + + if (!acc) + return NULL; + + res = isl_flow_alloc(acc); + if (!res) + goto error; + ctx = isl_map_get_ctx(acc->sink.map); + + depth = 2 * isl_map_dim(acc->sink.map, isl_dim_in) + 1; + mustdo = isl_map_domain(isl_map_copy(acc->sink.map)); + maydo = isl_set_empty(isl_set_get_space(mustdo)); + if (!mustdo || !maydo) + goto error; + if (isl_set_plain_is_empty(mustdo)) + goto done; + + must_rel = isl_calloc_array(ctx, struct isl_map *, acc->n_must); + may_rel = isl_calloc_array(ctx, struct isl_map *, acc->n_must); + if (!must_rel || !may_rel) + goto error; + + for (level = depth; level >= 1; --level) { + for (j = acc->n_must-1; j >=0; --j) { + isl_space *space; + space = isl_map_get_space(res->dep[2 * j].map); + must_rel[j] = isl_map_empty(space); + may_rel[j] = isl_map_copy(must_rel[j]); + } + + for (j = acc->n_must - 1; j >= 0; --j) { + struct isl_map *T; + struct isl_set *rest; + int plevel; + + plevel = acc->level_before(acc->source[j].data, + acc->sink.data); + if (plevel < 0) + goto error; + if (!can_precede_at_level(plevel, level)) + continue; + + T = last_source(acc, mustdo, j, level, &rest); + must_rel[j] = isl_map_union_disjoint(must_rel[j], T); + mustdo = rest; + + if (intermediate_sources(acc, must_rel, j, level) < 0) + goto error; + + T = last_source(acc, maydo, j, level, &rest); + may_rel[j] = isl_map_union_disjoint(may_rel[j], T); + maydo = rest; + + if (intermediate_sources(acc, may_rel, j, level) < 0) + goto error; + + if (isl_set_plain_is_empty(mustdo) && + isl_set_plain_is_empty(maydo)) + break; + } + for (j = j - 1; j >= 0; --j) { + int plevel; + + plevel = acc->level_before(acc->source[j].data, + acc->sink.data); + if (plevel < 0) + goto error; + if (!can_precede_at_level(plevel, level)) + continue; + + if (intermediate_sources(acc, must_rel, j, level) < 0) + goto error; + if (intermediate_sources(acc, may_rel, j, level) < 0) + goto error; + } + + handle_coscheduled(acc, must_rel, may_rel, res); + + for (j = 0; j < acc->n_may; ++j) { + int plevel; + isl_map *T; + isl_set *ran; + + plevel = acc->level_before(acc->source[acc->n_must + j].data, + acc->sink.data); + if (plevel < 0) + goto error; + if (!can_precede_at_level(plevel, level)) + continue; + + T = all_sources(acc, isl_set_copy(maydo), j, level); + res->dep[2 * acc->n_must + j].map = + isl_map_union(res->dep[2 * acc->n_must + j].map, T); + T = all_sources(acc, isl_set_copy(mustdo), j, level); + ran = isl_map_range(isl_map_copy(T)); + res->dep[2 * acc->n_must + j].map = + isl_map_union(res->dep[2 * acc->n_must + j].map, T); + mustdo = isl_set_subtract(mustdo, isl_set_copy(ran)); + maydo = isl_set_union_disjoint(maydo, ran); + + T = res->dep[2 * acc->n_must + j].map; + T = all_intermediate_sources(acc, T, must_rel, may_rel, + j, level); + res->dep[2 * acc->n_must + j].map = T; + } + + for (j = acc->n_must - 1; j >= 0; --j) { + res->dep[2 * j].map = + isl_map_union_disjoint(res->dep[2 * j].map, + must_rel[j]); + res->dep[2 * j + 1].map = + isl_map_union_disjoint(res->dep[2 * j + 1].map, + may_rel[j]); + } + + if (isl_set_plain_is_empty(mustdo) && + isl_set_plain_is_empty(maydo)) + break; + } + + free(must_rel); + free(may_rel); +done: + res->must_no_source = mustdo; + res->may_no_source = maydo; + return res; +error: + if (must_rel) + for (j = 0; j < acc->n_must; ++j) + isl_map_free(must_rel[j]); + if (may_rel) + for (j = 0; j < acc->n_must; ++j) + isl_map_free(may_rel[j]); + isl_flow_free(res); + isl_set_free(mustdo); + isl_set_free(maydo); + free(must_rel); + free(may_rel); + return NULL; +} + +/* Given a "sink" access, a list of n "source" accesses, + * compute for each iteration of the sink access + * and for each element accessed by that iteration, + * the source access in the list that last accessed the + * element accessed by the sink access before this sink access. + * Each access is given as a map from the loop iterators + * to the array indices. + * The result is a list of n relations between source and sink + * iterations and a subset of the domain of the sink access, + * corresponding to those iterations that access an element + * not previously accessed. + * + * To deal with multi-valued sink access relations, the sink iteration + * domain is first extended with dimensions that correspond to the data + * space. However, these extra dimensions are not projected out again. + * It is up to the caller to decide whether these dimensions should be kept. + */ +static __isl_give isl_flow *access_info_compute_flow_core( + __isl_take isl_access_info *acc) +{ + struct isl_flow *res = NULL; + + if (!acc) + return NULL; + + acc->sink.map = isl_map_range_map(acc->sink.map); + if (!acc->sink.map) + goto error; + + if (acc->n_must == 0) + res = compute_mem_based_dependences(acc); + else { + acc = isl_access_info_sort_sources(acc); + res = compute_val_based_dependences(acc); + } + acc = isl_access_info_free(acc); + if (!res) + return NULL; + if (!res->must_no_source || !res->may_no_source) + goto error; + return res; +error: + isl_access_info_free(acc); + isl_flow_free(res); + return NULL; +} + +/* Given a "sink" access, a list of n "source" accesses, + * compute for each iteration of the sink access + * and for each element accessed by that iteration, + * the source access in the list that last accessed the + * element accessed by the sink access before this sink access. + * Each access is given as a map from the loop iterators + * to the array indices. + * The result is a list of n relations between source and sink + * iterations and a subset of the domain of the sink access, + * corresponding to those iterations that access an element + * not previously accessed. + * + * To deal with multi-valued sink access relations, + * access_info_compute_flow_core extends the sink iteration domain + * with dimensions that correspond to the data space. These extra dimensions + * are projected out from the result of access_info_compute_flow_core. + */ +__isl_give isl_flow *isl_access_info_compute_flow(__isl_take isl_access_info *acc) +{ + int j; + struct isl_flow *res; + + if (!acc) + return NULL; + + acc->domain_map = isl_map_domain_map(isl_map_copy(acc->sink.map)); + res = access_info_compute_flow_core(acc); + if (!res) + return NULL; + + for (j = 0; j < res->n_source; ++j) { + res->dep[j].map = isl_map_range_factor_domain(res->dep[j].map); + if (!res->dep[j].map) + goto error; + } + + return res; +error: + isl_flow_free(res); + return NULL; +} + + +/* Keep track of some information about a schedule for a given + * access. In particular, keep track of which dimensions + * have a constant value and of the actual constant values. + */ +struct isl_sched_info { + int *is_cst; + isl_vec *cst; +}; + +static void sched_info_free(__isl_take struct isl_sched_info *info) +{ + if (!info) + return; + isl_vec_free(info->cst); + free(info->is_cst); + free(info); +} + +/* Extract information on the constant dimensions of the schedule + * for a given access. The "map" is of the form + * + * [S -> D] -> A + * + * with S the schedule domain, D the iteration domain and A the data domain. + */ +static __isl_give struct isl_sched_info *sched_info_alloc( + __isl_keep isl_map *map) +{ + isl_ctx *ctx; + isl_space *dim; + struct isl_sched_info *info; + int i, n; + + if (!map) + return NULL; + + dim = isl_space_unwrap(isl_space_domain(isl_map_get_space(map))); + if (!dim) + return NULL; + n = isl_space_dim(dim, isl_dim_in); + isl_space_free(dim); + + ctx = isl_map_get_ctx(map); + info = isl_alloc_type(ctx, struct isl_sched_info); + if (!info) + return NULL; + info->is_cst = isl_alloc_array(ctx, int, n); + info->cst = isl_vec_alloc(ctx, n); + if (n && (!info->is_cst || !info->cst)) + goto error; + + for (i = 0; i < n; ++i) { + isl_val *v; + + v = isl_map_plain_get_val_if_fixed(map, isl_dim_in, i); + if (!v) + goto error; + info->is_cst[i] = !isl_val_is_nan(v); + if (info->is_cst[i]) + info->cst = isl_vec_set_element_val(info->cst, i, v); + else + isl_val_free(v); + } + + return info; +error: + sched_info_free(info); + return NULL; +} + +/* The different types of access relations that isl_union_access_info + * keeps track of. + + * "isl_access_sink" represents the sink accesses. + * "isl_access_must_source" represents the definite source accesses. + * "isl_access_may_source" represents the possible source accesses. + * "isl_access_kill" represents the kills. + * + * isl_access_sink is sometimes treated differently and + * should therefore appear first. + */ +enum isl_access_type { + isl_access_sink, + isl_access_must_source, + isl_access_may_source, + isl_access_kill, + isl_access_end +}; + +/* This structure represents the input for a dependence analysis computation. + * + * "access" contains the access relations. + * + * "schedule" or "schedule_map" represents the execution order. + * Exactly one of these fields should be NULL. The other field + * determines the execution order. + * + * The domains of these four maps refer to the same iteration spaces(s). + * The ranges of the first three maps also refer to the same data space(s). + * + * After a call to isl_union_access_info_introduce_schedule, + * the "schedule_map" field no longer contains useful information. + */ +struct isl_union_access_info { + isl_union_map *access[isl_access_end]; + + isl_schedule *schedule; + isl_union_map *schedule_map; +}; + +/* Free "access" and return NULL. + */ +__isl_null isl_union_access_info *isl_union_access_info_free( + __isl_take isl_union_access_info *access) +{ + enum isl_access_type i; + + if (!access) + return NULL; + + for (i = isl_access_sink; i < isl_access_end; ++i) + isl_union_map_free(access->access[i]); + isl_schedule_free(access->schedule); + isl_union_map_free(access->schedule_map); + free(access); + + return NULL; +} + +/* Return the isl_ctx to which "access" belongs. + */ +isl_ctx *isl_union_access_info_get_ctx(__isl_keep isl_union_access_info *access) +{ + if (!access) + return NULL; + return isl_union_map_get_ctx(access->access[isl_access_sink]); +} + +/* Construct an empty (invalid) isl_union_access_info object. + * The caller is responsible for setting the sink access relation and + * initializing all the other fields, e.g., by calling + * isl_union_access_info_init. + */ +static __isl_give isl_union_access_info *isl_union_access_info_alloc( + isl_ctx *ctx) +{ + return isl_calloc_type(ctx, isl_union_access_info); +} + +/* Initialize all the fields of "info", except the sink access relation, + * which is assumed to have been set by the caller. + * + * By default, we use the schedule field of the isl_union_access_info, + * but this may be overridden by a call + * to isl_union_access_info_set_schedule_map. + */ +static __isl_give isl_union_access_info *isl_union_access_info_init( + __isl_take isl_union_access_info *info) +{ + isl_space *space; + isl_union_map *empty; + enum isl_access_type i; + + if (!info) + return NULL; + if (!info->access[isl_access_sink]) + return isl_union_access_info_free(info); + + space = isl_union_map_get_space(info->access[isl_access_sink]); + empty = isl_union_map_empty(isl_space_copy(space)); + for (i = isl_access_sink + 1; i < isl_access_end; ++i) + if (!info->access[i]) + info->access[i] = isl_union_map_copy(empty); + isl_union_map_free(empty); + if (!info->schedule && !info->schedule_map) + info->schedule = isl_schedule_empty(isl_space_copy(space)); + isl_space_free(space); + + for (i = isl_access_sink + 1; i < isl_access_end; ++i) + if (!info->access[i]) + return isl_union_access_info_free(info); + if (!info->schedule && !info->schedule_map) + return isl_union_access_info_free(info); + + return info; +} + +/* Create a new isl_union_access_info with the given sink accesses and + * and no other accesses or schedule information. + */ +__isl_give isl_union_access_info *isl_union_access_info_from_sink( + __isl_take isl_union_map *sink) +{ + isl_ctx *ctx; + isl_union_access_info *access; + + if (!sink) + return NULL; + ctx = isl_union_map_get_ctx(sink); + access = isl_union_access_info_alloc(ctx); + if (!access) + goto error; + access->access[isl_access_sink] = sink; + return isl_union_access_info_init(access); +error: + isl_union_map_free(sink); + return NULL; +} + +/* Replace the access relation of type "type" of "info" by "access". + */ +static __isl_give isl_union_access_info *isl_union_access_info_set( + __isl_take isl_union_access_info *info, + enum isl_access_type type, __isl_take isl_union_map *access) +{ + if (!info || !access) + goto error; + + isl_union_map_free(info->access[type]); + info->access[type] = access; + + return info; +error: + isl_union_access_info_free(info); + isl_union_map_free(access); + return NULL; +} + +/* Replace the definite source accesses of "access" by "must_source". + */ +__isl_give isl_union_access_info *isl_union_access_info_set_must_source( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *must_source) +{ + return isl_union_access_info_set(access, isl_access_must_source, + must_source); +} + +/* Replace the possible source accesses of "access" by "may_source". + */ +__isl_give isl_union_access_info *isl_union_access_info_set_may_source( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *may_source) +{ + return isl_union_access_info_set(access, isl_access_may_source, + may_source); +} + +/* Replace the kills of "info" by "kill". + */ +__isl_give isl_union_access_info *isl_union_access_info_set_kill( + __isl_take isl_union_access_info *info, __isl_take isl_union_map *kill) +{ + return isl_union_access_info_set(info, isl_access_kill, kill); +} + +/* Return the access relation of type "type" of "info". + */ +static __isl_give isl_union_map *isl_union_access_info_get( + __isl_keep isl_union_access_info *info, enum isl_access_type type) +{ + if (!info) + return NULL; + return isl_union_map_copy(info->access[type]); +} + +/* Return the definite source accesses of "info". + */ +__isl_give isl_union_map *isl_union_access_info_get_must_source( + __isl_keep isl_union_access_info *info) +{ + return isl_union_access_info_get(info, isl_access_must_source); +} + +/* Return the possible source accesses of "info". + */ +__isl_give isl_union_map *isl_union_access_info_get_may_source( + __isl_keep isl_union_access_info *info) +{ + return isl_union_access_info_get(info, isl_access_may_source); +} + +/* Return the kills of "info". + */ +__isl_give isl_union_map *isl_union_access_info_get_kill( + __isl_keep isl_union_access_info *info) +{ + return isl_union_access_info_get(info, isl_access_kill); +} + +/* Does "info" specify any kills? + */ +static isl_bool isl_union_access_has_kill( + __isl_keep isl_union_access_info *info) +{ + isl_bool empty; + + if (!info) + return isl_bool_error; + empty = isl_union_map_is_empty(info->access[isl_access_kill]); + return isl_bool_not(empty); +} + +/* Replace the schedule of "access" by "schedule". + * Also free the schedule_map in case it was set last. + */ +__isl_give isl_union_access_info *isl_union_access_info_set_schedule( + __isl_take isl_union_access_info *access, + __isl_take isl_schedule *schedule) +{ + if (!access || !schedule) + goto error; + + access->schedule_map = isl_union_map_free(access->schedule_map); + isl_schedule_free(access->schedule); + access->schedule = schedule; + + return access; +error: + isl_union_access_info_free(access); + isl_schedule_free(schedule); + return NULL; +} + +/* Replace the schedule map of "access" by "schedule_map". + * Also free the schedule in case it was set last. + */ +__isl_give isl_union_access_info *isl_union_access_info_set_schedule_map( + __isl_take isl_union_access_info *access, + __isl_take isl_union_map *schedule_map) +{ + if (!access || !schedule_map) + goto error; + + isl_union_map_free(access->schedule_map); + access->schedule = isl_schedule_free(access->schedule); + access->schedule_map = schedule_map; + + return access; +error: + isl_union_access_info_free(access); + isl_union_map_free(schedule_map); + return NULL; +} + +__isl_give isl_union_access_info *isl_union_access_info_copy( + __isl_keep isl_union_access_info *access) +{ + isl_union_access_info *copy; + enum isl_access_type i; + + if (!access) + return NULL; + copy = isl_union_access_info_from_sink( + isl_union_map_copy(access->access[isl_access_sink])); + for (i = isl_access_sink + 1; i < isl_access_end; ++i) + copy = isl_union_access_info_set(copy, i, + isl_union_map_copy(access->access[i])); + if (access->schedule) + copy = isl_union_access_info_set_schedule(copy, + isl_schedule_copy(access->schedule)); + else + copy = isl_union_access_info_set_schedule_map(copy, + isl_union_map_copy(access->schedule_map)); + + return copy; +} + +/* Print a key-value pair of a YAML mapping to "p", + * with key "name" and value "umap". + */ +static __isl_give isl_printer *print_union_map_field(__isl_take isl_printer *p, + const char *name, __isl_keep isl_union_map *umap) +{ + p = isl_printer_print_str(p, name); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_map(p, umap); + p = isl_printer_print_str(p, "\""); + p = isl_printer_yaml_next(p); + + return p; +} + +/* An enumeration of the various keys that may appear in a YAML mapping + * of an isl_union_access_info object. + * The keys for the access relation types are assumed to have the same values + * as the access relation types in isl_access_type. + */ +enum isl_ai_key { + isl_ai_key_error = -1, + isl_ai_key_sink = isl_access_sink, + isl_ai_key_must_source = isl_access_must_source, + isl_ai_key_may_source = isl_access_may_source, + isl_ai_key_kill = isl_access_kill, + isl_ai_key_schedule_map, + isl_ai_key_schedule, + isl_ai_key_end +}; + +/* Textual representations of the YAML keys for an isl_union_access_info + * object. + */ +static char *key_str[] = { + [isl_ai_key_sink] = "sink", + [isl_ai_key_must_source] = "must_source", + [isl_ai_key_may_source] = "may_source", + [isl_ai_key_kill] = "kill", + [isl_ai_key_schedule_map] = "schedule_map", + [isl_ai_key_schedule] = "schedule", +}; + +/* Print a key-value pair corresponding to the access relation of type "type" + * of a YAML mapping of "info" to "p". + * + * The sink access relation is always printed, but any other access relation + * is only printed if it is non-empty. + */ +static __isl_give isl_printer *print_access_field(__isl_take isl_printer *p, + __isl_keep isl_union_access_info *info, enum isl_access_type type) +{ + if (type != isl_access_sink) { + isl_bool empty; + + empty = isl_union_map_is_empty(info->access[type]); + if (empty < 0) + return isl_printer_free(p); + if (empty) + return p; + } + return print_union_map_field(p, key_str[type], info->access[type]); +} + +/* Print the information contained in "access" to "p". + * The information is printed as a YAML document. + */ +__isl_give isl_printer *isl_printer_print_union_access_info( + __isl_take isl_printer *p, __isl_keep isl_union_access_info *access) +{ + enum isl_access_type i; + + if (!access) + return isl_printer_free(p); + + p = isl_printer_yaml_start_mapping(p); + for (i = isl_access_sink; i < isl_access_end; ++i) + p = print_access_field(p, access, i); + if (access->schedule) { + p = isl_printer_print_str(p, key_str[isl_ai_key_schedule]); + p = isl_printer_yaml_next(p); + p = isl_printer_print_schedule(p, access->schedule); + p = isl_printer_yaml_next(p); + } else { + p = print_union_map_field(p, key_str[isl_ai_key_schedule_map], + access->schedule_map); + } + p = isl_printer_yaml_end_mapping(p); + + return p; +} + +/* Return a string representation of the information in "access". + * The information is printed in flow format. + */ +__isl_give char *isl_union_access_info_to_str( + __isl_keep isl_union_access_info *access) +{ + isl_printer *p; + char *s; + + if (!access) + return NULL; + + p = isl_printer_to_str(isl_union_access_info_get_ctx(access)); + p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW); + p = isl_printer_print_union_access_info(p, access); + s = isl_printer_get_str(p); + isl_printer_free(p); + + return s; +} + +#undef KEY +#define KEY enum isl_ai_key +#undef KEY_ERROR +#define KEY_ERROR isl_ai_key_error +#undef KEY_END +#define KEY_END isl_ai_key_end +#include "extract_key.c" + +#undef BASE +#define BASE union_map +#include "read_in_string_templ.c" + +/* Read an isl_union_access_info object from "s". + * + * Start off with an empty (invalid) isl_union_access_info object and + * then fill up the fields based on the input. + * The input needs to contain at least a description of the sink + * access relation as well as some form of schedule. + * The other access relations are set to empty relations + * by isl_union_access_info_init if they are not specified in the input. + */ +__isl_give isl_union_access_info *isl_stream_read_union_access_info( + isl_stream *s) +{ + isl_ctx *ctx; + isl_union_access_info *info; + int more; + int sink_set = 0; + int schedule_set = 0; + + if (isl_stream_yaml_read_start_mapping(s)) + return NULL; + + ctx = isl_stream_get_ctx(s); + info = isl_union_access_info_alloc(ctx); + while ((more = isl_stream_yaml_next(s)) > 0) { + enum isl_ai_key key; + isl_union_map *access, *schedule_map; + isl_schedule *schedule; + + key = get_key(s); + if (isl_stream_yaml_next(s) < 0) + return isl_union_access_info_free(info); + switch (key) { + case isl_ai_key_end: + case isl_ai_key_error: + return isl_union_access_info_free(info); + case isl_ai_key_sink: + sink_set = 1; + case isl_ai_key_must_source: + case isl_ai_key_may_source: + case isl_ai_key_kill: + access = read_union_map(s); + info = isl_union_access_info_set(info, key, access); + if (!info) + return NULL; + break; + case isl_ai_key_schedule_map: + schedule_set = 1; + schedule_map = read_union_map(s); + info = isl_union_access_info_set_schedule_map(info, + schedule_map); + if (!info) + return NULL; + break; + case isl_ai_key_schedule: + schedule_set = 1; + schedule = isl_stream_read_schedule(s); + info = isl_union_access_info_set_schedule(info, + schedule); + if (!info) + return NULL; + break; + } + } + if (more < 0) + return isl_union_access_info_free(info); + + if (isl_stream_yaml_read_end_mapping(s) < 0) { + isl_stream_error(s, NULL, "unexpected extra elements"); + return isl_union_access_info_free(info); + } + + if (!sink_set) { + isl_stream_error(s, NULL, "no sink specified"); + return isl_union_access_info_free(info); + } + + if (!schedule_set) { + isl_stream_error(s, NULL, "no schedule specified"); + return isl_union_access_info_free(info); + } + + return isl_union_access_info_init(info); +} + +/* Read an isl_union_access_info object from the file "input". + */ +__isl_give isl_union_access_info *isl_union_access_info_read_from_file( + isl_ctx *ctx, FILE *input) +{ + isl_stream *s; + isl_union_access_info *access; + + s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + access = isl_stream_read_union_access_info(s); + isl_stream_free(s); + + return access; +} + +/* Update the fields of "access" such that they all have the same parameters, + * keeping in mind that the schedule_map field may be NULL and ignoring + * the schedule field. + */ +static __isl_give isl_union_access_info *isl_union_access_info_align_params( + __isl_take isl_union_access_info *access) +{ + isl_space *space; + enum isl_access_type i; + + if (!access) + return NULL; + + space = isl_union_map_get_space(access->access[isl_access_sink]); + for (i = isl_access_sink + 1; i < isl_access_end; ++i) + space = isl_space_align_params(space, + isl_union_map_get_space(access->access[i])); + if (access->schedule_map) + space = isl_space_align_params(space, + isl_union_map_get_space(access->schedule_map)); + for (i = isl_access_sink; i < isl_access_end; ++i) + access->access[i] = + isl_union_map_align_params(access->access[i], + isl_space_copy(space)); + if (!access->schedule_map) { + isl_space_free(space); + } else { + access->schedule_map = + isl_union_map_align_params(access->schedule_map, space); + if (!access->schedule_map) + return isl_union_access_info_free(access); + } + + for (i = isl_access_sink; i < isl_access_end; ++i) + if (!access->access[i]) + return isl_union_access_info_free(access); + + return access; +} + +/* Prepend the schedule dimensions to the iteration domains. + * + * That is, if the schedule is of the form + * + * D -> S + * + * while the access relations are of the form + * + * D -> A + * + * then the updated access relations are of the form + * + * [S -> D] -> A + * + * The schedule map is also replaced by the map + * + * [S -> D] -> D + * + * that is used during the internal computation. + * Neither the original schedule map nor this updated schedule map + * are used after the call to this function. + */ +static __isl_give isl_union_access_info * +isl_union_access_info_introduce_schedule( + __isl_take isl_union_access_info *access) +{ + isl_union_map *sm; + enum isl_access_type i; + + if (!access) + return NULL; + + sm = isl_union_map_reverse(access->schedule_map); + sm = isl_union_map_range_map(sm); + for (i = isl_access_sink; i < isl_access_end; ++i) + access->access[i] = + isl_union_map_apply_range(isl_union_map_copy(sm), + access->access[i]); + access->schedule_map = sm; + + for (i = isl_access_sink; i < isl_access_end; ++i) + if (!access->access[i]) + return isl_union_access_info_free(access); + if (!access->schedule_map) + return isl_union_access_info_free(access); + + return access; +} + +/* This structure represents the result of a dependence analysis computation. + * + * "must_dep" represents the full definite dependences + * "may_dep" represents the full non-definite dependences. + * Both are of the form + * + * [Source] -> [[Sink -> Data]] + * + * (after the schedule dimensions have been projected out). + * "must_no_source" represents the subset of the sink accesses for which + * definitely no source was found. + * "may_no_source" represents the subset of the sink accesses for which + * possibly, but not definitely, no source was found. + */ +struct isl_union_flow { + isl_union_map *must_dep; + isl_union_map *may_dep; + isl_union_map *must_no_source; + isl_union_map *may_no_source; +}; + +/* Return the isl_ctx to which "flow" belongs. + */ +isl_ctx *isl_union_flow_get_ctx(__isl_keep isl_union_flow *flow) +{ + return flow ? isl_union_map_get_ctx(flow->must_dep) : NULL; +} + +/* Free "flow" and return NULL. + */ +__isl_null isl_union_flow *isl_union_flow_free(__isl_take isl_union_flow *flow) +{ + if (!flow) + return NULL; + isl_union_map_free(flow->must_dep); + isl_union_map_free(flow->may_dep); + isl_union_map_free(flow->must_no_source); + isl_union_map_free(flow->may_no_source); + free(flow); + return NULL; +} + +void isl_union_flow_dump(__isl_keep isl_union_flow *flow) +{ + if (!flow) + return; + + fprintf(stderr, "must dependences: "); + isl_union_map_dump(flow->must_dep); + fprintf(stderr, "may dependences: "); + isl_union_map_dump(flow->may_dep); + fprintf(stderr, "must no source: "); + isl_union_map_dump(flow->must_no_source); + fprintf(stderr, "may no source: "); + isl_union_map_dump(flow->may_no_source); +} + +/* Return the full definite dependences in "flow", with accessed elements. + */ +__isl_give isl_union_map *isl_union_flow_get_full_must_dependence( + __isl_keep isl_union_flow *flow) +{ + if (!flow) + return NULL; + return isl_union_map_copy(flow->must_dep); +} + +/* Return the full possible dependences in "flow", including the definite + * dependences, with accessed elements. + */ +__isl_give isl_union_map *isl_union_flow_get_full_may_dependence( + __isl_keep isl_union_flow *flow) +{ + if (!flow) + return NULL; + return isl_union_map_union(isl_union_map_copy(flow->must_dep), + isl_union_map_copy(flow->may_dep)); +} + +/* Return the definite dependences in "flow", without the accessed elements. + */ +__isl_give isl_union_map *isl_union_flow_get_must_dependence( + __isl_keep isl_union_flow *flow) +{ + isl_union_map *dep; + + if (!flow) + return NULL; + dep = isl_union_map_copy(flow->must_dep); + return isl_union_map_range_factor_domain(dep); +} + +/* Return the possible dependences in "flow", including the definite + * dependences, without the accessed elements. + */ +__isl_give isl_union_map *isl_union_flow_get_may_dependence( + __isl_keep isl_union_flow *flow) +{ + isl_union_map *dep; + + if (!flow) + return NULL; + dep = isl_union_map_union(isl_union_map_copy(flow->must_dep), + isl_union_map_copy(flow->may_dep)); + return isl_union_map_range_factor_domain(dep); +} + +/* Return the non-definite dependences in "flow". + */ +static __isl_give isl_union_map *isl_union_flow_get_non_must_dependence( + __isl_keep isl_union_flow *flow) +{ + if (!flow) + return NULL; + return isl_union_map_copy(flow->may_dep); +} + +/* Return the subset of the sink accesses for which definitely + * no source was found. + */ +__isl_give isl_union_map *isl_union_flow_get_must_no_source( + __isl_keep isl_union_flow *flow) +{ + if (!flow) + return NULL; + return isl_union_map_copy(flow->must_no_source); +} + +/* Return the subset of the sink accesses for which possibly + * no source was found, including those for which definitely + * no source was found. + */ +__isl_give isl_union_map *isl_union_flow_get_may_no_source( + __isl_keep isl_union_flow *flow) +{ + if (!flow) + return NULL; + return isl_union_map_union(isl_union_map_copy(flow->must_no_source), + isl_union_map_copy(flow->may_no_source)); +} + +/* Return the subset of the sink accesses for which possibly, but not + * definitely, no source was found. + */ +static __isl_give isl_union_map *isl_union_flow_get_non_must_no_source( + __isl_keep isl_union_flow *flow) +{ + if (!flow) + return NULL; + return isl_union_map_copy(flow->may_no_source); +} + +/* Create a new isl_union_flow object, initialized with empty + * dependence relations and sink subsets. + */ +static __isl_give isl_union_flow *isl_union_flow_alloc( + __isl_take isl_space *space) +{ + isl_ctx *ctx; + isl_union_map *empty; + isl_union_flow *flow; + + if (!space) + return NULL; + ctx = isl_space_get_ctx(space); + flow = isl_alloc_type(ctx, isl_union_flow); + if (!flow) + goto error; + + empty = isl_union_map_empty(space); + flow->must_dep = isl_union_map_copy(empty); + flow->may_dep = isl_union_map_copy(empty); + flow->must_no_source = isl_union_map_copy(empty); + flow->may_no_source = empty; + + if (!flow->must_dep || !flow->may_dep || + !flow->must_no_source || !flow->may_no_source) + return isl_union_flow_free(flow); + + return flow; +error: + isl_space_free(space); + return NULL; +} + +/* Copy this isl_union_flow object. + */ +__isl_give isl_union_flow *isl_union_flow_copy(__isl_keep isl_union_flow *flow) +{ + isl_union_flow *copy; + + if (!flow) + return NULL; + + copy = isl_union_flow_alloc(isl_union_map_get_space(flow->must_dep)); + + if (!copy) + return NULL; + + copy->must_dep = isl_union_map_union(copy->must_dep, + isl_union_map_copy(flow->must_dep)); + copy->may_dep = isl_union_map_union(copy->may_dep, + isl_union_map_copy(flow->may_dep)); + copy->must_no_source = isl_union_map_union(copy->must_no_source, + isl_union_map_copy(flow->must_no_source)); + copy->may_no_source = isl_union_map_union(copy->may_no_source, + isl_union_map_copy(flow->may_no_source)); + + if (!copy->must_dep || !copy->may_dep || + !copy->must_no_source || !copy->may_no_source) + return isl_union_flow_free(copy); + + return copy; +} + +/* Drop the schedule dimensions from the iteration domains in "flow". + * In particular, the schedule dimensions have been prepended + * to the iteration domains prior to the dependence analysis by + * replacing the iteration domain D, by the wrapped map [S -> D]. + * Replace these wrapped maps by the original D. + * + * In particular, the dependences computed by access_info_compute_flow_core + * are of the form + * + * [S -> D] -> [[S' -> D'] -> A] + * + * The schedule dimensions are projected out by first currying the range, + * resulting in + * + * [S -> D] -> [S' -> [D' -> A]] + * + * and then computing the factor range + * + * D -> [D' -> A] + */ +static __isl_give isl_union_flow *isl_union_flow_drop_schedule( + __isl_take isl_union_flow *flow) +{ + if (!flow) + return NULL; + + flow->must_dep = isl_union_map_range_curry(flow->must_dep); + flow->must_dep = isl_union_map_factor_range(flow->must_dep); + flow->may_dep = isl_union_map_range_curry(flow->may_dep); + flow->may_dep = isl_union_map_factor_range(flow->may_dep); + flow->must_no_source = + isl_union_map_domain_factor_range(flow->must_no_source); + flow->may_no_source = + isl_union_map_domain_factor_range(flow->may_no_source); + + if (!flow->must_dep || !flow->may_dep || + !flow->must_no_source || !flow->may_no_source) + return isl_union_flow_free(flow); + + return flow; +} + +struct isl_compute_flow_data { + isl_union_map *must_source; + isl_union_map *may_source; + isl_union_flow *flow; + + int count; + int must; + isl_space *dim; + struct isl_sched_info *sink_info; + struct isl_sched_info **source_info; + isl_access_info *accesses; +}; + +static isl_stat count_matching_array(__isl_take isl_map *map, void *user) +{ + int eq; + isl_space *dim; + struct isl_compute_flow_data *data; + + data = (struct isl_compute_flow_data *)user; + + dim = isl_space_range(isl_map_get_space(map)); + + eq = isl_space_is_equal(dim, data->dim); + + isl_space_free(dim); + isl_map_free(map); + + if (eq < 0) + return isl_stat_error; + if (eq) + data->count++; + + return isl_stat_ok; +} + +static isl_stat collect_matching_array(__isl_take isl_map *map, void *user) +{ + int eq; + isl_space *dim; + struct isl_sched_info *info; + struct isl_compute_flow_data *data; + + data = (struct isl_compute_flow_data *)user; + + dim = isl_space_range(isl_map_get_space(map)); + + eq = isl_space_is_equal(dim, data->dim); + + isl_space_free(dim); + + if (eq < 0) + goto error; + if (!eq) { + isl_map_free(map); + return isl_stat_ok; + } + + info = sched_info_alloc(map); + data->source_info[data->count] = info; + + data->accesses = isl_access_info_add_source(data->accesses, + map, data->must, info); + + data->count++; + + return isl_stat_ok; +error: + isl_map_free(map); + return isl_stat_error; +} + +/* Determine the shared nesting level and the "textual order" of + * the given accesses. + * + * We first determine the minimal schedule dimension for both accesses. + * + * If among those dimensions, we can find one where both have a fixed + * value and if moreover those values are different, then the previous + * dimension is the last shared nesting level and the textual order + * is determined based on the order of the fixed values. + * If no such fixed values can be found, then we set the shared + * nesting level to the minimal schedule dimension, with no textual ordering. + */ +static int before(void *first, void *second) +{ + struct isl_sched_info *info1 = first; + struct isl_sched_info *info2 = second; + int n1, n2; + int i; + + n1 = isl_vec_size(info1->cst); + n2 = isl_vec_size(info2->cst); + + if (n2 < n1) + n1 = n2; + + for (i = 0; i < n1; ++i) { + int r; + int cmp; + + if (!info1->is_cst[i]) + continue; + if (!info2->is_cst[i]) + continue; + cmp = isl_vec_cmp_element(info1->cst, info2->cst, i); + if (cmp == 0) + continue; + + r = 2 * i + (cmp < 0); + + return r; + } + + return 2 * n1; +} + +/* Check if the given two accesses may be coscheduled. + * If so, return 1. Otherwise return 0. + * + * Two accesses may only be coscheduled if the fixed schedule + * coordinates have the same values. + */ +static int coscheduled(void *first, void *second) +{ + struct isl_sched_info *info1 = first; + struct isl_sched_info *info2 = second; + int n1, n2; + int i; + + n1 = isl_vec_size(info1->cst); + n2 = isl_vec_size(info2->cst); + + if (n2 < n1) + n1 = n2; + + for (i = 0; i < n1; ++i) { + int cmp; + + if (!info1->is_cst[i]) + continue; + if (!info2->is_cst[i]) + continue; + cmp = isl_vec_cmp_element(info1->cst, info2->cst, i); + if (cmp != 0) + return 0; + } + + return 1; +} + +/* Given a sink access, look for all the source accesses that access + * the same array and perform dataflow analysis on them using + * isl_access_info_compute_flow_core. + */ +static isl_stat compute_flow(__isl_take isl_map *map, void *user) +{ + int i; + isl_ctx *ctx; + struct isl_compute_flow_data *data; + isl_flow *flow; + isl_union_flow *df; + + data = (struct isl_compute_flow_data *)user; + df = data->flow; + + ctx = isl_map_get_ctx(map); + + data->accesses = NULL; + data->sink_info = NULL; + data->source_info = NULL; + data->count = 0; + data->dim = isl_space_range(isl_map_get_space(map)); + + if (isl_union_map_foreach_map(data->must_source, + &count_matching_array, data) < 0) + goto error; + if (isl_union_map_foreach_map(data->may_source, + &count_matching_array, data) < 0) + goto error; + + data->sink_info = sched_info_alloc(map); + data->source_info = isl_calloc_array(ctx, struct isl_sched_info *, + data->count); + + data->accesses = isl_access_info_alloc(isl_map_copy(map), + data->sink_info, &before, data->count); + if (!data->sink_info || (data->count && !data->source_info) || + !data->accesses) + goto error; + data->accesses->coscheduled = &coscheduled; + data->count = 0; + data->must = 1; + if (isl_union_map_foreach_map(data->must_source, + &collect_matching_array, data) < 0) + goto error; + data->must = 0; + if (isl_union_map_foreach_map(data->may_source, + &collect_matching_array, data) < 0) + goto error; + + flow = access_info_compute_flow_core(data->accesses); + data->accesses = NULL; + + if (!flow) + goto error; + + df->must_no_source = isl_union_map_union(df->must_no_source, + isl_union_map_from_map(isl_flow_get_no_source(flow, 1))); + df->may_no_source = isl_union_map_union(df->may_no_source, + isl_union_map_from_map(isl_flow_get_no_source(flow, 0))); + + for (i = 0; i < flow->n_source; ++i) { + isl_union_map *dep; + dep = isl_union_map_from_map(isl_map_copy(flow->dep[i].map)); + if (flow->dep[i].must) + df->must_dep = isl_union_map_union(df->must_dep, dep); + else + df->may_dep = isl_union_map_union(df->may_dep, dep); + } + + isl_flow_free(flow); + + sched_info_free(data->sink_info); + if (data->source_info) { + for (i = 0; i < data->count; ++i) + sched_info_free(data->source_info[i]); + free(data->source_info); + } + isl_space_free(data->dim); + isl_map_free(map); + + return isl_stat_ok; +error: + isl_access_info_free(data->accesses); + sched_info_free(data->sink_info); + if (data->source_info) { + for (i = 0; i < data->count; ++i) + sched_info_free(data->source_info[i]); + free(data->source_info); + } + isl_space_free(data->dim); + isl_map_free(map); + + return isl_stat_error; +} + +/* Add the kills of "info" to the must-sources. + */ +static __isl_give isl_union_access_info * +isl_union_access_info_add_kill_to_must_source( + __isl_take isl_union_access_info *info) +{ + isl_union_map *must, *kill; + + must = isl_union_access_info_get_must_source(info); + kill = isl_union_access_info_get_kill(info); + must = isl_union_map_union(must, kill); + return isl_union_access_info_set_must_source(info, must); +} + +/* Drop dependences from "flow" that purely originate from kills. + * That is, only keep those dependences that originate from + * the original must-sources "must" and/or the original may-sources "may". + * In particular, "must" contains the must-sources from before + * the kills were added and "may" contains the may-source from before + * the kills were removed. + * + * The dependences are of the form + * + * Source -> [Sink -> Data] + * + * Only those dependences are kept where the Source -> Data part + * is a subset of the original may-sources or must-sources. + * Of those, only the must-dependences that intersect with the must-sources + * remain must-dependences. + * If there is some overlap between the may-sources and the must-sources, + * then the may-dependences and must-dependences may also overlap. + * This should be fine since the may-dependences are only kept + * disjoint from the must-dependences for the isl_union_map_compute_flow + * interface. This interface does not support kills, so it will + * not end up calling this function. + */ +static __isl_give isl_union_flow *isl_union_flow_drop_kill_source( + __isl_take isl_union_flow *flow, __isl_take isl_union_map *must, + __isl_take isl_union_map *may) +{ + isl_union_map *move; + + if (!flow) + goto error; + move = isl_union_map_copy(flow->must_dep); + move = isl_union_map_intersect_range_factor_range(move, + isl_union_map_copy(may)); + may = isl_union_map_union(may, isl_union_map_copy(must)); + flow->may_dep = isl_union_map_intersect_range_factor_range( + flow->may_dep, may); + flow->must_dep = isl_union_map_intersect_range_factor_range( + flow->must_dep, must); + flow->may_dep = isl_union_map_union(flow->may_dep, move); + if (!flow->must_dep || !flow->may_dep) + return isl_union_flow_free(flow); + + return flow; +error: + isl_union_map_free(must); + isl_union_map_free(may); + return NULL; +} + +/* Remove the must accesses from the may accesses. + * + * A must access always trumps a may access, so there is no need + * for a must access to also be considered as a may access. Doing so + * would only cost extra computations only to find out that + * the duplicated may access does not make any difference. + */ +static __isl_give isl_union_access_info *isl_union_access_info_normalize( + __isl_take isl_union_access_info *access) +{ + if (!access) + return NULL; + access->access[isl_access_may_source] = + isl_union_map_subtract(access->access[isl_access_may_source], + isl_union_map_copy(access->access[isl_access_must_source])); + if (!access->access[isl_access_may_source]) + return isl_union_access_info_free(access); + + return access; +} + +/* Given a description of the "sink" accesses, the "source" accesses and + * a schedule, compute for each instance of a sink access + * and for each element accessed by that instance, + * the possible or definite source accesses that last accessed the + * element accessed by the sink access before this sink access + * in the sense that there is no intermediate definite source access. + * + * The must_no_source and may_no_source elements of the result + * are subsets of access->sink. The elements must_dep and may_dep + * map domain elements of access->{may,must)_source to + * domain elements of access->sink. + * + * This function is used when only the schedule map representation + * is available. + * + * We first prepend the schedule dimensions to the domain + * of the accesses so that we can easily compare their relative order. + * Then we consider each sink access individually in compute_flow. + */ +static __isl_give isl_union_flow *compute_flow_union_map( + __isl_take isl_union_access_info *access) +{ + struct isl_compute_flow_data data; + isl_union_map *sink; + + access = isl_union_access_info_align_params(access); + access = isl_union_access_info_introduce_schedule(access); + if (!access) + return NULL; + + data.must_source = access->access[isl_access_must_source]; + data.may_source = access->access[isl_access_may_source]; + + sink = access->access[isl_access_sink]; + data.flow = isl_union_flow_alloc(isl_union_map_get_space(sink)); + + if (isl_union_map_foreach_map(sink, &compute_flow, &data) < 0) + goto error; + + data.flow = isl_union_flow_drop_schedule(data.flow); + + isl_union_access_info_free(access); + return data.flow; +error: + isl_union_access_info_free(access); + isl_union_flow_free(data.flow); + return NULL; +} + +/* A schedule access relation. + * + * The access relation "access" is of the form [S -> D] -> A, + * where S corresponds to the prefix schedule at "node". + * "must" is only relevant for source accesses and indicates + * whether the access is a must source or a may source. + */ +struct isl_scheduled_access { + isl_map *access; + int must; + isl_schedule_node *node; +}; + +/* Data structure for keeping track of individual scheduled sink and source + * accesses when computing dependence analysis based on a schedule tree. + * + * "n_sink" is the number of used entries in "sink" + * "n_source" is the number of used entries in "source" + * + * "set_sink", "must" and "node" are only used inside collect_sink_source, + * to keep track of the current node and + * of what extract_sink_source needs to do. + */ +struct isl_compute_flow_schedule_data { + isl_union_access_info *access; + + int n_sink; + int n_source; + + struct isl_scheduled_access *sink; + struct isl_scheduled_access *source; + + int set_sink; + int must; + isl_schedule_node *node; +}; + +/* Align the parameters of all sinks with all sources. + * + * If there are no sinks or no sources, then no alignment is needed. + */ +static void isl_compute_flow_schedule_data_align_params( + struct isl_compute_flow_schedule_data *data) +{ + int i; + isl_space *space; + + if (data->n_sink == 0 || data->n_source == 0) + return; + + space = isl_map_get_space(data->sink[0].access); + + for (i = 1; i < data->n_sink; ++i) + space = isl_space_align_params(space, + isl_map_get_space(data->sink[i].access)); + for (i = 0; i < data->n_source; ++i) + space = isl_space_align_params(space, + isl_map_get_space(data->source[i].access)); + + for (i = 0; i < data->n_sink; ++i) + data->sink[i].access = + isl_map_align_params(data->sink[i].access, + isl_space_copy(space)); + for (i = 0; i < data->n_source; ++i) + data->source[i].access = + isl_map_align_params(data->source[i].access, + isl_space_copy(space)); + + isl_space_free(space); +} + +/* Free all the memory referenced from "data". + * Do not free "data" itself as it may be allocated on the stack. + */ +static void isl_compute_flow_schedule_data_clear( + struct isl_compute_flow_schedule_data *data) +{ + int i; + + if (!data->sink) + return; + + for (i = 0; i < data->n_sink; ++i) { + isl_map_free(data->sink[i].access); + isl_schedule_node_free(data->sink[i].node); + } + + for (i = 0; i < data->n_source; ++i) { + isl_map_free(data->source[i].access); + isl_schedule_node_free(data->source[i].node); + } + + free(data->sink); +} + +/* isl_schedule_foreach_schedule_node_top_down callback for counting + * (an upper bound on) the number of sinks and sources. + * + * Sinks and sources are only extracted at leaves of the tree, + * so we skip the node if it is not a leaf. + * Otherwise we increment data->n_sink and data->n_source with + * the number of spaces in the sink and source access domains + * that reach this node. + */ +static isl_bool count_sink_source(__isl_keep isl_schedule_node *node, + void *user) +{ + struct isl_compute_flow_schedule_data *data = user; + isl_union_set *domain; + isl_union_map *umap; + isl_bool r = isl_bool_false; + + if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf) + return isl_bool_true; + + domain = isl_schedule_node_get_universe_domain(node); + + umap = isl_union_map_copy(data->access->access[isl_access_sink]); + umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain)); + data->n_sink += isl_union_map_n_map(umap); + isl_union_map_free(umap); + if (!umap) + r = isl_bool_error; + + umap = isl_union_map_copy(data->access->access[isl_access_must_source]); + umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain)); + data->n_source += isl_union_map_n_map(umap); + isl_union_map_free(umap); + if (!umap) + r = isl_bool_error; + + umap = isl_union_map_copy(data->access->access[isl_access_may_source]); + umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain)); + data->n_source += isl_union_map_n_map(umap); + isl_union_map_free(umap); + if (!umap) + r = isl_bool_error; + + isl_union_set_free(domain); + + return r; +} + +/* Add a single scheduled sink or source (depending on data->set_sink) + * with scheduled access relation "map", must property data->must and + * schedule node data->node to the list of sinks or sources. + */ +static isl_stat extract_sink_source(__isl_take isl_map *map, void *user) +{ + struct isl_compute_flow_schedule_data *data = user; + struct isl_scheduled_access *access; + + if (data->set_sink) + access = data->sink + data->n_sink++; + else + access = data->source + data->n_source++; + + access->access = map; + access->must = data->must; + access->node = isl_schedule_node_copy(data->node); + + return isl_stat_ok; +} + +/* isl_schedule_foreach_schedule_node_top_down callback for collecting + * individual scheduled source and sink accesses (taking into account + * the domain of the schedule). + * + * We only collect accesses at the leaves of the schedule tree. + * We prepend the schedule dimensions at the leaf to the iteration + * domains of the source and sink accesses and then extract + * the individual accesses (per space). + * + * In particular, if the prefix schedule at the node is of the form + * + * D -> S + * + * while the access relations are of the form + * + * D -> A + * + * then the updated access relations are of the form + * + * [S -> D] -> A + * + * Note that S consists of a single space such that introducing S + * in the access relations does not increase the number of spaces. + */ +static isl_bool collect_sink_source(__isl_keep isl_schedule_node *node, + void *user) +{ + struct isl_compute_flow_schedule_data *data = user; + isl_union_map *prefix; + isl_union_map *umap; + isl_bool r = isl_bool_false; + + if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf) + return isl_bool_true; + + data->node = node; + + prefix = isl_schedule_node_get_prefix_schedule_relation(node); + prefix = isl_union_map_reverse(prefix); + prefix = isl_union_map_range_map(prefix); + + data->set_sink = 1; + umap = isl_union_map_copy(data->access->access[isl_access_sink]); + umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap); + if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0) + r = isl_bool_error; + isl_union_map_free(umap); + + data->set_sink = 0; + data->must = 1; + umap = isl_union_map_copy(data->access->access[isl_access_must_source]); + umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap); + if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0) + r = isl_bool_error; + isl_union_map_free(umap); + + data->set_sink = 0; + data->must = 0; + umap = isl_union_map_copy(data->access->access[isl_access_may_source]); + umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap); + if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0) + r = isl_bool_error; + isl_union_map_free(umap); + + isl_union_map_free(prefix); + + return r; +} + +/* isl_access_info_compute_flow callback for determining whether + * the shared nesting level and the ordering within that level + * for two scheduled accesses for use in compute_single_flow. + * + * The tokens passed to this function refer to the leaves + * in the schedule tree where the accesses take place. + * + * If n is the shared number of loops, then we need to return + * "2 * n + 1" if "first" precedes "second" inside the innermost + * shared loop and "2 * n" otherwise. + * + * The innermost shared ancestor may be the leaves themselves + * if the accesses take place in the same leaf. Otherwise, + * it is either a set node or a sequence node. Only in the case + * of a sequence node do we consider one access to precede the other. + */ +static int before_node(void *first, void *second) +{ + isl_schedule_node *node1 = first; + isl_schedule_node *node2 = second; + isl_schedule_node *shared; + int depth; + int before = 0; + + shared = isl_schedule_node_get_shared_ancestor(node1, node2); + if (!shared) + return -1; + + depth = isl_schedule_node_get_schedule_depth(shared); + if (isl_schedule_node_get_type(shared) == isl_schedule_node_sequence) { + int pos1, pos2; + + pos1 = isl_schedule_node_get_ancestor_child_position(node1, + shared); + pos2 = isl_schedule_node_get_ancestor_child_position(node2, + shared); + before = pos1 < pos2; + } + + isl_schedule_node_free(shared); + + return 2 * depth + before; +} + +/* Check if the given two accesses may be coscheduled. + * If so, return 1. Otherwise return 0. + * + * Two accesses may only be coscheduled if they appear in the same leaf. + */ +static int coscheduled_node(void *first, void *second) +{ + isl_schedule_node *node1 = first; + isl_schedule_node *node2 = second; + + return node1 == node2; +} + +/* Add the scheduled sources from "data" that access + * the same data space as "sink" to "access". + */ +static __isl_give isl_access_info *add_matching_sources( + __isl_take isl_access_info *access, struct isl_scheduled_access *sink, + struct isl_compute_flow_schedule_data *data) +{ + int i; + isl_space *space; + + space = isl_space_range(isl_map_get_space(sink->access)); + for (i = 0; i < data->n_source; ++i) { + struct isl_scheduled_access *source; + isl_space *source_space; + int eq; + + source = &data->source[i]; + source_space = isl_map_get_space(source->access); + source_space = isl_space_range(source_space); + eq = isl_space_is_equal(space, source_space); + isl_space_free(source_space); + + if (!eq) + continue; + if (eq < 0) + goto error; + + access = isl_access_info_add_source(access, + isl_map_copy(source->access), source->must, source->node); + } + + isl_space_free(space); + return access; +error: + isl_space_free(space); + isl_access_info_free(access); + return NULL; +} + +/* Given a scheduled sink access relation "sink", compute the corresponding + * dependences on the sources in "data" and add the computed dependences + * to "uf". + * + * The dependences computed by access_info_compute_flow_core are of the form + * + * [S -> I] -> [[S' -> I'] -> A] + * + * The schedule dimensions are projected out by first currying the range, + * resulting in + * + * [S -> I] -> [S' -> [I' -> A]] + * + * and then computing the factor range + * + * I -> [I' -> A] + */ +static __isl_give isl_union_flow *compute_single_flow( + __isl_take isl_union_flow *uf, struct isl_scheduled_access *sink, + struct isl_compute_flow_schedule_data *data) +{ + int i; + isl_access_info *access; + isl_flow *flow; + isl_map *map; + + if (!uf) + return NULL; + + access = isl_access_info_alloc(isl_map_copy(sink->access), sink->node, + &before_node, data->n_source); + if (access) + access->coscheduled = &coscheduled_node; + access = add_matching_sources(access, sink, data); + + flow = access_info_compute_flow_core(access); + if (!flow) + return isl_union_flow_free(uf); + + map = isl_map_domain_factor_range(isl_flow_get_no_source(flow, 1)); + uf->must_no_source = isl_union_map_union(uf->must_no_source, + isl_union_map_from_map(map)); + map = isl_map_domain_factor_range(isl_flow_get_no_source(flow, 0)); + uf->may_no_source = isl_union_map_union(uf->may_no_source, + isl_union_map_from_map(map)); + + for (i = 0; i < flow->n_source; ++i) { + isl_union_map *dep; + + map = isl_map_range_curry(isl_map_copy(flow->dep[i].map)); + map = isl_map_factor_range(map); + dep = isl_union_map_from_map(map); + if (flow->dep[i].must) + uf->must_dep = isl_union_map_union(uf->must_dep, dep); + else + uf->may_dep = isl_union_map_union(uf->may_dep, dep); + } + + isl_flow_free(flow); + + return uf; +} + +/* Given a description of the "sink" accesses, the "source" accesses and + * a schedule, compute for each instance of a sink access + * and for each element accessed by that instance, + * the possible or definite source accesses that last accessed the + * element accessed by the sink access before this sink access + * in the sense that there is no intermediate definite source access. + * Only consider dependences between statement instances that belong + * to the domain of the schedule. + * + * The must_no_source and may_no_source elements of the result + * are subsets of access->sink. The elements must_dep and may_dep + * map domain elements of access->{may,must)_source to + * domain elements of access->sink. + * + * This function is used when a schedule tree representation + * is available. + * + * We extract the individual scheduled source and sink access relations + * (taking into account the domain of the schedule) and + * then compute dependences for each scheduled sink individually. + */ +static __isl_give isl_union_flow *compute_flow_schedule( + __isl_take isl_union_access_info *access) +{ + struct isl_compute_flow_schedule_data data = { access }; + int i, n; + isl_ctx *ctx; + isl_space *space; + isl_union_flow *flow; + + ctx = isl_union_access_info_get_ctx(access); + + data.n_sink = 0; + data.n_source = 0; + if (isl_schedule_foreach_schedule_node_top_down(access->schedule, + &count_sink_source, &data) < 0) + goto error; + + n = data.n_sink + data.n_source; + data.sink = isl_calloc_array(ctx, struct isl_scheduled_access, n); + if (n && !data.sink) + goto error; + data.source = data.sink + data.n_sink; + + data.n_sink = 0; + data.n_source = 0; + if (isl_schedule_foreach_schedule_node_top_down(access->schedule, + &collect_sink_source, &data) < 0) + goto error; + + space = isl_union_map_get_space(access->access[isl_access_sink]); + flow = isl_union_flow_alloc(space); + + isl_compute_flow_schedule_data_align_params(&data); + + for (i = 0; i < data.n_sink; ++i) + flow = compute_single_flow(flow, &data.sink[i], &data); + + isl_compute_flow_schedule_data_clear(&data); + + isl_union_access_info_free(access); + return flow; +error: + isl_union_access_info_free(access); + isl_compute_flow_schedule_data_clear(&data); + return NULL; +} + +/* Given a description of the "sink" accesses, the "source" accesses and + * a schedule, compute for each instance of a sink access + * and for each element accessed by that instance, + * the possible or definite source accesses that last accessed the + * element accessed by the sink access before this sink access + * in the sense that there is no intermediate definite source access. + * + * The must_no_source and may_no_source elements of the result + * are subsets of access->sink. The elements must_dep and may_dep + * map domain elements of access->{may,must)_source to + * domain elements of access->sink. + * + * If any kills have been specified, then they are treated as + * must-sources internally. Any dependence that purely derives + * from an original kill is removed from the output. + * + * We check whether the schedule is available as a schedule tree + * or a schedule map and call the corresponding function to perform + * the analysis. + */ +__isl_give isl_union_flow *isl_union_access_info_compute_flow( + __isl_take isl_union_access_info *access) +{ + isl_bool has_kill; + isl_union_map *must = NULL, *may = NULL; + isl_union_flow *flow; + + has_kill = isl_union_access_has_kill(access); + if (has_kill < 0) + goto error; + if (has_kill) { + must = isl_union_access_info_get_must_source(access); + may = isl_union_access_info_get_may_source(access); + } + access = isl_union_access_info_add_kill_to_must_source(access); + access = isl_union_access_info_normalize(access); + if (!access) + goto error; + if (access->schedule) + flow = compute_flow_schedule(access); + else + flow = compute_flow_union_map(access); + if (has_kill) + flow = isl_union_flow_drop_kill_source(flow, must, may); + return flow; +error: + isl_union_access_info_free(access); + isl_union_map_free(must); + isl_union_map_free(may); + return NULL; +} + +/* Print the information contained in "flow" to "p". + * The information is printed as a YAML document. + */ +__isl_give isl_printer *isl_printer_print_union_flow( + __isl_take isl_printer *p, __isl_keep isl_union_flow *flow) +{ + isl_union_map *umap; + + if (!flow) + return isl_printer_free(p); + + p = isl_printer_yaml_start_mapping(p); + umap = isl_union_flow_get_full_must_dependence(flow); + p = print_union_map_field(p, "must_dependence", umap); + isl_union_map_free(umap); + umap = isl_union_flow_get_full_may_dependence(flow); + p = print_union_map_field(p, "may_dependence", umap); + isl_union_map_free(umap); + p = print_union_map_field(p, "must_no_source", flow->must_no_source); + umap = isl_union_flow_get_may_no_source(flow); + p = print_union_map_field(p, "may_no_source", umap); + isl_union_map_free(umap); + p = isl_printer_yaml_end_mapping(p); + + return p; +} + +/* Return a string representation of the information in "flow". + * The information is printed in flow format. + */ +__isl_give char *isl_union_flow_to_str(__isl_keep isl_union_flow *flow) +{ + isl_printer *p; + char *s; + + if (!flow) + return NULL; + + p = isl_printer_to_str(isl_union_flow_get_ctx(flow)); + p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW); + p = isl_printer_print_union_flow(p, flow); + s = isl_printer_get_str(p); + isl_printer_free(p); + + return s; +} + +/* Given a collection of "sink" and "source" accesses, + * compute for each iteration of a sink access + * and for each element accessed by that iteration, + * the source access in the list that last accessed the + * element accessed by the sink access before this sink access. + * Each access is given as a map from the loop iterators + * to the array indices. + * The result is a relations between source and sink + * iterations and a subset of the domain of the sink accesses, + * corresponding to those iterations that access an element + * not previously accessed. + * + * We collect the inputs in an isl_union_access_info object, + * call isl_union_access_info_compute_flow and extract + * the outputs from the result. + */ +int isl_union_map_compute_flow(__isl_take isl_union_map *sink, + __isl_take isl_union_map *must_source, + __isl_take isl_union_map *may_source, + __isl_take isl_union_map *schedule, + __isl_give isl_union_map **must_dep, __isl_give isl_union_map **may_dep, + __isl_give isl_union_map **must_no_source, + __isl_give isl_union_map **may_no_source) +{ + isl_union_access_info *access; + isl_union_flow *flow; + + access = isl_union_access_info_from_sink(sink); + access = isl_union_access_info_set_must_source(access, must_source); + access = isl_union_access_info_set_may_source(access, may_source); + access = isl_union_access_info_set_schedule_map(access, schedule); + flow = isl_union_access_info_compute_flow(access); + + if (must_dep) + *must_dep = isl_union_flow_get_must_dependence(flow); + if (may_dep) + *may_dep = isl_union_flow_get_non_must_dependence(flow); + if (must_no_source) + *must_no_source = isl_union_flow_get_must_no_source(flow); + if (may_no_source) + *may_no_source = isl_union_flow_get_non_must_no_source(flow); + + isl_union_flow_free(flow); + + if ((must_dep && !*must_dep) || (may_dep && !*may_dep) || + (must_no_source && !*must_no_source) || + (may_no_source && !*may_no_source)) + goto error; + + return 0; +error: + if (must_dep) + *must_dep = isl_union_map_free(*must_dep); + if (may_dep) + *may_dep = isl_union_map_free(*may_dep); + if (must_no_source) + *must_no_source = isl_union_map_free(*must_no_source); + if (may_no_source) + *may_no_source = isl_union_map_free(*may_no_source); + return -1; +} Index: contrib/isl/isl_fold.c =================================================================== --- /dev/null +++ contrib/isl/isl_fold.c @@ -0,0 +1,1794 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#define ISL_DIM_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum isl_fold isl_fold_type_negate(enum isl_fold type) +{ + switch (type) { + case isl_fold_min: + return isl_fold_max; + case isl_fold_max: + return isl_fold_min; + case isl_fold_list: + return isl_fold_list; + } + + isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort()); +} + +static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc( + enum isl_fold type, __isl_take isl_space *dim, int n) +{ + isl_qpolynomial_fold *fold; + + if (!dim) + goto error; + + isl_assert(dim->ctx, n >= 0, goto error); + fold = isl_calloc(dim->ctx, struct isl_qpolynomial_fold, + sizeof(struct isl_qpolynomial_fold) + + (n - 1) * sizeof(struct isl_qpolynomial *)); + if (!fold) + goto error; + + fold->ref = 1; + fold->size = n; + fold->n = 0; + fold->type = type; + fold->dim = dim; + + return fold; +error: + isl_space_free(dim); + return NULL; +} + +isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold) +{ + return fold ? fold->dim->ctx : NULL; +} + +__isl_give isl_space *isl_qpolynomial_fold_get_domain_space( + __isl_keep isl_qpolynomial_fold *fold) +{ + return fold ? isl_space_copy(fold->dim) : NULL; +} + +__isl_give isl_space *isl_qpolynomial_fold_get_space( + __isl_keep isl_qpolynomial_fold *fold) +{ + isl_space *space; + if (!fold) + return NULL; + space = isl_space_copy(fold->dim); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, 1); + return space; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim) +{ + int i; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold || !dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_reset_domain_space(fold->qp[i], + isl_space_copy(dim)); + if (!fold->qp[i]) + goto error; + } + + isl_space_free(fold->dim); + fold->dim = dim; + + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_space_free(dim); + return NULL; +} + +/* Reset the space of "fold". This function is called from isl_pw_templ.c + * and doesn't know if the space of an element object is represented + * directly or through its domain. It therefore passes along both. + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space, + __isl_take isl_space *domain) +{ + isl_space_free(space); + return isl_qpolynomial_fold_reset_domain_space(fold, domain); +} + +int isl_qpolynomial_fold_involves_dims(__isl_keep isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!fold) + return -1; + if (fold->n == 0 || n == 0) + return 0; + + for (i = 0; i < fold->n; ++i) { + int involves = isl_qpolynomial_involves_dims(fold->qp[i], + type, first, n); + if (involves < 0 || involves) + return involves; + } + return 0; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned pos, const char *s) +{ + int i; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + fold->dim = isl_space_set_dim_name(fold->dim, type, pos, s); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_set_dim_name(fold->qp[i], + type, pos, s); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + +/* Given a dimension type for an isl_qpolynomial_fold, + * return the corresponding type for the domain. + */ +static enum isl_dim_type domain_type(enum isl_dim_type type) +{ + if (type == isl_dim_in) + return isl_dim_set; + return type; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + enum isl_dim_type set_type; + + if (!fold) + return NULL; + if (n == 0) + return fold; + + set_type = domain_type(type); + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + fold->dim = isl_space_drop_dims(fold->dim, set_type, first, n); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_drop_dims(fold->qp[i], + type, first, n); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!fold) + return NULL; + if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type)) + return fold; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + fold->dim = isl_space_insert_dims(fold->dim, type, first, n); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_insert_dims(fold->qp[i], + type, first, n); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + +/* Determine the sign of the constant quasipolynomial "qp". + * + * Return + * -1 if qp <= 0 + * 1 if qp >= 0 + * 0 if unknown + * + * For qp == 0, we can return either -1 or 1. In practice, we return 1. + * For qp == NaN, the sign is undefined, so we return 0. + */ +static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp) +{ + struct isl_upoly_cst *cst; + + if (isl_qpolynomial_is_nan(qp)) + return 0; + + cst = isl_upoly_as_cst(qp->upoly); + if (!cst) + return 0; + + return isl_int_sgn(cst->n) < 0 ? -1 : 1; +} + +static int isl_qpolynomial_aff_sign(__isl_keep isl_set *set, + __isl_keep isl_qpolynomial *qp) +{ + enum isl_lp_result res; + isl_vec *aff; + isl_int opt; + int sgn = 0; + + aff = isl_qpolynomial_extract_affine(qp); + if (!aff) + return 0; + + isl_int_init(opt); + + res = isl_set_solve_lp(set, 0, aff->el + 1, aff->el[0], + &opt, NULL, NULL); + if (res == isl_lp_error) + goto done; + if (res == isl_lp_empty || + (res == isl_lp_ok && !isl_int_is_neg(opt))) { + sgn = 1; + goto done; + } + + res = isl_set_solve_lp(set, 1, aff->el + 1, aff->el[0], + &opt, NULL, NULL); + if (res == isl_lp_ok && !isl_int_is_pos(opt)) + sgn = -1; + +done: + isl_int_clear(opt); + isl_vec_free(aff); + return sgn; +} + +/* Determine, if possible, the sign of the quasipolynomial "qp" on + * the domain "set". + * + * If qp is a constant, then the problem is trivial. + * If qp is linear, then we check if the minimum of the corresponding + * affine constraint is non-negative or if the maximum is non-positive. + * + * Otherwise, we check if the outermost variable "v" has a lower bound "l" + * in "set". If so, we write qp(v,v') as + * + * q(v,v') * (v - l) + r(v') + * + * if q(v,v') and r(v') have the same known sign, then the original + * quasipolynomial has the same sign as well. + * + * Return + * -1 if qp <= 0 + * 1 if qp >= 0 + * 0 if unknown + */ +static int isl_qpolynomial_sign(__isl_keep isl_set *set, + __isl_keep isl_qpolynomial *qp) +{ + int d; + int i; + int is; + struct isl_upoly_rec *rec; + isl_vec *v; + isl_int l; + enum isl_lp_result res; + int sgn = 0; + + is = isl_qpolynomial_is_cst(qp, NULL, NULL); + if (is < 0) + return 0; + if (is) + return isl_qpolynomial_cst_sign(qp); + + is = isl_qpolynomial_is_affine(qp); + if (is < 0) + return 0; + if (is) + return isl_qpolynomial_aff_sign(set, qp); + + if (qp->div->n_row > 0) + return 0; + + rec = isl_upoly_as_rec(qp->upoly); + if (!rec) + return 0; + + d = isl_space_dim(qp->dim, isl_dim_all); + v = isl_vec_alloc(set->ctx, 2 + d); + if (!v) + return 0; + + isl_seq_clr(v->el + 1, 1 + d); + isl_int_set_si(v->el[0], 1); + isl_int_set_si(v->el[2 + qp->upoly->var], 1); + + isl_int_init(l); + + res = isl_set_solve_lp(set, 0, v->el + 1, v->el[0], &l, NULL, NULL); + if (res == isl_lp_ok) { + isl_qpolynomial *min; + isl_qpolynomial *base; + isl_qpolynomial *r, *q; + isl_qpolynomial *t; + + min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l); + base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim), + qp->upoly->var, 1); + + r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0, + isl_upoly_copy(rec->p[rec->n - 1])); + q = isl_qpolynomial_copy(r); + + for (i = rec->n - 2; i >= 0; --i) { + r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min)); + t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0, + isl_upoly_copy(rec->p[i])); + r = isl_qpolynomial_add(r, t); + if (i == 0) + break; + q = isl_qpolynomial_mul(q, isl_qpolynomial_copy(base)); + q = isl_qpolynomial_add(q, isl_qpolynomial_copy(r)); + } + + if (isl_qpolynomial_is_zero(q)) + sgn = isl_qpolynomial_sign(set, r); + else if (isl_qpolynomial_is_zero(r)) + sgn = isl_qpolynomial_sign(set, q); + else { + int sgn_q, sgn_r; + sgn_r = isl_qpolynomial_sign(set, r); + sgn_q = isl_qpolynomial_sign(set, q); + if (sgn_r == sgn_q) + sgn = sgn_r; + } + + isl_qpolynomial_free(min); + isl_qpolynomial_free(base); + isl_qpolynomial_free(q); + isl_qpolynomial_free(r); + } + + isl_int_clear(l); + + isl_vec_free(v); + + return sgn; +} + +/* Combine "fold1" and "fold2" into a single reduction, eliminating + * those elements of one reduction that are already covered by the other + * reduction on "set". + * + * If "fold1" or "fold2" is an empty reduction, then return + * the other reduction. + * If "fold1" or "fold2" is a NaN, then return this NaN. + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain( + __isl_keep isl_set *set, + __isl_take isl_qpolynomial_fold *fold1, + __isl_take isl_qpolynomial_fold *fold2) +{ + int i, j; + int n1; + struct isl_qpolynomial_fold *res = NULL; + int better; + + if (!fold1 || !fold2) + goto error; + + isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error); + isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim), + goto error); + + better = fold1->type == isl_fold_max ? -1 : 1; + + if (isl_qpolynomial_fold_is_empty(fold1) || + isl_qpolynomial_fold_is_nan(fold2)) { + isl_qpolynomial_fold_free(fold1); + return fold2; + } + + if (isl_qpolynomial_fold_is_empty(fold2) || + isl_qpolynomial_fold_is_nan(fold1)) { + isl_qpolynomial_fold_free(fold2); + return fold1; + } + + res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim), + fold1->n + fold2->n); + if (!res) + goto error; + + for (i = 0; i < fold1->n; ++i) { + res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]); + if (!res->qp[res->n]) + goto error; + res->n++; + } + n1 = res->n; + + for (i = 0; i < fold2->n; ++i) { + for (j = n1 - 1; j >= 0; --j) { + isl_qpolynomial *d; + int sgn, equal; + equal = isl_qpolynomial_plain_is_equal(res->qp[j], + fold2->qp[i]); + if (equal < 0) + goto error; + if (equal) + break; + d = isl_qpolynomial_sub( + isl_qpolynomial_copy(res->qp[j]), + isl_qpolynomial_copy(fold2->qp[i])); + sgn = isl_qpolynomial_sign(set, d); + isl_qpolynomial_free(d); + if (sgn == 0) + continue; + if (sgn != better) + break; + isl_qpolynomial_free(res->qp[j]); + if (j != n1 - 1) + res->qp[j] = res->qp[n1 - 1]; + n1--; + if (n1 != res->n - 1) + res->qp[n1] = res->qp[res->n - 1]; + res->n--; + } + if (j >= 0) + continue; + res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]); + if (!res->qp[res->n]) + goto error; + res->n++; + } + + isl_qpolynomial_fold_free(fold1); + isl_qpolynomial_fold_free(fold2); + + return res; +error: + isl_qpolynomial_fold_free(res); + isl_qpolynomial_fold_free(fold1); + isl_qpolynomial_fold_free(fold2); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp) +{ + int i; + + if (!fold || !qp) + goto error; + + if (isl_qpolynomial_is_zero(qp)) { + isl_qpolynomial_free(qp); + return fold; + } + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_add(fold->qp[i], + isl_qpolynomial_copy(qp)); + if (!fold->qp[i]) + goto error; + } + + isl_qpolynomial_free(qp); + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain( + __isl_keep isl_set *dom, + __isl_take isl_qpolynomial_fold *fold1, + __isl_take isl_qpolynomial_fold *fold2) +{ + int i; + isl_qpolynomial_fold *res = NULL; + + if (!fold1 || !fold2) + goto error; + + if (isl_qpolynomial_fold_is_empty(fold1)) { + isl_qpolynomial_fold_free(fold1); + return fold2; + } + + if (isl_qpolynomial_fold_is_empty(fold2)) { + isl_qpolynomial_fold_free(fold2); + return fold1; + } + + if (fold1->n == 1 && fold2->n != 1) + return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1); + + if (fold2->n == 1) { + res = isl_qpolynomial_fold_add_qpolynomial(fold1, + isl_qpolynomial_copy(fold2->qp[0])); + isl_qpolynomial_fold_free(fold2); + return res; + } + + res = isl_qpolynomial_fold_add_qpolynomial( + isl_qpolynomial_fold_copy(fold1), + isl_qpolynomial_copy(fold2->qp[0])); + + for (i = 1; i < fold2->n; ++i) { + isl_qpolynomial_fold *res_i; + res_i = isl_qpolynomial_fold_add_qpolynomial( + isl_qpolynomial_fold_copy(fold1), + isl_qpolynomial_copy(fold2->qp[i])); + res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i); + } + + isl_qpolynomial_fold_free(fold1); + isl_qpolynomial_fold_free(fold2); + return res; +error: + isl_qpolynomial_fold_free(res); + isl_qpolynomial_fold_free(fold1); + isl_qpolynomial_fold_free(fold2); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq) +{ + int i; + + if (!fold || !eq) + goto error; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_substitute_equalities(fold->qp[i], + isl_basic_set_copy(eq)); + if (!fold->qp[i]) + goto error; + } + + isl_basic_set_free(eq); + return fold; +error: + isl_basic_set_free(eq); + isl_qpolynomial_fold_free(fold); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context) +{ + int i; + + if (!fold || !context) + goto error; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_gist(fold->qp[i], + isl_set_copy(context)); + if (!fold->qp[i]) + goto error; + } + + isl_set_free(context); + return fold; +error: + isl_set_free(context); + isl_qpolynomial_fold_free(fold); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context) +{ + isl_space *space = isl_qpolynomial_fold_get_domain_space(fold); + isl_set *dom_context = isl_set_universe(space); + dom_context = isl_set_intersect_params(dom_context, context); + return isl_qpolynomial_fold_gist(fold, dom_context); +} + +#define isl_qpolynomial_fold_involves_nan isl_qpolynomial_fold_is_nan + +#define HAS_TYPE + +#undef PW +#define PW isl_pw_qpolynomial_fold +#undef EL +#define EL isl_qpolynomial_fold +#undef EL_IS_ZERO +#define EL_IS_ZERO is_empty +#undef ZERO +#define ZERO zero +#undef IS_ZERO +#define IS_ZERO is_zero +#undef FIELD +#define FIELD fold +#undef DEFAULT_IS_ZERO +#define DEFAULT_IS_ZERO 1 + +#define NO_NEG +#define NO_SUB +#define NO_PULLBACK + +#include + +#undef UNION +#define UNION isl_union_pw_qpolynomial_fold +#undef PART +#define PART isl_pw_qpolynomial_fold +#undef PARTS +#define PARTS pw_qpolynomial_fold + +#define NO_SUB + +#include +#include + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type, + __isl_take isl_space *dim) +{ + return qpolynomial_fold_alloc(type, dim, 0); +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc( + enum isl_fold type, __isl_take isl_qpolynomial *qp) +{ + isl_qpolynomial_fold *fold; + + if (!qp) + return NULL; + + fold = qpolynomial_fold_alloc(type, isl_space_copy(qp->dim), 1); + if (!fold) + goto error; + + fold->qp[0] = qp; + fold->n++; + + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy( + __isl_keep isl_qpolynomial_fold *fold) +{ + if (!fold) + return NULL; + + fold->ref++; + return fold; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup( + __isl_keep isl_qpolynomial_fold *fold) +{ + int i; + isl_qpolynomial_fold *dup; + + if (!fold) + return NULL; + dup = qpolynomial_fold_alloc(fold->type, + isl_space_copy(fold->dim), fold->n); + if (!dup) + return NULL; + + dup->n = fold->n; + for (i = 0; i < fold->n; ++i) { + dup->qp[i] = isl_qpolynomial_copy(fold->qp[i]); + if (!dup->qp[i]) + goto error; + } + + return dup; +error: + isl_qpolynomial_fold_free(dup); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow( + __isl_take isl_qpolynomial_fold *fold) +{ + if (!fold) + return NULL; + + if (fold->ref == 1) + return fold; + fold->ref--; + return isl_qpolynomial_fold_dup(fold); +} + +void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold) +{ + int i; + + if (!fold) + return; + if (--fold->ref > 0) + return; + + for (i = 0; i < fold->n; ++i) + isl_qpolynomial_free(fold->qp[i]); + isl_space_free(fold->dim); + free(fold); +} + +int isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold) +{ + if (!fold) + return -1; + + return fold->n == 0; +} + +/* Does "fold" represent max(NaN) or min(NaN)? + */ +isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold) +{ + if (!fold) + return isl_bool_error; + if (fold->n != 1) + return isl_bool_false; + return isl_qpolynomial_is_nan(fold->qp[0]); +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold( + __isl_take isl_qpolynomial_fold *fold1, + __isl_take isl_qpolynomial_fold *fold2) +{ + int i; + struct isl_qpolynomial_fold *res = NULL; + + if (!fold1 || !fold2) + goto error; + + isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error); + isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim), + goto error); + + if (isl_qpolynomial_fold_is_empty(fold1)) { + isl_qpolynomial_fold_free(fold1); + return fold2; + } + + if (isl_qpolynomial_fold_is_empty(fold2)) { + isl_qpolynomial_fold_free(fold2); + return fold1; + } + + res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim), + fold1->n + fold2->n); + if (!res) + goto error; + + for (i = 0; i < fold1->n; ++i) { + res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]); + if (!res->qp[res->n]) + goto error; + res->n++; + } + + for (i = 0; i < fold2->n; ++i) { + res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]); + if (!res->qp[res->n]) + goto error; + res->n++; + } + + isl_qpolynomial_fold_free(fold1); + isl_qpolynomial_fold_free(fold2); + + return res; +error: + isl_qpolynomial_fold_free(res); + isl_qpolynomial_fold_free(fold1); + isl_qpolynomial_fold_free(fold2); + return NULL; +} + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold( + __isl_take isl_pw_qpolynomial_fold *pw1, + __isl_take isl_pw_qpolynomial_fold *pw2) +{ + int i, j, n; + struct isl_pw_qpolynomial_fold *res; + isl_set *set; + + if (!pw1 || !pw2) + goto error; + + isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error); + + if (isl_pw_qpolynomial_fold_is_zero(pw1)) { + isl_pw_qpolynomial_fold_free(pw1); + return pw2; + } + + if (isl_pw_qpolynomial_fold_is_zero(pw2)) { + isl_pw_qpolynomial_fold_free(pw2); + return pw1; + } + + if (pw1->type != pw2->type) + isl_die(pw1->dim->ctx, isl_error_invalid, + "fold types don't match", goto error); + + n = (pw1->n + 1) * (pw2->n + 1); + res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim), + pw1->type, n); + + for (i = 0; i < pw1->n; ++i) { + set = isl_set_copy(pw1->p[i].set); + for (j = 0; j < pw2->n; ++j) { + struct isl_set *common; + isl_qpolynomial_fold *sum; + set = isl_set_subtract(set, + 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_plain_is_empty(common)) { + isl_set_free(common); + continue; + } + + sum = isl_qpolynomial_fold_fold_on_domain(common, + isl_qpolynomial_fold_copy(pw1->p[i].fold), + isl_qpolynomial_fold_copy(pw2->p[j].fold)); + + res = isl_pw_qpolynomial_fold_add_piece(res, common, sum); + } + res = isl_pw_qpolynomial_fold_add_piece(res, set, + isl_qpolynomial_fold_copy(pw1->p[i].fold)); + } + + for (j = 0; j < pw2->n; ++j) { + set = isl_set_copy(pw2->p[j].set); + for (i = 0; i < pw1->n; ++i) + set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set)); + res = isl_pw_qpolynomial_fold_add_piece(res, set, + isl_qpolynomial_fold_copy(pw2->p[j].fold)); + } + + isl_pw_qpolynomial_fold_free(pw1); + isl_pw_qpolynomial_fold_free(pw2); + + return res; +error: + isl_pw_qpolynomial_fold_free(pw1); + isl_pw_qpolynomial_fold_free(pw2); + return NULL; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( + __isl_take isl_union_pw_qpolynomial_fold *u, + __isl_take isl_pw_qpolynomial_fold *part) +{ + struct isl_hash_table_entry *entry; + + u = isl_union_pw_qpolynomial_fold_cow(u); + + if (!part || !u) + goto error; + if (isl_space_check_equal_params(part->dim, u->space) < 0) + goto error; + + entry = isl_union_pw_qpolynomial_fold_find_part_entry(u, part->dim, 1); + if (!entry) + goto error; + + if (!entry->data) + entry->data = part; + else { + entry->data = isl_pw_qpolynomial_fold_fold(entry->data, + isl_pw_qpolynomial_fold_copy(part)); + if (!entry->data) + goto error; + isl_pw_qpolynomial_fold_free(part); + } + + return u; +error: + isl_pw_qpolynomial_fold_free(part); + isl_union_pw_qpolynomial_fold_free(u); + return NULL; +} + +static isl_stat fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user) +{ + isl_union_pw_qpolynomial_fold **u; + u = (isl_union_pw_qpolynomial_fold **)user; + + *u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part); + + return isl_stat_ok; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold( + __isl_take isl_union_pw_qpolynomial_fold *u1, + __isl_take isl_union_pw_qpolynomial_fold *u2) +{ + u1 = isl_union_pw_qpolynomial_fold_cow(u1); + + if (!u1 || !u2) + goto error; + + if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2, + &fold_part, &u1) < 0) + goto error; + + isl_union_pw_qpolynomial_fold_free(u2); + + return u1; +error: + isl_union_pw_qpolynomial_fold_free(u1); + isl_union_pw_qpolynomial_fold_free(u2); + return NULL; +} + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial( + enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp) +{ + int i; + isl_pw_qpolynomial_fold *pwf; + + if (!pwqp) + return NULL; + + pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim), + type, pwqp->n); + + for (i = 0; i < pwqp->n; ++i) + pwf = isl_pw_qpolynomial_fold_add_piece(pwf, + isl_set_copy(pwqp->p[i].set), + isl_qpolynomial_fold_alloc(type, + isl_qpolynomial_copy(pwqp->p[i].qp))); + + isl_pw_qpolynomial_free(pwqp); + + return pwf; +} + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add( + __isl_take isl_pw_qpolynomial_fold *pwf1, + __isl_take isl_pw_qpolynomial_fold *pwf2) +{ + return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2); +} + +/* Compare two quasi-polynomial reductions. + * + * Return -1 if "fold1" is "smaller" than "fold2", 1 if "fold1" is "greater" + * than "fold2" and 0 if they are equal. + */ +int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1, + __isl_keep isl_qpolynomial_fold *fold2) +{ + int i; + + if (fold1 == fold2) + return 0; + if (!fold1) + return -1; + if (!fold2) + return 1; + + if (fold1->n != fold2->n) + return fold1->n - fold2->n; + + for (i = 0; i < fold1->n; ++i) { + int cmp; + + cmp = isl_qpolynomial_plain_cmp(fold1->qp[i], fold2->qp[i]); + if (cmp != 0) + return cmp; + } + + return 0; +} + +int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1, + __isl_keep isl_qpolynomial_fold *fold2) +{ + int i; + + if (!fold1 || !fold2) + return -1; + + if (fold1->n != fold2->n) + return 0; + + /* We probably want to sort the qps first... */ + for (i = 0; i < fold1->n; ++i) { + int eq = isl_qpolynomial_plain_is_equal(fold1->qp[i], fold2->qp[i]); + if (eq < 0 || !eq) + return eq; + } + + return 1; +} + +__isl_give isl_val *isl_qpolynomial_fold_eval( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt) +{ + isl_ctx *ctx; + isl_val *v; + + if (!fold || !pnt) + goto error; + ctx = isl_point_get_ctx(pnt); + isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error); + isl_assert(pnt->dim->ctx, + fold->type == isl_fold_max || fold->type == isl_fold_min, + goto error); + + if (fold->n == 0) + v = isl_val_zero(ctx); + else { + int i; + v = isl_qpolynomial_eval(isl_qpolynomial_copy(fold->qp[0]), + isl_point_copy(pnt)); + for (i = 1; i < fold->n; ++i) { + isl_val *v_i; + v_i = isl_qpolynomial_eval( + isl_qpolynomial_copy(fold->qp[i]), + isl_point_copy(pnt)); + if (fold->type == isl_fold_max) + v = isl_val_max(v, v_i); + else + v = isl_val_min(v, v_i); + } + } + isl_qpolynomial_fold_free(fold); + isl_point_free(pnt); + + return v; +error: + isl_qpolynomial_fold_free(fold); + isl_point_free(pnt); + return NULL; +} + +size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf) +{ + int i; + size_t n = 0; + + for (i = 0; i < pwf->n; ++i) + n += pwf->p[i].fold->n; + + return n; +} + +__isl_give isl_val *isl_qpolynomial_fold_opt_on_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max) +{ + int i; + isl_val *opt; + + if (!set || !fold) + goto error; + + if (fold->n == 0) { + opt = isl_val_zero(isl_set_get_ctx(set)); + isl_set_free(set); + isl_qpolynomial_fold_free(fold); + return opt; + } + + opt = isl_qpolynomial_opt_on_domain(isl_qpolynomial_copy(fold->qp[0]), + isl_set_copy(set), max); + for (i = 1; i < fold->n; ++i) { + isl_val *opt_i; + opt_i = isl_qpolynomial_opt_on_domain( + isl_qpolynomial_copy(fold->qp[i]), + isl_set_copy(set), max); + if (max) + opt = isl_val_max(opt, opt_i); + else + opt = isl_val_min(opt, opt_i); + } + + isl_set_free(set); + isl_qpolynomial_fold_free(fold); + + return opt; +error: + isl_set_free(set); + isl_qpolynomial_fold_free(fold); + return NULL; +} + +/* Check whether for each quasi-polynomial in "fold2" there is + * a quasi-polynomial in "fold1" that dominates it on "set". + */ +static int qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set, + __isl_keep isl_qpolynomial_fold *fold1, + __isl_keep isl_qpolynomial_fold *fold2) +{ + int i, j; + int covers; + + if (!set || !fold1 || !fold2) + return -1; + + covers = fold1->type == isl_fold_max ? 1 : -1; + + for (i = 0; i < fold2->n; ++i) { + for (j = 0; j < fold1->n; ++j) { + isl_qpolynomial *d; + int sgn; + + d = isl_qpolynomial_sub( + isl_qpolynomial_copy(fold1->qp[j]), + isl_qpolynomial_copy(fold2->qp[i])); + sgn = isl_qpolynomial_sign(set, d); + isl_qpolynomial_free(d); + if (sgn == covers) + break; + } + if (j >= fold1->n) + return 0; + } + + return 1; +} + +/* Check whether "pwf1" dominated "pwf2", i.e., the domain of "pwf1" contains + * that of "pwf2" and on each cell, the corresponding fold from pwf1 dominates + * that of pwf2. + */ +int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1, + __isl_keep isl_pw_qpolynomial_fold *pwf2) +{ + int i, j; + isl_set *dom1, *dom2; + int is_subset; + + if (!pwf1 || !pwf2) + return -1; + + if (pwf2->n == 0) + return 1; + if (pwf1->n == 0) + return 0; + + dom1 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf1)); + dom2 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf2)); + is_subset = isl_set_is_subset(dom2, dom1); + isl_set_free(dom1); + isl_set_free(dom2); + + if (is_subset < 0 || !is_subset) + return is_subset; + + for (i = 0; i < pwf2->n; ++i) { + for (j = 0; j < pwf1->n; ++j) { + int is_empty; + isl_set *common; + int covers; + + common = isl_set_intersect(isl_set_copy(pwf1->p[j].set), + isl_set_copy(pwf2->p[i].set)); + is_empty = isl_set_is_empty(common); + if (is_empty < 0 || is_empty) { + isl_set_free(common); + if (is_empty < 0) + return -1; + continue; + } + covers = qpolynomial_fold_covers_on_domain(common, + pwf1->p[j].fold, pwf2->p[i].fold); + isl_set_free(common); + if (covers < 0 || !covers) + return covers; + } + } + + return 1; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph) +{ + int i; + isl_ctx *ctx; + + if (!fold || !morph) + goto error; + + ctx = fold->dim->ctx; + isl_assert(ctx, isl_space_is_equal(fold->dim, morph->dom->dim), goto error); + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + goto error; + + isl_space_free(fold->dim); + fold->dim = isl_space_copy(morph->ran->dim); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_morph_domain(fold->qp[i], + isl_morph_copy(morph)); + if (!fold->qp[i]) + goto error; + } + + isl_morph_free(morph); + + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_morph_free(morph); + return NULL; +} + +enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold) +{ + if (!fold) + return isl_fold_list; + return fold->type; +} + +enum isl_fold isl_union_pw_qpolynomial_fold_get_type( + __isl_keep isl_union_pw_qpolynomial_fold *upwf) +{ + if (!upwf) + return isl_fold_list; + return upwf->type; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim) +{ + int i; + + if (!fold || !dim) + goto error; + + if (isl_space_is_equal(fold->dim, dim)) { + isl_space_free(dim); + return fold; + } + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + goto error; + + isl_space_free(fold->dim); + fold->dim = isl_space_copy(dim); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_lift(fold->qp[i], + isl_space_copy(dim)); + if (!fold->qp[i]) + goto error; + } + + isl_space_free(dim); + + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_space_free(dim); + return NULL; +} + +isl_stat isl_qpolynomial_fold_foreach_qpolynomial( + __isl_keep isl_qpolynomial_fold *fold, + isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user) +{ + int i; + + if (!fold) + return isl_stat_error; + + for (i = 0; i < fold->n; ++i) + if (fn(isl_qpolynomial_copy(fold->qp[i]), user) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + int i; + enum isl_dim_type set_src_type, set_dst_type; + + if (n == 0) + return fold; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + set_src_type = domain_type(src_type); + set_dst_type = domain_type(dst_type); + + fold->dim = isl_space_move_dims(fold->dim, set_dst_type, dst_pos, + set_src_type, src_pos, n); + if (!fold->dim) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_move_dims(fold->qp[i], + dst_type, dst_pos, src_type, src_pos, n); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + +/* For each 0 <= i < "n", replace variable "first" + i of type "type" + * in fold->qp[k] by subs[i]. + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute( + __isl_take isl_qpolynomial_fold *fold, + enum isl_dim_type type, unsigned first, unsigned n, + __isl_keep isl_qpolynomial **subs) +{ + int i; + + if (n == 0) + return fold; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_substitute(fold->qp[i], + type, first, n, subs); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + +static isl_stat add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user) +{ + isl_pw_qpolynomial_fold *pwf; + isl_union_pw_qpolynomial_fold **upwf; + struct isl_hash_table_entry *entry; + + upwf = (isl_union_pw_qpolynomial_fold **)user; + + entry = isl_union_pw_qpolynomial_fold_find_part_entry(*upwf, + pwqp->dim, 1); + if (!entry) + goto error; + + pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp); + if (!entry->data) + entry->data = pwf; + else { + entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf); + if (!entry->data) + return isl_stat_error; + if (isl_pw_qpolynomial_fold_is_zero(entry->data)) + *upwf = isl_union_pw_qpolynomial_fold_remove_part_entry( + *upwf, entry); + } + + return isl_stat_ok; +error: + isl_pw_qpolynomial_free(pwqp); + return isl_stat_error; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_pw_qpolynomial *upwqp) +{ + upwf = isl_union_pw_qpolynomial_fold_align_params(upwf, + isl_union_pw_qpolynomial_get_space(upwqp)); + upwqp = isl_union_pw_qpolynomial_align_params(upwqp, + isl_union_pw_qpolynomial_fold_get_space(upwf)); + + upwf = isl_union_pw_qpolynomial_fold_cow(upwf); + if (!upwf || !upwqp) + goto error; + + if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp, + &upwf) < 0) + goto error; + + isl_union_pw_qpolynomial_free(upwqp); + + return upwf; +error: + isl_union_pw_qpolynomial_fold_free(upwf); + isl_union_pw_qpolynomial_free(upwqp); + return NULL; +} + +static isl_bool join_compatible(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + isl_bool m; + m = isl_space_has_equal_params(space1, space2); + if (m < 0 || !m) + return m; + return isl_space_tuple_is_equal(space1, isl_dim_out, + space2, isl_dim_in); +} + +/* Compute the intersection of the range of the map and the domain + * of the piecewise quasipolynomial reduction and then compute a bound + * on the associated quasipolynomial reduction over all elements + * in this intersection. + * + * We first introduce some unconstrained dimensions in the + * piecewise quasipolynomial, intersect the resulting domain + * with the wrapped map and the compute the sum. + */ +__isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold( + __isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf, + int *tight) +{ + isl_ctx *ctx; + isl_set *dom; + isl_space *map_dim; + isl_space *pwf_dim; + unsigned n_in; + isl_bool ok; + + ctx = isl_map_get_ctx(map); + if (!ctx) + goto error; + + map_dim = isl_map_get_space(map); + pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf); + ok = join_compatible(map_dim, pwf_dim); + isl_space_free(map_dim); + isl_space_free(pwf_dim); + if (ok < 0) + goto error; + if (!ok) + isl_die(ctx, isl_error_invalid, "incompatible dimensions", + goto error); + + n_in = isl_map_dim(map, isl_dim_in); + pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in); + + dom = isl_map_wrap(map); + pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf, + isl_set_get_space(dom)); + + pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom); + pwf = isl_pw_qpolynomial_fold_bound(pwf, tight); + + return pwf; +error: + isl_map_free(map); + isl_pw_qpolynomial_fold_free(pwf); + return NULL; +} + +__isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold( + __isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf, + int *tight) +{ + return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight); +} + +struct isl_apply_fold_data { + isl_union_pw_qpolynomial_fold *upwf; + isl_union_pw_qpolynomial_fold *res; + isl_map *map; + int tight; +}; + +static isl_stat pw_qpolynomial_fold_apply( + __isl_take isl_pw_qpolynomial_fold *pwf, void *user) +{ + isl_space *map_dim; + isl_space *pwf_dim; + struct isl_apply_fold_data *data = user; + isl_bool ok; + + map_dim = isl_map_get_space(data->map); + pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf); + ok = join_compatible(map_dim, pwf_dim); + isl_space_free(map_dim); + isl_space_free(pwf_dim); + + if (ok < 0) + return isl_stat_error; + if (ok) { + pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map), + pwf, data->tight ? &data->tight : NULL); + data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( + data->res, pwf); + } else + isl_pw_qpolynomial_fold_free(pwf); + + return isl_stat_ok; +} + +static isl_stat map_apply(__isl_take isl_map *map, void *user) +{ + struct isl_apply_fold_data *data = user; + isl_stat r; + + data->map = map; + r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold( + data->upwf, &pw_qpolynomial_fold_apply, data); + + isl_map_free(map); + return r; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight) +{ + isl_space *dim; + enum isl_fold type; + struct isl_apply_fold_data data; + + upwf = isl_union_pw_qpolynomial_fold_align_params(upwf, + isl_union_map_get_space(umap)); + umap = isl_union_map_align_params(umap, + isl_union_pw_qpolynomial_fold_get_space(upwf)); + + data.upwf = upwf; + data.tight = tight ? 1 : 0; + dim = isl_union_pw_qpolynomial_fold_get_space(upwf); + type = isl_union_pw_qpolynomial_fold_get_type(upwf); + data.res = isl_union_pw_qpolynomial_fold_zero(dim, type); + if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0) + goto error; + + isl_union_map_free(umap); + isl_union_pw_qpolynomial_fold_free(upwf); + + if (tight) + *tight = data.tight; + + return data.res; +error: + isl_union_map_free(umap); + isl_union_pw_qpolynomial_fold_free(upwf); + isl_union_pw_qpolynomial_fold_free(data.res); + return NULL; +} + +__isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold( + __isl_take isl_union_set *uset, + __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight) +{ + return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight); +} + +/* Reorder the dimension of "fold" according to the given reordering. + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r) +{ + int i; + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold || !r) + goto error; + + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_realign_domain(fold->qp[i], + isl_reordering_copy(r)); + if (!fold->qp[i]) + goto error; + } + + fold = isl_qpolynomial_fold_reset_domain_space(fold, + isl_space_copy(r->dim)); + + isl_reordering_free(r); + + return fold; +error: + isl_qpolynomial_fold_free(fold); + isl_reordering_free(r); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int( + __isl_take isl_qpolynomial_fold *fold, isl_int v) +{ + int i; + + if (isl_int_is_one(v)) + return fold; + if (fold && isl_int_is_zero(v)) { + isl_qpolynomial_fold *zero; + isl_space *dim = isl_space_copy(fold->dim); + zero = isl_qpolynomial_fold_empty(fold->type, dim); + isl_qpolynomial_fold_free(fold); + return zero; + } + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + return NULL; + + if (isl_int_is_neg(v)) + fold->type = isl_fold_type_negate(fold->type); + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_mul_isl_int(fold->qp[i], v); + if (!fold->qp[i]) + goto error; + } + + return fold; +error: + isl_qpolynomial_fold_free(fold); + return NULL; +} + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale( + __isl_take isl_qpolynomial_fold *fold, isl_int v) +{ + return isl_qpolynomial_fold_mul_isl_int(fold, v); +} + +/* Multiply "fold" by "v". + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v) +{ + int i; + + if (!fold || !v) + goto error; + + if (isl_val_is_one(v)) { + isl_val_free(v); + return fold; + } + if (isl_val_is_zero(v)) { + isl_qpolynomial_fold *zero; + isl_space *space = isl_qpolynomial_fold_get_domain_space(fold); + zero = isl_qpolynomial_fold_empty(fold->type, space); + isl_qpolynomial_fold_free(fold); + isl_val_free(v); + return zero; + } + if (!isl_val_is_rat(v)) + isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid, + "expecting rational factor", goto error); + + fold = isl_qpolynomial_fold_cow(fold); + if (!fold) + goto error; + + if (isl_val_is_neg(v)) + fold->type = isl_fold_type_negate(fold->type); + for (i = 0; i < fold->n; ++i) { + fold->qp[i] = isl_qpolynomial_scale_val(fold->qp[i], + isl_val_copy(v)); + if (!fold->qp[i]) + goto error; + } + + isl_val_free(v); + return fold; +error: + isl_val_free(v); + isl_qpolynomial_fold_free(fold); + return NULL; +} + +/* Divide "fold" by "v". + */ +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v) +{ + if (!fold || !v) + goto error; + + if (isl_val_is_one(v)) { + isl_val_free(v); + return fold; + } + if (!isl_val_is_rat(v)) + isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid, + "expecting rational factor", goto error); + if (isl_val_is_zero(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "cannot scale down by zero", goto error); + + return isl_qpolynomial_fold_scale_val(fold, isl_val_inv(v)); +error: + isl_val_free(v); + isl_qpolynomial_fold_free(fold); + return NULL; +} Index: contrib/isl/isl_gmp.c =================================================================== --- /dev/null +++ contrib/isl/isl_gmp.c @@ -0,0 +1,24 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include + +uint32_t isl_gmp_hash(mpz_t v, uint32_t hash) +{ + int sa = v[0]._mp_size; + int abs_sa = sa < 0 ? -sa : sa; + unsigned char *data = (unsigned char *)v[0]._mp_d; + unsigned char *end = data + abs_sa * sizeof(v[0]._mp_d[0]); + + if (sa < 0) + isl_hash_byte(hash, 0xFF); + for (; data < end; ++data) + isl_hash_byte(hash, *data); + return hash; +} Index: contrib/isl/isl_hash.c =================================================================== --- /dev/null +++ contrib/isl/isl_hash.c @@ -0,0 +1,235 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include "isl_config.h" + +uint32_t isl_hash_string(uint32_t hash, const char *s) +{ + for (; *s; s++) + isl_hash_byte(hash, *s); + return hash; +} + +uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len) +{ + int i; + const char *s = p; + for (i = 0; i < len; ++i) + isl_hash_byte(hash, s[i]); + return hash; +} + +static unsigned int round_up(unsigned int v) +{ + int old_v = v; + + while (v) { + old_v = v; + v ^= v & -v; + } + return old_v << 1; +} + +int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table, + int min_size) +{ + size_t size; + + if (!table) + return -1; + + if (min_size < 2) + min_size = 2; + table->bits = ffs(round_up(4 * (min_size + 1) / 3 - 1)) - 1; + table->n = 0; + + size = 1 << table->bits; + table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry, + size); + if (!table->entries) + return -1; + + return 0; +} + +/* Dummy comparison function that always returns false. + */ +static int no(const void *entry, const void *val) +{ + return 0; +} + +/* Extend "table" to twice its size. + * Return 0 on success and -1 on error. + * + * We reuse isl_hash_table_find to create entries in the extended table. + * Since all entries in the original table are assumed to be different, + * there is no need to compare them against each other. + */ +static int grow_table(struct isl_ctx *ctx, struct isl_hash_table *table) +{ + int n; + size_t old_size, size; + struct isl_hash_table_entry *entries; + uint32_t h; + + entries = table->entries; + old_size = 1 << table->bits; + size = 2 * old_size; + table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry, + size); + if (!table->entries) { + table->entries = entries; + return -1; + } + + n = table->n; + table->n = 0; + table->bits++; + + for (h = 0; h < old_size; ++h) { + struct isl_hash_table_entry *entry; + + if (!entries[h].data) + continue; + + entry = isl_hash_table_find(ctx, table, entries[h].hash, + &no, NULL, 1); + if (!entry) { + table->bits--; + free(table->entries); + table->entries = entries; + table->n = n; + return -1; + } + + *entry = entries[h]; + } + + free(entries); + + return 0; +} + +struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size) +{ + struct isl_hash_table *table = NULL; + + table = isl_alloc_type(ctx, struct isl_hash_table); + if (isl_hash_table_init(ctx, table, min_size)) + goto error; + return table; +error: + isl_hash_table_free(ctx, table); + return NULL; +} + +void isl_hash_table_clear(struct isl_hash_table *table) +{ + if (!table) + return; + free(table->entries); +} + +void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table) +{ + if (!table) + return; + isl_hash_table_clear(table); + free(table); +} + +/* A dummy entry that can be used to make a distinction between + * a missing entry and an error condition. + * It is used by isl_union_*_find_part_entry. + */ +static struct isl_hash_table_entry none = { 0, NULL }; +struct isl_hash_table_entry *isl_hash_table_entry_none = &none; + +struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx, + struct isl_hash_table *table, + uint32_t key_hash, + int (*eq)(const void *entry, const void *val), + const void *val, int reserve) +{ + size_t size; + uint32_t h, key_bits; + + key_bits = isl_hash_bits(key_hash, table->bits); + size = 1 << table->bits; + for (h = key_bits; table->entries[h].data; h = (h+1) % size) + if (table->entries[h].hash == key_hash && + eq(table->entries[h].data, val)) + return &table->entries[h]; + + if (!reserve) + return NULL; + + if (4 * table->n >= 3 * size) { + if (grow_table(ctx, table) < 0) + return NULL; + return isl_hash_table_find(ctx, table, key_hash, eq, val, 1); + } + + table->n++; + table->entries[h].hash = key_hash; + + return &table->entries[h]; +} + +isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table, + isl_stat (*fn)(void **entry, void *user), void *user) +{ + size_t size; + uint32_t h; + + if (!table->entries) + return isl_stat_error; + + size = 1 << table->bits; + for (h = 0; h < size; ++ h) + if (table->entries[h].data && + fn(&table->entries[h].data, user) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +void isl_hash_table_remove(struct isl_ctx *ctx, + struct isl_hash_table *table, + struct isl_hash_table_entry *entry) +{ + int h, h2; + size_t size; + + if (!table || !entry) + return; + + size = 1 << table->bits; + h = entry - table->entries; + isl_assert(ctx, h >= 0 && h < size, return); + + for (h2 = h+1; table->entries[h2 % size].data; h2++) { + uint32_t bits = isl_hash_bits(table->entries[h2 % size].hash, + table->bits); + uint32_t offset = (size + bits - (h+1)) % size; + if (offset <= h2 - (h+1)) + continue; + *entry = table->entries[h2 % size]; + h = h2; + entry = &table->entries[h % size]; + } + + entry->hash = 0; + entry->data = NULL; + table->n--; +} Index: contrib/isl/isl_hash_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_hash_private.h @@ -0,0 +1,8 @@ +#ifndef ISL_HASH_PRIVATE +#define ISL_HASH_PRIVATE + +#include + +extern struct isl_hash_table_entry *isl_hash_table_entry_none; + +#endif Index: contrib/isl/isl_id.c =================================================================== --- /dev/null +++ contrib/isl/isl_id.c @@ -0,0 +1,244 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include + +#undef BASE +#define BASE id + +#include + +/* A special, static isl_id to use as domains (and ranges) + * of sets and parameters domains. + * The user should never get a hold on this isl_id. + */ +isl_id isl_id_none = { + .ref = -1, + .ctx = NULL, + .name = "#none", + .user = NULL +}; + +isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id) +{ + return id ? id->ctx : NULL; +} + +void *isl_id_get_user(__isl_keep isl_id *id) +{ + return id ? id->user : NULL; +} + +const char *isl_id_get_name(__isl_keep isl_id *id) +{ + return id ? id->name : NULL; +} + +static __isl_give isl_id *id_alloc(isl_ctx *ctx, const char *name, void *user) +{ + const char *copy = name ? strdup(name) : NULL; + isl_id *id; + + if (name && !copy) + return NULL; + id = isl_calloc_type(ctx, struct isl_id); + if (!id) + goto error; + + id->ctx = ctx; + isl_ctx_ref(id->ctx); + id->ref = 1; + id->name = copy; + id->user = user; + + id->hash = isl_hash_init(); + if (name) + id->hash = isl_hash_string(id->hash, name); + else + id->hash = isl_hash_builtin(id->hash, user); + + return id; +error: + free((char *)copy); + return NULL; +} + +uint32_t isl_id_get_hash(__isl_keep isl_id *id) +{ + return id ? id->hash : 0; +} + +struct isl_name_and_user { + const char *name; + void *user; +}; + +static int isl_id_has_name_and_user(const void *entry, const void *val) +{ + isl_id *id = (isl_id *)entry; + struct isl_name_and_user *nu = (struct isl_name_and_user *) val; + + if (id->user != nu->user) + return 0; + if (id->name == nu->name) + return 1; + if (!id->name || !nu->name) + return 0; + + return !strcmp(id->name, nu->name); +} + +__isl_give isl_id *isl_id_alloc(isl_ctx *ctx, const char *name, void *user) +{ + struct isl_hash_table_entry *entry; + uint32_t id_hash; + struct isl_name_and_user nu = { name, user }; + + if (!ctx) + return NULL; + + id_hash = isl_hash_init(); + if (name) + id_hash = isl_hash_string(id_hash, name); + else + id_hash = isl_hash_builtin(id_hash, user); + entry = isl_hash_table_find(ctx, &ctx->id_table, id_hash, + isl_id_has_name_and_user, &nu, 1); + if (!entry) + return NULL; + if (entry->data) + return isl_id_copy(entry->data); + entry->data = id_alloc(ctx, name, user); + if (!entry->data) + ctx->id_table.n--; + return entry->data; +} + +/* If the id has a negative refcount, then it is a static isl_id + * which should not be changed. + */ +__isl_give isl_id *isl_id_copy(isl_id *id) +{ + if (!id) + return NULL; + + if (id->ref < 0) + return id; + + id->ref++; + return id; +} + +/* Compare two isl_ids. + * + * The order is fairly arbitrary. We do keep the comparison of + * the user pointers as a last resort since these pointer values + * may not be stable across different systems or even different runs. + */ +int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2) +{ + if (id1 == id2) + return 0; + if (!id1) + return -1; + if (!id2) + return 1; + if (!id1->name != !id2->name) + return !id1->name - !id2->name; + if (id1->name) { + int cmp = strcmp(id1->name, id2->name); + if (cmp != 0) + return cmp; + } + if (id1->user < id2->user) + return -1; + else + return 1; +} + +static int isl_id_eq(const void *entry, const void *name) +{ + return entry == name; +} + +uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id) +{ + if (id) + isl_hash_hash(hash, id->hash); + + return hash; +} + +/* Replace the free_user callback by "free_user". + */ +__isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, + void (*free_user)(void *user)) +{ + if (!id) + return NULL; + + id->free_user = free_user; + + return id; +} + +/* If the id has a negative refcount, then it is a static isl_id + * and should not be freed. + */ +__isl_null isl_id *isl_id_free(__isl_take isl_id *id) +{ + struct isl_hash_table_entry *entry; + + if (!id) + return NULL; + + if (id->ref < 0) + return NULL; + + if (--id->ref > 0) + return NULL; + + entry = isl_hash_table_find(id->ctx, &id->ctx->id_table, id->hash, + isl_id_eq, id, 0); + if (!entry) + isl_die(id->ctx, isl_error_unknown, + "unable to find id", (void)0); + else + isl_hash_table_remove(id->ctx, &id->ctx->id_table, entry); + + if (id->free_user) + id->free_user(id->user); + + free((char *)id->name); + isl_ctx_deref(id->ctx); + free(id); + + return NULL; +} + +__isl_give isl_printer *isl_printer_print_id(__isl_take isl_printer *p, + __isl_keep isl_id *id) +{ + if (!id) + goto error; + + if (id->name) + p = isl_printer_print_str(p, id->name); + if (id->user) { + char buffer[50]; + snprintf(buffer, sizeof(buffer), "@%p", id->user); + p = isl_printer_print_str(p, buffer); + } + return p; +error: + isl_printer_free(p); + return NULL; +} Index: contrib/isl/isl_id_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_id_private.h @@ -0,0 +1,41 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_ID_PRIVATE_H +#define ISL_ID_PRIVATE_H + +#include + +/* Represent a name and/or user pointer. + * + * If "free_user" is set, then it will be called on "user" when + * the last instance of the isl_id is freed. + */ +struct isl_id { + int ref; + isl_ctx *ctx; + + const char *name; + void *user; + uint32_t hash; + + __isl_give void (*free_user)(void *user); +}; + +#undef EL +#define EL isl_id + +#include + +uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id); +int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2); + +extern isl_id isl_id_none; + +#endif Index: contrib/isl/isl_id_to_ast_expr.c =================================================================== --- /dev/null +++ contrib/isl/isl_id_to_ast_expr.c @@ -0,0 +1,15 @@ +#include +#include + +#define isl_id_is_equal(id1,id2) id1 == id2 + +#define ISL_KEY isl_id +#define ISL_VAL isl_ast_expr +#define ISL_HMAP_SUFFIX id_to_ast_expr +#define ISL_HMAP isl_id_to_ast_expr +#define ISL_KEY_IS_EQUAL isl_id_is_equal +#define ISL_VAL_IS_EQUAL isl_ast_expr_is_equal +#define ISL_KEY_PRINT isl_printer_print_id +#define ISL_VAL_PRINT isl_printer_print_ast_expr + +#include Index: contrib/isl/isl_id_to_id.c =================================================================== --- /dev/null +++ contrib/isl/isl_id_to_id.c @@ -0,0 +1,14 @@ +#include + +#define isl_id_is_equal(id1,id2) id1 == id2 + +#define ISL_KEY isl_id +#define ISL_VAL isl_id +#define ISL_HMAP_SUFFIX id_to_id +#define ISL_HMAP isl_id_to_id +#define ISL_KEY_IS_EQUAL isl_id_is_equal +#define ISL_VAL_IS_EQUAL isl_id_is_equal +#define ISL_KEY_PRINT isl_printer_print_id +#define ISL_VAL_PRINT isl_printer_print_id + +#include Index: contrib/isl/isl_id_to_pw_aff.c =================================================================== --- /dev/null +++ contrib/isl/isl_id_to_pw_aff.c @@ -0,0 +1,15 @@ +#include +#include + +#define isl_id_is_equal(id1,id2) id1 == id2 + +#define ISL_KEY isl_id +#define ISL_VAL isl_pw_aff +#define ISL_HMAP_SUFFIX id_to_pw_aff +#define ISL_HMAP isl_id_to_pw_aff +#define ISL_KEY_IS_EQUAL isl_id_is_equal +#define ISL_VAL_IS_EQUAL isl_pw_aff_plain_is_equal +#define ISL_KEY_PRINT isl_printer_print_id +#define ISL_VAL_PRINT isl_printer_print_pw_aff + +#include Index: contrib/isl/isl_ilp.c =================================================================== --- /dev/null +++ contrib/isl/isl_ilp.c @@ -0,0 +1,818 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include +#include "isl_sample.h" +#include +#include "isl_equalities.h" +#include +#include +#include +#include +#include +#include +#include + +/* 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 + * the given basic set. + * Note that U may not contain all points that satisfy this property. + * + * We simply add the sum of all negative coefficients to the constant + * term. This ensures that if x satisfies the resulting constraints, + * then x plus any sum of unit vectors satisfies the original constraints. + */ +static __isl_give isl_basic_set *unit_box_base_points( + __isl_take isl_basic_set *bset) +{ + int i, j, k; + struct isl_basic_set *unit_box = NULL; + unsigned total; + + if (!bset) + goto error; + + if (bset->n_eq != 0) { + isl_space *space = isl_basic_set_get_space(bset); + isl_basic_set_free(bset); + return isl_basic_set_empty(space); + } + + total = isl_basic_set_total_dim(bset); + unit_box = isl_basic_set_alloc_space(isl_basic_set_get_space(bset), + 0, 0, bset->n_ineq); + + for (i = 0; i < bset->n_ineq; ++i) { + k = isl_basic_set_alloc_inequality(unit_box); + if (k < 0) + goto error; + isl_seq_cpy(unit_box->ineq[k], bset->ineq[i], 1 + total); + for (j = 0; j < total; ++j) { + if (isl_int_is_nonneg(unit_box->ineq[k][1 + j])) + continue; + isl_int_add(unit_box->ineq[k][0], + unit_box->ineq[k][0], unit_box->ineq[k][1 + j]); + } + } + + isl_basic_set_free(bset); + return unit_box; +error: + isl_basic_set_free(bset); + isl_basic_set_free(unit_box); + return NULL; +} + +/* Find an integer point in "bset", preferably one that is + * close to minimizing "f". + * + * We first check if we can easily put unit boxes inside bset. + * If so, we take the best base point of any of the unit boxes we can find + * and round it up to the nearest integer. + * If not, we simply pick any integer point in "bset". + */ +static __isl_give isl_vec *initial_solution(__isl_keep isl_basic_set *bset, + isl_int *f) +{ + enum isl_lp_result res; + struct isl_basic_set *unit_box; + struct isl_vec *sol; + + unit_box = unit_box_base_points(isl_basic_set_copy(bset)); + + res = isl_basic_set_solve_lp(unit_box, 0, f, bset->ctx->one, + NULL, NULL, &sol); + if (res == isl_lp_ok) { + isl_basic_set_free(unit_box); + return isl_vec_ceil(sol); + } + + isl_basic_set_free(unit_box); + + return isl_basic_set_sample_vec(isl_basic_set_copy(bset)); +} + +/* Restrict "bset" to those points with values for f in the interval [l, u]. + */ +static __isl_give isl_basic_set *add_bounds(__isl_take isl_basic_set *bset, + isl_int *f, isl_int l, isl_int u) +{ + int k; + unsigned total; + + total = isl_basic_set_total_dim(bset); + bset = isl_basic_set_extend_constraints(bset, 0, 2); + + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_cpy(bset->ineq[k], f, 1 + total); + isl_int_sub(bset->ineq[k][0], bset->ineq[k][0], l); + + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_neg(bset->ineq[k], f, 1 + total); + isl_int_add(bset->ineq[k][0], bset->ineq[k][0], u); + + return bset; +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Find an integer point in "bset" that minimizes f (in any) such that + * the value of f lies inside the interval [l, u]. + * Return this integer point if it can be found. + * Otherwise, return sol. + * + * We perform a number of steps until l > u. + * In each step, we look for an integer point with value in either + * the whole interval [l, u] or half of the interval [l, l+floor(u-l-1/2)]. + * The choice depends on whether we have found an integer point in the + * previous step. If so, we look for the next point in half of the remaining + * interval. + * If we find a point, the current solution is updated and u is set + * to its value minus 1. + * If no point can be found, we update l to the upper bound of the interval + * we checked (u or l+floor(u-l-1/2)) plus 1. + */ +static __isl_give isl_vec *solve_ilp_search(__isl_keep isl_basic_set *bset, + isl_int *f, isl_int *opt, __isl_take isl_vec *sol, isl_int l, isl_int u) +{ + isl_int tmp; + int divide = 1; + + isl_int_init(tmp); + + while (isl_int_le(l, u)) { + struct isl_basic_set *slice; + struct isl_vec *sample; + + if (!divide) + isl_int_set(tmp, u); + else { + isl_int_sub(tmp, u, l); + isl_int_fdiv_q_ui(tmp, tmp, 2); + isl_int_add(tmp, tmp, l); + } + slice = add_bounds(isl_basic_set_copy(bset), f, l, tmp); + sample = isl_basic_set_sample_vec(slice); + if (!sample) { + isl_vec_free(sol); + sol = NULL; + break; + } + if (sample->size > 0) { + isl_vec_free(sol); + sol = sample; + isl_seq_inner_product(f, sol->el, sol->size, opt); + isl_int_sub_ui(u, *opt, 1); + divide = 1; + } else { + isl_vec_free(sample); + if (!divide) + break; + isl_int_add_ui(l, tmp, 1); + divide = 0; + } + } + + isl_int_clear(tmp); + + return sol; +} + +/* Find an integer point in "bset" that minimizes f (if any). + * If sol_p is not NULL then the integer point is returned in *sol_p. + * The optimal value of f is returned in *opt. + * + * The algorithm maintains a currently best solution and an interval [l, u] + * of values of f for which integer solutions could potentially still be found. + * The initial value of the best solution so far is any solution. + * The initial value of l is minimal value of f over the rationals + * (rounded up to the nearest integer). + * The initial value of u is the value of f at the initial solution minus 1. + * + * We then call solve_ilp_search to perform a binary search on the interval. + */ +static enum isl_lp_result solve_ilp(__isl_keep isl_basic_set *bset, + isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p) +{ + enum isl_lp_result res; + isl_int l, u; + struct isl_vec *sol; + + res = isl_basic_set_solve_lp(bset, 0, f, bset->ctx->one, + opt, NULL, &sol); + if (res == isl_lp_ok && isl_int_is_one(sol->el[0])) { + if (sol_p) + *sol_p = sol; + else + isl_vec_free(sol); + return isl_lp_ok; + } + isl_vec_free(sol); + if (res == isl_lp_error || res == isl_lp_empty) + return res; + + sol = initial_solution(bset, f); + if (!sol) + return isl_lp_error; + if (sol->size == 0) { + isl_vec_free(sol); + return isl_lp_empty; + } + if (res == isl_lp_unbounded) { + isl_vec_free(sol); + return isl_lp_unbounded; + } + + isl_int_init(l); + isl_int_init(u); + + isl_int_set(l, *opt); + + isl_seq_inner_product(f, sol->el, sol->size, opt); + isl_int_sub_ui(u, *opt, 1); + + sol = solve_ilp_search(bset, f, opt, sol, l, u); + if (!sol) + res = isl_lp_error; + + isl_int_clear(l); + isl_int_clear(u); + + if (sol_p) + *sol_p = sol; + else + isl_vec_free(sol); + + return res; +} + +static enum isl_lp_result solve_ilp_with_eq(__isl_keep isl_basic_set *bset, + int max, isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p) +{ + unsigned dim; + enum isl_lp_result res; + struct isl_mat *T = NULL; + struct isl_vec *v; + + bset = isl_basic_set_copy(bset); + dim = isl_basic_set_total_dim(bset); + v = isl_vec_alloc(bset->ctx, 1 + dim); + if (!v) + goto error; + isl_seq_cpy(v->el, f, 1 + dim); + bset = isl_basic_set_remove_equalities(bset, &T, NULL); + v = isl_vec_mat_product(v, isl_mat_copy(T)); + if (!v) + goto error; + res = isl_basic_set_solve_ilp(bset, max, v->el, opt, sol_p); + isl_vec_free(v); + if (res == isl_lp_ok && sol_p) { + *sol_p = isl_mat_vec_product(T, *sol_p); + if (!*sol_p) + res = isl_lp_error; + } else + isl_mat_free(T); + isl_basic_set_free(bset); + return res; +error: + isl_mat_free(T); + isl_basic_set_free(bset); + return isl_lp_error; +} + +/* Find an integer point in "bset" that minimizes (or maximizes if max is set) + * f (if any). + * If sol_p is not NULL then the integer point is returned in *sol_p. + * The optimal value of f is returned in *opt. + * + * If there is any equality among the points in "bset", then we first + * project it out. Otherwise, we continue with solve_ilp above. + */ +enum isl_lp_result isl_basic_set_solve_ilp(__isl_keep isl_basic_set *bset, + int max, isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p) +{ + unsigned dim; + enum isl_lp_result res; + + if (!bset) + return isl_lp_error; + if (sol_p) + *sol_p = NULL; + + isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, + return isl_lp_error); + + if (isl_basic_set_plain_is_empty(bset)) + return isl_lp_empty; + + if (bset->n_eq) + return solve_ilp_with_eq(bset, max, f, opt, sol_p); + + dim = isl_basic_set_total_dim(bset); + + if (max) + isl_seq_neg(f, f, 1 + dim); + + res = solve_ilp(bset, f, opt, sol_p); + + if (max) { + isl_seq_neg(f, f, 1 + dim); + isl_int_neg(*opt, *opt); + } + + return res; +} + +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; + int bset_n_div, obj_n_div; + + if (!bset || !obj) + return isl_lp_error; + + ctx = isl_aff_get_ctx(obj); + if (!isl_space_is_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); + + bset_n_div = isl_basic_set_dim(bset, isl_dim_div); + obj_n_div = isl_aff_dim(obj, isl_dim_div); + if (bset_n_div == 0 && obj_n_div == 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_n_div); + exp2 = isl_alloc_array(ctx, int, obj_n_div); + if (!bset_div || (bset_n_div && !exp1) || (obj_n_div && !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. + * + * The parameters are assumed to have been aligned. + */ +static enum isl_lp_result isl_set_opt_aligned(__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_empty) + continue; + empty = 0; + if (max ? isl_int_gt(opt_i, *opt) : isl_int_lt(opt_i, *opt)) + isl_int_set(*opt, opt_i); + } + isl_int_clear(opt_i); + + return empty ? isl_lp_empty : isl_lp_ok; +} + +/* 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) +{ + enum isl_lp_result res; + isl_bool aligned; + + if (!set || !obj) + return isl_lp_error; + + aligned = isl_set_space_has_equal_params(set, obj->ls->dim); + if (aligned < 0) + return isl_lp_error; + if (aligned) + return isl_set_opt_aligned(set, max, obj, opt); + + set = isl_set_copy(set); + obj = isl_aff_copy(obj); + set = isl_set_align_params(set, isl_aff_get_domain_space(obj)); + obj = isl_aff_align_params(obj, isl_set_get_space(set)); + + res = isl_set_opt_aligned(set, max, obj, opt); + + isl_set_free(set); + isl_aff_free(obj); + + return res; +} + +/* Convert the result of a function that returns an isl_lp_result + * to an isl_val. The numerator of "v" is set to the optimal value + * if lp_res is isl_lp_ok. "max" is set if a maximum was computed. + * + * Return "v" with denominator set to 1 if lp_res is isl_lp_ok. + * Return NULL on error. + * Return a NaN if lp_res is isl_lp_empty. + * Return infinity or negative infinity if lp_res is isl_lp_unbounded, + * depending on "max". + */ +static __isl_give isl_val *convert_lp_result(enum isl_lp_result lp_res, + __isl_take isl_val *v, int max) +{ + isl_ctx *ctx; + + if (lp_res == isl_lp_ok) { + isl_int_set_si(v->d, 1); + return isl_val_normalize(v); + } + ctx = isl_val_get_ctx(v); + isl_val_free(v); + if (lp_res == isl_lp_error) + return NULL; + if (lp_res == isl_lp_empty) + return isl_val_nan(ctx); + if (max) + return isl_val_infty(ctx); + else + return isl_val_neginfty(ctx); +} + +/* Return the minimum (maximum if max is set) of the integer affine + * expression "obj" over the points in "bset". + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if "bset" is empty. + * + * Call isl_basic_set_opt and translate the results. + */ +__isl_give isl_val *isl_basic_set_opt_val(__isl_keep isl_basic_set *bset, + int max, __isl_keep isl_aff *obj) +{ + isl_ctx *ctx; + isl_val *res; + enum isl_lp_result lp_res; + + if (!bset || !obj) + return NULL; + + ctx = isl_aff_get_ctx(obj); + res = isl_val_alloc(ctx); + if (!res) + return NULL; + lp_res = isl_basic_set_opt(bset, max, obj, &res->n); + return convert_lp_result(lp_res, res, max); +} + +/* Return the maximum of the integer affine + * expression "obj" over the points in "bset". + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if "bset" is empty. + */ +__isl_give isl_val *isl_basic_set_max_val(__isl_keep isl_basic_set *bset, + __isl_keep isl_aff *obj) +{ + return isl_basic_set_opt_val(bset, 1, obj); +} + +/* Return the minimum (maximum if max is set) of the integer affine + * expression "obj" over the points in "set". + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if "set" is empty. + * + * Call isl_set_opt and translate the results. + */ +__isl_give isl_val *isl_set_opt_val(__isl_keep isl_set *set, int max, + __isl_keep isl_aff *obj) +{ + isl_ctx *ctx; + isl_val *res; + enum isl_lp_result lp_res; + + if (!set || !obj) + return NULL; + + ctx = isl_aff_get_ctx(obj); + res = isl_val_alloc(ctx); + if (!res) + return NULL; + lp_res = isl_set_opt(set, max, obj, &res->n); + return convert_lp_result(lp_res, res, max); +} + +/* Return the minimum of the integer affine + * expression "obj" over the points in "set". + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if "set" is empty. + */ +__isl_give isl_val *isl_set_min_val(__isl_keep isl_set *set, + __isl_keep isl_aff *obj) +{ + return isl_set_opt_val(set, 0, obj); +} + +/* Return the maximum of the integer affine + * expression "obj" over the points in "set". + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if "set" is empty. + */ +__isl_give isl_val *isl_set_max_val(__isl_keep isl_set *set, + __isl_keep isl_aff *obj) +{ + return isl_set_opt_val(set, 1, obj); +} + +/* Return the optimum (min or max depending on "max") of "v1" and "v2", + * where either may be NaN, signifying an uninitialized value. + * That is, if either is NaN, then return the other one. + */ +static __isl_give isl_val *val_opt(__isl_take isl_val *v1, + __isl_take isl_val *v2, int max) +{ + if (!v1 || !v2) + goto error; + if (isl_val_is_nan(v1)) { + isl_val_free(v1); + return v2; + } + if (isl_val_is_nan(v2)) { + isl_val_free(v2); + return v1; + } + if (max) + return isl_val_max(v1, v2); + else + return isl_val_min(v1, v2); +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Internal data structure for isl_set_opt_pw_aff. + * + * "max" is set if the maximum should be computed. + * "set" is the set over which the optimum should be computed. + * "res" contains the current optimum and is initialized to NaN. + */ +struct isl_set_opt_data { + int max; + isl_set *set; + + isl_val *res; +}; + +/* Update the optimum in data->res with respect to the affine function + * "aff" defined over "set". + */ +static isl_stat piece_opt(__isl_take isl_set *set, __isl_take isl_aff *aff, + void *user) +{ + struct isl_set_opt_data *data = user; + isl_val *opt; + + set = isl_set_intersect(set, isl_set_copy(data->set)); + opt = isl_set_opt_val(set, data->max, aff); + isl_set_free(set); + isl_aff_free(aff); + + data->res = val_opt(data->res, opt, data->max); + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Return the minimum (maximum if "max" is set) of the integer piecewise affine + * expression "obj" over the points in "set". + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if the intersection of "set" with the domain of "obj" is empty. + * + * Initialize the result to NaN and then update it for each of the pieces + * in "obj". + */ +static __isl_give isl_val *isl_set_opt_pw_aff(__isl_keep isl_set *set, int max, + __isl_keep isl_pw_aff *obj) +{ + struct isl_set_opt_data data = { max, set }; + + data.res = isl_val_nan(isl_set_get_ctx(set)); + if (isl_pw_aff_foreach_piece(obj, &piece_opt, &data) < 0) + return isl_val_free(data.res); + + return data.res; +} + +/* Internal data structure for isl_union_set_opt_union_pw_aff. + * + * "max" is set if the maximum should be computed. + * "obj" is the objective function that needs to be optimized. + * "res" contains the current optimum and is initialized to NaN. + */ +struct isl_union_set_opt_data { + int max; + isl_union_pw_aff *obj; + + isl_val *res; +}; + +/* Update the optimum in data->res with the optimum over "set". + * Do so by first extracting the matching objective function + * from data->obj. + */ +static isl_stat set_opt(__isl_take isl_set *set, void *user) +{ + struct isl_union_set_opt_data *data = user; + isl_space *space; + isl_pw_aff *pa; + isl_val *opt; + + space = isl_set_get_space(set); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, 1); + pa = isl_union_pw_aff_extract_pw_aff(data->obj, space); + opt = isl_set_opt_pw_aff(set, data->max, pa); + isl_pw_aff_free(pa); + isl_set_free(set); + + data->res = val_opt(data->res, opt, data->max); + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Return the minimum (maximum if "max" is set) of the integer piecewise affine + * expression "obj" over the points in "uset". + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if the intersection of "uset" with the domain of "obj" is empty. + * + * Initialize the result to NaN and then update it for each of the sets + * in "uset". + */ +static __isl_give isl_val *isl_union_set_opt_union_pw_aff( + __isl_keep isl_union_set *uset, int max, + __isl_keep isl_union_pw_aff *obj) +{ + struct isl_union_set_opt_data data = { max, obj }; + + data.res = isl_val_nan(isl_union_set_get_ctx(uset)); + if (isl_union_set_foreach_set(uset, &set_opt, &data) < 0) + return isl_val_free(data.res); + + return data.res; +} + +/* Return a list of minima (maxima if "max" is set) over the points in "uset" + * for each of the expressions in "obj". + * + * An element in the list is infinity or negative infinity if the optimal + * value of the corresponding expression is unbounded and + * NaN if the intersection of "uset" with the domain of the expression + * is empty. + * + * Iterate over all the expressions in "obj" and collect the results. + */ +static __isl_give isl_multi_val *isl_union_set_opt_multi_union_pw_aff( + __isl_keep isl_union_set *uset, int max, + __isl_keep isl_multi_union_pw_aff *obj) +{ + int i, n; + isl_multi_val *mv; + + if (!uset || !obj) + return NULL; + + n = isl_multi_union_pw_aff_dim(obj, isl_dim_set); + mv = isl_multi_val_zero(isl_multi_union_pw_aff_get_space(obj)); + + for (i = 0; i < n; ++i) { + isl_val *v; + isl_union_pw_aff *upa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(obj, i); + v = isl_union_set_opt_union_pw_aff(uset, max, upa); + isl_union_pw_aff_free(upa); + mv = isl_multi_val_set_val(mv, i, v); + } + + return mv; +} + +/* Return a list of minima over the points in "uset" + * for each of the expressions in "obj". + * + * An element in the list is infinity or negative infinity if the optimal + * value of the corresponding expression is unbounded and + * NaN if the intersection of "uset" with the domain of the expression + * is empty. + */ +__isl_give isl_multi_val *isl_union_set_min_multi_union_pw_aff( + __isl_keep isl_union_set *uset, __isl_keep isl_multi_union_pw_aff *obj) +{ + return isl_union_set_opt_multi_union_pw_aff(uset, 0, obj); +} Index: contrib/isl/isl_ilp_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_ilp_private.h @@ -0,0 +1,11 @@ +#ifndef ISL_ILP_PRIVATE_H +#define ISL_ILP_PRIVATE_H + +#include +#include +#include + +enum isl_lp_result isl_basic_set_solve_ilp(__isl_keep isl_basic_set *bset, + int max, isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p); + +#endif Index: contrib/isl/isl_imath.h =================================================================== --- /dev/null +++ contrib/isl/isl_imath.h @@ -0,0 +1,10 @@ +#include +#include + +uint32_t isl_imath_hash(mp_int v, uint32_t hash); +int isl_imath_fits_ulong_p(mp_int op); +int isl_imath_fits_slong_p(mp_int op); +void isl_imath_addmul_ui(mp_int rop, mp_int op1, unsigned long op2); +void isl_imath_submul_ui(mp_int rop, mp_int op1, unsigned long op2); +void isl_imath_cdiv_q_ui(mp_int rop, mp_int op1, unsigned long op2); +void isl_imath_fdiv_q_ui(mp_int rop, mp_int op1, unsigned long op2); Index: contrib/isl/isl_imath.c =================================================================== --- /dev/null +++ contrib/isl/isl_imath.c @@ -0,0 +1,83 @@ +#include + +uint32_t isl_imath_hash(mp_int v, uint32_t hash) +{ + unsigned const char *data = (unsigned char *)v->digits; + unsigned const char *end = data + v->used * sizeof(v->digits[0]); + + if (v->sign == 1) + isl_hash_byte(hash, 0xFF); + for (; data < end; ++data) + isl_hash_byte(hash, *data); + return hash; +} + +/* Try a standard conversion that fits into a long. + */ +int isl_imath_fits_slong_p(mp_int op) +{ + long out; + mp_result res = mp_int_to_int(op, &out); + return res == MP_OK; +} + +/* Try a standard conversion that fits into an unsigned long. + */ +int isl_imath_fits_ulong_p(mp_int op) +{ + unsigned long out; + mp_result res = mp_int_to_uint(op, &out); + return res == MP_OK; +} + +void isl_imath_addmul_ui(mp_int rop, mp_int op1, unsigned long op2) +{ + mpz_t temp; + mp_int_init(&temp); + + mp_int_set_uvalue(&temp, op2); + mp_int_mul(op1, &temp, &temp); + mp_int_add(rop, &temp, rop); + + mp_int_clear(&temp); +} + +void isl_imath_submul_ui(mp_int rop, mp_int op1, unsigned long op2) +{ + mpz_t temp; + mp_int_init(&temp); + + mp_int_set_uvalue(&temp, op2); + mp_int_mul(op1, &temp, &temp); + mp_int_sub(rop, &temp, rop); + + mp_int_clear(&temp); +} + +/* Compute the division of lhs by a rhs of type unsigned long, rounding towards + * positive infinity (Ceil). + */ +void isl_imath_cdiv_q_ui(mp_int rop, mp_int lhs, unsigned long rhs) +{ + mpz_t temp; + mp_int_init(&temp); + + mp_int_set_uvalue(&temp, rhs); + impz_cdiv_q(rop, lhs, &temp); + + mp_int_clear(&temp); +} + +/* Compute the division of lhs by a rhs of type unsigned long, rounding towards + * negative infinity (Floor). + */ +void isl_imath_fdiv_q_ui(mp_int rop, mp_int lhs, unsigned long rhs) +{ + mpz_t temp; + mp_int_init(&temp); + + mp_int_set_uvalue(&temp, rhs); + impz_fdiv_q(rop, lhs, &temp); + + mp_int_clear(&temp); +} Index: contrib/isl/isl_input.c =================================================================== --- /dev/null +++ contrib/isl/isl_input.c @@ -0,0 +1,4050 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "isl_polynomial_private.h" +#include +#include +#include +#include +#include +#include +#include + +struct variable { + char *name; + int pos; + struct variable *next; +}; + +struct vars { + struct isl_ctx *ctx; + int n; + struct variable *v; +}; + +static struct vars *vars_new(struct isl_ctx *ctx) +{ + struct vars *v; + v = isl_alloc_type(ctx, struct vars); + if (!v) + return NULL; + v->ctx = ctx; + v->n = 0; + v->v = NULL; + return v; +} + +static void variable_free(struct variable *var) +{ + while (var) { + struct variable *next = var->next; + free(var->name); + free(var); + var = next; + } +} + +static void vars_free(struct vars *v) +{ + if (!v) + return; + variable_free(v->v); + free(v); +} + +static void vars_drop(struct vars *v, int n) +{ + struct variable *var; + + if (!v || !v->v) + return; + + v->n -= n; + + var = v->v; + while (--n >= 0) { + struct variable *next = var->next; + free(var->name); + free(var); + var = next; + } + v->v = var; +} + +static struct variable *variable_new(struct vars *v, const char *name, int len, + int pos) +{ + struct variable *var; + var = isl_calloc_type(v->ctx, struct variable); + if (!var) + goto error; + var->name = strdup(name); + var->name[len] = '\0'; + var->pos = pos; + var->next = v->v; + return var; +error: + variable_free(v->v); + return NULL; +} + +static int vars_pos(struct vars *v, const char *s, int len) +{ + int pos; + struct variable *q; + + if (len == -1) + len = strlen(s); + for (q = v->v; q; q = q->next) { + if (strncmp(q->name, s, len) == 0 && q->name[len] == '\0') + break; + } + if (q) + pos = q->pos; + else { + pos = v->n; + v->v = variable_new(v, s, len, v->n); + if (!v->v) + return -1; + v->n++; + } + return pos; +} + +static int vars_add_anon(struct vars *v) +{ + v->v = variable_new(v, "", 0, v->n); + + if (!v->v) + return -1; + v->n++; + + return 0; +} + +/* Obtain next token, with some preprocessing. + * In particular, evaluate expressions of the form x^y, + * with x and y values. + */ +static struct isl_token *next_token(__isl_keep isl_stream *s) +{ + struct isl_token *tok, *tok2; + + tok = isl_stream_next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) + return tok; + if (!isl_stream_eat_if_available(s, '^')) + return tok; + tok2 = isl_stream_next_token(s); + if (!tok2 || tok2->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok2, "expecting constant value"); + goto error; + } + + isl_int_pow_ui(tok->u.v, tok->u.v, isl_int_get_ui(tok2->u.v)); + + isl_token_free(tok2); + return tok; +error: + isl_token_free(tok); + isl_token_free(tok2); + return NULL; +} + +/* Read an isl_val from "s". + * + * The following token sequences are recognized + * + * "infty" -> infty + * "-" "infty" -> -infty + * "NaN" -> NaN + * n "/" d -> n/d + * v -> v + * + * where n, d and v are integer constants. + */ +__isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s) +{ + struct isl_token *tok = NULL; + struct isl_token *tok2 = NULL; + isl_val *val; + + tok = next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + if (tok->type == ISL_TOKEN_INFTY) { + isl_token_free(tok); + return isl_val_infty(s->ctx); + } + if (tok->type == '-' && + isl_stream_eat_if_available(s, ISL_TOKEN_INFTY)) { + isl_token_free(tok); + return isl_val_neginfty(s->ctx); + } + if (tok->type == ISL_TOKEN_NAN) { + isl_token_free(tok); + return isl_val_nan(s->ctx); + } + if (tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting value"); + goto error; + } + + if (isl_stream_eat_if_available(s, '/')) { + tok2 = next_token(s); + if (!tok2) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + if (tok2->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok2, "expecting value"); + goto error; + } + val = isl_val_rat_from_isl_int(s->ctx, tok->u.v, tok2->u.v); + val = isl_val_normalize(val); + } else { + val = isl_val_int_from_isl_int(s->ctx, tok->u.v); + } + + isl_token_free(tok); + isl_token_free(tok2); + return val; +error: + isl_token_free(tok); + isl_token_free(tok2); + return NULL; +} + +/* Read an isl_val from "str". + */ +struct isl_val *isl_val_read_from_str(struct isl_ctx *ctx, + const char *str) +{ + isl_val *val; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + val = isl_stream_read_val(s); + isl_stream_free(s); + return val; +} + +static int accept_cst_factor(__isl_keep isl_stream *s, isl_int *f) +{ + struct isl_token *tok; + + tok = next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting constant value"); + goto error; + } + + isl_int_mul(*f, *f, tok->u.v); + + isl_token_free(tok); + + if (isl_stream_eat_if_available(s, '*')) + return accept_cst_factor(s, f); + + return 0; +error: + isl_token_free(tok); + return -1; +} + +/* Given an affine expression aff, return an affine expression + * for aff % d, with d the next token on the stream, which is + * assumed to be a constant. + * + * We introduce an integer division q = [aff/d] and the result + * is set to aff - d q. + */ +static __isl_give isl_pw_aff *affine_mod(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_pw_aff *aff) +{ + struct isl_token *tok; + isl_pw_aff *q; + + tok = next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting constant value"); + goto error; + } + + q = isl_pw_aff_copy(aff); + q = isl_pw_aff_scale_down(q, tok->u.v); + q = isl_pw_aff_floor(q); + q = isl_pw_aff_scale(q, tok->u.v); + + aff = isl_pw_aff_sub(aff, q); + + isl_token_free(tok); + return aff; +error: + isl_pw_aff_free(aff); + isl_token_free(tok); + return NULL; +} + +static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s, + __isl_take isl_space *space, struct vars *v); +static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s, + __isl_take isl_space *dim, struct vars *v); + +static __isl_give isl_pw_aff *accept_minmax(__isl_keep isl_stream *s, + __isl_take isl_space *dim, struct vars *v) +{ + struct isl_token *tok; + isl_pw_aff_list *list = NULL; + int min; + + tok = isl_stream_next_token(s); + if (!tok) + goto error; + min = tok->type == ISL_TOKEN_MIN; + isl_token_free(tok); + + if (isl_stream_eat(s, '(')) + goto error; + + list = accept_affine_list(s, isl_space_copy(dim), v); + if (!list) + goto error; + + if (isl_stream_eat(s, ')')) + goto error; + + isl_space_free(dim); + return min ? isl_pw_aff_list_min(list) : isl_pw_aff_list_max(list); +error: + isl_space_free(dim); + isl_pw_aff_list_free(list); + return NULL; +} + +/* Is "tok" the start of an integer division? + */ +static int is_start_of_div(struct isl_token *tok) +{ + if (!tok) + return 0; + if (tok->type == '[') + return 1; + if (tok->type == ISL_TOKEN_FLOOR) + return 1; + if (tok->type == ISL_TOKEN_CEIL) + return 1; + if (tok->type == ISL_TOKEN_FLOORD) + return 1; + if (tok->type == ISL_TOKEN_CEILD) + return 1; + return 0; +} + +/* Read an integer division from "s" and return it as an isl_pw_aff. + * + * The integer division can be of the form + * + * [] + * floor() + * ceil() + * floord(,) + * ceild(,) + */ +static __isl_give isl_pw_aff *accept_div(__isl_keep isl_stream *s, + __isl_take isl_space *dim, struct vars *v) +{ + struct isl_token *tok; + int f = 0; + int c = 0; + int extra = 0; + isl_pw_aff *pwaff = NULL; + + if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOORD)) + extra = f = 1; + else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEILD)) + extra = c = 1; + else if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOOR)) + f = 1; + else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEIL)) + c = 1; + if (f || c) { + if (isl_stream_eat(s, '(')) + goto error; + } else { + if (isl_stream_eat(s, '[')) + goto error; + } + + pwaff = accept_affine(s, isl_space_copy(dim), v); + + if (extra) { + if (isl_stream_eat(s, ',')) + goto error; + + tok = next_token(s); + if (!tok) + goto error; + if (tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expected denominator"); + isl_stream_push_token(s, tok); + goto error; + } + pwaff = isl_pw_aff_scale_down(pwaff, tok->u.v); + isl_token_free(tok); + } + + if (c) + pwaff = isl_pw_aff_ceil(pwaff); + else + pwaff = isl_pw_aff_floor(pwaff); + + if (f || c) { + if (isl_stream_eat(s, ')')) + goto error; + } else { + if (isl_stream_eat(s, ']')) + goto error; + } + + isl_space_free(dim); + return pwaff; +error: + isl_space_free(dim); + isl_pw_aff_free(pwaff); + return NULL; +} + +static __isl_give isl_pw_aff *accept_affine_factor(__isl_keep isl_stream *s, + __isl_take isl_space *dim, struct vars *v) +{ + struct isl_token *tok = NULL; + isl_pw_aff *res = NULL; + + tok = next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + + if (tok->type == ISL_TOKEN_AFF) { + res = isl_pw_aff_copy(tok->u.pwaff); + isl_token_free(tok); + } else if (tok->type == ISL_TOKEN_IDENT) { + int n = v->n; + int pos = vars_pos(v, tok->u.s, -1); + isl_aff *aff; + + if (pos < 0) + goto error; + if (pos >= n) { + vars_drop(v, v->n - n); + isl_stream_error(s, tok, "unknown identifier"); + goto error; + } + + aff = isl_aff_zero_on_domain(isl_local_space_from_space(isl_space_copy(dim))); + if (!aff) + goto error; + isl_int_set_si(aff->v->el[2 + pos], 1); + res = isl_pw_aff_from_aff(aff); + isl_token_free(tok); + } else if (tok->type == ISL_TOKEN_VALUE) { + if (isl_stream_eat_if_available(s, '*')) { + res = accept_affine_factor(s, isl_space_copy(dim), v); + res = isl_pw_aff_scale(res, tok->u.v); + } else { + isl_local_space *ls; + isl_aff *aff; + ls = isl_local_space_from_space(isl_space_copy(dim)); + aff = isl_aff_zero_on_domain(ls); + aff = isl_aff_add_constant(aff, tok->u.v); + res = isl_pw_aff_from_aff(aff); + } + isl_token_free(tok); + } else if (tok->type == '(') { + isl_token_free(tok); + tok = NULL; + res = accept_affine(s, isl_space_copy(dim), v); + if (!res) + goto error; + if (isl_stream_eat(s, ')')) + goto error; + } else if (is_start_of_div(tok)) { + isl_stream_push_token(s, tok); + tok = NULL; + res = accept_div(s, isl_space_copy(dim), v); + } else if (tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX) { + isl_stream_push_token(s, tok); + tok = NULL; + res = accept_minmax(s, isl_space_copy(dim), v); + } else { + isl_stream_error(s, tok, "expecting factor"); + goto error; + } + if (isl_stream_eat_if_available(s, '%') || + isl_stream_eat_if_available(s, ISL_TOKEN_MOD)) { + isl_space_free(dim); + return affine_mod(s, v, res); + } + if (isl_stream_eat_if_available(s, '*')) { + isl_int f; + isl_int_init(f); + isl_int_set_si(f, 1); + if (accept_cst_factor(s, &f) < 0) { + isl_int_clear(f); + goto error2; + } + res = isl_pw_aff_scale(res, f); + isl_int_clear(f); + } + if (isl_stream_eat_if_available(s, '/')) { + isl_int f; + isl_int_init(f); + isl_int_set_si(f, 1); + if (accept_cst_factor(s, &f) < 0) { + isl_int_clear(f); + goto error2; + } + res = isl_pw_aff_scale_down(res, f); + isl_int_clear(f); + } + + isl_space_free(dim); + return res; +error: + isl_token_free(tok); +error2: + isl_pw_aff_free(res); + isl_space_free(dim); + return NULL; +} + +static __isl_give isl_pw_aff *add_cst(__isl_take isl_pw_aff *pwaff, isl_int v) +{ + isl_aff *aff; + isl_space *space; + + space = isl_pw_aff_get_domain_space(pwaff); + aff = isl_aff_zero_on_domain(isl_local_space_from_space(space)); + aff = isl_aff_add_constant(aff, v); + + return isl_pw_aff_add(pwaff, isl_pw_aff_from_aff(aff)); +} + +/* Return a piecewise affine expression defined on the specified domain + * that represents NaN. + */ +static __isl_give isl_pw_aff *nan_on_domain(__isl_keep isl_space *space) +{ + isl_local_space *ls; + + ls = isl_local_space_from_space(isl_space_copy(space)); + return isl_pw_aff_nan_on_domain(ls); +} + +static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s, + __isl_take isl_space *space, struct vars *v) +{ + struct isl_token *tok = NULL; + isl_local_space *ls; + isl_pw_aff *res; + int sign = 1; + + ls = isl_local_space_from_space(isl_space_copy(space)); + res = isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls)); + if (!res) + goto error; + + for (;;) { + tok = next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + if (tok->type == '-') { + sign = -sign; + isl_token_free(tok); + continue; + } + if (tok->type == '(' || is_start_of_div(tok) || + tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX || + tok->type == ISL_TOKEN_IDENT || + tok->type == ISL_TOKEN_AFF) { + isl_pw_aff *term; + isl_stream_push_token(s, tok); + tok = NULL; + term = accept_affine_factor(s, + isl_space_copy(space), v); + if (sign < 0) + res = isl_pw_aff_sub(res, term); + else + res = isl_pw_aff_add(res, term); + if (!res) + goto error; + sign = 1; + } else if (tok->type == ISL_TOKEN_VALUE) { + if (sign < 0) + isl_int_neg(tok->u.v, tok->u.v); + if (isl_stream_eat_if_available(s, '*') || + isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) { + isl_pw_aff *term; + term = accept_affine_factor(s, + isl_space_copy(space), v); + term = isl_pw_aff_scale(term, tok->u.v); + res = isl_pw_aff_add(res, term); + if (!res) + goto error; + } else { + res = add_cst(res, tok->u.v); + } + sign = 1; + } else if (tok->type == ISL_TOKEN_NAN) { + res = isl_pw_aff_add(res, nan_on_domain(space)); + } else { + isl_stream_error(s, tok, "unexpected isl_token"); + isl_stream_push_token(s, tok); + isl_pw_aff_free(res); + isl_space_free(space); + return NULL; + } + isl_token_free(tok); + + tok = next_token(s); + if (tok && tok->type == '-') { + sign = -sign; + isl_token_free(tok); + } else if (tok && tok->type == '+') { + /* nothing */ + isl_token_free(tok); + } else if (tok && tok->type == ISL_TOKEN_VALUE && + isl_int_is_neg(tok->u.v)) { + isl_stream_push_token(s, tok); + } else { + if (tok) + isl_stream_push_token(s, tok); + break; + } + } + + isl_space_free(space); + return res; +error: + isl_space_free(space); + isl_token_free(tok); + isl_pw_aff_free(res); + return NULL; +} + +/* Is "type" the type of a comparison operator between lists + * of affine expressions? + */ +static int is_list_comparator_type(int type) +{ + switch (type) { + case ISL_TOKEN_LEX_LT: + case ISL_TOKEN_LEX_GT: + case ISL_TOKEN_LEX_LE: + case ISL_TOKEN_LEX_GE: + return 1; + default: + return 0; + } +} + +static int is_comparator(struct isl_token *tok) +{ + if (!tok) + return 0; + if (is_list_comparator_type(tok->type)) + return 1; + + switch (tok->type) { + case ISL_TOKEN_LT: + case ISL_TOKEN_GT: + case ISL_TOKEN_LE: + case ISL_TOKEN_GE: + case ISL_TOKEN_NE: + case '=': + return 1; + default: + return 0; + } +} + +static __isl_give isl_map *read_formula(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational); +static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s, + __isl_take isl_space *dim, struct vars *v, int rational); + +/* Accept a ternary operator, given the first argument. + */ +static __isl_give isl_pw_aff *accept_ternary(__isl_keep isl_stream *s, + __isl_take isl_map *cond, struct vars *v, int rational) +{ + isl_space *dim; + isl_pw_aff *pwaff1 = NULL, *pwaff2 = NULL, *pa_cond; + + if (!cond) + return NULL; + + if (isl_stream_eat(s, '?')) + goto error; + + dim = isl_space_wrap(isl_map_get_space(cond)); + pwaff1 = accept_extended_affine(s, dim, v, rational); + if (!pwaff1) + goto error; + + if (isl_stream_eat(s, ':')) + goto error; + + dim = isl_pw_aff_get_domain_space(pwaff1); + pwaff2 = accept_extended_affine(s, dim, v, rational); + if (!pwaff1) + goto error; + + pa_cond = isl_set_indicator_function(isl_map_wrap(cond)); + return isl_pw_aff_cond(pa_cond, pwaff1, pwaff2); +error: + isl_map_free(cond); + isl_pw_aff_free(pwaff1); + isl_pw_aff_free(pwaff2); + return NULL; +} + +/* Set *line and *col to those of the next token, if any. + */ +static void set_current_line_col(__isl_keep isl_stream *s, int *line, int *col) +{ + struct isl_token *tok; + + tok = isl_stream_next_token(s); + if (!tok) + return; + + *line = tok->line; + *col = tok->col; + isl_stream_push_token(s, tok); +} + +/* Push a token encapsulating "pa" onto "s", with the given + * line and column. + */ +static int push_aff(__isl_keep isl_stream *s, int line, int col, + __isl_take isl_pw_aff *pa) +{ + struct isl_token *tok; + + tok = isl_token_new(s->ctx, line, col, 0); + if (!tok) + goto error; + tok->type = ISL_TOKEN_AFF; + tok->u.pwaff = pa; + isl_stream_push_token(s, tok); + + return 0; +error: + isl_pw_aff_free(pa); + return -1; +} + +/* Accept an affine expression that may involve ternary operators. + * We first read an affine expression. + * If it is not followed by a comparison operator, we simply return it. + * Otherwise, we assume the affine expression is part of the first + * argument of a ternary operator and try to parse that. + */ +static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s, + __isl_take isl_space *dim, struct vars *v, int rational) +{ + isl_space *space; + isl_map *cond; + isl_pw_aff *pwaff; + struct isl_token *tok; + int line = -1, col = -1; + int is_comp; + + set_current_line_col(s, &line, &col); + + pwaff = accept_affine(s, dim, v); + if (rational) + pwaff = isl_pw_aff_set_rational(pwaff); + if (!pwaff) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) + return isl_pw_aff_free(pwaff); + + is_comp = is_comparator(tok); + isl_stream_push_token(s, tok); + if (!is_comp) + return pwaff; + + space = isl_pw_aff_get_domain_space(pwaff); + cond = isl_map_universe(isl_space_unwrap(space)); + + if (push_aff(s, line, col, pwaff) < 0) + cond = isl_map_free(cond); + if (!cond) + return NULL; + + cond = read_formula(s, v, cond, rational); + + return accept_ternary(s, cond, v, rational); +} + +static __isl_give isl_map *read_var_def(__isl_keep isl_stream *s, + __isl_take isl_map *map, enum isl_dim_type type, struct vars *v, + int rational) +{ + isl_pw_aff *def; + int pos; + isl_map *def_map; + + if (type == isl_dim_param) + pos = isl_map_dim(map, isl_dim_param); + else { + pos = isl_map_dim(map, isl_dim_in); + if (type == isl_dim_out) + pos += isl_map_dim(map, isl_dim_out); + type = isl_dim_in; + } + --pos; + + def = accept_extended_affine(s, isl_space_wrap(isl_map_get_space(map)), + v, rational); + def_map = isl_map_from_pw_aff(def); + def_map = isl_map_equate(def_map, type, pos, isl_dim_out, 0); + def_map = isl_set_unwrap(isl_map_domain(def_map)); + + map = isl_map_intersect(map, def_map); + + return map; +} + +static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s, + __isl_take isl_space *dim, struct vars *v) +{ + isl_pw_aff *pwaff; + isl_pw_aff_list *list; + struct isl_token *tok = NULL; + + pwaff = accept_affine(s, isl_space_copy(dim), v); + list = isl_pw_aff_list_from_pw_aff(pwaff); + if (!list) + goto error; + + for (;;) { + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + if (tok->type != ',') { + isl_stream_push_token(s, tok); + break; + } + isl_token_free(tok); + + pwaff = accept_affine(s, isl_space_copy(dim), v); + list = isl_pw_aff_list_concat(list, + isl_pw_aff_list_from_pw_aff(pwaff)); + if (!list) + goto error; + } + + isl_space_free(dim); + return list; +error: + isl_space_free(dim); + isl_pw_aff_list_free(list); + return NULL; +} + +static __isl_give isl_map *read_defined_var_list(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational) +{ + struct isl_token *tok; + + while ((tok = isl_stream_next_token(s)) != NULL) { + int p; + int n = v->n; + + if (tok->type != ISL_TOKEN_IDENT) + break; + + p = vars_pos(v, tok->u.s, -1); + if (p < 0) + goto error; + if (p < n) { + isl_stream_error(s, tok, "expecting unique identifier"); + goto error; + } + + map = isl_map_add_dims(map, isl_dim_out, 1); + + isl_token_free(tok); + tok = isl_stream_next_token(s); + if (tok && tok->type == '=') { + isl_token_free(tok); + map = read_var_def(s, map, isl_dim_out, v, rational); + tok = isl_stream_next_token(s); + } + + if (!tok || tok->type != ',') + break; + + isl_token_free(tok); + } + if (tok) + isl_stream_push_token(s, tok); + + return map; +error: + isl_token_free(tok); + isl_map_free(map); + return NULL; +} + +static int next_is_tuple(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int is_tuple; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type == '[') { + isl_stream_push_token(s, tok); + return 1; + } + if (tok->type != ISL_TOKEN_IDENT && !tok->is_keyword) { + isl_stream_push_token(s, tok); + return 0; + } + + is_tuple = isl_stream_next_token_is(s, '['); + + isl_stream_push_token(s, tok); + + return is_tuple; +} + +/* Is "pa" an expression in term of earlier dimensions? + * The alternative is that the dimension is defined to be equal to itself, + * meaning that it has a universe domain and an expression that depends + * on itself. "i" is the position of the expression in a sequence + * of "n" expressions. The final dimensions of "pa" correspond to + * these "n" expressions. + */ +static int pw_aff_is_expr(__isl_keep isl_pw_aff *pa, int i, int n) +{ + isl_aff *aff; + + if (!pa) + return -1; + if (pa->n != 1) + return 1; + if (!isl_set_plain_is_universe(pa->p[0].set)) + return 1; + + aff = pa->p[0].aff; + if (isl_int_is_zero(aff->v->el[aff->v->size - n + i])) + return 1; + return 0; +} + +/* Does the tuple contain any dimensions that are defined + * in terms of earlier dimensions? + */ +static int tuple_has_expr(__isl_keep isl_multi_pw_aff *tuple) +{ + int i, n; + int has_expr = 0; + isl_pw_aff *pa; + + if (!tuple) + return -1; + n = isl_multi_pw_aff_dim(tuple, isl_dim_out); + for (i = 0; i < n; ++i) { + pa = isl_multi_pw_aff_get_pw_aff(tuple, i); + has_expr = pw_aff_is_expr(pa, i, n); + isl_pw_aff_free(pa); + if (has_expr < 0 || has_expr) + break; + } + + return has_expr; +} + +/* Set the name of dimension "pos" in "space" to "name". + * During printing, we add primes if the same name appears more than once + * to distinguish the occurrences. Here, we remove those primes from "name" + * before setting the name of the dimension. + */ +static __isl_give isl_space *space_set_dim_name(__isl_take isl_space *space, + int pos, char *name) +{ + char *prime; + + if (!name) + return space; + + prime = strchr(name, '\''); + if (prime) + *prime = '\0'; + space = isl_space_set_dim_name(space, isl_dim_out, pos, name); + if (prime) + *prime = '\''; + + return space; +} + +/* Accept a piecewise affine expression. + * + * At the outer level, the piecewise affine expression may be of the form + * + * aff1 : condition1; aff2 : conditions2; ... + * + * or simply + * + * aff + * + * each of the affine expressions may in turn include ternary operators. + * + * There may be parentheses around some subexpression of "aff1" + * around "aff1" itself, around "aff1 : condition1" and/or + * around the entire piecewise affine expression. + * We therefore remove the opening parenthesis (if any) from the stream + * in case the closing parenthesis follows the colon, but if the closing + * parenthesis is the first thing in the stream after the parsed affine + * expression, we push the parsed expression onto the stream and parse + * again in case the parentheses enclose some subexpression of "aff1". + */ +static __isl_give isl_pw_aff *accept_piecewise_affine(__isl_keep isl_stream *s, + __isl_take isl_space *space, struct vars *v, int rational) +{ + isl_pw_aff *res; + isl_space *res_space; + + res_space = isl_space_from_domain(isl_space_copy(space)); + res_space = isl_space_add_dims(res_space, isl_dim_out, 1); + res = isl_pw_aff_empty(res_space); + do { + isl_pw_aff *pa; + int seen_paren; + int line = -1, col = -1; + + set_current_line_col(s, &line, &col); + seen_paren = isl_stream_eat_if_available(s, '('); + if (seen_paren) + pa = accept_piecewise_affine(s, isl_space_copy(space), + v, rational); + else + pa = accept_extended_affine(s, isl_space_copy(space), + v, rational); + if (seen_paren && isl_stream_eat_if_available(s, ')')) { + seen_paren = 0; + if (push_aff(s, line, col, pa) < 0) + goto error; + pa = accept_extended_affine(s, isl_space_copy(space), + v, rational); + } + if (isl_stream_eat_if_available(s, ':')) { + isl_space *dom_space; + isl_set *dom; + + dom_space = isl_pw_aff_get_domain_space(pa); + dom = isl_set_universe(dom_space); + dom = read_formula(s, v, dom, rational); + pa = isl_pw_aff_intersect_domain(pa, dom); + } + + res = isl_pw_aff_union_add(res, pa); + + if (seen_paren && isl_stream_eat(s, ')')) + goto error; + } while (isl_stream_eat_if_available(s, ';')); + + isl_space_free(space); + + return res; +error: + isl_space_free(space); + return isl_pw_aff_free(res); +} + +/* Read an affine expression from "s" for use in read_tuple. + * + * accept_extended_affine requires a wrapped space as input. + * read_tuple on the other hand expects each isl_pw_aff + * to have an anonymous space. We therefore adjust the space + * of the isl_pw_aff before returning it. + */ +static __isl_give isl_pw_aff *read_tuple_var_def(__isl_keep isl_stream *s, + struct vars *v, int rational) +{ + isl_space *space; + isl_pw_aff *def; + + space = isl_space_wrap(isl_space_alloc(s->ctx, 0, v->n, 0)); + + def = accept_piecewise_affine(s, space, v, rational); + + space = isl_space_set_alloc(s->ctx, 0, v->n); + def = isl_pw_aff_reset_domain_space(def, space); + + return def; +} + +/* Read a list of tuple elements by calling "read_el" on each of them and + * return a space with the same number of set dimensions derived from + * the parameter space "space" and possibly updated by "read_el". + * The elements in the list are separated by either "," or "][". + * If "comma" is set then only "," is allowed. + */ +static __isl_give isl_space *read_tuple_list(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, int comma, + __isl_give isl_space *(*read_el)(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, + void *user), + void *user) +{ + if (!space) + return NULL; + + space = isl_space_set_from_params(space); + + if (isl_stream_next_token_is(s, ']')) + return space; + + for (;;) { + struct isl_token *tok; + + space = isl_space_add_dims(space, isl_dim_set, 1); + + space = read_el(s, v, space, rational, user); + if (!space) + return NULL; + + tok = isl_stream_next_token(s); + if (!comma && tok && tok->type == ']' && + isl_stream_next_token_is(s, '[')) { + isl_token_free(tok); + tok = isl_stream_next_token(s); + } else if (!tok || tok->type != ',') { + if (tok) + isl_stream_push_token(s, tok); + break; + } + + isl_token_free(tok); + } + + return space; +} + +/* Read a tuple space from "s" derived from the parameter space "space". + * Call "read_el" on each element in the tuples. + */ +static __isl_give isl_space *read_tuple_space(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, int comma, + __isl_give isl_space *(*read_el)(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, + void *user), + void *user) +{ + struct isl_token *tok; + char *name = NULL; + isl_space *res = NULL; + + tok = isl_stream_next_token(s); + if (!tok) + goto error; + if (tok->type == ISL_TOKEN_IDENT || tok->is_keyword) { + name = strdup(tok->u.s); + isl_token_free(tok); + if (!name) + goto error; + } else + isl_stream_push_token(s, tok); + if (isl_stream_eat(s, '[')) + goto error; + if (next_is_tuple(s)) { + isl_space *out; + res = read_tuple_space(s, v, isl_space_copy(space), + rational, comma, read_el, user); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + out = read_tuple_space(s, v, isl_space_copy(space), + rational, comma, read_el, user); + res = isl_space_product(res, out); + } else + res = read_tuple_list(s, v, isl_space_copy(space), + rational, comma, read_el, user); + if (isl_stream_eat(s, ']')) + goto error; + + if (name) { + res = isl_space_set_tuple_name(res, isl_dim_set, name); + free(name); + } + + isl_space_free(space); + return res; +error: + free(name); + isl_space_free(res); + isl_space_free(space); + return NULL; +} + +/* Construct an isl_pw_aff defined on a space with v->n variables + * that is equal to the last of those variables. + */ +static __isl_give isl_pw_aff *identity_tuple_el(struct vars *v) +{ + isl_space *space; + isl_aff *aff; + + space = isl_space_set_alloc(v->ctx, 0, v->n); + aff = isl_aff_zero_on_domain(isl_local_space_from_space(space)); + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, v->n - 1, 1); + return isl_pw_aff_from_aff(aff); +} + +/* This function is called for each element in a tuple inside read_tuple. + * Add a new variable to "v" and construct a corresponding isl_pw_aff defined + * over a space containing all variables in "v" defined so far. + * The isl_pw_aff expresses the new variable in terms of earlier variables + * if a definition is provided. Otherwise, it is represented as being + * equal to itself. + * Add the isl_pw_aff to *list. + * If the new variable was named, then adjust "space" accordingly and + * return the updated space. + */ +static __isl_give isl_space *read_tuple_pw_aff_el(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, void *user) +{ + isl_pw_aff_list **list = (isl_pw_aff_list **) user; + isl_pw_aff *pa; + struct isl_token *tok; + int new_name = 0; + + tok = next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return isl_space_free(space); + } + + if (tok->type == ISL_TOKEN_IDENT) { + int n = v->n; + int p = vars_pos(v, tok->u.s, -1); + if (p < 0) + goto error; + new_name = p >= n; + } + + if (tok->type == '*') { + if (vars_add_anon(v) < 0) + goto error; + isl_token_free(tok); + pa = identity_tuple_el(v); + } else if (new_name) { + int pos = isl_space_dim(space, isl_dim_out) - 1; + space = space_set_dim_name(space, pos, v->v->name); + isl_token_free(tok); + if (isl_stream_eat_if_available(s, '=')) + pa = read_tuple_var_def(s, v, rational); + else + pa = identity_tuple_el(v); + } else { + isl_stream_push_token(s, tok); + tok = NULL; + if (vars_add_anon(v) < 0) + goto error; + pa = read_tuple_var_def(s, v, rational); + } + + *list = isl_pw_aff_list_add(*list, pa); + if (!*list) + return isl_space_free(space); + + return space; +error: + isl_token_free(tok); + return isl_space_free(space); +} + +/* Read a tuple and represent it as an isl_multi_pw_aff. + * The range space of the isl_multi_pw_aff is the space of the tuple. + * The domain space is an anonymous space + * with a dimension for each variable in the set of variables in "v", + * including the variables in the range. + * If a given dimension is not defined in terms of earlier dimensions in + * the input, then the corresponding isl_pw_aff is set equal to one time + * the variable corresponding to the dimension being defined. + * + * The elements in the tuple are collected in a list by read_tuple_pw_aff_el. + * Each element in this list is defined over a space representing + * the variables defined so far. We need to adjust the earlier + * elements to have as many variables in the domain as the final + * element in the list. + */ +static __isl_give isl_multi_pw_aff *read_tuple(__isl_keep isl_stream *s, + struct vars *v, int rational, int comma) +{ + int i, n; + isl_space *space; + isl_pw_aff_list *list; + + space = isl_space_params_alloc(v->ctx, 0); + list = isl_pw_aff_list_alloc(s->ctx, 0); + space = read_tuple_space(s, v, space, rational, comma, + &read_tuple_pw_aff_el, &list); + n = isl_space_dim(space, isl_dim_set); + for (i = 0; i + 1 < n; ++i) { + isl_pw_aff *pa; + + pa = isl_pw_aff_list_get_pw_aff(list, i); + pa = isl_pw_aff_add_dims(pa, isl_dim_in, n - (i + 1)); + list = isl_pw_aff_list_set_pw_aff(list, i, pa); + } + + space = isl_space_from_range(space); + space = isl_space_add_dims(space, isl_dim_in, v->n); + return isl_multi_pw_aff_from_pw_aff_list(space, list); +} + +/* Add the tuple represented by the isl_multi_pw_aff "tuple" to "map". + * We first create the appropriate space in "map" based on the range + * space of this isl_multi_pw_aff. Then, we add equalities based + * on the affine expressions. These live in an anonymous space, + * however, so we first need to reset the space to that of "map". + */ +static __isl_give isl_map *map_from_tuple(__isl_take isl_multi_pw_aff *tuple, + __isl_take isl_map *map, enum isl_dim_type type, struct vars *v, + int rational) +{ + int i, n; + isl_ctx *ctx; + isl_space *space = NULL; + + if (!map || !tuple) + goto error; + ctx = isl_multi_pw_aff_get_ctx(tuple); + n = isl_multi_pw_aff_dim(tuple, isl_dim_out); + space = isl_space_range(isl_multi_pw_aff_get_space(tuple)); + if (!space) + goto error; + + if (type == isl_dim_param) { + if (isl_space_has_tuple_name(space, isl_dim_set) || + isl_space_is_wrapping(space)) { + isl_die(ctx, isl_error_invalid, + "parameter tuples cannot be named or nested", + goto error); + } + map = isl_map_add_dims(map, type, n); + for (i = 0; i < n; ++i) { + isl_id *id; + if (!isl_space_has_dim_name(space, isl_dim_set, i)) + isl_die(ctx, isl_error_invalid, + "parameters must be named", + goto error); + id = isl_space_get_dim_id(space, isl_dim_set, i); + map = isl_map_set_dim_id(map, isl_dim_param, i, id); + } + } else if (type == isl_dim_in) { + isl_set *set; + + set = isl_set_universe(isl_space_copy(space)); + if (rational) + set = isl_set_set_rational(set); + set = isl_set_intersect_params(set, isl_map_params(map)); + map = isl_map_from_domain(set); + } else { + isl_set *set; + + set = isl_set_universe(isl_space_copy(space)); + if (rational) + set = isl_set_set_rational(set); + map = isl_map_from_domain_and_range(isl_map_domain(map), set); + } + + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + isl_space *space; + isl_aff *aff; + isl_set *set; + isl_map *map_i; + + pa = isl_multi_pw_aff_get_pw_aff(tuple, i); + space = isl_pw_aff_get_domain_space(pa); + aff = isl_aff_zero_on_domain(isl_local_space_from_space(space)); + aff = isl_aff_add_coefficient_si(aff, + isl_dim_in, v->n - n + i, -1); + pa = isl_pw_aff_add(pa, isl_pw_aff_from_aff(aff)); + if (rational) + pa = isl_pw_aff_set_rational(pa); + set = isl_pw_aff_zero_set(pa); + map_i = isl_map_from_range(set); + map_i = isl_map_reset_space(map_i, isl_map_get_space(map)); + map = isl_map_intersect(map, map_i); + } + + isl_space_free(space); + isl_multi_pw_aff_free(tuple); + return map; +error: + isl_space_free(space); + isl_multi_pw_aff_free(tuple); + isl_map_free(map); + return NULL; +} + +/* Read a tuple from "s" and add it to "map". + * The tuple is initially represented as an isl_multi_pw_aff and + * then added to "map". + */ +static __isl_give isl_map *read_map_tuple(__isl_keep isl_stream *s, + __isl_take isl_map *map, enum isl_dim_type type, struct vars *v, + int rational, int comma) +{ + isl_multi_pw_aff *tuple; + + tuple = read_tuple(s, v, rational, comma); + if (!tuple) + return isl_map_free(map); + + return map_from_tuple(tuple, map, type, v, rational); +} + +/* Given two equal-length lists of piecewise affine expression with the space + * of "set" as domain, construct a set in the same space that expresses + * that "left" and "right" satisfy the comparison "type". + * + * A space is constructed of the same dimension as the number of elements + * in the two lists. The comparison is then expressed in a map from + * this space to itself and wrapped into a set. Finally the two lists + * of piecewise affine expressions are plugged into this set. + * + * Let S be the space of "set" and T the constructed space. + * The lists are first changed into two isl_multi_pw_affs in S -> T and + * then combined into an isl_multi_pw_aff in S -> [T -> T], + * while the comparison is first expressed in T -> T, then [T -> T] + * and finally in S. + */ +static __isl_give isl_set *list_cmp(__isl_keep isl_set *set, int type, + __isl_take isl_pw_aff_list *left, __isl_take isl_pw_aff_list *right) +{ + isl_space *space; + int n; + isl_multi_pw_aff *mpa1, *mpa2; + + if (!set || !left || !right) + goto error; + + space = isl_set_get_space(set); + n = isl_pw_aff_list_n_pw_aff(left); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, n); + mpa1 = isl_multi_pw_aff_from_pw_aff_list(isl_space_copy(space), left); + mpa2 = isl_multi_pw_aff_from_pw_aff_list(isl_space_copy(space), right); + mpa1 = isl_multi_pw_aff_range_product(mpa1, mpa2); + + space = isl_space_range(space); + switch (type) { + case ISL_TOKEN_LEX_LT: + set = isl_map_wrap(isl_map_lex_lt(space)); + break; + case ISL_TOKEN_LEX_GT: + set = isl_map_wrap(isl_map_lex_gt(space)); + break; + case ISL_TOKEN_LEX_LE: + set = isl_map_wrap(isl_map_lex_le(space)); + break; + case ISL_TOKEN_LEX_GE: + set = isl_map_wrap(isl_map_lex_ge(space)); + break; + default: + isl_multi_pw_aff_free(mpa1); + isl_space_free(space); + isl_die(isl_set_get_ctx(set), isl_error_internal, + "unhandled list comparison type", return NULL); + } + set = isl_set_preimage_multi_pw_aff(set, mpa1); + return set; +error: + isl_pw_aff_list_free(left); + isl_pw_aff_list_free(right); + return NULL; +} + +/* Construct constraints of the form + * + * a op b + * + * where a is an element in "left", op is an operator of type "type" and + * b is an element in "right", add the constraints to "set" and return + * the result. + * "rational" is set if the constraints should be treated as + * a rational constraints. + * + * If "type" is the type of a comparison operator between lists + * of affine expressions, then a single (compound) constraint + * is constructed by list_cmp instead. + */ +static __isl_give isl_set *construct_constraints( + __isl_take isl_set *set, int type, + __isl_keep isl_pw_aff_list *left, __isl_keep isl_pw_aff_list *right, + int rational) +{ + isl_set *cond; + + left = isl_pw_aff_list_copy(left); + right = isl_pw_aff_list_copy(right); + if (rational) { + left = isl_pw_aff_list_set_rational(left); + right = isl_pw_aff_list_set_rational(right); + } + if (is_list_comparator_type(type)) + cond = list_cmp(set, type, left, right); + else if (type == ISL_TOKEN_LE) + cond = isl_pw_aff_list_le_set(left, right); + else if (type == ISL_TOKEN_GE) + cond = isl_pw_aff_list_ge_set(left, right); + else if (type == ISL_TOKEN_LT) + cond = isl_pw_aff_list_lt_set(left, right); + else if (type == ISL_TOKEN_GT) + cond = isl_pw_aff_list_gt_set(left, right); + else if (type == ISL_TOKEN_NE) + cond = isl_pw_aff_list_ne_set(left, right); + else + cond = isl_pw_aff_list_eq_set(left, right); + + return isl_set_intersect(set, cond); +} + +/* Read a constraint from "s", add it to "map" and return the result. + * "v" contains a description of the identifiers parsed so far. + * "rational" is set if the constraint should be treated as + * a rational constraint. + * The constraint read from "s" may be applied to multiple pairs + * of affine expressions and may be chained. + * In particular, a list of affine expressions is read, followed + * by a comparison operator and another list of affine expressions. + * The comparison operator is then applied to each pair of elements + * in the two lists and the results are added to "map". + * However, if the operator expects two lists of affine expressions, + * then it is applied directly to those lists and the two lists + * are required to have the same length. + * If the next token is another comparison operator, then another + * list of affine expressions is read and the process repeats. + * + * The processing is performed on a wrapped copy of "map" because + * an affine expression cannot have a binary relation as domain. + */ +static __isl_give isl_map *add_constraint(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational) +{ + struct isl_token *tok; + int type; + isl_pw_aff_list *list1 = NULL, *list2 = NULL; + int n1, n2; + isl_set *set; + + set = isl_map_wrap(map); + list1 = accept_affine_list(s, isl_set_get_space(set), v); + if (!list1) + goto error; + tok = isl_stream_next_token(s); + if (!is_comparator(tok)) { + isl_stream_error(s, tok, "missing operator"); + if (tok) + isl_stream_push_token(s, tok); + goto error; + } + type = tok->type; + isl_token_free(tok); + for (;;) { + list2 = accept_affine_list(s, isl_set_get_space(set), v); + if (!list2) + goto error; + n1 = isl_pw_aff_list_n_pw_aff(list1); + n2 = isl_pw_aff_list_n_pw_aff(list2); + if (is_list_comparator_type(type) && n1 != n2) { + isl_stream_error(s, NULL, + "list arguments not of same size"); + goto error; + } + + set = construct_constraints(set, type, list1, list2, rational); + isl_pw_aff_list_free(list1); + list1 = list2; + + tok = isl_stream_next_token(s); + if (!is_comparator(tok)) { + if (tok) + isl_stream_push_token(s, tok); + break; + } + type = tok->type; + isl_token_free(tok); + } + isl_pw_aff_list_free(list1); + + return isl_set_unwrap(set); +error: + isl_pw_aff_list_free(list1); + isl_pw_aff_list_free(list2); + isl_set_free(set); + return NULL; +} + +static __isl_give isl_map *read_exists(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational) +{ + int n = v->n; + int seen_paren = isl_stream_eat_if_available(s, '('); + + map = isl_map_from_domain(isl_map_wrap(map)); + map = read_defined_var_list(s, v, map, rational); + + if (isl_stream_eat(s, ':')) + goto error; + + map = read_formula(s, v, map, rational); + map = isl_set_unwrap(isl_map_domain(map)); + + vars_drop(v, v->n - n); + if (seen_paren && isl_stream_eat(s, ')')) + goto error; + + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Parse an expression between parentheses and push the result + * back on the stream. + * + * The parsed expression may be either an affine expression + * or a condition. The first type is pushed onto the stream + * as an isl_pw_aff, while the second is pushed as an isl_map. + * + * If the initial token indicates the start of a condition, + * we parse it as such. + * Otherwise, we first parse an affine expression and push + * that onto the stream. If the affine expression covers the + * entire expression between parentheses, we return. + * Otherwise, we assume that the affine expression is the + * start of a condition and continue parsing. + */ +static int resolve_paren_expr(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational) +{ + struct isl_token *tok, *tok2; + int line, col; + isl_pw_aff *pwaff; + + tok = isl_stream_next_token(s); + if (!tok || tok->type != '(') + goto error; + + if (isl_stream_next_token_is(s, '(')) + if (resolve_paren_expr(s, v, isl_map_copy(map), rational)) + goto error; + + if (isl_stream_next_token_is(s, ISL_TOKEN_EXISTS) || + isl_stream_next_token_is(s, ISL_TOKEN_NOT) || + isl_stream_next_token_is(s, ISL_TOKEN_TRUE) || + isl_stream_next_token_is(s, ISL_TOKEN_FALSE) || + isl_stream_next_token_is(s, ISL_TOKEN_MAP)) { + map = read_formula(s, v, map, rational); + if (isl_stream_eat(s, ')')) + goto error; + tok->type = ISL_TOKEN_MAP; + tok->u.map = map; + isl_stream_push_token(s, tok); + return 0; + } + + tok2 = isl_stream_next_token(s); + if (!tok2) + goto error; + line = tok2->line; + col = tok2->col; + isl_stream_push_token(s, tok2); + + pwaff = accept_affine(s, isl_space_wrap(isl_map_get_space(map)), v); + if (!pwaff) + goto error; + + tok2 = isl_token_new(s->ctx, line, col, 0); + if (!tok2) + goto error2; + tok2->type = ISL_TOKEN_AFF; + tok2->u.pwaff = pwaff; + + if (isl_stream_eat_if_available(s, ')')) { + isl_stream_push_token(s, tok2); + isl_token_free(tok); + isl_map_free(map); + return 0; + } + + isl_stream_push_token(s, tok2); + + map = read_formula(s, v, map, rational); + if (isl_stream_eat(s, ')')) + goto error; + + tok->type = ISL_TOKEN_MAP; + tok->u.map = map; + isl_stream_push_token(s, tok); + + return 0; +error2: + isl_pw_aff_free(pwaff); +error: + isl_token_free(tok); + isl_map_free(map); + return -1; +} + +static __isl_give isl_map *read_conjunct(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational) +{ + if (isl_stream_next_token_is(s, '(')) + if (resolve_paren_expr(s, v, isl_map_copy(map), rational)) + goto error; + + if (isl_stream_next_token_is(s, ISL_TOKEN_MAP)) { + struct isl_token *tok; + tok = isl_stream_next_token(s); + if (!tok) + goto error; + isl_map_free(map); + map = isl_map_copy(tok->u.map); + isl_token_free(tok); + return map; + } + + if (isl_stream_eat_if_available(s, ISL_TOKEN_EXISTS)) + return read_exists(s, v, map, rational); + + if (isl_stream_eat_if_available(s, ISL_TOKEN_TRUE)) + return map; + + if (isl_stream_eat_if_available(s, ISL_TOKEN_FALSE)) { + isl_space *dim = isl_map_get_space(map); + isl_map_free(map); + return isl_map_empty(dim); + } + + return add_constraint(s, v, map, rational); +error: + isl_map_free(map); + return NULL; +} + +static __isl_give isl_map *read_conjuncts(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational) +{ + isl_map *res; + int negate; + + negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT); + res = read_conjunct(s, v, isl_map_copy(map), rational); + if (negate) + res = isl_map_subtract(isl_map_copy(map), res); + + while (res && isl_stream_eat_if_available(s, ISL_TOKEN_AND)) { + isl_map *res_i; + + negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT); + res_i = read_conjunct(s, v, isl_map_copy(map), rational); + if (negate) + res = isl_map_subtract(res, res_i); + else + res = isl_map_intersect(res, res_i); + } + + isl_map_free(map); + return res; +} + +static struct isl_map *read_disjuncts(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational) +{ + isl_map *res; + + if (isl_stream_next_token_is(s, '}')) + return map; + + res = read_conjuncts(s, v, isl_map_copy(map), rational); + while (isl_stream_eat_if_available(s, ISL_TOKEN_OR)) { + isl_map *res_i; + + res_i = read_conjuncts(s, v, isl_map_copy(map), rational); + res = isl_map_union(res, res_i); + } + + isl_map_free(map); + return res; +} + +/* Read a first order formula from "s", add the corresponding + * constraints to "map" and return the result. + * + * In particular, read a formula of the form + * + * a + * + * or + * + * a implies b + * + * where a and b are disjunctions. + * + * In the first case, map is replaced by + * + * map \cap { [..] : a } + * + * In the second case, it is replaced by + * + * (map \setminus { [..] : a}) \cup (map \cap { [..] : b }) + */ +static __isl_give isl_map *read_formula(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_map *map, int rational) +{ + isl_map *res; + + res = read_disjuncts(s, v, isl_map_copy(map), rational); + + if (isl_stream_eat_if_available(s, ISL_TOKEN_IMPLIES)) { + isl_map *res2; + + res = isl_map_subtract(isl_map_copy(map), res); + res2 = read_disjuncts(s, v, map, rational); + res = isl_map_union(res, res2); + } else + isl_map_free(map); + + return res; +} + +static int polylib_pos_to_isl_pos(__isl_keep isl_basic_map *bmap, int pos) +{ + if (pos < isl_basic_map_dim(bmap, isl_dim_out)) + return 1 + isl_basic_map_dim(bmap, isl_dim_param) + + isl_basic_map_dim(bmap, isl_dim_in) + pos; + pos -= isl_basic_map_dim(bmap, isl_dim_out); + + if (pos < isl_basic_map_dim(bmap, isl_dim_in)) + return 1 + isl_basic_map_dim(bmap, isl_dim_param) + pos; + pos -= isl_basic_map_dim(bmap, isl_dim_in); + + if (pos < isl_basic_map_dim(bmap, isl_dim_div)) + return 1 + isl_basic_map_dim(bmap, isl_dim_param) + + isl_basic_map_dim(bmap, isl_dim_in) + + isl_basic_map_dim(bmap, isl_dim_out) + pos; + pos -= isl_basic_map_dim(bmap, isl_dim_div); + + if (pos < isl_basic_map_dim(bmap, isl_dim_param)) + return 1 + pos; + + return 0; +} + +static __isl_give isl_basic_map *basic_map_read_polylib_constraint( + __isl_keep isl_stream *s, __isl_take isl_basic_map *bmap) +{ + int j; + struct isl_token *tok; + int type; + int k; + isl_int *c; + + if (!bmap) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting coefficient"); + if (tok) + isl_stream_push_token(s, tok); + goto error; + } + if (!tok->on_new_line) { + isl_stream_error(s, tok, "coefficient should appear on new line"); + isl_stream_push_token(s, tok); + goto error; + } + + type = isl_int_get_si(tok->u.v); + isl_token_free(tok); + + isl_assert(s->ctx, type == 0 || type == 1, goto error); + if (type == 0) { + k = isl_basic_map_alloc_equality(bmap); + c = bmap->eq[k]; + } else { + k = isl_basic_map_alloc_inequality(bmap); + c = bmap->ineq[k]; + } + if (k < 0) + goto error; + + for (j = 0; j < 1 + isl_basic_map_total_dim(bmap); ++j) { + int pos; + tok = isl_stream_next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting coefficient"); + if (tok) + isl_stream_push_token(s, tok); + goto error; + } + if (tok->on_new_line) { + isl_stream_error(s, tok, + "coefficient should not appear on new line"); + isl_stream_push_token(s, tok); + goto error; + } + pos = polylib_pos_to_isl_pos(bmap, j); + isl_int_set(c[pos], tok->u.v); + isl_token_free(tok); + } + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +static __isl_give isl_basic_map *basic_map_read_polylib( + __isl_keep isl_stream *s) +{ + int i; + struct isl_token *tok; + struct isl_token *tok2; + int n_row, n_col; + int on_new_line; + unsigned in = 0, out, local = 0; + struct isl_basic_map *bmap = NULL; + int nparam = 0; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + tok2 = isl_stream_next_token(s); + if (!tok2) { + isl_token_free(tok); + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + if (tok->type != ISL_TOKEN_VALUE || tok2->type != ISL_TOKEN_VALUE) { + isl_stream_push_token(s, tok2); + isl_stream_push_token(s, tok); + isl_stream_error(s, NULL, + "expecting constraint matrix dimensions"); + return NULL; + } + n_row = isl_int_get_si(tok->u.v); + n_col = isl_int_get_si(tok2->u.v); + on_new_line = tok2->on_new_line; + isl_token_free(tok2); + isl_token_free(tok); + isl_assert(s->ctx, !on_new_line, return NULL); + isl_assert(s->ctx, n_row >= 0, return NULL); + isl_assert(s->ctx, n_col >= 2 + nparam, return NULL); + tok = isl_stream_next_token_on_same_line(s); + if (tok) { + if (tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, + "expecting number of output dimensions"); + isl_stream_push_token(s, tok); + goto error; + } + out = isl_int_get_si(tok->u.v); + isl_token_free(tok); + + tok = isl_stream_next_token_on_same_line(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, + "expecting number of input dimensions"); + if (tok) + isl_stream_push_token(s, tok); + goto error; + } + in = isl_int_get_si(tok->u.v); + isl_token_free(tok); + + tok = isl_stream_next_token_on_same_line(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, + "expecting number of existentials"); + if (tok) + isl_stream_push_token(s, tok); + goto error; + } + local = isl_int_get_si(tok->u.v); + isl_token_free(tok); + + tok = isl_stream_next_token_on_same_line(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, + "expecting number of parameters"); + if (tok) + isl_stream_push_token(s, tok); + goto error; + } + nparam = isl_int_get_si(tok->u.v); + isl_token_free(tok); + if (n_col != 1 + out + in + local + nparam + 1) { + isl_stream_error(s, NULL, + "dimensions don't match"); + goto error; + } + } else + out = n_col - 2 - nparam; + bmap = isl_basic_map_alloc(s->ctx, nparam, in, out, local, n_row, n_row); + if (!bmap) + return NULL; + + for (i = 0; i < local; ++i) { + int k = isl_basic_map_alloc_div(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->div[k], 1 + 1 + nparam + in + out + local); + } + + for (i = 0; i < n_row; ++i) + bmap = basic_map_read_polylib_constraint(s, bmap); + + tok = isl_stream_next_token_on_same_line(s); + if (tok) { + isl_stream_error(s, tok, "unexpected extra token on line"); + isl_stream_push_token(s, tok); + goto error; + } + + bmap = isl_basic_map_simplify(bmap); + bmap = isl_basic_map_finalize(bmap); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +static struct isl_map *map_read_polylib(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + struct isl_token *tok2; + int i, n; + struct isl_map *map; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + tok2 = isl_stream_next_token_on_same_line(s); + if (tok2 && tok2->type == ISL_TOKEN_VALUE) { + isl_stream_push_token(s, tok2); + isl_stream_push_token(s, tok); + return isl_map_from_basic_map(basic_map_read_polylib(s)); + } + if (tok2) { + isl_stream_error(s, tok2, "unexpected token"); + isl_stream_push_token(s, tok2); + isl_stream_push_token(s, tok); + return NULL; + } + n = isl_int_get_si(tok->u.v); + isl_token_free(tok); + + isl_assert(s->ctx, n >= 1, return NULL); + + map = isl_map_from_basic_map(basic_map_read_polylib(s)); + + for (i = 1; map && i < n; ++i) + map = isl_map_union(map, + isl_map_from_basic_map(basic_map_read_polylib(s))); + + return map; +} + +static int optional_power(__isl_keep isl_stream *s) +{ + int pow; + struct isl_token *tok; + + tok = isl_stream_next_token(s); + if (!tok) + return 1; + if (tok->type != '^') { + isl_stream_push_token(s, tok); + return 1; + } + isl_token_free(tok); + tok = isl_stream_next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting exponent"); + if (tok) + isl_stream_push_token(s, tok); + return 1; + } + pow = isl_int_get_si(tok->u.v); + isl_token_free(tok); + return pow; +} + +static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s, + __isl_keep isl_map *map, struct vars *v); + +static __isl_give isl_pw_qpolynomial *read_factor(__isl_keep isl_stream *s, + __isl_keep isl_map *map, struct vars *v) +{ + isl_pw_qpolynomial *pwqp; + struct isl_token *tok; + + tok = next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + if (tok->type == '(') { + int pow; + + isl_token_free(tok); + pwqp = read_term(s, map, v); + if (!pwqp) + return NULL; + if (isl_stream_eat(s, ')')) + goto error; + pow = optional_power(s); + pwqp = isl_pw_qpolynomial_pow(pwqp, pow); + } else if (tok->type == ISL_TOKEN_VALUE) { + struct isl_token *tok2; + isl_qpolynomial *qp; + + tok2 = isl_stream_next_token(s); + if (tok2 && tok2->type == '/') { + isl_token_free(tok2); + tok2 = next_token(s); + if (!tok2 || tok2->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok2, "expected denominator"); + isl_token_free(tok); + isl_token_free(tok2); + return NULL; + } + qp = isl_qpolynomial_rat_cst_on_domain(isl_map_get_space(map), + tok->u.v, tok2->u.v); + isl_token_free(tok2); + } else { + isl_stream_push_token(s, tok2); + qp = isl_qpolynomial_cst_on_domain(isl_map_get_space(map), + tok->u.v); + } + isl_token_free(tok); + pwqp = isl_pw_qpolynomial_from_qpolynomial(qp); + } else if (tok->type == ISL_TOKEN_INFTY) { + isl_qpolynomial *qp; + isl_token_free(tok); + qp = isl_qpolynomial_infty_on_domain(isl_map_get_space(map)); + pwqp = isl_pw_qpolynomial_from_qpolynomial(qp); + } else if (tok->type == ISL_TOKEN_NAN) { + isl_qpolynomial *qp; + isl_token_free(tok); + qp = isl_qpolynomial_nan_on_domain(isl_map_get_space(map)); + pwqp = isl_pw_qpolynomial_from_qpolynomial(qp); + } else if (tok->type == ISL_TOKEN_IDENT) { + int n = v->n; + int pos = vars_pos(v, tok->u.s, -1); + int pow; + isl_qpolynomial *qp; + if (pos < 0) { + isl_token_free(tok); + return NULL; + } + if (pos >= n) { + vars_drop(v, v->n - n); + isl_stream_error(s, tok, "unknown identifier"); + isl_token_free(tok); + return NULL; + } + isl_token_free(tok); + pow = optional_power(s); + qp = isl_qpolynomial_var_pow_on_domain(isl_map_get_space(map), pos, pow); + pwqp = isl_pw_qpolynomial_from_qpolynomial(qp); + } else if (is_start_of_div(tok)) { + isl_pw_aff *pwaff; + int pow; + + isl_stream_push_token(s, tok); + pwaff = accept_div(s, isl_map_get_space(map), v); + pow = optional_power(s); + pwqp = isl_pw_qpolynomial_from_pw_aff(pwaff); + pwqp = isl_pw_qpolynomial_pow(pwqp, pow); + } else if (tok->type == '-') { + isl_token_free(tok); + pwqp = read_factor(s, map, v); + pwqp = isl_pw_qpolynomial_neg(pwqp); + } else { + isl_stream_error(s, tok, "unexpected isl_token"); + isl_stream_push_token(s, tok); + return NULL; + } + + if (isl_stream_eat_if_available(s, '*') || + isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) { + isl_pw_qpolynomial *pwqp2; + + pwqp2 = read_factor(s, map, v); + pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp2); + } + + return pwqp; +error: + isl_pw_qpolynomial_free(pwqp); + return NULL; +} + +static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s, + __isl_keep isl_map *map, struct vars *v) +{ + struct isl_token *tok; + isl_pw_qpolynomial *pwqp; + + pwqp = read_factor(s, map, v); + + for (;;) { + tok = next_token(s); + if (!tok) + return pwqp; + + if (tok->type == '+') { + isl_pw_qpolynomial *pwqp2; + + isl_token_free(tok); + pwqp2 = read_factor(s, map, v); + pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2); + } else if (tok->type == '-') { + isl_pw_qpolynomial *pwqp2; + + isl_token_free(tok); + pwqp2 = read_factor(s, map, v); + pwqp = isl_pw_qpolynomial_sub(pwqp, pwqp2); + } else if (tok->type == ISL_TOKEN_VALUE && + isl_int_is_neg(tok->u.v)) { + isl_pw_qpolynomial *pwqp2; + + isl_stream_push_token(s, tok); + pwqp2 = read_factor(s, map, v); + pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2); + } else { + isl_stream_push_token(s, tok); + break; + } + } + + return pwqp; +} + +static __isl_give isl_map *read_optional_formula(__isl_keep isl_stream *s, + __isl_take isl_map *map, struct vars *v, int rational) +{ + struct isl_token *tok; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + if (tok->type == ':' || + (tok->type == ISL_TOKEN_OR && !strcmp(tok->u.s, "|"))) { + isl_token_free(tok); + map = read_formula(s, v, map, rational); + } else + isl_stream_push_token(s, tok); + + return map; +error: + isl_map_free(map); + return NULL; +} + +static struct isl_obj obj_read_poly(__isl_keep isl_stream *s, + __isl_take isl_map *map, struct vars *v, int n) +{ + struct isl_obj obj = { isl_obj_pw_qpolynomial, NULL }; + isl_pw_qpolynomial *pwqp; + struct isl_set *set; + + pwqp = read_term(s, map, v); + map = read_optional_formula(s, map, v, 0); + set = isl_map_range(map); + + pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, set); + + vars_drop(v, v->n - n); + + obj.v = pwqp; + return obj; +} + +static struct isl_obj obj_read_poly_or_fold(__isl_keep isl_stream *s, + __isl_take isl_set *set, struct vars *v, int n) +{ + struct isl_obj obj = { isl_obj_pw_qpolynomial_fold, NULL }; + isl_pw_qpolynomial *pwqp; + isl_pw_qpolynomial_fold *pwf = NULL; + + if (!isl_stream_eat_if_available(s, ISL_TOKEN_MAX)) + return obj_read_poly(s, set, v, n); + + if (isl_stream_eat(s, '(')) + goto error; + + pwqp = read_term(s, set, v); + pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max, pwqp); + + while (isl_stream_eat_if_available(s, ',')) { + isl_pw_qpolynomial_fold *pwf_i; + pwqp = read_term(s, set, v); + pwf_i = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max, + pwqp); + pwf = isl_pw_qpolynomial_fold_fold(pwf, pwf_i); + } + + if (isl_stream_eat(s, ')')) + goto error; + + set = read_optional_formula(s, set, v, 0); + pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, set); + + vars_drop(v, v->n - n); + + obj.v = pwf; + return obj; +error: + isl_set_free(set); + isl_pw_qpolynomial_fold_free(pwf); + obj.type = isl_obj_none; + return obj; +} + +static int is_rational(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type == ISL_TOKEN_RAT && isl_stream_next_token_is(s, ':')) { + isl_token_free(tok); + isl_stream_eat(s, ':'); + return 1; + } + + isl_stream_push_token(s, tok); + + return 0; +} + +static struct isl_obj obj_read_body(__isl_keep isl_stream *s, + __isl_take isl_map *map, struct vars *v) +{ + struct isl_token *tok; + struct isl_obj obj = { isl_obj_set, NULL }; + int n = v->n; + int rational; + + rational = is_rational(s); + if (rational) + map = isl_map_set_rational(map); + + if (isl_stream_next_token_is(s, ':')) { + obj.type = isl_obj_set; + obj.v = read_optional_formula(s, map, v, rational); + return obj; + } + + if (!next_is_tuple(s)) + return obj_read_poly_or_fold(s, map, v, n); + + map = read_map_tuple(s, map, isl_dim_in, v, rational, 0); + if (!map) + goto error; + tok = isl_stream_next_token(s); + if (!tok) + goto error; + if (tok->type == ISL_TOKEN_TO) { + obj.type = isl_obj_map; + isl_token_free(tok); + if (!next_is_tuple(s)) { + isl_set *set = isl_map_domain(map); + return obj_read_poly_or_fold(s, set, v, n); + } + map = read_map_tuple(s, map, isl_dim_out, v, rational, 0); + if (!map) + goto error; + } else { + map = isl_map_domain(map); + isl_stream_push_token(s, tok); + } + + map = read_optional_formula(s, map, v, rational); + + vars_drop(v, v->n - n); + + obj.v = map; + return obj; +error: + isl_map_free(map); + obj.type = isl_obj_none; + return obj; +} + +static struct isl_obj to_union(isl_ctx *ctx, struct isl_obj obj) +{ + if (obj.type == isl_obj_map) { + obj.v = isl_union_map_from_map(obj.v); + obj.type = isl_obj_union_map; + } else if (obj.type == isl_obj_set) { + obj.v = isl_union_set_from_set(obj.v); + obj.type = isl_obj_union_set; + } else if (obj.type == isl_obj_pw_qpolynomial) { + obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v); + obj.type = isl_obj_union_pw_qpolynomial; + } else if (obj.type == isl_obj_pw_qpolynomial_fold) { + obj.v = isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(obj.v); + obj.type = isl_obj_union_pw_qpolynomial_fold; + } else + isl_assert(ctx, 0, goto error); + return obj; +error: + obj.type->free(obj.v); + obj.type = isl_obj_none; + return obj; +} + +static struct isl_obj obj_add(__isl_keep isl_stream *s, + struct isl_obj obj1, struct isl_obj obj2) +{ + if (obj1.type == isl_obj_set && obj2.type == isl_obj_union_set) + obj1 = to_union(s->ctx, obj1); + if (obj1.type == isl_obj_union_set && obj2.type == isl_obj_set) + obj2 = to_union(s->ctx, obj2); + if (obj1.type == isl_obj_map && obj2.type == isl_obj_union_map) + obj1 = to_union(s->ctx, obj1); + if (obj1.type == isl_obj_union_map && obj2.type == isl_obj_map) + obj2 = to_union(s->ctx, obj2); + if (obj1.type == isl_obj_pw_qpolynomial && + obj2.type == isl_obj_union_pw_qpolynomial) + obj1 = to_union(s->ctx, obj1); + if (obj1.type == isl_obj_union_pw_qpolynomial && + obj2.type == isl_obj_pw_qpolynomial) + obj2 = to_union(s->ctx, obj2); + if (obj1.type == isl_obj_pw_qpolynomial_fold && + obj2.type == isl_obj_union_pw_qpolynomial_fold) + obj1 = to_union(s->ctx, obj1); + if (obj1.type == isl_obj_union_pw_qpolynomial_fold && + obj2.type == isl_obj_pw_qpolynomial_fold) + obj2 = to_union(s->ctx, obj2); + if (obj1.type != obj2.type) { + isl_stream_error(s, NULL, + "attempt to combine incompatible objects"); + goto error; + } + if (!obj1.type->add) + isl_die(s->ctx, isl_error_internal, + "combination not supported on object type", goto error); + if (obj1.type == isl_obj_map && !isl_map_has_equal_space(obj1.v, obj2.v)) { + obj1 = to_union(s->ctx, obj1); + obj2 = to_union(s->ctx, obj2); + } + if (obj1.type == isl_obj_set && !isl_set_has_equal_space(obj1.v, obj2.v)) { + obj1 = to_union(s->ctx, obj1); + obj2 = to_union(s->ctx, obj2); + } + if (obj1.type == isl_obj_pw_qpolynomial && + !isl_pw_qpolynomial_has_equal_space(obj1.v, obj2.v)) { + obj1 = to_union(s->ctx, obj1); + obj2 = to_union(s->ctx, obj2); + } + if (obj1.type == isl_obj_pw_qpolynomial_fold && + !isl_pw_qpolynomial_fold_has_equal_space(obj1.v, obj2.v)) { + obj1 = to_union(s->ctx, obj1); + obj2 = to_union(s->ctx, obj2); + } + obj1.v = obj1.type->add(obj1.v, obj2.v); + return obj1; +error: + obj1.type->free(obj1.v); + obj2.type->free(obj2.v); + obj1.type = isl_obj_none; + obj1.v = NULL; + return obj1; +} + +/* Are the first two tokens on "s", "domain" (either as a string + * or as an identifier) followed by ":"? + */ +static int next_is_domain_colon(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + char *name; + int res; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type != ISL_TOKEN_IDENT && tok->type != ISL_TOKEN_STRING) { + isl_stream_push_token(s, tok); + return 0; + } + + name = isl_token_get_str(s->ctx, tok); + res = !strcmp(name, "domain") && isl_stream_next_token_is(s, ':'); + free(name); + + isl_stream_push_token(s, tok); + + return res; +} + +/* Do the first tokens on "s" look like a schedule? + * + * The root of a schedule is always a domain node, so the first thing + * we expect in the stream is a domain key, i.e., "domain" followed + * by ":". If the schedule was printed in YAML flow style, then + * we additionally expect a "{" to open the outer mapping. + */ +static int next_is_schedule(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int is_schedule; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type != '{') { + isl_stream_push_token(s, tok); + return next_is_domain_colon(s); + } + + is_schedule = next_is_domain_colon(s); + isl_stream_push_token(s, tok); + + return is_schedule; +} + +/* Read an isl_schedule from "s" and store it in an isl_obj. + */ +static struct isl_obj schedule_read(__isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj.type = isl_obj_schedule; + obj.v = isl_stream_read_schedule(s); + + return obj; +} + +static struct isl_obj obj_read(__isl_keep isl_stream *s) +{ + isl_map *map = NULL; + struct isl_token *tok; + struct vars *v = NULL; + struct isl_obj obj = { isl_obj_set, NULL }; + + if (next_is_schedule(s)) + return schedule_read(s); + + tok = next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + if (tok->type == ISL_TOKEN_VALUE) { + struct isl_token *tok2; + struct isl_map *map; + + tok2 = isl_stream_next_token(s); + if (!tok2 || tok2->type != ISL_TOKEN_VALUE || + isl_int_is_neg(tok2->u.v)) { + if (tok2) + isl_stream_push_token(s, tok2); + obj.type = isl_obj_val; + obj.v = isl_val_int_from_isl_int(s->ctx, tok->u.v); + isl_token_free(tok); + return obj; + } + isl_stream_push_token(s, tok2); + isl_stream_push_token(s, tok); + map = map_read_polylib(s); + if (!map) + goto error; + if (isl_map_may_be_set(map)) + obj.v = isl_map_range(map); + else { + obj.type = isl_obj_map; + obj.v = map; + } + return obj; + } + v = vars_new(s->ctx); + if (!v) { + isl_stream_push_token(s, tok); + goto error; + } + map = isl_map_universe(isl_space_params_alloc(s->ctx, 0)); + if (tok->type == '[') { + isl_stream_push_token(s, tok); + map = read_map_tuple(s, map, isl_dim_param, v, 0, 0); + if (!map) + goto error; + tok = isl_stream_next_token(s); + if (!tok || tok->type != ISL_TOKEN_TO) { + isl_stream_error(s, tok, "expecting '->'"); + if (tok) + isl_stream_push_token(s, tok); + goto error; + } + isl_token_free(tok); + tok = isl_stream_next_token(s); + } + if (!tok || tok->type != '{') { + isl_stream_error(s, tok, "expecting '{'"); + if (tok) + isl_stream_push_token(s, tok); + goto error; + } + isl_token_free(tok); + + tok = isl_stream_next_token(s); + if (!tok) + ; + else if (tok->type == ISL_TOKEN_IDENT && !strcmp(tok->u.s, "Sym")) { + isl_token_free(tok); + if (isl_stream_eat(s, '=')) + goto error; + map = read_map_tuple(s, map, isl_dim_param, v, 0, 1); + if (!map) + goto error; + } else if (tok->type == '}') { + obj.type = isl_obj_union_set; + obj.v = isl_union_set_empty(isl_map_get_space(map)); + isl_token_free(tok); + goto done; + } else + isl_stream_push_token(s, tok); + + for (;;) { + struct isl_obj o; + tok = NULL; + o = obj_read_body(s, isl_map_copy(map), v); + if (o.type == isl_obj_none || !o.v) + goto error; + if (!obj.v) + obj = o; + else { + obj = obj_add(s, obj, o); + if (obj.type == isl_obj_none || !obj.v) + goto error; + } + tok = isl_stream_next_token(s); + if (!tok || tok->type != ';') + break; + isl_token_free(tok); + if (isl_stream_next_token_is(s, '}')) { + tok = isl_stream_next_token(s); + break; + } + } + + if (tok && tok->type == '}') { + isl_token_free(tok); + } else { + isl_stream_error(s, tok, "unexpected isl_token"); + if (tok) + isl_token_free(tok); + goto error; + } +done: + vars_free(v); + isl_map_free(map); + + return obj; +error: + isl_map_free(map); + obj.type->free(obj.v); + if (v) + vars_free(v); + obj.v = NULL; + return obj; +} + +struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s) +{ + return obj_read(s); +} + +__isl_give isl_map *isl_stream_read_map(__isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj = obj_read(s); + if (obj.v) + isl_assert(s->ctx, obj.type == isl_obj_map || + obj.type == isl_obj_set, goto error); + + if (obj.type == isl_obj_set) + obj.v = isl_map_from_range(obj.v); + + return obj.v; +error: + obj.type->free(obj.v); + return NULL; +} + +__isl_give isl_set *isl_stream_read_set(__isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj = obj_read(s); + if (obj.v) { + if (obj.type == isl_obj_map && isl_map_may_be_set(obj.v)) { + obj.v = isl_map_range(obj.v); + obj.type = isl_obj_set; + } + isl_assert(s->ctx, obj.type == isl_obj_set, goto error); + } + + return obj.v; +error: + obj.type->free(obj.v); + return NULL; +} + +__isl_give isl_union_map *isl_stream_read_union_map(__isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj = obj_read(s); + if (obj.type == isl_obj_map) { + obj.type = isl_obj_union_map; + obj.v = isl_union_map_from_map(obj.v); + } + if (obj.type == isl_obj_set) { + obj.type = isl_obj_union_set; + obj.v = isl_union_set_from_set(obj.v); + } + if (obj.v && obj.type == isl_obj_union_set && + isl_union_set_is_empty(obj.v)) + obj.type = isl_obj_union_map; + if (obj.v && obj.type != isl_obj_union_map) + isl_die(s->ctx, isl_error_invalid, "invalid input", goto error); + + return obj.v; +error: + obj.type->free(obj.v); + return NULL; +} + +__isl_give isl_union_set *isl_stream_read_union_set(__isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj = obj_read(s); + if (obj.type == isl_obj_set) { + obj.type = isl_obj_union_set; + obj.v = isl_union_set_from_set(obj.v); + } + if (obj.v) + isl_assert(s->ctx, obj.type == isl_obj_union_set, goto error); + + return obj.v; +error: + obj.type->free(obj.v); + return NULL; +} + +static __isl_give isl_basic_map *basic_map_read(__isl_keep isl_stream *s) +{ + struct isl_obj obj; + struct isl_map *map; + struct isl_basic_map *bmap; + + obj = obj_read(s); + if (obj.v && (obj.type != isl_obj_map && obj.type != isl_obj_set)) + isl_die(s->ctx, isl_error_invalid, "not a (basic) set or map", + goto error); + map = obj.v; + if (!map) + return NULL; + + if (map->n > 1) + isl_die(s->ctx, isl_error_invalid, + "set or map description involves " + "more than one disjunct", goto error); + + if (map->n == 0) + bmap = isl_basic_map_empty(isl_map_get_space(map)); + else + bmap = isl_basic_map_copy(map->p[0]); + + isl_map_free(map); + + return bmap; +error: + obj.type->free(obj.v); + return NULL; +} + +static __isl_give isl_basic_set *basic_set_read(__isl_keep isl_stream *s) +{ + isl_basic_map *bmap; + bmap = basic_map_read(s); + if (!bmap) + return NULL; + if (!isl_basic_map_may_be_set(bmap)) + isl_die(s->ctx, isl_error_invalid, + "input is not a set", goto error); + return isl_basic_map_range(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx, + FILE *input) +{ + struct isl_basic_map *bmap; + isl_stream *s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + bmap = basic_map_read(s); + isl_stream_free(s); + return bmap; +} + +__isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx, + FILE *input) +{ + isl_basic_set *bset; + isl_stream *s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + bset = basic_set_read(s); + isl_stream_free(s); + return bset; +} + +struct isl_basic_map *isl_basic_map_read_from_str(struct isl_ctx *ctx, + const char *str) +{ + struct isl_basic_map *bmap; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + bmap = basic_map_read(s); + isl_stream_free(s); + return bmap; +} + +struct isl_basic_set *isl_basic_set_read_from_str(struct isl_ctx *ctx, + const char *str) +{ + isl_basic_set *bset; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + bset = basic_set_read(s); + isl_stream_free(s); + return bset; +} + +__isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx, + FILE *input) +{ + struct isl_map *map; + isl_stream *s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + map = isl_stream_read_map(s); + isl_stream_free(s); + return map; +} + +__isl_give isl_map *isl_map_read_from_str(struct isl_ctx *ctx, + const char *str) +{ + struct isl_map *map; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + map = isl_stream_read_map(s); + isl_stream_free(s); + return map; +} + +__isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx, + FILE *input) +{ + isl_set *set; + isl_stream *s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + set = isl_stream_read_set(s); + isl_stream_free(s); + return set; +} + +struct isl_set *isl_set_read_from_str(struct isl_ctx *ctx, + const char *str) +{ + isl_set *set; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + set = isl_stream_read_set(s); + isl_stream_free(s); + return set; +} + +__isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx, + FILE *input) +{ + isl_union_map *umap; + isl_stream *s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + umap = isl_stream_read_union_map(s); + isl_stream_free(s); + return umap; +} + +__isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx, + const char *str) +{ + isl_union_map *umap; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + umap = isl_stream_read_union_map(s); + isl_stream_free(s); + return umap; +} + +__isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx, + FILE *input) +{ + isl_union_set *uset; + isl_stream *s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + uset = isl_stream_read_union_set(s); + isl_stream_free(s); + return uset; +} + +__isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx, + const char *str) +{ + isl_union_set *uset; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + uset = isl_stream_read_union_set(s); + isl_stream_free(s); + return uset; +} + +static __isl_give isl_vec *isl_vec_read_polylib(__isl_keep isl_stream *s) +{ + struct isl_vec *vec = NULL; + struct isl_token *tok; + unsigned size; + int j; + + tok = isl_stream_next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting vector length"); + goto error; + } + + size = isl_int_get_si(tok->u.v); + isl_token_free(tok); + + vec = isl_vec_alloc(s->ctx, size); + + for (j = 0; j < size; ++j) { + tok = isl_stream_next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting constant value"); + goto error; + } + isl_int_set(vec->el[j], tok->u.v); + isl_token_free(tok); + } + + return vec; +error: + isl_token_free(tok); + isl_vec_free(vec); + return NULL; +} + +static __isl_give isl_vec *vec_read(__isl_keep isl_stream *s) +{ + return isl_vec_read_polylib(s); +} + +__isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input) +{ + isl_vec *v; + isl_stream *s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + v = vec_read(s); + isl_stream_free(s); + return v; +} + +__isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial( + __isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj = obj_read(s); + if (obj.v) + isl_assert(s->ctx, obj.type == isl_obj_pw_qpolynomial, + goto error); + + return obj.v; +error: + obj.type->free(obj.v); + return NULL; +} + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx, + const char *str) +{ + isl_pw_qpolynomial *pwqp; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + pwqp = isl_stream_read_pw_qpolynomial(s); + isl_stream_free(s); + return pwqp; +} + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx, + FILE *input) +{ + isl_pw_qpolynomial *pwqp; + isl_stream *s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + pwqp = isl_stream_read_pw_qpolynomial(s); + isl_stream_free(s); + return pwqp; +} + +/* Is the next token an identifer not in "v"? + */ +static int next_is_fresh_ident(__isl_keep isl_stream *s, struct vars *v) +{ + int n = v->n; + int fresh; + struct isl_token *tok; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + fresh = tok->type == ISL_TOKEN_IDENT && vars_pos(v, tok->u.s, -1) >= n; + isl_stream_push_token(s, tok); + + vars_drop(v, v->n - n); + + return fresh; +} + +/* First read the domain of the affine expression, which may be + * a parameter space or a set. + * The tricky part is that we don't know if the domain is a set or not, + * so when we are trying to read the domain, we may actually be reading + * the affine expression itself (defined on a parameter domains) + * If the tuple we are reading is named, we assume it's the domain. + * Also, if inside the tuple, the first thing we find is a nested tuple + * or a new identifier, we again assume it's the domain. + * Finally, if the tuple is empty, then it must be the domain + * since it does not contain an affine expression. + * Otherwise, we assume we are reading an affine expression. + */ +static __isl_give isl_set *read_aff_domain(__isl_keep isl_stream *s, + __isl_take isl_set *dom, struct vars *v) +{ + struct isl_token *tok, *tok2; + int is_empty; + + tok = isl_stream_next_token(s); + if (tok && (tok->type == ISL_TOKEN_IDENT || tok->is_keyword)) { + isl_stream_push_token(s, tok); + return read_map_tuple(s, dom, isl_dim_set, v, 1, 0); + } + if (!tok || tok->type != '[') { + isl_stream_error(s, tok, "expecting '['"); + goto error; + } + tok2 = isl_stream_next_token(s); + is_empty = tok2 && tok2->type == ']'; + if (tok2) + isl_stream_push_token(s, tok2); + if (is_empty || next_is_tuple(s) || next_is_fresh_ident(s, v)) { + isl_stream_push_token(s, tok); + dom = read_map_tuple(s, dom, isl_dim_set, v, 1, 0); + } else + isl_stream_push_token(s, tok); + + return dom; +error: + if (tok) + isl_stream_push_token(s, tok); + isl_set_free(dom); + return NULL; +} + +/* Read an affine expression from "s". + */ +__isl_give isl_aff *isl_stream_read_aff(__isl_keep isl_stream *s) +{ + isl_aff *aff; + isl_multi_aff *ma; + + ma = isl_stream_read_multi_aff(s); + if (!ma) + return NULL; + if (isl_multi_aff_dim(ma, isl_dim_out) != 1) + isl_die(s->ctx, isl_error_invalid, + "expecting single affine expression", + goto error); + + aff = isl_multi_aff_get_aff(ma, 0); + isl_multi_aff_free(ma); + return aff; +error: + isl_multi_aff_free(ma); + return NULL; +} + +/* Read a piecewise affine expression from "s" with domain (space) "dom". + */ +static __isl_give isl_pw_aff *read_pw_aff_with_dom(__isl_keep isl_stream *s, + __isl_take isl_set *dom, struct vars *v) +{ + isl_pw_aff *pwaff = NULL; + + if (!isl_set_is_params(dom) && isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + + if (isl_stream_eat(s, '[')) + goto error; + + pwaff = accept_affine(s, isl_set_get_space(dom), v); + + if (isl_stream_eat(s, ']')) + goto error; + + dom = read_optional_formula(s, dom, v, 0); + pwaff = isl_pw_aff_intersect_domain(pwaff, dom); + + return pwaff; +error: + isl_set_free(dom); + isl_pw_aff_free(pwaff); + return NULL; +} + +__isl_give isl_pw_aff *isl_stream_read_pw_aff(__isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom = NULL; + isl_set *aff_dom; + isl_pw_aff *pa = NULL; + int n; + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + if (isl_stream_eat(s, '{')) + goto error; + + n = v->n; + aff_dom = read_aff_domain(s, isl_set_copy(dom), v); + pa = read_pw_aff_with_dom(s, aff_dom, v); + vars_drop(v, v->n - n); + + while (isl_stream_eat_if_available(s, ';')) { + isl_pw_aff *pa_i; + + n = v->n; + aff_dom = read_aff_domain(s, isl_set_copy(dom), v); + pa_i = read_pw_aff_with_dom(s, aff_dom, v); + vars_drop(v, v->n - n); + + pa = isl_pw_aff_union_add(pa, pa_i); + } + + if (isl_stream_eat(s, '}')) + goto error; + + vars_free(v); + isl_set_free(dom); + return pa; +error: + vars_free(v); + isl_set_free(dom); + isl_pw_aff_free(pa); + return NULL; +} + +__isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str) +{ + isl_aff *aff; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + aff = isl_stream_read_aff(s); + isl_stream_free(s); + return aff; +} + +__isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str) +{ + isl_pw_aff *pa; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + pa = isl_stream_read_pw_aff(s); + isl_stream_free(s); + return pa; +} + +/* Extract an isl_multi_pw_aff with domain space "dom_space" + * from a tuple "tuple" read by read_tuple. + * + * Note that the function read_tuple accepts tuples where some output or + * set dimensions are defined in terms of other output or set dimensions + * since this function is also used to read maps. As a special case, + * read_tuple also accept dimensions that are defined in terms of themselves + * (i.e., that are not defined). + * These cases are not allowed when extracting an isl_multi_pw_aff so check + * that the definitions of the output/set dimensions do not involve any + * output/set dimensions. + * Finally, drop the output dimensions from the domain of the result + * of read_tuple (which is of the form [input, output] -> [output], + * with anonymous domain) and reset the space. + */ +static __isl_give isl_multi_pw_aff *extract_mpa_from_tuple( + __isl_take isl_space *dom_space, __isl_keep isl_multi_pw_aff *tuple) +{ + int dim, i, n; + isl_space *space; + isl_multi_pw_aff *mpa; + + n = isl_multi_pw_aff_dim(tuple, isl_dim_out); + dim = isl_space_dim(dom_space, isl_dim_all); + space = isl_space_range(isl_multi_pw_aff_get_space(tuple)); + space = isl_space_align_params(space, isl_space_copy(dom_space)); + if (!isl_space_is_params(dom_space)) + space = isl_space_map_from_domain_and_range( + isl_space_copy(dom_space), space); + isl_space_free(dom_space); + mpa = isl_multi_pw_aff_alloc(space); + + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + pa = isl_multi_pw_aff_get_pw_aff(tuple, i); + if (!pa) + return isl_multi_pw_aff_free(mpa); + if (isl_pw_aff_involves_dims(pa, isl_dim_in, dim, i + 1)) { + isl_ctx *ctx = isl_pw_aff_get_ctx(pa); + isl_pw_aff_free(pa); + isl_die(ctx, isl_error_invalid, + "not an affine expression", + return isl_multi_pw_aff_free(mpa)); + } + pa = isl_pw_aff_drop_dims(pa, isl_dim_in, dim, n); + space = isl_multi_pw_aff_get_domain_space(mpa); + pa = isl_pw_aff_reset_domain_space(pa, space); + mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa); + } + + return mpa; +} + +/* Read a tuple of affine expressions, together with optional constraints + * on the domain from "s". "dom" represents the initial constraints + * on the domain. + * + * The isl_multi_aff may live in either a set or a map space. + * First read the first tuple and check if it is followed by a "->". + * If so, convert the tuple into the domain of the isl_multi_pw_aff and + * read in the next tuple. This tuple (or the first tuple if it was + * not followed by a "->") is then converted into an isl_multi_pw_aff + * through a call to extract_mpa_from_tuple. + * The result is converted to an isl_pw_multi_aff and + * its domain is intersected with the domain. + */ +static __isl_give isl_pw_multi_aff *read_conditional_multi_aff( + __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v) +{ + isl_multi_pw_aff *tuple; + isl_multi_pw_aff *mpa; + isl_pw_multi_aff *pma; + int n = v->n; + + tuple = read_tuple(s, v, 0, 0); + if (!tuple) + goto error; + if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) { + isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0); + dom = isl_map_domain(map); + tuple = read_tuple(s, v, 0, 0); + if (!tuple) + goto error; + } + + dom = read_optional_formula(s, dom, v, 0); + + vars_drop(v, v->n - n); + + mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple); + isl_multi_pw_aff_free(tuple); + pma = isl_pw_multi_aff_from_multi_pw_aff(mpa); + pma = isl_pw_multi_aff_intersect_domain(pma, dom); + + return pma; +error: + isl_set_free(dom); + return NULL; +} + +/* Read an isl_pw_multi_aff from "s". + * + * In particular, first read the parameters and then read a sequence + * of one or more tuples of affine expressions with optional conditions and + * add them up. + */ +__isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff( + __isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom; + isl_pw_multi_aff *pma = NULL; + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + if (isl_stream_eat(s, '{')) + goto error; + + pma = read_conditional_multi_aff(s, isl_set_copy(dom), v); + + while (isl_stream_eat_if_available(s, ';')) { + isl_pw_multi_aff *pma2; + + pma2 = read_conditional_multi_aff(s, isl_set_copy(dom), v); + pma = isl_pw_multi_aff_union_add(pma, pma2); + if (!pma) + goto error; + } + + if (isl_stream_eat(s, '}')) + goto error; + + isl_set_free(dom); + vars_free(v); + return pma; +error: + isl_pw_multi_aff_free(pma); + isl_set_free(dom); + vars_free(v); + return NULL; +} + +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx, + const char *str) +{ + isl_pw_multi_aff *pma; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + pma = isl_stream_read_pw_multi_aff(s); + isl_stream_free(s); + return pma; +} + +/* Read an isl_union_pw_multi_aff from "s". + * We currently read a generic object and if it turns out to be a set or + * a map, we convert that to an isl_union_pw_multi_aff. + * It would be more efficient if we were to construct + * the isl_union_pw_multi_aff directly. + */ +__isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff( + __isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj = obj_read(s); + if (!obj.v) + return NULL; + + if (obj.type == isl_obj_map || obj.type == isl_obj_set) + obj = to_union(s->ctx, obj); + if (obj.type == isl_obj_union_map) + return isl_union_pw_multi_aff_from_union_map(obj.v); + if (obj.type == isl_obj_union_set) + return isl_union_pw_multi_aff_from_union_set(obj.v); + + obj.type->free(obj.v); + isl_die(s->ctx, isl_error_invalid, "unexpected object type", + return NULL); +} + +/* Read an isl_union_pw_multi_aff from "str". + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str( + isl_ctx *ctx, const char *str) +{ + isl_union_pw_multi_aff *upma; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + upma = isl_stream_read_union_pw_multi_aff(s); + isl_stream_free(s); + return upma; +} + +/* Assuming "pa" represents a single affine expression defined on a universe + * domain, extract this affine expression. + */ +static __isl_give isl_aff *aff_from_pw_aff(__isl_take isl_pw_aff *pa) +{ + isl_aff *aff; + + if (!pa) + return NULL; + if (pa->n != 1) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "expecting single affine expression", + goto error); + if (!isl_set_plain_is_universe(pa->p[0].set)) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "expecting universe domain", + goto error); + + aff = isl_aff_copy(pa->p[0].aff); + isl_pw_aff_free(pa); + return aff; +error: + isl_pw_aff_free(pa); + return NULL; +} + +/* This function is called for each element in a tuple inside + * isl_stream_read_multi_val. + * Read an isl_val from "s" and add it to *list. + */ +static __isl_give isl_space *read_val_el(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, void *user) +{ + isl_val_list **list = (isl_val_list **) user; + isl_val *val; + + val = isl_stream_read_val(s); + *list = isl_val_list_add(*list, val); + if (!*list) + return isl_space_free(space); + + return space; +} + +/* Read an isl_multi_val from "s". + * + * We first read a tuple space, collecting the element values in a list. + * Then we create an isl_multi_val from the space and the isl_val_list. + */ +__isl_give isl_multi_val *isl_stream_read_multi_val(__isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom = NULL; + isl_space *space; + isl_multi_val *mv = NULL; + isl_val_list *list; + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + if (!isl_set_plain_is_universe(dom)) + isl_die(s->ctx, isl_error_invalid, + "expecting universe parameter domain", goto error); + if (isl_stream_eat(s, '{')) + goto error; + + space = isl_set_get_space(dom); + + list = isl_val_list_alloc(s->ctx, 0); + space = read_tuple_space(s, v, space, 1, 0, &read_val_el, &list); + mv = isl_multi_val_from_val_list(space, list); + + if (isl_stream_eat(s, '}')) + goto error; + + vars_free(v); + isl_set_free(dom); + return mv; +error: + vars_free(v); + isl_set_free(dom); + isl_multi_val_free(mv); + return NULL; +} + +/* Read an isl_multi_val from "str". + */ +__isl_give isl_multi_val *isl_multi_val_read_from_str(isl_ctx *ctx, + const char *str) +{ + isl_multi_val *mv; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + mv = isl_stream_read_multi_val(s); + isl_stream_free(s); + return mv; +} + +/* Read a multi-affine expression from "s". + * If the multi-affine expression has a domain, then the tuple + * representing this domain cannot involve any affine expressions. + * The tuple representing the actual expressions needs to consist + * of only affine expressions. Moreover, these expressions can + * only depend on parameters and input dimensions and not on other + * output dimensions. + */ +__isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom = NULL; + isl_multi_pw_aff *tuple = NULL; + int dim, i, n; + isl_space *space, *dom_space; + isl_multi_aff *ma = NULL; + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + if (!isl_set_plain_is_universe(dom)) + isl_die(s->ctx, isl_error_invalid, + "expecting universe parameter domain", goto error); + if (isl_stream_eat(s, '{')) + goto error; + + tuple = read_tuple(s, v, 0, 0); + if (!tuple) + goto error; + if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) { + isl_set *set; + isl_space *space; + int has_expr; + + has_expr = tuple_has_expr(tuple); + if (has_expr < 0) + goto error; + if (has_expr) + isl_die(s->ctx, isl_error_invalid, + "expecting universe domain", goto error); + space = isl_space_range(isl_multi_pw_aff_get_space(tuple)); + set = isl_set_universe(space); + dom = isl_set_intersect_params(set, dom); + isl_multi_pw_aff_free(tuple); + tuple = read_tuple(s, v, 0, 0); + if (!tuple) + goto error; + } + + if (isl_stream_eat(s, '}')) + goto error; + + n = isl_multi_pw_aff_dim(tuple, isl_dim_out); + dim = isl_set_dim(dom, isl_dim_all); + dom_space = isl_set_get_space(dom); + space = isl_space_range(isl_multi_pw_aff_get_space(tuple)); + space = isl_space_align_params(space, isl_space_copy(dom_space)); + if (!isl_space_is_params(dom_space)) + space = isl_space_map_from_domain_and_range( + isl_space_copy(dom_space), space); + isl_space_free(dom_space); + ma = isl_multi_aff_alloc(space); + + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + isl_aff *aff; + pa = isl_multi_pw_aff_get_pw_aff(tuple, i); + aff = aff_from_pw_aff(pa); + if (!aff) + goto error; + if (isl_aff_involves_dims(aff, isl_dim_in, dim, i + 1)) { + isl_aff_free(aff); + isl_die(s->ctx, isl_error_invalid, + "not an affine expression", goto error); + } + aff = isl_aff_drop_dims(aff, isl_dim_in, dim, n); + space = isl_multi_aff_get_domain_space(ma); + aff = isl_aff_reset_domain_space(aff, space); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + + isl_multi_pw_aff_free(tuple); + vars_free(v); + isl_set_free(dom); + return ma; +error: + isl_multi_pw_aff_free(tuple); + vars_free(v); + isl_set_free(dom); + isl_multi_aff_free(ma); + return NULL; +} + +__isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx, + const char *str) +{ + isl_multi_aff *maff; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + maff = isl_stream_read_multi_aff(s); + isl_stream_free(s); + return maff; +} + +/* Read an isl_multi_pw_aff from "s". + * + * The input format is similar to that of map, except that any conditions + * on the domains should be specified inside the tuple since each + * piecewise affine expression may have a different domain. + * + * Since we do not know in advance if the isl_multi_pw_aff lives + * in a set or a map space, we first read the first tuple and check + * if it is followed by a "->". If so, we convert the tuple into + * the domain of the isl_multi_pw_aff and read in the next tuple. + * This tuple (or the first tuple if it was not followed by a "->") + * is then converted into the isl_multi_pw_aff through a call + * to extract_mpa_from_tuple and the domain of the result + * is intersected with the domain. + */ +__isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff( + __isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom = NULL; + isl_multi_pw_aff *tuple = NULL; + isl_multi_pw_aff *mpa = NULL; + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + if (isl_stream_eat(s, '{')) + goto error; + + tuple = read_tuple(s, v, 0, 0); + if (!tuple) + goto error; + if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) { + isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0); + dom = isl_map_domain(map); + tuple = read_tuple(s, v, 0, 0); + if (!tuple) + goto error; + } + + if (isl_stream_eat(s, '}')) + goto error; + + mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple); + + isl_multi_pw_aff_free(tuple); + vars_free(v); + mpa = isl_multi_pw_aff_intersect_domain(mpa, dom); + return mpa; +error: + isl_multi_pw_aff_free(tuple); + vars_free(v); + isl_set_free(dom); + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Read an isl_multi_pw_aff from "str". + */ +__isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx, + const char *str) +{ + isl_multi_pw_aff *mpa; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + mpa = isl_stream_read_multi_pw_aff(s); + isl_stream_free(s); + return mpa; +} + +/* Read the body of an isl_union_pw_aff from "s" with parameter domain "dom". + */ +static __isl_give isl_union_pw_aff *read_union_pw_aff_with_dom( + __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v) +{ + isl_pw_aff *pa; + isl_union_pw_aff *upa = NULL; + isl_set *aff_dom; + int n; + + n = v->n; + aff_dom = read_aff_domain(s, isl_set_copy(dom), v); + pa = read_pw_aff_with_dom(s, aff_dom, v); + vars_drop(v, v->n - n); + + upa = isl_union_pw_aff_from_pw_aff(pa); + + while (isl_stream_eat_if_available(s, ';')) { + isl_pw_aff *pa_i; + isl_union_pw_aff *upa_i; + + n = v->n; + aff_dom = read_aff_domain(s, isl_set_copy(dom), v); + pa_i = read_pw_aff_with_dom(s, aff_dom, v); + vars_drop(v, v->n - n); + + upa_i = isl_union_pw_aff_from_pw_aff(pa_i); + upa = isl_union_pw_aff_union_add(upa, upa_i); + } + + isl_set_free(dom); + return upa; +} + +/* Read an isl_union_pw_aff from "s". + * + * First check if there are any paramters, then read in the opening brace + * and use read_union_pw_aff_with_dom to read in the body of + * the isl_union_pw_aff. Finally, read the closing brace. + */ +__isl_give isl_union_pw_aff *isl_stream_read_union_pw_aff( + __isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom; + isl_union_pw_aff *upa = NULL; + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + if (isl_stream_eat(s, '{')) + goto error; + + upa = read_union_pw_aff_with_dom(s, isl_set_copy(dom), v); + + if (isl_stream_eat(s, '}')) + goto error; + + vars_free(v); + isl_set_free(dom); + return upa; +error: + vars_free(v); + isl_set_free(dom); + isl_union_pw_aff_free(upa); + return NULL; +} + +/* Read an isl_union_pw_aff from "str". + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_read_from_str(isl_ctx *ctx, + const char *str) +{ + isl_union_pw_aff *upa; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + upa = isl_stream_read_union_pw_aff(s); + isl_stream_free(s); + return upa; +} + +/* This function is called for each element in a tuple inside + * isl_stream_read_multi_union_pw_aff. + * + * Read a '{', the union piecewise affine expression body and a '}' and + * add the isl_union_pw_aff to *list. + */ +static __isl_give isl_space *read_union_pw_aff_el(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, void *user) +{ + isl_set *dom; + isl_union_pw_aff *upa; + isl_union_pw_aff_list **list = (isl_union_pw_aff_list **) user; + + dom = isl_set_universe(isl_space_params(isl_space_copy(space))); + if (isl_stream_eat(s, '{')) + goto error; + upa = read_union_pw_aff_with_dom(s, dom, v); + *list = isl_union_pw_aff_list_add(*list, upa); + if (isl_stream_eat(s, '}')) + return isl_space_free(space); + if (!*list) + return isl_space_free(space); + return space; +error: + isl_set_free(dom); + return isl_space_free(space); +} + +/* Do the next tokens in "s" correspond to an empty tuple? + * In particular, does the stream start with a '[', followed by a ']', + * not followed by a "->"? + */ +static int next_is_empty_tuple(__isl_keep isl_stream *s) +{ + struct isl_token *tok, *tok2, *tok3; + int is_empty_tuple = 0; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type != '[') { + isl_stream_push_token(s, tok); + return 0; + } + + tok2 = isl_stream_next_token(s); + if (tok2 && tok2->type == ']') { + tok3 = isl_stream_next_token(s); + is_empty_tuple = !tok || tok->type != ISL_TOKEN_TO; + if (tok3) + isl_stream_push_token(s, tok3); + } + if (tok2) + isl_stream_push_token(s, tok2); + isl_stream_push_token(s, tok); + + return is_empty_tuple; +} + +/* Do the next tokens in "s" correspond to a tuple of parameters? + * In particular, does the stream start with a '[' that is not + * followed by a '{' or a nested tuple? + */ +static int next_is_param_tuple(__isl_keep isl_stream *s) +{ + struct isl_token *tok, *tok2; + int is_tuple; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type != '[' || next_is_tuple(s)) { + isl_stream_push_token(s, tok); + return 0; + } + + tok2 = isl_stream_next_token(s); + is_tuple = tok2 && tok2->type != '{'; + if (tok2) + isl_stream_push_token(s, tok2); + isl_stream_push_token(s, tok); + + return is_tuple; +} + +/* Read an isl_multi_union_pw_aff from "s". + * + * The input has the form + * + * [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }] + * + * or + * + * [..] -> [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }] + * + * We first check for the special case of an empty tuple "[]". + * Then we check if there are any parameters. + * Finally, we read the tuple, collecting the individual isl_union_pw_aff + * elements in a list and construct the result from the tuple space and + * the list. + */ +__isl_give isl_multi_union_pw_aff *isl_stream_read_multi_union_pw_aff( + __isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom = NULL; + isl_space *space; + isl_multi_union_pw_aff *mupa = NULL; + isl_union_pw_aff_list *list; + + if (next_is_empty_tuple(s)) { + if (isl_stream_eat(s, '[')) + return NULL; + if (isl_stream_eat(s, ']')) + return NULL; + space = isl_space_set_alloc(s->ctx, 0, 0); + return isl_multi_union_pw_aff_zero(space); + } + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_param_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + space = isl_set_get_space(dom); + isl_set_free(dom); + list = isl_union_pw_aff_list_alloc(s->ctx, 0); + space = read_tuple_space(s, v, space, 1, 0, + &read_union_pw_aff_el, &list); + mupa = isl_multi_union_pw_aff_from_union_pw_aff_list(space, list); + + vars_free(v); + + return mupa; +error: + vars_free(v); + isl_set_free(dom); + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Read an isl_multi_union_pw_aff from "str". + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_read_from_str( + isl_ctx *ctx, const char *str) +{ + isl_multi_union_pw_aff *mupa; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + mupa = isl_stream_read_multi_union_pw_aff(s); + isl_stream_free(s); + return mupa; +} + +__isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial( + __isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj = obj_read(s); + if (obj.type == isl_obj_pw_qpolynomial) { + obj.type = isl_obj_union_pw_qpolynomial; + obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v); + } + if (obj.v) + isl_assert(s->ctx, obj.type == isl_obj_union_pw_qpolynomial, + goto error); + + return obj.v; +error: + obj.type->free(obj.v); + return NULL; +} + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str( + isl_ctx *ctx, const char *str) +{ + isl_union_pw_qpolynomial *upwqp; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + upwqp = isl_stream_read_union_pw_qpolynomial(s); + isl_stream_free(s); + return upwqp; +} Index: contrib/isl/isl_int.h =================================================================== --- /dev/null +++ contrib/isl/isl_int.h @@ -0,0 +1,52 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_INT_H +#define ISL_INT_H +#define ISL_DEPRECATED_INT_H + +#include +#include +#include +#include + +#ifdef USE_GMP_FOR_MP +#include +#endif + +#ifdef USE_IMATH_FOR_MP +#ifdef USE_SMALL_INT_OPT +#include +#else /* USE_SMALL_INT_OPT */ +#include +#endif /* USE_SMALL_INT_OPT */ +#endif /* USE_IMATH_FOR_MP */ + +#define isl_int_is_zero(i) (isl_int_sgn(i) == 0) +#define isl_int_is_one(i) (isl_int_cmp_si(i,1) == 0) +#define isl_int_is_negone(i) (isl_int_cmp_si(i,-1) == 0) +#define isl_int_is_pos(i) (isl_int_sgn(i) > 0) +#define isl_int_is_neg(i) (isl_int_sgn(i) < 0) +#define isl_int_is_nonpos(i) (isl_int_sgn(i) <= 0) +#define isl_int_is_nonneg(i) (isl_int_sgn(i) >= 0) + +#ifndef USE_SMALL_INT_OPT +#define isl_int_print(out,i,width) \ + do { \ + char *s; \ + s = isl_int_get_str(i); \ + fprintf(out, "%*s", width, s); \ + isl_int_free_str(s); \ + } while (0) +#endif /* USE_SMALL_INT_OPT */ + +__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p, + isl_int i); + +#endif /* ISL_INT_H */ Index: contrib/isl/isl_int_gmp.h =================================================================== --- /dev/null +++ contrib/isl/isl_int_gmp.h @@ -0,0 +1,89 @@ +#ifndef ISL_INT_GMP_H +#define ISL_INT_GMP_H + +#include + +/* isl_int is the basic integer type, implemented with GMP's mpz_t. In the + * future, different types such as long long or cln::cl_I will be supported. + */ +typedef mpz_t isl_int; + +#define isl_int_init(i) mpz_init(i) +#define isl_int_clear(i) mpz_clear(i) + +#define isl_int_set(r,i) mpz_set(r,i) +#define isl_int_set_si(r,i) mpz_set_si(r,i) +#define isl_int_set_ui(r,i) mpz_set_ui(r,i) +#define isl_int_fits_slong(r) mpz_fits_slong_p(r) +#define isl_int_get_si(r) mpz_get_si(r) +#define isl_int_fits_ulong(r) mpz_fits_ulong_p(r) +#define isl_int_get_ui(r) mpz_get_ui(r) +#define isl_int_get_d(r) mpz_get_d(r) +#define isl_int_get_str(r) mpz_get_str(0, 10, r) +#define isl_int_abs(r,i) mpz_abs(r,i) +#define isl_int_neg(r,i) mpz_neg(r,i) +#define isl_int_swap(i,j) mpz_swap(i,j) +#define isl_int_swap_or_set(i,j) mpz_swap(i,j) +#define isl_int_add_ui(r,i,j) mpz_add_ui(r,i,j) +#define isl_int_sub_ui(r,i,j) mpz_sub_ui(r,i,j) + +#define isl_int_add(r,i,j) mpz_add(r,i,j) +#define isl_int_sub(r,i,j) mpz_sub(r,i,j) +#define isl_int_mul(r,i,j) mpz_mul(r,i,j) +#define isl_int_mul_2exp(r,i,j) mpz_mul_2exp(r,i,j) +#define isl_int_mul_si(r,i,j) mpz_mul_si(r,i,j) +#define isl_int_mul_ui(r,i,j) mpz_mul_ui(r,i,j) +#define isl_int_pow_ui(r,i,j) mpz_pow_ui(r,i,j) +#define isl_int_addmul(r,i,j) mpz_addmul(r,i,j) +#define isl_int_addmul_ui(r,i,j) mpz_addmul_ui(r,i,j) +#define isl_int_submul(r,i,j) mpz_submul(r,i,j) +#define isl_int_submul_ui(r,i,j) mpz_submul_ui(r,i,j) + +#define isl_int_gcd(r,i,j) mpz_gcd(r,i,j) +#define isl_int_lcm(r,i,j) mpz_lcm(r,i,j) +#define isl_int_divexact(r,i,j) mpz_divexact(r,i,j) +#define isl_int_divexact_ui(r,i,j) mpz_divexact_ui(r,i,j) +#define isl_int_tdiv_q(r,i,j) mpz_tdiv_q(r,i,j) +#define isl_int_cdiv_q(r,i,j) mpz_cdiv_q(r,i,j) +#define isl_int_cdiv_q_ui(r,i,j) mpz_cdiv_q_ui(r,i,j) +#define isl_int_fdiv_q(r,i,j) mpz_fdiv_q(r,i,j) +#define isl_int_fdiv_r(r,i,j) mpz_fdiv_r(r,i,j) +#define isl_int_fdiv_q_ui(r,i,j) mpz_fdiv_q_ui(r,i,j) + +#define isl_int_read(r,s) mpz_set_str(r,s,10) +#define isl_int_sgn(i) mpz_sgn(i) +#define isl_int_cmp(i,j) mpz_cmp(i,j) +#define isl_int_cmp_si(i,si) mpz_cmp_si(i,si) +#define isl_int_eq(i,j) (mpz_cmp(i,j) == 0) +#define isl_int_ne(i,j) (mpz_cmp(i,j) != 0) +#define isl_int_lt(i,j) (mpz_cmp(i,j) < 0) +#define isl_int_le(i,j) (mpz_cmp(i,j) <= 0) +#define isl_int_gt(i,j) (mpz_cmp(i,j) > 0) +#define isl_int_ge(i,j) (mpz_cmp(i,j) >= 0) +#define isl_int_abs_cmp(i,j) mpz_cmpabs(i,j) +#define isl_int_abs_eq(i,j) (mpz_cmpabs(i,j) == 0) +#define isl_int_abs_ne(i,j) (mpz_cmpabs(i,j) != 0) +#define isl_int_abs_lt(i,j) (mpz_cmpabs(i,j) < 0) +#define isl_int_abs_gt(i,j) (mpz_cmpabs(i,j) > 0) +#define isl_int_abs_ge(i,j) (mpz_cmpabs(i,j) >= 0) +#define isl_int_is_divisible_by(i,j) mpz_divisible_p(i,j) + +uint32_t isl_gmp_hash(mpz_t v, uint32_t hash); +#define isl_int_hash(v,h) isl_gmp_hash(v,h) + +#ifndef mp_get_memory_functions +void mp_get_memory_functions( + void *(**alloc_func_ptr) (size_t), + void *(**realloc_func_ptr) (void *, size_t, size_t), + void (**free_func_ptr) (void *, size_t)); +#endif + +typedef void (*isl_int_print_mp_free_t)(void *, size_t); +#define isl_int_free_str(s) \ + do { \ + isl_int_print_mp_free_t mp_free; \ + mp_get_memory_functions(NULL, NULL, &mp_free); \ + (*mp_free)(s, strlen(s) + 1); \ + } while (0) + +#endif /* ISL_INT_GMP_H */ Index: contrib/isl/isl_int_imath.h =================================================================== --- /dev/null +++ contrib/isl/isl_int_imath.h @@ -0,0 +1,75 @@ +#ifndef ISL_INT_IMATH_H +#define ISL_INT_IMATH_H + +#include + +/* isl_int is the basic integer type, implemented with imath's mp_int. */ +typedef mp_int isl_int; + +#define isl_int_init(i) i = mp_int_alloc() +#define isl_int_clear(i) mp_int_free(i) + +#define isl_int_set(r,i) impz_set(r,i) +#define isl_int_set_si(r,i) impz_set_si(r,i) +#define isl_int_set_ui(r,i) impz_set_ui(r,i) +#define isl_int_fits_slong(r) isl_imath_fits_slong_p(r) +#define isl_int_get_si(r) impz_get_si(r) +#define isl_int_fits_ulong(r) isl_imath_fits_ulong_p(r) +#define isl_int_get_ui(r) impz_get_ui(r) +#define isl_int_get_d(r) impz_get_si(r) +#define isl_int_get_str(r) impz_get_str(0, 10, r) +#define isl_int_abs(r,i) impz_abs(r,i) +#define isl_int_neg(r,i) impz_neg(r,i) +#define isl_int_swap(i,j) impz_swap(i,j) +#define isl_int_swap_or_set(i,j) impz_swap(i,j) +#define isl_int_add_ui(r,i,j) impz_add_ui(r,i,j) +#define isl_int_sub_ui(r,i,j) impz_sub_ui(r,i,j) + +#define isl_int_add(r,i,j) impz_add(r,i,j) +#define isl_int_sub(r,i,j) impz_sub(r,i,j) +#define isl_int_mul(r,i,j) impz_mul(r,i,j) +#define isl_int_mul_2exp(r,i,j) impz_mul_2exp(r,i,j) +#define isl_int_mul_si(r,i,j) mp_int_mul_value(i,j,r) +#define isl_int_mul_ui(r,i,j) impz_mul_ui(r,i,j) +#define isl_int_pow_ui(r,i,j) impz_pow_ui(r,i,j) +#define isl_int_addmul(r,i,j) impz_addmul(r,i,j) +#define isl_int_addmul_ui(r,i,j) isl_imath_addmul_ui(r,i,j) +#define isl_int_submul(r,i,j) impz_submul(r,i,j) +#define isl_int_submul_ui(r,i,j) isl_imath_submul_ui(r,i,j) + +#define isl_int_gcd(r,i,j) impz_gcd(r,i,j) +#define isl_int_lcm(r,i,j) impz_lcm(r,i,j) +#define isl_int_divexact(r,i,j) impz_divexact(r,i,j) +#define isl_int_divexact_ui(r,i,j) impz_divexact_ui(r,i,j) +#define isl_int_tdiv_q(r,i,j) impz_tdiv_q(r,i,j) +#define isl_int_cdiv_q(r,i,j) impz_cdiv_q(r,i,j) +#define isl_int_cdiv_q_ui(r,i,j) isl_imath_cdiv_q_ui(r,i,j) +#define isl_int_fdiv_q(r,i,j) impz_fdiv_q(r,i,j) +#define isl_int_fdiv_r(r,i,j) impz_fdiv_r(r,i,j) +#define isl_int_fdiv_q_ui(r,i,j) isl_imath_fdiv_q_ui(r,i,j) + +#define isl_int_read(r,s) impz_set_str(r,s,10) +#define isl_int_sgn(i) impz_sgn(i) +#define isl_int_cmp(i,j) impz_cmp(i,j) +#define isl_int_cmp_si(i,si) impz_cmp_si(i,si) +#define isl_int_eq(i,j) (impz_cmp(i,j) == 0) +#define isl_int_ne(i,j) (impz_cmp(i,j) != 0) +#define isl_int_lt(i,j) (impz_cmp(i,j) < 0) +#define isl_int_le(i,j) (impz_cmp(i,j) <= 0) +#define isl_int_gt(i,j) (impz_cmp(i,j) > 0) +#define isl_int_ge(i,j) (impz_cmp(i,j) >= 0) +#define isl_int_abs_cmp(i,j) impz_cmpabs(i,j) +#define isl_int_abs_eq(i,j) (impz_cmpabs(i,j) == 0) +#define isl_int_abs_ne(i,j) (impz_cmpabs(i,j) != 0) +#define isl_int_abs_lt(i,j) (impz_cmpabs(i,j) < 0) +#define isl_int_abs_gt(i,j) (impz_cmpabs(i,j) > 0) +#define isl_int_abs_ge(i,j) (impz_cmpabs(i,j) >= 0) +#define isl_int_is_divisible_by(i,j) impz_divisible_p(i,j) + +uint32_t isl_imath_hash(mp_int v, uint32_t hash); +#define isl_int_hash(v,h) isl_imath_hash(v,h) + +typedef void (*isl_int_print_mp_free_t)(void *, size_t); +#define isl_int_free_str(s) free(s) + +#endif /* ISL_INT_IMATH_H */ Index: contrib/isl/isl_int_sioimath.h =================================================================== --- /dev/null +++ contrib/isl/isl_int_sioimath.h @@ -0,0 +1,1254 @@ +/* + * Copyright 2015 INRIA Paris-Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Michael Kruse, INRIA Paris-Rocquencourt, + * Domaine de Voluceau, Rocquenqourt, B.P. 105, + * 78153 Le Chesnay Cedex France + */ +#ifndef ISL_INT_SIOIMATH_H +#define ISL_INT_SIOIMATH_H + +#include +#include +#include +#include + +#include +#include + +#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array)) + +/* Visual Studio before VS2015 does not support the inline keyword when + * compiling in C mode because it was introduced in C99 which it does not + * officially support. Instead, it has a proprietary extension using __inline. + */ +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define inline __inline +#endif + +/* The type to represent integers optimized for small values. It is either a + * pointer to an mp_int ( = mpz_t*; big representation) or an int32_t (small + * represenation) with a discriminator at the least significant bit. In big + * representation it will be always zero because of heap alignment. It is set + * to 1 for small representation and use the 32 most significant bits for the + * int32_t. + * + * Structure on 64 bit machines, with 8-byte aligment (3 bits): + * + * Big representation: + * MSB LSB + * |------------------------------------------------------------000 + * | mpz_t* | + * | != NULL | + * + * Small representation: + * MSB 32 LSB + * |------------------------------|00000000000000000000000000000001 + * | int32_t | + * | 2147483647 ... -2147483647 | + * ^ + * | + * discriminator bit + * + * On 32 bit machines isl_sioimath type is blown up to 8 bytes, i.e. + * isl_sioimath is guaranteed to be at least 8 bytes. This is to ensure the + * int32_t can be hidden in that type without data loss. In the future we might + * optimize this to use 31 hidden bits in a 32 bit pointer. We may also use 63 + * bits on 64 bit machines, but this comes with the cost of additional overflow + * checks because there is no standardized 128 bit integer we could expand to. + * + * We use native integer types and avoid union structures to avoid assumptions + * on the machine's endianness. + * + * This implementation makes the following assumptions: + * - long can represent any int32_t + * - mp_small is signed long + * - mp_usmall is unsigned long + * - adresses returned by malloc are aligned to 2-byte boundaries (leastmost + * bit is zero) + */ +#if UINT64_MAX > UINTPTR_MAX +typedef uint64_t isl_sioimath; +#else +typedef uintptr_t isl_sioimath; +#endif + +/* The negation of the smallest possible number in int32_t, INT32_MIN + * (0x80000000u, -2147483648), cannot be represented in an int32_t, therefore + * every operation that may produce this value needs to special-case it. + * The operations are: + * abs(INT32_MIN) + * -INT32_MIN (negation) + * -1 * INT32_MIN (multiplication) + * INT32_MIN/-1 (any division: divexact, fdiv, cdiv, tdiv) + * To avoid checking these cases, we exclude INT32_MIN from small + * representation. + */ +#define ISL_SIOIMATH_SMALL_MIN (-INT32_MAX) + +/* Largest possible number in small representation */ +#define ISL_SIOIMATH_SMALL_MAX INT32_MAX + +/* Used for function parameters the function modifies. */ +typedef isl_sioimath *isl_sioimath_ptr; + +/* Used for function parameters that are read-only. */ +typedef isl_sioimath isl_sioimath_src; + +/* Return whether the argument is stored in small representation. + */ +inline int isl_sioimath_is_small(isl_sioimath val) +{ + return val & 0x00000001; +} + +/* Return whether the argument is stored in big representation. + */ +inline int isl_sioimath_is_big(isl_sioimath val) +{ + return !isl_sioimath_is_small(val); +} + +/* Get the number of an isl_int in small representation. Result is undefined if + * val is not stored in that format. + */ +inline int32_t isl_sioimath_get_small(isl_sioimath val) +{ + return val >> 32; +} + +/* Get the number of an in isl_int in big representation. Result is undefined if + * val is not stored in that format. + */ +inline mp_int isl_sioimath_get_big(isl_sioimath val) +{ + return (mp_int)(uintptr_t) val; +} + +/* Return 1 if val is stored in small representation and store its value to + * small. We rely on the compiler to optimize the isl_sioimath_get_small such + * that the shift is moved into the branch that executes in case of small + * representation. If there is no such branch, then a single shift is still + * cheaper than introducing branching code. + */ +inline int isl_sioimath_decode_small(isl_sioimath val, int32_t *small) +{ + *small = isl_sioimath_get_small(val); + return isl_sioimath_is_small(val); +} + +/* Return 1 if val is stored in big representation and store its value to big. + */ +inline int isl_sioimath_decode_big(isl_sioimath val, mp_int *big) +{ + *big = isl_sioimath_get_big(val); + return isl_sioimath_is_big(val); +} + +/* Encode a small representation into an isl_int. + */ +inline isl_sioimath isl_sioimath_encode_small(int32_t val) +{ + return ((isl_sioimath) val) << 32 | 0x00000001; +} + +/* Encode a big representation. + */ +inline isl_sioimath isl_sioimath_encode_big(mp_int val) +{ + return (isl_sioimath)(uintptr_t) val; +} + +/* A common situation is to call an IMath function with at least one argument + * that is currently in small representation or an integer parameter, i.e. a big + * representation of the same number is required. Promoting the original + * argument comes with multiple problems, such as modifying a read-only + * argument, the responsibility of deallocation and the execution cost. Instead, + * we make a copy by 'faking' the IMath internal structure. + * + * We reserve the maximum number of required digits on the stack to avoid heap + * allocations. + * + * mp_digit can be uint32_t or uint16_t. This code must work for little and big + * endian digits. The structure for an uint64_t argument and 32-bit mp_digits is + * sketched below. + * + * |----------------------------| + * uint64_t + * + * |-------------||-------------| + * mp_digit mp_digit + * digits[1] digits[0] + * Most sig digit Least sig digit + */ +typedef struct { + mpz_t big; + mp_digit digits[(sizeof(uintmax_t) + sizeof(mp_digit) - 1) / + sizeof(mp_digit)]; +} isl_sioimath_scratchspace_t; + +/* Convert a native integer to IMath's digit representation. A native integer + * might be big- or little endian, but IMath always stores the least significant + * digit in the lowest array indices. memcpy therefore is not possible. + * + * We also have to consider that long and mp_digit can be of different sizes, + * depending on the compiler (LP64, LLP64) and IMath's USE_64BIT_WORDS. This + * macro should work for all of them. + * + * "used" is set to the number of written digits. It must be minimal (IMath + * checks zeroness using the used field), but always at least one. Also note + * that the result of num>>(sizeof(num)*CHAR_BIT) is undefined. + */ +#define ISL_SIOIMATH_TO_DIGITS(num, digits, used) \ + do { \ + int i = 0; \ + do { \ + (digits)[i] = \ + ((num) >> (sizeof(mp_digit) * CHAR_BIT * i)); \ + i += 1; \ + if (i >= (sizeof(num) + sizeof(mp_digit) - 1) / \ + sizeof(mp_digit)) \ + break; \ + if (((num) >> (sizeof(mp_digit) * CHAR_BIT * i)) == 0) \ + break; \ + } while (1); \ + (used) = i; \ + } while (0) + +inline void isl_siomath_uint32_to_digits(uint32_t num, mp_digit *digits, + mp_size *used) +{ + ISL_SIOIMATH_TO_DIGITS(num, digits, *used); +} + +inline void isl_siomath_ulong_to_digits(unsigned long num, mp_digit *digits, + mp_size *used) +{ + ISL_SIOIMATH_TO_DIGITS(num, digits, *used); +} + +inline void isl_siomath_uint64_to_digits(uint64_t num, mp_digit *digits, + mp_size *used) +{ + ISL_SIOIMATH_TO_DIGITS(num, digits, *used); +} + +/* Get the IMath representation of an isl_int without modifying it. + * For the case it is not in big representation yet, pass some scratch space we + * can use to store the big representation in. + * In order to avoid requiring init and free on the scratch space, we directly + * modify the internal representation. + * + * The name derives from its indented use: getting the big representation of an + * input (src) argument. + */ +inline mp_int isl_sioimath_bigarg_src(isl_sioimath arg, + isl_sioimath_scratchspace_t *scratch) +{ + mp_int big; + int32_t small; + uint32_t num; + + if (isl_sioimath_decode_big(arg, &big)) + return big; + + small = isl_sioimath_get_small(arg); + scratch->big.digits = scratch->digits; + scratch->big.alloc = ARRAY_SIZE(scratch->digits); + if (small >= 0) { + scratch->big.sign = MP_ZPOS; + num = small; + } else { + scratch->big.sign = MP_NEG; + num = -small; + } + + isl_siomath_uint32_to_digits(num, scratch->digits, &scratch->big.used); + return &scratch->big; +} + +/* Create a temporary IMath mp_int for a signed long. + */ +inline mp_int isl_sioimath_siarg_src(signed long arg, + isl_sioimath_scratchspace_t *scratch) +{ + unsigned long num; + + scratch->big.digits = scratch->digits; + scratch->big.alloc = ARRAY_SIZE(scratch->digits); + if (arg >= 0) { + scratch->big.sign = MP_ZPOS; + num = arg; + } else { + scratch->big.sign = MP_NEG; + num = (arg == LONG_MIN) ? ((unsigned long) LONG_MAX) + 1 : -arg; + } + + isl_siomath_ulong_to_digits(num, scratch->digits, &scratch->big.used); + return &scratch->big; +} + +/* Create a temporary IMath mp_int for an int64_t. + */ +inline mp_int isl_sioimath_si64arg_src(int64_t arg, + isl_sioimath_scratchspace_t *scratch) +{ + uint64_t num; + + scratch->big.digits = scratch->digits; + scratch->big.alloc = ARRAY_SIZE(scratch->digits); + if (arg >= 0) { + scratch->big.sign = MP_ZPOS; + num = arg; + } else { + scratch->big.sign = MP_NEG; + num = (arg == INT64_MIN) ? ((uint64_t) INT64_MAX) + 1 : -arg; + } + + isl_siomath_uint64_to_digits(num, scratch->digits, &scratch->big.used); + return &scratch->big; +} + +/* Create a temporary IMath mp_int for an unsigned long. + */ +inline mp_int isl_sioimath_uiarg_src(unsigned long arg, + isl_sioimath_scratchspace_t *scratch) +{ + scratch->big.digits = scratch->digits; + scratch->big.alloc = ARRAY_SIZE(scratch->digits); + scratch->big.sign = MP_ZPOS; + + isl_siomath_ulong_to_digits(arg, scratch->digits, &scratch->big.used); + return &scratch->big; +} + +/* Ensure big representation. Does not preserve the current number. + * Callers may use the fact that the value _is_ preserved if the presentation + * was big before. + */ +inline mp_int isl_sioimath_reinit_big(isl_sioimath_ptr ptr) +{ + if (isl_sioimath_is_small(*ptr)) + *ptr = isl_sioimath_encode_big(mp_int_alloc()); + return isl_sioimath_get_big(*ptr); +} + +/* Set ptr to a number in small representation. + */ +inline void isl_sioimath_set_small(isl_sioimath_ptr ptr, int32_t val) +{ + if (isl_sioimath_is_big(*ptr)) + mp_int_free(isl_sioimath_get_big(*ptr)); + *ptr = isl_sioimath_encode_small(val); +} + +/* Set ptr to val, choosing small representation if possible. + */ +inline void isl_sioimath_set_int32(isl_sioimath_ptr ptr, int32_t val) +{ + if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) { + isl_sioimath_set_small(ptr, val); + return; + } + + mp_int_init_value(isl_sioimath_reinit_big(ptr), val); +} + +/* Assign an int64_t number using small representation if possible. + */ +inline void isl_sioimath_set_int64(isl_sioimath_ptr ptr, int64_t val) +{ + if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) { + isl_sioimath_set_small(ptr, val); + return; + } + + isl_sioimath_scratchspace_t scratch; + mp_int_copy(isl_sioimath_si64arg_src(val, &scratch), + isl_sioimath_reinit_big(ptr)); +} + +/* Convert to big representation while preserving the current number. + */ +inline void isl_sioimath_promote(isl_sioimath_ptr dst) +{ + int32_t small; + + if (isl_sioimath_is_big(*dst)) + return; + + small = isl_sioimath_get_small(*dst); + mp_int_set_value(isl_sioimath_reinit_big(dst), small); +} + +/* Convert to small representation while preserving the current number. Does + * nothing if dst doesn't fit small representation. + */ +inline void isl_sioimath_try_demote(isl_sioimath_ptr dst) +{ + mp_small small; + + if (isl_sioimath_is_small(*dst)) + return; + + if (mp_int_to_int(isl_sioimath_get_big(*dst), &small) != MP_OK) + return; + + if (ISL_SIOIMATH_SMALL_MIN <= small && small <= ISL_SIOIMATH_SMALL_MAX) + isl_sioimath_set_small(dst, small); +} + +/* Initialize an isl_int. The implicit value is 0 in small representation. + */ +inline void isl_sioimath_init(isl_sioimath_ptr dst) +{ + *dst = isl_sioimath_encode_small(0); +} + +/* Free the resources taken by an isl_int. + */ +inline void isl_sioimath_clear(isl_sioimath_ptr dst) +{ + if (isl_sioimath_is_small(*dst)) + return; + + mp_int_free(isl_sioimath_get_big(*dst)); +} + +/* Copy the value of one isl_int to another. + */ +inline void isl_sioimath_set(isl_sioimath_ptr dst, isl_sioimath_src val) +{ + if (isl_sioimath_is_small(val)) { + isl_sioimath_set_small(dst, isl_sioimath_get_small(val)); + return; + } + + mp_int_copy(isl_sioimath_get_big(val), isl_sioimath_reinit_big(dst)); +} + +/* Store a signed long into an isl_int. + */ +inline void isl_sioimath_set_si(isl_sioimath_ptr dst, long val) +{ + if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) { + isl_sioimath_set_small(dst, val); + return; + } + + mp_int_set_value(isl_sioimath_reinit_big(dst), val); +} + +/* Store an unsigned long into an isl_int. + */ +inline void isl_sioimath_set_ui(isl_sioimath_ptr dst, unsigned long val) +{ + if (val <= ISL_SIOIMATH_SMALL_MAX) { + isl_sioimath_set_small(dst, val); + return; + } + + mp_int_set_uvalue(isl_sioimath_reinit_big(dst), val); +} + +/* Return whether a number can be represented by a signed long. + */ +inline int isl_sioimath_fits_slong(isl_sioimath_src val) +{ + mp_small dummy; + + if (isl_sioimath_is_small(val)) + return 1; + + return mp_int_to_int(isl_sioimath_get_big(val), &dummy) == MP_OK; +} + +/* Return a number as signed long. Result is undefined if the number cannot be + * represented as long. + */ +inline long isl_sioimath_get_si(isl_sioimath_src val) +{ + mp_small result; + + if (isl_sioimath_is_small(val)) + return isl_sioimath_get_small(val); + + mp_int_to_int(isl_sioimath_get_big(val), &result); + return result; +} + +/* Return whether a number can be represented as unsigned long. + */ +inline int isl_sioimath_fits_ulong(isl_sioimath_src val) +{ + mp_usmall dummy; + + if (isl_sioimath_is_small(val)) + return isl_sioimath_get_small(val) >= 0; + + return mp_int_to_uint(isl_sioimath_get_big(val), &dummy) == MP_OK; +} + +/* Return a number as unsigned long. Result is undefined if the number cannot be + * represented as unsigned long. + */ +inline unsigned long isl_sioimath_get_ui(isl_sioimath_src val) +{ + mp_usmall result; + + if (isl_sioimath_is_small(val)) + return isl_sioimath_get_small(val); + + mp_int_to_uint(isl_sioimath_get_big(val), &result); + return result; +} + +/* Return a number as floating point value. + */ +inline double isl_sioimath_get_d(isl_sioimath_src val) +{ + mp_int big; + double result = 0; + int i; + + if (isl_sioimath_is_small(val)) + return isl_sioimath_get_small(val); + + big = isl_sioimath_get_big(val); + for (i = 0; i < big->used; ++i) + result = result * (double) ((uintmax_t) MP_DIGIT_MAX + 1) + + (double) big->digits[i]; + + if (big->sign == MP_NEG) + result = -result; + + return result; +} + +/* Format a number as decimal string. + * + * The largest possible string from small representation is 12 characters + * ("-2147483647"). + */ +inline char *isl_sioimath_get_str(isl_sioimath_src val) +{ + char *result; + + if (isl_sioimath_is_small(val)) { + result = malloc(12); + snprintf(result, 12, "%" PRIi32, isl_sioimath_get_small(val)); + return result; + } + + return impz_get_str(NULL, 10, isl_sioimath_get_big(val)); +} + +/* Return the absolute value. + */ +inline void isl_sioimath_abs(isl_sioimath_ptr dst, isl_sioimath_src arg) +{ + if (isl_sioimath_is_small(arg)) { + isl_sioimath_set_small(dst, labs(isl_sioimath_get_small(arg))); + return; + } + + mp_int_abs(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst)); +} + +/* Return the negation of a number. + */ +inline void isl_sioimath_neg(isl_sioimath_ptr dst, isl_sioimath_src arg) +{ + if (isl_sioimath_is_small(arg)) { + isl_sioimath_set_small(dst, -isl_sioimath_get_small(arg)); + return; + } + + mp_int_neg(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst)); +} + +/* Swap two isl_ints. + * + * isl_sioimath can be copied bytewise; nothing depends on its address. It can + * also be stored in a CPU register. + */ +inline void isl_sioimath_swap(isl_sioimath_ptr lhs, isl_sioimath_ptr rhs) +{ + isl_sioimath tmp = *lhs; + *lhs = *rhs; + *rhs = tmp; +} + +/* Add an unsigned long to the number. + * + * On LP64 unsigned long exceeds the range of an int64_t, therefore we check in + * advance whether small representation possibly overflows. + */ +inline void isl_sioimath_add_ui(isl_sioimath_ptr dst, isl_sioimath lhs, + unsigned long rhs) +{ + int32_t smalllhs; + isl_sioimath_scratchspace_t lhsscratch; + + if (isl_sioimath_decode_small(lhs, &smalllhs) && + (rhs <= (uint64_t) INT64_MAX - (uint64_t) ISL_SIOIMATH_SMALL_MAX)) { + isl_sioimath_set_int64(dst, (int64_t) smalllhs + rhs); + return; + } + + impz_add_ui(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs); + isl_sioimath_try_demote(dst); +} + +/* Subtract an unsigned long. + * + * On LP64 unsigned long exceeds the range of an int64_t. If + * ISL_SIOIMATH_SMALL_MIN-rhs>=INT64_MIN we can do the calculation using int64_t + * without risking an overflow. + */ +inline void isl_sioimath_sub_ui(isl_sioimath_ptr dst, isl_sioimath lhs, + unsigned long rhs) +{ + int32_t smalllhs; + isl_sioimath_scratchspace_t lhsscratch; + + if (isl_sioimath_decode_small(lhs, &smalllhs) && + (rhs < (uint64_t) INT64_MIN - (uint64_t) ISL_SIOIMATH_SMALL_MIN)) { + isl_sioimath_set_int64(dst, (int64_t) smalllhs - rhs); + return; + } + + impz_sub_ui(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs); + isl_sioimath_try_demote(dst); +} + +/* Sum of two isl_ints. + */ +inline void isl_sioimath_add(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t scratchlhs, scratchrhs; + int32_t smalllhs, smallrhs; + + if (isl_sioimath_decode_small(lhs, &smalllhs) && + isl_sioimath_decode_small(rhs, &smallrhs)) { + isl_sioimath_set_int64( + dst, (int64_t) smalllhs + (int64_t) smallrhs); + return; + } + + mp_int_add(isl_sioimath_bigarg_src(lhs, &scratchlhs), + isl_sioimath_bigarg_src(rhs, &scratchrhs), + isl_sioimath_reinit_big(dst)); + isl_sioimath_try_demote(dst); +} + +/* Subtract two isl_ints. + */ +inline void isl_sioimath_sub(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t scratchlhs, scratchrhs; + int32_t smalllhs, smallrhs; + + if (isl_sioimath_decode_small(lhs, &smalllhs) && + isl_sioimath_decode_small(rhs, &smallrhs)) { + isl_sioimath_set_int64( + dst, (int64_t) smalllhs - (int64_t) smallrhs); + return; + } + + mp_int_sub(isl_sioimath_bigarg_src(lhs, &scratchlhs), + isl_sioimath_bigarg_src(rhs, &scratchrhs), + isl_sioimath_reinit_big(dst)); + isl_sioimath_try_demote(dst); +} + +/* Multiply two isl_ints. + */ +inline void isl_sioimath_mul(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t scratchlhs, scratchrhs; + int32_t smalllhs, smallrhs; + + if (isl_sioimath_decode_small(lhs, &smalllhs) && + isl_sioimath_decode_small(rhs, &smallrhs)) { + isl_sioimath_set_int64( + dst, (int64_t) smalllhs * (int64_t) smallrhs); + return; + } + + mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs), + isl_sioimath_bigarg_src(rhs, &scratchrhs), + isl_sioimath_reinit_big(dst)); + isl_sioimath_try_demote(dst); +} + +/* Shift lhs by rhs bits to the left and store the result in dst. Effectively, + * this operation computes 'lhs * 2^rhs'. + */ +inline void isl_sioimath_mul_2exp(isl_sioimath_ptr dst, isl_sioimath lhs, + unsigned long rhs) +{ + isl_sioimath_scratchspace_t scratchlhs; + int32_t smalllhs; + + if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= 32ul)) { + isl_sioimath_set_int64(dst, ((int64_t) smalllhs) << rhs); + return; + } + + mp_int_mul_pow2(isl_sioimath_bigarg_src(lhs, &scratchlhs), rhs, + isl_sioimath_reinit_big(dst)); +} + +/* Multiply an isl_int and a signed long. + */ +inline void isl_sioimath_mul_si(isl_sioimath_ptr dst, isl_sioimath lhs, + signed long rhs) +{ + isl_sioimath_scratchspace_t scratchlhs, scratchrhs; + int32_t smalllhs; + + if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs > LONG_MIN) && + (labs(rhs) <= UINT32_MAX)) { + isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs); + return; + } + + mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs), + isl_sioimath_siarg_src(rhs, &scratchrhs), + isl_sioimath_reinit_big(dst)); + isl_sioimath_try_demote(dst); +} + +/* Multiply an isl_int and an unsigned long. + */ +inline void isl_sioimath_mul_ui(isl_sioimath_ptr dst, isl_sioimath lhs, + unsigned long rhs) +{ + isl_sioimath_scratchspace_t scratchlhs, scratchrhs; + int32_t smalllhs; + + if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= UINT32_MAX)) { + isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs); + return; + } + + mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs), + isl_sioimath_uiarg_src(rhs, &scratchrhs), + isl_sioimath_reinit_big(dst)); + isl_sioimath_try_demote(dst); +} + +/* Compute the power of an isl_int to an unsigned long. + * Always let IMath do it; the result is unlikely to be small except in some + * special cases. + * Note: 0^0 == 1 + */ +inline void isl_sioimath_pow_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs) +{ + isl_sioimath_scratchspace_t scratchlhs, scratchrhs; + int32_t smalllhs; + + switch (rhs) { + case 0: + isl_sioimath_set_small(dst, 1); + return; + case 1: + isl_sioimath_set(dst, lhs); + return; + case 2: + isl_sioimath_mul(dst, lhs, lhs); + return; + } + + if (isl_sioimath_decode_small(lhs, &smalllhs)) { + switch (smalllhs) { + case 0: + isl_sioimath_set_small(dst, 0); + return; + case 1: + isl_sioimath_set_small(dst, 1); + return; + case 2: + isl_sioimath_set_small(dst, 1); + isl_sioimath_mul_2exp(dst, *dst, rhs); + return; + default: + if ((MP_SMALL_MIN <= rhs) && (rhs <= MP_SMALL_MAX)) { + mp_int_expt_value(smalllhs, rhs, + isl_sioimath_reinit_big(dst)); + isl_sioimath_try_demote(dst); + return; + } + } + } + + mp_int_expt_full(isl_sioimath_bigarg_src(lhs, &scratchlhs), + isl_sioimath_uiarg_src(rhs, &scratchrhs), + isl_sioimath_reinit_big(dst)); + isl_sioimath_try_demote(dst); +} + +/* Fused multiply-add. + */ +inline void isl_sioimath_addmul(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath tmp; + isl_sioimath_init(&tmp); + isl_sioimath_mul(&tmp, lhs, rhs); + isl_sioimath_add(dst, *dst, tmp); + isl_sioimath_clear(&tmp); +} + +/* Fused multiply-add with an unsigned long. + */ +inline void isl_sioimath_addmul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs) +{ + isl_sioimath tmp; + isl_sioimath_init(&tmp); + isl_sioimath_mul_ui(&tmp, lhs, rhs); + isl_sioimath_add(dst, *dst, tmp); + isl_sioimath_clear(&tmp); +} + +/* Fused multiply-subtract. + */ +inline void isl_sioimath_submul(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath tmp; + isl_sioimath_init(&tmp); + isl_sioimath_mul(&tmp, lhs, rhs); + isl_sioimath_sub(dst, *dst, tmp); + isl_sioimath_clear(&tmp); +} + +/* Fused multiply-add with an unsigned long. + */ +inline void isl_sioimath_submul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs) +{ + isl_sioimath tmp; + isl_sioimath_init(&tmp); + isl_sioimath_mul_ui(&tmp, lhs, rhs); + isl_sioimath_sub(dst, *dst, tmp); + isl_sioimath_clear(&tmp); +} + +void isl_sioimath_gcd(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +void isl_sioimath_lcm(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); + +/* Divide lhs by rhs, rounding to zero (Truncate). + */ +inline void isl_sioimath_tdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t lhssmall, rhssmall; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && + isl_sioimath_decode_small(rhs, &rhssmall)) { + isl_sioimath_set_small(dst, lhssmall / rhssmall); + return; + } + + mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_bigarg_src(rhs, &rhsscratch), + isl_sioimath_reinit_big(dst), NULL); + isl_sioimath_try_demote(dst); + return; +} + +/* Divide lhs by an unsigned long rhs, rounding to zero (Truncate). + */ +inline void isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t lhssmall; + + if (isl_sioimath_is_small(lhs) && (rhs <= (unsigned long) INT32_MAX)) { + lhssmall = isl_sioimath_get_small(lhs); + isl_sioimath_set_small(dst, lhssmall / (int32_t) rhs); + return; + } + + if (rhs <= MP_SMALL_MAX) { + mp_int_div_value(isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs, + isl_sioimath_reinit_big(dst), NULL); + isl_sioimath_try_demote(dst); + return; + } + + mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_uiarg_src(rhs, &rhsscratch), + isl_sioimath_reinit_big(dst), NULL); + isl_sioimath_try_demote(dst); +} + +/* Divide lhs by rhs, rounding to positive infinity (Ceil). + */ +inline void isl_sioimath_cdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + int32_t lhssmall, rhssmall; + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t q; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && + isl_sioimath_decode_small(rhs, &rhssmall)) { + if ((lhssmall >= 0) && (rhssmall >= 0)) + q = ((int64_t) lhssmall + (int64_t) rhssmall - 1) / + rhssmall; + else if ((lhssmall < 0) && (rhssmall < 0)) + q = ((int64_t) lhssmall + (int64_t) rhssmall + 1) / + rhssmall; + else + q = lhssmall / rhssmall; + isl_sioimath_set_small(dst, q); + return; + } + + impz_cdiv_q(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_bigarg_src(rhs, &rhsscratch)); + isl_sioimath_try_demote(dst); +} + +/* Compute the division of lhs by a rhs of type unsigned long, rounding towards + * positive infinity (Ceil). + */ +inline void isl_sioimath_cdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t lhssmall, q; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)) { + if (lhssmall >= 0) + q = ((int64_t) lhssmall + ((int64_t) rhs - 1)) / + (int64_t) rhs; + else + q = lhssmall / (int32_t) rhs; + isl_sioimath_set_small(dst, q); + return; + } + + impz_cdiv_q(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_uiarg_src(rhs, &rhsscratch)); + isl_sioimath_try_demote(dst); +} + +/* Divide lhs by rhs, rounding to negative infinity (Floor). + */ +inline void isl_sioimath_fdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t lhssmall, rhssmall; + int32_t q; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && + isl_sioimath_decode_small(rhs, &rhssmall)) { + if ((lhssmall < 0) && (rhssmall >= 0)) + q = ((int64_t) lhssmall - ((int64_t) rhssmall - 1)) / + rhssmall; + else if ((lhssmall >= 0) && (rhssmall < 0)) + q = ((int64_t) lhssmall - ((int64_t) rhssmall + 1)) / + rhssmall; + else + q = lhssmall / rhssmall; + isl_sioimath_set_small(dst, q); + return; + } + + impz_fdiv_q(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_bigarg_src(rhs, &rhsscratch)); + isl_sioimath_try_demote(dst); +} + +/* Compute the division of lhs by a rhs of type unsigned long, rounding towards + * negative infinity (Floor). + */ +inline void isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t lhssmall, q; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)) { + if (lhssmall >= 0) + q = (uint32_t) lhssmall / rhs; + else + q = ((int64_t) lhssmall - ((int64_t) rhs - 1)) / + (int64_t) rhs; + isl_sioimath_set_small(dst, q); + return; + } + + impz_fdiv_q(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_uiarg_src(rhs, &rhsscratch)); + isl_sioimath_try_demote(dst); +} + +/* Get the remainder of: lhs divided by rhs rounded towards negative infinite + * (Floor). + */ +inline void isl_sioimath_fdiv_r(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int64_t lhssmall, rhssmall; + int32_t r; + + if (isl_sioimath_is_small(lhs) && isl_sioimath_is_small(rhs)) { + lhssmall = isl_sioimath_get_small(lhs); + rhssmall = isl_sioimath_get_small(rhs); + r = (rhssmall + lhssmall % rhssmall) % rhssmall; + isl_sioimath_set_small(dst, r); + return; + } + + impz_fdiv_r(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_bigarg_src(rhs, &rhsscratch)); + isl_sioimath_try_demote(dst); +} + +void isl_sioimath_read(isl_sioimath_ptr dst, const char *str); + +/* Return: + * +1 for a positive number + * -1 for a negative number + * 0 if the number is zero + */ +inline int isl_sioimath_sgn(isl_sioimath_src arg) +{ + int32_t small; + + if (isl_sioimath_decode_small(arg, &small)) + return (small > 0) - (small < 0); + + return mp_int_compare_zero(isl_sioimath_get_big(arg)); +} + +/* Return: + * +1 if lhs > rhs + * -1 if lhs < rhs + * 0 if lhs = rhs + */ +inline int isl_sioimath_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t lhssmall, rhssmall; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && + isl_sioimath_decode_small(rhs, &rhssmall)) + return (lhssmall > rhssmall) - (lhssmall < rhssmall); + + if (isl_sioimath_decode_small(rhs, &rhssmall)) + return mp_int_compare_value( + isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall); + + if (isl_sioimath_decode_small(lhs, &lhssmall)) + return -mp_int_compare_value( + isl_sioimath_bigarg_src(rhs, &rhsscratch), lhssmall); + + return mp_int_compare( + isl_sioimath_get_big(lhs), isl_sioimath_get_big(rhs)); +} + +/* As isl_sioimath_cmp, but with signed long rhs. + */ +inline int isl_sioimath_cmp_si(isl_sioimath_src lhs, signed long rhs) +{ + int32_t lhssmall; + + if (isl_sioimath_decode_small(lhs, &lhssmall)) + return (lhssmall > rhs) - (lhssmall < rhs); + + return mp_int_compare_value(isl_sioimath_get_big(lhs), rhs); +} + +/* Return: + * +1 if |lhs| > |rhs| + * -1 if |lhs| < |rhs| + * 0 if |lhs| = |rhs| + */ +inline int isl_sioimath_abs_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t lhssmall, rhssmall; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && + isl_sioimath_decode_small(rhs, &rhssmall)) { + lhssmall = labs(lhssmall); + rhssmall = labs(rhssmall); + return (lhssmall > rhssmall) - (lhssmall < rhssmall); + } + + return mp_int_compare_unsigned( + isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_bigarg_src(rhs, &rhsscratch)); +} + +/* Return whether lhs is divisible by rhs. + * In particular, can rhs be multiplied by some integer to result in lhs? + * If rhs is zero, then this means lhs has to be zero too. + */ +inline int isl_sioimath_is_divisible_by(isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + isl_sioimath_scratchspace_t lhsscratch, rhsscratch; + int32_t lhssmall, rhssmall; + mpz_t rem; + int cmp; + + if (isl_sioimath_sgn(rhs) == 0) + return isl_sioimath_sgn(lhs) == 0; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && + isl_sioimath_decode_small(rhs, &rhssmall)) + return lhssmall % rhssmall == 0; + + if (isl_sioimath_decode_small(rhs, &rhssmall)) + return mp_int_divisible_value( + isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall); + + mp_int_init(&rem); + mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch), + isl_sioimath_bigarg_src(rhs, &rhsscratch), NULL, &rem); + cmp = mp_int_compare_zero(&rem); + mp_int_clear(&rem); + return cmp == 0; +} + +/* Return a hash code of an isl_sioimath. + * The hash code for a number in small and big representation must be identical + * on the same machine because small representation if not obligatory if fits. + */ +inline uint32_t isl_sioimath_hash(isl_sioimath_src arg, uint32_t hash) +{ + int32_t small; + int i; + uint32_t num; + mp_digit digits[(sizeof(uint32_t) + sizeof(mp_digit) - 1) / + sizeof(mp_digit)]; + mp_size used; + const unsigned char *digitdata = (const unsigned char *) &digits; + + if (isl_sioimath_decode_small(arg, &small)) { + if (small < 0) + isl_hash_byte(hash, 0xFF); + num = labs(small); + + isl_siomath_uint32_to_digits(num, digits, &used); + for (i = 0; i < used * sizeof(mp_digit); i += 1) + isl_hash_byte(hash, digitdata[i]); + return hash; + } + + return isl_imath_hash(isl_sioimath_get_big(arg), hash); +} + +/* Return the number of digits in a number of the given base or more, i.e. the + * string length without sign and null terminator. + * + * Current implementation for small representation returns the maximal number + * of binary digits in that representation, which can be much larger than the + * smallest possible solution. + */ +inline size_t isl_sioimath_sizeinbase(isl_sioimath_src arg, int base) +{ + int32_t small; + + if (isl_sioimath_decode_small(arg, &small)) + return sizeof(int32_t) * CHAR_BIT - 1; + + return impz_sizeinbase(isl_sioimath_get_big(arg), base); +} + +void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width); +void isl_sioimath_dump(isl_sioimath_src arg); + +typedef isl_sioimath isl_int[1]; +#define isl_int_init(i) isl_sioimath_init((i)) +#define isl_int_clear(i) isl_sioimath_clear((i)) + +#define isl_int_set(r, i) isl_sioimath_set((r), *(i)) +#define isl_int_set_si(r, i) isl_sioimath_set_si((r), i) +#define isl_int_set_ui(r, i) isl_sioimath_set_ui((r), i) +#define isl_int_fits_slong(r) isl_sioimath_fits_slong(*(r)) +#define isl_int_get_si(r) isl_sioimath_get_si(*(r)) +#define isl_int_fits_ulong(r) isl_sioimath_fits_ulong(*(r)) +#define isl_int_get_ui(r) isl_sioimath_get_ui(*(r)) +#define isl_int_get_d(r) isl_sioimath_get_d(*(r)) +#define isl_int_get_str(r) isl_sioimath_get_str(*(r)) +#define isl_int_abs(r, i) isl_sioimath_abs((r), *(i)) +#define isl_int_neg(r, i) isl_sioimath_neg((r), *(i)) +#define isl_int_swap(i, j) isl_sioimath_swap((i), (j)) +#define isl_int_swap_or_set(i, j) isl_sioimath_swap((i), (j)) +#define isl_int_add_ui(r, i, j) isl_sioimath_add_ui((r), *(i), j) +#define isl_int_sub_ui(r, i, j) isl_sioimath_sub_ui((r), *(i), j) + +#define isl_int_add(r, i, j) isl_sioimath_add((r), *(i), *(j)) +#define isl_int_sub(r, i, j) isl_sioimath_sub((r), *(i), *(j)) +#define isl_int_mul(r, i, j) isl_sioimath_mul((r), *(i), *(j)) +#define isl_int_mul_2exp(r, i, j) isl_sioimath_mul_2exp((r), *(i), j) +#define isl_int_mul_si(r, i, j) isl_sioimath_mul_si((r), *(i), j) +#define isl_int_mul_ui(r, i, j) isl_sioimath_mul_ui((r), *(i), j) +#define isl_int_pow_ui(r, i, j) isl_sioimath_pow_ui((r), *(i), j) +#define isl_int_addmul(r, i, j) isl_sioimath_addmul((r), *(i), *(j)) +#define isl_int_addmul_ui(r, i, j) isl_sioimath_addmul_ui((r), *(i), j) +#define isl_int_submul(r, i, j) isl_sioimath_submul((r), *(i), *(j)) +#define isl_int_submul_ui(r, i, j) isl_sioimath_submul_ui((r), *(i), j) + +#define isl_int_gcd(r, i, j) isl_sioimath_gcd((r), *(i), *(j)) +#define isl_int_lcm(r, i, j) isl_sioimath_lcm((r), *(i), *(j)) +#define isl_int_divexact(r, i, j) isl_sioimath_tdiv_q((r), *(i), *(j)) +#define isl_int_divexact_ui(r, i, j) isl_sioimath_tdiv_q_ui((r), *(i), j) +#define isl_int_tdiv_q(r, i, j) isl_sioimath_tdiv_q((r), *(i), *(j)) +#define isl_int_cdiv_q(r, i, j) isl_sioimath_cdiv_q((r), *(i), *(j)) +#define isl_int_cdiv_q_ui(r, i, j) isl_sioimath_cdiv_q_ui((r), *(i), j) +#define isl_int_fdiv_q(r, i, j) isl_sioimath_fdiv_q((r), *(i), *(j)) +#define isl_int_fdiv_r(r, i, j) isl_sioimath_fdiv_r((r), *(i), *(j)) +#define isl_int_fdiv_q_ui(r, i, j) isl_sioimath_fdiv_q_ui((r), *(i), j) + +#define isl_int_read(r, s) isl_sioimath_read((r), s) +#define isl_int_sgn(i) isl_sioimath_sgn(*(i)) +#define isl_int_cmp(i, j) isl_sioimath_cmp(*(i), *(j)) +#define isl_int_cmp_si(i, si) isl_sioimath_cmp_si(*(i), si) +#define isl_int_eq(i, j) (isl_sioimath_cmp(*(i), *(j)) == 0) +#define isl_int_ne(i, j) (isl_sioimath_cmp(*(i), *(j)) != 0) +#define isl_int_lt(i, j) (isl_sioimath_cmp(*(i), *(j)) < 0) +#define isl_int_le(i, j) (isl_sioimath_cmp(*(i), *(j)) <= 0) +#define isl_int_gt(i, j) (isl_sioimath_cmp(*(i), *(j)) > 0) +#define isl_int_ge(i, j) (isl_sioimath_cmp(*(i), *(j)) >= 0) +#define isl_int_abs_cmp(i, j) isl_sioimath_abs_cmp(*(i), *(j)) +#define isl_int_abs_eq(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) == 0) +#define isl_int_abs_ne(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) != 0) +#define isl_int_abs_lt(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) < 0) +#define isl_int_abs_gt(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) > 0) +#define isl_int_abs_ge(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) >= 0) +#define isl_int_is_divisible_by(i, j) isl_sioimath_is_divisible_by(*(i), *(j)) + +#define isl_int_hash(v, h) isl_sioimath_hash(*(v), h) +#define isl_int_free_str(s) free(s) +#define isl_int_print(out, i, width) isl_sioimath_print(out, *(i), width) + +#endif /* ISL_INT_SIOIMATH_H */ Index: contrib/isl/isl_int_sioimath.c =================================================================== --- /dev/null +++ contrib/isl/isl_int_sioimath.c @@ -0,0 +1,223 @@ +#include +#include + +#include + +extern int isl_sioimath_decode(isl_sioimath val, int32_t *small, mp_int *big); +extern int isl_sioimath_decode_big(isl_sioimath val, mp_int *big); +extern int isl_sioimath_decode_small(isl_sioimath val, int32_t *small); + +extern isl_sioimath isl_sioimath_encode_small(int32_t val); +extern isl_sioimath isl_sioimath_encode_big(mp_int val); +extern int isl_sioimath_is_small(isl_sioimath val); +extern int isl_sioimath_is_big(isl_sioimath val); +extern int32_t isl_sioimath_get_small(isl_sioimath val); +extern mp_int isl_sioimath_get_big(isl_sioimath val); + +extern void isl_siomath_uint32_to_digits(uint32_t num, mp_digit *digits, + mp_size *used); +extern void isl_siomath_ulong_to_digits(unsigned long num, mp_digit *digits, + mp_size *used); +extern void isl_siomath_uint64_to_digits(uint64_t num, mp_digit *digits, + mp_size *used); + +extern mp_int isl_sioimath_bigarg_src(isl_sioimath arg, + isl_sioimath_scratchspace_t *scratch); +extern mp_int isl_sioimath_siarg_src(signed long arg, + isl_sioimath_scratchspace_t *scratch); +extern mp_int isl_sioimath_si64arg_src(int64_t arg, + isl_sioimath_scratchspace_t *scratch); +extern mp_int isl_sioimath_uiarg_src(unsigned long arg, + isl_sioimath_scratchspace_t *scratch); +extern mp_int isl_sioimath_reinit_big(isl_sioimath_ptr ptr); +extern void isl_sioimath_set_small(isl_sioimath_ptr ptr, int32_t val); +extern void isl_sioimath_set_int32(isl_sioimath_ptr ptr, int32_t val); +extern void isl_sioimath_set_int64(isl_sioimath_ptr ptr, int64_t val); +extern void isl_sioimath_promote(isl_sioimath_ptr dst); +extern void isl_sioimath_try_demote(isl_sioimath_ptr dst); + +extern void isl_sioimath_init(isl_sioimath_ptr dst); +extern void isl_sioimath_clear(isl_sioimath_ptr dst); +extern void isl_sioimath_set(isl_sioimath_ptr dst, isl_sioimath_src val); +extern void isl_sioimath_set_si(isl_sioimath_ptr dst, long val); +extern void isl_sioimath_set_ui(isl_sioimath_ptr dst, unsigned long val); +extern int isl_sioimath_fits_slong(isl_sioimath_src val); +extern long isl_sioimath_get_si(isl_sioimath_src val); +extern int isl_sioimath_fits_ulong(isl_sioimath_src val); +extern unsigned long isl_sioimath_get_ui(isl_sioimath_src val); +extern double isl_sioimath_get_d(isl_sioimath_src val); +extern char *isl_sioimath_get_str(isl_sioimath_src val); +extern void isl_sioimath_abs(isl_sioimath_ptr dst, isl_sioimath_src arg); +extern void isl_sioimath_neg(isl_sioimath_ptr dst, isl_sioimath_src arg); +extern void isl_sioimath_swap(isl_sioimath_ptr lhs, isl_sioimath_ptr rhs); +extern void isl_sioimath_add_ui(isl_sioimath_ptr dst, isl_sioimath lhs, + unsigned long rhs); +extern void isl_sioimath_sub_ui(isl_sioimath_ptr dst, isl_sioimath lhs, + unsigned long rhs); + +extern void isl_sioimath_add(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +extern void isl_sioimath_sub(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +extern void isl_sioimath_mul(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +extern void isl_sioimath_mul_2exp(isl_sioimath_ptr dst, isl_sioimath lhs, + unsigned long rhs); +extern void isl_sioimath_mul_si(isl_sioimath_ptr dst, isl_sioimath lhs, + signed long rhs); +extern void isl_sioimath_mul_ui(isl_sioimath_ptr dst, isl_sioimath lhs, + unsigned long rhs); +extern void isl_sioimath_pow_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs); +extern void isl_sioimath_addmul(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +extern void isl_sioimath_addmul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs); +extern void isl_sioimath_submul(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +extern void isl_sioimath_submul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs); + +/* Implements the Euclidean algorithm to compute the greatest common divisor of + * two values in small representation. + */ +static uint32_t isl_sioimath_smallgcd(int32_t lhs, int32_t rhs) +{ + uint32_t dividend, divisor, remainder; + + dividend = labs(lhs); + divisor = labs(rhs); + while (divisor) { + remainder = dividend % divisor; + dividend = divisor; + divisor = remainder; + } + + return dividend; +} + +/* Compute the greatest common divisor. + * + * Per GMP convention, gcd(0,0)==0 and otherwise always positive. + */ +void isl_sioimath_gcd(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + int32_t lhssmall, rhssmall; + uint32_t smallgcd; + isl_sioimath_scratchspace_t scratchlhs, scratchrhs; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && + isl_sioimath_decode_small(rhs, &rhssmall)) { + smallgcd = isl_sioimath_smallgcd(lhssmall, rhssmall); + isl_sioimath_set_small(dst, smallgcd); + return; + } + + impz_gcd(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &scratchlhs), + isl_sioimath_bigarg_src(rhs, &scratchrhs)); + isl_sioimath_try_demote(dst); +} + +/* Compute the lowest common multiple of two numbers. + */ +void isl_sioimath_lcm(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs) +{ + int32_t lhssmall, rhssmall; + uint32_t smallgcd; + uint64_t multiple; + isl_sioimath_scratchspace_t scratchlhs, scratchrhs; + + if (isl_sioimath_decode_small(lhs, &lhssmall) && + isl_sioimath_decode_small(rhs, &rhssmall)) { + if (lhssmall == 0 || rhssmall == 0) { + isl_sioimath_set_small(dst, 0); + return; + } + smallgcd = isl_sioimath_smallgcd(lhssmall, rhssmall); + multiple = (uint64_t) abs(lhssmall) * (uint64_t) abs(rhssmall); + isl_sioimath_set_int64(dst, multiple / smallgcd); + return; + } + + impz_lcm(isl_sioimath_reinit_big(dst), + isl_sioimath_bigarg_src(lhs, &scratchlhs), + isl_sioimath_bigarg_src(rhs, &scratchrhs)); + isl_sioimath_try_demote(dst); +} + +extern void isl_sioimath_tdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +extern void isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs); +extern void isl_sioimath_cdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +extern void isl_sioimath_cdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs); +extern void isl_sioimath_fdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); +extern void isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, + unsigned long rhs); +extern void isl_sioimath_fdiv_r(isl_sioimath_ptr dst, isl_sioimath_src lhs, + isl_sioimath_src rhs); + +/* Parse a number from a string. + * If it has less than 10 characters then it will fit into the small + * representation (i.e. strlen("2147483647")). Otherwise, let IMath parse it. + */ +void isl_sioimath_read(isl_sioimath_ptr dst, const char *str) +{ + int32_t small; + + if (strlen(str) < 10) { + small = strtol(str, NULL, 10); + isl_sioimath_set_small(dst, small); + return; + } + + mp_int_read_string(isl_sioimath_reinit_big(dst), 10, str); + isl_sioimath_try_demote(dst); +} + +extern int isl_sioimath_sgn(isl_sioimath_src arg); +extern int isl_sioimath_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs); +extern int isl_sioimath_cmp_si(isl_sioimath_src lhs, signed long rhs); +extern int isl_sioimath_abs_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs); +extern int isl_sioimath_is_divisible_by(isl_sioimath_src lhs, + isl_sioimath_src rhs); + +extern uint32_t isl_sioimath_hash(isl_sioimath_src arg, uint32_t hash); +extern size_t isl_sioimath_sizeinbase(isl_sioimath_src arg, int base); +extern void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width); + +/* Print an isl_int to FILE*. Adds space padding to the left until at least + * width characters are printed. + */ +void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width) +{ + size_t len; + int32_t small; + mp_int big; + char *buf; + + if (isl_sioimath_decode_small(i, &small)) { + fprintf(out, "%*" PRIi32, width, small); + return; + } + + big = isl_sioimath_get_big(i); + len = mp_int_string_len(big, 10); + buf = malloc(len); + mp_int_to_string(big, 10, buf, len); + fprintf(out, "%*s", width, buf); + free(buf); +} + +/* Print a number to stdout. Meant for debugging. + */ +void isl_sioimath_dump(isl_sioimath_src arg) +{ + isl_sioimath_print(stdout, arg, 0); +} Index: contrib/isl/isl_list_templ.h =================================================================== --- /dev/null +++ contrib/isl/isl_list_templ.h @@ -0,0 +1,16 @@ +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) +#define xLIST(EL) EL ## _list +#define LIST(EL) xLIST(EL) + +struct LIST(EL) { + int ref; + isl_ctx *ctx; + + int n; + + size_t size; + struct EL *p[1]; +}; + +__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list); Index: contrib/isl/isl_list_templ.c =================================================================== --- /dev/null +++ contrib/isl/isl_list_templ.c @@ -0,0 +1,612 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2011 INRIA Saclay + * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2017 Sven Verdoolaege + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include + +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef EL +#define EL CAT(isl_,BASE) +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) +#define xLIST(EL) EL ## _list +#define LIST(EL) xLIST(EL) +#define xS(TYPE,NAME) struct TYPE ## _ ## NAME +#define S(TYPE,NAME) xS(TYPE,NAME) + +isl_ctx *FN(LIST(EL),get_ctx)(__isl_keep LIST(EL) *list) +{ + return list ? list->ctx : NULL; +} + +__isl_give LIST(EL) *FN(LIST(EL),alloc)(isl_ctx *ctx, int n) +{ + LIST(EL) *list; + + if (n < 0) + isl_die(ctx, isl_error_invalid, + "cannot create list of negative length", + return NULL); + list = isl_alloc(ctx, LIST(EL), + sizeof(LIST(EL)) + (n - 1) * sizeof(struct EL *)); + if (!list) + return NULL; + + list->ctx = ctx; + isl_ctx_ref(ctx); + list->ref = 1; + list->size = n; + list->n = 0; + return list; +} + +__isl_give LIST(EL) *FN(LIST(EL),copy)(__isl_keep LIST(EL) *list) +{ + if (!list) + return NULL; + + list->ref++; + return list; +} + +__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list) +{ + int i; + LIST(EL) *dup; + + if (!list) + return NULL; + + dup = FN(LIST(EL),alloc)(FN(LIST(EL),get_ctx)(list), list->n); + if (!dup) + return NULL; + for (i = 0; i < list->n; ++i) + dup = FN(LIST(EL),add)(dup, FN(EL,copy)(list->p[i])); + return dup; +} + +__isl_give LIST(EL) *FN(LIST(EL),cow)(__isl_take LIST(EL) *list) +{ + if (!list) + return NULL; + + if (list->ref == 1) + return list; + list->ref--; + return FN(LIST(EL),dup)(list); +} + +/* Make sure "list" has room for at least "n" more pieces. + * Always return a list with a single reference. + * + * If there is only one reference to list, we extend it in place. + * Otherwise, we create a new LIST(EL) and copy the elements. + */ +static __isl_give LIST(EL) *FN(LIST(EL),grow)(__isl_take LIST(EL) *list, int n) +{ + isl_ctx *ctx; + int i, new_size; + LIST(EL) *res; + + if (!list) + return NULL; + if (list->ref == 1 && list->n + n <= list->size) + return list; + + ctx = FN(LIST(EL),get_ctx)(list); + new_size = ((list->n + n + 1) * 3) / 2; + if (list->ref == 1) { + res = isl_realloc(ctx, list, LIST(EL), + sizeof(LIST(EL)) + (new_size - 1) * sizeof(EL *)); + if (!res) + return FN(LIST(EL),free)(list); + res->size = new_size; + return res; + } + + if (list->n + n <= list->size && list->size < new_size) + new_size = list->size; + + res = FN(LIST(EL),alloc)(ctx, new_size); + if (!res) + return FN(LIST(EL),free)(list); + + for (i = 0; i < list->n; ++i) + res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i])); + + FN(LIST(EL),free)(list); + return res; +} + +/* Check that "index" is a valid position in "list". + */ +static isl_stat FN(LIST(EL),check_index)(__isl_keep LIST(EL) *list, int index) +{ + if (!list) + return isl_stat_error; + if (index < 0 || index >= list->n) + isl_die(FN(LIST(EL),get_ctx)(list), isl_error_invalid, + "index out of bounds", return isl_stat_error); + return isl_stat_ok; +} + +__isl_give LIST(EL) *FN(LIST(EL),add)(__isl_take LIST(EL) *list, + __isl_take struct EL *el) +{ + list = FN(LIST(EL),grow)(list, 1); + if (!list || !el) + goto error; + list->p[list->n] = el; + list->n++; + return list; +error: + FN(EL,free)(el); + FN(LIST(EL),free)(list); + return NULL; +} + +/* Remove the "n" elements starting at "first" from "list". + */ +__isl_give LIST(EL) *FN(LIST(EL),drop)(__isl_take LIST(EL) *list, + unsigned first, unsigned n) +{ + int i; + + if (!list) + return NULL; + if (first + n > list->n || first + n < first) + isl_die(list->ctx, isl_error_invalid, + "index out of bounds", return FN(LIST(EL),free)(list)); + if (n == 0) + return list; + list = FN(LIST(EL),cow)(list); + if (!list) + return NULL; + for (i = 0; i < n; ++i) + FN(EL,free)(list->p[first + i]); + for (i = first; i + n < list->n; ++i) + list->p[i] = list->p[i + n]; + list->n -= n; + return list; +} + +/* Insert "el" at position "pos" in "list". + * + * If there is only one reference to "list" and if it already has space + * for one extra element, we insert it directly into "list". + * Otherwise, we create a new list consisting of "el" and copied + * elements from "list". + */ +__isl_give LIST(EL) *FN(LIST(EL),insert)(__isl_take LIST(EL) *list, + unsigned pos, __isl_take struct EL *el) +{ + int i; + isl_ctx *ctx; + LIST(EL) *res; + + if (!list || !el) + goto error; + ctx = FN(LIST(EL),get_ctx)(list); + if (pos > list->n) + isl_die(ctx, isl_error_invalid, + "index out of bounds", goto error); + + if (list->ref == 1 && list->size > list->n) { + for (i = list->n; i > pos; --i) + list->p[i] = list->p[i - 1]; + list->n++; + list->p[pos] = el; + return list; + } + + res = FN(LIST(EL),alloc)(ctx, list->n + 1); + for (i = 0; i < pos; ++i) + res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i])); + res = FN(LIST(EL),add)(res, el); + for (i = pos; i < list->n; ++i) + res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i])); + FN(LIST(EL),free)(list); + + return res; +error: + FN(EL,free)(el); + FN(LIST(EL),free)(list); + return NULL; +} + +__isl_null LIST(EL) *FN(LIST(EL),free)(__isl_take LIST(EL) *list) +{ + int i; + + if (!list) + return NULL; + + if (--list->ref > 0) + return NULL; + + isl_ctx_deref(list->ctx); + for (i = 0; i < list->n; ++i) + FN(EL,free)(list->p[i]); + free(list); + + return NULL; +} + +int FN(FN(LIST(EL),n),BASE)(__isl_keep LIST(EL) *list) +{ + return list ? list->n : 0; +} + +__isl_give EL *FN(FN(LIST(EL),get),BASE)(__isl_keep LIST(EL) *list, int index) +{ + if (FN(LIST(EL),check_index)(list, index) < 0) + return NULL; + return FN(EL,copy)(list->p[index]); +} + +/* Replace the element at position "index" in "list" by "el". + */ +__isl_give LIST(EL) *FN(FN(LIST(EL),set),BASE)(__isl_take LIST(EL) *list, + int index, __isl_take EL *el) +{ + if (!list || !el) + goto error; + if (FN(LIST(EL),check_index)(list, index) < 0) + goto error; + if (list->p[index] == el) { + FN(EL,free)(el); + return list; + } + list = FN(LIST(EL),cow)(list); + if (!list) + goto error; + FN(EL,free)(list->p[index]); + list->p[index] = el; + return list; +error: + FN(EL,free)(el); + FN(LIST(EL),free)(list); + return NULL; +} + +/* Return the element at position "index" of "list". + * This may be either a copy or the element itself + * if there is only one reference to "list". + * This allows the element to be modified inplace + * if both the list and the element have only a single reference. + * The caller is not allowed to modify "list" between + * this call to isl_list_*_take_* and a subsequent call + * to isl_list_*_restore_*. + * The only exception is that isl_list_*_free can be called instead. + */ +static __isl_give EL *FN(FN(LIST(EL),take),BASE)(__isl_keep LIST(EL) *list, + int index) +{ + EL *el; + + if (FN(LIST(EL),check_index)(list, index) < 0) + return NULL; + if (list->ref != 1) + return FN(FN(LIST(EL),get),BASE)(list, index); + el = list->p[index]; + list->p[index] = NULL; + return el; +} + +/* Set the element at position "index" of "list" to "el", + * where the position may be empty due to a previous call + * to isl_list_*_take_*. + */ +static __isl_give LIST(EL) *FN(FN(LIST(EL),restore),BASE)( + __isl_take LIST(EL) *list, int index, __isl_take EL *el) +{ + return FN(FN(LIST(EL),set),BASE)(list, index, el); +} + +isl_stat FN(LIST(EL),foreach)(__isl_keep LIST(EL) *list, + isl_stat (*fn)(__isl_take EL *el, void *user), void *user) +{ + int i; + + if (!list) + return isl_stat_error; + + for (i = 0; i < list->n; ++i) { + EL *el = FN(EL,copy)(list->p[i]); + if (!el) + return isl_stat_error; + if (fn(el, user) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Replace each element in "list" by the result of calling "fn" + * on the element. + */ +__isl_give LIST(EL) *FN(LIST(EL),map)(__isl_keep LIST(EL) *list, + __isl_give EL *(*fn)(__isl_take EL *el, void *user), void *user) +{ + int i, n; + + if (!list) + return NULL; + + n = list->n; + for (i = 0; i < n; ++i) { + EL *el = FN(FN(LIST(EL),take),BASE)(list, i); + if (!el) + return FN(LIST(EL),free)(list); + el = fn(el, user); + list = FN(FN(LIST(EL),restore),BASE)(list, i, el); + } + + return list; +} + +/* Internal data structure for isl_*_list_sort. + * + * "cmp" is the original comparison function. + * "user" is a user provided pointer that should be passed to "cmp". + */ +S(LIST(EL),sort_data) { + int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user); + void *user; +}; + +/* Compare two entries of an isl_*_list based on the user provided + * comparison function on pairs of isl_* objects. + */ +static int FN(LIST(EL),cmp)(const void *a, const void *b, void *user) +{ + S(LIST(EL),sort_data) *data = user; + EL * const *el1 = a; + EL * const *el2 = b; + + return data->cmp(*el1, *el2, data->user); +} + +/* Sort the elements of "list" in ascending order according to + * comparison function "cmp". + */ +__isl_give LIST(EL) *FN(LIST(EL),sort)(__isl_take LIST(EL) *list, + int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user), void *user) +{ + S(LIST(EL),sort_data) data = { cmp, user }; + + if (!list) + return NULL; + if (list->n <= 1) + return list; + list = FN(LIST(EL),cow)(list); + if (!list) + return NULL; + + if (isl_sort(list->p, list->n, sizeof(list->p[0]), + &FN(LIST(EL),cmp), &data) < 0) + return FN(LIST(EL),free)(list); + + return list; +} + +/* Internal data structure for isl_*_list_foreach_scc. + * + * "list" is the original list. + * "follows" is the user provided callback that defines the edges of the graph. + */ +S(LIST(EL),foreach_scc_data) { + LIST(EL) *list; + isl_bool (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user); + void *follows_user; +}; + +/* Does element i of data->list follow element j? + * + * Use the user provided callback to find out. + */ +static isl_bool FN(LIST(EL),follows)(int i, int j, void *user) +{ + S(LIST(EL),foreach_scc_data) *data = user; + + return data->follows(data->list->p[i], data->list->p[j], + data->follows_user); +} + +/* Call "fn" on the sublist of "list" that consists of the elements + * with indices specified by the "n" elements of "pos". + */ +static isl_stat FN(LIST(EL),call_on_scc)(__isl_keep LIST(EL) *list, int *pos, + int n, isl_stat (*fn)(__isl_take LIST(EL) *scc, void *user), void *user) +{ + int i; + isl_ctx *ctx; + LIST(EL) *slice; + + ctx = FN(LIST(EL),get_ctx)(list); + slice = FN(LIST(EL),alloc)(ctx, n); + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(EL,copy)(list->p[pos[i]]); + slice = FN(LIST(EL),add)(slice, el); + } + + return fn(slice, user); +} + +/* Call "fn" on each of the strongly connected components (SCCs) of + * the graph with as vertices the elements of "list" and + * a directed edge from node b to node a iff follows(a, b) + * returns 1. follows should return -1 on error. + * + * If SCC a contains a node i that follows a node j in another SCC b + * (i.e., follows(i, j, user) returns 1), then fn will be called on SCC a + * after being called on SCC b. + * + * We simply call isl_tarjan_graph_init, extract the SCCs from the result and + * call fn on each of them. + */ +isl_stat FN(LIST(EL),foreach_scc)(__isl_keep LIST(EL) *list, + isl_bool (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user), + void *follows_user, + isl_stat (*fn)(__isl_take LIST(EL) *scc, void *user), void *fn_user) +{ + S(LIST(EL),foreach_scc_data) data = { list, follows, follows_user }; + int i, n; + isl_ctx *ctx; + struct isl_tarjan_graph *g; + + if (!list) + return isl_stat_error; + if (list->n == 0) + return isl_stat_ok; + if (list->n == 1) + return fn(FN(LIST(EL),copy)(list), fn_user); + + ctx = FN(LIST(EL),get_ctx)(list); + n = list->n; + g = isl_tarjan_graph_init(ctx, n, &FN(LIST(EL),follows), &data); + if (!g) + return isl_stat_error; + + i = 0; + do { + int first; + + if (g->order[i] == -1) + isl_die(ctx, isl_error_internal, "cannot happen", + break); + first = i; + while (g->order[i] != -1) { + ++i; --n; + } + if (first == 0 && n == 0) { + isl_tarjan_graph_free(g); + return fn(FN(LIST(EL),copy)(list), fn_user); + } + if (FN(LIST(EL),call_on_scc)(list, g->order + first, i - first, + fn, fn_user) < 0) + break; + ++i; + } while (n); + + isl_tarjan_graph_free(g); + + return n > 0 ? isl_stat_error : isl_stat_ok; +} + +__isl_give LIST(EL) *FN(FN(LIST(EL),from),BASE)(__isl_take EL *el) +{ + isl_ctx *ctx; + LIST(EL) *list; + + if (!el) + return NULL; + ctx = FN(EL,get_ctx)(el); + list = FN(LIST(EL),alloc)(ctx, 1); + if (!list) + goto error; + list = FN(LIST(EL),add)(list, el); + return list; +error: + FN(EL,free)(el); + return NULL; +} + +/* Append the elements of "list2" to "list1", where "list1" is known + * to have only a single reference and enough room to hold + * the extra elements. + */ +static __isl_give LIST(EL) *FN(LIST(EL),concat_inplace)( + __isl_take LIST(EL) *list1, __isl_take LIST(EL) *list2) +{ + int i; + + for (i = 0; i < list2->n; ++i) + list1 = FN(LIST(EL),add)(list1, FN(EL,copy)(list2->p[i])); + FN(LIST(EL),free)(list2); + return list1; +} + +/* Concatenate "list1" and "list2". + * If "list1" has only one reference and has enough room + * for the elements of "list2", the add the elements to "list1" itself. + * Otherwise, create a new list to store the result. + */ +__isl_give LIST(EL) *FN(LIST(EL),concat)(__isl_take LIST(EL) *list1, + __isl_take LIST(EL) *list2) +{ + int i; + isl_ctx *ctx; + LIST(EL) *res; + + if (!list1 || !list2) + goto error; + + if (list1->ref == 1 && list1->n + list2->n <= list1->size) + return FN(LIST(EL),concat_inplace)(list1, list2); + + ctx = FN(LIST(EL),get_ctx)(list1); + res = FN(LIST(EL),alloc)(ctx, list1->n + list2->n); + for (i = 0; i < list1->n; ++i) + res = FN(LIST(EL),add)(res, FN(EL,copy)(list1->p[i])); + for (i = 0; i < list2->n; ++i) + res = FN(LIST(EL),add)(res, FN(EL,copy)(list2->p[i])); + + FN(LIST(EL),free)(list1); + FN(LIST(EL),free)(list2); + return res; +error: + FN(LIST(EL),free)(list1); + FN(LIST(EL),free)(list2); + return NULL; +} + +__isl_give isl_printer *CAT(isl_printer_print_,LIST(BASE))( + __isl_take isl_printer *p, __isl_keep LIST(EL) *list) +{ + int i; + + if (!p || !list) + goto error; + p = isl_printer_print_str(p, "("); + for (i = 0; i < list->n; ++i) { + if (i) + p = isl_printer_print_str(p, ","); + p = CAT(isl_printer_print_,BASE)(p, list->p[i]); + } + p = isl_printer_print_str(p, ")"); + return p; +error: + isl_printer_free(p); + return NULL; +} + +void FN(LIST(EL),dump)(__isl_keep LIST(EL) *list) +{ + isl_printer *printer; + + if (!list) + return; + + printer = isl_printer_to_file(FN(LIST(EL),get_ctx)(list), stderr); + printer = CAT(isl_printer_print_,LIST(BASE))(printer, list); + printer = isl_printer_end_line(printer); + + isl_printer_free(printer); +} Index: contrib/isl/isl_local.h =================================================================== --- /dev/null +++ contrib/isl/isl_local.h @@ -0,0 +1,10 @@ +#ifndef ISL_LOCAL_H +#define ISL_LOCAL_H + +#include + +isl_bool isl_local_div_is_marked_unknown(__isl_keep isl_mat *div, int pos); +isl_bool isl_local_div_is_known(__isl_keep isl_mat *div, int pos); +int isl_local_cmp(__isl_keep isl_mat *div1, __isl_keep isl_mat *div2); + +#endif Index: contrib/isl/isl_local.c =================================================================== --- /dev/null +++ contrib/isl/isl_local.c @@ -0,0 +1,117 @@ +/* + * Copyright 2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include + +/* Given a matrix "div" representing local variables, + * is the variable at position "pos" marked as not having + * an explicit representation? + * Note that even if this variable is not marked in this way and therefore + * does have an explicit representation, this representation may still + * depend (indirectly) on other local variables that do not + * have an explicit representation. + */ +isl_bool isl_local_div_is_marked_unknown(__isl_keep isl_mat *div, int pos) +{ + if (!div) + return isl_bool_error; + if (pos < 0 || pos >= div->n_row) + isl_die(isl_mat_get_ctx(div), isl_error_invalid, + "position out of bounds", return isl_bool_error); + return isl_int_is_zero(div->row[pos][0]); +} + +/* Given a matrix "div" representing local variables, + * does the variable at position "pos" have a complete explicit representation? + * Having a complete explicit representation requires not only + * an explicit representation, but also that all local variables + * that appear in this explicit representation in turn have + * a complete explicit representation. + */ +isl_bool isl_local_div_is_known(__isl_keep isl_mat *div, int pos) +{ + isl_bool marked; + int i, n, off; + + if (!div) + return isl_bool_error; + if (pos < 0 || pos >= div->n_row) + isl_die(isl_mat_get_ctx(div), isl_error_invalid, + "position out of bounds", return isl_bool_error); + + marked = isl_local_div_is_marked_unknown(div, pos); + if (marked < 0 || marked) + return isl_bool_not(marked); + + n = isl_mat_rows(div); + off = isl_mat_cols(div) - n; + + for (i = n - 1; i >= 0; --i) { + isl_bool known; + + if (isl_int_is_zero(div->row[pos][off + i])) + continue; + known = isl_local_div_is_known(div, i); + if (known < 0 || !known) + return known; + } + + return isl_bool_true; +} + +/* Compare two matrices representing local variables, defined over + * the same space. + * + * Return -1 if "div1" is "smaller" than "div2", 1 if "div1" is "greater" + * than "div2" and 0 if they are equal. + * + * The order is fairly arbitrary. We do "prefer" divs that only involve + * earlier dimensions in the sense that we consider matrices where + * the first differing div involves earlier dimensions to be smaller. + */ +int isl_local_cmp(__isl_keep isl_mat *div1, __isl_keep isl_mat *div2) +{ + int i; + int cmp; + isl_bool unknown1, unknown2; + int last1, last2; + int n_col; + + if (div1 == div2) + return 0; + if (!div1) + return -1; + if (!div2) + return 1; + + if (div1->n_row != div2->n_row) + return div1->n_row - div2->n_row; + + n_col = isl_mat_cols(div1); + for (i = 0; i < div1->n_row; ++i) { + unknown1 = isl_local_div_is_marked_unknown(div1, i); + unknown2 = isl_local_div_is_marked_unknown(div2, i); + if (unknown1 && unknown2) + continue; + if (unknown1) + return 1; + if (unknown2) + return -1; + last1 = isl_seq_last_non_zero(div1->row[i] + 1, n_col - 1); + last2 = isl_seq_last_non_zero(div2->row[i] + 1, n_col - 1); + if (last1 != last2) + return last1 - last2; + cmp = isl_seq_cmp(div1->row[i], div2->row[i], n_col); + if (cmp != 0) + return cmp; + } + + return 0; +} Index: contrib/isl/isl_local_space.c =================================================================== --- /dev/null +++ contrib/isl/isl_local_space.c @@ -0,0 +1,1451 @@ +/* + * Copyright 2011 INRIA Saclay + * Copyright 2012-2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls) +{ + return ls ? ls->dim->ctx : NULL; +} + +/* Return a hash value that digests "ls". + */ +uint32_t isl_local_space_get_hash(__isl_keep isl_local_space *ls) +{ + uint32_t hash, space_hash, div_hash; + + if (!ls) + return 0; + + hash = isl_hash_init(); + space_hash = isl_space_get_hash(ls->dim); + isl_hash_hash(hash, space_hash); + div_hash = isl_mat_get_hash(ls->div); + isl_hash_hash(hash, div_hash); + + return hash; +} + +__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim, + __isl_take isl_mat *div) +{ + isl_ctx *ctx; + isl_local_space *ls = NULL; + + if (!dim || !div) + goto error; + + ctx = isl_space_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_mat_free(div); + isl_space_free(dim); + isl_local_space_free(ls); + return NULL; +} + +__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim, + unsigned n_div) +{ + isl_ctx *ctx; + isl_mat *div; + unsigned total; + + if (!dim) + return NULL; + + total = isl_space_dim(dim, isl_dim_all); + + ctx = isl_space_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_space(__isl_take isl_space *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) +{ + if (!ls) + return NULL; + + return isl_local_space_alloc_div(isl_space_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); +} + +__isl_null isl_local_space *isl_local_space_free( + __isl_take isl_local_space *ls) +{ + if (!ls) + return NULL; + + if (--ls->ref > 0) + return NULL; + + isl_space_free(ls->dim); + isl_mat_free(ls->div); + + free(ls); + + return NULL; +} + +/* Is the local space that of a parameter domain? + */ +isl_bool isl_local_space_is_params(__isl_keep isl_local_space *ls) +{ + if (!ls) + return isl_bool_error; + return isl_space_is_params(ls->dim); +} + +/* Is the local space that of a set? + */ +isl_bool isl_local_space_is_set(__isl_keep isl_local_space *ls) +{ + return ls ? isl_space_is_set(ls->dim) : isl_bool_error; +} + +/* Do "ls1" and "ls2" have the same space? + */ +isl_bool isl_local_space_has_equal_space(__isl_keep isl_local_space *ls1, + __isl_keep isl_local_space *ls2) +{ + if (!ls1 || !ls2) + return isl_bool_error; + + return isl_space_is_equal(ls1->dim, ls2->dim); +} + +/* Return true if the two local spaces are identical, with identical + * expressions for the integer divisions. + */ +isl_bool isl_local_space_is_equal(__isl_keep isl_local_space *ls1, + __isl_keep isl_local_space *ls2) +{ + isl_bool equal; + + equal = isl_local_space_has_equal_space(ls1, ls2); + if (equal < 0 || !equal) + return equal; + + if (!isl_local_space_divs_known(ls1)) + return isl_bool_false; + if (!isl_local_space_divs_known(ls2)) + return isl_bool_false; + + return isl_mat_is_equal(ls1->div, ls2->div); +} + +/* Compare two isl_local_spaces. + * + * Return -1 if "ls1" is "smaller" than "ls2", 1 if "ls1" is "greater" + * than "ls2" and 0 if they are equal. + */ +int isl_local_space_cmp(__isl_keep isl_local_space *ls1, + __isl_keep isl_local_space *ls2) +{ + int cmp; + + if (ls1 == ls2) + return 0; + if (!ls1) + return -1; + if (!ls2) + return 1; + + cmp = isl_space_cmp(ls1->dim, ls2->dim); + if (cmp != 0) + return cmp; + + return isl_local_cmp(ls1->div, ls2->div); +} + +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_space_dim(ls->dim, isl_dim_all) + ls->div->n_row; + return isl_space_dim(ls->dim, type); +} + +unsigned isl_local_space_offset(__isl_keep isl_local_space *ls, + enum isl_dim_type type) +{ + isl_space *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; + } +} + +/* Return the position of the dimension of the given type and name + * in "ls". + * Return -1 if no such dimension can be found. + */ +int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls, + enum isl_dim_type type, const char *name) +{ + if (!ls) + return -1; + if (type == isl_dim_div) + return -1; + return isl_space_find_dim_by_name(ls->dim, type, name); +} + +/* Does the given dimension have a name? + */ +isl_bool isl_local_space_has_dim_name(__isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos) +{ + return ls ? isl_space_has_dim_name(ls->dim, type, pos) : isl_bool_error; +} + +const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos) +{ + return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL; +} + +isl_bool isl_local_space_has_dim_id(__isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos) +{ + return ls ? isl_space_has_dim_id(ls->dim, type, pos) : isl_bool_error; +} + +__isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls, + enum isl_dim_type type, unsigned pos) +{ + return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL; +} + +/* Return the argument of the integer division at position "pos" in "ls". + * All local variables in "ls" are known to have a (complete) explicit + * representation. + */ +static __isl_give isl_aff *extract_div(__isl_keep isl_local_space *ls, int pos) +{ + isl_aff *aff; + + aff = isl_aff_alloc(isl_local_space_copy(ls)); + if (!aff) + return NULL; + isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size); + return aff; +} + +/* Return the argument of the integer division at position "pos" in "ls". + * The integer division at that position is known to have a complete + * explicit representation, but some of the others do not. + * Remove them first because the domain of an isl_aff + * is not allowed to have unknown local variables. + */ +static __isl_give isl_aff *drop_unknown_divs_and_extract_div( + __isl_keep isl_local_space *ls, int pos) +{ + int i, n; + isl_bool unknown; + isl_aff *aff; + + ls = isl_local_space_copy(ls); + n = isl_local_space_dim(ls, isl_dim_div); + for (i = n - 1; i >= 0; --i) { + unknown = isl_local_space_div_is_marked_unknown(ls, i); + if (unknown < 0) + ls = isl_local_space_free(ls); + else if (!unknown) + continue; + ls = isl_local_space_drop_dims(ls, isl_dim_div, i, 1); + if (pos > i) + --pos; + } + aff = extract_div(ls, pos); + isl_local_space_free(ls); + return aff; +} + +/* Return the argument of the integer division at position "pos" in "ls". + * The integer division is assumed to have a complete explicit + * representation. If some of the other integer divisions + * do not have an explicit representation, then they need + * to be removed first because the domain of an isl_aff + * is not allowed to have unknown local variables. + */ +__isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls, + int pos) +{ + isl_bool known; + + 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); + + known = isl_local_space_div_is_known(ls, pos); + if (known < 0) + return NULL; + if (!known) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "expression of div unknown", return NULL); + if (!isl_local_space_is_set(ls)) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "cannot represent divs of map spaces", return NULL); + + known = isl_local_space_divs_known(ls); + if (known < 0) + return NULL; + if (known) + return extract_div(ls, pos); + else + return drop_unknown_divs_and_extract_div(ls, pos); +} + +__isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls) +{ + if (!ls) + return NULL; + + return isl_space_copy(ls->dim); +} + +/* Replace the identifier of the tuple of type "type" by "id". + */ +__isl_give isl_local_space *isl_local_space_set_tuple_id( + __isl_take isl_local_space *ls, + enum isl_dim_type type, __isl_take isl_id *id) +{ + ls = isl_local_space_cow(ls); + if (!ls) + goto error; + ls->dim = isl_space_set_tuple_id(ls->dim, type, id); + if (!ls->dim) + return isl_local_space_free(ls); + return ls; +error: + isl_id_free(id); + return NULL; +} + +__isl_give isl_local_space *isl_local_space_set_dim_name( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, const char *s) +{ + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s); + if (!ls->dim) + return isl_local_space_free(ls); + + return ls; +} + +__isl_give isl_local_space *isl_local_space_set_dim_id( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) +{ + ls = isl_local_space_cow(ls); + if (!ls) + goto error; + ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id); + if (!ls->dim) + return isl_local_space_free(ls); + + return ls; +error: + isl_id_free(id); + return NULL; +} + +__isl_give isl_local_space *isl_local_space_reset_space( + __isl_take isl_local_space *ls, __isl_take isl_space *dim) +{ + ls = isl_local_space_cow(ls); + if (!ls || !dim) + goto error; + + isl_space_free(ls->dim); + ls->dim = dim; + + return ls; +error: + isl_local_space_free(ls); + isl_space_free(dim); + return NULL; +} + +/* Reorder the columns of the given div definitions according to the + * given reordering. + * The order of the divs themselves is assumed not to change. + */ +static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div, + __isl_take isl_reordering *r) +{ + int i, j; + isl_mat *mat; + int extra; + + if (!div || !r) + goto error; + + extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len; + mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra); + if (!mat) + goto error; + + for (i = 0; i < div->n_row; ++i) { + isl_seq_cpy(mat->row[i], div->row[i], 2); + isl_seq_clr(mat->row[i] + 2, mat->n_col - 2); + for (j = 0; j < r->len; ++j) + isl_int_set(mat->row[i][2 + r->pos[j]], + div->row[i][2 + j]); + } + + isl_reordering_free(r); + isl_mat_free(div); + return mat; +error: + isl_reordering_free(r); + isl_mat_free(div); + return NULL; +} + +/* Reorder the dimensions of "ls" according to the given reordering. + * The reordering r is assumed to have been extended with the local + * variables, leaving them in the same order. + */ +__isl_give isl_local_space *isl_local_space_realign( + __isl_take isl_local_space *ls, __isl_take isl_reordering *r) +{ + ls = isl_local_space_cow(ls); + if (!ls || !r) + goto error; + + ls->div = reorder_divs(ls->div, isl_reordering_copy(r)); + if (!ls->div) + goto error; + + ls = isl_local_space_reset_space(ls, isl_space_copy(r->dim)); + + isl_reordering_free(r); + return ls; +error: + isl_local_space_free(ls); + isl_reordering_free(r); + return NULL; +} + +__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. + * In particular, if both divs are unknown, we respect their + * current order. Otherwise, we sort the known div after the unknown + * div only if the known div depends on the unknown div. + */ +static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j, + unsigned n_row, unsigned n_col) +{ + int li, lj; + int unknown_i, unknown_j; + + unknown_i = isl_int_is_zero(row_i[0]); + unknown_j = isl_int_is_zero(row_j[0]); + + if (unknown_i && unknown_j) + return i - j; + + if (unknown_i) + li = n_col - n_row + i; + else + li = isl_seq_last_non_zero(row_i, n_col); + if (unknown_j) + lj = n_col - n_row + j; + else + lj = isl_seq_last_non_zero(row_j, n_col); + + if (li != lj) + return li - lj; + + return isl_seq_cmp(row_i, row_j, n_col); +} + +/* Call cmp_row for divs in a matrix. + */ +int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j) +{ + return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col); +} + +/* Call cmp_row for divs in a basic map. + */ +static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j, + unsigned total) +{ + return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total); +} + +/* Sort the divs in "bmap". + * + * We first make sure divs are placed after divs on which they depend. + * Then we perform a simple insertion sort based on the same ordering + * that is used in isl_merge_divs. + */ +__isl_give isl_basic_map *isl_basic_map_sort_divs( + __isl_take isl_basic_map *bmap) +{ + int i, j; + unsigned total; + + bmap = isl_basic_map_order_divs(bmap); + if (!bmap) + return NULL; + if (bmap->n_div <= 1) + return bmap; + + total = 2 + isl_basic_map_total_dim(bmap); + for (i = 1; i < bmap->n_div; ++i) { + for (j = i - 1; j >= 0; --j) { + if (bmap_cmp_row(bmap, j, j + 1, total) <= 0) + break; + isl_basic_map_swap_div(bmap, j, j + 1); + } + } + + return bmap; +} + +/* Sort the divs in the basic maps of "map". + */ +__isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map) +{ + return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs); +} + +/* 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; + + if (!div1 || !div2) + return NULL; + + 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 = isl_mat_cmp_div(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; +} + +/* Swap divs "a" and "b" in "ls". + */ +__isl_give isl_local_space *isl_local_space_swap_div( + __isl_take isl_local_space *ls, int a, int b) +{ + int offset; + + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "index out of bounds", return isl_local_space_free(ls)); + offset = ls->div->n_col - ls->div->n_row; + ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b); + ls->div = isl_mat_swap_rows(ls->div, a, b); + if (!ls->div) + return isl_local_space_free(ls); + return ls; +} + +/* Construct a local space that contains all the divs in either + * "ls1" or "ls2". + */ +__isl_give isl_local_space *isl_local_space_intersect( + __isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2) +{ + isl_ctx *ctx; + int *exp1 = NULL; + int *exp2 = NULL; + isl_mat *div = NULL; + isl_bool equal; + + if (!ls1 || !ls2) + goto error; + + ctx = isl_local_space_get_ctx(ls1); + if (!isl_space_is_equal(ls1->dim, ls2->dim)) + isl_die(ctx, isl_error_invalid, + "spaces should be identical", goto error); + + if (ls2->div->n_row == 0) { + isl_local_space_free(ls2); + return ls1; + } + + if (ls1->div->n_row == 0) { + isl_local_space_free(ls1); + return ls2; + } + + exp1 = isl_alloc_array(ctx, int, ls1->div->n_row); + exp2 = isl_alloc_array(ctx, int, ls2->div->n_row); + if (!exp1 || !exp2) + goto error; + + div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2); + if (!div) + goto error; + + equal = isl_mat_is_equal(ls1->div, div); + if (equal < 0) + goto error; + if (!equal) + ls1 = isl_local_space_cow(ls1); + if (!ls1) + goto error; + + free(exp1); + free(exp2); + isl_local_space_free(ls2); + isl_mat_free(ls1->div); + ls1->div = div; + + return ls1; +error: + free(exp1); + free(exp2); + isl_mat_free(div); + isl_local_space_free(ls1); + isl_local_space_free(ls2); + return NULL; +} + +/* Is the local variable "div" of "ls" marked as not having + * an explicit representation? + * Note that even if this variable is not marked in this way and therefore + * does have an explicit representation, this representation may still + * depend (indirectly) on other local variables that do not + * have an explicit representation. + */ +isl_bool isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space *ls, + int div) +{ + if (!ls) + return isl_bool_error; + return isl_local_div_is_marked_unknown(ls->div, div); +} + +/* Does "ls" have a complete explicit representation for div "div"? + */ +isl_bool isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div) +{ + if (!ls) + return isl_bool_error; + return isl_local_div_is_known(ls->div, div); +} + +/* Does "ls" have an explicit representation for all local variables? + */ +isl_bool isl_local_space_divs_known(__isl_keep isl_local_space *ls) +{ + int i; + + if (!ls) + return isl_bool_error; + + for (i = 0; i < ls->div->n_row; ++i) { + isl_bool unknown = isl_local_space_div_is_marked_unknown(ls, i); + if (unknown < 0 || unknown) + return isl_bool_not(unknown); + } + + return isl_bool_true; +} + +__isl_give isl_local_space *isl_local_space_domain( + __isl_take isl_local_space *ls) +{ + ls = isl_local_space_drop_dims(ls, isl_dim_out, + 0, isl_local_space_dim(ls, isl_dim_out)); + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + ls->dim = isl_space_domain(ls->dim); + if (!ls->dim) + return isl_local_space_free(ls); + return ls; +} + +__isl_give isl_local_space *isl_local_space_range( + __isl_take isl_local_space *ls) +{ + ls = isl_local_space_drop_dims(ls, isl_dim_in, + 0, isl_local_space_dim(ls, isl_dim_in)); + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + ls->dim = isl_space_range(ls->dim); + if (!ls->dim) + return isl_local_space_free(ls); + return ls; +} + +/* Construct a local space for a map that has the given local + * space as domain and that has a zero-dimensional range. + */ +__isl_give isl_local_space *isl_local_space_from_domain( + __isl_take isl_local_space *ls) +{ + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + ls->dim = isl_space_from_domain(ls->dim); + if (!ls->dim) + return isl_local_space_free(ls); + return ls; +} + +__isl_give isl_local_space *isl_local_space_add_dims( + __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n) +{ + int pos; + + if (!ls) + return NULL; + pos = isl_local_space_dim(ls, type); + return isl_local_space_insert_dims(ls, type, pos, n); +} + +/* Remove common factor of non-constant terms and denominator. + */ +static void normalize_div(__isl_keep isl_local_space *ls, int div) +{ + isl_ctx *ctx = ls->div->ctx; + unsigned total = ls->div->n_col - 2; + + isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd); + isl_int_gcd(ctx->normalize_gcd, + ctx->normalize_gcd, ls->div->row[div][0]); + if (isl_int_is_one(ctx->normalize_gcd)) + return; + + isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2, + ctx->normalize_gcd, total); + isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0], + ctx->normalize_gcd); + isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1], + ctx->normalize_gcd); +} + +/* Exploit the equalities in "eq" to simplify the expressions of + * the integer divisions in "ls". + * The integer divisions in "ls" are assumed to appear as regular + * dimensions in "eq". + */ +__isl_give isl_local_space *isl_local_space_substitute_equalities( + __isl_take isl_local_space *ls, __isl_take isl_basic_set *eq) +{ + int i, j, k; + unsigned total; + unsigned n_div; + + if (!ls || !eq) + goto error; + + total = isl_space_dim(eq->dim, isl_dim_all); + if (isl_local_space_dim(ls, isl_dim_all) != total) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "spaces don't match", goto error); + total++; + n_div = eq->n_div; + for (i = 0; i < eq->n_eq; ++i) { + j = isl_seq_last_non_zero(eq->eq[i], total + n_div); + if (j < 0 || j == 0 || j >= total) + continue; + + for (k = 0; k < ls->div->n_row; ++k) { + if (isl_int_is_zero(ls->div->row[k][1 + j])) + continue; + ls = isl_local_space_cow(ls); + if (!ls) + goto error; + ls->div = isl_mat_cow(ls->div); + if (!ls->div) + goto error; + isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total, + &ls->div->row[k][0]); + normalize_div(ls, k); + } + } + + isl_basic_set_free(eq); + return ls; +error: + isl_basic_set_free(eq); + isl_local_space_free(ls); + return NULL; +} + +/* Plug in the affine expressions "subs" of length "subs_len" (including + * the denominator and the constant term) into the variable at position "pos" + * of the "n" div expressions starting at "first". + * + * Let i be the dimension to replace and let "subs" be of the form + * + * f/d + * + * Any integer division starting at "first" with a non-zero coefficient for i, + * + * floor((a i + g)/m) + * + * is replaced by + * + * floor((a f + d g)/(m d)) + */ +__isl_give isl_local_space *isl_local_space_substitute_seq( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len, + int first, int n) +{ + int i; + isl_int v; + + if (n == 0) + return ls; + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + ls->div = isl_mat_cow(ls->div); + if (!ls->div) + return isl_local_space_free(ls); + + if (first + n > ls->div->n_row) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "index out of bounds", return isl_local_space_free(ls)); + + pos += isl_local_space_offset(ls, type); + + isl_int_init(v); + for (i = first; i < first + n; ++i) { + if (isl_int_is_zero(ls->div->row[i][1 + pos])) + continue; + isl_seq_substitute(ls->div->row[i], pos, subs, + ls->div->n_col, subs_len, v); + normalize_div(ls, i); + } + isl_int_clear(v); + + return ls; +} + +/* Plug in "subs" for dimension "type", "pos" in the integer divisions + * of "ls". + * + * Let i be the dimension to replace and let "subs" be of the form + * + * f/d + * + * Any integer division with a non-zero coefficient for i, + * + * floor((a i + g)/m) + * + * is replaced by + * + * floor((a f + d g)/(m d)) + */ +__isl_give isl_local_space *isl_local_space_substitute( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) +{ + ls = isl_local_space_cow(ls); + if (!ls || !subs) + return isl_local_space_free(ls); + + if (!isl_space_is_equal(ls->dim, subs->ls->dim)) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "spaces don't match", return isl_local_space_free(ls)); + if (isl_local_space_dim(subs->ls, isl_dim_div) != 0) + isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported, + "cannot handle divs yet", + return isl_local_space_free(ls)); + + return isl_local_space_substitute_seq(ls, type, pos, subs->v->el, + subs->v->size, 0, ls->div->n_row); +} + +isl_bool isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls, + enum isl_dim_type type) +{ + if (!ls) + return isl_bool_error; + return isl_space_is_named_or_nested(ls->dim, type); +} + +__isl_give isl_local_space *isl_local_space_drop_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_ctx *ctx; + + if (!ls) + return NULL; + if (n == 0 && !isl_local_space_is_named_or_nested(ls, type)) + return ls; + + ctx = isl_local_space_get_ctx(ls); + if (first + n > isl_local_space_dim(ls, type)) + isl_die(ctx, isl_error_invalid, "range out of bounds", + return isl_local_space_free(ls)); + + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + if (type == isl_dim_div) { + ls->div = isl_mat_drop_rows(ls->div, first, n); + } else { + ls->dim = isl_space_drop_dims(ls->dim, type, first, n); + if (!ls->dim) + return isl_local_space_free(ls); + } + + first += 1 + isl_local_space_offset(ls, type); + ls->div = isl_mat_drop_cols(ls->div, first, n); + if (!ls->div) + return isl_local_space_free(ls); + + return ls; +} + +__isl_give isl_local_space *isl_local_space_insert_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_ctx *ctx; + + if (!ls) + return NULL; + if (n == 0 && !isl_local_space_is_named_or_nested(ls, type)) + return ls; + + ctx = isl_local_space_get_ctx(ls); + if (first > isl_local_space_dim(ls, type)) + isl_die(ctx, isl_error_invalid, "position out of bounds", + return isl_local_space_free(ls)); + + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + if (type == isl_dim_div) { + ls->div = isl_mat_insert_zero_rows(ls->div, first, n); + } else { + ls->dim = isl_space_insert_dims(ls->dim, type, first, n); + if (!ls->dim) + return isl_local_space_free(ls); + } + + first += 1 + isl_local_space_offset(ls, type); + ls->div = isl_mat_insert_zero_cols(ls->div, first, n); + if (!ls->div) + return isl_local_space_free(ls); + + return ls; +} + +/* Check if the constraints pointed to by "constraint" is a div + * constraint corresponding to div "div" in "ls". + * + * That is, if div = floor(f/m), then check if the constraint is + * + * f - m d >= 0 + * or + * -(f-(m-1)) + m d >= 0 + */ +isl_bool isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls, + isl_int *constraint, unsigned div) +{ + unsigned pos; + + if (!ls) + return isl_bool_error; + + if (isl_int_is_zero(ls->div->row[div][0])) + return isl_bool_false; + + pos = isl_local_space_offset(ls, isl_dim_div) + div; + + if (isl_int_eq(constraint[pos], ls->div->row[div][0])) { + int neg; + isl_int_sub(ls->div->row[div][1], + ls->div->row[div][1], ls->div->row[div][0]); + isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1); + neg = isl_seq_is_neg(constraint, ls->div->row[div]+1, pos); + isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1); + isl_int_add(ls->div->row[div][1], + ls->div->row[div][1], ls->div->row[div][0]); + if (!neg) + return isl_bool_false; + if (isl_seq_first_non_zero(constraint+pos+1, + ls->div->n_row-div-1) != -1) + return isl_bool_false; + } else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) { + if (!isl_seq_eq(constraint, ls->div->row[div]+1, pos)) + return isl_bool_false; + if (isl_seq_first_non_zero(constraint+pos+1, + ls->div->n_row-div-1) != -1) + return isl_bool_false; + } else + return isl_bool_false; + + return isl_bool_true; +} + +/* + * Set active[i] to 1 if the dimension at position i is involved + * in the linear expression l. + */ +int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l) +{ + int i, j; + isl_ctx *ctx; + int *active = NULL; + unsigned total; + unsigned offset; + + ctx = isl_local_space_get_ctx(ls); + total = isl_local_space_dim(ls, isl_dim_all); + active = isl_calloc_array(ctx, int, total); + if (total && !active) + return NULL; + + for (i = 0; i < total; ++i) + active[i] = !isl_int_is_zero(l[i]); + + offset = isl_local_space_offset(ls, isl_dim_div) - 1; + for (i = ls->div->n_row - 1; i >= 0; --i) { + if (!active[offset + i]) + continue; + for (j = 0; j < total; ++j) + active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]); + } + + return active; +} + +/* Given a local space "ls" of a set, create a local space + * for the lift of the set. In particular, the result + * is of the form [dim -> local[..]], with ls->div->n_row variables in the + * range of the wrapped map. + */ +__isl_give isl_local_space *isl_local_space_lift( + __isl_take isl_local_space *ls) +{ + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + ls->dim = isl_space_lift(ls->dim, ls->div->n_row); + ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row); + if (!ls->dim || !ls->div) + return isl_local_space_free(ls); + + return ls; +} + +/* Construct a basic map that maps a set living in local space "ls" + * to the corresponding lifted local space. + */ +__isl_give isl_basic_map *isl_local_space_lifting( + __isl_take isl_local_space *ls) +{ + isl_basic_map *lifting; + isl_basic_set *bset; + + if (!ls) + return NULL; + if (!isl_local_space_is_set(ls)) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "lifting only defined on set spaces", goto error); + + bset = isl_basic_set_from_local_space(ls); + lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset)); + lifting = isl_basic_map_domain_map(lifting); + lifting = isl_basic_map_reverse(lifting); + + return lifting; +error: + isl_local_space_free(ls); + return NULL; +} + +/* Compute the preimage of "ls" under the function represented by "ma". + * In other words, plug in "ma" in "ls". The result is a local space + * that is part of the domain space of "ma". + * + * If the divs in "ls" are represented as + * + * floor((a_i(p) + b_i x + c_i(divs))/n_i) + * + * and ma is represented by + * + * x = D(p) + F(y) + G(divs') + * + * then the resulting divs are + * + * floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i) + * + * We first copy over the divs from "ma" and then + * we add the modified divs from "ls". + */ +__isl_give isl_local_space *isl_local_space_preimage_multi_aff( + __isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma) +{ + int i; + isl_space *space; + isl_local_space *res = NULL; + int n_div_ls, n_div_ma; + isl_int f, c1, c2, g; + + ma = isl_multi_aff_align_divs(ma); + if (!ls || !ma) + goto error; + if (!isl_space_is_range_internal(ls->dim, ma->space)) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "spaces don't match", goto error); + + n_div_ls = isl_local_space_dim(ls, isl_dim_div); + n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0; + + space = isl_space_domain(isl_multi_aff_get_space(ma)); + res = isl_local_space_alloc(space, n_div_ma + n_div_ls); + if (!res) + goto error; + + if (n_div_ma) { + isl_mat_free(res->div); + res->div = isl_mat_copy(ma->p[0]->ls->div); + res->div = isl_mat_add_zero_cols(res->div, n_div_ls); + res->div = isl_mat_add_rows(res->div, n_div_ls); + if (!res->div) + goto error; + } + + isl_int_init(f); + isl_int_init(c1); + isl_int_init(c2); + isl_int_init(g); + + for (i = 0; i < ls->div->n_row; ++i) { + if (isl_int_is_zero(ls->div->row[i][0])) { + isl_int_set_si(res->div->row[n_div_ma + i][0], 0); + continue; + } + isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i], + ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1); + normalize_div(res, n_div_ma + i); + } + + isl_int_clear(f); + isl_int_clear(c1); + isl_int_clear(c2); + isl_int_clear(g); + + isl_local_space_free(ls); + isl_multi_aff_free(ma); + return res; +error: + isl_local_space_free(ls); + isl_multi_aff_free(ma); + isl_local_space_free(res); + return NULL; +} + +/* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls" + * to dimensions of "dst_type" at "dst_pos". + * + * Moving to/from local dimensions is not allowed. + * We currently assume that the dimension type changes. + */ +__isl_give isl_local_space *isl_local_space_move_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + unsigned g_dst_pos; + unsigned g_src_pos; + + if (!ls) + return NULL; + if (n == 0 && + !isl_local_space_is_named_or_nested(ls, src_type) && + !isl_local_space_is_named_or_nested(ls, dst_type)) + return ls; + + if (src_pos + n > isl_local_space_dim(ls, src_type)) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "range out of bounds", return isl_local_space_free(ls)); + if (dst_pos > isl_local_space_dim(ls, dst_type)) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "position out of bounds", + return isl_local_space_free(ls)); + if (src_type == isl_dim_div) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "cannot move divs", return isl_local_space_free(ls)); + if (dst_type == isl_dim_div) + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "cannot move to divs", return isl_local_space_free(ls)); + if (dst_type == src_type && dst_pos == src_pos) + return ls; + if (dst_type == src_type) + isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported, + "moving dims within the same type not supported", + return isl_local_space_free(ls)); + + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos; + g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos; + if (dst_type > src_type) + g_dst_pos -= n; + ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n); + if (!ls->div) + return isl_local_space_free(ls); + ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos, + src_type, src_pos, n); + if (!ls->dim) + return isl_local_space_free(ls); + + return ls; +} + +/* Remove any internal structure of the domain of "ls". + * If there is any such internal structure in the input, + * then the name of the corresponding space is also removed. + */ +__isl_give isl_local_space *isl_local_space_flatten_domain( + __isl_take isl_local_space *ls) +{ + if (!ls) + return NULL; + + if (!ls->dim->nested[0]) + return ls; + + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + ls->dim = isl_space_flatten_domain(ls->dim); + if (!ls->dim) + return isl_local_space_free(ls); + + return ls; +} + +/* Remove any internal structure of the range of "ls". + * If there is any such internal structure in the input, + * then the name of the corresponding space is also removed. + */ +__isl_give isl_local_space *isl_local_space_flatten_range( + __isl_take isl_local_space *ls) +{ + if (!ls) + return NULL; + + if (!ls->dim->nested[1]) + return ls; + + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + ls->dim = isl_space_flatten_range(ls->dim); + if (!ls->dim) + return isl_local_space_free(ls); + + return ls; +} + +/* Given the local space "ls" of a map, return the local space of a set + * that lives in a space that wraps the space of "ls" and that has + * the same divs. + */ +__isl_give isl_local_space *isl_local_space_wrap(__isl_take isl_local_space *ls) +{ + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + ls->dim = isl_space_wrap(ls->dim); + if (!ls->dim) + return isl_local_space_free(ls); + + return ls; +} Index: contrib/isl/isl_local_space_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_local_space_private.h @@ -0,0 +1,82 @@ +#ifndef ISL_LOCAL_SPACE_PRIVATE_H +#define ISL_LOCAL_SPACE_PRIVATE_H + +#include +#include +#include + +struct isl_local_space { + int ref; + + isl_space *dim; + isl_mat *div; +}; + +uint32_t isl_local_space_get_hash(__isl_keep isl_local_space *ls); + +__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim, + unsigned n_div); +__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim, + __isl_take isl_mat *div); + +__isl_give isl_local_space *isl_local_space_swap_div( + __isl_take isl_local_space *ls, int a, int b); +__isl_give isl_local_space *isl_local_space_add_div( + __isl_take isl_local_space *ls, __isl_take isl_vec *div); + +int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j); +__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); +isl_bool isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space *ls, + int div); +isl_bool isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div); +isl_bool isl_local_space_divs_known(__isl_keep isl_local_space *ls); + +__isl_give isl_local_space *isl_local_space_substitute_equalities( + __isl_take isl_local_space *ls, __isl_take isl_basic_set *eq); + +isl_bool isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls, + enum isl_dim_type type); + +isl_bool isl_local_space_has_equal_space(__isl_keep isl_local_space *ls1, + __isl_keep isl_local_space *ls2); + +__isl_give isl_local_space *isl_local_space_reset_space( + __isl_take isl_local_space *ls, __isl_take isl_space *dim); +__isl_give isl_local_space *isl_local_space_realign( + __isl_take isl_local_space *ls, __isl_take isl_reordering *r); + +isl_bool isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls, + isl_int *constraint, unsigned div); + +int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l); + +__isl_give isl_local_space *isl_local_space_substitute_seq( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len, + int first, int n); +__isl_give isl_local_space *isl_local_space_substitute( + __isl_take isl_local_space *ls, + enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs); + +__isl_give isl_local_space *isl_local_space_lift( + __isl_take isl_local_space *ls); + +__isl_give isl_local_space *isl_local_space_preimage_multi_aff( + __isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma); + +__isl_give isl_local_space *isl_local_space_move_dims( + __isl_take isl_local_space *ls, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n); + +int isl_local_space_cmp(__isl_keep isl_local_space *ls1, + __isl_keep isl_local_space *ls2); + +#endif Index: contrib/isl/isl_lp.c =================================================================== --- /dev/null +++ contrib/isl/isl_lp.c @@ -0,0 +1,366 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include +#include "isl_tab.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +enum isl_lp_result isl_tab_solve_lp(__isl_keep isl_basic_map *bmap, + int maximize, isl_int *f, isl_int denom, isl_int *opt, + isl_int *opt_denom, __isl_give isl_vec **sol) +{ + struct isl_tab *tab; + enum isl_lp_result res; + unsigned dim = isl_basic_map_total_dim(bmap); + + if (maximize) + isl_seq_neg(f, f, 1 + dim); + + bmap = isl_basic_map_gauss(bmap, NULL); + tab = isl_tab_from_basic_map(bmap, 0); + res = isl_tab_min(tab, f, denom, opt, opt_denom, 0); + if (res == isl_lp_ok && sol) { + *sol = isl_tab_get_sample_value(tab); + if (!*sol) + res = isl_lp_error; + } + isl_tab_free(tab); + + if (maximize) + isl_seq_neg(f, f, 1 + dim); + if (maximize && opt) + isl_int_neg(*opt, *opt); + + return res; +} + +/* Given a basic map "bmap" and an affine combination of the variables "f" + * with denominator "denom", set *opt / *opt_denom to the minimal + * (or maximal if "maximize" is true) value attained by f/d over "bmap", + * assuming the basic map is not empty and the expression cannot attain + * arbitrarily small (or large) values. + * If opt_denom is NULL, then *opt is rounded up (or down) + * to the nearest integer. + * The return value reflects the nature of the result (empty, unbounded, + * minimal or maximal value returned in *opt). + */ +enum isl_lp_result isl_basic_map_solve_lp(__isl_keep isl_basic_map *bmap, + int max, isl_int *f, isl_int d, isl_int *opt, isl_int *opt_denom, + __isl_give isl_vec **sol) +{ + if (sol) + *sol = NULL; + + if (!bmap) + return isl_lp_error; + + return isl_tab_solve_lp(bmap, max, f, d, opt, opt_denom, sol); +} + +enum isl_lp_result isl_basic_set_solve_lp(struct isl_basic_set *bset, int max, + isl_int *f, isl_int d, isl_int *opt, + isl_int *opt_denom, + struct isl_vec **sol) +{ + return isl_basic_map_solve_lp(bset_to_bmap(bset), max, + f, d, opt, opt_denom, sol); +} + +enum isl_lp_result isl_map_solve_lp(__isl_keep isl_map *map, int max, + isl_int *f, isl_int d, isl_int *opt, + isl_int *opt_denom, + struct isl_vec **sol) +{ + int i; + isl_int o; + isl_int t; + isl_int opt_i; + isl_int opt_denom_i; + enum isl_lp_result res; + int max_div; + isl_vec *v = NULL; + + if (!map) + return isl_lp_error; + if (map->n == 0) + return isl_lp_empty; + + max_div = 0; + for (i = 0; i < map->n; ++i) + if (map->p[i]->n_div > max_div) + max_div = map->p[i]->n_div; + if (max_div > 0) { + unsigned total = isl_space_dim(map->dim, isl_dim_all); + v = isl_vec_alloc(map->ctx, 1 + total + max_div); + if (!v) + return isl_lp_error; + isl_seq_cpy(v->el, f, 1 + total); + isl_seq_clr(v->el + 1 + total, max_div); + f = v->el; + } + + if (!opt && map->n > 1 && sol) { + isl_int_init(o); + opt = &o; + } + if (map->n > 0) + isl_int_init(opt_i); + if (map->n > 0 && opt_denom) { + isl_int_init(opt_denom_i); + isl_int_init(t); + } + + res = isl_basic_map_solve_lp(map->p[0], max, f, d, + opt, opt_denom, sol); + if (res == isl_lp_error || res == isl_lp_unbounded) + goto done; + + if (sol) + *sol = NULL; + + for (i = 1; i < map->n; ++i) { + isl_vec *sol_i = NULL; + enum isl_lp_result res_i; + int better; + + res_i = isl_basic_map_solve_lp(map->p[i], max, f, d, + &opt_i, + opt_denom ? &opt_denom_i : NULL, + sol ? &sol_i : NULL); + if (res_i == isl_lp_error || res_i == isl_lp_unbounded) { + res = res_i; + goto done; + } + if (res_i == isl_lp_empty) + continue; + if (res == isl_lp_empty) { + better = 1; + } else if (!opt_denom) { + if (max) + better = isl_int_gt(opt_i, *opt); + else + better = isl_int_lt(opt_i, *opt); + } else { + isl_int_mul(t, opt_i, *opt_denom); + isl_int_submul(t, *opt, opt_denom_i); + if (max) + better = isl_int_is_pos(t); + else + better = isl_int_is_neg(t); + } + if (better) { + res = res_i; + if (opt) + isl_int_set(*opt, opt_i); + if (opt_denom) + isl_int_set(*opt_denom, opt_denom_i); + if (sol) { + isl_vec_free(*sol); + *sol = sol_i; + } + } else + isl_vec_free(sol_i); + } + +done: + isl_vec_free(v); + if (map->n > 0 && opt_denom) { + isl_int_clear(opt_denom_i); + isl_int_clear(t); + } + if (map->n > 0) + isl_int_clear(opt_i); + if (opt == &o) + isl_int_clear(o); + return res; +} + +enum isl_lp_result isl_set_solve_lp(__isl_keep isl_set *set, int max, + isl_int *f, isl_int d, isl_int *opt, + isl_int *opt_denom, + struct isl_vec **sol) +{ + return isl_map_solve_lp(set_to_map(set), max, + f, d, opt, opt_denom, sol); +} + +/* Return the optimal (rational) value of "obj" over "bset", assuming + * that "obj" and "bset" have aligned parameters and divs. + * If "max" is set, then the maximal value is computed. + * Otherwise, the minimal value is computed. + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if "bset" is empty. + * + * Call isl_basic_set_solve_lp and translate the results. + */ +static __isl_give isl_val *basic_set_opt_lp( + __isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj) +{ + isl_ctx *ctx; + isl_val *res; + enum isl_lp_result lp_res; + + if (!bset || !obj) + return NULL; + + ctx = isl_aff_get_ctx(obj); + res = isl_val_alloc(ctx); + if (!res) + return NULL; + lp_res = isl_basic_set_solve_lp(bset, max, obj->v->el + 1, + obj->v->el[0], &res->n, &res->d, NULL); + if (lp_res == isl_lp_ok) + return isl_val_normalize(res); + isl_val_free(res); + if (lp_res == isl_lp_error) + return NULL; + if (lp_res == isl_lp_empty) + return isl_val_nan(ctx); + if (max) + return isl_val_infty(ctx); + else + return isl_val_neginfty(ctx); +} + +/* Return the optimal (rational) value of "obj" over "bset", assuming + * that "obj" and "bset" have aligned parameters. + * If "max" is set, then the maximal value is computed. + * Otherwise, the minimal value is computed. + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if "bset" is empty. + * + * Align the divs of "bset" and "obj" and call basic_set_opt_lp. + */ +static __isl_give isl_val *isl_basic_set_opt_lp_val_aligned( + __isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj) +{ + int *exp1 = NULL; + int *exp2 = NULL; + isl_ctx *ctx; + isl_mat *bset_div = NULL; + isl_mat *div = NULL; + isl_val *res; + int bset_n_div, obj_n_div; + + if (!bset || !obj) + return NULL; + + ctx = isl_aff_get_ctx(obj); + if (!isl_space_is_equal(bset->dim, obj->ls->dim)) + isl_die(ctx, isl_error_invalid, + "spaces don't match", return NULL); + + bset_n_div = isl_basic_set_dim(bset, isl_dim_div); + obj_n_div = isl_aff_dim(obj, isl_dim_div); + if (bset_n_div == 0 && obj_n_div == 0) + return basic_set_opt_lp(bset, max, obj); + + bset = isl_basic_set_copy(bset); + obj = isl_aff_copy(obj); + + bset_div = isl_basic_set_get_divs(bset); + exp1 = isl_alloc_array(ctx, int, bset_n_div); + exp2 = isl_alloc_array(ctx, int, obj_n_div); + if (!bset_div || (bset_n_div && !exp1) || (obj_n_div && !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_lp(bset, max, obj); + + 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 NULL; +} + +/* Return the optimal (rational) value of "obj" over "bset". + * If "max" is set, then the maximal value is computed. + * Otherwise, the minimal value is computed. + * + * Return infinity or negative infinity if the optimal value is unbounded and + * NaN if "bset" is empty. + */ +static __isl_give isl_val *isl_basic_set_opt_lp_val( + __isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj) +{ + isl_bool equal; + isl_val *res; + + if (!bset || !obj) + return NULL; + + equal = isl_basic_set_space_has_equal_params(bset, obj->ls->dim); + if (equal < 0) + return NULL; + if (equal) + return isl_basic_set_opt_lp_val_aligned(bset, max, obj); + + bset = isl_basic_set_copy(bset); + obj = isl_aff_copy(obj); + bset = isl_basic_set_align_params(bset, isl_aff_get_domain_space(obj)); + obj = isl_aff_align_params(obj, isl_basic_set_get_space(bset)); + + res = isl_basic_set_opt_lp_val_aligned(bset, max, obj); + + isl_basic_set_free(bset); + isl_aff_free(obj); + + return res; +} + +/* Return the minimal (rational) value of "obj" over "bset". + * + * Return negative infinity if the minimal value is unbounded and + * NaN if "bset" is empty. + */ +__isl_give isl_val *isl_basic_set_min_lp_val(__isl_keep isl_basic_set *bset, + __isl_keep isl_aff *obj) +{ + return isl_basic_set_opt_lp_val(bset, 0, obj); +} + +/* Return the maximal (rational) value of "obj" over "bset". + * + * Return infinity if the maximal value is unbounded and + * NaN if "bset" is empty. + */ +__isl_give isl_val *isl_basic_set_max_lp_val(__isl_keep isl_basic_set *bset, + __isl_keep isl_aff *obj) +{ + return isl_basic_set_opt_lp_val(bset, 1, obj); +} Index: contrib/isl/isl_lp_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_lp_private.h @@ -0,0 +1,21 @@ +#ifndef ISL_LP_PRIVATE_H +#define ISL_LP_PRIVATE_H + +#include +#include +#include + +enum isl_lp_result isl_basic_map_solve_lp(__isl_keep isl_basic_map *bmap, + int max, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom, + __isl_give isl_vec **sol); +enum isl_lp_result isl_basic_set_solve_lp(__isl_keep isl_basic_set *bset, + int max, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom, + __isl_give isl_vec **sol); +enum isl_lp_result isl_map_solve_lp(__isl_keep isl_map *map, int max, + isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom, + __isl_give isl_vec **sol); +enum isl_lp_result isl_set_solve_lp(__isl_keep isl_set *set, int max, + isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom, + __isl_give isl_vec **sol); + +#endif Index: contrib/isl/isl_map.c =================================================================== --- /dev/null +++ contrib/isl/isl_map.c @@ -0,0 +1,13605 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2012-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * Copyright 2016 INRIA Paris + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12, + * CS 42112, 75589 Paris Cedex 12, France + */ + +#include +#include +#include +#include +#include +#include "isl_space_private.h" +#include "isl_equalities.h" +#include +#include +#include +#include +#include +#include "isl_sample.h" +#include +#include "isl_tab.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type) +{ + switch (type) { + case isl_dim_param: return dim->nparam; + case isl_dim_in: return dim->n_in; + case isl_dim_out: return dim->n_out; + case isl_dim_all: return dim->nparam + dim->n_in + dim->n_out; + default: return 0; + } +} + +static unsigned pos(__isl_keep isl_space *dim, enum isl_dim_type type) +{ + switch (type) { + 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; + default: return 0; + } +} + +unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type) +{ + if (!bmap) + return 0; + switch (type) { + case isl_dim_cst: return 1; + case isl_dim_param: + case isl_dim_in: + case isl_dim_out: return isl_space_dim(bmap->dim, type); + case isl_dim_div: return bmap->n_div; + case isl_dim_all: return isl_basic_map_total_dim(bmap); + default: return 0; + } +} + +/* Return the space of "map". + */ +__isl_keep isl_space *isl_map_peek_space(__isl_keep const isl_map *map) +{ + return map ? map->dim : NULL; +} + +unsigned isl_map_dim(__isl_keep isl_map *map, enum isl_dim_type type) +{ + return map ? n(map->dim, type) : 0; +} + +unsigned isl_set_dim(__isl_keep isl_set *set, enum isl_dim_type type) +{ + return set ? n(set->dim, type) : 0; +} + +unsigned isl_basic_map_offset(struct isl_basic_map *bmap, + enum isl_dim_type type) +{ + isl_space *space; + + if (!bmap) + return 0; + + space = bmap->dim; + switch (type) { + case isl_dim_cst: return 0; + case isl_dim_param: return 1; + case isl_dim_in: return 1 + space->nparam; + case isl_dim_out: return 1 + space->nparam + space->n_in; + case isl_dim_div: return 1 + space->nparam + space->n_in + + space->n_out; + default: return 0; + } +} + +unsigned isl_basic_set_offset(__isl_keep isl_basic_set *bset, + enum isl_dim_type type) +{ + return isl_basic_map_offset(bset, type); +} + +static unsigned map_offset(__isl_keep isl_map *map, enum isl_dim_type type) +{ + return pos(map->dim, type); +} + +unsigned isl_basic_set_dim(__isl_keep isl_basic_set *bset, + enum isl_dim_type type) +{ + return isl_basic_map_dim(bset, type); +} + +unsigned isl_basic_set_n_dim(__isl_keep isl_basic_set *bset) +{ + return isl_basic_set_dim(bset, isl_dim_set); +} + +unsigned isl_basic_set_n_param(__isl_keep isl_basic_set *bset) +{ + return isl_basic_set_dim(bset, isl_dim_param); +} + +unsigned isl_basic_set_total_dim(__isl_keep const isl_basic_set *bset) +{ + if (!bset) + return 0; + return isl_space_dim(bset->dim, isl_dim_all) + bset->n_div; +} + +unsigned isl_set_n_dim(__isl_keep isl_set *set) +{ + return isl_set_dim(set, isl_dim_set); +} + +unsigned isl_set_n_param(__isl_keep isl_set *set) +{ + return isl_set_dim(set, isl_dim_param); +} + +unsigned isl_basic_map_n_in(__isl_keep const isl_basic_map *bmap) +{ + return bmap ? bmap->dim->n_in : 0; +} + +unsigned isl_basic_map_n_out(__isl_keep const isl_basic_map *bmap) +{ + return bmap ? bmap->dim->n_out : 0; +} + +unsigned isl_basic_map_n_param(__isl_keep const isl_basic_map *bmap) +{ + return bmap ? bmap->dim->nparam : 0; +} + +unsigned isl_basic_map_n_div(__isl_keep const isl_basic_map *bmap) +{ + return bmap ? bmap->n_div : 0; +} + +unsigned isl_basic_map_total_dim(__isl_keep const isl_basic_map *bmap) +{ + return bmap ? isl_space_dim(bmap->dim, isl_dim_all) + bmap->n_div : 0; +} + +unsigned isl_map_n_in(__isl_keep const isl_map *map) +{ + return map ? map->dim->n_in : 0; +} + +unsigned isl_map_n_out(__isl_keep const isl_map *map) +{ + return map ? map->dim->n_out : 0; +} + +unsigned isl_map_n_param(__isl_keep const isl_map *map) +{ + return map ? map->dim->nparam : 0; +} + +/* Return the number of equality constraints in the description of "bmap". + * Return -1 on error. + */ +int isl_basic_map_n_equality(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return -1; + return bmap->n_eq; +} + +/* Return the number of equality constraints in the description of "bset". + * Return -1 on error. + */ +int isl_basic_set_n_equality(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_n_equality(bset_to_bmap(bset)); +} + +/* Return the number of inequality constraints in the description of "bmap". + * Return -1 on error. + */ +int isl_basic_map_n_inequality(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return -1; + return bmap->n_ineq; +} + +/* Return the number of inequality constraints in the description of "bset". + * Return -1 on error. + */ +int isl_basic_set_n_inequality(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_n_inequality(bset_to_bmap(bset)); +} + +/* Do "bmap1" and "bmap2" have the same parameters? + */ +static isl_bool isl_basic_map_has_equal_params(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2) +{ + isl_space *space1, *space2; + + space1 = isl_basic_map_peek_space(bmap1); + space2 = isl_basic_map_peek_space(bmap2); + return isl_space_has_equal_params(space1, space2); +} + +/* Do "map1" and "map2" have the same parameters? + */ +isl_bool isl_map_has_equal_params(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + isl_space *space1, *space2; + + space1 = isl_map_peek_space(map1); + space2 = isl_map_peek_space(map2); + return isl_space_has_equal_params(space1, space2); +} + +/* Do "map" and "set" have the same parameters? + */ +static isl_bool isl_map_set_has_equal_params(__isl_keep isl_map *map, + __isl_keep isl_set *set) +{ + return isl_map_has_equal_params(map, set_to_map(set)); +} + +isl_bool isl_map_compatible_domain(__isl_keep isl_map *map, + __isl_keep isl_set *set) +{ + isl_bool m; + if (!map || !set) + return isl_bool_error; + m = isl_map_has_equal_params(map, set_to_map(set)); + if (m < 0 || !m) + return m; + return isl_space_tuple_is_equal(map->dim, isl_dim_in, + set->dim, isl_dim_set); +} + +isl_bool isl_basic_map_compatible_domain(__isl_keep isl_basic_map *bmap, + __isl_keep isl_basic_set *bset) +{ + isl_bool m; + if (!bmap || !bset) + return isl_bool_error; + m = isl_basic_map_has_equal_params(bmap, bset_to_bmap(bset)); + if (m < 0 || !m) + return m; + return isl_space_tuple_is_equal(bmap->dim, isl_dim_in, + bset->dim, isl_dim_set); +} + +isl_bool isl_map_compatible_range(__isl_keep isl_map *map, + __isl_keep isl_set *set) +{ + isl_bool m; + if (!map || !set) + return isl_bool_error; + m = isl_map_has_equal_params(map, set_to_map(set)); + if (m < 0 || !m) + return m; + return isl_space_tuple_is_equal(map->dim, isl_dim_out, + set->dim, isl_dim_set); +} + +isl_bool isl_basic_map_compatible_range(__isl_keep isl_basic_map *bmap, + __isl_keep isl_basic_set *bset) +{ + isl_bool m; + if (!bmap || !bset) + return isl_bool_error; + m = isl_basic_map_has_equal_params(bmap, bset_to_bmap(bset)); + if (m < 0 || !m) + return m; + return isl_space_tuple_is_equal(bmap->dim, isl_dim_out, + bset->dim, isl_dim_set); +} + +isl_ctx *isl_basic_map_get_ctx(__isl_keep isl_basic_map *bmap) +{ + return bmap ? bmap->ctx : NULL; +} + +isl_ctx *isl_basic_set_get_ctx(__isl_keep isl_basic_set *bset) +{ + return bset ? bset->ctx : NULL; +} + +isl_ctx *isl_map_get_ctx(__isl_keep isl_map *map) +{ + return map ? map->ctx : NULL; +} + +isl_ctx *isl_set_get_ctx(__isl_keep isl_set *set) +{ + return set ? set->ctx : NULL; +} + +/* Return the space of "bmap". + */ +__isl_keep isl_space *isl_basic_map_peek_space( + __isl_keep const isl_basic_map *bmap) +{ + return bmap ? bmap->dim : NULL; +} + +/* Return the space of "bset". + */ +__isl_keep isl_space *isl_basic_set_peek_space(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_peek_space(bset_to_bmap(bset)); +} + +__isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap) +{ + return isl_space_copy(isl_basic_map_peek_space(bmap)); +} + +__isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_get_space(bset_to_bmap(bset)); +} + +/* Extract the divs in "bmap" as a matrix. + */ +__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap) +{ + int i; + isl_ctx *ctx; + isl_mat *div; + unsigned total; + unsigned cols; + + if (!bmap) + return NULL; + + ctx = isl_basic_map_get_ctx(bmap); + total = isl_space_dim(bmap->dim, isl_dim_all); + cols = 1 + 1 + total + bmap->n_div; + div = isl_mat_alloc(ctx, bmap->n_div, cols); + if (!div) + return NULL; + + for (i = 0; i < bmap->n_div; ++i) + isl_seq_cpy(div->row[i], bmap->div[i], cols); + + return div; +} + +/* Extract the divs in "bset" as a matrix. + */ +__isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_get_divs(bset); +} + +__isl_give isl_local_space *isl_basic_map_get_local_space( + __isl_keep isl_basic_map *bmap) +{ + isl_mat *div; + + if (!bmap) + return NULL; + + div = isl_basic_map_get_divs(bmap); + return isl_local_space_alloc_div(isl_space_copy(bmap->dim), div); +} + +__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); +} + +/* For each known div d = floor(f/m), add the constraints + * + * f - m d >= 0 + * -(f-(m-1)) + m d >= 0 + * + * Do not finalize the result. + */ +static __isl_give isl_basic_map *add_known_div_constraints( + __isl_take isl_basic_map *bmap) +{ + int i; + unsigned n_div; + + if (!bmap) + return NULL; + n_div = isl_basic_map_dim(bmap, isl_dim_div); + if (n_div == 0) + return bmap; + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_extend_constraints(bmap, 0, 2 * n_div); + if (!bmap) + return NULL; + for (i = 0; i < n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_basic_map_add_div_constraints(bmap, i) < 0) + return isl_basic_map_free(bmap); + } + + return bmap; +} + +__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_space(isl_local_space_get_space(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); + bmap = add_known_div_constraints(bmap); + + 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); +} + +__isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map) +{ + return isl_space_copy(isl_map_peek_space(map)); +} + +__isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set) +{ + if (!set) + return NULL; + return isl_space_copy(set->dim); +} + +__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) +{ + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + bmap->dim = isl_space_set_tuple_name(bmap->dim, type, s); + if (!bmap->dim) + goto error; + bmap = isl_basic_map_finalize(bmap); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_set_tuple_name( + __isl_take isl_basic_set *bset, const char *s) +{ + return isl_basic_map_set_tuple_name(bset, isl_dim_set, s); +} + +const char *isl_basic_map_get_tuple_name(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type) +{ + return bmap ? isl_space_get_tuple_name(bmap->dim, type) : NULL; +} + +__isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map, + enum isl_dim_type type, const char *s) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + map->dim = isl_space_set_tuple_name(map->dim, type, s); + if (!map->dim) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_set_tuple_name(map->p[i], type, s); + if (!map->p[i]) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Replace the identifier of the tuple of type "type" by "id". + */ +__isl_give isl_basic_map *isl_basic_map_set_tuple_id( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, __isl_take isl_id *id) +{ + bmap = isl_basic_map_cow(bmap); + if (!bmap) + goto error; + bmap->dim = isl_space_set_tuple_id(bmap->dim, type, id); + if (!bmap->dim) + return isl_basic_map_free(bmap); + bmap = isl_basic_map_finalize(bmap); + return bmap; +error: + isl_id_free(id); + return NULL; +} + +/* Replace the identifier of the tuple by "id". + */ +__isl_give isl_basic_set *isl_basic_set_set_tuple_id( + __isl_take isl_basic_set *bset, __isl_take isl_id *id) +{ + return isl_basic_map_set_tuple_id(bset, isl_dim_set, id); +} + +/* Does the input or output tuple have a name? + */ +isl_bool isl_map_has_tuple_name(__isl_keep isl_map *map, enum isl_dim_type type) +{ + return map ? isl_space_has_tuple_name(map->dim, type) : isl_bool_error; +} + +const char *isl_map_get_tuple_name(__isl_keep isl_map *map, + enum isl_dim_type type) +{ + return map ? isl_space_get_tuple_name(map->dim, type) : NULL; +} + +__isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set, + const char *s) +{ + return set_from_map(isl_map_set_tuple_name(set_to_map(set), + isl_dim_set, s)); +} + +__isl_give isl_map *isl_map_set_tuple_id(__isl_take isl_map *map, + enum isl_dim_type type, __isl_take isl_id *id) +{ + map = isl_map_cow(map); + if (!map) + goto error; + + map->dim = isl_space_set_tuple_id(map->dim, type, id); + + return isl_map_reset_space(map, isl_space_copy(map->dim)); +error: + isl_id_free(id); + return NULL; +} + +__isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set, + __isl_take isl_id *id) +{ + return isl_map_set_tuple_id(set, isl_dim_set, id); +} + +__isl_give isl_map *isl_map_reset_tuple_id(__isl_take isl_map *map, + enum isl_dim_type type) +{ + map = isl_map_cow(map); + if (!map) + return NULL; + + map->dim = isl_space_reset_tuple_id(map->dim, type); + + return isl_map_reset_space(map, isl_space_copy(map->dim)); +} + +__isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set) +{ + return isl_map_reset_tuple_id(set, isl_dim_set); +} + +isl_bool isl_map_has_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type) +{ + return map ? isl_space_has_tuple_id(map->dim, type) : isl_bool_error; +} + +__isl_give isl_id *isl_map_get_tuple_id(__isl_keep isl_map *map, + enum isl_dim_type type) +{ + return map ? isl_space_get_tuple_id(map->dim, type) : NULL; +} + +isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set) +{ + return isl_map_has_tuple_id(set, isl_dim_set); +} + +__isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set) +{ + return isl_map_get_tuple_id(set, isl_dim_set); +} + +/* Does the set tuple have a name? + */ +isl_bool isl_set_has_tuple_name(__isl_keep isl_set *set) +{ + if (!set) + return isl_bool_error; + return isl_space_has_tuple_name(set->dim, isl_dim_set); +} + + +const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset) +{ + return bset ? isl_space_get_tuple_name(bset->dim, isl_dim_set) : NULL; +} + +const char *isl_set_get_tuple_name(__isl_keep isl_set *set) +{ + return set ? isl_space_get_tuple_name(set->dim, isl_dim_set) : NULL; +} + +const char *isl_basic_map_get_dim_name(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos) +{ + return bmap ? isl_space_get_dim_name(bmap->dim, type, pos) : NULL; +} + +const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos) +{ + return bset ? isl_space_get_dim_name(bset->dim, type, pos) : NULL; +} + +/* Does the given dimension have a name? + */ +isl_bool isl_map_has_dim_name(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos) +{ + if (!map) + return isl_bool_error; + return isl_space_has_dim_name(map->dim, type, pos); +} + +const char *isl_map_get_dim_name(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos) +{ + return map ? isl_space_get_dim_name(map->dim, type, pos) : NULL; +} + +const char *isl_set_get_dim_name(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return set ? isl_space_get_dim_name(set->dim, type, pos) : NULL; +} + +/* Does the given dimension have a name? + */ +isl_bool isl_set_has_dim_name(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + if (!set) + return isl_bool_error; + return isl_space_has_dim_name(set->dim, type, pos); +} + +__isl_give isl_basic_map *isl_basic_map_set_dim_name( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, const char *s) +{ + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + bmap->dim = isl_space_set_dim_name(bmap->dim, type, pos, s); + if (!bmap->dim) + goto error; + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, const char *s) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + map->dim = isl_space_set_dim_name(map->dim, type, pos, s); + if (!map->dim) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_set_dim_name(map->p[i], type, pos, s); + if (!map->p[i]) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_set_dim_name( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, const char *s) +{ + return bset_from_bmap(isl_basic_map_set_dim_name(bset_to_bmap(bset), + type, pos, s)); +} + +__isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, const char *s) +{ + return set_from_map(isl_map_set_dim_name(set_to_map(set), + type, pos, s)); +} + +isl_bool isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos) +{ + if (!bmap) + return isl_bool_error; + return isl_space_has_dim_id(bmap->dim, type, pos); +} + +__isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned pos) +{ + return bset ? isl_space_get_dim_id(bset->dim, type, pos) : NULL; +} + +isl_bool isl_map_has_dim_id(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos) +{ + return map ? isl_space_has_dim_id(map->dim, type, pos) : isl_bool_error; +} + +__isl_give isl_id *isl_map_get_dim_id(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos) +{ + return map ? isl_space_get_dim_id(map->dim, type, pos) : NULL; +} + +isl_bool isl_set_has_dim_id(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return isl_map_has_dim_id(set, type, pos); +} + +__isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return isl_map_get_dim_id(set, type, pos); +} + +__isl_give isl_map *isl_map_set_dim_id(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) +{ + map = isl_map_cow(map); + if (!map) + goto error; + + map->dim = isl_space_set_dim_id(map->dim, type, pos, id); + + return isl_map_reset_space(map, isl_space_copy(map->dim)); +error: + isl_id_free(id); + return NULL; +} + +__isl_give isl_set *isl_set_set_dim_id(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) +{ + return isl_map_set_dim_id(set, type, pos, id); +} + +int isl_map_find_dim_by_id(__isl_keep isl_map *map, enum isl_dim_type type, + __isl_keep isl_id *id) +{ + if (!map) + return -1; + return isl_space_find_dim_by_id(map->dim, type, id); +} + +int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type, + __isl_keep isl_id *id) +{ + return isl_map_find_dim_by_id(set, type, id); +} + +/* Return the position of the dimension of the given type and name + * in "bmap". + * Return -1 if no such dimension can be found. + */ +int isl_basic_map_find_dim_by_name(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, const char *name) +{ + if (!bmap) + return -1; + return isl_space_find_dim_by_name(bmap->dim, type, name); +} + +int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type, + const char *name) +{ + if (!map) + return -1; + return isl_space_find_dim_by_name(map->dim, type, name); +} + +int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type, + const char *name) +{ + return isl_map_find_dim_by_name(set, type, name); +} + +/* Check whether equality i of bset is a pure stride constraint + * on a single dimension, i.e., of the form + * + * v = k e + * + * with k a constant and e an existentially quantified variable. + */ +isl_bool isl_basic_set_eq_is_stride(__isl_keep isl_basic_set *bset, int i) +{ + unsigned nparam; + unsigned d; + unsigned n_div; + int pos1; + int pos2; + + if (!bset) + return isl_bool_error; + + if (!isl_int_is_zero(bset->eq[i][0])) + return isl_bool_false; + + nparam = isl_basic_set_dim(bset, isl_dim_param); + d = isl_basic_set_dim(bset, isl_dim_set); + n_div = isl_basic_set_dim(bset, isl_dim_div); + + if (isl_seq_first_non_zero(bset->eq[i] + 1, nparam) != -1) + return isl_bool_false; + pos1 = isl_seq_first_non_zero(bset->eq[i] + 1 + nparam, d); + if (pos1 == -1) + return isl_bool_false; + if (isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + pos1 + 1, + d - pos1 - 1) != -1) + return isl_bool_false; + + pos2 = isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + d, n_div); + if (pos2 == -1) + return isl_bool_false; + if (isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + d + pos2 + 1, + n_div - pos2 - 1) != -1) + return isl_bool_false; + if (!isl_int_is_one(bset->eq[i][1 + nparam + pos1]) && + !isl_int_is_negone(bset->eq[i][1 + nparam + pos1])) + return isl_bool_false; + + return isl_bool_true; +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the space of "map". + */ +__isl_give isl_map *isl_map_reset_user(__isl_take isl_map *map) +{ + isl_space *space; + + space = isl_map_get_space(map); + space = isl_space_reset_user(space); + map = isl_map_reset_space(map, space); + + return map; +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the space of "set". + */ +__isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set) +{ + return isl_map_reset_user(set); +} + +isl_bool isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + return ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); +} + +/* Has "map" been marked as a rational map? + * In particular, have all basic maps in "map" been marked this way? + * An empty map is not considered to be rational. + * Maps where only some of the basic maps are marked rational + * are not allowed. + */ +isl_bool isl_map_is_rational(__isl_keep isl_map *map) +{ + int i; + isl_bool rational; + + if (!map) + return isl_bool_error; + if (map->n == 0) + return isl_bool_false; + rational = isl_basic_map_is_rational(map->p[0]); + if (rational < 0) + return rational; + for (i = 1; i < map->n; ++i) { + isl_bool rational_i; + + rational_i = isl_basic_map_is_rational(map->p[i]); + if (rational_i < 0) + return rational_i; + if (rational != rational_i) + isl_die(isl_map_get_ctx(map), isl_error_unsupported, + "mixed rational and integer basic maps " + "not supported", return isl_bool_error); + } + + return rational; +} + +/* Has "set" been marked as a rational set? + * In particular, have all basic set in "set" been marked this way? + * An empty set is not considered to be rational. + * Sets where only some of the basic sets are marked rational + * are not allowed. + */ +isl_bool isl_set_is_rational(__isl_keep isl_set *set) +{ + return isl_map_is_rational(set); +} + +int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_is_rational(bset); +} + +/* Does "bmap" contain any rational points? + * + * If "bmap" has an equality for each dimension, equating the dimension + * to an integer constant, then it has no rational points, even if it + * is marked as rational. + */ +isl_bool isl_basic_map_has_rational(__isl_keep isl_basic_map *bmap) +{ + isl_bool has_rational = isl_bool_true; + unsigned total; + + if (!bmap) + return isl_bool_error; + if (isl_basic_map_plain_is_empty(bmap)) + return isl_bool_false; + if (!isl_basic_map_is_rational(bmap)) + return isl_bool_false; + bmap = isl_basic_map_copy(bmap); + bmap = isl_basic_map_implicit_equalities(bmap); + if (!bmap) + return isl_bool_error; + total = isl_basic_map_total_dim(bmap); + if (bmap->n_eq == total) { + int i, j; + for (i = 0; i < bmap->n_eq; ++i) { + j = isl_seq_first_non_zero(bmap->eq[i] + 1, total); + if (j < 0) + break; + if (!isl_int_is_one(bmap->eq[i][1 + j]) && + !isl_int_is_negone(bmap->eq[i][1 + j])) + break; + j = isl_seq_first_non_zero(bmap->eq[i] + 1 + j + 1, + total - j - 1); + if (j >= 0) + break; + } + if (i == bmap->n_eq) + has_rational = isl_bool_false; + } + isl_basic_map_free(bmap); + + return has_rational; +} + +/* Does "map" contain any rational points? + */ +isl_bool isl_map_has_rational(__isl_keep isl_map *map) +{ + int i; + isl_bool has_rational; + + if (!map) + return isl_bool_error; + for (i = 0; i < map->n; ++i) { + has_rational = isl_basic_map_has_rational(map->p[i]); + if (has_rational < 0 || has_rational) + return has_rational; + } + return isl_bool_false; +} + +/* Does "set" contain any rational points? + */ +isl_bool isl_set_has_rational(__isl_keep isl_set *set) +{ + return isl_map_has_rational(set); +} + +/* Is this basic set a parameter domain? + */ +isl_bool isl_basic_set_is_params(__isl_keep isl_basic_set *bset) +{ + if (!bset) + return isl_bool_error; + return isl_space_is_params(bset->dim); +} + +/* Is this set a parameter domain? + */ +isl_bool isl_set_is_params(__isl_keep isl_set *set) +{ + if (!set) + return isl_bool_error; + return isl_space_is_params(set->dim); +} + +/* Is this map actually a parameter domain? + * Users should never call this function. Outside of isl, + * a map can never be a parameter domain. + */ +isl_bool isl_map_is_params(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + return isl_space_is_params(map->dim); +} + +static struct isl_basic_map *basic_map_init(struct isl_ctx *ctx, + struct isl_basic_map *bmap, unsigned extra, + unsigned n_eq, unsigned n_ineq) +{ + int i; + size_t row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + extra; + + bmap->ctx = ctx; + isl_ctx_ref(ctx); + + bmap->block = isl_blk_alloc(ctx, (n_ineq + n_eq) * row_size); + if (isl_blk_is_error(bmap->block)) + goto error; + + bmap->ineq = isl_alloc_array(ctx, isl_int *, n_ineq + n_eq); + if ((n_ineq + n_eq) && !bmap->ineq) + goto error; + + if (extra == 0) { + bmap->block2 = isl_blk_empty(); + bmap->div = NULL; + } else { + bmap->block2 = isl_blk_alloc(ctx, extra * (1 + row_size)); + if (isl_blk_is_error(bmap->block2)) + goto error; + + bmap->div = isl_alloc_array(ctx, isl_int *, extra); + if (!bmap->div) + goto error; + } + + for (i = 0; i < n_ineq + n_eq; ++i) + bmap->ineq[i] = bmap->block.data + i * row_size; + + for (i = 0; i < extra; ++i) + bmap->div[i] = bmap->block2.data + i * (1 + row_size); + + bmap->ref = 1; + bmap->flags = 0; + bmap->c_size = n_eq + n_ineq; + bmap->eq = bmap->ineq + n_ineq; + bmap->extra = extra; + bmap->n_eq = 0; + bmap->n_ineq = 0; + bmap->n_div = 0; + bmap->sample = NULL; + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +struct isl_basic_set *isl_basic_set_alloc(struct isl_ctx *ctx, + unsigned nparam, unsigned dim, unsigned extra, + unsigned n_eq, unsigned n_ineq) +{ + struct isl_basic_map *bmap; + isl_space *space; + + space = isl_space_set_alloc(ctx, nparam, dim); + if (!space) + return NULL; + + bmap = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq); + return bset_from_bmap(bmap); +} + +__isl_give isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim, + unsigned extra, unsigned n_eq, unsigned n_ineq) +{ + struct isl_basic_map *bmap; + if (!dim) + return NULL; + isl_assert(dim->ctx, dim->n_in == 0, goto error); + bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq); + return bset_from_bmap(bmap); +error: + isl_space_free(dim); + return NULL; +} + +struct isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim, + unsigned extra, unsigned n_eq, unsigned n_ineq) +{ + struct isl_basic_map *bmap; + + if (!dim) + return NULL; + bmap = isl_calloc_type(dim->ctx, struct isl_basic_map); + if (!bmap) + goto error; + bmap->dim = dim; + + return basic_map_init(dim->ctx, bmap, extra, n_eq, n_ineq); +error: + isl_space_free(dim); + return NULL; +} + +struct isl_basic_map *isl_basic_map_alloc(struct isl_ctx *ctx, + unsigned nparam, unsigned in, unsigned out, unsigned extra, + unsigned n_eq, unsigned n_ineq) +{ + struct isl_basic_map *bmap; + isl_space *dim; + + dim = isl_space_alloc(ctx, nparam, in, out); + if (!dim) + return NULL; + + bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq); + return bmap; +} + +static void dup_constraints( + struct isl_basic_map *dst, struct isl_basic_map *src) +{ + int i; + unsigned total = isl_basic_map_total_dim(src); + + for (i = 0; i < src->n_eq; ++i) { + int j = isl_basic_map_alloc_equality(dst); + isl_seq_cpy(dst->eq[j], src->eq[i], 1+total); + } + + for (i = 0; i < src->n_ineq; ++i) { + int j = isl_basic_map_alloc_inequality(dst); + isl_seq_cpy(dst->ineq[j], src->ineq[i], 1+total); + } + + for (i = 0; i < src->n_div; ++i) { + int j = isl_basic_map_alloc_div(dst); + isl_seq_cpy(dst->div[j], src->div[i], 1+1+total); + } + ISL_F_SET(dst, ISL_BASIC_SET_FINAL); +} + +__isl_give isl_basic_map *isl_basic_map_dup(__isl_keep isl_basic_map *bmap) +{ + struct isl_basic_map *dup; + + if (!bmap) + return NULL; + dup = isl_basic_map_alloc_space(isl_space_copy(bmap->dim), + bmap->n_div, bmap->n_eq, bmap->n_ineq); + if (!dup) + return NULL; + dup_constraints(dup, bmap); + dup->flags = bmap->flags; + dup->sample = isl_vec_copy(bmap->sample); + return dup; +} + +struct isl_basic_set *isl_basic_set_dup(struct isl_basic_set *bset) +{ + struct isl_basic_map *dup; + + dup = isl_basic_map_dup(bset_to_bmap(bset)); + return bset_from_bmap(dup); +} + +__isl_give isl_basic_set *isl_basic_set_copy(__isl_keep isl_basic_set *bset) +{ + if (!bset) + return NULL; + + if (ISL_F_ISSET(bset, ISL_BASIC_SET_FINAL)) { + bset->ref++; + return bset; + } + return isl_basic_set_dup(bset); +} + +__isl_give isl_set *isl_set_copy(__isl_keep isl_set *set) +{ + if (!set) + return NULL; + + set->ref++; + return set; +} + +__isl_give isl_basic_map *isl_basic_map_copy(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + + if (ISL_F_ISSET(bmap, ISL_BASIC_SET_FINAL)) { + bmap->ref++; + return bmap; + } + bmap = isl_basic_map_dup(bmap); + if (bmap) + ISL_F_SET(bmap, ISL_BASIC_SET_FINAL); + return bmap; +} + +__isl_give isl_map *isl_map_copy(__isl_keep isl_map *map) +{ + if (!map) + return NULL; + + map->ref++; + return map; +} + +__isl_null isl_basic_map *isl_basic_map_free(__isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + + if (--bmap->ref > 0) + return NULL; + + isl_ctx_deref(bmap->ctx); + free(bmap->div); + isl_blk_free(bmap->ctx, bmap->block2); + free(bmap->ineq); + isl_blk_free(bmap->ctx, bmap->block); + isl_vec_free(bmap->sample); + isl_space_free(bmap->dim); + free(bmap); + + return NULL; +} + +__isl_null isl_basic_set *isl_basic_set_free(__isl_take isl_basic_set *bset) +{ + return isl_basic_map_free(bset_to_bmap(bset)); +} + +static int room_for_con(struct isl_basic_map *bmap, unsigned n) +{ + return bmap->n_eq + bmap->n_ineq + n <= bmap->c_size; +} + +/* Check that "map" has only named parameters, reporting an error + * if it does not. + */ +isl_stat isl_map_check_named_params(__isl_keep isl_map *map) +{ + return isl_space_check_named_params(isl_map_peek_space(map)); +} + +/* Check that "bmap1" and "bmap2" have the same parameters, + * reporting an error if they do not. + */ +static isl_stat isl_basic_map_check_equal_params( + __isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2) +{ + isl_bool match; + + match = isl_basic_map_has_equal_params(bmap1, bmap2); + if (match < 0) + return isl_stat_error; + if (!match) + isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, + "parameters don't match", return isl_stat_error); + return isl_stat_ok; +} + +__isl_give isl_map *isl_map_align_params_map_map_and( + __isl_take isl_map *map1, __isl_take isl_map *map2, + __isl_give isl_map *(*fn)(__isl_take isl_map *map1, + __isl_take isl_map *map2)) +{ + if (!map1 || !map2) + goto error; + if (isl_map_has_equal_params(map1, map2)) + return fn(map1, map2); + if (isl_map_check_named_params(map1) < 0) + goto error; + if (isl_map_check_named_params(map2) < 0) + goto error; + map1 = isl_map_align_params(map1, isl_map_get_space(map2)); + map2 = isl_map_align_params(map2, isl_map_get_space(map1)); + return fn(map1, map2); +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +isl_bool isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1, + __isl_keep isl_map *map2, + isl_bool (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2)) +{ + isl_bool r; + + if (!map1 || !map2) + return isl_bool_error; + if (isl_map_has_equal_params(map1, map2)) + return fn(map1, map2); + if (isl_map_check_named_params(map1) < 0) + return isl_bool_error; + if (isl_map_check_named_params(map2) < 0) + return isl_bool_error; + map1 = isl_map_copy(map1); + map2 = isl_map_copy(map2); + map1 = isl_map_align_params(map1, isl_map_get_space(map2)); + map2 = isl_map_align_params(map2, isl_map_get_space(map1)); + r = fn(map1, map2); + isl_map_free(map1); + isl_map_free(map2); + return r; +} + +int isl_basic_map_alloc_equality(struct isl_basic_map *bmap) +{ + struct isl_ctx *ctx; + if (!bmap) + return -1; + ctx = bmap->ctx; + isl_assert(ctx, room_for_con(bmap, 1), return -1); + isl_assert(ctx, (bmap->eq - bmap->ineq) + bmap->n_eq <= bmap->c_size, + return -1); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT); + ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); + if ((bmap->eq - bmap->ineq) + bmap->n_eq == bmap->c_size) { + isl_int *t; + int j = isl_basic_map_alloc_inequality(bmap); + if (j < 0) + return -1; + t = bmap->ineq[j]; + bmap->ineq[j] = bmap->ineq[bmap->n_ineq - 1]; + bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1]; + bmap->eq[-1] = t; + bmap->n_eq++; + bmap->n_ineq--; + bmap->eq--; + return 0; + } + isl_seq_clr(bmap->eq[bmap->n_eq] + 1 + isl_basic_map_total_dim(bmap), + bmap->extra - bmap->n_div); + return bmap->n_eq++; +} + +int isl_basic_set_alloc_equality(struct isl_basic_set *bset) +{ + return isl_basic_map_alloc_equality(bset_to_bmap(bset)); +} + +int isl_basic_map_free_equality(struct isl_basic_map *bmap, unsigned n) +{ + if (!bmap) + return -1; + isl_assert(bmap->ctx, n <= bmap->n_eq, return -1); + bmap->n_eq -= n; + return 0; +} + +int isl_basic_set_free_equality(struct isl_basic_set *bset, unsigned n) +{ + return isl_basic_map_free_equality(bset_to_bmap(bset), n); +} + +int isl_basic_map_drop_equality(struct isl_basic_map *bmap, unsigned pos) +{ + isl_int *t; + if (!bmap) + return -1; + isl_assert(bmap->ctx, pos < bmap->n_eq, return -1); + + if (pos != bmap->n_eq - 1) { + t = bmap->eq[pos]; + bmap->eq[pos] = bmap->eq[bmap->n_eq - 1]; + bmap->eq[bmap->n_eq - 1] = t; + } + bmap->n_eq--; + return 0; +} + +/* Turn inequality "pos" of "bmap" into an equality. + * + * In particular, we move the inequality in front of the equalities + * and move the last inequality in the position of the moved inequality. + * Note that isl_tab_make_equalities_explicit depends on this particular + * change in the ordering of the constraints. + */ +void isl_basic_map_inequality_to_equality( + struct isl_basic_map *bmap, unsigned pos) +{ + isl_int *t; + + t = bmap->ineq[pos]; + bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1]; + bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1]; + bmap->eq[-1] = t; + bmap->n_eq++; + bmap->n_ineq--; + bmap->eq--; + ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); + ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES); +} + +static int room_for_ineq(struct isl_basic_map *bmap, unsigned n) +{ + return bmap->n_ineq + n <= bmap->eq - bmap->ineq; +} + +int isl_basic_map_alloc_inequality(__isl_keep isl_basic_map *bmap) +{ + struct isl_ctx *ctx; + if (!bmap) + return -1; + ctx = bmap->ctx; + isl_assert(ctx, room_for_ineq(bmap, 1), return -1); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES); + isl_seq_clr(bmap->ineq[bmap->n_ineq] + + 1 + isl_basic_map_total_dim(bmap), + bmap->extra - bmap->n_div); + return bmap->n_ineq++; +} + +int isl_basic_set_alloc_inequality(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_alloc_inequality(bset_to_bmap(bset)); +} + +int isl_basic_map_free_inequality(struct isl_basic_map *bmap, unsigned n) +{ + if (!bmap) + return -1; + isl_assert(bmap->ctx, n <= bmap->n_ineq, return -1); + bmap->n_ineq -= n; + return 0; +} + +int isl_basic_set_free_inequality(struct isl_basic_set *bset, unsigned n) +{ + return isl_basic_map_free_inequality(bset_to_bmap(bset), n); +} + +int isl_basic_map_drop_inequality(struct isl_basic_map *bmap, unsigned pos) +{ + isl_int *t; + if (!bmap) + return -1; + isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1); + + if (pos != bmap->n_ineq - 1) { + t = bmap->ineq[pos]; + bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1]; + bmap->ineq[bmap->n_ineq - 1] = t; + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + } + bmap->n_ineq--; + return 0; +} + +int isl_basic_set_drop_inequality(struct isl_basic_set *bset, unsigned pos) +{ + return isl_basic_map_drop_inequality(bset_to_bmap(bset), pos); +} + +__isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap, + isl_int *eq) +{ + int k; + + bmap = isl_basic_map_extend_constraints(bmap, 1, 0); + if (!bmap) + return NULL; + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + isl_seq_cpy(bmap->eq[k], eq, 1 + isl_basic_map_total_dim(bmap)); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset, + isl_int *eq) +{ + return bset_from_bmap(isl_basic_map_add_eq(bset_to_bmap(bset), eq)); +} + +__isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap, + isl_int *ineq) +{ + int k; + + bmap = isl_basic_map_extend_constraints(bmap, 0, 1); + if (!bmap) + return NULL; + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + isl_seq_cpy(bmap->ineq[k], ineq, 1 + isl_basic_map_total_dim(bmap)); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset, + isl_int *ineq) +{ + return bset_from_bmap(isl_basic_map_add_ineq(bset_to_bmap(bset), ineq)); +} + +int isl_basic_map_alloc_div(struct isl_basic_map *bmap) +{ + if (!bmap) + return -1; + isl_assert(bmap->ctx, bmap->n_div < bmap->extra, return -1); + isl_seq_clr(bmap->div[bmap->n_div] + + 1 + 1 + isl_basic_map_total_dim(bmap), + bmap->extra - bmap->n_div); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); + return bmap->n_div++; +} + +int isl_basic_set_alloc_div(struct isl_basic_set *bset) +{ + return isl_basic_map_alloc_div(bset_to_bmap(bset)); +} + +/* Check that there are "n" dimensions of type "type" starting at "first" + * in "bmap". + */ +static isl_stat isl_basic_map_check_range(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + unsigned dim; + + if (!bmap) + return isl_stat_error; + dim = isl_basic_map_dim(bmap, type); + if (first + n > dim || first + n < first) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "position or range out of bounds", + return isl_stat_error); + return isl_stat_ok; +} + +/* Insert an extra integer division, prescribed by "div", to "bmap" + * at (integer division) position "pos". + * + * The integer division is first added at the end and then moved + * into the right position. + */ +__isl_give isl_basic_map *isl_basic_map_insert_div( + __isl_take isl_basic_map *bmap, int pos, __isl_keep isl_vec *div) +{ + int i, k; + + bmap = isl_basic_map_cow(bmap); + if (!bmap || !div) + return isl_basic_map_free(bmap); + + if (div->size != 1 + 1 + isl_basic_map_dim(bmap, isl_dim_all)) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "unexpected size", return isl_basic_map_free(bmap)); + if (isl_basic_map_check_range(bmap, isl_dim_div, pos, 0) < 0) + return isl_basic_map_free(bmap); + + bmap = isl_basic_map_extend_space(bmap, + isl_basic_map_get_space(bmap), 1, 0, 2); + k = isl_basic_map_alloc_div(bmap); + if (k < 0) + return isl_basic_map_free(bmap); + isl_seq_cpy(bmap->div[k], div->el, div->size); + isl_int_set_si(bmap->div[k][div->size], 0); + + for (i = k; i > pos; --i) + isl_basic_map_swap_div(bmap, i, i - 1); + + return bmap; +} + +isl_stat isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n) +{ + if (!bmap) + return isl_stat_error; + isl_assert(bmap->ctx, n <= bmap->n_div, return isl_stat_error); + bmap->n_div -= n; + return isl_stat_ok; +} + +/* Copy constraint from src to dst, putting the vars of src at offset + * dim_off in dst and the divs of src at offset div_off in dst. + * If both sets are actually map, then dim_off applies to the input + * variables. + */ +static void copy_constraint(struct isl_basic_map *dst_map, isl_int *dst, + struct isl_basic_map *src_map, isl_int *src, + unsigned in_off, unsigned out_off, unsigned div_off) +{ + unsigned src_nparam = isl_basic_map_dim(src_map, isl_dim_param); + unsigned dst_nparam = isl_basic_map_dim(dst_map, isl_dim_param); + unsigned src_in = isl_basic_map_dim(src_map, isl_dim_in); + unsigned dst_in = isl_basic_map_dim(dst_map, isl_dim_in); + unsigned src_out = isl_basic_map_dim(src_map, isl_dim_out); + unsigned dst_out = isl_basic_map_dim(dst_map, isl_dim_out); + isl_int_set(dst[0], src[0]); + isl_seq_cpy(dst+1, src+1, isl_min(dst_nparam, src_nparam)); + if (dst_nparam > src_nparam) + isl_seq_clr(dst+1+src_nparam, + dst_nparam - src_nparam); + isl_seq_clr(dst+1+dst_nparam, in_off); + isl_seq_cpy(dst+1+dst_nparam+in_off, + src+1+src_nparam, + isl_min(dst_in-in_off, src_in)); + if (dst_in-in_off > src_in) + isl_seq_clr(dst+1+dst_nparam+in_off+src_in, + dst_in - in_off - src_in); + isl_seq_clr(dst+1+dst_nparam+dst_in, out_off); + isl_seq_cpy(dst+1+dst_nparam+dst_in+out_off, + src+1+src_nparam+src_in, + isl_min(dst_out-out_off, src_out)); + if (dst_out-out_off > src_out) + isl_seq_clr(dst+1+dst_nparam+dst_in+out_off+src_out, + dst_out - out_off - src_out); + isl_seq_clr(dst+1+dst_nparam+dst_in+dst_out, div_off); + isl_seq_cpy(dst+1+dst_nparam+dst_in+dst_out+div_off, + src+1+src_nparam+src_in+src_out, + isl_min(dst_map->extra-div_off, src_map->n_div)); + if (dst_map->n_div-div_off > src_map->n_div) + isl_seq_clr(dst+1+dst_nparam+dst_in+dst_out+ + div_off+src_map->n_div, + dst_map->n_div - div_off - src_map->n_div); +} + +static void copy_div(struct isl_basic_map *dst_map, isl_int *dst, + struct isl_basic_map *src_map, isl_int *src, + unsigned in_off, unsigned out_off, unsigned div_off) +{ + isl_int_set(dst[0], src[0]); + copy_constraint(dst_map, dst+1, src_map, src+1, in_off, out_off, div_off); +} + +static __isl_give isl_basic_map *add_constraints( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2, + unsigned i_pos, unsigned o_pos) +{ + int i; + unsigned div_off; + + if (!bmap1 || !bmap2) + goto error; + + div_off = bmap1->n_div; + + for (i = 0; i < bmap2->n_eq; ++i) { + int i1 = isl_basic_map_alloc_equality(bmap1); + if (i1 < 0) + goto error; + copy_constraint(bmap1, bmap1->eq[i1], bmap2, bmap2->eq[i], + i_pos, o_pos, div_off); + } + + for (i = 0; i < bmap2->n_ineq; ++i) { + int i1 = isl_basic_map_alloc_inequality(bmap1); + if (i1 < 0) + goto error; + copy_constraint(bmap1, bmap1->ineq[i1], bmap2, bmap2->ineq[i], + i_pos, o_pos, div_off); + } + + for (i = 0; i < bmap2->n_div; ++i) { + int i1 = isl_basic_map_alloc_div(bmap1); + if (i1 < 0) + goto error; + copy_div(bmap1, bmap1->div[i1], bmap2, bmap2->div[i], + i_pos, o_pos, div_off); + } + + isl_basic_map_free(bmap2); + + return bmap1; + +error: + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1, + struct isl_basic_set *bset2, unsigned pos) +{ + return bset_from_bmap(add_constraints(bset_to_bmap(bset1), + bset_to_bmap(bset2), 0, pos)); +} + +__isl_give isl_basic_map *isl_basic_map_extend_space( + __isl_take isl_basic_map *base, __isl_take isl_space *dim, + unsigned extra, unsigned n_eq, unsigned n_ineq) +{ + struct isl_basic_map *ext; + unsigned flags; + int dims_ok; + + if (!dim) + goto error; + + if (!base) + goto error; + + dims_ok = isl_space_is_equal(base->dim, dim) && + base->extra >= base->n_div + extra; + + if (dims_ok && room_for_con(base, n_eq + n_ineq) && + room_for_ineq(base, n_ineq)) { + isl_space_free(dim); + return base; + } + + isl_assert(base->ctx, base->dim->nparam <= dim->nparam, goto error); + isl_assert(base->ctx, base->dim->n_in <= dim->n_in, goto error); + isl_assert(base->ctx, base->dim->n_out <= dim->n_out, goto error); + extra += base->extra; + n_eq += base->n_eq; + n_ineq += base->n_ineq; + + ext = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq); + dim = NULL; + if (!ext) + goto error; + + if (dims_ok) + ext->sample = isl_vec_copy(base->sample); + flags = base->flags; + ext = add_constraints(ext, base, 0, 0); + if (ext) { + ext->flags = flags; + ISL_F_CLR(ext, ISL_BASIC_SET_FINAL); + } + + return ext; + +error: + isl_space_free(dim); + isl_basic_map_free(base); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_extend_space( + __isl_take isl_basic_set *base, + __isl_take isl_space *dim, unsigned extra, + unsigned n_eq, unsigned n_ineq) +{ + return bset_from_bmap(isl_basic_map_extend_space(bset_to_bmap(base), + dim, extra, n_eq, n_ineq)); +} + +struct isl_basic_map *isl_basic_map_extend_constraints( + struct isl_basic_map *base, unsigned n_eq, unsigned n_ineq) +{ + if (!base) + return NULL; + return isl_basic_map_extend_space(base, isl_space_copy(base->dim), + 0, n_eq, n_ineq); +} + +struct isl_basic_map *isl_basic_map_extend(struct isl_basic_map *base, + unsigned nparam, unsigned n_in, unsigned n_out, unsigned extra, + unsigned n_eq, unsigned n_ineq) +{ + struct isl_basic_map *bmap; + isl_space *dim; + + if (!base) + return NULL; + dim = isl_space_alloc(base->ctx, nparam, n_in, n_out); + if (!dim) + goto error; + + bmap = isl_basic_map_extend_space(base, dim, extra, n_eq, n_ineq); + return bmap; +error: + isl_basic_map_free(base); + return NULL; +} + +struct isl_basic_set *isl_basic_set_extend(struct isl_basic_set *base, + unsigned nparam, unsigned dim, unsigned extra, + unsigned n_eq, unsigned n_ineq) +{ + return bset_from_bmap(isl_basic_map_extend(bset_to_bmap(base), + nparam, 0, dim, extra, n_eq, n_ineq)); +} + +struct isl_basic_set *isl_basic_set_extend_constraints( + struct isl_basic_set *base, unsigned n_eq, unsigned n_ineq) +{ + isl_basic_map *bmap = bset_to_bmap(base); + bmap = isl_basic_map_extend_constraints(bmap, n_eq, n_ineq); + return bset_from_bmap(bmap); +} + +__isl_give isl_basic_set *isl_basic_set_cow(__isl_take isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_cow(bset_to_bmap(bset))); +} + +__isl_give isl_basic_map *isl_basic_map_cow(__isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + + if (bmap->ref > 1) { + bmap->ref--; + bmap = isl_basic_map_dup(bmap); + } + if (bmap) { + ISL_F_CLR(bmap, ISL_BASIC_SET_FINAL); + ISL_F_CLR(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS); + } + return bmap; +} + +/* Clear all cached information in "map", either because it is about + * to be modified or because it is being freed. + * Always return the same pointer that is passed in. + * This is needed for the use in isl_map_free. + */ +static __isl_give isl_map *clear_caches(__isl_take isl_map *map) +{ + isl_basic_map_free(map->cached_simple_hull[0]); + isl_basic_map_free(map->cached_simple_hull[1]); + map->cached_simple_hull[0] = NULL; + map->cached_simple_hull[1] = NULL; + return map; +} + +__isl_give isl_set *isl_set_cow(__isl_take isl_set *set) +{ + return isl_map_cow(set); +} + +/* Return an isl_map that is equal to "map" and that has only + * a single reference. + * + * If the original input already has only one reference, then + * simply return it, but clear all cached information, since + * it may be rendered invalid by the operations that will be + * performed on the result. + * + * Otherwise, create a duplicate (without any cached information). + */ +__isl_give isl_map *isl_map_cow(__isl_take isl_map *map) +{ + if (!map) + return NULL; + + if (map->ref == 1) + return clear_caches(map); + map->ref--; + return isl_map_dup(map); +} + +static void swap_vars(struct isl_blk blk, isl_int *a, + unsigned a_len, unsigned b_len) +{ + isl_seq_cpy(blk.data, a+a_len, b_len); + isl_seq_cpy(blk.data+b_len, a, a_len); + isl_seq_cpy(a, blk.data, b_len+a_len); +} + +static __isl_give isl_basic_map *isl_basic_map_swap_vars( + __isl_take isl_basic_map *bmap, unsigned pos, unsigned n1, unsigned n2) +{ + int i; + struct isl_blk blk; + + if (!bmap) + goto error; + + isl_assert(bmap->ctx, + pos + n1 + n2 <= 1 + isl_basic_map_total_dim(bmap), goto error); + + if (n1 == 0 || n2 == 0) + return bmap; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + blk = isl_blk_alloc(bmap->ctx, n1 + n2); + if (isl_blk_is_error(blk)) + goto error; + + for (i = 0; i < bmap->n_eq; ++i) + swap_vars(blk, + bmap->eq[i] + pos, n1, n2); + + for (i = 0; i < bmap->n_ineq; ++i) + swap_vars(blk, + bmap->ineq[i] + pos, n1, n2); + + for (i = 0; i < bmap->n_div; ++i) + swap_vars(blk, + bmap->div[i]+1 + pos, n1, n2); + + isl_blk_free(bmap->ctx, blk); + + ISL_F_CLR(bmap, ISL_BASIC_SET_NORMALIZED); + bmap = isl_basic_map_gauss(bmap, NULL); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_set_to_empty( + __isl_take isl_basic_map *bmap) +{ + int i = 0; + unsigned total; + if (!bmap) + goto error; + total = isl_basic_map_total_dim(bmap); + if (isl_basic_map_free_div(bmap, bmap->n_div) < 0) + return isl_basic_map_free(bmap); + isl_basic_map_free_inequality(bmap, bmap->n_ineq); + if (bmap->n_eq > 0) + isl_basic_map_free_equality(bmap, bmap->n_eq-1); + else { + i = isl_basic_map_alloc_equality(bmap); + if (i < 0) + goto error; + } + isl_int_set_si(bmap->eq[i][0], 1); + isl_seq_clr(bmap->eq[i]+1, total); + ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY); + isl_vec_free(bmap->sample); + bmap->sample = NULL; + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_set_to_empty( + __isl_take isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_set_to_empty(bset_to_bmap(bset))); +} + +__isl_give isl_basic_map *isl_basic_map_set_rational( + __isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) + return bmap; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + ISL_F_SET(bmap, ISL_BASIC_MAP_RATIONAL); + + return isl_basic_map_finalize(bmap); +} + +__isl_give isl_basic_set *isl_basic_set_set_rational( + __isl_take isl_basic_set *bset) +{ + return isl_basic_map_set_rational(bset); +} + +__isl_give isl_basic_set *isl_basic_set_set_integral( + __isl_take isl_basic_set *bset) +{ + if (!bset) + return NULL; + + if (!ISL_F_ISSET(bset, ISL_BASIC_MAP_RATIONAL)) + return bset; + + bset = isl_basic_set_cow(bset); + if (!bset) + return NULL; + + ISL_F_CLR(bset, ISL_BASIC_MAP_RATIONAL); + + return isl_basic_set_finalize(bset); +} + +__isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_set_rational(map->p[i]); + if (!map->p[i]) + goto error; + } + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set) +{ + return isl_map_set_rational(set); +} + +/* Swap divs "a" and "b" in "bmap" (without modifying any of the constraints + * of "bmap"). + */ +static void swap_div(__isl_keep isl_basic_map *bmap, int a, int b) +{ + isl_int *t = bmap->div[a]; + bmap->div[a] = bmap->div[b]; + bmap->div[b] = t; +} + +/* Swap divs "a" and "b" in "bmap" and adjust the constraints and + * div definitions accordingly. + */ +void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b) +{ + int i; + unsigned off = isl_space_dim(bmap->dim, isl_dim_all); + + swap_div(bmap, a, b); + + for (i = 0; i < bmap->n_eq; ++i) + isl_int_swap(bmap->eq[i][1+off+a], bmap->eq[i][1+off+b]); + + for (i = 0; i < bmap->n_ineq; ++i) + isl_int_swap(bmap->ineq[i][1+off+a], bmap->ineq[i][1+off+b]); + + for (i = 0; i < bmap->n_div; ++i) + isl_int_swap(bmap->div[i][1+1+off+a], bmap->div[i][1+1+off+b]); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); +} + +/* Swap divs "a" and "b" in "bset" and adjust the constraints and + * div definitions accordingly. + */ +void isl_basic_set_swap_div(__isl_keep isl_basic_set *bset, int a, int b) +{ + isl_basic_map_swap_div(bset, a, b); +} + +static void constraint_drop_vars(isl_int *c, unsigned n, unsigned rem) +{ + isl_seq_cpy(c, c + n, rem); + isl_seq_clr(c + rem, n); +} + +/* Drop n dimensions starting at first. + * + * In principle, this frees up some extra variables as the number + * of columns remains constant, but we would have to extend + * the div array too as the number of rows in this array is assumed + * to be equal to extra. + */ +__isl_give isl_basic_set *isl_basic_set_drop_dims( + __isl_take isl_basic_set *bset, unsigned first, unsigned n) +{ + return isl_basic_map_drop(bset_to_bmap(bset), isl_dim_set, first, n); +} + +/* Move "n" divs starting at "first" to the end of the list of divs. + */ +static struct isl_basic_map *move_divs_last(struct isl_basic_map *bmap, + unsigned first, unsigned n) +{ + isl_int **div; + int i; + + if (first + n == bmap->n_div) + return bmap; + + div = isl_alloc_array(bmap->ctx, isl_int *, n); + if (!div) + goto error; + for (i = 0; i < n; ++i) + div[i] = bmap->div[first + i]; + for (i = 0; i < bmap->n_div - first - n; ++i) + bmap->div[first + i] = bmap->div[first + n + i]; + for (i = 0; i < n; ++i) + bmap->div[bmap->n_div - n + i] = div[i]; + free(div); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Drop "n" dimensions of type "type" starting at "first". + * + * In principle, this frees up some extra variables as the number + * of columns remains constant, but we would have to extend + * the div array too as the number of rows in this array is assumed + * to be equal to extra. + */ +__isl_give isl_basic_map *isl_basic_map_drop(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + unsigned dim; + unsigned offset; + unsigned left; + + if (!bmap) + goto error; + + dim = isl_basic_map_dim(bmap, type); + isl_assert(bmap->ctx, first + n <= dim, goto error); + + if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type)) + return bmap; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + offset = isl_basic_map_offset(bmap, type) + first; + left = isl_basic_map_total_dim(bmap) - (offset - 1) - n; + for (i = 0; i < bmap->n_eq; ++i) + constraint_drop_vars(bmap->eq[i]+offset, n, left); + + for (i = 0; i < bmap->n_ineq; ++i) + constraint_drop_vars(bmap->ineq[i]+offset, n, left); + + for (i = 0; i < bmap->n_div; ++i) + constraint_drop_vars(bmap->div[i]+1+offset, n, left); + + if (type == isl_dim_div) { + bmap = move_divs_last(bmap, first, n); + if (!bmap) + goto error; + if (isl_basic_map_free_div(bmap, n) < 0) + return isl_basic_map_free(bmap); + } else + bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n); + if (!bmap->dim) + goto error; + + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return bset_from_bmap(isl_basic_map_drop(bset_to_bmap(bset), + type, first, n)); +} + +__isl_give isl_map *isl_map_drop(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!map) + goto error; + + isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error); + + if (n == 0 && !isl_space_is_named_or_nested(map->dim, type)) + return map; + map = isl_map_cow(map); + if (!map) + goto error; + map->dim = isl_space_drop_dims(map->dim, type, first, n); + if (!map->dim) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_drop(map->p[i], type, first, n); + if (!map->p[i]) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_drop(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return set_from_map(isl_map_drop(set_to_map(set), type, first, n)); +} + +/* + * We don't cow, as the div is assumed to be redundant. + */ +__isl_give isl_basic_map *isl_basic_map_drop_div( + __isl_take isl_basic_map *bmap, unsigned div) +{ + int i; + unsigned pos; + + if (!bmap) + goto error; + + pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div; + + isl_assert(bmap->ctx, div < bmap->n_div, goto error); + + for (i = 0; i < bmap->n_eq; ++i) + constraint_drop_vars(bmap->eq[i]+pos, 1, bmap->extra-div-1); + + for (i = 0; i < bmap->n_ineq; ++i) { + if (!isl_int_is_zero(bmap->ineq[i][pos])) { + isl_basic_map_drop_inequality(bmap, i); + --i; + continue; + } + constraint_drop_vars(bmap->ineq[i]+pos, 1, bmap->extra-div-1); + } + + for (i = 0; i < bmap->n_div; ++i) + constraint_drop_vars(bmap->div[i]+1+pos, 1, bmap->extra-div-1); + + if (div != bmap->n_div - 1) { + int j; + isl_int *t = bmap->div[div]; + + for (j = div; j < bmap->n_div - 1; ++j) + bmap->div[j] = bmap->div[j+1]; + + bmap->div[bmap->n_div - 1] = t; + } + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + if (isl_basic_map_free_div(bmap, 1) < 0) + return isl_basic_map_free(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Eliminate the specified n dimensions starting at first from the + * constraints, without removing the dimensions from the space. + * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. + */ +__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!map) + return NULL; + if (n == 0) + return map; + + if (first + n > isl_map_dim(map, type) || first + n < first) + isl_die(map->ctx, isl_error_invalid, + "index out of bounds", goto error); + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_eliminate(map->p[i], type, first, n); + if (!map->p[i]) + goto error; + } + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Eliminate the specified n dimensions starting at first from the + * constraints, without removing the dimensions from the space. + * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. + */ +__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return set_from_map(isl_map_eliminate(set_to_map(set), type, first, n)); +} + +/* Eliminate the specified n dimensions starting at first from the + * constraints, without removing the dimensions from the space. + * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. + */ +__isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set, + unsigned first, unsigned n) +{ + return isl_set_eliminate(set, isl_dim_set, first, n); +} + +__isl_give isl_basic_map *isl_basic_map_remove_divs( + __isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + bmap = isl_basic_map_eliminate_vars(bmap, + isl_space_dim(bmap->dim, isl_dim_all), bmap->n_div); + if (!bmap) + return NULL; + bmap->n_div = 0; + return isl_basic_map_finalize(bmap); +} + +__isl_give isl_basic_set *isl_basic_set_remove_divs( + __isl_take isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_remove_divs(bset_to_bmap(bset))); +} + +__isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map) +{ + int i; + + if (!map) + return NULL; + if (map->n == 0) + return map; + + map = isl_map_cow(map); + if (!map) + return NULL; + + 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 map; +error: + 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); +} + +__isl_give isl_basic_map *isl_basic_map_remove_dims( + __isl_take isl_basic_map *bmap, enum isl_dim_type type, + unsigned first, unsigned n) +{ + if (isl_basic_map_check_range(bmap, type, first, n) < 0) + return isl_basic_map_free(bmap); + if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type)) + return bmap; + bmap = isl_basic_map_eliminate_vars(bmap, + isl_basic_map_offset(bmap, type) - 1 + first, n); + if (!bmap) + return bmap; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY) && type == isl_dim_div) + return bmap; + bmap = isl_basic_map_drop(bmap, type, first, n); + return bmap; +} + +/* Return true if the definition of the given div (recursively) involves + * any of the given variables. + */ +static isl_bool div_involves_vars(__isl_keep isl_basic_map *bmap, int div, + unsigned first, unsigned n) +{ + int i; + unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div); + + if (isl_int_is_zero(bmap->div[div][0])) + return isl_bool_false; + if (isl_seq_first_non_zero(bmap->div[div] + 1 + first, n) >= 0) + return isl_bool_true; + + for (i = bmap->n_div - 1; i >= 0; --i) { + isl_bool involves; + + if (isl_int_is_zero(bmap->div[div][1 + div_offset + i])) + continue; + involves = div_involves_vars(bmap, i, first, n); + if (involves < 0 || involves) + return involves; + } + + return isl_bool_false; +} + +/* Try and add a lower and/or upper bound on "div" to "bmap" + * based on inequality "i". + * "total" is the total number of variables (excluding the divs). + * "v" is a temporary object that can be used during the calculations. + * If "lb" is set, then a lower bound should be constructed. + * If "ub" is set, then an upper bound should be constructed. + * + * The calling function has already checked that the inequality does not + * reference "div", but we still need to check that the inequality is + * of the right form. We'll consider the case where we want to construct + * a lower bound. The construction of upper bounds is similar. + * + * Let "div" be of the form + * + * q = floor((a + f(x))/d) + * + * We essentially check if constraint "i" is of the form + * + * b + f(x) >= 0 + * + * so that we can use it to derive a lower bound on "div". + * However, we allow a slightly more general form + * + * b + g(x) >= 0 + * + * with the condition that the coefficients of g(x) - f(x) are all + * divisible by d. + * Rewriting this constraint as + * + * 0 >= -b - g(x) + * + * adding a + f(x) to both sides and dividing by d, we obtain + * + * (a + f(x))/d >= (a-b)/d + (f(x)-g(x))/d + * + * Taking the floor on both sides, we obtain + * + * q >= floor((a-b)/d) + (f(x)-g(x))/d + * + * or + * + * (g(x)-f(x))/d + ceil((b-a)/d) + q >= 0 + * + * In the case of an upper bound, we construct the constraint + * + * (g(x)+f(x))/d + floor((b+a)/d) - q >= 0 + * + */ +static __isl_give isl_basic_map *insert_bounds_on_div_from_ineq( + __isl_take isl_basic_map *bmap, int div, int i, + unsigned total, isl_int v, int lb, int ub) +{ + int j; + + for (j = 0; (lb || ub) && j < total + bmap->n_div; ++j) { + if (lb) { + isl_int_sub(v, bmap->ineq[i][1 + j], + bmap->div[div][1 + 1 + j]); + lb = isl_int_is_divisible_by(v, bmap->div[div][0]); + } + if (ub) { + isl_int_add(v, bmap->ineq[i][1 + j], + bmap->div[div][1 + 1 + j]); + ub = isl_int_is_divisible_by(v, bmap->div[div][0]); + } + } + if (!lb && !ub) + return bmap; + + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_extend_constraints(bmap, 0, lb + ub); + if (lb) { + int k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + for (j = 0; j < 1 + total + bmap->n_div; ++j) { + isl_int_sub(bmap->ineq[k][j], bmap->ineq[i][j], + bmap->div[div][1 + j]); + isl_int_cdiv_q(bmap->ineq[k][j], + bmap->ineq[k][j], bmap->div[div][0]); + } + isl_int_set_si(bmap->ineq[k][1 + total + div], 1); + } + if (ub) { + int k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + for (j = 0; j < 1 + total + bmap->n_div; ++j) { + isl_int_add(bmap->ineq[k][j], bmap->ineq[i][j], + bmap->div[div][1 + j]); + isl_int_fdiv_q(bmap->ineq[k][j], + bmap->ineq[k][j], bmap->div[div][0]); + } + isl_int_set_si(bmap->ineq[k][1 + total + div], -1); + } + + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* This function is called right before "div" is eliminated from "bmap" + * using Fourier-Motzkin. + * Look through the constraints of "bmap" for constraints on the argument + * of the integer division and use them to construct constraints on the + * integer division itself. These constraints can then be combined + * during the Fourier-Motzkin elimination. + * Note that it is only useful to introduce lower bounds on "div" + * if "bmap" already contains upper bounds on "div" as the newly + * introduce lower bounds can then be combined with the pre-existing + * upper bounds. Similarly for upper bounds. + * We therefore first check if "bmap" contains any lower and/or upper bounds + * on "div". + * + * It is interesting to note that the introduction of these constraints + * can indeed lead to more accurate results, even when compared to + * deriving constraints on the argument of "div" from constraints on "div". + * Consider, for example, the set + * + * { [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k } + * + * The second constraint can be rewritten as + * + * 2 * [(-i-2j+3)/4] + k >= 0 + * + * from which we can derive + * + * -i - 2j + 3 >= -2k + * + * or + * + * i + 2j <= 3 + 2k + * + * Combined with the first constraint, we obtain + * + * -3 <= 3 + 2k or k >= -3 + * + * If, on the other hand we derive a constraint on [(i+2j)/4] from + * the first constraint, we obtain + * + * [(i + 2j)/4] >= [-3/4] = -1 + * + * Combining this constraint with the second constraint, we obtain + * + * k >= -2 + */ +static __isl_give isl_basic_map *insert_bounds_on_div( + __isl_take isl_basic_map *bmap, int div) +{ + int i; + int check_lb, check_ub; + isl_int v; + unsigned total; + + if (!bmap) + return NULL; + + if (isl_int_is_zero(bmap->div[div][0])) + return bmap; + + total = isl_space_dim(bmap->dim, isl_dim_all); + + check_lb = 0; + check_ub = 0; + for (i = 0; (!check_lb || !check_ub) && i < bmap->n_ineq; ++i) { + int s = isl_int_sgn(bmap->ineq[i][1 + total + div]); + if (s > 0) + check_ub = 1; + if (s < 0) + check_lb = 1; + } + + if (!check_lb && !check_ub) + return bmap; + + isl_int_init(v); + + for (i = 0; bmap && i < bmap->n_ineq; ++i) { + if (!isl_int_is_zero(bmap->ineq[i][1 + total + div])) + continue; + + bmap = insert_bounds_on_div_from_ineq(bmap, div, i, total, v, + check_lb, check_ub); + } + + isl_int_clear(v); + + return bmap; +} + +/* Remove all divs (recursively) involving any of the given dimensions + * in their definitions. + */ +__isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (isl_basic_map_check_range(bmap, type, first, n) < 0) + return isl_basic_map_free(bmap); + first += isl_basic_map_offset(bmap, type); + + for (i = bmap->n_div - 1; i >= 0; --i) { + isl_bool involves; + + involves = div_involves_vars(bmap, i, first, n); + if (involves < 0) + return isl_basic_map_free(bmap); + if (!involves) + continue; + bmap = insert_bounds_on_div(bmap, i); + bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1); + if (!bmap) + return NULL; + i = bmap->n_div; + } + + return bmap; +} + +__isl_give isl_basic_set *isl_basic_set_remove_divs_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_basic_map_remove_divs_involving_dims(bset, type, first, n); +} + +__isl_give isl_map *isl_map_remove_divs_involving_dims(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!map) + return NULL; + if (map->n == 0) + return map; + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_remove_divs_involving_dims(map->p[i], + type, first, n); + if (!map->p[i]) + goto error; + } + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return set_from_map(isl_map_remove_divs_involving_dims(set_to_map(set), + type, first, n)); +} + +/* Does the description of "bmap" depend on the specified dimensions? + * We also check whether the dimensions appear in any of the div definitions. + * In principle there is no need for this check. If the dimensions appear + * in a div definition, they also appear in the defining constraints of that + * div. + */ +isl_bool isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (isl_basic_map_check_range(bmap, type, first, n) < 0) + return isl_bool_error; + + first += isl_basic_map_offset(bmap, type); + for (i = 0; i < bmap->n_eq; ++i) + if (isl_seq_first_non_zero(bmap->eq[i] + first, n) >= 0) + return isl_bool_true; + for (i = 0; i < bmap->n_ineq; ++i) + if (isl_seq_first_non_zero(bmap->ineq[i] + first, n) >= 0) + return isl_bool_true; + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_seq_first_non_zero(bmap->div[i] + 1 + first, n) >= 0) + return isl_bool_true; + } + + return isl_bool_false; +} + +isl_bool isl_map_involves_dims(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!map) + return isl_bool_error; + + if (first + n > isl_map_dim(map, type)) + isl_die(map->ctx, isl_error_invalid, + "index out of bounds", return isl_bool_error); + + for (i = 0; i < map->n; ++i) { + isl_bool involves = isl_basic_map_involves_dims(map->p[i], + type, first, n); + if (involves < 0 || involves) + return involves; + } + + return isl_bool_false; +} + +isl_bool isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_basic_map_involves_dims(bset, type, first, n); +} + +isl_bool isl_set_involves_dims(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_map_involves_dims(set, type, first, n); +} + +/* Drop all constraints in bmap that involve any of the dimensions + * first to first+n-1. + */ +static __isl_give isl_basic_map *isl_basic_map_drop_constraints_involving( + __isl_take isl_basic_map *bmap, unsigned first, unsigned n) +{ + int i; + + if (n == 0) + return bmap; + + bmap = isl_basic_map_cow(bmap); + + if (!bmap) + return NULL; + + for (i = bmap->n_eq - 1; i >= 0; --i) { + if (isl_seq_first_non_zero(bmap->eq[i] + 1 + first, n) == -1) + continue; + isl_basic_map_drop_equality(bmap, i); + } + + for (i = bmap->n_ineq - 1; i >= 0; --i) { + if (isl_seq_first_non_zero(bmap->ineq[i] + 1 + first, n) == -1) + continue; + isl_basic_map_drop_inequality(bmap, i); + } + + bmap = isl_basic_map_add_known_div_constraints(bmap); + return bmap; +} + +/* Drop all constraints in bset that involve any of the dimensions + * first to first+n-1. + */ +__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving( + __isl_take isl_basic_set *bset, unsigned first, unsigned n) +{ + return isl_basic_map_drop_constraints_involving(bset, first, n); +} + +/* Drop all constraints in bmap that do not involve any of the dimensions + * first to first + n - 1 of the given type. + */ +__isl_give isl_basic_map *isl_basic_map_drop_constraints_not_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (n == 0) { + isl_space *space = isl_basic_map_get_space(bmap); + isl_basic_map_free(bmap); + return isl_basic_map_universe(space); + } + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + if (isl_basic_map_check_range(bmap, type, first, n) < 0) + return isl_basic_map_free(bmap); + + first += isl_basic_map_offset(bmap, type) - 1; + + for (i = bmap->n_eq - 1; i >= 0; --i) { + if (isl_seq_first_non_zero(bmap->eq[i] + 1 + first, n) != -1) + continue; + isl_basic_map_drop_equality(bmap, i); + } + + for (i = bmap->n_ineq - 1; i >= 0; --i) { + if (isl_seq_first_non_zero(bmap->ineq[i] + 1 + first, n) != -1) + continue; + isl_basic_map_drop_inequality(bmap, i); + } + + bmap = isl_basic_map_add_known_div_constraints(bmap); + return bmap; +} + +/* Drop all constraints in bset that do not involve any of the dimensions + * first to first + n - 1 of the given type. + */ +__isl_give isl_basic_set *isl_basic_set_drop_constraints_not_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_basic_map_drop_constraints_not_involving_dims(bset, + type, first, n); +} + +/* Drop all constraints in bmap that involve any of the dimensions + * first to first + n - 1 of the given type. + */ +__isl_give isl_basic_map *isl_basic_map_drop_constraints_involving_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + if (!bmap) + return NULL; + if (n == 0) + return bmap; + + if (isl_basic_map_check_range(bmap, type, first, n) < 0) + return isl_basic_map_free(bmap); + + bmap = isl_basic_map_remove_divs_involving_dims(bmap, type, first, n); + first += isl_basic_map_offset(bmap, type) - 1; + return isl_basic_map_drop_constraints_involving(bmap, first, n); +} + +/* Drop all constraints in bset that involve any of the dimensions + * first to first + n - 1 of the given type. + */ +__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_basic_map_drop_constraints_involving_dims(bset, + type, first, n); +} + +/* Drop constraints from "map" by applying "drop" to each basic map. + */ +static __isl_give isl_map *drop_constraints(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n, + __isl_give isl_basic_map *(*drop)(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n)) +{ + int i; + unsigned dim; + + if (!map) + return NULL; + + dim = isl_map_dim(map, type); + if (first + n > dim || first + n < first) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "index out of bounds", return isl_map_free(map)); + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = drop(map->p[i], type, first, n); + if (!map->p[i]) + return isl_map_free(map); + } + + if (map->n > 1) + ISL_F_CLR(map, ISL_MAP_DISJOINT); + + return map; +} + +/* Drop all constraints in map that involve any of the dimensions + * first to first + n - 1 of the given type. + */ +__isl_give isl_map *isl_map_drop_constraints_involving_dims( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n) +{ + if (n == 0) + return map; + return drop_constraints(map, type, first, n, + &isl_basic_map_drop_constraints_involving_dims); +} + +/* Drop all constraints in "map" that do not involve any of the dimensions + * first to first + n - 1 of the given type. + */ +__isl_give isl_map *isl_map_drop_constraints_not_involving_dims( + __isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n) +{ + if (n == 0) { + isl_space *space = isl_map_get_space(map); + isl_map_free(map); + return isl_map_universe(space); + } + return drop_constraints(map, type, first, n, + &isl_basic_map_drop_constraints_not_involving_dims); +} + +/* Drop all constraints in set that involve any of the dimensions + * first to first + n - 1 of the given type. + */ +__isl_give isl_set *isl_set_drop_constraints_involving_dims( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_map_drop_constraints_involving_dims(set, type, first, n); +} + +/* Drop all constraints in "set" that do not involve any of the dimensions + * first to first + n - 1 of the given type. + */ +__isl_give isl_set *isl_set_drop_constraints_not_involving_dims( + __isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_map_drop_constraints_not_involving_dims(set, type, first, n); +} + +/* Does local variable "div" of "bmap" have a complete explicit representation? + * Having a complete explicit representation requires not only + * an explicit representation, but also that all local variables + * that appear in this explicit representation in turn have + * a complete explicit representation. + */ +isl_bool isl_basic_map_div_is_known(__isl_keep isl_basic_map *bmap, int div) +{ + int i; + unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div); + isl_bool marked; + + marked = isl_basic_map_div_is_marked_unknown(bmap, div); + if (marked < 0 || marked) + return isl_bool_not(marked); + + for (i = bmap->n_div - 1; i >= 0; --i) { + isl_bool known; + + if (isl_int_is_zero(bmap->div[div][1 + div_offset + i])) + continue; + known = isl_basic_map_div_is_known(bmap, i); + if (known < 0 || !known) + return known; + } + + return isl_bool_true; +} + +/* Remove all divs that are unknown or defined in terms of unknown divs. + */ +__isl_give isl_basic_map *isl_basic_map_remove_unknown_divs( + __isl_take isl_basic_map *bmap) +{ + int i; + + if (!bmap) + return NULL; + + for (i = bmap->n_div - 1; i >= 0; --i) { + if (isl_basic_map_div_is_known(bmap, i)) + continue; + bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1); + if (!bmap) + return NULL; + i = bmap->n_div; + } + + return bmap; +} + +/* Remove all divs that are unknown or defined in terms of unknown divs. + */ +__isl_give isl_basic_set *isl_basic_set_remove_unknown_divs( + __isl_take isl_basic_set *bset) +{ + return isl_basic_map_remove_unknown_divs(bset); +} + +__isl_give isl_map *isl_map_remove_unknown_divs(__isl_take isl_map *map) +{ + int i; + + if (!map) + return NULL; + if (map->n == 0) + return map; + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_remove_unknown_divs(map->p[i]); + if (!map->p[i]) + goto error; + } + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_remove_unknown_divs(__isl_take isl_set *set) +{ + return set_from_map(isl_map_remove_unknown_divs(set_to_map(set))); +} + +__isl_give isl_basic_set *isl_basic_set_remove_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_basic_map *bmap = bset_to_bmap(bset); + bmap = isl_basic_map_remove_dims(bmap, type, first, n); + return bset_from_bmap(bmap); +} + +__isl_give isl_map *isl_map_remove_dims(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (n == 0) + return map; + + map = isl_map_cow(map); + if (!map) + return NULL; + isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error); + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_eliminate_vars(map->p[i], + isl_basic_map_offset(map->p[i], type) - 1 + first, n); + if (!map->p[i]) + goto error; + } + map = isl_map_drop(map, type, first, n); + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_remove_dims(__isl_take isl_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return set_from_map(isl_map_remove_dims(set_to_map(bset), + type, first, n)); +} + +/* Project out n inputs starting at first using Fourier-Motzkin */ +struct isl_map *isl_map_remove_inputs(struct isl_map *map, + unsigned first, unsigned n) +{ + return isl_map_remove_dims(map, isl_dim_in, first, n); +} + +static void dump_term(struct isl_basic_map *bmap, + isl_int c, int pos, FILE *out) +{ + const char *name; + unsigned in = isl_basic_map_dim(bmap, isl_dim_in); + unsigned dim = in + isl_basic_map_dim(bmap, isl_dim_out); + unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param); + if (!pos) + isl_int_print(out, c, 0); + else { + if (!isl_int_is_one(c)) + isl_int_print(out, c, 0); + if (pos < 1 + nparam) { + name = isl_space_get_dim_name(bmap->dim, + isl_dim_param, pos - 1); + if (name) + fprintf(out, "%s", name); + else + fprintf(out, "p%d", pos - 1); + } else if (pos < 1 + nparam + in) + fprintf(out, "i%d", pos - 1 - nparam); + else if (pos < 1 + nparam + dim) + fprintf(out, "o%d", pos - 1 - nparam - in); + else + fprintf(out, "e%d", pos - 1 - nparam - dim); + } +} + +static void dump_constraint_sign(struct isl_basic_map *bmap, isl_int *c, + int sign, FILE *out) +{ + int i; + int first; + unsigned len = 1 + isl_basic_map_total_dim(bmap); + isl_int v; + + isl_int_init(v); + for (i = 0, first = 1; i < len; ++i) { + if (isl_int_sgn(c[i]) * sign <= 0) + continue; + if (!first) + fprintf(out, " + "); + first = 0; + isl_int_abs(v, c[i]); + dump_term(bmap, v, i, out); + } + isl_int_clear(v); + if (first) + fprintf(out, "0"); +} + +static void dump_constraint(struct isl_basic_map *bmap, isl_int *c, + const char *op, FILE *out, int indent) +{ + int i; + + fprintf(out, "%*s", indent, ""); + + dump_constraint_sign(bmap, c, 1, out); + fprintf(out, " %s ", op); + dump_constraint_sign(bmap, c, -1, out); + + fprintf(out, "\n"); + + for (i = bmap->n_div; i < bmap->extra; ++i) { + if (isl_int_is_zero(c[1+isl_space_dim(bmap->dim, isl_dim_all)+i])) + continue; + fprintf(out, "%*s", indent, ""); + fprintf(out, "ERROR: unused div coefficient not zero\n"); + abort(); + } +} + +static void dump_constraints(struct isl_basic_map *bmap, + isl_int **c, unsigned n, + const char *op, FILE *out, int indent) +{ + int i; + + for (i = 0; i < n; ++i) + dump_constraint(bmap, c[i], op, out, indent); +} + +static void dump_affine(struct isl_basic_map *bmap, isl_int *exp, FILE *out) +{ + int j; + int first = 1; + unsigned total = isl_basic_map_total_dim(bmap); + + for (j = 0; j < 1 + total; ++j) { + if (isl_int_is_zero(exp[j])) + continue; + if (!first && isl_int_is_pos(exp[j])) + fprintf(out, "+"); + dump_term(bmap, exp[j], j, out); + first = 0; + } +} + +static void dump(struct isl_basic_map *bmap, FILE *out, int indent) +{ + int i; + + dump_constraints(bmap, bmap->eq, bmap->n_eq, "=", out, indent); + dump_constraints(bmap, bmap->ineq, bmap->n_ineq, ">=", out, indent); + + for (i = 0; i < bmap->n_div; ++i) { + fprintf(out, "%*s", indent, ""); + fprintf(out, "e%d = [(", i); + dump_affine(bmap, bmap->div[i]+1, out); + fprintf(out, ")/"); + isl_int_print(out, bmap->div[i][0], 0); + fprintf(out, "]\n"); + } +} + +void isl_basic_set_print_internal(struct isl_basic_set *bset, + FILE *out, int indent) +{ + if (!bset) { + fprintf(out, "null basic set\n"); + return; + } + + fprintf(out, "%*s", indent, ""); + fprintf(out, "ref: %d, nparam: %d, dim: %d, extra: %d, flags: %x\n", + bset->ref, bset->dim->nparam, bset->dim->n_out, + bset->extra, bset->flags); + dump(bset_to_bmap(bset), out, indent); +} + +void isl_basic_map_print_internal(struct isl_basic_map *bmap, + FILE *out, int indent) +{ + if (!bmap) { + fprintf(out, "null basic map\n"); + return; + } + + fprintf(out, "%*s", indent, ""); + fprintf(out, "ref: %d, nparam: %d, in: %d, out: %d, extra: %d, " + "flags: %x, n_name: %d\n", + bmap->ref, + bmap->dim->nparam, bmap->dim->n_in, bmap->dim->n_out, + bmap->extra, bmap->flags, bmap->dim->n_id); + dump(bmap, out, indent); +} + +int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos) +{ + unsigned total; + if (!bmap) + return -1; + total = isl_basic_map_total_dim(bmap); + isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1); + isl_seq_neg(bmap->ineq[pos], bmap->ineq[pos], 1 + total); + isl_int_sub_ui(bmap->ineq[pos][0], bmap->ineq[pos][0], 1); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + return 0; +} + +__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *space, int n, + unsigned flags) +{ + if (!space) + return NULL; + if (isl_space_dim(space, isl_dim_in) != 0) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "set cannot have input dimensions", goto error); + return isl_map_alloc_space(space, n, flags); +error: + isl_space_free(space); + return NULL; +} + +/* Make sure "map" has room for at least "n" more basic maps. + */ +__isl_give isl_map *isl_map_grow(__isl_take isl_map *map, int n) +{ + int i; + struct isl_map *grown = NULL; + + if (!map) + return NULL; + isl_assert(map->ctx, n >= 0, goto error); + if (map->n + n <= map->size) + return map; + grown = isl_map_alloc_space(isl_map_get_space(map), map->n + n, map->flags); + if (!grown) + goto error; + for (i = 0; i < map->n; ++i) { + grown->p[i] = isl_basic_map_copy(map->p[i]); + if (!grown->p[i]) + goto error; + grown->n++; + } + isl_map_free(map); + return grown; +error: + isl_map_free(grown); + isl_map_free(map); + return NULL; +} + +/* Make sure "set" has room for at least "n" more basic sets. + */ +struct isl_set *isl_set_grow(struct isl_set *set, int n) +{ + return set_from_map(isl_map_grow(set_to_map(set), n)); +} + +__isl_give isl_set *isl_set_from_basic_set(__isl_take isl_basic_set *bset) +{ + return isl_map_from_basic_map(bset); +} + +__isl_give isl_map *isl_map_from_basic_map(__isl_take isl_basic_map *bmap) +{ + struct isl_map *map; + + if (!bmap) + return NULL; + + map = isl_map_alloc_space(isl_space_copy(bmap->dim), 1, ISL_MAP_DISJOINT); + return isl_map_add_basic_map(map, bmap); +} + +__isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *bset) +{ + return set_from_map(isl_map_add_basic_map(set_to_map(set), + bset_to_bmap(bset))); +} + +__isl_null isl_set *isl_set_free(__isl_take isl_set *set) +{ + return isl_map_free(set); +} + +void isl_set_print_internal(struct isl_set *set, FILE *out, int indent) +{ + int i; + + if (!set) { + fprintf(out, "null set\n"); + return; + } + + fprintf(out, "%*s", indent, ""); + fprintf(out, "ref: %d, n: %d, nparam: %d, dim: %d, flags: %x\n", + set->ref, set->n, set->dim->nparam, set->dim->n_out, + set->flags); + for (i = 0; i < set->n; ++i) { + fprintf(out, "%*s", indent, ""); + fprintf(out, "basic set %d:\n", i); + isl_basic_set_print_internal(set->p[i], out, indent+4); + } +} + +void isl_map_print_internal(struct isl_map *map, FILE *out, int indent) +{ + int i; + + if (!map) { + fprintf(out, "null map\n"); + return; + } + + fprintf(out, "%*s", indent, ""); + fprintf(out, "ref: %d, n: %d, nparam: %d, in: %d, out: %d, " + "flags: %x, n_name: %d\n", + map->ref, map->n, map->dim->nparam, map->dim->n_in, + map->dim->n_out, map->flags, map->dim->n_id); + for (i = 0; i < map->n; ++i) { + fprintf(out, "%*s", indent, ""); + fprintf(out, "basic map %d:\n", i); + isl_basic_map_print_internal(map->p[i], out, indent+4); + } +} + +__isl_give isl_basic_map *isl_basic_map_intersect_domain( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *bset) +{ + struct isl_basic_map *bmap_domain; + + if (isl_basic_map_check_equal_params(bmap, bset_to_bmap(bset)) < 0) + goto error; + + if (isl_space_dim(bset->dim, isl_dim_set) != 0) + isl_assert(bset->ctx, + isl_basic_map_compatible_domain(bmap, bset), goto error); + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + goto error; + bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim), + bset->n_div, bset->n_eq, bset->n_ineq); + bmap_domain = isl_basic_map_from_domain(bset); + bmap = add_constraints(bmap, bmap_domain, 0, 0); + + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + isl_basic_set_free(bset); + return NULL; +} + +/* Check that the space of "bset" is the same as that of the range of "bmap". + */ +static isl_stat isl_basic_map_check_compatible_range( + __isl_keep isl_basic_map *bmap, __isl_keep isl_basic_set *bset) +{ + isl_bool ok; + + ok = isl_basic_map_compatible_range(bmap, bset); + if (ok < 0) + return isl_stat_error; + if (!ok) + isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, + "incompatible spaces", return isl_stat_error); + + return isl_stat_ok; +} + +__isl_give isl_basic_map *isl_basic_map_intersect_range( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *bset) +{ + struct isl_basic_map *bmap_range; + + if (isl_basic_map_check_equal_params(bmap, bset_to_bmap(bset)) < 0) + goto error; + + if (isl_space_dim(bset->dim, isl_dim_set) != 0 && + isl_basic_map_check_compatible_range(bmap, bset) < 0) + goto error; + + if (isl_basic_set_plain_is_universe(bset)) { + isl_basic_set_free(bset); + return bmap; + } + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + goto error; + bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim), + bset->n_div, bset->n_eq, bset->n_ineq); + bmap_range = bset_to_bmap(bset); + bmap = add_constraints(bmap, bmap_range, 0, 0); + + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + isl_basic_set_free(bset); + return NULL; +} + +isl_bool isl_basic_map_contains(__isl_keep isl_basic_map *bmap, + __isl_keep isl_vec *vec) +{ + int i; + unsigned total; + isl_int s; + + if (!bmap || !vec) + return isl_bool_error; + + total = 1 + isl_basic_map_total_dim(bmap); + if (total != vec->size) + return isl_bool_false; + + isl_int_init(s); + + for (i = 0; i < bmap->n_eq; ++i) { + isl_seq_inner_product(vec->el, bmap->eq[i], total, &s); + if (!isl_int_is_zero(s)) { + isl_int_clear(s); + return isl_bool_false; + } + } + + for (i = 0; i < bmap->n_ineq; ++i) { + isl_seq_inner_product(vec->el, bmap->ineq[i], total, &s); + if (isl_int_is_neg(s)) { + isl_int_clear(s); + return isl_bool_false; + } + } + + isl_int_clear(s); + + return isl_bool_true; +} + +isl_bool isl_basic_set_contains(__isl_keep isl_basic_set *bset, + __isl_keep isl_vec *vec) +{ + return isl_basic_map_contains(bset_to_bmap(bset), vec); +} + +__isl_give isl_basic_map *isl_basic_map_intersect( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) +{ + struct isl_vec *sample = NULL; + + if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) + goto error; + if (isl_space_dim(bmap1->dim, isl_dim_all) == + isl_space_dim(bmap1->dim, isl_dim_param) && + isl_space_dim(bmap2->dim, isl_dim_all) != + isl_space_dim(bmap2->dim, isl_dim_param)) + return isl_basic_map_intersect(bmap2, bmap1); + + if (isl_space_dim(bmap2->dim, isl_dim_all) != + isl_space_dim(bmap2->dim, isl_dim_param)) + isl_assert(bmap1->ctx, + isl_space_is_equal(bmap1->dim, bmap2->dim), goto error); + + if (isl_basic_map_plain_is_empty(bmap1)) { + isl_basic_map_free(bmap2); + return bmap1; + } + if (isl_basic_map_plain_is_empty(bmap2)) { + isl_basic_map_free(bmap1); + return bmap2; + } + + if (bmap1->sample && + isl_basic_map_contains(bmap1, bmap1->sample) > 0 && + isl_basic_map_contains(bmap2, bmap1->sample) > 0) + sample = isl_vec_copy(bmap1->sample); + else if (bmap2->sample && + isl_basic_map_contains(bmap1, bmap2->sample) > 0 && + isl_basic_map_contains(bmap2, bmap2->sample) > 0) + sample = isl_vec_copy(bmap2->sample); + + bmap1 = isl_basic_map_cow(bmap1); + if (!bmap1) + goto error; + bmap1 = isl_basic_map_extend_space(bmap1, isl_space_copy(bmap1->dim), + bmap2->n_div, bmap2->n_eq, bmap2->n_ineq); + bmap1 = add_constraints(bmap1, bmap2, 0, 0); + + if (!bmap1) + isl_vec_free(sample); + else if (sample) { + isl_vec_free(bmap1->sample); + bmap1->sample = sample; + } + + bmap1 = isl_basic_map_simplify(bmap1); + return isl_basic_map_finalize(bmap1); +error: + if (sample) + isl_vec_free(sample); + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +struct isl_basic_set *isl_basic_set_intersect( + struct isl_basic_set *bset1, struct isl_basic_set *bset2) +{ + return bset_from_bmap(isl_basic_map_intersect(bset_to_bmap(bset1), + bset_to_bmap(bset2))); +} + +__isl_give isl_basic_set *isl_basic_set_intersect_params( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + return isl_basic_set_intersect(bset1, bset2); +} + +/* Special case of isl_map_intersect, where both map1 and map2 + * are convex, without any divs and such that either map1 or map2 + * contains a single constraint. This constraint is then simply + * added to the other map. + */ +static __isl_give isl_map *map_intersect_add_constraint( + __isl_take isl_map *map1, __isl_take isl_map *map2) +{ + isl_assert(map1->ctx, map1->n == 1, goto error); + isl_assert(map2->ctx, map1->n == 1, goto error); + isl_assert(map1->ctx, map1->p[0]->n_div == 0, goto error); + isl_assert(map2->ctx, map1->p[0]->n_div == 0, goto error); + + if (map2->p[0]->n_eq + map2->p[0]->n_ineq != 1) + return isl_map_intersect(map2, map1); + + map1 = isl_map_cow(map1); + if (!map1) + goto error; + if (isl_map_plain_is_empty(map1)) { + isl_map_free(map2); + return map1; + } + map1->p[0] = isl_basic_map_cow(map1->p[0]); + if (map2->p[0]->n_eq == 1) + map1->p[0] = isl_basic_map_add_eq(map1->p[0], map2->p[0]->eq[0]); + else + map1->p[0] = isl_basic_map_add_ineq(map1->p[0], + map2->p[0]->ineq[0]); + + map1->p[0] = isl_basic_map_simplify(map1->p[0]); + map1->p[0] = isl_basic_map_finalize(map1->p[0]); + if (!map1->p[0]) + goto error; + + if (isl_basic_map_plain_is_empty(map1->p[0])) { + isl_basic_map_free(map1->p[0]); + map1->n = 0; + } + + isl_map_free(map2); + + return map1; +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +/* map2 may be either a parameter domain or a map living in the same + * space as map1. + */ +static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + unsigned flags = 0; + isl_map *result; + int i, j; + + if (!map1 || !map2) + goto error; + + if ((isl_map_plain_is_empty(map1) || + isl_map_plain_is_universe(map2)) && + isl_space_is_equal(map1->dim, map2->dim)) { + isl_map_free(map2); + return map1; + } + if ((isl_map_plain_is_empty(map2) || + isl_map_plain_is_universe(map1)) && + isl_space_is_equal(map1->dim, map2->dim)) { + isl_map_free(map1); + return map2; + } + + if (map1->n == 1 && map2->n == 1 && + map1->p[0]->n_div == 0 && map2->p[0]->n_div == 0 && + isl_space_is_equal(map1->dim, map2->dim) && + (map1->p[0]->n_eq + map1->p[0]->n_ineq == 1 || + map2->p[0]->n_eq + map2->p[0]->n_ineq == 1)) + return map_intersect_add_constraint(map1, map2); + + if (isl_space_dim(map2->dim, isl_dim_all) != + isl_space_dim(map2->dim, isl_dim_param)) + isl_assert(map1->ctx, + isl_space_is_equal(map1->dim, map2->dim), goto error); + + if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) && + ISL_F_ISSET(map2, ISL_MAP_DISJOINT)) + ISL_FL_SET(flags, ISL_MAP_DISJOINT); + + result = isl_map_alloc_space(isl_space_copy(map1->dim), + map1->n * map2->n, flags); + if (!result) + goto error; + for (i = 0; i < map1->n; ++i) + for (j = 0; j < map2->n; ++j) { + struct isl_basic_map *part; + part = isl_basic_map_intersect( + isl_basic_map_copy(map1->p[i]), + isl_basic_map_copy(map2->p[j])); + if (isl_basic_map_is_empty(part) < 0) + part = isl_basic_map_free(part); + result = isl_map_add_basic_map(result, part); + if (!result) + goto error; + } + isl_map_free(map1); + isl_map_free(map2); + return result; +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +static __isl_give isl_map *map_intersect(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + if (!map1 || !map2) + goto error; + if (!isl_space_is_equal(map1->dim, map2->dim)) + isl_die(isl_map_get_ctx(map1), isl_error_invalid, + "spaces don't match", goto error); + return map_intersect_internal(map1, map2); +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +__isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, &map_intersect); +} + +struct isl_set *isl_set_intersect(struct isl_set *set1, struct isl_set *set2) +{ + return set_from_map(isl_map_intersect(set_to_map(set1), + set_to_map(set2))); +} + +/* map_intersect_internal accepts intersections + * with parameter domains, so we can just call that function. + */ +static __isl_give isl_map *map_intersect_params(__isl_take isl_map *map, + __isl_take isl_set *params) +{ + return map_intersect_internal(map, params); +} + +__isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, &map_intersect_params); +} + +__isl_give isl_set *isl_set_intersect_params(__isl_take isl_set *set, + __isl_take isl_set *params) +{ + return isl_map_intersect_params(set, params); +} + +__isl_give isl_basic_map *isl_basic_map_reverse(__isl_take isl_basic_map *bmap) +{ + isl_space *space; + unsigned pos, n1, n2; + + if (!bmap) + return NULL; + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + space = isl_space_reverse(isl_space_copy(bmap->dim)); + pos = isl_basic_map_offset(bmap, isl_dim_in); + n1 = isl_basic_map_dim(bmap, isl_dim_in); + n2 = isl_basic_map_dim(bmap, isl_dim_out); + bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2); + return isl_basic_map_reset_space(bmap, space); +} + +static __isl_give isl_basic_map *basic_map_space_reset( + __isl_take isl_basic_map *bmap, enum isl_dim_type type) +{ + isl_space *space; + + if (!bmap) + return NULL; + if (!isl_space_is_named_or_nested(bmap->dim, type)) + return bmap; + + space = isl_basic_map_get_space(bmap); + space = isl_space_reset(space, type); + bmap = isl_basic_map_reset_space(bmap, space); + return bmap; +} + +__isl_give isl_basic_map *isl_basic_map_insert_dims( + __isl_take isl_basic_map *bmap, enum isl_dim_type type, + unsigned pos, unsigned n) +{ + isl_bool rational; + isl_space *res_dim; + struct isl_basic_map *res; + struct isl_dim_map *dim_map; + unsigned total, off; + enum isl_dim_type t; + + if (n == 0) + return basic_map_space_reset(bmap, type); + + if (!bmap) + return NULL; + + res_dim = isl_space_insert_dims(isl_basic_map_get_space(bmap), type, pos, n); + + total = isl_basic_map_total_dim(bmap) + n; + dim_map = isl_dim_map_alloc(bmap->ctx, total); + off = 0; + for (t = isl_dim_param; t <= isl_dim_out; ++t) { + if (t != type) { + isl_dim_map_dim(dim_map, bmap->dim, t, off); + } else { + unsigned size = isl_basic_map_dim(bmap, t); + isl_dim_map_dim_range(dim_map, bmap->dim, t, + 0, pos, off); + isl_dim_map_dim_range(dim_map, bmap->dim, t, + pos, size - pos, off + pos + n); + } + off += isl_space_dim(res_dim, t); + } + isl_dim_map_div(dim_map, bmap, off); + + res = isl_basic_map_alloc_space(res_dim, + bmap->n_div, bmap->n_eq, bmap->n_ineq); + rational = isl_basic_map_is_rational(bmap); + if (rational < 0) + res = isl_basic_map_free(res); + if (rational) + res = isl_basic_map_set_rational(res); + if (isl_basic_map_plain_is_empty(bmap)) { + isl_basic_map_free(bmap); + free(dim_map); + return isl_basic_map_set_to_empty(res); + } + res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map); + return isl_basic_map_finalize(res); +} + +__isl_give isl_basic_set *isl_basic_set_insert_dims( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, unsigned n) +{ + return isl_basic_map_insert_dims(bset, type, pos, n); +} + +__isl_give isl_basic_map *isl_basic_map_add_dims(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned n) +{ + if (!bmap) + return NULL; + return isl_basic_map_insert_dims(bmap, type, + isl_basic_map_dim(bmap, type), n); +} + +__isl_give isl_basic_set *isl_basic_set_add_dims(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned n) +{ + if (!bset) + return NULL; + isl_assert(bset->ctx, type != isl_dim_in, goto error); + return isl_basic_map_add_dims(bset, type, n); +error: + isl_basic_set_free(bset); + return NULL; +} + +static __isl_give isl_map *map_space_reset(__isl_take isl_map *map, + enum isl_dim_type type) +{ + isl_space *space; + + if (!map || !isl_space_is_named_or_nested(map->dim, type)) + return map; + + space = isl_map_get_space(map); + space = isl_space_reset(space, type); + map = isl_map_reset_space(map, space); + return map; +} + +__isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, unsigned n) +{ + int i; + + if (n == 0) + return map_space_reset(map, type); + + map = isl_map_cow(map); + if (!map) + return NULL; + + map->dim = isl_space_insert_dims(map->dim, type, pos, n); + if (!map->dim) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_insert_dims(map->p[i], type, pos, n); + if (!map->p[i]) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_insert_dims(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, unsigned n) +{ + return isl_map_insert_dims(set, type, pos, n); +} + +__isl_give isl_map *isl_map_add_dims(__isl_take isl_map *map, + enum isl_dim_type type, unsigned n) +{ + if (!map) + return NULL; + return isl_map_insert_dims(map, type, isl_map_dim(map, type), n); +} + +__isl_give isl_set *isl_set_add_dims(__isl_take isl_set *set, + enum isl_dim_type type, unsigned n) +{ + if (!set) + return NULL; + isl_assert(set->ctx, type != isl_dim_in, goto error); + return set_from_map(isl_map_add_dims(set_to_map(set), type, n)); +error: + isl_set_free(set); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_move_dims( + __isl_take isl_basic_map *bmap, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + struct isl_dim_map *dim_map; + struct isl_basic_map *res; + enum isl_dim_type t; + unsigned total, off; + + if (!bmap) + return NULL; + if (n == 0) { + bmap = isl_basic_map_reset(bmap, src_type); + bmap = isl_basic_map_reset(bmap, dst_type); + return bmap; + } + + if (isl_basic_map_check_range(bmap, src_type, src_pos, n) < 0) + return isl_basic_map_free(bmap); + + if (dst_type == src_type && dst_pos == src_pos) + return bmap; + + isl_assert(bmap->ctx, dst_type != src_type, goto error); + + if (pos(bmap->dim, dst_type) + dst_pos == + pos(bmap->dim, src_type) + src_pos + + ((src_type < dst_type) ? n : 0)) { + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos, + src_type, src_pos, n); + if (!bmap->dim) + goto error; + + bmap = isl_basic_map_finalize(bmap); + + return bmap; + } + + total = isl_basic_map_total_dim(bmap); + dim_map = isl_dim_map_alloc(bmap->ctx, total); + + off = 0; + for (t = isl_dim_param; t <= isl_dim_out; ++t) { + unsigned size = isl_space_dim(bmap->dim, t); + if (t == dst_type) { + isl_dim_map_dim_range(dim_map, bmap->dim, t, + 0, dst_pos, off); + off += dst_pos; + isl_dim_map_dim_range(dim_map, bmap->dim, src_type, + src_pos, n, off); + off += n; + isl_dim_map_dim_range(dim_map, bmap->dim, t, + dst_pos, size - dst_pos, off); + off += size - dst_pos; + } else if (t == src_type) { + isl_dim_map_dim_range(dim_map, bmap->dim, t, + 0, src_pos, off); + off += src_pos; + isl_dim_map_dim_range(dim_map, bmap->dim, t, + src_pos + n, size - src_pos - n, off); + off += size - src_pos - n; + } else { + isl_dim_map_dim(dim_map, bmap->dim, t, off); + off += size; + } + } + isl_dim_map_div(dim_map, bmap, off); + + res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap), + bmap->n_div, bmap->n_eq, bmap->n_ineq); + bmap = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map); + if (!bmap) + goto error; + + bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos, + src_type, src_pos, n); + if (!bmap->dim) + goto error; + + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + bmap = isl_basic_map_gauss(bmap, NULL); + bmap = isl_basic_map_finalize(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_move_dims(__isl_take isl_basic_set *bset, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + isl_basic_map *bmap = bset_to_bmap(bset); + bmap = isl_basic_map_move_dims(bmap, dst_type, dst_pos, + src_type, src_pos, n); + return bset_from_bmap(bmap); +} + +__isl_give isl_set *isl_set_move_dims(__isl_take isl_set *set, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + if (!set) + return NULL; + isl_assert(set->ctx, dst_type != isl_dim_in, goto error); + return set_from_map(isl_map_move_dims(set_to_map(set), + dst_type, dst_pos, src_type, src_pos, n)); +error: + isl_set_free(set); + return NULL; +} + +__isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + int i; + + if (!map) + return NULL; + if (n == 0) { + map = isl_map_reset(map, src_type); + map = isl_map_reset(map, dst_type); + return map; + } + + isl_assert(map->ctx, src_pos + n <= isl_map_dim(map, src_type), + goto error); + + if (dst_type == src_type && dst_pos == src_pos) + return map; + + isl_assert(map->ctx, dst_type != src_type, goto error); + + map = isl_map_cow(map); + if (!map) + return NULL; + + map->dim = isl_space_move_dims(map->dim, dst_type, dst_pos, src_type, src_pos, n); + if (!map->dim) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_move_dims(map->p[i], + dst_type, dst_pos, + src_type, src_pos, n); + if (!map->p[i]) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Move the specified dimensions to the last columns right before + * the divs. Don't change the dimension specification of bmap. + * That's the responsibility of the caller. + */ +static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + struct isl_dim_map *dim_map; + struct isl_basic_map *res; + enum isl_dim_type t; + unsigned total, off; + + if (!bmap) + return NULL; + if (pos(bmap->dim, type) + first + n == + 1 + isl_space_dim(bmap->dim, isl_dim_all)) + return bmap; + + total = isl_basic_map_total_dim(bmap); + dim_map = isl_dim_map_alloc(bmap->ctx, total); + + off = 0; + for (t = isl_dim_param; t <= isl_dim_out; ++t) { + unsigned size = isl_space_dim(bmap->dim, t); + if (t == type) { + isl_dim_map_dim_range(dim_map, bmap->dim, t, + 0, first, off); + off += first; + isl_dim_map_dim_range(dim_map, bmap->dim, t, + first, n, total - bmap->n_div - n); + isl_dim_map_dim_range(dim_map, bmap->dim, t, + first + n, size - (first + n), off); + off += size - (first + n); + } else { + isl_dim_map_dim(dim_map, bmap->dim, t, off); + off += size; + } + } + isl_dim_map_div(dim_map, bmap, off + n); + + res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap), + bmap->n_div, bmap->n_eq, bmap->n_ineq); + res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map); + return res; +} + +/* Insert "n" rows in the divs of "bmap". + * + * The number of columns is not changed, which means that the last + * dimensions of "bmap" are being reintepreted as the new divs. + * The space of "bmap" is not adjusted, however, which means + * that "bmap" is left in an inconsistent state. Removing "n" dimensions + * from the space of "bmap" is the responsibility of the caller. + */ +static __isl_give isl_basic_map *insert_div_rows(__isl_take isl_basic_map *bmap, + int n) +{ + int i; + size_t row_size; + isl_int **new_div; + isl_int *old; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + bmap->extra; + old = bmap->block2.data; + bmap->block2 = isl_blk_extend(bmap->ctx, bmap->block2, + (bmap->extra + n) * (1 + row_size)); + if (!bmap->block2.data) + return isl_basic_map_free(bmap); + new_div = isl_alloc_array(bmap->ctx, isl_int *, bmap->extra + n); + if (!new_div) + return isl_basic_map_free(bmap); + for (i = 0; i < n; ++i) { + new_div[i] = bmap->block2.data + + (bmap->extra + i) * (1 + row_size); + isl_seq_clr(new_div[i], 1 + row_size); + } + for (i = 0; i < bmap->extra; ++i) + new_div[n + i] = bmap->block2.data + (bmap->div[i] - old); + free(bmap->div); + bmap->div = new_div; + bmap->n_div += n; + bmap->extra += n; + + return bmap; +} + +/* Drop constraints from "bmap" that only involve the variables + * of "type" in the range [first, first + n] that are not related + * to any of the variables outside that interval. + * These constraints cannot influence the values for the variables + * outside the interval, except in case they cause "bmap" to be empty. + * Only drop the constraints if "bmap" is known to be non-empty. + */ +static __isl_give isl_basic_map *drop_irrelevant_constraints( + __isl_take isl_basic_map *bmap, enum isl_dim_type type, + unsigned first, unsigned n) +{ + int i; + int *groups; + unsigned dim, n_div; + isl_bool non_empty; + + non_empty = isl_basic_map_plain_is_non_empty(bmap); + if (non_empty < 0) + return isl_basic_map_free(bmap); + if (!non_empty) + return bmap; + + dim = isl_basic_map_dim(bmap, isl_dim_all); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + groups = isl_calloc_array(isl_basic_map_get_ctx(bmap), int, dim); + if (!groups) + return isl_basic_map_free(bmap); + first += isl_basic_map_offset(bmap, type) - 1; + for (i = 0; i < first; ++i) + groups[i] = -1; + for (i = first + n; i < dim - n_div; ++i) + groups[i] = -1; + + bmap = isl_basic_map_drop_unrelated_constraints(bmap, groups); + + return bmap; +} + +/* Turn the n dimensions of type type, starting at first + * into existentially quantified variables. + * + * If a subset of the projected out variables are unrelated + * to any of the variables that remain, then the constraints + * involving this subset are simply dropped first. + */ +__isl_give isl_basic_map *isl_basic_map_project_out( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_bool empty; + + if (n == 0) + return basic_map_space_reset(bmap, type); + if (type == isl_dim_div) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "cannot project out existentially quantified variables", + return isl_basic_map_free(bmap)); + + empty = isl_basic_map_plain_is_empty(bmap); + if (empty < 0) + return isl_basic_map_free(bmap); + if (empty) + bmap = isl_basic_map_set_to_empty(bmap); + + bmap = drop_irrelevant_constraints(bmap, type, first, n); + if (!bmap) + return NULL; + + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) + return isl_basic_map_remove_dims(bmap, type, first, n); + + if (isl_basic_map_check_range(bmap, type, first, n) < 0) + return isl_basic_map_free(bmap); + + bmap = move_last(bmap, type, first, n); + bmap = isl_basic_map_cow(bmap); + bmap = insert_div_rows(bmap, n); + if (!bmap) + return NULL; + + bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n); + if (!bmap->dim) + goto error; + bmap = isl_basic_map_simplify(bmap); + bmap = isl_basic_map_drop_redundant_divs(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Turn the n dimensions of type type, starting at first + * into existentially quantified variables. + */ +struct isl_basic_set *isl_basic_set_project_out(struct isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return bset_from_bmap(isl_basic_map_project_out(bset_to_bmap(bset), + type, first, n)); +} + +/* Turn the n dimensions of type type, starting at first + * into existentially quantified variables. + */ +__isl_give isl_map *isl_map_project_out(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!map) + return NULL; + + if (n == 0) + return map_space_reset(map, type); + + isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error); + + map = isl_map_cow(map); + if (!map) + return NULL; + + map->dim = isl_space_drop_dims(map->dim, type, first, n); + if (!map->dim) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_project_out(map->p[i], type, first, n); + if (!map->p[i]) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Turn the n dimensions of type type, starting at first + * into existentially quantified variables. + */ +__isl_give isl_set *isl_set_project_out(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return set_from_map(isl_map_project_out(set_to_map(set), + type, first, n)); +} + +/* Return a map that projects the elements in "set" onto their + * "n" set dimensions starting at "first". + * "type" should be equal to isl_dim_set. + */ +__isl_give isl_map *isl_set_project_onto_map(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + int dim; + isl_map *map; + + if (!set) + return NULL; + if (type != isl_dim_set) + isl_die(isl_set_get_ctx(set), isl_error_invalid, + "only set dimensions can be projected out", goto error); + dim = isl_set_dim(set, isl_dim_set); + if (first + n > dim || first + n < first) + isl_die(isl_set_get_ctx(set), isl_error_invalid, + "index out of bounds", goto error); + + map = isl_map_from_domain(set); + map = isl_map_add_dims(map, isl_dim_out, n); + for (i = 0; i < n; ++i) + map = isl_map_equate(map, isl_dim_in, first + i, + isl_dim_out, i); + return map; +error: + isl_set_free(set); + return NULL; +} + +static struct isl_basic_map *add_divs(struct isl_basic_map *bmap, unsigned n) +{ + int i, j; + + for (i = 0; i < n; ++i) { + j = isl_basic_map_alloc_div(bmap); + if (j < 0) + goto error; + isl_seq_clr(bmap->div[j], 1+1+isl_basic_map_total_dim(bmap)); + } + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +struct isl_basic_map *isl_basic_map_apply_range( + struct isl_basic_map *bmap1, struct isl_basic_map *bmap2) +{ + isl_space *dim_result = NULL; + struct isl_basic_map *bmap; + unsigned n_in, n_out, n, nparam, total, pos; + struct isl_dim_map *dim_map1, *dim_map2; + + if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) + goto error; + if (!isl_space_tuple_is_equal(bmap1->dim, isl_dim_out, + bmap2->dim, isl_dim_in)) + isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, + "spaces don't match", goto error); + + dim_result = isl_space_join(isl_space_copy(bmap1->dim), + isl_space_copy(bmap2->dim)); + + n_in = isl_basic_map_dim(bmap1, isl_dim_in); + n_out = isl_basic_map_dim(bmap2, isl_dim_out); + n = isl_basic_map_dim(bmap1, isl_dim_out); + nparam = isl_basic_map_dim(bmap1, isl_dim_param); + + total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + n; + dim_map1 = isl_dim_map_alloc(bmap1->ctx, total); + dim_map2 = isl_dim_map_alloc(bmap1->ctx, total); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_in); + isl_dim_map_div(dim_map1, bmap1, pos += n_out); + isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos); + + bmap = isl_basic_map_alloc_space(dim_result, + bmap1->n_div + bmap2->n_div + n, + bmap1->n_eq + bmap2->n_eq, + bmap1->n_ineq + bmap2->n_ineq); + 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); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +struct isl_basic_set *isl_basic_set_apply( + struct isl_basic_set *bset, struct isl_basic_map *bmap) +{ + if (!bset || !bmap) + goto error; + + isl_assert(bset->ctx, isl_basic_map_compatible_domain(bmap, bset), + goto error); + + return bset_from_bmap(isl_basic_map_apply_range(bset_to_bmap(bset), + bmap)); +error: + isl_basic_set_free(bset); + isl_basic_map_free(bmap); + return NULL; +} + +struct isl_basic_map *isl_basic_map_apply_domain( + struct isl_basic_map *bmap1, struct isl_basic_map *bmap2) +{ + if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) + goto error; + if (!isl_space_tuple_is_equal(bmap1->dim, isl_dim_in, + bmap2->dim, isl_dim_in)) + isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, + "spaces don't match", goto error); + + bmap1 = isl_basic_map_reverse(bmap1); + bmap1 = isl_basic_map_apply_range(bmap1, bmap2); + return isl_basic_map_reverse(bmap1); +error: + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +/* Given two basic maps A -> f(A) and B -> g(B), construct a basic map + * A \cap B -> f(A) + f(B) + */ +__isl_give isl_basic_map *isl_basic_map_sum(__isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2) +{ + unsigned n_in, n_out, nparam, total, pos; + struct isl_basic_map *bmap = NULL; + struct isl_dim_map *dim_map1, *dim_map2; + int i; + + if (!bmap1 || !bmap2) + goto error; + + isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim), + goto error); + + nparam = isl_basic_map_dim(bmap1, isl_dim_param); + n_in = isl_basic_map_dim(bmap1, isl_dim_in); + n_out = isl_basic_map_dim(bmap1, isl_dim_out); + + total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + 2 * n_out; + dim_map1 = isl_dim_map_alloc(bmap1->ctx, total); + dim_map2 = isl_dim_map_alloc(bmap2->ctx, total); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos); + isl_dim_map_div(dim_map1, bmap1, pos += n_in + n_out); + isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_out); + + bmap = isl_basic_map_alloc_space(isl_space_copy(bmap1->dim), + bmap1->n_div + bmap2->n_div + 2 * n_out, + bmap1->n_eq + bmap2->n_eq + n_out, + bmap1->n_ineq + bmap2->n_ineq); + for (i = 0; i < n_out; ++i) { + int j = isl_basic_map_alloc_equality(bmap); + if (j < 0) + goto error; + isl_seq_clr(bmap->eq[j], 1+total); + isl_int_set_si(bmap->eq[j][1+nparam+n_in+i], -1); + 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 = 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); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +/* Given two maps A -> f(A) and B -> g(B), construct a map + * A \cap B -> f(A) + f(B) + */ +__isl_give isl_map *isl_map_sum(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + struct isl_map *result; + int i, j; + + if (!map1 || !map2) + goto error; + + isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error); + + result = isl_map_alloc_space(isl_space_copy(map1->dim), + map1->n * map2->n, 0); + if (!result) + goto error; + for (i = 0; i < map1->n; ++i) + for (j = 0; j < map2->n; ++j) { + struct isl_basic_map *part; + part = isl_basic_map_sum( + isl_basic_map_copy(map1->p[i]), + isl_basic_map_copy(map2->p[j])); + if (isl_basic_map_is_empty(part)) + isl_basic_map_free(part); + else + result = isl_map_add_basic_map(result, part); + if (!result) + goto error; + } + isl_map_free(map1); + isl_map_free(map2); + return result; +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +__isl_give isl_set *isl_set_sum(__isl_take isl_set *set1, + __isl_take isl_set *set2) +{ + return set_from_map(isl_map_sum(set_to_map(set1), set_to_map(set2))); +} + +/* Given a basic map A -> f(A), construct A -> -f(A). + */ +__isl_give isl_basic_map *isl_basic_map_neg(__isl_take isl_basic_map *bmap) +{ + int i, j; + unsigned off, n; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + n = isl_basic_map_dim(bmap, isl_dim_out); + off = isl_basic_map_offset(bmap, isl_dim_out); + for (i = 0; i < bmap->n_eq; ++i) + for (j = 0; j < n; ++j) + isl_int_neg(bmap->eq[i][off+j], bmap->eq[i][off+j]); + for (i = 0; i < bmap->n_ineq; ++i) + for (j = 0; j < n; ++j) + isl_int_neg(bmap->ineq[i][off+j], bmap->ineq[i][off+j]); + for (i = 0; i < bmap->n_div; ++i) + for (j = 0; j < n; ++j) + isl_int_neg(bmap->div[i][1+off+j], bmap->div[i][1+off+j]); + bmap = isl_basic_map_gauss(bmap, NULL); + return isl_basic_map_finalize(bmap); +} + +__isl_give isl_basic_set *isl_basic_set_neg(__isl_take isl_basic_set *bset) +{ + return isl_basic_map_neg(bset); +} + +/* Given a map A -> f(A), construct A -> -f(A). + */ +__isl_give isl_map *isl_map_neg(__isl_take isl_map *map) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_neg(map->p[i]); + if (!map->p[i]) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_neg(__isl_take isl_set *set) +{ + return set_from_map(isl_map_neg(set_to_map(set))); +} + +/* Given a basic map A -> f(A) and an integer d, construct a basic map + * A -> floor(f(A)/d). + */ +__isl_give isl_basic_map *isl_basic_map_floordiv(__isl_take isl_basic_map *bmap, + isl_int d) +{ + unsigned n_in, n_out, nparam, total, pos; + struct isl_basic_map *result = NULL; + struct isl_dim_map *dim_map; + int i; + + if (!bmap) + return NULL; + + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + + total = nparam + n_in + n_out + bmap->n_div + n_out; + dim_map = isl_dim_map_alloc(bmap->ctx, total); + isl_dim_map_dim(dim_map, bmap->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map, bmap->dim, isl_dim_in, pos += nparam); + isl_dim_map_div(dim_map, bmap, pos += n_in + n_out); + isl_dim_map_dim(dim_map, bmap->dim, isl_dim_out, pos += bmap->n_div); + + result = isl_basic_map_alloc_space(isl_space_copy(bmap->dim), + bmap->n_div + n_out, + bmap->n_eq, bmap->n_ineq + 2 * n_out); + 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; + j = isl_basic_map_alloc_inequality(result); + if (j < 0) + goto error; + isl_seq_clr(result->ineq[j], 1+total); + isl_int_neg(result->ineq[j][1+nparam+n_in+i], d); + isl_int_set_si(result->ineq[j][1+pos+i], 1); + j = isl_basic_map_alloc_inequality(result); + if (j < 0) + goto error; + isl_seq_clr(result->ineq[j], 1+total); + isl_int_set(result->ineq[j][1+nparam+n_in+i], d); + isl_int_set_si(result->ineq[j][1+pos+i], -1); + isl_int_sub_ui(result->ineq[j][0], d, 1); + } + + result = isl_basic_map_simplify(result); + return isl_basic_map_finalize(result); +error: + isl_basic_map_free(result); + return NULL; +} + +/* Given a map A -> f(A) and an integer d, construct a map + * A -> floor(f(A)/d). + */ +__isl_give isl_map *isl_map_floordiv(__isl_take isl_map *map, isl_int d) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + ISL_F_CLR(map, ISL_MAP_DISJOINT); + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_floordiv(map->p[i], d); + if (!map->p[i]) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Given a map A -> f(A) and an integer d, construct a map + * A -> floor(f(A)/d). + */ +__isl_give isl_map *isl_map_floordiv_val(__isl_take isl_map *map, + __isl_take isl_val *d) +{ + if (!map || !d) + goto error; + if (!isl_val_is_int(d)) + isl_die(isl_val_get_ctx(d), isl_error_invalid, + "expecting integer denominator", goto error); + map = isl_map_floordiv(map, d->n); + isl_val_free(d); + return map; +error: + isl_map_free(map); + isl_val_free(d); + return NULL; +} + +static __isl_give isl_basic_map *var_equal(__isl_take isl_basic_map *bmap, + unsigned pos) +{ + int i; + unsigned nparam; + unsigned n_in; + + i = isl_basic_map_alloc_equality(bmap); + if (i < 0) + goto error; + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->eq[i][1+nparam+pos], -1); + isl_int_set_si(bmap->eq[i][1+nparam+n_in+pos], 1); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Add a constraint to "bmap" expressing i_pos < o_pos + */ +static __isl_give isl_basic_map *var_less(__isl_take isl_basic_map *bmap, + unsigned pos) +{ + int i; + unsigned nparam; + unsigned n_in; + + i = isl_basic_map_alloc_inequality(bmap); + if (i < 0) + goto error; + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->ineq[i][0], -1); + isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1); + isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Add a constraint to "bmap" expressing i_pos <= o_pos + */ +static __isl_give isl_basic_map *var_less_or_equal( + __isl_take isl_basic_map *bmap, unsigned pos) +{ + int i; + unsigned nparam; + unsigned n_in; + + i = isl_basic_map_alloc_inequality(bmap); + if (i < 0) + goto error; + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1); + isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Add a constraint to "bmap" expressing i_pos > o_pos + */ +static __isl_give isl_basic_map *var_more(__isl_take isl_basic_map *bmap, + unsigned pos) +{ + int i; + unsigned nparam; + unsigned n_in; + + i = isl_basic_map_alloc_inequality(bmap); + if (i < 0) + goto error; + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->ineq[i][0], -1); + isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1); + isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Add a constraint to "bmap" expressing i_pos >= o_pos + */ +static __isl_give isl_basic_map *var_more_or_equal( + __isl_take isl_basic_map *bmap, unsigned pos) +{ + int i; + unsigned nparam; + unsigned n_in; + + i = isl_basic_map_alloc_inequality(bmap); + if (i < 0) + goto error; + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1); + isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_equal( + __isl_take isl_space *dim, unsigned n_equal) +{ + int i; + struct isl_basic_map *bmap; + bmap = isl_basic_map_alloc_space(dim, 0, n_equal, 0); + if (!bmap) + return NULL; + for (i = 0; i < n_equal && bmap; ++i) + bmap = var_equal(bmap, i); + return isl_basic_map_finalize(bmap); +} + +/* Return a relation on of dimension "dim" expressing i_[0..pos] << o_[0..pos] + */ +__isl_give isl_basic_map *isl_basic_map_less_at(__isl_take isl_space *dim, + unsigned pos) +{ + int i; + struct isl_basic_map *bmap; + bmap = isl_basic_map_alloc_space(dim, 0, pos, 1); + if (!bmap) + return NULL; + for (i = 0; i < pos && bmap; ++i) + bmap = var_equal(bmap, i); + if (bmap) + bmap = var_less(bmap, pos); + return isl_basic_map_finalize(bmap); +} + +/* Return a relation on "dim" expressing i_[0..pos] <<= o_[0..pos] + */ +__isl_give isl_basic_map *isl_basic_map_less_or_equal_at( + __isl_take isl_space *dim, unsigned pos) +{ + int i; + isl_basic_map *bmap; + + bmap = isl_basic_map_alloc_space(dim, 0, pos, 1); + for (i = 0; i < pos; ++i) + bmap = var_equal(bmap, i); + bmap = var_less_or_equal(bmap, pos); + return isl_basic_map_finalize(bmap); +} + +/* Return a relation on "dim" expressing i_pos > o_pos + */ +__isl_give isl_basic_map *isl_basic_map_more_at(__isl_take isl_space *dim, + unsigned pos) +{ + int i; + struct isl_basic_map *bmap; + bmap = isl_basic_map_alloc_space(dim, 0, pos, 1); + if (!bmap) + return NULL; + for (i = 0; i < pos && bmap; ++i) + bmap = var_equal(bmap, i); + if (bmap) + bmap = var_more(bmap, pos); + return isl_basic_map_finalize(bmap); +} + +/* Return a relation on "dim" expressing i_[0..pos] >>= o_[0..pos] + */ +__isl_give isl_basic_map *isl_basic_map_more_or_equal_at( + __isl_take isl_space *dim, unsigned pos) +{ + int i; + isl_basic_map *bmap; + + bmap = isl_basic_map_alloc_space(dim, 0, pos, 1); + for (i = 0; i < pos; ++i) + bmap = var_equal(bmap, i); + bmap = var_more_or_equal(bmap, pos); + return isl_basic_map_finalize(bmap); +} + +static __isl_give isl_map *map_lex_lte_first(__isl_take isl_space *dims, + unsigned n, int equal) +{ + struct isl_map *map; + int i; + + if (n == 0 && equal) + return isl_map_universe(dims); + + map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT); + + for (i = 0; i + 1 < n; ++i) + map = isl_map_add_basic_map(map, + isl_basic_map_less_at(isl_space_copy(dims), i)); + if (n > 0) { + if (equal) + map = isl_map_add_basic_map(map, + isl_basic_map_less_or_equal_at(dims, n - 1)); + else + map = isl_map_add_basic_map(map, + isl_basic_map_less_at(dims, n - 1)); + } else + isl_space_free(dims); + + return map; +} + +static __isl_give isl_map *map_lex_lte(__isl_take isl_space *dims, int equal) +{ + if (!dims) + return NULL; + return map_lex_lte_first(dims, dims->n_out, equal); +} + +__isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_space *dim, unsigned n) +{ + return map_lex_lte_first(dim, n, 0); +} + +__isl_give isl_map *isl_map_lex_le_first(__isl_take isl_space *dim, unsigned n) +{ + return map_lex_lte_first(dim, n, 1); +} + +__isl_give isl_map *isl_map_lex_lt(__isl_take isl_space *set_dim) +{ + return map_lex_lte(isl_space_map_from_set(set_dim), 0); +} + +__isl_give isl_map *isl_map_lex_le(__isl_take isl_space *set_dim) +{ + return map_lex_lte(isl_space_map_from_set(set_dim), 1); +} + +static __isl_give isl_map *map_lex_gte_first(__isl_take isl_space *dims, + unsigned n, int equal) +{ + struct isl_map *map; + int i; + + if (n == 0 && equal) + return isl_map_universe(dims); + + map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT); + + for (i = 0; i + 1 < n; ++i) + map = isl_map_add_basic_map(map, + isl_basic_map_more_at(isl_space_copy(dims), i)); + if (n > 0) { + if (equal) + map = isl_map_add_basic_map(map, + isl_basic_map_more_or_equal_at(dims, n - 1)); + else + map = isl_map_add_basic_map(map, + isl_basic_map_more_at(dims, n - 1)); + } else + isl_space_free(dims); + + return map; +} + +static __isl_give isl_map *map_lex_gte(__isl_take isl_space *dims, int equal) +{ + if (!dims) + return NULL; + return map_lex_gte_first(dims, dims->n_out, equal); +} + +__isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_space *dim, unsigned n) +{ + return map_lex_gte_first(dim, n, 0); +} + +__isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_space *dim, unsigned n) +{ + return map_lex_gte_first(dim, n, 1); +} + +__isl_give isl_map *isl_map_lex_gt(__isl_take isl_space *set_dim) +{ + return map_lex_gte(isl_space_map_from_set(set_dim), 0); +} + +__isl_give isl_map *isl_map_lex_ge(__isl_take isl_space *set_dim) +{ + return map_lex_gte(isl_space_map_from_set(set_dim), 1); +} + +__isl_give isl_map *isl_set_lex_le_set(__isl_take isl_set *set1, + __isl_take isl_set *set2) +{ + isl_map *map; + map = isl_map_lex_le(isl_set_get_space(set1)); + map = isl_map_intersect_domain(map, set1); + map = isl_map_intersect_range(map, set2); + return map; +} + +__isl_give isl_map *isl_set_lex_lt_set(__isl_take isl_set *set1, + __isl_take isl_set *set2) +{ + isl_map *map; + map = isl_map_lex_lt(isl_set_get_space(set1)); + map = isl_map_intersect_domain(map, set1); + map = isl_map_intersect_range(map, set2); + return map; +} + +__isl_give isl_map *isl_set_lex_ge_set(__isl_take isl_set *set1, + __isl_take isl_set *set2) +{ + isl_map *map; + map = isl_map_lex_ge(isl_set_get_space(set1)); + map = isl_map_intersect_domain(map, set1); + map = isl_map_intersect_range(map, set2); + return map; +} + +__isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1, + __isl_take isl_set *set2) +{ + isl_map *map; + map = isl_map_lex_gt(isl_set_get_space(set1)); + map = isl_map_intersect_domain(map, set1); + map = isl_map_intersect_range(map, set2); + return map; +} + +__isl_give isl_map *isl_map_lex_le_map(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_map *map; + map = isl_map_lex_le(isl_space_range(isl_map_get_space(map1))); + map = isl_map_apply_domain(map, isl_map_reverse(map1)); + map = isl_map_apply_range(map, isl_map_reverse(map2)); + return map; +} + +__isl_give isl_map *isl_map_lex_lt_map(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_map *map; + map = isl_map_lex_lt(isl_space_range(isl_map_get_space(map1))); + map = isl_map_apply_domain(map, isl_map_reverse(map1)); + map = isl_map_apply_range(map, isl_map_reverse(map2)); + return map; +} + +__isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_map *map; + map = isl_map_lex_ge(isl_space_range(isl_map_get_space(map1))); + map = isl_map_apply_domain(map, isl_map_reverse(map1)); + map = isl_map_apply_range(map, isl_map_reverse(map2)); + return map; +} + +__isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_map *map; + map = isl_map_lex_gt(isl_space_range(isl_map_get_space(map1))); + map = isl_map_apply_domain(map, isl_map_reverse(map1)); + map = isl_map_apply_range(map, isl_map_reverse(map2)); + return map; +} + +/* For a div d = floor(f/m), add the constraint + * + * f - m d >= 0 + */ +static isl_stat add_upper_div_constraint(__isl_keep isl_basic_map *bmap, + unsigned pos, isl_int *div) +{ + int i; + unsigned total = isl_basic_map_total_dim(bmap); + + i = isl_basic_map_alloc_inequality(bmap); + if (i < 0) + return isl_stat_error; + isl_seq_cpy(bmap->ineq[i], div + 1, 1 + total); + isl_int_neg(bmap->ineq[i][1 + pos], div[0]); + + return isl_stat_ok; +} + +/* For a div d = floor(f/m), add the constraint + * + * -(f-(m-1)) + m d >= 0 + */ +static isl_stat add_lower_div_constraint(__isl_keep isl_basic_map *bmap, + unsigned pos, isl_int *div) +{ + int i; + unsigned total = isl_basic_map_total_dim(bmap); + + i = isl_basic_map_alloc_inequality(bmap); + if (i < 0) + return isl_stat_error; + isl_seq_neg(bmap->ineq[i], div + 1, 1 + total); + isl_int_set(bmap->ineq[i][1 + pos], div[0]); + isl_int_add(bmap->ineq[i][0], bmap->ineq[i][0], bmap->ineq[i][1 + pos]); + isl_int_sub_ui(bmap->ineq[i][0], bmap->ineq[i][0], 1); + + return isl_stat_ok; +} + +/* For a div d = floor(f/m), add the constraints + * + * f - m d >= 0 + * -(f-(m-1)) + m d >= 0 + * + * Note that the second constraint is the negation of + * + * f - m d >= m + */ +int isl_basic_map_add_div_constraints_var(__isl_keep isl_basic_map *bmap, + unsigned pos, isl_int *div) +{ + if (add_upper_div_constraint(bmap, pos, div) < 0) + return -1; + if (add_lower_div_constraint(bmap, pos, div) < 0) + return -1; + return 0; +} + +int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset, + unsigned pos, isl_int *div) +{ + return isl_basic_map_add_div_constraints_var(bset_to_bmap(bset), + pos, div); +} + +int isl_basic_map_add_div_constraints(struct isl_basic_map *bmap, unsigned div) +{ + unsigned total = isl_basic_map_total_dim(bmap); + unsigned div_pos = total - bmap->n_div + div; + + return isl_basic_map_add_div_constraints_var(bmap, div_pos, + bmap->div[div]); +} + +/* For each known div d = floor(f/m), add the constraints + * + * f - m d >= 0 + * -(f-(m-1)) + m d >= 0 + * + * Remove duplicate constraints in case of some these div constraints + * already appear in "bmap". + */ +__isl_give isl_basic_map *isl_basic_map_add_known_div_constraints( + __isl_take isl_basic_map *bmap) +{ + unsigned n_div; + + if (!bmap) + return NULL; + n_div = isl_basic_map_dim(bmap, isl_dim_div); + if (n_div == 0) + return bmap; + + bmap = add_known_div_constraints(bmap); + bmap = isl_basic_map_remove_duplicate_constraints(bmap, NULL, 0); + bmap = isl_basic_map_finalize(bmap); + return bmap; +} + +/* Add the div constraint of sign "sign" for div "div" of "bmap". + * + * In particular, if this div is of the form d = floor(f/m), + * then add the constraint + * + * f - m d >= 0 + * + * if sign < 0 or the constraint + * + * -(f-(m-1)) + m d >= 0 + * + * if sign > 0. + */ +int isl_basic_map_add_div_constraint(__isl_keep isl_basic_map *bmap, + unsigned div, int sign) +{ + unsigned total; + unsigned div_pos; + + if (!bmap) + return -1; + + total = isl_basic_map_total_dim(bmap); + div_pos = total - bmap->n_div + div; + + if (sign < 0) + return add_upper_div_constraint(bmap, div_pos, bmap->div[div]); + else + return add_lower_div_constraint(bmap, div_pos, bmap->div[div]); +} + +__isl_give isl_basic_set *isl_basic_map_underlying_set( + __isl_take isl_basic_map *bmap) +{ + if (!bmap) + goto error; + if (bmap->dim->nparam == 0 && bmap->dim->n_in == 0 && + bmap->n_div == 0 && + !isl_space_is_named_or_nested(bmap->dim, isl_dim_in) && + !isl_space_is_named_or_nested(bmap->dim, isl_dim_out)) + return bset_from_bmap(bmap); + bmap = isl_basic_map_cow(bmap); + if (!bmap) + goto error; + bmap->dim = isl_space_underlying(bmap->dim, bmap->n_div); + if (!bmap->dim) + goto error; + bmap->extra -= bmap->n_div; + bmap->n_div = 0; + bmap = isl_basic_map_finalize(bmap); + return bset_from_bmap(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_underlying_set( + __isl_take isl_basic_set *bset) +{ + return isl_basic_map_underlying_set(bset_to_bmap(bset)); +} + +/* Replace each element in "list" by the result of applying + * isl_basic_map_underlying_set to the element. + */ +__isl_give isl_basic_set_list *isl_basic_map_list_underlying_set( + __isl_take isl_basic_map_list *list) +{ + int i, n; + + if (!list) + return NULL; + + n = isl_basic_map_list_n_basic_map(list); + for (i = 0; i < n; ++i) { + isl_basic_map *bmap; + isl_basic_set *bset; + + bmap = isl_basic_map_list_get_basic_map(list, i); + bset = isl_basic_set_underlying_set(bmap); + list = isl_basic_set_list_set_basic_set(list, i, bset); + } + + return list; +} + +__isl_give isl_basic_map *isl_basic_map_overlying_set( + __isl_take isl_basic_set *bset, __isl_take isl_basic_map *like) +{ + struct isl_basic_map *bmap; + struct isl_ctx *ctx; + unsigned total; + int i; + + if (!bset || !like) + goto error; + ctx = bset->ctx; + isl_assert(ctx, bset->n_div == 0, goto error); + isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error); + isl_assert(ctx, bset->dim->n_out == isl_basic_map_total_dim(like), + goto error); + if (like->n_div == 0) { + isl_space *space = isl_basic_map_get_space(like); + isl_basic_map_free(like); + return isl_basic_map_reset_space(bset, space); + } + bset = isl_basic_set_cow(bset); + if (!bset) + goto error; + total = bset->dim->n_out + bset->extra; + bmap = bset_to_bmap(bset); + isl_space_free(bmap->dim); + bmap->dim = isl_space_copy(like->dim); + if (!bmap->dim) + goto error; + bmap->n_div = like->n_div; + bmap->extra += like->n_div; + if (bmap->extra) { + unsigned ltotal; + isl_int **div; + ltotal = total - bmap->extra + like->extra; + if (ltotal > total) + ltotal = total; + bmap->block2 = isl_blk_extend(ctx, bmap->block2, + bmap->extra * (1 + 1 + total)); + if (isl_blk_is_error(bmap->block2)) + goto error; + div = isl_realloc_array(ctx, bmap->div, isl_int *, bmap->extra); + if (!div) + goto error; + bmap->div = div; + for (i = 0; i < bmap->extra; ++i) + bmap->div[i] = bmap->block2.data + i * (1 + 1 + total); + for (i = 0; i < like->n_div; ++i) { + isl_seq_cpy(bmap->div[i], like->div[i], 1 + 1 + ltotal); + isl_seq_clr(bmap->div[i]+1+1+ltotal, total - ltotal); + } + bmap = isl_basic_map_add_known_div_constraints(bmap); + } + isl_basic_map_free(like); + bmap = isl_basic_map_simplify(bmap); + bmap = isl_basic_map_finalize(bmap); + return bmap; +error: + isl_basic_map_free(like); + isl_basic_set_free(bset); + return NULL; +} + +struct isl_basic_set *isl_basic_set_from_underlying_set( + struct isl_basic_set *bset, struct isl_basic_set *like) +{ + return bset_from_bmap(isl_basic_map_overlying_set(bset, + bset_to_bmap(like))); +} + +__isl_give isl_set *isl_map_underlying_set(__isl_take isl_map *map) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + map->dim = isl_space_cow(map->dim); + if (!map->dim) + goto error; + + for (i = 1; i < map->n; ++i) + isl_assert(map->ctx, map->p[0]->n_div == map->p[i]->n_div, + goto error); + for (i = 0; i < map->n; ++i) { + map->p[i] = bset_to_bmap( + isl_basic_map_underlying_set(map->p[i])); + if (!map->p[i]) + goto error; + } + if (map->n == 0) + map->dim = isl_space_underlying(map->dim, 0); + else { + isl_space_free(map->dim); + map->dim = isl_space_copy(map->p[0]->dim); + } + if (!map->dim) + goto error; + return set_from_map(map); +error: + isl_map_free(map); + return NULL; +} + +/* Replace the space of "bmap" by "space". + * + * If the space of "bmap" is identical to "space" (including the identifiers + * of the input and output dimensions), then simply return the original input. + */ +__isl_give isl_basic_map *isl_basic_map_reset_space( + __isl_take isl_basic_map *bmap, __isl_take isl_space *space) +{ + isl_bool equal; + isl_space *bmap_space; + + bmap_space = isl_basic_map_peek_space(bmap); + equal = isl_space_is_equal(bmap_space, space); + if (equal >= 0 && equal) + equal = isl_space_has_equal_ids(bmap_space, space); + if (equal < 0) + goto error; + if (equal) { + isl_space_free(space); + return bmap; + } + bmap = isl_basic_map_cow(bmap); + if (!bmap || !space) + goto error; + + isl_space_free(bmap->dim); + bmap->dim = space; + + bmap = isl_basic_map_finalize(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + isl_space_free(space); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_reset_space( + __isl_take isl_basic_set *bset, __isl_take isl_space *dim) +{ + return bset_from_bmap(isl_basic_map_reset_space(bset_to_bmap(bset), + dim)); +} + +__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map, + __isl_take isl_space *dim) +{ + int i; + + map = isl_map_cow(map); + if (!map || !dim) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_reset_space(map->p[i], + isl_space_copy(dim)); + if (!map->p[i]) + goto error; + } + isl_space_free(map->dim); + map->dim = dim; + + return map; +error: + isl_map_free(map); + isl_space_free(dim); + return NULL; +} + +__isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set, + __isl_take isl_space *dim) +{ + return set_from_map(isl_map_reset_space(set_to_map(set), dim)); +} + +/* Compute the parameter domain of the given basic set. + */ +__isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset) +{ + isl_bool is_params; + isl_space *space; + unsigned n; + + is_params = isl_basic_set_is_params(bset); + if (is_params < 0) + return isl_basic_set_free(bset); + if (is_params) + return bset; + + n = isl_basic_set_dim(bset, isl_dim_set); + bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n); + space = isl_basic_set_get_space(bset); + space = isl_space_params(space); + bset = isl_basic_set_reset_space(bset, space); + return bset; +} + +/* Construct a zero-dimensional basic set with the given parameter domain. + */ +__isl_give isl_basic_set *isl_basic_set_from_params( + __isl_take isl_basic_set *bset) +{ + isl_space *space; + space = isl_basic_set_get_space(bset); + space = isl_space_set_from_params(space); + bset = isl_basic_set_reset_space(bset, space); + return bset; +} + +/* Compute the parameter domain of the given set. + */ +__isl_give isl_set *isl_set_params(__isl_take isl_set *set) +{ + isl_space *space; + unsigned n; + + if (isl_set_is_params(set)) + return set; + + n = isl_set_dim(set, isl_dim_set); + set = isl_set_project_out(set, isl_dim_set, 0, n); + space = isl_set_get_space(set); + space = isl_space_params(space); + set = isl_set_reset_space(set, space); + return set; +} + +/* Construct a zero-dimensional set with the given parameter domain. + */ +__isl_give isl_set *isl_set_from_params(__isl_take isl_set *set) +{ + isl_space *space; + space = isl_set_get_space(set); + space = isl_space_set_from_params(space); + set = isl_set_reset_space(set, space); + return set; +} + +/* Compute the parameter domain of the given map. + */ +__isl_give isl_set *isl_map_params(__isl_take isl_map *map) +{ + isl_space *space; + unsigned n; + + n = isl_map_dim(map, isl_dim_in); + map = isl_map_project_out(map, isl_dim_in, 0, n); + n = isl_map_dim(map, isl_dim_out); + map = isl_map_project_out(map, isl_dim_out, 0, n); + space = isl_map_get_space(map); + space = isl_space_params(space); + map = isl_map_reset_space(map, space); + return map; +} + +struct isl_basic_set *isl_basic_map_domain(struct isl_basic_map *bmap) +{ + isl_space *space; + unsigned n_out; + + if (!bmap) + return NULL; + space = isl_space_domain(isl_basic_map_get_space(bmap)); + + n_out = isl_basic_map_dim(bmap, isl_dim_out); + bmap = isl_basic_map_project_out(bmap, isl_dim_out, 0, n_out); + + return isl_basic_map_reset_space(bmap, space); +} + +isl_bool isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + return isl_space_may_be_set(bmap->dim); +} + +/* Is this basic map actually a set? + * Users should never call this function. Outside of isl, + * the type should indicate whether something is a set or a map. + */ +isl_bool isl_basic_map_is_set(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + return isl_space_is_set(bmap->dim); +} + +struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap) +{ + isl_bool is_set; + + is_set = isl_basic_map_is_set(bmap); + if (is_set < 0) + goto error; + if (is_set) + return bmap; + return isl_basic_map_domain(isl_basic_map_reverse(bmap)); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_domain_map( + __isl_take isl_basic_map *bmap) +{ + int i; + isl_space *dim; + isl_basic_map *domain; + int nparam, n_in, n_out; + + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + + dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap))); + domain = isl_basic_map_universe(dim); + + bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap)); + bmap = isl_basic_map_apply_range(bmap, domain); + bmap = isl_basic_map_extend_constraints(bmap, n_in, 0); + + for (i = 0; i < n_in; ++i) + bmap = isl_basic_map_equate(bmap, isl_dim_in, i, + isl_dim_out, i); + + bmap = isl_basic_map_gauss(bmap, NULL); + return isl_basic_map_finalize(bmap); +} + +__isl_give isl_basic_map *isl_basic_map_range_map( + __isl_take isl_basic_map *bmap) +{ + int i; + isl_space *dim; + isl_basic_map *range; + int nparam, n_in, n_out; + + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + + dim = isl_space_from_range(isl_space_range(isl_basic_map_get_space(bmap))); + range = isl_basic_map_universe(dim); + + bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap)); + bmap = isl_basic_map_apply_range(bmap, range); + bmap = isl_basic_map_extend_constraints(bmap, n_out, 0); + + for (i = 0; i < n_out; ++i) + bmap = isl_basic_map_equate(bmap, isl_dim_in, n_in + i, + isl_dim_out, i); + + bmap = isl_basic_map_gauss(bmap, NULL); + return isl_basic_map_finalize(bmap); +} + +int isl_map_may_be_set(__isl_keep isl_map *map) +{ + if (!map) + return -1; + return isl_space_may_be_set(map->dim); +} + +/* Is this map actually a set? + * Users should never call this function. Outside of isl, + * the type should indicate whether something is a set or a map. + */ +isl_bool isl_map_is_set(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + return isl_space_is_set(map->dim); +} + +__isl_give isl_set *isl_map_range(__isl_take isl_map *map) +{ + int i; + isl_bool is_set; + struct isl_set *set; + + is_set = isl_map_is_set(map); + if (is_set < 0) + goto error; + if (is_set) + return set_from_map(map); + + map = isl_map_cow(map); + if (!map) + goto error; + + set = set_from_map(map); + set->dim = isl_space_range(set->dim); + if (!set->dim) + goto error; + for (i = 0; i < map->n; ++i) { + set->p[i] = isl_basic_map_range(map->p[i]); + if (!set->p[i]) + goto error; + } + ISL_F_CLR(set, ISL_MAP_DISJOINT); + ISL_F_CLR(set, ISL_SET_NORMALIZED); + return set; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + map->dim = isl_space_domain_map(map->dim); + if (!map->dim) + goto error; + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_domain_map(map->p[i]); + if (!map->p[i]) + goto error; + } + ISL_F_CLR(map, ISL_MAP_DISJOINT); + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_map *isl_map_range_map(__isl_take isl_map *map) +{ + int i; + isl_space *range_dim; + + map = isl_map_cow(map); + if (!map) + return NULL; + + range_dim = isl_space_range(isl_map_get_space(map)); + range_dim = isl_space_from_range(range_dim); + map->dim = isl_space_from_domain(isl_space_wrap(map->dim)); + map->dim = isl_space_join(map->dim, range_dim); + if (!map->dim) + goto error; + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_range_map(map->p[i]); + if (!map->p[i]) + goto error; + } + ISL_F_CLR(map, ISL_MAP_DISJOINT); + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Given a wrapped map of the form A[B -> C], + * return the map A[B -> C] -> B. + */ +__isl_give isl_map *isl_set_wrapped_domain_map(__isl_take isl_set *set) +{ + isl_id *id; + isl_map *map; + + if (!set) + return NULL; + if (!isl_set_has_tuple_id(set)) + return isl_map_domain_map(isl_set_unwrap(set)); + + id = isl_set_get_tuple_id(set); + map = isl_map_domain_map(isl_set_unwrap(set)); + map = isl_map_set_tuple_id(map, isl_dim_in, id); + + return map; +} + +__isl_give isl_basic_map *isl_basic_map_from_domain( + __isl_take isl_basic_set *bset) +{ + return isl_basic_map_reverse(isl_basic_map_from_range(bset)); +} + +__isl_give isl_basic_map *isl_basic_map_from_range( + __isl_take isl_basic_set *bset) +{ + isl_space *space; + space = isl_basic_set_get_space(bset); + space = isl_space_from_range(space); + bset = isl_basic_set_reset_space(bset, space); + return bset_to_bmap(bset); +} + +/* Create a relation with the given set as range. + * The domain of the created relation is a zero-dimensional + * flat anonymous space. + */ +__isl_give isl_map *isl_map_from_range(__isl_take isl_set *set) +{ + isl_space *space; + space = isl_set_get_space(set); + space = isl_space_from_range(space); + set = isl_set_reset_space(set, space); + return set_to_map(set); +} + +/* Create a relation with the given set as domain. + * The range of the created relation is a zero-dimensional + * flat anonymous space. + */ +__isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set) +{ + return isl_map_reverse(isl_map_from_range(set)); +} + +__isl_give isl_basic_map *isl_basic_map_from_domain_and_range( + __isl_take isl_basic_set *domain, __isl_take isl_basic_set *range) +{ + return isl_basic_map_apply_range(isl_basic_map_reverse(domain), range); +} + +__isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain, + __isl_take isl_set *range) +{ + return isl_map_apply_range(isl_map_reverse(domain), range); +} + +/* Return a newly allocated isl_map with given space and flags and + * room for "n" basic maps. + * Make sure that all cached information is cleared. + */ +__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *space, int n, + unsigned flags) +{ + struct isl_map *map; + + if (!space) + return NULL; + if (n < 0) + isl_die(space->ctx, isl_error_internal, + "negative number of basic maps", goto error); + map = isl_calloc(space->ctx, struct isl_map, + sizeof(struct isl_map) + + (n - 1) * sizeof(struct isl_basic_map *)); + if (!map) + goto error; + + map->ctx = space->ctx; + isl_ctx_ref(map->ctx); + map->ref = 1; + map->size = n; + map->n = 0; + map->dim = space; + map->flags = flags; + return map; +error: + isl_space_free(space); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_empty(__isl_take isl_space *space) +{ + struct isl_basic_map *bmap; + bmap = isl_basic_map_alloc_space(space, 0, 1, 0); + bmap = isl_basic_map_set_to_empty(bmap); + return bmap; +} + +__isl_give isl_basic_set *isl_basic_set_empty(__isl_take isl_space *space) +{ + struct isl_basic_set *bset; + bset = isl_basic_set_alloc_space(space, 0, 1, 0); + bset = isl_basic_set_set_to_empty(bset); + return bset; +} + +__isl_give isl_basic_map *isl_basic_map_universe(__isl_take isl_space *space) +{ + struct isl_basic_map *bmap; + bmap = isl_basic_map_alloc_space(space, 0, 0, 0); + bmap = isl_basic_map_finalize(bmap); + return bmap; +} + +__isl_give isl_basic_set *isl_basic_set_universe(__isl_take isl_space *space) +{ + struct isl_basic_set *bset; + bset = isl_basic_set_alloc_space(space, 0, 0, 0); + bset = isl_basic_set_finalize(bset); + return bset; +} + +__isl_give isl_basic_map *isl_basic_map_nat_universe(__isl_take isl_space *dim) +{ + int i; + unsigned total = isl_space_dim(dim, isl_dim_all); + isl_basic_map *bmap; + + bmap= isl_basic_map_alloc_space(dim, 0, 0, total); + for (i = 0; i < total; ++i) { + int k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->ineq[k], 1 + total); + isl_int_set_si(bmap->ineq[k][1 + i], 1); + } + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_nat_universe(__isl_take isl_space *dim) +{ + return isl_basic_map_nat_universe(dim); +} + +__isl_give isl_map *isl_map_nat_universe(__isl_take isl_space *dim) +{ + return isl_map_from_basic_map(isl_basic_map_nat_universe(dim)); +} + +__isl_give isl_set *isl_set_nat_universe(__isl_take isl_space *dim) +{ + return isl_map_nat_universe(dim); +} + +__isl_give isl_map *isl_map_empty(__isl_take isl_space *space) +{ + return isl_map_alloc_space(space, 0, ISL_MAP_DISJOINT); +} + +__isl_give isl_set *isl_set_empty(__isl_take isl_space *space) +{ + return isl_set_alloc_space(space, 0, ISL_MAP_DISJOINT); +} + +__isl_give isl_map *isl_map_universe(__isl_take isl_space *space) +{ + struct isl_map *map; + if (!space) + return NULL; + map = isl_map_alloc_space(isl_space_copy(space), 1, ISL_MAP_DISJOINT); + map = isl_map_add_basic_map(map, isl_basic_map_universe(space)); + return map; +} + +__isl_give isl_set *isl_set_universe(__isl_take isl_space *space) +{ + struct isl_set *set; + if (!space) + return NULL; + set = isl_set_alloc_space(isl_space_copy(space), 1, ISL_MAP_DISJOINT); + set = isl_set_add_basic_set(set, isl_basic_set_universe(space)); + return set; +} + +struct isl_map *isl_map_dup(struct isl_map *map) +{ + int i; + struct isl_map *dup; + + if (!map) + return NULL; + dup = isl_map_alloc_space(isl_space_copy(map->dim), map->n, map->flags); + for (i = 0; i < map->n; ++i) + dup = isl_map_add_basic_map(dup, isl_basic_map_copy(map->p[i])); + return dup; +} + +__isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map, + __isl_take isl_basic_map *bmap) +{ + if (!bmap || !map) + goto error; + if (isl_basic_map_plain_is_empty(bmap)) { + isl_basic_map_free(bmap); + return map; + } + isl_assert(map->ctx, isl_space_is_equal(map->dim, bmap->dim), goto error); + isl_assert(map->ctx, map->n < map->size, goto error); + map->p[map->n] = bmap; + map->n++; + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + if (map) + isl_map_free(map); + if (bmap) + isl_basic_map_free(bmap); + return NULL; +} + +__isl_null isl_map *isl_map_free(__isl_take isl_map *map) +{ + int i; + + if (!map) + return NULL; + + if (--map->ref > 0) + return NULL; + + clear_caches(map); + isl_ctx_deref(map->ctx); + for (i = 0; i < map->n; ++i) + isl_basic_map_free(map->p[i]); + isl_space_free(map->dim); + free(map); + + return NULL; +} + +static struct isl_basic_map *isl_basic_map_fix_pos_si( + struct isl_basic_map *bmap, unsigned pos, int value) +{ + int j; + + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_extend_constraints(bmap, 1, 0); + j = isl_basic_map_alloc_equality(bmap); + if (j < 0) + goto error; + isl_seq_clr(bmap->eq[j] + 1, isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->eq[j][pos], -1); + isl_int_set_si(bmap->eq[j][0], value); + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +static __isl_give isl_basic_map *isl_basic_map_fix_pos( + __isl_take isl_basic_map *bmap, unsigned pos, isl_int value) +{ + int j; + + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_extend_constraints(bmap, 1, 0); + j = isl_basic_map_alloc_equality(bmap); + if (j < 0) + goto error; + isl_seq_clr(bmap->eq[j] + 1, isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->eq[j][pos], -1); + isl_int_set(bmap->eq[j][0], value); + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_fix_si(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value) +{ + if (isl_basic_map_check_range(bmap, type, pos, 1) < 0) + return isl_basic_map_free(bmap); + return isl_basic_map_fix_pos_si(bmap, + isl_basic_map_offset(bmap, type) + pos, value); +} + +__isl_give isl_basic_map *isl_basic_map_fix(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + if (isl_basic_map_check_range(bmap, type, pos, 1) < 0) + return isl_basic_map_free(bmap); + return isl_basic_map_fix_pos(bmap, + isl_basic_map_offset(bmap, type) + pos, value); +} + +/* Fix the value of the variable at position "pos" of type "type" of "bmap" + * to be equal to "v". + */ +__isl_give isl_basic_map *isl_basic_map_fix_val(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) +{ + if (!bmap || !v) + goto error; + if (!isl_val_is_int(v)) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "expecting integer value", goto error); + if (isl_basic_map_check_range(bmap, type, pos, 1) < 0) + goto error; + pos += isl_basic_map_offset(bmap, type); + bmap = isl_basic_map_fix_pos(bmap, pos, v->n); + isl_val_free(v); + return bmap; +error: + isl_basic_map_free(bmap); + isl_val_free(v); + return NULL; +} + +/* Fix the value of the variable at position "pos" of type "type" of "bset" + * to be equal to "v". + */ +__isl_give isl_basic_set *isl_basic_set_fix_val(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) +{ + return isl_basic_map_fix_val(bset, type, pos, v); +} + +struct isl_basic_set *isl_basic_set_fix_si(struct isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, int value) +{ + return bset_from_bmap(isl_basic_map_fix_si(bset_to_bmap(bset), + type, pos, value)); +} + +__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return bset_from_bmap(isl_basic_map_fix(bset_to_bmap(bset), + type, pos, value)); +} + +struct isl_basic_map *isl_basic_map_fix_input_si(struct isl_basic_map *bmap, + unsigned input, int value) +{ + return isl_basic_map_fix_si(bmap, isl_dim_in, input, value); +} + +struct isl_basic_set *isl_basic_set_fix_dim_si(struct isl_basic_set *bset, + unsigned dim, int value) +{ + return bset_from_bmap(isl_basic_map_fix_si(bset_to_bmap(bset), + isl_dim_set, dim, value)); +} + +static int remove_if_empty(__isl_keep isl_map *map, int i) +{ + int empty = isl_basic_map_plain_is_empty(map->p[i]); + + if (empty < 0) + return -1; + if (!empty) + return 0; + + isl_basic_map_free(map->p[i]); + if (i != map->n - 1) { + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + map->p[i] = map->p[map->n - 1]; + } + map->n--; + + return 0; +} + +/* Perform "fn" on each basic map of "map", where we may not be holding + * the only reference to "map". + * In particular, "fn" should be a semantics preserving operation + * that we want to apply to all copies of "map". We therefore need + * to be careful not to modify "map" in a way that breaks "map" + * in case anything goes wrong. + */ +__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map, + __isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap)) +{ + struct isl_basic_map *bmap; + int i; + + if (!map) + return NULL; + + for (i = map->n - 1; i >= 0; --i) { + bmap = isl_basic_map_copy(map->p[i]); + bmap = fn(bmap); + if (!bmap) + goto error; + isl_basic_map_free(map->p[i]); + map->p[i] = bmap; + if (remove_if_empty(map, i) < 0) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_map *isl_map_fix_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error); + for (i = map->n - 1; i >= 0; --i) { + map->p[i] = isl_basic_map_fix_si(map->p[i], type, pos, value); + if (remove_if_empty(map, i) < 0) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value) +{ + return set_from_map(isl_map_fix_si(set_to_map(set), type, pos, value)); +} + +__isl_give isl_map *isl_map_fix(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error); + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_fix(map->p[i], type, pos, value); + if (!map->p[i]) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_fix(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return set_from_map(isl_map_fix(set_to_map(set), type, pos, value)); +} + +/* Fix the value of the variable at position "pos" of type "type" of "map" + * to be equal to "v". + */ +__isl_give isl_map *isl_map_fix_val(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) +{ + int i; + + map = isl_map_cow(map); + if (!map || !v) + goto error; + + if (!isl_val_is_int(v)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "expecting integer value", goto error); + if (pos >= isl_map_dim(map, type)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "index out of bounds", goto error); + for (i = map->n - 1; i >= 0; --i) { + map->p[i] = isl_basic_map_fix_val(map->p[i], type, pos, + isl_val_copy(v)); + if (remove_if_empty(map, i) < 0) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + isl_val_free(v); + return map; +error: + isl_map_free(map); + isl_val_free(v); + return NULL; +} + +/* Fix the value of the variable at position "pos" of type "type" of "set" + * to be equal to "v". + */ +__isl_give isl_set *isl_set_fix_val(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) +{ + return isl_map_fix_val(set, type, pos, v); +} + +struct isl_map *isl_map_fix_input_si(struct isl_map *map, + unsigned input, int value) +{ + return isl_map_fix_si(map, isl_dim_in, input, value); +} + +struct isl_set *isl_set_fix_dim_si(struct isl_set *set, unsigned dim, int value) +{ + return set_from_map(isl_map_fix_si(set_to_map(set), + isl_dim_set, dim, value)); +} + +static __isl_give isl_basic_map *basic_map_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value, int upper) +{ + int j; + + if (isl_basic_map_check_range(bmap, type, pos, 1) < 0) + return isl_basic_map_free(bmap); + pos += isl_basic_map_offset(bmap, type); + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_extend_constraints(bmap, 0, 1); + j = isl_basic_map_alloc_inequality(bmap); + if (j < 0) + goto error; + isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap)); + if (upper) { + isl_int_set_si(bmap->ineq[j][pos], -1); + isl_int_set_si(bmap->ineq[j][0], value); + } else { + isl_int_set_si(bmap->ineq[j][pos], 1); + isl_int_set_si(bmap->ineq[j][0], -value); + } + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_lower_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value) +{ + return basic_map_bound_si(bmap, type, pos, value, 0); +} + +/* Constrain the values of the given dimension to be no greater than "value". + */ +__isl_give isl_basic_map *isl_basic_map_upper_bound_si( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int value) +{ + return basic_map_bound_si(bmap, type, pos, value, 1); +} + +static __isl_give isl_map *map_bound_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value, int upper) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error); + for (i = 0; i < map->n; ++i) { + map->p[i] = basic_map_bound_si(map->p[i], + type, pos, value, upper); + if (!map->p[i]) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value) +{ + return map_bound_si(map, type, pos, value, 0); +} + +__isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int value) +{ + return map_bound_si(map, type, pos, value, 1); +} + +__isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value) +{ + return set_from_map(isl_map_lower_bound_si(set_to_map(set), + type, pos, value)); +} + +__isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, int value) +{ + return isl_map_upper_bound_si(set, type, pos, value); +} + +/* Bound the given variable of "bmap" from below (or above is "upper" + * is set) to "value". + */ +static __isl_give isl_basic_map *basic_map_bound( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, isl_int value, int upper) +{ + int j; + + if (isl_basic_map_check_range(bmap, type, pos, 1) < 0) + return isl_basic_map_free(bmap); + pos += isl_basic_map_offset(bmap, type); + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_extend_constraints(bmap, 0, 1); + j = isl_basic_map_alloc_inequality(bmap); + if (j < 0) + goto error; + isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap)); + if (upper) { + isl_int_set_si(bmap->ineq[j][pos], -1); + isl_int_set(bmap->ineq[j][0], value); + } else { + isl_int_set_si(bmap->ineq[j][pos], 1); + isl_int_neg(bmap->ineq[j][0], value); + } + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Bound the given variable of "map" from below (or above is "upper" + * is set) to "value". + */ +static __isl_give isl_map *map_bound(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, isl_int value, int upper) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + if (pos >= isl_map_dim(map, type)) + isl_die(map->ctx, isl_error_invalid, + "index out of bounds", goto error); + for (i = map->n - 1; i >= 0; --i) { + map->p[i] = basic_map_bound(map->p[i], type, pos, value, upper); + if (remove_if_empty(map, i) < 0) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_map *isl_map_lower_bound(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return map_bound(map, type, pos, value, 0); +} + +__isl_give isl_map *isl_map_upper_bound(__isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return map_bound(map, type, pos, value, 1); +} + +__isl_give isl_set *isl_set_lower_bound(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return isl_map_lower_bound(set, type, pos, value); +} + +__isl_give isl_set *isl_set_upper_bound(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, isl_int value) +{ + return isl_map_upper_bound(set, type, pos, value); +} + +/* Force the values of the variable at position "pos" of type "type" of "set" + * to be no smaller than "value". + */ +__isl_give isl_set *isl_set_lower_bound_val(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *value) +{ + if (!value) + goto error; + if (!isl_val_is_int(value)) + isl_die(isl_set_get_ctx(set), isl_error_invalid, + "expecting integer value", goto error); + set = isl_set_lower_bound(set, type, pos, value->n); + isl_val_free(value); + return set; +error: + isl_val_free(value); + isl_set_free(set); + return NULL; +} + +/* Force the values of the variable at position "pos" of type "type" of "set" + * to be no greater than "value". + */ +__isl_give isl_set *isl_set_upper_bound_val(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *value) +{ + if (!value) + goto error; + if (!isl_val_is_int(value)) + isl_die(isl_set_get_ctx(set), isl_error_invalid, + "expecting integer value", goto error); + set = isl_set_upper_bound(set, type, pos, value->n); + isl_val_free(value); + return set; +error: + isl_val_free(value); + isl_set_free(set); + return NULL; +} + +/* Bound the given variable of "bset" from below (or above is "upper" + * is set) to "value". + */ +static __isl_give isl_basic_set *isl_basic_set_bound( + __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, + isl_int value, int upper) +{ + return bset_from_bmap(basic_map_bound(bset_to_bmap(bset), + type, pos, value, upper)); +} + +/* Bound the given variable of "bset" from below (or above is "upper" + * is set) to "value". + */ +static __isl_give isl_basic_set *isl_basic_set_bound_val( + __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value, int upper) +{ + if (!value) + goto error; + if (!isl_val_is_int(value)) + isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, + "expecting integer value", goto error); + bset = isl_basic_set_bound(bset, type, pos, value->n, upper); + isl_val_free(value); + return bset; +error: + isl_val_free(value); + isl_basic_set_free(bset); + return NULL; +} + +/* Bound the given variable of "bset" from below to "value". + */ +__isl_give isl_basic_set *isl_basic_set_lower_bound_val( + __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value) +{ + return isl_basic_set_bound_val(bset, type, pos, value, 0); +} + +/* Bound the given variable of "bset" from above to "value". + */ +__isl_give isl_basic_set *isl_basic_set_upper_bound_val( + __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, + __isl_take isl_val *value) +{ + return isl_basic_set_bound_val(bset, type, pos, value, 1); +} + +__isl_give isl_map *isl_map_reverse(__isl_take isl_map *map) +{ + int i; + + map = isl_map_cow(map); + if (!map) + return NULL; + + map->dim = isl_space_reverse(map->dim); + if (!map->dim) + goto error; + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_reverse(map->p[i]); + if (!map->p[i]) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +#undef TYPE +#define TYPE isl_pw_multi_aff +#undef SUFFIX +#define SUFFIX _pw_multi_aff +#undef EMPTY +#define EMPTY isl_pw_multi_aff_empty +#undef ADD +#define ADD isl_pw_multi_aff_union_add +#include "isl_map_lexopt_templ.c" + +/* Given a map "map", compute the lexicographically minimal + * (or maximal) image element for each domain element in dom, + * in the form of an isl_pw_multi_aff. + * If "empty" is not NULL, then set *empty to those elements in dom that + * do not have an image element. + * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum + * should be computed over the domain of "map". "empty" is also NULL + * in this case. + * + * We first compute the lexicographically minimal or maximal element + * in the first basic map. This results in a partial solution "res" + * and a subset "todo" of dom that still need to be handled. + * We then consider each of the remaining maps in "map" and successively + * update both "res" and "todo". + * If "empty" is NULL, then the todo sets are not needed and therefore + * also not computed. + */ +static __isl_give isl_pw_multi_aff *isl_map_partial_lexopt_aligned_pw_multi_aff( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty, unsigned flags) +{ + int i; + int full; + isl_pw_multi_aff *res; + isl_set *todo; + + full = ISL_FL_ISSET(flags, ISL_OPT_FULL); + if (!map || (!full && !dom)) + goto error; + + if (isl_map_plain_is_empty(map)) { + if (empty) + *empty = dom; + else + isl_set_free(dom); + return isl_pw_multi_aff_from_map(map); + } + + res = basic_map_partial_lexopt_pw_multi_aff( + isl_basic_map_copy(map->p[0]), + isl_set_copy(dom), empty, flags); + + if (empty) + todo = *empty; + for (i = 1; i < map->n; ++i) { + isl_pw_multi_aff *res_i; + + res_i = basic_map_partial_lexopt_pw_multi_aff( + isl_basic_map_copy(map->p[i]), + isl_set_copy(dom), empty, flags); + + if (ISL_FL_ISSET(flags, ISL_OPT_MAX)) + res = isl_pw_multi_aff_union_lexmax(res, res_i); + else + res = isl_pw_multi_aff_union_lexmin(res, res_i); + + if (empty) + todo = isl_set_intersect(todo, *empty); + } + + isl_set_free(dom); + isl_map_free(map); + + if (empty) + *empty = todo; + + return res; +error: + if (empty) + *empty = NULL; + isl_set_free(dom); + isl_map_free(map); + return NULL; +} + +#undef TYPE +#define TYPE isl_map +#undef SUFFIX +#define SUFFIX +#undef EMPTY +#define EMPTY isl_map_empty +#undef ADD +#define ADD isl_map_union_disjoint +#include "isl_map_lexopt_templ.c" + +/* Given a map "map", compute the lexicographically minimal + * (or maximal) image element for each domain element in "dom", + * in the form of an isl_map. + * If "empty" is not NULL, then set *empty to those elements in "dom" that + * do not have an image element. + * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum + * should be computed over the domain of "map". "empty" is also NULL + * in this case. + * + * If the input consists of more than one disjunct, then first + * compute the desired result in the form of an isl_pw_multi_aff and + * then convert that into an isl_map. + * + * This function used to have an explicit implementation in terms + * of isl_maps, but it would continually intersect the domains of + * partial results with the complement of the domain of the next + * partial solution, potentially leading to an explosion in the number + * of disjuncts if there are several disjuncts in the input. + * An even earlier implementation of this function would look for + * better results in the domain of the partial result and for extra + * results in the complement of this domain, which would lead to + * even more splintering. + */ +static __isl_give isl_map *isl_map_partial_lexopt_aligned( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty, unsigned flags) +{ + int full; + struct isl_map *res; + isl_pw_multi_aff *pma; + + full = ISL_FL_ISSET(flags, ISL_OPT_FULL); + if (!map || (!full && !dom)) + goto error; + + if (isl_map_plain_is_empty(map)) { + if (empty) + *empty = dom; + else + isl_set_free(dom); + return map; + } + + if (map->n == 1) { + res = basic_map_partial_lexopt(isl_basic_map_copy(map->p[0]), + dom, empty, flags); + isl_map_free(map); + return res; + } + + pma = isl_map_partial_lexopt_aligned_pw_multi_aff(map, dom, empty, + flags); + return isl_map_from_pw_multi_aff(pma); +error: + if (empty) + *empty = NULL; + isl_set_free(dom); + isl_map_free(map); + return NULL; +} + +__isl_give isl_map *isl_map_partial_lexmax( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty) +{ + return isl_map_partial_lexopt(map, dom, empty, ISL_OPT_MAX); +} + +__isl_give isl_map *isl_map_partial_lexmin( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty) +{ + return isl_map_partial_lexopt(map, dom, empty, 0); +} + +__isl_give isl_set *isl_set_partial_lexmin( + __isl_take isl_set *set, __isl_take isl_set *dom, + __isl_give isl_set **empty) +{ + return set_from_map(isl_map_partial_lexmin(set_to_map(set), + dom, empty)); +} + +__isl_give isl_set *isl_set_partial_lexmax( + __isl_take isl_set *set, __isl_take isl_set *dom, + __isl_give isl_set **empty) +{ + return set_from_map(isl_map_partial_lexmax(set_to_map(set), + dom, empty)); +} + +/* Compute the lexicographic minimum (or maximum if "flags" includes + * ISL_OPT_MAX) of "bset" over its parametric domain. + */ +__isl_give isl_set *isl_basic_set_lexopt(__isl_take isl_basic_set *bset, + unsigned flags) +{ + return isl_basic_map_lexopt(bset, flags); +} + +__isl_give isl_map *isl_basic_map_lexmax(__isl_take isl_basic_map *bmap) +{ + return isl_basic_map_lexopt(bmap, ISL_OPT_MAX); +} + +__isl_give isl_set *isl_basic_set_lexmin(__isl_take isl_basic_set *bset) +{ + return set_from_map(isl_basic_map_lexmin(bset_to_bmap(bset))); +} + +__isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset) +{ + return set_from_map(isl_basic_map_lexmax(bset_to_bmap(bset))); +} + +/* Compute the lexicographic minimum of "bset" over its parametric domain + * for the purpose of quantifier elimination. + * That is, find an explicit representation for all the existentially + * quantified variables in "bset" by computing their lexicographic + * minimum. + */ +static __isl_give isl_set *isl_basic_set_lexmin_compute_divs( + __isl_take isl_basic_set *bset) +{ + return isl_basic_set_lexopt(bset, ISL_OPT_QE); +} + +/* Given a basic map with one output dimension, compute the minimum or + * maximum of that dimension as an isl_pw_aff. + * + * Compute the optimum as a lexicographic optimum over the single + * output dimension and extract the single isl_pw_aff from the result. + */ +static __isl_give isl_pw_aff *basic_map_dim_opt(__isl_keep isl_basic_map *bmap, + int max) +{ + isl_pw_multi_aff *pma; + isl_pw_aff *pwaff; + + bmap = isl_basic_map_copy(bmap); + pma = isl_basic_map_lexopt_pw_multi_aff(bmap, max ? ISL_OPT_MAX : 0); + pwaff = isl_pw_multi_aff_get_pw_aff(pma, 0); + isl_pw_multi_aff_free(pma); + + return pwaff; +} + +/* Compute the minimum or maximum of the given output dimension + * as a function of the parameters and the input dimensions, + * but independently of the other output dimensions. + * + * We first project out the other output dimension and then compute + * the "lexicographic" maximum in each basic map, combining the results + * using isl_pw_aff_union_max. + */ +static __isl_give isl_pw_aff *map_dim_opt(__isl_take isl_map *map, int pos, + int max) +{ + int i; + isl_pw_aff *pwaff; + unsigned n_out; + + n_out = isl_map_dim(map, isl_dim_out); + map = isl_map_project_out(map, isl_dim_out, pos + 1, n_out - (pos + 1)); + map = isl_map_project_out(map, isl_dim_out, 0, pos); + if (!map) + return NULL; + + if (map->n == 0) { + isl_space *dim = isl_map_get_space(map); + isl_map_free(map); + return isl_pw_aff_empty(dim); + } + + pwaff = basic_map_dim_opt(map->p[0], max); + for (i = 1; i < map->n; ++i) { + isl_pw_aff *pwaff_i; + + pwaff_i = basic_map_dim_opt(map->p[i], max); + pwaff = isl_pw_aff_union_opt(pwaff, pwaff_i, max); + } + + isl_map_free(map); + + return pwaff; +} + +/* Compute the minimum of the given output dimension as a function of the + * parameters and input dimensions, but independently of + * the other output dimensions. + */ +__isl_give isl_pw_aff *isl_map_dim_min(__isl_take isl_map *map, int pos) +{ + return map_dim_opt(map, pos, 0); +} + +/* Compute the maximum of the given output dimension as a function of the + * parameters and input dimensions, but independently of + * the other output dimensions. + */ +__isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos) +{ + return map_dim_opt(map, pos, 1); +} + +/* Compute the minimum or maximum of the given set dimension + * as a function of the parameters, + * but independently of the other set dimensions. + */ +static __isl_give isl_pw_aff *set_dim_opt(__isl_take isl_set *set, int pos, + int max) +{ + return map_dim_opt(set, pos, max); +} + +/* Compute the maximum of the given set dimension as a function of the + * parameters, but independently of the other set dimensions. + */ +__isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos) +{ + return set_dim_opt(set, pos, 1); +} + +/* Compute the minimum of the given set dimension as a function of the + * parameters, but independently of the other set dimensions. + */ +__isl_give isl_pw_aff *isl_set_dim_min(__isl_take isl_set *set, int pos) +{ + return set_dim_opt(set, pos, 0); +} + +/* Apply a preimage specified by "mat" on the parameters of "bset". + * bset is assumed to have only parameters and divs. + */ +static __isl_give isl_basic_set *basic_set_parameter_preimage( + __isl_take isl_basic_set *bset, __isl_take isl_mat *mat) +{ + unsigned nparam; + + if (!bset || !mat) + goto error; + + bset->dim = isl_space_cow(bset->dim); + if (!bset->dim) + goto error; + + nparam = isl_basic_set_dim(bset, isl_dim_param); + + isl_assert(bset->ctx, mat->n_row == 1 + nparam, goto error); + + bset->dim->nparam = 0; + bset->dim->n_out = nparam; + bset = isl_basic_set_preimage(bset, mat); + if (bset) { + bset->dim->nparam = bset->dim->n_out; + bset->dim->n_out = 0; + } + return bset; +error: + isl_mat_free(mat); + isl_basic_set_free(bset); + return NULL; +} + +/* Apply a preimage specified by "mat" on the parameters of "set". + * set is assumed to have only parameters and divs. + */ +static __isl_give isl_set *set_parameter_preimage(__isl_take isl_set *set, + __isl_take isl_mat *mat) +{ + isl_space *space; + unsigned nparam; + + if (!set || !mat) + goto error; + + nparam = isl_set_dim(set, isl_dim_param); + + if (mat->n_row != 1 + nparam) + isl_die(isl_set_get_ctx(set), isl_error_internal, + "unexpected number of rows", goto error); + + space = isl_set_get_space(set); + space = isl_space_move_dims(space, isl_dim_set, 0, + isl_dim_param, 0, nparam); + set = isl_set_reset_space(set, space); + set = isl_set_preimage(set, mat); + nparam = isl_set_dim(set, isl_dim_out); + space = isl_set_get_space(set); + space = isl_space_move_dims(space, isl_dim_param, 0, + isl_dim_out, 0, nparam); + set = isl_set_reset_space(set, space); + return set; +error: + isl_mat_free(mat); + isl_set_free(set); + return NULL; +} + +/* Intersect the basic set "bset" with the affine space specified by the + * equalities in "eq". + */ +static __isl_give isl_basic_set *basic_set_append_equalities( + __isl_take isl_basic_set *bset, __isl_take isl_mat *eq) +{ + int i, k; + unsigned len; + + if (!bset || !eq) + goto error; + + bset = isl_basic_set_extend_space(bset, isl_space_copy(bset->dim), 0, + eq->n_row, 0); + if (!bset) + goto error; + + len = 1 + isl_space_dim(bset->dim, isl_dim_all) + bset->extra; + for (i = 0; i < eq->n_row; ++i) { + k = isl_basic_set_alloc_equality(bset); + if (k < 0) + goto error; + isl_seq_cpy(bset->eq[k], eq->row[i], eq->n_col); + isl_seq_clr(bset->eq[k] + eq->n_col, len - eq->n_col); + } + isl_mat_free(eq); + + bset = isl_basic_set_gauss(bset, NULL); + bset = isl_basic_set_finalize(bset); + + return bset; +error: + isl_mat_free(eq); + isl_basic_set_free(bset); + return NULL; +} + +/* Intersect the set "set" with the affine space specified by the + * equalities in "eq". + */ +static struct isl_set *set_append_equalities(struct isl_set *set, + struct isl_mat *eq) +{ + int i; + + if (!set || !eq) + goto error; + + for (i = 0; i < set->n; ++i) { + set->p[i] = basic_set_append_equalities(set->p[i], + isl_mat_copy(eq)); + if (!set->p[i]) + goto error; + } + isl_mat_free(eq); + return set; +error: + isl_mat_free(eq); + isl_set_free(set); + return NULL; +} + +/* Given a basic set "bset" that only involves parameters and existentially + * quantified variables, return the index of the first equality + * that only involves parameters. If there is no such equality then + * return bset->n_eq. + * + * This function assumes that isl_basic_set_gauss has been called on "bset". + */ +static int first_parameter_equality(__isl_keep isl_basic_set *bset) +{ + int i, j; + unsigned nparam, n_div; + + if (!bset) + return -1; + + nparam = isl_basic_set_dim(bset, isl_dim_param); + n_div = isl_basic_set_dim(bset, isl_dim_div); + + for (i = 0, j = n_div - 1; i < bset->n_eq && j >= 0; --j) { + if (!isl_int_is_zero(bset->eq[i][1 + nparam + j])) + ++i; + } + + return i; +} + +/* Compute an explicit representation for the existentially quantified + * variables in "bset" by computing the "minimal value" of the set + * variables. Since there are no set variables, the computation of + * the minimal value essentially computes an explicit representation + * of the non-empty part(s) of "bset". + * + * The input only involves parameters and existentially quantified variables. + * All equalities among parameters have been removed. + * + * Since the existentially quantified variables in the result are in general + * going to be different from those in the input, we first replace + * them by the minimal number of variables based on their equalities. + * This should simplify the parametric integer programming. + */ +static __isl_give isl_set *base_compute_divs(__isl_take isl_basic_set *bset) +{ + isl_morph *morph1, *morph2; + isl_set *set; + unsigned n; + + if (!bset) + return NULL; + if (bset->n_eq == 0) + return isl_basic_set_lexmin_compute_divs(bset); + + morph1 = isl_basic_set_parameter_compression(bset); + bset = isl_morph_basic_set(isl_morph_copy(morph1), bset); + bset = isl_basic_set_lift(bset); + morph2 = isl_basic_set_variable_compression(bset, isl_dim_set); + bset = isl_morph_basic_set(morph2, bset); + n = isl_basic_set_dim(bset, isl_dim_set); + bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n); + + set = isl_basic_set_lexmin_compute_divs(bset); + + set = isl_morph_set(isl_morph_inverse(morph1), set); + + return set; +} + +/* Project the given basic set onto its parameter domain, possibly introducing + * new, explicit, existential variables in the constraints. + * The input has parameters and (possibly implicit) existential variables. + * The output has the same parameters, but only + * explicit existentially quantified variables. + * + * The actual projection is performed by pip, but pip doesn't seem + * to like equalities very much, so we first remove the equalities + * among the parameters by performing a variable compression on + * the parameters. Afterward, an inverse transformation is performed + * and the equalities among the parameters are inserted back in. + * + * The variable compression on the parameters may uncover additional + * equalities that were only implicit before. We therefore check + * if there are any new parameter equalities in the result and + * if so recurse. The removal of parameter equalities is required + * for the parameter compression performed by base_compute_divs. + */ +static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset) +{ + int i; + struct isl_mat *eq; + struct isl_mat *T, *T2; + struct isl_set *set; + unsigned nparam; + + bset = isl_basic_set_cow(bset); + if (!bset) + return NULL; + + if (bset->n_eq == 0) + return base_compute_divs(bset); + + bset = isl_basic_set_gauss(bset, NULL); + if (!bset) + return NULL; + if (isl_basic_set_plain_is_empty(bset)) + return isl_set_from_basic_set(bset); + + i = first_parameter_equality(bset); + if (i == bset->n_eq) + return base_compute_divs(bset); + + nparam = isl_basic_set_dim(bset, isl_dim_param); + 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 (T && T->n_col == 0) { + isl_mat_free(T); + isl_mat_free(T2); + isl_mat_free(eq); + bset = isl_basic_set_set_to_empty(bset); + return isl_set_from_basic_set(bset); + } + bset = basic_set_parameter_preimage(bset, T); + + i = first_parameter_equality(bset); + if (!bset) + set = NULL; + else if (i == bset->n_eq) + set = base_compute_divs(bset); + else + set = parameter_compute_divs(bset); + set = set_parameter_preimage(set, T2); + set = set_append_equalities(set, eq); + return set; +} + +/* Insert the divs from "ls" before those of "bmap". + * + * The number of columns is not changed, which means that the last + * dimensions of "bmap" are being reintepreted as the divs from "ls". + * The caller is responsible for removing the same number of dimensions + * from the space of "bmap". + */ +static __isl_give isl_basic_map *insert_divs_from_local_space( + __isl_take isl_basic_map *bmap, __isl_keep isl_local_space *ls) +{ + int i; + int n_div; + int old_n_div; + + n_div = isl_local_space_dim(ls, isl_dim_div); + if (n_div == 0) + return bmap; + + old_n_div = bmap->n_div; + bmap = insert_div_rows(bmap, n_div); + if (!bmap) + return NULL; + + for (i = 0; i < n_div; ++i) { + isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col); + isl_seq_clr(bmap->div[i] + ls->div->n_col, old_n_div); + } + + return bmap; +} + +/* Replace the space of "bmap" by the space and divs of "ls". + * + * If "ls" has any divs, then we simplify the result since we may + * have discovered some additional equalities that could simplify + * the div expressions. + */ +static __isl_give isl_basic_map *basic_replace_space_by_local_space( + __isl_take isl_basic_map *bmap, __isl_take isl_local_space *ls) +{ + int n_div; + + bmap = isl_basic_map_cow(bmap); + if (!bmap || !ls) + goto error; + + n_div = isl_local_space_dim(ls, isl_dim_div); + bmap = insert_divs_from_local_space(bmap, ls); + if (!bmap) + goto error; + + isl_space_free(bmap->dim); + bmap->dim = isl_local_space_get_space(ls); + if (!bmap->dim) + goto error; + + isl_local_space_free(ls); + if (n_div > 0) + bmap = isl_basic_map_simplify(bmap); + bmap = isl_basic_map_finalize(bmap); + return bmap; +error: + isl_basic_map_free(bmap); + isl_local_space_free(ls); + return NULL; +} + +/* Replace the space of "map" by the space and divs of "ls". + */ +static __isl_give isl_map *replace_space_by_local_space(__isl_take isl_map *map, + __isl_take isl_local_space *ls) +{ + int i; + + map = isl_map_cow(map); + if (!map || !ls) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = basic_replace_space_by_local_space(map->p[i], + isl_local_space_copy(ls)); + if (!map->p[i]) + goto error; + } + isl_space_free(map->dim); + map->dim = isl_local_space_get_space(ls); + if (!map->dim) + goto error; + + isl_local_space_free(ls); + return map; +error: + isl_local_space_free(ls); + isl_map_free(map); + return NULL; +} + +/* Compute an explicit representation for the existentially + * quantified variables for which do not know any explicit representation yet. + * + * We first sort the existentially quantified variables so that the + * existentially quantified variables for which we already have an explicit + * representation are placed before those for which we do not. + * The input dimensions, the output dimensions and the existentially + * quantified variables for which we already have an explicit + * representation are then turned into parameters. + * compute_divs returns a map with the same parameters and + * no input or output dimensions and the dimension specification + * is reset to that of the input, including the existentially quantified + * variables for which we already had an explicit representation. + */ +static struct isl_map *compute_divs(struct isl_basic_map *bmap) +{ + struct isl_basic_set *bset; + struct isl_set *set; + struct isl_map *map; + isl_space *dim; + isl_local_space *ls; + unsigned nparam; + unsigned n_in; + unsigned n_out; + int n_known; + int i; + + bmap = isl_basic_map_sort_divs(bmap); + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + n_known = isl_basic_map_first_unknown_div(bmap); + if (n_known < 0) + return isl_map_from_basic_map(isl_basic_map_free(bmap)); + + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + dim = isl_space_set_alloc(bmap->ctx, + nparam + n_in + n_out + n_known, 0); + if (!dim) + goto error; + + ls = isl_basic_map_get_local_space(bmap); + ls = isl_local_space_drop_dims(ls, isl_dim_div, + n_known, bmap->n_div - n_known); + if (n_known > 0) { + for (i = n_known; i < bmap->n_div; ++i) + swap_div(bmap, i - n_known, i); + bmap->n_div -= n_known; + bmap->extra -= n_known; + } + bmap = isl_basic_map_reset_space(bmap, dim); + bset = bset_from_bmap(bmap); + + set = parameter_compute_divs(bset); + map = set_to_map(set); + map = replace_space_by_local_space(map, ls); + + return map; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Remove the explicit representation of local variable "div", + * if there is any. + */ +__isl_give isl_basic_map *isl_basic_map_mark_div_unknown( + __isl_take isl_basic_map *bmap, int div) +{ + isl_bool unknown; + + unknown = isl_basic_map_div_is_marked_unknown(bmap, div); + if (unknown < 0) + return isl_basic_map_free(bmap); + if (unknown) + return bmap; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + isl_int_set_si(bmap->div[div][0], 0); + return bmap; +} + +/* Is local variable "div" of "bmap" marked as not having an explicit + * representation? + * Note that even if "div" is not marked in this way and therefore + * has an explicit representation, this representation may still + * depend (indirectly) on other local variables that do not + * have an explicit representation. + */ +isl_bool isl_basic_map_div_is_marked_unknown(__isl_keep isl_basic_map *bmap, + int div) +{ + if (isl_basic_map_check_range(bmap, isl_dim_div, div, 1) < 0) + return isl_bool_error; + return isl_int_is_zero(bmap->div[div][0]); +} + +/* Return the position of the first local variable that does not + * have an explicit representation. + * Return the total number of local variables if they all have + * an explicit representation. + * Return -1 on error. + */ +int isl_basic_map_first_unknown_div(__isl_keep isl_basic_map *bmap) +{ + int i; + + if (!bmap) + return -1; + + for (i = 0; i < bmap->n_div; ++i) { + if (!isl_basic_map_div_is_known(bmap, i)) + return i; + } + return bmap->n_div; +} + +/* Return the position of the first local variable that does not + * have an explicit representation. + * Return the total number of local variables if they all have + * an explicit representation. + * Return -1 on error. + */ +int isl_basic_set_first_unknown_div(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_first_unknown_div(bset); +} + +/* Does "bmap" have an explicit representation for all local variables? + */ +isl_bool isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap) +{ + int first, n; + + n = isl_basic_map_dim(bmap, isl_dim_div); + first = isl_basic_map_first_unknown_div(bmap); + if (first < 0) + return isl_bool_error; + return first == n; +} + +/* Do all basic maps in "map" have an explicit representation + * for all local variables? + */ +isl_bool isl_map_divs_known(__isl_keep isl_map *map) +{ + int i; + + if (!map) + return isl_bool_error; + + for (i = 0; i < map->n; ++i) { + int known = isl_basic_map_divs_known(map->p[i]); + if (known <= 0) + return known; + } + + return isl_bool_true; +} + +/* If bmap contains any unknown divs, then compute explicit + * expressions for them. However, this computation may be + * quite expensive, so first try to remove divs that aren't + * strictly needed. + */ +__isl_give isl_map *isl_basic_map_compute_divs(__isl_take isl_basic_map *bmap) +{ + int known; + struct isl_map *map; + + known = isl_basic_map_divs_known(bmap); + if (known < 0) + goto error; + if (known) + return isl_map_from_basic_map(bmap); + + bmap = isl_basic_map_drop_redundant_divs(bmap); + + known = isl_basic_map_divs_known(bmap); + if (known < 0) + goto error; + if (known) + return isl_map_from_basic_map(bmap); + + map = compute_divs(bmap); + return map; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_map *isl_map_compute_divs(__isl_take isl_map *map) +{ + int i; + int known; + struct isl_map *res; + + if (!map) + return NULL; + if (map->n == 0) + return map; + + known = isl_map_divs_known(map); + if (known < 0) { + isl_map_free(map); + return NULL; + } + if (known) + return map; + + res = isl_basic_map_compute_divs(isl_basic_map_copy(map->p[0])); + for (i = 1 ; i < map->n; ++i) { + struct isl_map *r2; + r2 = isl_basic_map_compute_divs(isl_basic_map_copy(map->p[i])); + if (ISL_F_ISSET(map, ISL_MAP_DISJOINT)) + res = isl_map_union_disjoint(res, r2); + else + res = isl_map_union(res, r2); + } + isl_map_free(map); + + return res; +} + +__isl_give isl_set *isl_basic_set_compute_divs(__isl_take isl_basic_set *bset) +{ + return set_from_map(isl_basic_map_compute_divs(bset_to_bmap(bset))); +} + +struct isl_set *isl_set_compute_divs(struct isl_set *set) +{ + return set_from_map(isl_map_compute_divs(set_to_map(set))); +} + +__isl_give isl_set *isl_map_domain(__isl_take isl_map *map) +{ + int i; + struct isl_set *set; + + if (!map) + goto error; + + map = isl_map_cow(map); + if (!map) + return NULL; + + set = set_from_map(map); + set->dim = isl_space_domain(set->dim); + if (!set->dim) + goto error; + for (i = 0; i < map->n; ++i) { + set->p[i] = isl_basic_map_domain(map->p[i]); + if (!set->p[i]) + goto error; + } + ISL_F_CLR(set, ISL_MAP_DISJOINT); + ISL_F_CLR(set, ISL_SET_NORMALIZED); + return set; +error: + isl_map_free(map); + return NULL; +} + +/* Return the union of "map1" and "map2", where we assume for now that + * "map1" and "map2" are disjoint. Note that the basic maps inside + * "map1" or "map2" may not be disjoint from each other. + * Also note that this function is also called from isl_map_union, + * which takes care of handling the situation where "map1" and "map2" + * may not be disjoint. + * + * If one of the inputs is empty, we can simply return the other input. + * Similarly, if one of the inputs is universal, then it is equal to the union. + */ +static __isl_give isl_map *map_union_disjoint(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + int i; + unsigned flags = 0; + struct isl_map *map = NULL; + int is_universe; + + if (!map1 || !map2) + goto error; + + if (!isl_space_is_equal(map1->dim, map2->dim)) + isl_die(isl_map_get_ctx(map1), isl_error_invalid, + "spaces don't match", goto error); + + if (map1->n == 0) { + isl_map_free(map1); + return map2; + } + if (map2->n == 0) { + isl_map_free(map2); + return map1; + } + + is_universe = isl_map_plain_is_universe(map1); + if (is_universe < 0) + goto error; + if (is_universe) { + isl_map_free(map2); + return map1; + } + + is_universe = isl_map_plain_is_universe(map2); + if (is_universe < 0) + goto error; + if (is_universe) { + isl_map_free(map1); + return map2; + } + + if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) && + ISL_F_ISSET(map2, ISL_MAP_DISJOINT)) + ISL_FL_SET(flags, ISL_MAP_DISJOINT); + + map = isl_map_alloc_space(isl_space_copy(map1->dim), + map1->n + map2->n, flags); + if (!map) + goto error; + for (i = 0; i < map1->n; ++i) { + map = isl_map_add_basic_map(map, + isl_basic_map_copy(map1->p[i])); + if (!map) + goto error; + } + for (i = 0; i < map2->n; ++i) { + map = isl_map_add_basic_map(map, + isl_basic_map_copy(map2->p[i])); + if (!map) + goto error; + } + isl_map_free(map1); + isl_map_free(map2); + return map; +error: + isl_map_free(map); + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +/* Return the union of "map1" and "map2", where "map1" and "map2" are + * guaranteed to be disjoint by the caller. + * + * Note that this functions is called from within isl_map_make_disjoint, + * so we have to be careful not to touch the constraints of the inputs + * in any way. + */ +__isl_give isl_map *isl_map_union_disjoint(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, &map_union_disjoint); +} + +/* Return the union of "map1" and "map2", where "map1" and "map2" may + * not be disjoint. The parameters are assumed to have been aligned. + * + * We currently simply call map_union_disjoint, the internal operation + * of which does not really depend on the inputs being disjoint. + * If the result contains more than one basic map, then we clear + * the disjoint flag since the result may contain basic maps from + * both inputs and these are not guaranteed to be disjoint. + * + * As a special case, if "map1" and "map2" are obviously equal, + * then we simply return "map1". + */ +static __isl_give isl_map *map_union_aligned(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + int equal; + + if (!map1 || !map2) + goto error; + + equal = isl_map_plain_is_equal(map1, map2); + if (equal < 0) + goto error; + if (equal) { + isl_map_free(map2); + return map1; + } + + map1 = map_union_disjoint(map1, map2); + if (!map1) + return NULL; + if (map1->n > 1) + ISL_F_CLR(map1, ISL_MAP_DISJOINT); + return map1; +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +/* Return the union of "map1" and "map2", where "map1" and "map2" may + * not be disjoint. + */ +__isl_give isl_map *isl_map_union(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, &map_union_aligned); +} + +__isl_give isl_set *isl_set_union_disjoint( + __isl_take isl_set *set1, __isl_take isl_set *set2) +{ + return set_from_map(isl_map_union_disjoint(set_to_map(set1), + set_to_map(set2))); +} + +struct isl_set *isl_set_union(struct isl_set *set1, struct isl_set *set2) +{ + return set_from_map(isl_map_union(set_to_map(set1), set_to_map(set2))); +} + +/* Apply "fn" to pairs of elements from "map" and "set" and collect + * the results. + * + * "map" and "set" are assumed to be compatible and non-NULL. + */ +static __isl_give isl_map *map_intersect_set(__isl_take isl_map *map, + __isl_take isl_set *set, + __isl_give isl_basic_map *fn(__isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *bset)) +{ + unsigned flags = 0; + struct isl_map *result; + int i, j; + + 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); + + result = isl_map_alloc_space(isl_space_copy(map->dim), + map->n * set->n, flags); + for (i = 0; result && i < map->n; ++i) + for (j = 0; j < set->n; ++j) { + result = isl_map_add_basic_map(result, + fn(isl_basic_map_copy(map->p[i]), + isl_basic_set_copy(set->p[j]))); + if (!result) + break; + } + + isl_map_free(map); + isl_set_free(set); + return result; +} + +static __isl_give isl_map *map_intersect_range(__isl_take isl_map *map, + __isl_take isl_set *set) +{ + isl_bool ok; + + ok = isl_map_compatible_range(map, set); + if (ok < 0) + goto error; + if (!ok) + isl_die(set->ctx, isl_error_invalid, + "incompatible spaces", goto error); + + return map_intersect_set(map, set, &isl_basic_map_intersect_range); +error: + isl_map_free(map); + isl_set_free(set); + return NULL; +} + +__isl_give isl_map *isl_map_intersect_range(__isl_take isl_map *map, + __isl_take isl_set *set) +{ + return isl_map_align_params_map_map_and(map, set, &map_intersect_range); +} + +static __isl_give isl_map *map_intersect_domain(__isl_take isl_map *map, + __isl_take isl_set *set) +{ + isl_bool ok; + + ok = isl_map_compatible_domain(map, set); + if (ok < 0) + goto error; + if (!ok) + isl_die(set->ctx, isl_error_invalid, + "incompatible spaces", goto error); + + return map_intersect_set(map, set, &isl_basic_map_intersect_domain); +error: + isl_map_free(map); + isl_set_free(set); + return NULL; +} + +__isl_give isl_map *isl_map_intersect_domain(__isl_take isl_map *map, + __isl_take isl_set *set) +{ + return isl_map_align_params_map_map_and(map, set, + &map_intersect_domain); +} + +/* Given a map "map" in a space [A -> B] -> C and a map "factor" + * in the space B -> C, return the intersection. + * The parameters are assumed to have been aligned. + * + * The map "factor" is first extended to a map living in the space + * [A -> B] -> C and then a regular intersection is computed. + */ +static __isl_give isl_map *map_intersect_domain_factor_range( + __isl_take isl_map *map, __isl_take isl_map *factor) +{ + isl_space *space; + isl_map *ext_factor; + + space = isl_space_domain_factor_domain(isl_map_get_space(map)); + ext_factor = isl_map_universe(space); + ext_factor = isl_map_domain_product(ext_factor, factor); + return map_intersect(map, ext_factor); +} + +/* Given a map "map" in a space [A -> B] -> C and a map "factor" + * in the space B -> C, return the intersection. + */ +__isl_give isl_map *isl_map_intersect_domain_factor_range( + __isl_take isl_map *map, __isl_take isl_map *factor) +{ + return isl_map_align_params_map_map_and(map, factor, + &map_intersect_domain_factor_range); +} + +/* Given a map "map" in a space A -> [B -> C] and a map "factor" + * in the space A -> C, return the intersection. + * + * The map "factor" is first extended to a map living in the space + * A -> [B -> C] and then a regular intersection is computed. + */ +static __isl_give isl_map *map_intersect_range_factor_range( + __isl_take isl_map *map, __isl_take isl_map *factor) +{ + isl_space *space; + isl_map *ext_factor; + + space = isl_space_range_factor_domain(isl_map_get_space(map)); + ext_factor = isl_map_universe(space); + ext_factor = isl_map_range_product(ext_factor, factor); + return isl_map_intersect(map, ext_factor); +} + +/* Given a map "map" in a space A -> [B -> C] and a map "factor" + * in the space A -> C, return the intersection. + */ +__isl_give isl_map *isl_map_intersect_range_factor_range( + __isl_take isl_map *map, __isl_take isl_map *factor) +{ + return isl_map_align_params_map_map_and(map, factor, + &map_intersect_range_factor_range); +} + +static __isl_give isl_map *map_apply_domain(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + if (!map1 || !map2) + goto error; + map1 = isl_map_reverse(map1); + map1 = isl_map_apply_range(map1, map2); + return isl_map_reverse(map1); +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +__isl_give isl_map *isl_map_apply_domain(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, &map_apply_domain); +} + +static __isl_give isl_map *map_apply_range(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_space *dim_result; + struct isl_map *result; + int i, j; + + if (!map1 || !map2) + goto error; + + dim_result = isl_space_join(isl_space_copy(map1->dim), + isl_space_copy(map2->dim)); + + result = isl_map_alloc_space(dim_result, map1->n * map2->n, 0); + if (!result) + goto error; + for (i = 0; i < map1->n; ++i) + for (j = 0; j < map2->n; ++j) { + result = isl_map_add_basic_map(result, + isl_basic_map_apply_range( + isl_basic_map_copy(map1->p[i]), + isl_basic_map_copy(map2->p[j]))); + if (!result) + goto error; + } + isl_map_free(map1); + isl_map_free(map2); + if (result && result->n <= 1) + ISL_F_SET(result, ISL_MAP_DISJOINT); + return result; +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +__isl_give isl_map *isl_map_apply_range(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, &map_apply_range); +} + +/* + * returns range - domain + */ +__isl_give isl_basic_set *isl_basic_map_deltas(__isl_take isl_basic_map *bmap) +{ + isl_space *target_space; + struct isl_basic_set *bset; + unsigned dim; + unsigned nparam; + int i; + + if (!bmap) + goto error; + isl_assert(bmap->ctx, isl_space_tuple_is_equal(bmap->dim, isl_dim_in, + bmap->dim, isl_dim_out), + goto error); + target_space = isl_space_domain(isl_basic_map_get_space(bmap)); + dim = isl_basic_map_dim(bmap, isl_dim_in); + nparam = isl_basic_map_dim(bmap, isl_dim_param); + bmap = isl_basic_map_from_range(isl_basic_map_wrap(bmap)); + bmap = isl_basic_map_add_dims(bmap, isl_dim_in, dim); + bmap = isl_basic_map_extend_constraints(bmap, dim, 0); + for (i = 0; i < dim; ++i) { + int j = isl_basic_map_alloc_equality(bmap); + if (j < 0) { + bmap = isl_basic_map_free(bmap); + break; + } + isl_seq_clr(bmap->eq[j], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->eq[j][1+nparam+i], 1); + isl_int_set_si(bmap->eq[j][1+nparam+dim+i], 1); + isl_int_set_si(bmap->eq[j][1+nparam+2*dim+i], -1); + } + bset = isl_basic_map_domain(bmap); + bset = isl_basic_set_reset_space(bset, target_space); + return bset; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* + * returns range - domain + */ +__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map) +{ + int i; + isl_space *dim; + struct isl_set *result; + + if (!map) + return NULL; + + isl_assert(map->ctx, isl_space_tuple_is_equal(map->dim, isl_dim_in, + map->dim, isl_dim_out), + goto error); + dim = isl_map_get_space(map); + dim = isl_space_domain(dim); + result = isl_set_alloc_space(dim, map->n, 0); + if (!result) + goto error; + for (i = 0; i < map->n; ++i) + result = isl_set_add_basic_set(result, + isl_basic_map_deltas(isl_basic_map_copy(map->p[i]))); + isl_map_free(map); + return result; +error: + isl_map_free(map); + return NULL; +} + +/* + * returns [domain -> range] -> range - domain + */ +__isl_give isl_basic_map *isl_basic_map_deltas_map( + __isl_take isl_basic_map *bmap) +{ + int i, k; + isl_space *dim; + isl_basic_map *domain; + int nparam, n; + unsigned total; + + if (!isl_space_tuple_is_equal(bmap->dim, isl_dim_in, + bmap->dim, isl_dim_out)) + isl_die(bmap->ctx, isl_error_invalid, + "domain and range don't match", goto error); + + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n = isl_basic_map_dim(bmap, isl_dim_in); + + dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap))); + domain = isl_basic_map_universe(dim); + + bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap)); + bmap = isl_basic_map_apply_range(bmap, domain); + bmap = isl_basic_map_extend_constraints(bmap, n, 0); + + total = isl_basic_map_total_dim(bmap); + + for (i = 0; i < n; ++i) { + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->eq[k], 1 + total); + isl_int_set_si(bmap->eq[k][1 + nparam + i], 1); + isl_int_set_si(bmap->eq[k][1 + nparam + n + i], -1); + isl_int_set_si(bmap->eq[k][1 + nparam + n + n + i], 1); + } + + bmap = isl_basic_map_gauss(bmap, NULL); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* + * returns [domain -> range] -> range - domain + */ +__isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map) +{ + int i; + isl_space *domain_dim; + + if (!map) + return NULL; + + if (!isl_space_tuple_is_equal(map->dim, isl_dim_in, + map->dim, isl_dim_out)) + isl_die(map->ctx, isl_error_invalid, + "domain and range don't match", goto error); + + map = isl_map_cow(map); + if (!map) + return NULL; + + domain_dim = isl_space_from_range(isl_space_domain(isl_map_get_space(map))); + map->dim = isl_space_from_domain(isl_space_wrap(map->dim)); + map->dim = isl_space_join(map->dim, domain_dim); + if (!map->dim) + goto error; + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_deltas_map(map->p[i]); + if (!map->p[i]) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +static __isl_give isl_basic_map *basic_map_identity(__isl_take isl_space *dims) +{ + struct isl_basic_map *bmap; + unsigned nparam; + unsigned dim; + int i; + + if (!dims) + return NULL; + + nparam = dims->nparam; + dim = dims->n_out; + bmap = isl_basic_map_alloc_space(dims, 0, dim, 0); + if (!bmap) + goto error; + + for (i = 0; i < dim; ++i) { + int j = isl_basic_map_alloc_equality(bmap); + if (j < 0) + goto error; + isl_seq_clr(bmap->eq[j], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->eq[j][1+nparam+i], 1); + isl_int_set_si(bmap->eq[j][1+nparam+dim+i], -1); + } + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_space *dim) +{ + if (!dim) + return NULL; + if (dim->n_in != dim->n_out) + isl_die(dim->ctx, isl_error_invalid, + "number of input and output dimensions needs to be " + "the same", goto error); + return basic_map_identity(dim); +error: + isl_space_free(dim); + return NULL; +} + +__isl_give isl_map *isl_map_identity(__isl_take isl_space *dim) +{ + return isl_map_from_basic_map(isl_basic_map_identity(dim)); +} + +__isl_give isl_map *isl_set_identity(__isl_take isl_set *set) +{ + isl_space *dim = isl_set_get_space(set); + isl_map *id; + id = isl_map_identity(isl_space_map_from_set(dim)); + return isl_map_intersect_range(id, set); +} + +/* Construct a basic set with all set dimensions having only non-negative + * values. + */ +__isl_give isl_basic_set *isl_basic_set_positive_orthant( + __isl_take isl_space *space) +{ + int i; + unsigned nparam; + unsigned dim; + struct isl_basic_set *bset; + + if (!space) + return NULL; + nparam = space->nparam; + dim = space->n_out; + bset = isl_basic_set_alloc_space(space, 0, 0, dim); + if (!bset) + return NULL; + for (i = 0; i < dim; ++i) { + int k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_clr(bset->ineq[k], 1 + isl_basic_set_total_dim(bset)); + isl_int_set_si(bset->ineq[k][1 + nparam + i], 1); + } + return bset; +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Construct the half-space x_pos >= 0. + */ +static __isl_give isl_basic_set *nonneg_halfspace(__isl_take isl_space *dim, + int pos) +{ + int k; + isl_basic_set *nonneg; + + nonneg = isl_basic_set_alloc_space(dim, 0, 0, 1); + k = isl_basic_set_alloc_inequality(nonneg); + if (k < 0) + goto error; + isl_seq_clr(nonneg->ineq[k], 1 + isl_basic_set_total_dim(nonneg)); + isl_int_set_si(nonneg->ineq[k][pos], 1); + + return isl_basic_set_finalize(nonneg); +error: + isl_basic_set_free(nonneg); + return NULL; +} + +/* Construct the half-space x_pos <= -1. + */ +static __isl_give isl_basic_set *neg_halfspace(__isl_take isl_space *dim, int pos) +{ + int k; + isl_basic_set *neg; + + neg = isl_basic_set_alloc_space(dim, 0, 0, 1); + k = isl_basic_set_alloc_inequality(neg); + if (k < 0) + goto error; + isl_seq_clr(neg->ineq[k], 1 + isl_basic_set_total_dim(neg)); + isl_int_set_si(neg->ineq[k][0], -1); + isl_int_set_si(neg->ineq[k][pos], -1); + + return isl_basic_set_finalize(neg); +error: + isl_basic_set_free(neg); + return NULL; +} + +__isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + unsigned offset; + isl_basic_set *nonneg; + isl_basic_set *neg; + + if (!set) + return NULL; + if (n == 0) + return set; + + isl_assert(set->ctx, first + n <= isl_set_dim(set, type), goto error); + + offset = pos(set->dim, type); + for (i = 0; i < n; ++i) { + nonneg = nonneg_halfspace(isl_set_get_space(set), + offset + first + i); + neg = neg_halfspace(isl_set_get_space(set), offset + first + i); + + set = isl_set_intersect(set, isl_basic_set_union(nonneg, neg)); + } + + return set; +error: + isl_set_free(set); + return NULL; +} + +static isl_stat foreach_orthant(__isl_take isl_set *set, int *signs, int first, + int len, + isl_stat (*fn)(__isl_take isl_set *orthant, int *signs, void *user), + void *user) +{ + isl_set *half; + + if (!set) + return isl_stat_error; + if (isl_set_plain_is_empty(set)) { + isl_set_free(set); + return isl_stat_ok; + } + if (first == len) + return fn(set, signs, user); + + signs[first] = 1; + half = isl_set_from_basic_set(nonneg_halfspace(isl_set_get_space(set), + 1 + first)); + half = isl_set_intersect(half, isl_set_copy(set)); + if (foreach_orthant(half, signs, first + 1, len, fn, user) < 0) + goto error; + + signs[first] = -1; + half = isl_set_from_basic_set(neg_halfspace(isl_set_get_space(set), + 1 + first)); + half = isl_set_intersect(half, set); + return foreach_orthant(half, signs, first + 1, len, fn, user); +error: + isl_set_free(set); + return isl_stat_error; +} + +/* Call "fn" on the intersections of "set" with each of the orthants + * (except for obviously empty intersections). The orthant is identified + * by the signs array, with each entry having value 1 or -1 according + * to the sign of the corresponding variable. + */ +isl_stat isl_set_foreach_orthant(__isl_keep isl_set *set, + isl_stat (*fn)(__isl_take isl_set *orthant, int *signs, void *user), + void *user) +{ + unsigned nparam; + unsigned nvar; + int *signs; + isl_stat r; + + if (!set) + return isl_stat_error; + if (isl_set_plain_is_empty(set)) + return isl_stat_ok; + + nparam = isl_set_dim(set, isl_dim_param); + nvar = isl_set_dim(set, isl_dim_set); + + signs = isl_alloc_array(set->ctx, int, nparam + nvar); + + r = foreach_orthant(isl_set_copy(set), signs, 0, nparam + nvar, + fn, user); + + free(signs); + + return r; +} + +isl_bool isl_set_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2) +{ + return isl_map_is_equal(set_to_map(set1), set_to_map(set2)); +} + +isl_bool isl_basic_map_is_subset(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2) +{ + int is_subset; + struct isl_map *map1; + struct isl_map *map2; + + if (!bmap1 || !bmap2) + return isl_bool_error; + + map1 = isl_map_from_basic_map(isl_basic_map_copy(bmap1)); + map2 = isl_map_from_basic_map(isl_basic_map_copy(bmap2)); + + is_subset = isl_map_is_subset(map1, map2); + + isl_map_free(map1); + isl_map_free(map2); + + return is_subset; +} + +isl_bool isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2) +{ + return isl_basic_map_is_subset(bset1, bset2); +} + +isl_bool isl_basic_map_is_equal(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2) +{ + isl_bool is_subset; + + if (!bmap1 || !bmap2) + return isl_bool_error; + is_subset = isl_basic_map_is_subset(bmap1, bmap2); + if (is_subset != isl_bool_true) + return is_subset; + is_subset = isl_basic_map_is_subset(bmap2, bmap1); + return is_subset; +} + +isl_bool isl_basic_set_is_equal(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2) +{ + return isl_basic_map_is_equal( + bset_to_bmap(bset1), bset_to_bmap(bset2)); +} + +isl_bool isl_map_is_empty(__isl_keep isl_map *map) +{ + int i; + int is_empty; + + if (!map) + return isl_bool_error; + for (i = 0; i < map->n; ++i) { + is_empty = isl_basic_map_is_empty(map->p[i]); + if (is_empty < 0) + return isl_bool_error; + if (!is_empty) + return isl_bool_false; + } + return isl_bool_true; +} + +isl_bool isl_map_plain_is_empty(__isl_keep isl_map *map) +{ + return map ? map->n == 0 : isl_bool_error; +} + +isl_bool isl_set_plain_is_empty(__isl_keep isl_set *set) +{ + return set ? set->n == 0 : isl_bool_error; +} + +isl_bool isl_set_is_empty(__isl_keep isl_set *set) +{ + return isl_map_is_empty(set_to_map(set)); +} + +isl_bool isl_map_has_equal_space(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + if (!map1 || !map2) + return isl_bool_error; + + return isl_space_is_equal(map1->dim, map2->dim); +} + +isl_bool isl_set_has_equal_space(__isl_keep isl_set *set1, + __isl_keep isl_set *set2) +{ + if (!set1 || !set2) + return isl_bool_error; + + return isl_space_is_equal(set1->dim, set2->dim); +} + +static isl_bool map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2) +{ + isl_bool is_subset; + + if (!map1 || !map2) + return isl_bool_error; + is_subset = isl_map_is_subset(map1, map2); + if (is_subset != isl_bool_true) + return is_subset; + is_subset = isl_map_is_subset(map2, map1); + return is_subset; +} + +/* Is "map1" equal to "map2"? + * + * First check if they are obviously equal. + * If not, then perform a more detailed analysis. + */ +isl_bool isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2) +{ + isl_bool equal; + + equal = isl_map_plain_is_equal(map1, map2); + if (equal < 0 || equal) + return equal; + return isl_map_align_params_map_map_and_test(map1, map2, &map_is_equal); +} + +isl_bool isl_basic_map_is_strict_subset( + struct isl_basic_map *bmap1, struct isl_basic_map *bmap2) +{ + isl_bool is_subset; + + if (!bmap1 || !bmap2) + return isl_bool_error; + is_subset = isl_basic_map_is_subset(bmap1, bmap2); + if (is_subset != isl_bool_true) + return is_subset; + is_subset = isl_basic_map_is_subset(bmap2, bmap1); + if (is_subset == isl_bool_error) + return is_subset; + return !is_subset; +} + +isl_bool isl_map_is_strict_subset(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + isl_bool is_subset; + + if (!map1 || !map2) + return isl_bool_error; + is_subset = isl_map_is_subset(map1, map2); + if (is_subset != isl_bool_true) + return is_subset; + is_subset = isl_map_is_subset(map2, map1); + if (is_subset == isl_bool_error) + return is_subset; + return !is_subset; +} + +isl_bool isl_set_is_strict_subset(__isl_keep isl_set *set1, + __isl_keep isl_set *set2) +{ + return isl_map_is_strict_subset(set_to_map(set1), set_to_map(set2)); +} + +/* Is "bmap" obviously equal to the universe with the same space? + * + * That is, does it not have any constraints? + */ +isl_bool isl_basic_map_plain_is_universe(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + return bmap->n_eq == 0 && bmap->n_ineq == 0; +} + +/* Is "bset" obviously equal to the universe with the same space? + */ +isl_bool isl_basic_set_plain_is_universe(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_plain_is_universe(bset); +} + +/* If "c" does not involve any existentially quantified variables, + * then set *univ to false and abort + */ +static isl_stat involves_divs(__isl_take isl_constraint *c, void *user) +{ + isl_bool *univ = user; + unsigned n; + + n = isl_constraint_dim(c, isl_dim_div); + *univ = isl_constraint_involves_dims(c, isl_dim_div, 0, n); + isl_constraint_free(c); + if (*univ < 0 || !*univ) + return isl_stat_error; + return isl_stat_ok; +} + +/* Is "bmap" equal to the universe with the same space? + * + * First check if it is obviously equal to the universe. + * If not and if there are any constraints not involving + * existentially quantified variables, then it is certainly + * not equal to the universe. + * Otherwise, check if the universe is a subset of "bmap". + */ +isl_bool isl_basic_map_is_universe(__isl_keep isl_basic_map *bmap) +{ + isl_bool univ; + isl_basic_map *test; + + univ = isl_basic_map_plain_is_universe(bmap); + if (univ < 0 || univ) + return univ; + if (isl_basic_map_dim(bmap, isl_dim_div) == 0) + return isl_bool_false; + univ = isl_bool_true; + if (isl_basic_map_foreach_constraint(bmap, &involves_divs, &univ) < 0 && + univ) + return isl_bool_error; + if (univ < 0 || !univ) + return univ; + test = isl_basic_map_universe(isl_basic_map_get_space(bmap)); + univ = isl_basic_map_is_subset(test, bmap); + isl_basic_map_free(test); + return univ; +} + +/* Is "bset" equal to the universe with the same space? + */ +isl_bool isl_basic_set_is_universe(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_is_universe(bset); +} + +isl_bool isl_map_plain_is_universe(__isl_keep isl_map *map) +{ + int i; + + if (!map) + return isl_bool_error; + + for (i = 0; i < map->n; ++i) { + isl_bool r = isl_basic_map_plain_is_universe(map->p[i]); + if (r < 0 || r) + return r; + } + + return isl_bool_false; +} + +isl_bool isl_set_plain_is_universe(__isl_keep isl_set *set) +{ + return isl_map_plain_is_universe(set_to_map(set)); +} + +isl_bool isl_basic_map_is_empty(__isl_keep isl_basic_map *bmap) +{ + struct isl_basic_set *bset = NULL; + struct isl_vec *sample = NULL; + isl_bool empty, non_empty; + + if (!bmap) + return isl_bool_error; + + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) + return isl_bool_true; + + if (isl_basic_map_plain_is_universe(bmap)) + return isl_bool_false; + + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) { + struct isl_basic_map *copy = isl_basic_map_copy(bmap); + copy = isl_basic_map_remove_redundancies(copy); + empty = isl_basic_map_plain_is_empty(copy); + isl_basic_map_free(copy); + return empty; + } + + non_empty = isl_basic_map_plain_is_non_empty(bmap); + if (non_empty < 0) + return isl_bool_error; + if (non_empty) + return isl_bool_false; + isl_vec_free(bmap->sample); + bmap->sample = NULL; + bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap)); + if (!bset) + return isl_bool_error; + sample = isl_basic_set_sample_vec(bset); + if (!sample) + return isl_bool_error; + empty = sample->size == 0; + isl_vec_free(bmap->sample); + bmap->sample = sample; + if (empty) + ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY); + + return empty; +} + +isl_bool isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + return ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY); +} + +isl_bool isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset) +{ + if (!bset) + return isl_bool_error; + return ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY); +} + +/* Is "bmap" known to be non-empty? + * + * That is, is the cached sample still valid? + */ +isl_bool isl_basic_map_plain_is_non_empty(__isl_keep isl_basic_map *bmap) +{ + unsigned total; + + if (!bmap) + return isl_bool_error; + if (!bmap->sample) + return isl_bool_false; + total = 1 + isl_basic_map_total_dim(bmap); + if (bmap->sample->size != total) + return isl_bool_false; + return isl_basic_map_contains(bmap, bmap->sample); +} + +isl_bool isl_basic_set_is_empty(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_is_empty(bset_to_bmap(bset)); +} + +__isl_give isl_map *isl_basic_map_union(__isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2) +{ + struct isl_map *map; + if (!bmap1 || !bmap2) + goto error; + + isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim), goto error); + + map = isl_map_alloc_space(isl_space_copy(bmap1->dim), 2, 0); + if (!map) + goto error; + map = isl_map_add_basic_map(map, bmap1); + map = isl_map_add_basic_map(map, bmap2); + return map; +error: + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +struct isl_set *isl_basic_set_union( + struct isl_basic_set *bset1, struct isl_basic_set *bset2) +{ + return set_from_map(isl_basic_map_union(bset_to_bmap(bset1), + bset_to_bmap(bset2))); +} + +/* Order divs such that any div only depends on previous divs */ +__isl_give isl_basic_map *isl_basic_map_order_divs( + __isl_take isl_basic_map *bmap) +{ + int i; + unsigned off; + + if (!bmap) + return NULL; + + off = isl_space_dim(bmap->dim, isl_dim_all); + + for (i = 0; i < bmap->n_div; ++i) { + int pos; + if (isl_int_is_zero(bmap->div[i][0])) + continue; + pos = isl_seq_first_non_zero(bmap->div[i]+1+1+off+i, + bmap->n_div-i); + if (pos == -1) + continue; + if (pos == 0) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_internal, + "integer division depends on itself", + return isl_basic_map_free(bmap)); + isl_basic_map_swap_div(bmap, i, i + pos); + --i; + } + return bmap; +} + +struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_order_divs(bset_to_bmap(bset))); +} + +__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map) +{ + int i; + + if (!map) + return 0; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_order_divs(map->p[i]); + if (!map->p[i]) + goto error; + } + + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Sort the local variables of "bset". + */ +__isl_give isl_basic_set *isl_basic_set_sort_divs( + __isl_take isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_sort_divs(bset_to_bmap(bset))); +} + +/* 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". + * + * Move the integer divisions of "bmap" into the right position + * according to "exp" and then introduce the additional integer + * divisions, adding div constraints. + * The moving should be done first to avoid moving coefficients + * in the definitions of the extra integer divisions. + */ +__isl_give isl_basic_map *isl_basic_map_expand_divs( + __isl_take isl_basic_map *bmap, __isl_take isl_mat *div, int *exp) +{ + int i, j; + int n_div; + + bmap = isl_basic_map_cow(bmap); + if (!bmap || !div) + goto error; + + if (div->n_row < bmap->n_div) + isl_die(isl_mat_get_ctx(div), isl_error_invalid, + "not an expansion", goto error); + + n_div = bmap->n_div; + bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim), + div->n_row - n_div, 0, + 2 * (div->n_row - n_div)); + + for (i = n_div; i < div->n_row; ++i) + if (isl_basic_map_alloc_div(bmap) < 0) + goto error; + + for (j = n_div - 1; j >= 0; --j) { + if (exp[j] == j) + break; + isl_basic_map_swap_div(bmap, j, exp[j]); + } + j = 0; + for (i = 0; i < div->n_row; ++i) { + if (j < n_div && exp[j] == i) { + j++; + } else { + isl_seq_cpy(bmap->div[i], div->row[i], div->n_col); + if (isl_basic_map_div_is_marked_unknown(bmap, i)) + continue; + if (isl_basic_map_add_div_constraints(bmap, i) < 0) + goto error; + } + } + + isl_mat_free(div); + return bmap; +error: + isl_basic_map_free(bmap); + isl_mat_free(div); + 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) +{ + return isl_basic_map_expand_divs(bset, div, exp); +} + +/* 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. + * + * Returns -1 if no corresponding div was found and the position + * of the corresponding div in dst otherwise. + */ +static int find_div(__isl_keep isl_basic_map *dst, + __isl_keep isl_basic_map *src, unsigned div) +{ + int i; + + unsigned total = isl_space_dim(src->dim, isl_dim_all); + + isl_assert(dst->ctx, div <= dst->n_div, return -1); + for (i = div; i < dst->n_div; ++i) + if (isl_seq_eq(dst->div[i], src->div[div], 1+1+total+div) && + isl_seq_first_non_zero(dst->div[i]+1+1+total+div, + dst->n_div - div) == -1) + return i; + return -1; +} + +/* Align the divs of "dst" to those of "src", adding divs from "src" + * if needed. That is, make sure that the first src->n_div divs + * of the result are equal to those of src. + * + * The result is not finalized as by design it will have redundant + * divs if any divs from "src" were copied. + */ +__isl_give isl_basic_map *isl_basic_map_align_divs( + __isl_take isl_basic_map *dst, __isl_keep isl_basic_map *src) +{ + int i; + int known, extended; + unsigned total; + + if (!dst || !src) + return isl_basic_map_free(dst); + + if (src->n_div == 0) + return dst; + + known = isl_basic_map_divs_known(src); + if (known < 0) + return isl_basic_map_free(dst); + if (!known) + isl_die(isl_basic_map_get_ctx(src), isl_error_invalid, + "some src divs are unknown", + return isl_basic_map_free(dst)); + + src = isl_basic_map_order_divs(src); + + extended = 0; + total = isl_space_dim(src->dim, isl_dim_all); + for (i = 0; i < src->n_div; ++i) { + int j = find_div(dst, src, i); + if (j < 0) { + if (!extended) { + int extra = src->n_div - i; + dst = isl_basic_map_cow(dst); + if (!dst) + return NULL; + dst = isl_basic_map_extend_space(dst, + isl_space_copy(dst->dim), + extra, 0, 2 * extra); + extended = 1; + } + j = isl_basic_map_alloc_div(dst); + if (j < 0) + return isl_basic_map_free(dst); + isl_seq_cpy(dst->div[j], src->div[i], 1+1+total+i); + isl_seq_clr(dst->div[j]+1+1+total+i, dst->n_div - i); + if (isl_basic_map_add_div_constraints(dst, j) < 0) + return isl_basic_map_free(dst); + } + if (j != i) + isl_basic_map_swap_div(dst, i, j); + } + return dst; +} + +__isl_give isl_map *isl_map_align_divs_internal(__isl_take isl_map *map) +{ + int i; + + if (!map) + return NULL; + if (map->n == 0) + return map; + map = isl_map_compute_divs(map); + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 1; i < map->n; ++i) + map->p[0] = isl_basic_map_align_divs(map->p[0], map->p[i]); + for (i = 1; i < map->n; ++i) { + map->p[i] = isl_basic_map_align_divs(map->p[i], map->p[0]); + if (!map->p[i]) + return isl_map_free(map); + } + + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +} + +__isl_give isl_map *isl_map_align_divs(__isl_take isl_map *map) +{ + return isl_map_align_divs_internal(map); +} + +struct isl_set *isl_set_align_divs(struct isl_set *set) +{ + return set_from_map(isl_map_align_divs_internal(set_to_map(set))); +} + +/* Align the divs of the basic maps in "map" to those + * of the basic maps in "list", as well as to the other basic maps in "map". + * The elements in "list" are assumed to have known divs. + */ +__isl_give isl_map *isl_map_align_divs_to_basic_map_list( + __isl_take isl_map *map, __isl_keep isl_basic_map_list *list) +{ + int i, n; + + map = isl_map_compute_divs(map); + map = isl_map_cow(map); + if (!map || !list) + return isl_map_free(map); + if (map->n == 0) + return map; + + n = isl_basic_map_list_n_basic_map(list); + for (i = 0; i < n; ++i) { + isl_basic_map *bmap; + + bmap = isl_basic_map_list_get_basic_map(list, i); + map->p[0] = isl_basic_map_align_divs(map->p[0], bmap); + isl_basic_map_free(bmap); + } + if (!map->p[0]) + return isl_map_free(map); + + return isl_map_align_divs_internal(map); +} + +/* Align the divs of each element of "list" to those of "bmap". + * Both "bmap" and the elements of "list" are assumed to have known divs. + */ +__isl_give isl_basic_map_list *isl_basic_map_list_align_divs_to_basic_map( + __isl_take isl_basic_map_list *list, __isl_keep isl_basic_map *bmap) +{ + int i, n; + + if (!list || !bmap) + return isl_basic_map_list_free(list); + + n = isl_basic_map_list_n_basic_map(list); + for (i = 0; i < n; ++i) { + isl_basic_map *bmap_i; + + bmap_i = isl_basic_map_list_get_basic_map(list, i); + bmap_i = isl_basic_map_align_divs(bmap_i, bmap); + list = isl_basic_map_list_set_basic_map(list, i, bmap_i); + } + + return list; +} + +static __isl_give isl_set *set_apply( __isl_take isl_set *set, + __isl_take isl_map *map) +{ + isl_bool ok; + + ok = isl_map_compatible_domain(map, set); + if (ok < 0) + goto error; + if (!ok) + isl_die(isl_set_get_ctx(set), isl_error_invalid, + "incompatible spaces", goto error); + map = isl_map_intersect_domain(map, set); + set = isl_map_range(map); + return set; +error: + isl_set_free(set); + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_apply( __isl_take isl_set *set, + __isl_take isl_map *map) +{ + return isl_map_align_params_map_map_and(set, map, &set_apply); +} + +/* There is no need to cow as removing empty parts doesn't change + * the meaning of the set. + */ +__isl_give isl_map *isl_map_remove_empty_parts(__isl_take isl_map *map) +{ + int i; + + if (!map) + return NULL; + + for (i = map->n - 1; i >= 0; --i) + remove_if_empty(map, i); + + return map; +} + +struct isl_set *isl_set_remove_empty_parts(struct isl_set *set) +{ + return set_from_map(isl_map_remove_empty_parts(set_to_map(set))); +} + +/* Given two basic sets bset1 and bset2, compute the maximal difference + * between the values of dimension pos in bset1 and those in bset2 + * for any common value of the parameters and dimensions preceding pos. + */ +static enum isl_lp_result basic_set_maximal_difference_at( + __isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2, + int pos, isl_int *opt) +{ + isl_basic_map *bmap1; + isl_basic_map *bmap2; + struct isl_ctx *ctx; + struct isl_vec *obj; + unsigned total; + unsigned nparam; + unsigned dim1; + enum isl_lp_result res; + + if (!bset1 || !bset2) + return isl_lp_error; + + nparam = isl_basic_set_n_param(bset1); + dim1 = isl_basic_set_n_dim(bset1); + + bmap1 = isl_basic_map_from_range(isl_basic_set_copy(bset1)); + bmap2 = isl_basic_map_from_range(isl_basic_set_copy(bset2)); + bmap1 = isl_basic_map_move_dims(bmap1, isl_dim_in, 0, + isl_dim_out, 0, pos); + bmap2 = isl_basic_map_move_dims(bmap2, isl_dim_in, 0, + isl_dim_out, 0, pos); + bmap1 = isl_basic_map_range_product(bmap1, bmap2); + if (!bmap1) + return isl_lp_error; + + total = isl_basic_map_total_dim(bmap1); + ctx = bmap1->ctx; + obj = isl_vec_alloc(ctx, 1 + total); + if (!obj) + goto error; + isl_seq_clr(obj->block.data, 1 + total); + isl_int_set_si(obj->block.data[1+nparam+pos], 1); + isl_int_set_si(obj->block.data[1+nparam+pos+(dim1-pos)], -1); + res = isl_basic_map_solve_lp(bmap1, 1, obj->block.data, ctx->one, + opt, NULL, NULL); + isl_basic_map_free(bmap1); + isl_vec_free(obj); + return res; +error: + isl_basic_map_free(bmap1); + return isl_lp_error; +} + +/* Given two _disjoint_ basic sets bset1 and bset2, check whether + * for any common value of the parameters and dimensions preceding pos + * in both basic sets, the values of dimension pos in bset1 are + * smaller or larger than those in bset2. + * + * Returns + * 1 if bset1 follows bset2 + * -1 if bset1 precedes bset2 + * 0 if bset1 and bset2 are incomparable + * -2 if some error occurred. + */ +int isl_basic_set_compare_at(struct isl_basic_set *bset1, + struct isl_basic_set *bset2, int pos) +{ + isl_int opt; + enum isl_lp_result res; + int cmp; + + isl_int_init(opt); + + res = basic_set_maximal_difference_at(bset1, bset2, pos, &opt); + + if (res == isl_lp_empty) + cmp = 0; + else if ((res == isl_lp_ok && isl_int_is_pos(opt)) || + res == isl_lp_unbounded) + cmp = 1; + else if (res == isl_lp_ok && isl_int_is_neg(opt)) + cmp = -1; + else + cmp = -2; + + isl_int_clear(opt); + return cmp; +} + +/* Given two basic sets bset1 and bset2, check whether + * for any common value of the parameters and dimensions preceding pos + * there is a value of dimension pos in bset1 that is larger + * than a value of the same dimension in bset2. + * + * Return + * 1 if there exists such a pair + * 0 if there is no such pair, but there is a pair of equal values + * -1 otherwise + * -2 if some error occurred. + */ +int isl_basic_set_follows_at(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2, int pos) +{ + isl_int opt; + enum isl_lp_result res; + int cmp; + + isl_int_init(opt); + + res = basic_set_maximal_difference_at(bset1, bset2, pos, &opt); + + if (res == isl_lp_empty) + cmp = -1; + else if ((res == isl_lp_ok && isl_int_is_pos(opt)) || + res == isl_lp_unbounded) + cmp = 1; + else if (res == isl_lp_ok && isl_int_is_neg(opt)) + cmp = -1; + else if (res == isl_lp_ok) + cmp = 0; + else + cmp = -2; + + isl_int_clear(opt); + return cmp; +} + +/* Given two sets set1 and set2, check whether + * for any common value of the parameters and dimensions preceding pos + * there is a value of dimension pos in set1 that is larger + * than a value of the same dimension in set2. + * + * Return + * 1 if there exists such a pair + * 0 if there is no such pair, but there is a pair of equal values + * -1 otherwise + * -2 if some error occurred. + */ +int isl_set_follows_at(__isl_keep isl_set *set1, + __isl_keep isl_set *set2, int pos) +{ + int i, j; + int follows = -1; + + if (!set1 || !set2) + return -2; + + for (i = 0; i < set1->n; ++i) + for (j = 0; j < set2->n; ++j) { + int f; + f = isl_basic_set_follows_at(set1->p[i], set2->p[j], pos); + if (f == 1 || f == -2) + return f; + if (f > follows) + follows = f; + } + + return follows; +} + +static isl_bool isl_basic_map_plain_has_fixed_var( + __isl_keep isl_basic_map *bmap, unsigned pos, isl_int *val) +{ + int i; + int d; + unsigned total; + + if (!bmap) + return isl_bool_error; + total = isl_basic_map_total_dim(bmap); + for (i = 0, d = total-1; i < bmap->n_eq && d+1 > pos; ++i) { + for (; d+1 > pos; --d) + if (!isl_int_is_zero(bmap->eq[i][1+d])) + break; + if (d != pos) + continue; + if (isl_seq_first_non_zero(bmap->eq[i]+1, d) != -1) + return isl_bool_false; + if (isl_seq_first_non_zero(bmap->eq[i]+1+d+1, total-d-1) != -1) + return isl_bool_false; + if (!isl_int_is_one(bmap->eq[i][1+d])) + return isl_bool_false; + if (val) + isl_int_neg(*val, bmap->eq[i][0]); + return isl_bool_true; + } + return isl_bool_false; +} + +static isl_bool isl_map_plain_has_fixed_var(__isl_keep isl_map *map, + unsigned pos, isl_int *val) +{ + int i; + isl_int v; + isl_int tmp; + isl_bool fixed; + + if (!map) + return isl_bool_error; + if (map->n == 0) + return isl_bool_false; + if (map->n == 1) + 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_plain_has_fixed_var(map->p[0], pos, &v); + for (i = 1; fixed == isl_bool_true && i < map->n; ++i) { + fixed = isl_basic_map_plain_has_fixed_var(map->p[i], pos, &tmp); + if (fixed == isl_bool_true && isl_int_ne(tmp, v)) + fixed = isl_bool_false; + } + if (val) + isl_int_set(*val, v); + isl_int_clear(tmp); + isl_int_clear(v); + return fixed; +} + +static isl_bool isl_basic_set_plain_has_fixed_var( + __isl_keep isl_basic_set *bset, unsigned pos, isl_int *val) +{ + return isl_basic_map_plain_has_fixed_var(bset_to_bmap(bset), + pos, val); +} + +isl_bool isl_basic_map_plain_is_fixed(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, isl_int *val) +{ + if (isl_basic_map_check_range(bmap, type, pos, 1) < 0) + return isl_bool_error; + return isl_basic_map_plain_has_fixed_var(bmap, + isl_basic_map_offset(bmap, type) - 1 + pos, val); +} + +/* If "bmap" obviously lies on a hyperplane where the given dimension + * has a fixed value, then return that value. + * Otherwise return NaN. + */ +__isl_give isl_val *isl_basic_map_plain_get_val_if_fixed( + __isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos) +{ + isl_ctx *ctx; + isl_val *v; + isl_bool fixed; + + if (!bmap) + return NULL; + ctx = isl_basic_map_get_ctx(bmap); + v = isl_val_alloc(ctx); + if (!v) + return NULL; + fixed = isl_basic_map_plain_is_fixed(bmap, type, pos, &v->n); + if (fixed < 0) + return isl_val_free(v); + if (fixed) { + isl_int_set_si(v->d, 1); + return v; + } + isl_val_free(v); + return isl_val_nan(ctx); +} + +isl_bool 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)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "position out of bounds", return isl_bool_error); + return isl_map_plain_has_fixed_var(map, + map_offset(map, type) - 1 + pos, val); +} + +/* If "map" obviously lies on a hyperplane where the given dimension + * has a fixed value, then return that value. + * Otherwise return NaN. + */ +__isl_give isl_val *isl_map_plain_get_val_if_fixed(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos) +{ + isl_ctx *ctx; + isl_val *v; + isl_bool fixed; + + if (!map) + return NULL; + ctx = isl_map_get_ctx(map); + v = isl_val_alloc(ctx); + if (!v) + return NULL; + fixed = isl_map_plain_is_fixed(map, type, pos, &v->n); + if (fixed < 0) + return isl_val_free(v); + if (fixed) { + isl_int_set_si(v->d, 1); + return v; + } + isl_val_free(v); + return isl_val_nan(ctx); +} + +/* If "set" obviously lies on a hyperplane where the given dimension + * has a fixed value, then return that value. + * Otherwise return NaN. + */ +__isl_give isl_val *isl_set_plain_get_val_if_fixed(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return isl_map_plain_get_val_if_fixed(set, type, pos); +} + +/* Check if dimension dim has fixed value and if so and if val is not NULL, + * then return this fixed value in *val. + */ +isl_bool isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset, + unsigned dim, isl_int *val) +{ + return isl_basic_set_plain_has_fixed_var(bset, + isl_basic_set_n_param(bset) + dim, val); +} + +/* Return -1 if the constraint "c1" should be sorted before "c2" + * and 1 if it should be sorted after "c2". + * Return 0 if the two constraints are the same (up to the constant term). + * + * In particular, if a constraint involves later variables than another + * then it is sorted after this other constraint. + * uset_gist depends on constraints without existentially quantified + * variables sorting first. + * + * For constraints that have the same latest variable, those + * with the same coefficient for this latest variable (first in absolute value + * and then in actual value) are grouped together. + * This is useful for detecting pairs of constraints that can + * be chained in their printed representation. + * + * Finally, within a group, constraints are sorted according to + * their coefficients (excluding the constant term). + */ +static int sort_constraint_cmp(const void *p1, const void *p2, void *arg) +{ + isl_int **c1 = (isl_int **) p1; + isl_int **c2 = (isl_int **) p2; + int l1, l2; + unsigned size = *(unsigned *) arg; + int cmp; + + l1 = isl_seq_last_non_zero(*c1 + 1, size); + l2 = isl_seq_last_non_zero(*c2 + 1, size); + + if (l1 != l2) + return l1 - l2; + + cmp = isl_int_abs_cmp((*c1)[1 + l1], (*c2)[1 + l1]); + if (cmp != 0) + return cmp; + cmp = isl_int_cmp((*c1)[1 + l1], (*c2)[1 + l1]); + if (cmp != 0) + return -cmp; + + return isl_seq_cmp(*c1 + 1, *c2 + 1, size); +} + +/* Return -1 if the constraint "c1" of "bmap" is sorted before "c2" + * by isl_basic_map_sort_constraints, 1 if it is sorted after "c2" + * and 0 if the two constraints are the same (up to the constant term). + */ +int isl_basic_map_constraint_cmp(__isl_keep isl_basic_map *bmap, + isl_int *c1, isl_int *c2) +{ + unsigned total; + + if (!bmap) + return -2; + total = isl_basic_map_total_dim(bmap); + return sort_constraint_cmp(&c1, &c2, &total); +} + +__isl_give isl_basic_map *isl_basic_map_sort_constraints( + __isl_take isl_basic_map *bmap) +{ + unsigned total; + + if (!bmap) + return NULL; + if (bmap->n_ineq == 0) + return bmap; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED)) + return bmap; + total = isl_basic_map_total_dim(bmap); + if (isl_sort(bmap->ineq, bmap->n_ineq, sizeof(isl_int *), + &sort_constraint_cmp, &total) < 0) + return isl_basic_map_free(bmap); + return bmap; +} + +__isl_give isl_basic_set *isl_basic_set_sort_constraints( + __isl_take isl_basic_set *bset) +{ + isl_basic_map *bmap = bset_to_bmap(bset); + return bset_from_bmap(isl_basic_map_sort_constraints(bmap)); +} + +__isl_give isl_basic_map *isl_basic_map_normalize( + __isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED)) + return bmap; + bmap = isl_basic_map_remove_redundancies(bmap); + bmap = isl_basic_map_sort_constraints(bmap); + if (bmap) + ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED); + return bmap; +} +int isl_basic_map_plain_cmp(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2) +{ + int i, cmp; + unsigned total; + isl_space *space1, *space2; + + if (!bmap1 || !bmap2) + return -1; + + if (bmap1 == bmap2) + return 0; + space1 = isl_basic_map_peek_space(bmap1); + space2 = isl_basic_map_peek_space(bmap2); + cmp = isl_space_cmp(space1, space2); + if (cmp) + return cmp; + if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) != + ISL_F_ISSET(bmap2, ISL_BASIC_MAP_RATIONAL)) + return ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) ? -1 : 1; + if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY) && + ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY)) + return 0; + if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY)) + return 1; + if (ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY)) + return -1; + if (bmap1->n_eq != bmap2->n_eq) + return bmap1->n_eq - bmap2->n_eq; + if (bmap1->n_ineq != bmap2->n_ineq) + return bmap1->n_ineq - bmap2->n_ineq; + if (bmap1->n_div != bmap2->n_div) + return bmap1->n_div - bmap2->n_div; + total = isl_basic_map_total_dim(bmap1); + for (i = 0; i < bmap1->n_eq; ++i) { + cmp = isl_seq_cmp(bmap1->eq[i], bmap2->eq[i], 1+total); + if (cmp) + return cmp; + } + for (i = 0; i < bmap1->n_ineq; ++i) { + cmp = isl_seq_cmp(bmap1->ineq[i], bmap2->ineq[i], 1+total); + if (cmp) + return cmp; + } + for (i = 0; i < bmap1->n_div; ++i) { + cmp = isl_seq_cmp(bmap1->div[i], bmap2->div[i], 1+1+total); + if (cmp) + return cmp; + } + return 0; +} + +int isl_basic_set_plain_cmp(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2) +{ + return isl_basic_map_plain_cmp(bset1, bset2); +} + +int isl_set_plain_cmp(__isl_keep isl_set *set1, __isl_keep isl_set *set2) +{ + int i, cmp; + + if (set1 == set2) + return 0; + if (set1->n != set2->n) + return set1->n - set2->n; + + for (i = 0; i < set1->n; ++i) { + cmp = isl_basic_set_plain_cmp(set1->p[i], set2->p[i]); + if (cmp) + return cmp; + } + + return 0; +} + +isl_bool isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2) +{ + if (!bmap1 || !bmap2) + return isl_bool_error; + return isl_basic_map_plain_cmp(bmap1, bmap2) == 0; +} + +isl_bool isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2) +{ + return isl_basic_map_plain_is_equal(bset_to_bmap(bset1), + bset_to_bmap(bset2)); +} + +static int qsort_bmap_cmp(const void *p1, const void *p2) +{ + isl_basic_map *bmap1 = *(isl_basic_map **) p1; + isl_basic_map *bmap2 = *(isl_basic_map **) p2; + + return isl_basic_map_plain_cmp(bmap1, bmap2); +} + +/* Sort the basic maps of "map" and remove duplicate basic maps. + * + * While removing basic maps, we make sure that the basic maps remain + * sorted because isl_map_normalize expects the basic maps of the result + * to be sorted. + */ +static __isl_give isl_map *sort_and_remove_duplicates(__isl_take isl_map *map) +{ + int i, j; + + map = isl_map_remove_empty_parts(map); + if (!map) + return NULL; + qsort(map->p, map->n, sizeof(struct isl_basic_map *), qsort_bmap_cmp); + for (i = map->n - 1; i >= 1; --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) + map->p[j - 1] = map->p[j]; + map->n--; + } + + return map; +} + +/* Remove obvious duplicates among the basic maps of "map". + * + * Unlike isl_map_normalize, this function does not remove redundant + * constraints and only removes duplicates that have exactly the same + * constraints in the input. It does sort the constraints and + * the basic maps to ease the detection of duplicates. + * + * If "map" has already been normalized or if the basic maps are + * disjoint, then there can be no duplicates. + */ +__isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map) +{ + int i; + isl_basic_map *bmap; + + if (!map) + return NULL; + if (map->n <= 1) + return map; + if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED | ISL_MAP_DISJOINT)) + return map; + for (i = 0; i < map->n; ++i) { + bmap = isl_basic_map_copy(map->p[i]); + bmap = isl_basic_map_sort_constraints(bmap); + if (!bmap) + return isl_map_free(map); + isl_basic_map_free(map->p[i]); + map->p[i] = bmap; + } + + map = sort_and_remove_duplicates(map); + return map; +} + +/* We normalize in place, but if anything goes wrong we need + * to return NULL, so we need to make sure we don't change the + * meaning of any possible other copies of map. + */ +__isl_give isl_map *isl_map_normalize(__isl_take isl_map *map) +{ + int i; + struct isl_basic_map *bmap; + + if (!map) + return NULL; + if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED)) + return map; + for (i = 0; i < map->n; ++i) { + bmap = isl_basic_map_normalize(isl_basic_map_copy(map->p[i])); + if (!bmap) + goto error; + isl_basic_map_free(map->p[i]); + map->p[i] = bmap; + } + + map = sort_and_remove_duplicates(map); + if (map) + ISL_F_SET(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +struct isl_set *isl_set_normalize(struct isl_set *set) +{ + return set_from_map(isl_map_normalize(set_to_map(set))); +} + +isl_bool isl_map_plain_is_equal(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + int i; + isl_bool equal; + + if (!map1 || !map2) + return isl_bool_error; + + if (map1 == map2) + return isl_bool_true; + if (!isl_space_is_equal(map1->dim, map2->dim)) + return isl_bool_false; + + map1 = isl_map_copy(map1); + map2 = isl_map_copy(map2); + map1 = isl_map_normalize(map1); + map2 = isl_map_normalize(map2); + if (!map1 || !map2) + goto error; + equal = map1->n == map2->n; + for (i = 0; equal && i < map1->n; ++i) { + equal = isl_basic_map_plain_is_equal(map1->p[i], map2->p[i]); + if (equal < 0) + goto error; + } + isl_map_free(map1); + isl_map_free(map2); + return equal; +error: + isl_map_free(map1); + isl_map_free(map2); + return isl_bool_error; +} + +isl_bool isl_set_plain_is_equal(__isl_keep isl_set *set1, + __isl_keep isl_set *set2) +{ + return isl_map_plain_is_equal(set_to_map(set1), set_to_map(set2)); +} + +/* Return the basic maps in "map" as a list. + */ +__isl_give isl_basic_map_list *isl_map_get_basic_map_list( + __isl_keep isl_map *map) +{ + int i; + isl_ctx *ctx; + isl_basic_map_list *list; + + if (!map) + return NULL; + ctx = isl_map_get_ctx(map); + list = isl_basic_map_list_alloc(ctx, map->n); + + for (i = 0; i < map->n; ++i) { + isl_basic_map *bmap; + + bmap = isl_basic_map_copy(map->p[i]); + list = isl_basic_map_list_add(list, bmap); + } + + return list; +} + +/* Return the intersection of the elements in the non-empty list "list". + * All elements are assumed to live in the same space. + */ +__isl_give isl_basic_map *isl_basic_map_list_intersect( + __isl_take isl_basic_map_list *list) +{ + int i, n; + isl_basic_map *bmap; + + if (!list) + return NULL; + n = isl_basic_map_list_n_basic_map(list); + if (n < 1) + isl_die(isl_basic_map_list_get_ctx(list), isl_error_invalid, + "expecting non-empty list", goto error); + + bmap = isl_basic_map_list_get_basic_map(list, 0); + for (i = 1; i < n; ++i) { + isl_basic_map *bmap_i; + + bmap_i = isl_basic_map_list_get_basic_map(list, i); + bmap = isl_basic_map_intersect(bmap, bmap_i); + } + + isl_basic_map_list_free(list); + return bmap; +error: + isl_basic_map_list_free(list); + return NULL; +} + +/* Return the intersection of the elements in the non-empty list "list". + * All elements are assumed to live in the same space. + */ +__isl_give isl_basic_set *isl_basic_set_list_intersect( + __isl_take isl_basic_set_list *list) +{ + return isl_basic_map_list_intersect(list); +} + +/* Return the union of the elements of "list". + * The list is required to have at least one element. + */ +__isl_give isl_set *isl_basic_set_list_union( + __isl_take isl_basic_set_list *list) +{ + int i, n; + isl_space *space; + isl_basic_set *bset; + isl_set *set; + + if (!list) + return NULL; + n = isl_basic_set_list_n_basic_set(list); + if (n < 1) + isl_die(isl_basic_set_list_get_ctx(list), isl_error_invalid, + "expecting non-empty list", goto error); + + bset = isl_basic_set_list_get_basic_set(list, 0); + space = isl_basic_set_get_space(bset); + isl_basic_set_free(bset); + + set = isl_set_alloc_space(space, n, 0); + for (i = 0; i < n; ++i) { + bset = isl_basic_set_list_get_basic_set(list, i); + set = isl_set_add_basic_set(set, bset); + } + + isl_basic_set_list_free(list); + return set; +error: + isl_basic_set_list_free(list); + return NULL; +} + +/* Return the union of the elements in the non-empty list "list". + * All elements are assumed to live in the same space. + */ +__isl_give isl_set *isl_set_list_union(__isl_take isl_set_list *list) +{ + int i, n; + isl_set *set; + + if (!list) + return NULL; + n = isl_set_list_n_set(list); + if (n < 1) + isl_die(isl_set_list_get_ctx(list), isl_error_invalid, + "expecting non-empty list", goto error); + + set = isl_set_list_get_set(list, 0); + for (i = 1; i < n; ++i) { + isl_set *set_i; + + set_i = isl_set_list_get_set(list, i); + set = isl_set_union(set, set_i); + } + + isl_set_list_free(list); + return set; +error: + isl_set_list_free(list); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) +{ + isl_space *dim_result = NULL; + struct isl_basic_map *bmap; + unsigned in1, in2, out1, out2, nparam, total, pos; + struct isl_dim_map *dim_map1, *dim_map2; + + if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) + goto error; + dim_result = isl_space_product(isl_space_copy(bmap1->dim), + isl_space_copy(bmap2->dim)); + + in1 = isl_basic_map_dim(bmap1, isl_dim_in); + in2 = isl_basic_map_dim(bmap2, isl_dim_in); + out1 = isl_basic_map_dim(bmap1, isl_dim_out); + out2 = isl_basic_map_dim(bmap2, isl_dim_out); + nparam = isl_basic_map_dim(bmap1, isl_dim_param); + + total = nparam + in1 + in2 + out1 + out2 + bmap1->n_div + bmap2->n_div; + dim_map1 = isl_dim_map_alloc(bmap1->ctx, total); + dim_map2 = isl_dim_map_alloc(bmap1->ctx, total); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1); + isl_dim_map_div(dim_map1, bmap1, pos += out2); + isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div); + + bmap = isl_basic_map_alloc_space(dim_result, + bmap1->n_div + bmap2->n_div, + bmap1->n_eq + bmap2->n_eq, + bmap1->n_ineq + bmap2->n_ineq); + 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: + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_flat_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) +{ + isl_basic_map *prod; + + prod = isl_basic_map_product(bmap1, bmap2); + prod = isl_basic_map_flatten(prod); + return prod; +} + +__isl_give isl_basic_set *isl_basic_set_flat_product( + __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) +{ + return isl_basic_map_flat_range_product(bset1, bset2); +} + +__isl_give isl_basic_map *isl_basic_map_domain_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) +{ + isl_space *space_result = NULL; + isl_basic_map *bmap; + unsigned in1, in2, out, nparam, total, pos; + struct isl_dim_map *dim_map1, *dim_map2; + + if (!bmap1 || !bmap2) + goto error; + + space_result = isl_space_domain_product(isl_space_copy(bmap1->dim), + isl_space_copy(bmap2->dim)); + + in1 = isl_basic_map_dim(bmap1, isl_dim_in); + in2 = isl_basic_map_dim(bmap2, isl_dim_in); + out = isl_basic_map_dim(bmap1, isl_dim_out); + nparam = isl_basic_map_dim(bmap1, isl_dim_param); + + total = nparam + in1 + in2 + out + bmap1->n_div + bmap2->n_div; + dim_map1 = isl_dim_map_alloc(bmap1->ctx, total); + dim_map2 = isl_dim_map_alloc(bmap1->ctx, total); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos); + isl_dim_map_div(dim_map1, bmap1, pos += out); + isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div); + + bmap = isl_basic_map_alloc_space(space_result, + bmap1->n_div + bmap2->n_div, + bmap1->n_eq + bmap2->n_eq, + bmap1->n_ineq + bmap2->n_ineq); + 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: + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_range_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) +{ + isl_bool rational; + isl_space *dim_result = NULL; + isl_basic_map *bmap; + unsigned in, out1, out2, nparam, total, pos; + struct isl_dim_map *dim_map1, *dim_map2; + + rational = isl_basic_map_is_rational(bmap1); + if (rational >= 0 && rational) + rational = isl_basic_map_is_rational(bmap2); + if (!bmap1 || !bmap2 || rational < 0) + goto error; + + if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) + goto error; + + dim_result = isl_space_range_product(isl_space_copy(bmap1->dim), + isl_space_copy(bmap2->dim)); + + in = isl_basic_map_dim(bmap1, isl_dim_in); + out1 = isl_basic_map_dim(bmap1, isl_dim_out); + out2 = isl_basic_map_dim(bmap2, isl_dim_out); + nparam = isl_basic_map_dim(bmap1, isl_dim_param); + + total = nparam + in + out1 + out2 + bmap1->n_div + bmap2->n_div; + dim_map1 = isl_dim_map_alloc(bmap1->ctx, total); + dim_map2 = isl_dim_map_alloc(bmap1->ctx, total); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos); + isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in); + isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1); + isl_dim_map_div(dim_map1, bmap1, pos += out2); + isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div); + + bmap = isl_basic_map_alloc_space(dim_result, + bmap1->n_div + bmap2->n_div, + bmap1->n_eq + bmap2->n_eq, + bmap1->n_ineq + bmap2->n_ineq); + bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1); + bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2); + if (rational) + bmap = isl_basic_map_set_rational(bmap); + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_flat_range_product( + __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) +{ + isl_basic_map *prod; + + prod = isl_basic_map_range_product(bmap1, bmap2); + prod = isl_basic_map_flatten_range(prod); + return prod; +} + +/* Apply "basic_map_product" to each pair of basic maps in "map1" and "map2" + * and collect the results. + * The result live in the space obtained by calling "space_product" + * on the spaces of "map1" and "map2". + * If "remove_duplicates" is set then the result may contain duplicates + * (even if the inputs do not) and so we try and remove the obvious + * duplicates. + */ +static __isl_give isl_map *map_product(__isl_take isl_map *map1, + __isl_take isl_map *map2, + __isl_give isl_space *(*space_product)(__isl_take isl_space *left, + __isl_take isl_space *right), + __isl_give isl_basic_map *(*basic_map_product)( + __isl_take isl_basic_map *left, + __isl_take isl_basic_map *right), + int remove_duplicates) +{ + unsigned flags = 0; + struct isl_map *result; + int i, j; + isl_bool m; + + m = isl_map_has_equal_params(map1, map2); + if (m < 0) + goto error; + if (!m) + isl_die(isl_map_get_ctx(map1), isl_error_invalid, + "parameters don't match", goto error); + + if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) && + ISL_F_ISSET(map2, ISL_MAP_DISJOINT)) + ISL_FL_SET(flags, ISL_MAP_DISJOINT); + + result = isl_map_alloc_space(space_product(isl_space_copy(map1->dim), + isl_space_copy(map2->dim)), + map1->n * map2->n, flags); + if (!result) + goto error; + for (i = 0; i < map1->n; ++i) + for (j = 0; j < map2->n; ++j) { + struct isl_basic_map *part; + part = basic_map_product(isl_basic_map_copy(map1->p[i]), + isl_basic_map_copy(map2->p[j])); + if (isl_basic_map_is_empty(part)) + isl_basic_map_free(part); + else + result = isl_map_add_basic_map(result, part); + if (!result) + goto error; + } + if (remove_duplicates) + result = isl_map_remove_obvious_duplicates(result); + isl_map_free(map1); + isl_map_free(map2); + return result; +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +/* Given two maps A -> B and C -> D, construct a map [A -> C] -> [B -> D] + */ +static __isl_give isl_map *map_product_aligned(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return map_product(map1, map2, &isl_space_product, + &isl_basic_map_product, 0); +} + +__isl_give isl_map *isl_map_product(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, &map_product_aligned); +} + +/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B, D) + */ +__isl_give isl_map *isl_map_flat_product(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_map *prod; + + prod = isl_map_product(map1, map2); + prod = isl_map_flatten(prod); + return prod; +} + +/* Given two set A and B, construct its Cartesian product A x B. + */ +struct isl_set *isl_set_product(struct isl_set *set1, struct isl_set *set2) +{ + return isl_map_range_product(set1, set2); +} + +__isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1, + __isl_take isl_set *set2) +{ + return isl_map_flat_range_product(set1, set2); +} + +/* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D) + */ +static __isl_give isl_map *map_domain_product_aligned(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return map_product(map1, map2, &isl_space_domain_product, + &isl_basic_map_domain_product, 1); +} + +/* Given two maps A -> B and C -> D, construct a map (A * C) -> [B -> D] + */ +static __isl_give isl_map *map_range_product_aligned(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return map_product(map1, map2, &isl_space_range_product, + &isl_basic_map_range_product, 1); +} + +__isl_give isl_map *isl_map_domain_product(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, + &map_domain_product_aligned); +} + +__isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, + &map_range_product_aligned); +} + +/* Given a map of the form [A -> B] -> [C -> D], return the map A -> C. + */ +__isl_give isl_map *isl_map_factor_domain(__isl_take isl_map *map) +{ + isl_space *space; + int total1, keep1, total2, keep2; + + if (!map) + return NULL; + if (!isl_space_domain_is_wrapping(map->dim) || + !isl_space_range_is_wrapping(map->dim)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "not a product", return isl_map_free(map)); + + space = isl_map_get_space(map); + total1 = isl_space_dim(space, isl_dim_in); + total2 = isl_space_dim(space, isl_dim_out); + space = isl_space_factor_domain(space); + keep1 = isl_space_dim(space, isl_dim_in); + keep2 = isl_space_dim(space, isl_dim_out); + map = isl_map_project_out(map, isl_dim_in, keep1, total1 - keep1); + map = isl_map_project_out(map, isl_dim_out, keep2, total2 - keep2); + map = isl_map_reset_space(map, space); + + return map; +} + +/* Given a map of the form [A -> B] -> [C -> D], return the map B -> D. + */ +__isl_give isl_map *isl_map_factor_range(__isl_take isl_map *map) +{ + isl_space *space; + int total1, keep1, total2, keep2; + + if (!map) + return NULL; + if (!isl_space_domain_is_wrapping(map->dim) || + !isl_space_range_is_wrapping(map->dim)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "not a product", return isl_map_free(map)); + + space = isl_map_get_space(map); + total1 = isl_space_dim(space, isl_dim_in); + total2 = isl_space_dim(space, isl_dim_out); + space = isl_space_factor_range(space); + keep1 = isl_space_dim(space, isl_dim_in); + keep2 = isl_space_dim(space, isl_dim_out); + map = isl_map_project_out(map, isl_dim_in, 0, total1 - keep1); + map = isl_map_project_out(map, isl_dim_out, 0, total2 - keep2); + map = isl_map_reset_space(map, space); + + return map; +} + +/* Given a map of the form [A -> B] -> C, return the map A -> C. + */ +__isl_give isl_map *isl_map_domain_factor_domain(__isl_take isl_map *map) +{ + isl_space *space; + int total, keep; + + if (!map) + return NULL; + if (!isl_space_domain_is_wrapping(map->dim)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "domain is not a product", return isl_map_free(map)); + + space = isl_map_get_space(map); + total = isl_space_dim(space, isl_dim_in); + space = isl_space_domain_factor_domain(space); + keep = isl_space_dim(space, isl_dim_in); + map = isl_map_project_out(map, isl_dim_in, keep, total - keep); + map = isl_map_reset_space(map, space); + + return map; +} + +/* Given a map of the form [A -> B] -> C, return the map B -> C. + */ +__isl_give isl_map *isl_map_domain_factor_range(__isl_take isl_map *map) +{ + isl_space *space; + int total, keep; + + if (!map) + return NULL; + if (!isl_space_domain_is_wrapping(map->dim)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "domain is not a product", return isl_map_free(map)); + + space = isl_map_get_space(map); + total = isl_space_dim(space, isl_dim_in); + space = isl_space_domain_factor_range(space); + keep = isl_space_dim(space, isl_dim_in); + map = isl_map_project_out(map, isl_dim_in, 0, total - keep); + map = isl_map_reset_space(map, space); + + return map; +} + +/* Given a map A -> [B -> C], extract the map A -> B. + */ +__isl_give isl_map *isl_map_range_factor_domain(__isl_take isl_map *map) +{ + isl_space *space; + int total, keep; + + if (!map) + return NULL; + if (!isl_space_range_is_wrapping(map->dim)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "range is not a product", return isl_map_free(map)); + + space = isl_map_get_space(map); + total = isl_space_dim(space, isl_dim_out); + space = isl_space_range_factor_domain(space); + keep = isl_space_dim(space, isl_dim_out); + map = isl_map_project_out(map, isl_dim_out, keep, total - keep); + map = isl_map_reset_space(map, space); + + return map; +} + +/* Given a map A -> [B -> C], extract the map A -> C. + */ +__isl_give isl_map *isl_map_range_factor_range(__isl_take isl_map *map) +{ + isl_space *space; + int total, keep; + + if (!map) + return NULL; + if (!isl_space_range_is_wrapping(map->dim)) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "range is not a product", return isl_map_free(map)); + + space = isl_map_get_space(map); + total = isl_space_dim(space, isl_dim_out); + space = isl_space_range_factor_range(space); + keep = isl_space_dim(space, isl_dim_out); + map = isl_map_project_out(map, isl_dim_out, 0, total - keep); + map = isl_map_reset_space(map, space); + + return map; +} + +/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D) + */ +__isl_give isl_map *isl_map_flat_domain_product(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_map *prod; + + prod = isl_map_domain_product(map1, map2); + prod = isl_map_flatten_domain(prod); + return prod; +} + +/* Given two maps A -> B and C -> D, construct a map (A * C) -> (B, D) + */ +__isl_give isl_map *isl_map_flat_range_product(__isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_map *prod; + + prod = isl_map_range_product(map1, map2); + prod = isl_map_flatten_range(prod); + return prod; +} + +uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap) +{ + int i; + uint32_t hash = isl_hash_init(); + unsigned total; + + if (!bmap) + return 0; + bmap = isl_basic_map_copy(bmap); + bmap = isl_basic_map_normalize(bmap); + if (!bmap) + return 0; + total = isl_basic_map_total_dim(bmap); + isl_hash_byte(hash, bmap->n_eq & 0xFF); + for (i = 0; i < bmap->n_eq; ++i) { + uint32_t c_hash; + c_hash = isl_seq_get_hash(bmap->eq[i], 1 + total); + isl_hash_hash(hash, c_hash); + } + isl_hash_byte(hash, bmap->n_ineq & 0xFF); + for (i = 0; i < bmap->n_ineq; ++i) { + uint32_t c_hash; + c_hash = isl_seq_get_hash(bmap->ineq[i], 1 + total); + isl_hash_hash(hash, c_hash); + } + isl_hash_byte(hash, bmap->n_div & 0xFF); + for (i = 0; i < bmap->n_div; ++i) { + uint32_t c_hash; + if (isl_int_is_zero(bmap->div[i][0])) + continue; + isl_hash_byte(hash, i & 0xFF); + c_hash = isl_seq_get_hash(bmap->div[i], 1 + 1 + total); + isl_hash_hash(hash, c_hash); + } + isl_basic_map_free(bmap); + return hash; +} + +uint32_t isl_basic_set_get_hash(__isl_keep isl_basic_set *bset) +{ + return isl_basic_map_get_hash(bset_to_bmap(bset)); +} + +uint32_t isl_map_get_hash(__isl_keep isl_map *map) +{ + int i; + uint32_t hash; + + if (!map) + return 0; + map = isl_map_copy(map); + map = isl_map_normalize(map); + if (!map) + return 0; + + hash = isl_hash_init(); + for (i = 0; i < map->n; ++i) { + uint32_t bmap_hash; + bmap_hash = isl_basic_map_get_hash(map->p[i]); + isl_hash_hash(hash, bmap_hash); + } + + isl_map_free(map); + + return hash; +} + +uint32_t isl_set_get_hash(__isl_keep isl_set *set) +{ + return isl_map_get_hash(set_to_map(set)); +} + +/* Return the number of basic maps in the (current) representation of "map". + */ +int isl_map_n_basic_map(__isl_keep isl_map *map) +{ + return map ? map->n : 0; +} + +int isl_set_n_basic_set(__isl_keep isl_set *set) +{ + return set ? set->n : 0; +} + +isl_stat isl_map_foreach_basic_map(__isl_keep isl_map *map, + isl_stat (*fn)(__isl_take isl_basic_map *bmap, void *user), void *user) +{ + int i; + + if (!map) + return isl_stat_error; + + for (i = 0; i < map->n; ++i) + if (fn(isl_basic_map_copy(map->p[i]), user) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +isl_stat isl_set_foreach_basic_set(__isl_keep isl_set *set, + isl_stat (*fn)(__isl_take isl_basic_set *bset, void *user), void *user) +{ + int i; + + if (!set) + return isl_stat_error; + + for (i = 0; i < set->n; ++i) + if (fn(isl_basic_set_copy(set->p[i]), user) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Return a list of basic sets, the union of which is equal to "set". + */ +__isl_give isl_basic_set_list *isl_set_get_basic_set_list( + __isl_keep isl_set *set) +{ + int i; + isl_basic_set_list *list; + + if (!set) + return NULL; + + list = isl_basic_set_list_alloc(isl_set_get_ctx(set), set->n); + for (i = 0; i < set->n; ++i) { + isl_basic_set *bset; + + bset = isl_basic_set_copy(set->p[i]); + list = isl_basic_set_list_add(list, bset); + } + + return list; +} + +__isl_give isl_basic_set *isl_basic_set_lift(__isl_take isl_basic_set *bset) +{ + isl_space *dim; + + if (!bset) + return NULL; + + bset = isl_basic_set_cow(bset); + if (!bset) + return NULL; + + dim = isl_basic_set_get_space(bset); + dim = isl_space_lift(dim, bset->n_div); + if (!dim) + goto error; + isl_space_free(bset->dim); + bset->dim = dim; + bset->extra -= bset->n_div; + bset->n_div = 0; + + bset = isl_basic_set_finalize(bset); + + return bset; +error: + isl_basic_set_free(bset); + return NULL; +} + +__isl_give isl_set *isl_set_lift(__isl_take isl_set *set) +{ + int i; + isl_space *dim; + unsigned n_div; + + set = set_from_map(isl_map_align_divs_internal(set_to_map(set))); + + if (!set) + return NULL; + + set = isl_set_cow(set); + if (!set) + return NULL; + + n_div = set->p[0]->n_div; + dim = isl_set_get_space(set); + dim = isl_space_lift(dim, n_div); + if (!dim) + goto error; + isl_space_free(set->dim); + set->dim = dim; + + for (i = 0; i < set->n; ++i) { + set->p[i] = isl_basic_set_lift(set->p[i]); + if (!set->p[i]) + goto error; + } + + return set; +error: + isl_set_free(set); + return NULL; +} + +int isl_basic_set_size(__isl_keep isl_basic_set *bset) +{ + unsigned dim; + int size = 0; + + if (!bset) + return -1; + + dim = isl_basic_set_total_dim(bset); + size += bset->n_eq * (1 + dim); + size += bset->n_ineq * (1 + dim); + size += bset->n_div * (2 + dim); + + return size; +} + +int isl_set_size(__isl_keep isl_set *set) +{ + int i; + int size = 0; + + if (!set) + return -1; + + for (i = 0; i < set->n; ++i) + size += isl_basic_set_size(set->p[i]); + + return size; +} + +/* Check if there is any lower bound (if lower == 0) and/or upper + * bound (if upper == 0) on the specified dim. + */ +static isl_bool basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, int lower, int upper) +{ + int i; + + if (isl_basic_map_check_range(bmap, type, pos, 1) < 0) + return isl_bool_error; + + pos += isl_basic_map_offset(bmap, type); + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (!isl_int_is_zero(bmap->div[i][1 + pos])) + return isl_bool_true; + } + + for (i = 0; i < bmap->n_eq; ++i) + if (!isl_int_is_zero(bmap->eq[i][pos])) + return isl_bool_true; + + for (i = 0; i < bmap->n_ineq; ++i) { + int sgn = isl_int_sgn(bmap->ineq[i][pos]); + if (sgn > 0) + lower = 1; + if (sgn < 0) + upper = 1; + } + + return lower && upper; +} + +isl_bool isl_basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos) +{ + return basic_map_dim_is_bounded(bmap, type, pos, 0, 0); +} + +isl_bool isl_basic_map_dim_has_lower_bound(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos) +{ + return basic_map_dim_is_bounded(bmap, type, pos, 0, 1); +} + +isl_bool isl_basic_map_dim_has_upper_bound(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos) +{ + return basic_map_dim_is_bounded(bmap, type, pos, 1, 0); +} + +isl_bool isl_map_dim_is_bounded(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos) +{ + int i; + + if (!map) + return isl_bool_error; + + for (i = 0; i < map->n; ++i) { + isl_bool bounded; + bounded = isl_basic_map_dim_is_bounded(map->p[i], type, pos); + if (bounded < 0 || !bounded) + return bounded; + } + + return isl_bool_true; +} + +/* Return true if the specified dim is involved in both an upper bound + * and a lower bound. + */ +isl_bool isl_set_dim_is_bounded(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return isl_map_dim_is_bounded(set_to_map(set), type, pos); +} + +/* Does "map" have a bound (according to "fn") for any of its basic maps? + */ +static isl_bool has_any_bound(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos, + isl_bool (*fn)(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos)) +{ + int i; + + if (!map) + return isl_bool_error; + + for (i = 0; i < map->n; ++i) { + isl_bool bounded; + bounded = fn(map->p[i], type, pos); + if (bounded < 0 || bounded) + return bounded; + } + + return isl_bool_false; +} + +/* Return 1 if the specified dim is involved in any lower bound. + */ +isl_bool isl_set_dim_has_any_lower_bound(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return has_any_bound(set, type, pos, + &isl_basic_map_dim_has_lower_bound); +} + +/* Return 1 if the specified dim is involved in any upper bound. + */ +isl_bool isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return has_any_bound(set, type, pos, + &isl_basic_map_dim_has_upper_bound); +} + +/* Does "map" have a bound (according to "fn") for all of its basic maps? + */ +static isl_bool has_bound(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos, + isl_bool (*fn)(__isl_keep isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos)) +{ + int i; + + if (!map) + return isl_bool_error; + + for (i = 0; i < map->n; ++i) { + isl_bool bounded; + bounded = fn(map->p[i], type, pos); + if (bounded < 0 || !bounded) + return bounded; + } + + return isl_bool_true; +} + +/* Return 1 if the specified dim has a lower bound (in each of its basic sets). + */ +isl_bool isl_set_dim_has_lower_bound(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return has_bound(set, type, pos, &isl_basic_map_dim_has_lower_bound); +} + +/* Return 1 if the specified dim has an upper bound (in each of its basic sets). + */ +isl_bool isl_set_dim_has_upper_bound(__isl_keep isl_set *set, + enum isl_dim_type type, unsigned pos) +{ + return has_bound(set, type, pos, &isl_basic_map_dim_has_upper_bound); +} + +/* For each of the "n" variables starting at "first", determine + * the sign of the variable and put the results in the first "n" + * elements of the array "signs". + * Sign + * 1 means that the variable is non-negative + * -1 means that the variable is non-positive + * 0 means the variable attains both positive and negative values. + */ +isl_stat isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset, + unsigned first, unsigned n, int *signs) +{ + isl_vec *bound = NULL; + struct isl_tab *tab = NULL; + struct isl_tab_undo *snap; + int i; + + if (!bset || !signs) + return isl_stat_error; + + bound = isl_vec_alloc(bset->ctx, 1 + isl_basic_set_total_dim(bset)); + tab = isl_tab_from_basic_set(bset, 0); + if (!bound || !tab) + goto error; + + isl_seq_clr(bound->el, bound->size); + isl_int_set_si(bound->el[0], -1); + + snap = isl_tab_snap(tab); + for (i = 0; i < n; ++i) { + int empty; + + isl_int_set_si(bound->el[1 + first + i], -1); + if (isl_tab_add_ineq(tab, bound->el) < 0) + goto error; + empty = tab->empty; + isl_int_set_si(bound->el[1 + first + i], 0); + if (isl_tab_rollback(tab, snap) < 0) + goto error; + + if (empty) { + signs[i] = 1; + continue; + } + + isl_int_set_si(bound->el[1 + first + i], 1); + if (isl_tab_add_ineq(tab, bound->el) < 0) + goto error; + empty = tab->empty; + isl_int_set_si(bound->el[1 + first + i], 0); + if (isl_tab_rollback(tab, snap) < 0) + goto error; + + signs[i] = empty ? -1 : 0; + } + + isl_tab_free(tab); + isl_vec_free(bound); + return isl_stat_ok; +error: + isl_tab_free(tab); + isl_vec_free(bound); + return isl_stat_error; +} + +isl_stat isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n, int *signs) +{ + if (!bset || !signs) + return isl_stat_error; + isl_assert(bset->ctx, first + n <= isl_basic_set_dim(bset, type), + return isl_stat_error); + + first += pos(bset->dim, type) - 1; + return isl_basic_set_vars_get_sign(bset, first, n, signs); +} + +/* Is it possible for the integer division "div" to depend (possibly + * indirectly) on any output dimensions? + * + * If the div is undefined, then we conservatively assume that it + * may depend on them. + * Otherwise, we check if it actually depends on them or on any integer + * divisions that may depend on them. + */ +static isl_bool div_may_involve_output(__isl_keep isl_basic_map *bmap, int div) +{ + int i; + unsigned n_out, o_out; + unsigned n_div, o_div; + + if (isl_int_is_zero(bmap->div[div][0])) + return isl_bool_true; + + n_out = isl_basic_map_dim(bmap, isl_dim_out); + o_out = isl_basic_map_offset(bmap, isl_dim_out); + + if (isl_seq_first_non_zero(bmap->div[div] + 1 + o_out, n_out) != -1) + return isl_bool_true; + + n_div = isl_basic_map_dim(bmap, isl_dim_div); + o_div = isl_basic_map_offset(bmap, isl_dim_div); + + for (i = 0; i < n_div; ++i) { + isl_bool may_involve; + + if (isl_int_is_zero(bmap->div[div][1 + o_div + i])) + continue; + may_involve = div_may_involve_output(bmap, i); + if (may_involve < 0 || may_involve) + return may_involve; + } + + return isl_bool_false; +} + +/* Return the first integer division of "bmap" in the range + * [first, first + n[ that may depend on any output dimensions and + * that has a non-zero coefficient in "c" (where the first coefficient + * in "c" corresponds to integer division "first"). + */ +static int first_div_may_involve_output(__isl_keep isl_basic_map *bmap, + isl_int *c, int first, int n) +{ + int k; + + if (!bmap) + return -1; + + for (k = first; k < first + n; ++k) { + isl_bool may_involve; + + if (isl_int_is_zero(c[k])) + continue; + may_involve = div_may_involve_output(bmap, k); + if (may_involve < 0) + return -1; + if (may_involve) + return k; + } + + return first + n; +} + +/* Look for a pair of inequality constraints in "bmap" of the form + * + * -l + i >= 0 or i >= l + * and + * n + l - i >= 0 or i <= l + n + * + * with n < "m" and i the output dimension at position "pos". + * (Note that n >= 0 as otherwise the two constraints would conflict.) + * Furthermore, "l" is only allowed to involve parameters, input dimensions + * and earlier output dimensions, as well as integer divisions that do + * not involve any of the output dimensions. + * + * Return the index of the first inequality constraint or bmap->n_ineq + * if no such pair can be found. + */ +static int find_modulo_constraint_pair(__isl_keep isl_basic_map *bmap, + int pos, isl_int m) +{ + int i, j; + isl_ctx *ctx; + unsigned total; + unsigned n_div, o_div; + unsigned n_out, o_out; + int less; + + if (!bmap) + return -1; + + ctx = isl_basic_map_get_ctx(bmap); + total = isl_basic_map_total_dim(bmap); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + o_out = isl_basic_map_offset(bmap, isl_dim_out); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + o_div = isl_basic_map_offset(bmap, isl_dim_div); + for (i = 0; i < bmap->n_ineq; ++i) { + if (!isl_int_abs_eq(bmap->ineq[i][o_out + pos], ctx->one)) + continue; + if (isl_seq_first_non_zero(bmap->ineq[i] + o_out + pos + 1, + n_out - (pos + 1)) != -1) + continue; + if (first_div_may_involve_output(bmap, bmap->ineq[i] + o_div, + 0, n_div) < n_div) + continue; + for (j = i + 1; j < bmap->n_ineq; ++j) { + if (!isl_int_abs_eq(bmap->ineq[j][o_out + pos], + ctx->one)) + continue; + if (!isl_seq_is_neg(bmap->ineq[i] + 1, + bmap->ineq[j] + 1, total)) + continue; + break; + } + if (j >= bmap->n_ineq) + continue; + isl_int_add(bmap->ineq[i][0], + bmap->ineq[i][0], bmap->ineq[j][0]); + less = isl_int_abs_lt(bmap->ineq[i][0], m); + isl_int_sub(bmap->ineq[i][0], + bmap->ineq[i][0], bmap->ineq[j][0]); + if (!less) + continue; + if (isl_int_is_one(bmap->ineq[i][o_out + pos])) + return i; + else + return j; + } + + return bmap->n_ineq; +} + +/* Return the index of the equality of "bmap" that defines + * the output dimension "pos" in terms of earlier dimensions. + * The equality may also involve integer divisions, as long + * as those integer divisions are defined in terms of + * parameters or input dimensions. + * In this case, *div is set to the number of integer divisions and + * *ineq is set to the number of inequality constraints (provided + * div and ineq are not NULL). + * + * The equality may also involve a single integer division involving + * the output dimensions (typically only output dimension "pos") as + * long as the coefficient of output dimension "pos" is 1 or -1 and + * there is a pair of constraints i >= l and i <= l + n, with i referring + * to output dimension "pos", l an expression involving only earlier + * dimensions and n smaller than the coefficient of the integer division + * in the equality. In this case, the output dimension can be defined + * in terms of a modulo expression that does not involve the integer division. + * *div is then set to this single integer division and + * *ineq is set to the index of constraint i >= l. + * + * Return bmap->n_eq if there is no such equality. + * Return -1 on error. + */ +int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap, + int pos, int *div, int *ineq) +{ + int j, k, l; + unsigned n_out, o_out; + unsigned n_div, o_div; + + if (!bmap) + return -1; + + n_out = isl_basic_map_dim(bmap, isl_dim_out); + o_out = isl_basic_map_offset(bmap, isl_dim_out); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + o_div = isl_basic_map_offset(bmap, isl_dim_div); + + if (ineq) + *ineq = bmap->n_ineq; + if (div) + *div = n_div; + for (j = 0; j < bmap->n_eq; ++j) { + if (isl_int_is_zero(bmap->eq[j][o_out + pos])) + continue; + if (isl_seq_first_non_zero(bmap->eq[j] + o_out + pos + 1, + n_out - (pos + 1)) != -1) + continue; + k = first_div_may_involve_output(bmap, bmap->eq[j] + o_div, + 0, n_div); + if (k >= n_div) + return j; + if (!isl_int_is_one(bmap->eq[j][o_out + pos]) && + !isl_int_is_negone(bmap->eq[j][o_out + pos])) + continue; + if (first_div_may_involve_output(bmap, bmap->eq[j] + o_div, + k + 1, n_div - (k+1)) < n_div) + continue; + l = find_modulo_constraint_pair(bmap, pos, + bmap->eq[j][o_div + k]); + if (l < 0) + return -1; + if (l >= bmap->n_ineq) + continue; + if (div) + *div = k; + if (ineq) + *ineq = l; + return j; + } + + return bmap->n_eq; +} + +/* Check if the given basic map is obviously single-valued. + * In particular, for each output dimension, check that there is + * an equality that defines the output dimension in terms of + * earlier dimensions. + */ +isl_bool isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap) +{ + int i; + unsigned n_out; + + if (!bmap) + return isl_bool_error; + + n_out = isl_basic_map_dim(bmap, isl_dim_out); + + for (i = 0; i < n_out; ++i) { + int eq; + + eq = isl_basic_map_output_defining_equality(bmap, i, + NULL, NULL); + if (eq < 0) + return isl_bool_error; + if (eq >= bmap->n_eq) + return isl_bool_false; + } + + return isl_bool_true; +} + +/* Check if the given basic map is single-valued. + * We simply compute + * + * M \circ M^-1 + * + * and check if the result is a subset of the identity mapping. + */ +isl_bool isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap) +{ + isl_space *space; + isl_basic_map *test; + isl_basic_map *id; + isl_bool sv; + + sv = isl_basic_map_plain_is_single_valued(bmap); + if (sv < 0 || sv) + return sv; + + test = isl_basic_map_reverse(isl_basic_map_copy(bmap)); + test = isl_basic_map_apply_range(test, isl_basic_map_copy(bmap)); + + space = isl_basic_map_get_space(bmap); + space = isl_space_map_from_set(isl_space_range(space)); + id = isl_basic_map_identity(space); + + sv = isl_basic_map_is_subset(test, id); + + isl_basic_map_free(test); + isl_basic_map_free(id); + + return sv; +} + +/* Check if the given map is obviously single-valued. + */ +isl_bool isl_map_plain_is_single_valued(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + if (map->n == 0) + return isl_bool_true; + if (map->n >= 2) + return isl_bool_false; + + return isl_basic_map_plain_is_single_valued(map->p[0]); +} + +/* 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. + */ +isl_bool isl_map_is_single_valued(__isl_keep isl_map *map) +{ + isl_space *dim; + isl_map *test; + isl_map *id; + isl_bool sv; + + sv = isl_map_plain_is_single_valued(map); + if (sv < 0 || sv) + return sv; + + test = isl_map_reverse(isl_map_copy(map)); + test = isl_map_apply_range(test, isl_map_copy(map)); + + dim = isl_space_map_from_set(isl_space_range(isl_map_get_space(map))); + id = isl_map_identity(dim); + + sv = isl_map_is_subset(test, id); + + isl_map_free(test); + isl_map_free(id); + + return sv; +} + +isl_bool isl_map_is_injective(__isl_keep isl_map *map) +{ + isl_bool 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. + */ +isl_bool isl_map_plain_is_injective(__isl_keep isl_map *map) +{ + isl_bool 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; +} + +isl_bool isl_map_is_bijective(__isl_keep isl_map *map) +{ + isl_bool sv; + + sv = isl_map_is_single_valued(map); + if (sv < 0 || !sv) + return sv; + + return isl_map_is_injective(map); +} + +isl_bool isl_set_is_singleton(__isl_keep isl_set *set) +{ + return isl_map_is_single_valued(set_to_map(set)); +} + +/* Does "map" only map elements to themselves? + * + * If the domain and range spaces are different, then "map" + * is considered not to be an identity relation, even if it is empty. + * Otherwise, construct the maximal identity relation and + * check whether "map" is a subset of this relation. + */ +isl_bool isl_map_is_identity(__isl_keep isl_map *map) +{ + isl_space *space; + isl_map *id; + isl_bool equal, is_identity; + + space = isl_map_get_space(map); + equal = isl_space_tuple_is_equal(space, isl_dim_in, space, isl_dim_out); + isl_space_free(space); + if (equal < 0 || !equal) + return equal; + + id = isl_map_identity(isl_map_get_space(map)); + is_identity = isl_map_is_subset(map, id); + isl_map_free(id); + + return is_identity; +} + +int isl_map_is_translation(__isl_keep isl_map *map) +{ + int ok; + isl_set *delta; + + delta = isl_map_deltas(isl_map_copy(map)); + ok = isl_set_is_singleton(delta); + isl_set_free(delta); + + return ok; +} + +static int unique(isl_int *p, unsigned pos, unsigned len) +{ + if (isl_seq_first_non_zero(p, pos) != -1) + return 0; + if (isl_seq_first_non_zero(p + pos + 1, len - pos - 1) != -1) + return 0; + return 1; +} + +isl_bool isl_basic_set_is_box(__isl_keep isl_basic_set *bset) +{ + int i, j; + unsigned nvar; + unsigned ovar; + + if (!bset) + return isl_bool_error; + + if (isl_basic_set_dim(bset, isl_dim_div) != 0) + return isl_bool_false; + + nvar = isl_basic_set_dim(bset, isl_dim_set); + ovar = isl_space_offset(bset->dim, isl_dim_set); + for (j = 0; j < nvar; ++j) { + int lower = 0, upper = 0; + for (i = 0; i < bset->n_eq; ++i) { + if (isl_int_is_zero(bset->eq[i][1 + ovar + j])) + continue; + if (!unique(bset->eq[i] + 1 + ovar, j, nvar)) + return isl_bool_false; + break; + } + if (i < bset->n_eq) + continue; + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_int_is_zero(bset->ineq[i][1 + ovar + j])) + continue; + if (!unique(bset->ineq[i] + 1 + ovar, j, nvar)) + return isl_bool_false; + if (isl_int_is_pos(bset->ineq[i][1 + ovar + j])) + lower = 1; + else + upper = 1; + } + if (!lower || !upper) + return isl_bool_false; + } + + return isl_bool_true; +} + +isl_bool isl_set_is_box(__isl_keep isl_set *set) +{ + if (!set) + return isl_bool_error; + if (set->n != 1) + return isl_bool_false; + + return isl_basic_set_is_box(set->p[0]); +} + +isl_bool isl_basic_set_is_wrapping(__isl_keep isl_basic_set *bset) +{ + if (!bset) + return isl_bool_error; + + return isl_space_is_wrapping(bset->dim); +} + +isl_bool isl_set_is_wrapping(__isl_keep isl_set *set) +{ + if (!set) + return isl_bool_error; + + return isl_space_is_wrapping(set->dim); +} + +/* Modify the space of "map" through a call to "change". + * If "can_change" is set (not NULL), then first call it to check + * if the modification is allowed, printing the error message "cannot_change" + * if it is not. + */ +static __isl_give isl_map *isl_map_change_space(__isl_take isl_map *map, + isl_bool (*can_change)(__isl_keep isl_map *map), + const char *cannot_change, + __isl_give isl_space *(*change)(__isl_take isl_space *space)) +{ + isl_bool ok; + isl_space *space; + + if (!map) + return NULL; + + ok = can_change ? can_change(map) : isl_bool_true; + if (ok < 0) + return isl_map_free(map); + if (!ok) + isl_die(isl_map_get_ctx(map), isl_error_invalid, cannot_change, + return isl_map_free(map)); + + space = change(isl_map_get_space(map)); + map = isl_map_reset_space(map, space); + + return map; +} + +/* Is the domain of "map" a wrapped relation? + */ +isl_bool isl_map_domain_is_wrapping(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + + return isl_space_domain_is_wrapping(map->dim); +} + +/* Does "map" have a wrapped relation in both domain and range? + */ +isl_bool isl_map_is_product(__isl_keep isl_map *map) +{ + return isl_space_is_product(isl_map_peek_space(map)); +} + +/* Is the range of "map" a wrapped relation? + */ +isl_bool isl_map_range_is_wrapping(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + + return isl_space_range_is_wrapping(map->dim); +} + +__isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap) +{ + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + bmap->dim = isl_space_wrap(bmap->dim); + if (!bmap->dim) + goto error; + + bmap = isl_basic_map_finalize(bmap); + + return bset_from_bmap(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Given a map A -> B, return the set (A -> B). + */ +__isl_give isl_set *isl_map_wrap(__isl_take isl_map *map) +{ + return isl_map_change_space(map, NULL, NULL, &isl_space_wrap); +} + +__isl_give isl_basic_map *isl_basic_set_unwrap(__isl_take isl_basic_set *bset) +{ + bset = isl_basic_set_cow(bset); + if (!bset) + return NULL; + + bset->dim = isl_space_unwrap(bset->dim); + if (!bset->dim) + goto error; + + bset = isl_basic_set_finalize(bset); + + return bset_to_bmap(bset); +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Given a set (A -> B), return the map A -> B. + * Error out if "set" is not of the form (A -> B). + */ +__isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set) +{ + return isl_map_change_space(set, &isl_set_is_wrapping, + "not a wrapping set", &isl_space_unwrap); +} + +__isl_give isl_basic_map *isl_basic_map_reset(__isl_take isl_basic_map *bmap, + enum isl_dim_type type) +{ + if (!bmap) + return NULL; + + if (!isl_space_is_named_or_nested(bmap->dim, type)) + return bmap; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + bmap->dim = isl_space_reset(bmap->dim, type); + if (!bmap->dim) + goto error; + + bmap = isl_basic_map_finalize(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_map *isl_map_reset(__isl_take isl_map *map, + enum isl_dim_type type) +{ + int i; + + if (!map) + return NULL; + + if (!isl_space_is_named_or_nested(map->dim, type)) + return map; + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_reset(map->p[i], type); + if (!map->p[i]) + goto error; + } + map->dim = isl_space_reset(map->dim, type); + if (!map->dim) + goto error; + + return map; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_flatten(__isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + + if (!bmap->dim->nested[0] && !bmap->dim->nested[1]) + return bmap; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + bmap->dim = isl_space_flatten(bmap->dim); + if (!bmap->dim) + goto error; + + bmap = isl_basic_map_finalize(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_flatten(__isl_take isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_flatten(bset_to_bmap(bset))); +} + +__isl_give isl_basic_map *isl_basic_map_flatten_domain( + __isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + + if (!bmap->dim->nested[0]) + return bmap; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + bmap->dim = isl_space_flatten_domain(bmap->dim); + if (!bmap->dim) + goto error; + + bmap = isl_basic_map_finalize(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_flatten_range( + __isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + + if (!bmap->dim->nested[1]) + return bmap; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + + bmap->dim = isl_space_flatten_range(bmap->dim); + if (!bmap->dim) + goto error; + + bmap = isl_basic_map_finalize(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Remove any internal structure from the spaces of domain and range of "map". + */ +__isl_give isl_map *isl_map_flatten(__isl_take isl_map *map) +{ + if (!map) + return NULL; + + if (!map->dim->nested[0] && !map->dim->nested[1]) + return map; + + return isl_map_change_space(map, NULL, NULL, &isl_space_flatten); +} + +__isl_give isl_set *isl_set_flatten(__isl_take isl_set *set) +{ + return set_from_map(isl_map_flatten(set_to_map(set))); +} + +__isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set) +{ + isl_space *dim, *flat_dim; + isl_map *map; + + dim = isl_set_get_space(set); + flat_dim = isl_space_flatten(isl_space_copy(dim)); + map = isl_map_identity(isl_space_join(isl_space_reverse(dim), flat_dim)); + map = isl_map_intersect_domain(map, set); + + return map; +} + +/* Remove any internal structure from the space of the domain of "map". + */ +__isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map) +{ + if (!map) + return NULL; + + if (!map->dim->nested[0]) + return map; + + return isl_map_change_space(map, NULL, NULL, &isl_space_flatten_domain); +} + +/* Remove any internal structure from the space of the range of "map". + */ +__isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map) +{ + if (!map) + return NULL; + + if (!map->dim->nested[1]) + return map; + + return isl_map_change_space(map, NULL, NULL, &isl_space_flatten_range); +} + +/* Reorder the dimensions of "bmap" according to the given dim_map + * and set the dimension specification to "dim" and + * perform Gaussian elimination on the result. + */ +__isl_give isl_basic_map *isl_basic_map_realign(__isl_take isl_basic_map *bmap, + __isl_take isl_space *dim, __isl_take struct isl_dim_map *dim_map) +{ + isl_basic_map *res; + unsigned flags; + + bmap = isl_basic_map_cow(bmap); + if (!bmap || !dim || !dim_map) + goto error; + + flags = bmap->flags; + ISL_FL_CLR(flags, ISL_BASIC_MAP_FINAL); + ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED); + ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED_DIVS); + res = isl_basic_map_alloc_space(dim, + bmap->n_div, bmap->n_eq, bmap->n_ineq); + res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map); + if (res) + res->flags = flags; + res = isl_basic_map_gauss(res, NULL); + res = isl_basic_map_finalize(res); + return res; +error: + free(dim_map); + isl_basic_map_free(bmap); + isl_space_free(dim); + return NULL; +} + +/* Reorder the dimensions of "map" according to given reordering. + */ +__isl_give isl_map *isl_map_realign(__isl_take isl_map *map, + __isl_take isl_reordering *r) +{ + int i; + struct isl_dim_map *dim_map; + + map = isl_map_cow(map); + dim_map = isl_dim_map_from_reordering(r); + if (!map || !r || !dim_map) + goto error; + + for (i = 0; i < map->n; ++i) { + struct isl_dim_map *dim_map_i; + + dim_map_i = isl_dim_map_extend(dim_map, map->p[i]); + + map->p[i] = isl_basic_map_realign(map->p[i], + isl_space_copy(r->dim), dim_map_i); + + if (!map->p[i]) + goto error; + } + + map = isl_map_reset_space(map, isl_space_copy(r->dim)); + + isl_reordering_free(r); + free(dim_map); + return map; +error: + free(dim_map); + isl_map_free(map); + isl_reordering_free(r); + return NULL; +} + +__isl_give isl_set *isl_set_realign(__isl_take isl_set *set, + __isl_take isl_reordering *r) +{ + return set_from_map(isl_map_realign(set_to_map(set), r)); +} + +__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map, + __isl_take isl_space *model) +{ + isl_ctx *ctx; + isl_bool aligned; + + if (!map || !model) + goto error; + + ctx = isl_space_get_ctx(model); + if (!isl_space_has_named_params(model)) + isl_die(ctx, isl_error_invalid, + "model has unnamed parameters", goto error); + if (isl_map_check_named_params(map) < 0) + goto error; + aligned = isl_map_space_has_equal_params(map, model); + if (aligned < 0) + goto error; + if (!aligned) { + isl_reordering *exp; + + model = isl_space_drop_dims(model, isl_dim_in, + 0, isl_space_dim(model, isl_dim_in)); + model = isl_space_drop_dims(model, isl_dim_out, + 0, isl_space_dim(model, isl_dim_out)); + exp = isl_parameter_alignment_reordering(map->dim, model); + exp = isl_reordering_extend_space(exp, isl_map_get_space(map)); + map = isl_map_realign(map, exp); + } + + isl_space_free(model); + return map; +error: + isl_space_free(model); + isl_map_free(map); + return NULL; +} + +__isl_give isl_set *isl_set_align_params(__isl_take isl_set *set, + __isl_take isl_space *model) +{ + return isl_map_align_params(set, model); +} + +/* Align the parameters of "bmap" to those of "model", introducing + * additional parameters if needed. + */ +__isl_give isl_basic_map *isl_basic_map_align_params( + __isl_take isl_basic_map *bmap, __isl_take isl_space *model) +{ + isl_ctx *ctx; + isl_bool equal_params; + + if (!bmap || !model) + goto error; + + ctx = isl_space_get_ctx(model); + if (!isl_space_has_named_params(model)) + isl_die(ctx, isl_error_invalid, + "model has unnamed parameters", goto error); + if (!isl_space_has_named_params(bmap->dim)) + isl_die(ctx, isl_error_invalid, + "relation has unnamed parameters", goto error); + equal_params = isl_space_has_equal_params(bmap->dim, model); + if (equal_params < 0) + goto error; + if (!equal_params) { + isl_reordering *exp; + struct isl_dim_map *dim_map; + + model = isl_space_drop_dims(model, isl_dim_in, + 0, isl_space_dim(model, isl_dim_in)); + model = isl_space_drop_dims(model, isl_dim_out, + 0, isl_space_dim(model, isl_dim_out)); + exp = isl_parameter_alignment_reordering(bmap->dim, model); + exp = isl_reordering_extend_space(exp, + isl_basic_map_get_space(bmap)); + dim_map = isl_dim_map_from_reordering(exp); + bmap = isl_basic_map_realign(bmap, + exp ? isl_space_copy(exp->dim) : NULL, + isl_dim_map_extend(dim_map, bmap)); + isl_reordering_free(exp); + free(dim_map); + } + + isl_space_free(model); + return bmap; +error: + isl_space_free(model); + isl_basic_map_free(bmap); + return NULL; +} + +/* Do "bset" and "space" have the same parameters? + */ +isl_bool isl_basic_set_space_has_equal_params(__isl_keep isl_basic_set *bset, + __isl_keep isl_space *space) +{ + isl_space *bset_space; + + bset_space = isl_basic_set_peek_space(bset); + return isl_space_has_equal_params(bset_space, space); +} + +/* Do "map" and "space" have the same parameters? + */ +isl_bool isl_map_space_has_equal_params(__isl_keep isl_map *map, + __isl_keep isl_space *space) +{ + isl_space *map_space; + + map_space = isl_map_peek_space(map); + return isl_space_has_equal_params(map_space, space); +} + +/* Do "set" and "space" have the same parameters? + */ +isl_bool isl_set_space_has_equal_params(__isl_keep isl_set *set, + __isl_keep isl_space *space) +{ + return isl_map_space_has_equal_params(set_to_map(set), space); +} + +/* Align the parameters of "bset" to those of "model", introducing + * additional parameters if needed. + */ +__isl_give isl_basic_set *isl_basic_set_align_params( + __isl_take isl_basic_set *bset, __isl_take isl_space *model) +{ + return isl_basic_map_align_params(bset, 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, + enum isl_dim_type c4, enum isl_dim_type c5) +{ + enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 }; + struct isl_mat *mat; + int i, j, k; + int pos; + + if (!bmap) + return NULL; + mat = isl_mat_alloc(bmap->ctx, bmap->n_eq, + isl_basic_map_total_dim(bmap) + 1); + if (!mat) + return NULL; + for (i = 0; i < bmap->n_eq; ++i) + for (j = 0, pos = 0; j < 5; ++j) { + int off = isl_basic_map_offset(bmap, c[j]); + for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) { + isl_int_set(mat->row[i][pos], + bmap->eq[i][off + k]); + ++pos; + } + } + + return mat; +} + +__isl_give isl_mat *isl_basic_map_inequalities_matrix( + __isl_keep isl_basic_map *bmap, enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, + enum isl_dim_type c4, enum isl_dim_type c5) +{ + enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 }; + struct isl_mat *mat; + int i, j, k; + int pos; + + if (!bmap) + return NULL; + mat = isl_mat_alloc(bmap->ctx, bmap->n_ineq, + isl_basic_map_total_dim(bmap) + 1); + if (!mat) + return NULL; + for (i = 0; i < bmap->n_ineq; ++i) + for (j = 0, pos = 0; j < 5; ++j) { + int off = isl_basic_map_offset(bmap, c[j]); + for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) { + isl_int_set(mat->row[i][pos], + bmap->ineq[i][off + k]); + ++pos; + } + } + + return mat; +} + +__isl_give isl_basic_map *isl_basic_map_from_constraint_matrices( + __isl_take isl_space *dim, + __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, + enum isl_dim_type c4, enum isl_dim_type c5) +{ + enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 }; + isl_basic_map *bmap; + unsigned total; + unsigned extra; + int i, j, k, l; + int pos; + + if (!dim || !eq || !ineq) + goto error; + + if (eq->n_col != ineq->n_col) + isl_die(dim->ctx, isl_error_invalid, + "equalities and inequalities matrices should have " + "same number of columns", goto error); + + total = 1 + isl_space_dim(dim, isl_dim_all); + + if (eq->n_col < total) + isl_die(dim->ctx, isl_error_invalid, + "number of columns too small", goto error); + + extra = eq->n_col - total; + + bmap = isl_basic_map_alloc_space(isl_space_copy(dim), extra, + eq->n_row, ineq->n_row); + if (!bmap) + goto error; + for (i = 0; i < extra; ++i) { + k = isl_basic_map_alloc_div(bmap); + if (k < 0) + goto error; + isl_int_set_si(bmap->div[k][0], 0); + } + for (i = 0; i < eq->n_row; ++i) { + l = isl_basic_map_alloc_equality(bmap); + if (l < 0) + goto error; + for (j = 0, pos = 0; j < 5; ++j) { + int off = isl_basic_map_offset(bmap, c[j]); + for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) { + isl_int_set(bmap->eq[l][off + k], + eq->row[i][pos]); + ++pos; + } + } + } + for (i = 0; i < ineq->n_row; ++i) { + l = isl_basic_map_alloc_inequality(bmap); + if (l < 0) + goto error; + for (j = 0, pos = 0; j < 5; ++j) { + int off = isl_basic_map_offset(bmap, c[j]); + for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) { + isl_int_set(bmap->ineq[l][off + k], + ineq->row[i][pos]); + ++pos; + } + } + } + + isl_space_free(dim); + isl_mat_free(eq); + isl_mat_free(ineq); + + bmap = isl_basic_map_simplify(bmap); + return isl_basic_map_finalize(bmap); +error: + isl_space_free(dim); + isl_mat_free(eq); + isl_mat_free(ineq); + return NULL; +} + +__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) +{ + return isl_basic_map_equalities_matrix(bset_to_bmap(bset), + c1, c2, c3, c4, isl_dim_in); +} + +__isl_give isl_mat *isl_basic_set_inequalities_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) +{ + return isl_basic_map_inequalities_matrix(bset_to_bmap(bset), + c1, c2, c3, c4, isl_dim_in); +} + +__isl_give isl_basic_set *isl_basic_set_from_constraint_matrices( + __isl_take isl_space *dim, + __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1, + enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4) +{ + isl_basic_map *bmap; + bmap = isl_basic_map_from_constraint_matrices(dim, eq, ineq, + c1, c2, c3, c4, isl_dim_in); + return bset_from_bmap(bmap); +} + +isl_bool isl_basic_map_can_zip(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + + return isl_space_can_zip(bmap->dim); +} + +isl_bool isl_map_can_zip(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + + return isl_space_can_zip(map->dim); +} + +/* Given a basic map (A -> B) -> (C -> D), return the corresponding basic map + * (A -> C) -> (B -> D). + */ +__isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap) +{ + unsigned pos; + unsigned n1; + unsigned n2; + + if (!bmap) + return NULL; + + if (!isl_basic_map_can_zip(bmap)) + isl_die(bmap->ctx, isl_error_invalid, + "basic map cannot be zipped", goto error); + pos = isl_basic_map_offset(bmap, isl_dim_in) + + isl_space_dim(bmap->dim->nested[0], isl_dim_in); + n1 = isl_space_dim(bmap->dim->nested[0], isl_dim_out); + n2 = isl_space_dim(bmap->dim->nested[1], isl_dim_in); + bmap = isl_basic_map_cow(bmap); + bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2); + if (!bmap) + return NULL; + bmap->dim = isl_space_zip(bmap->dim); + if (!bmap->dim) + goto error; + bmap = isl_basic_map_mark_final(bmap); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Given a map (A -> B) -> (C -> D), return the corresponding map + * (A -> C) -> (B -> D). + */ +__isl_give isl_map *isl_map_zip(__isl_take isl_map *map) +{ + int i; + + if (!map) + return NULL; + + if (!isl_map_can_zip(map)) + isl_die(map->ctx, isl_error_invalid, "map cannot be zipped", + goto error); + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_zip(map->p[i]); + if (!map->p[i]) + goto error; + } + + map->dim = isl_space_zip(map->dim); + if (!map->dim) + goto error; + + return map; +error: + isl_map_free(map); + return NULL; +} + +/* Can we apply isl_basic_map_curry to "bmap"? + * That is, does it have a nested relation in its domain? + */ +isl_bool isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + + return isl_space_can_curry(bmap->dim); +} + +/* Can we apply isl_map_curry to "map"? + * That is, does it have a nested relation in its domain? + */ +isl_bool isl_map_can_curry(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + + return isl_space_can_curry(map->dim); +} + +/* Given a basic map (A -> B) -> C, return the corresponding basic map + * A -> (B -> C). + */ +__isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap) +{ + + if (!bmap) + return NULL; + + if (!isl_basic_map_can_curry(bmap)) + isl_die(bmap->ctx, isl_error_invalid, + "basic map cannot be curried", goto error); + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + bmap->dim = isl_space_curry(bmap->dim); + if (!bmap->dim) + goto error; + bmap = isl_basic_map_mark_final(bmap); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Given a map (A -> B) -> C, return the corresponding map + * A -> (B -> C). + */ +__isl_give isl_map *isl_map_curry(__isl_take isl_map *map) +{ + return isl_map_change_space(map, &isl_map_can_curry, + "map cannot be curried", &isl_space_curry); +} + +/* Can isl_map_range_curry be applied to "map"? + * That is, does it have a nested relation in its range, + * the domain of which is itself a nested relation? + */ +isl_bool isl_map_can_range_curry(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + + return isl_space_can_range_curry(map->dim); +} + +/* Given a map A -> ((B -> C) -> D), return the corresponding map + * A -> (B -> (C -> D)). + */ +__isl_give isl_map *isl_map_range_curry(__isl_take isl_map *map) +{ + return isl_map_change_space(map, &isl_map_can_range_curry, + "map range cannot be curried", + &isl_space_range_curry); +} + +/* Can we apply isl_basic_map_uncurry to "bmap"? + * That is, does it have a nested relation in its domain? + */ +isl_bool isl_basic_map_can_uncurry(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + + return isl_space_can_uncurry(bmap->dim); +} + +/* Can we apply isl_map_uncurry to "map"? + * That is, does it have a nested relation in its domain? + */ +isl_bool isl_map_can_uncurry(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + + return isl_space_can_uncurry(map->dim); +} + +/* Given a basic map A -> (B -> C), return the corresponding basic map + * (A -> B) -> C. + */ +__isl_give isl_basic_map *isl_basic_map_uncurry(__isl_take isl_basic_map *bmap) +{ + + if (!bmap) + return NULL; + + if (!isl_basic_map_can_uncurry(bmap)) + isl_die(bmap->ctx, isl_error_invalid, + "basic map cannot be uncurried", + return isl_basic_map_free(bmap)); + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + bmap->dim = isl_space_uncurry(bmap->dim); + if (!bmap->dim) + return isl_basic_map_free(bmap); + bmap = isl_basic_map_mark_final(bmap); + return bmap; +} + +/* Given a map A -> (B -> C), return the corresponding map + * (A -> B) -> C. + */ +__isl_give isl_map *isl_map_uncurry(__isl_take isl_map *map) +{ + return isl_map_change_space(map, &isl_map_can_uncurry, + "map cannot be uncurried", &isl_space_uncurry); +} + +/* Construct a basic map mapping the domain of the affine expression + * to a one-dimensional range prescribed by the affine expression. + * If "rational" is set, then construct a rational basic map. + * + * A NaN affine expression cannot be converted to a basic map. + */ +static __isl_give isl_basic_map *isl_basic_map_from_aff2( + __isl_take isl_aff *aff, int rational) +{ + int k; + int pos; + isl_bool is_nan; + isl_local_space *ls; + isl_basic_map *bmap = NULL; + + if (!aff) + return NULL; + is_nan = isl_aff_is_nan(aff); + if (is_nan < 0) + goto error; + if (is_nan) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "cannot convert NaN", goto error); + + ls = isl_aff_get_local_space(aff); + bmap = isl_basic_map_from_local_space(ls); + bmap = isl_basic_map_extend_constraints(bmap, 1, 0); + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + + pos = isl_basic_map_offset(bmap, isl_dim_out); + isl_seq_cpy(bmap->eq[k], aff->v->el + 1, pos); + isl_int_neg(bmap->eq[k][pos], aff->v->el[0]); + isl_seq_cpy(bmap->eq[k] + pos + 1, aff->v->el + 1 + pos, + aff->v->size - (pos + 1)); + + isl_aff_free(aff); + if (rational) + bmap = isl_basic_map_set_rational(bmap); + bmap = isl_basic_map_gauss(bmap, NULL); + bmap = isl_basic_map_finalize(bmap); + return bmap; +error: + isl_aff_free(aff); + isl_basic_map_free(bmap); + return NULL; +} + +/* Construct a basic map mapping the domain of the affine expression + * to a one-dimensional range prescribed by the affine expression. + */ +__isl_give isl_basic_map *isl_basic_map_from_aff(__isl_take isl_aff *aff) +{ + return isl_basic_map_from_aff2(aff, 0); +} + +/* Construct a map mapping the domain of the affine expression + * to a one-dimensional range prescribed by the affine expression. + */ +__isl_give isl_map *isl_map_from_aff(__isl_take isl_aff *aff) +{ + isl_basic_map *bmap; + + bmap = isl_basic_map_from_aff(aff); + return isl_map_from_basic_map(bmap); +} + +/* Construct a basic map mapping the domain the multi-affine expression + * to its range, with each dimension in the range equated to the + * corresponding affine expression. + * If "rational" is set, then construct a rational basic map. + */ +__isl_give isl_basic_map *isl_basic_map_from_multi_aff2( + __isl_take isl_multi_aff *maff, int rational) +{ + int i; + isl_space *space; + isl_basic_map *bmap; + + if (!maff) + return NULL; + + if (isl_space_dim(maff->space, isl_dim_out) != maff->n) + isl_die(isl_multi_aff_get_ctx(maff), isl_error_internal, + "invalid space", goto error); + + space = isl_space_domain(isl_multi_aff_get_space(maff)); + bmap = isl_basic_map_universe(isl_space_from_domain(space)); + if (rational) + bmap = isl_basic_map_set_rational(bmap); + + for (i = 0; i < maff->n; ++i) { + isl_aff *aff; + isl_basic_map *bmap_i; + + aff = isl_aff_copy(maff->p[i]); + bmap_i = isl_basic_map_from_aff2(aff, rational); + + bmap = isl_basic_map_flat_range_product(bmap, bmap_i); + } + + bmap = isl_basic_map_reset_space(bmap, isl_multi_aff_get_space(maff)); + + isl_multi_aff_free(maff); + return bmap; +error: + isl_multi_aff_free(maff); + return NULL; +} + +/* Construct a basic map mapping the domain the multi-affine expression + * to its range, with each dimension in the range equated to the + * corresponding affine expression. + */ +__isl_give isl_basic_map *isl_basic_map_from_multi_aff( + __isl_take isl_multi_aff *ma) +{ + return isl_basic_map_from_multi_aff2(ma, 0); +} + +/* Construct a map mapping the domain the multi-affine expression + * to its range, with each dimension in the range equated to the + * corresponding affine expression. + */ +__isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff) +{ + isl_basic_map *bmap; + + bmap = isl_basic_map_from_multi_aff(maff); + return isl_map_from_basic_map(bmap); +} + +/* Construct a basic map mapping a domain in the given space to + * to an n-dimensional range, with n the number of elements in the list, + * where each coordinate in the range is prescribed by the + * corresponding affine expression. + * The domains of all affine expressions in the list are assumed to match + * domain_dim. + */ +__isl_give isl_basic_map *isl_basic_map_from_aff_list( + __isl_take isl_space *domain_dim, __isl_take isl_aff_list *list) +{ + int i; + isl_space *dim; + isl_basic_map *bmap; + + if (!list) + return NULL; + + dim = isl_space_from_domain(domain_dim); + bmap = isl_basic_map_universe(dim); + + for (i = 0; i < list->n; ++i) { + isl_aff *aff; + isl_basic_map *bmap_i; + + aff = isl_aff_copy(list->p[i]); + bmap_i = isl_basic_map_from_aff(aff); + + bmap = isl_basic_map_flat_range_product(bmap, bmap_i); + } + + isl_aff_list_free(list); + return bmap; +} + +__isl_give isl_set *isl_set_equate(__isl_take isl_set *set, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + return isl_map_equate(set, type1, pos1, type2, pos2); +} + +/* Construct a basic map where the given dimensions are equal to each other. + */ +static __isl_give isl_basic_map *equator(__isl_take isl_space *space, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *bmap = NULL; + int i; + + if (!space) + return NULL; + + if (pos1 >= isl_space_dim(space, type1)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "index out of bounds", goto error); + if (pos2 >= isl_space_dim(space, type2)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "index out of bounds", goto error); + + if (type1 == type2 && pos1 == pos2) + return isl_basic_map_universe(space); + + bmap = isl_basic_map_alloc_space(isl_space_copy(space), 0, 1, 0); + i = isl_basic_map_alloc_equality(bmap); + if (i < 0) + goto error; + isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap)); + pos1 += isl_basic_map_offset(bmap, type1); + pos2 += isl_basic_map_offset(bmap, type2); + isl_int_set_si(bmap->eq[i][pos1], -1); + isl_int_set_si(bmap->eq[i][pos2], 1); + bmap = isl_basic_map_finalize(bmap); + isl_space_free(space); + return bmap; +error: + isl_space_free(space); + isl_basic_map_free(bmap); + return NULL; +} + +/* Add a constraint imposing that the given two dimensions are equal. + */ +__isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *eq; + + eq = equator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2); + + bmap = isl_basic_map_intersect(bmap, eq); + + return bmap; +} + +/* Add a constraint imposing that the given two dimensions are equal. + */ +__isl_give isl_map *isl_map_equate(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *bmap; + + bmap = equator(isl_map_get_space(map), type1, pos1, type2, pos2); + + map = isl_map_intersect(map, isl_map_from_basic_map(bmap)); + + return map; +} + +/* Add a constraint imposing that the given two dimensions have opposite values. + */ +__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *bmap = NULL; + int i; + + if (!map) + return NULL; + + if (pos1 >= isl_map_dim(map, type1)) + isl_die(map->ctx, isl_error_invalid, + "index out of bounds", goto error); + if (pos2 >= isl_map_dim(map, type2)) + isl_die(map->ctx, isl_error_invalid, + "index out of bounds", goto error); + + bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 1, 0); + i = isl_basic_map_alloc_equality(bmap); + if (i < 0) + goto error; + isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap)); + pos1 += isl_basic_map_offset(bmap, type1); + pos2 += isl_basic_map_offset(bmap, type2); + isl_int_set_si(bmap->eq[i][pos1], 1); + isl_int_set_si(bmap->eq[i][pos2], 1); + bmap = isl_basic_map_finalize(bmap); + + map = isl_map_intersect(map, isl_map_from_basic_map(bmap)); + + return map; +error: + isl_basic_map_free(bmap); + isl_map_free(map); + return NULL; +} + +/* Construct a constraint imposing that the value of the first dimension is + * greater than or equal to that of the second. + */ +static __isl_give isl_constraint *constraint_order_ge( + __isl_take isl_space *space, enum isl_dim_type type1, int pos1, + enum isl_dim_type type2, int pos2) +{ + isl_constraint *c; + + if (!space) + return NULL; + + c = isl_constraint_alloc_inequality(isl_local_space_from_space(space)); + + if (pos1 >= isl_constraint_dim(c, type1)) + isl_die(isl_constraint_get_ctx(c), isl_error_invalid, + "index out of bounds", return isl_constraint_free(c)); + if (pos2 >= isl_constraint_dim(c, type2)) + isl_die(isl_constraint_get_ctx(c), isl_error_invalid, + "index out of bounds", return isl_constraint_free(c)); + + if (type1 == type2 && pos1 == pos2) + return c; + + c = isl_constraint_set_coefficient_si(c, type1, pos1, 1); + c = isl_constraint_set_coefficient_si(c, type2, pos2, -1); + + return c; +} + +/* Add a constraint imposing that the value of the first dimension is + * greater than or equal to that of the second. + */ +__isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_constraint *c; + isl_space *space; + + if (type1 == type2 && pos1 == pos2) + return bmap; + space = isl_basic_map_get_space(bmap); + c = constraint_order_ge(space, type1, pos1, type2, pos2); + bmap = isl_basic_map_add_constraint(bmap, c); + + return bmap; +} + +/* Add a constraint imposing that the value of the first dimension is + * greater than or equal to that of the second. + */ +__isl_give isl_map *isl_map_order_ge(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_constraint *c; + isl_space *space; + + if (type1 == type2 && pos1 == pos2) + return map; + space = isl_map_get_space(map); + c = constraint_order_ge(space, type1, pos1, type2, pos2); + map = isl_map_add_constraint(map, c); + + return map; +} + +/* Add a constraint imposing that the value of the first dimension is + * less than or equal to that of the second. + */ +__isl_give isl_map *isl_map_order_le(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + return isl_map_order_ge(map, type2, pos2, type1, pos1); +} + +/* Construct a basic map where the value of the first dimension is + * greater than that of the second. + */ +static __isl_give isl_basic_map *greator(__isl_take isl_space *space, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *bmap = NULL; + int i; + + if (!space) + return NULL; + + if (pos1 >= isl_space_dim(space, type1)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "index out of bounds", goto error); + if (pos2 >= isl_space_dim(space, type2)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "index out of bounds", goto error); + + if (type1 == type2 && pos1 == pos2) + return isl_basic_map_empty(space); + + bmap = isl_basic_map_alloc_space(space, 0, 0, 1); + i = isl_basic_map_alloc_inequality(bmap); + if (i < 0) + return isl_basic_map_free(bmap); + isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap)); + pos1 += isl_basic_map_offset(bmap, type1); + pos2 += isl_basic_map_offset(bmap, type2); + isl_int_set_si(bmap->ineq[i][pos1], 1); + isl_int_set_si(bmap->ineq[i][pos2], -1); + isl_int_set_si(bmap->ineq[i][0], -1); + bmap = isl_basic_map_finalize(bmap); + + return bmap; +error: + isl_space_free(space); + isl_basic_map_free(bmap); + return NULL; +} + +/* Add a constraint imposing that the value of the first dimension is + * greater than that of the second. + */ +__isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *gt; + + gt = greator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2); + + bmap = isl_basic_map_intersect(bmap, gt); + + return bmap; +} + +/* Add a constraint imposing that the value of the first dimension is + * greater than that of the second. + */ +__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + isl_basic_map *bmap; + + bmap = greator(isl_map_get_space(map), type1, pos1, type2, pos2); + + map = isl_map_intersect(map, isl_map_from_basic_map(bmap)); + + return map; +} + +/* Add a constraint imposing that the value of the first dimension is + * smaller than that of the second. + */ +__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map, + enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) +{ + return isl_map_order_gt(map, type2, pos2, type1, pos1); +} + +__isl_give isl_aff *isl_basic_map_get_div(__isl_keep isl_basic_map *bmap, + int pos) +{ + isl_aff *div; + isl_local_space *ls; + + if (!bmap) + return NULL; + + if (!isl_basic_map_divs_known(bmap)) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "some divs are unknown", return NULL); + + ls = isl_basic_map_get_local_space(bmap); + div = isl_local_space_get_div(ls, pos); + isl_local_space_free(ls); + + return div; +} + +__isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset, + int pos) +{ + return isl_basic_map_get_div(bset, pos); +} + +/* Plug in "subs" for dimension "type", "pos" of "bset". + * + * Let i be the dimension to replace and let "subs" be of the form + * + * f/d + * + * Any integer division with a non-zero coefficient for i, + * + * floor((a i + g)/m) + * + * is replaced by + * + * floor((a f + d g)/(m d)) + * + * Constraints of the form + * + * a i + g + * + * are replaced by + * + * a f + d g + * + * We currently require that "subs" is an integral expression. + * Handling rational expressions may require us to add stride constraints + * as we do in isl_basic_set_preimage_multi_aff. + */ +__isl_give isl_basic_set *isl_basic_set_substitute( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) +{ + int i; + isl_int v; + isl_ctx *ctx; + + if (bset && isl_basic_set_plain_is_empty(bset)) + return bset; + + bset = isl_basic_set_cow(bset); + if (!bset || !subs) + goto error; + + ctx = isl_basic_set_get_ctx(bset); + if (!isl_space_is_equal(bset->dim, subs->ls->dim)) + isl_die(ctx, isl_error_invalid, + "spaces don't match", goto error); + if (isl_local_space_dim(subs->ls, isl_dim_div) != 0) + isl_die(ctx, isl_error_unsupported, + "cannot handle divs yet", goto error); + if (!isl_int_is_one(subs->v->el[0])) + isl_die(ctx, isl_error_invalid, + "can only substitute integer expressions", goto error); + + pos += isl_basic_set_offset(bset, type); + + isl_int_init(v); + + for (i = 0; i < bset->n_eq; ++i) { + if (isl_int_is_zero(bset->eq[i][pos])) + continue; + isl_int_set(v, bset->eq[i][pos]); + isl_int_set_si(bset->eq[i][pos], 0); + isl_seq_combine(bset->eq[i], subs->v->el[0], bset->eq[i], + v, subs->v->el + 1, subs->v->size - 1); + } + + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_int_is_zero(bset->ineq[i][pos])) + continue; + isl_int_set(v, bset->ineq[i][pos]); + isl_int_set_si(bset->ineq[i][pos], 0); + isl_seq_combine(bset->ineq[i], subs->v->el[0], bset->ineq[i], + v, subs->v->el + 1, subs->v->size - 1); + } + + for (i = 0; i < bset->n_div; ++i) { + if (isl_int_is_zero(bset->div[i][1 + pos])) + continue; + isl_int_set(v, bset->div[i][1 + pos]); + isl_int_set_si(bset->div[i][1 + pos], 0); + isl_seq_combine(bset->div[i] + 1, + subs->v->el[0], bset->div[i] + 1, + v, subs->v->el + 1, subs->v->size - 1); + isl_int_mul(bset->div[i][0], bset->div[i][0], subs->v->el[0]); + } + + isl_int_clear(v); + + bset = isl_basic_set_simplify(bset); + return isl_basic_set_finalize(bset); +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Plug in "subs" for dimension "type", "pos" of "set". + */ +__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) +{ + int i; + + if (set && isl_set_plain_is_empty(set)) + return set; + + set = isl_set_cow(set); + if (!set || !subs) + goto error; + + for (i = set->n - 1; i >= 0; --i) { + set->p[i] = isl_basic_set_substitute(set->p[i], type, pos, subs); + if (remove_if_empty(set, i) < 0) + goto error; + } + + return set; +error: + isl_set_free(set); + return NULL; +} + +/* Check if the range of "ma" is compatible with the domain or range + * (depending on "type") of "bmap". + */ +static isl_stat check_basic_map_compatible_range_multi_aff( + __isl_keep isl_basic_map *bmap, enum isl_dim_type type, + __isl_keep isl_multi_aff *ma) +{ + isl_bool m; + isl_space *ma_space; + + ma_space = isl_multi_aff_get_space(ma); + + m = isl_space_has_equal_params(bmap->dim, ma_space); + if (m < 0) + goto error; + if (!m) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "parameters don't match", goto error); + m = isl_space_tuple_is_equal(bmap->dim, type, ma_space, isl_dim_out); + if (m < 0) + goto error; + if (!m) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "spaces don't match", goto error); + + isl_space_free(ma_space); + return isl_stat_ok; +error: + isl_space_free(ma_space); + return isl_stat_error; +} + +/* Copy the divs from "ma" to "bmap", adding zeros for the "n_before" + * coefficients before the transformed range of dimensions, + * the "n_after" coefficients after the transformed range of dimensions + * and the coefficients of the other divs in "bmap". + */ +static int set_ma_divs(__isl_keep isl_basic_map *bmap, + __isl_keep isl_multi_aff *ma, int n_before, int n_after, int n_div) +{ + int i; + int n_param; + int n_set; + isl_local_space *ls; + + if (n_div == 0) + return 0; + + ls = isl_aff_get_domain_local_space(ma->p[0]); + if (!ls) + return -1; + + n_param = isl_local_space_dim(ls, isl_dim_param); + n_set = isl_local_space_dim(ls, isl_dim_set); + for (i = 0; i < n_div; ++i) { + int o_bmap = 0, o_ls = 0; + + isl_seq_cpy(bmap->div[i], ls->div->row[i], 1 + 1 + n_param); + o_bmap += 1 + 1 + n_param; + o_ls += 1 + 1 + n_param; + isl_seq_clr(bmap->div[i] + o_bmap, n_before); + o_bmap += n_before; + isl_seq_cpy(bmap->div[i] + o_bmap, + ls->div->row[i] + o_ls, n_set); + o_bmap += n_set; + o_ls += n_set; + isl_seq_clr(bmap->div[i] + o_bmap, n_after); + o_bmap += n_after; + isl_seq_cpy(bmap->div[i] + o_bmap, + ls->div->row[i] + o_ls, n_div); + o_bmap += n_div; + o_ls += n_div; + isl_seq_clr(bmap->div[i] + o_bmap, bmap->n_div - n_div); + if (isl_basic_map_add_div_constraints(bmap, i) < 0) + goto error; + } + + isl_local_space_free(ls); + return 0; +error: + isl_local_space_free(ls); + return -1; +} + +/* How many stride constraints does "ma" enforce? + * That is, how many of the affine expressions have a denominator + * different from one? + */ +static int multi_aff_strides(__isl_keep isl_multi_aff *ma) +{ + int i; + int strides = 0; + + for (i = 0; i < ma->n; ++i) + if (!isl_int_is_one(ma->p[i]->v->el[0])) + strides++; + + return strides; +} + +/* For each affine expression in ma of the form + * + * x_i = (f_i y + h_i)/m_i + * + * with m_i different from one, add a constraint to "bmap" + * of the form + * + * f_i y + h_i = m_i alpha_i + * + * with alpha_i an additional existentially quantified variable. + * + * The input variables of "ma" correspond to a subset of the variables + * of "bmap". There are "n_before" variables in "bmap" before this + * subset and "n_after" variables after this subset. + * The integer divisions of the affine expressions in "ma" are assumed + * to have been aligned. There are "n_div_ma" of them and + * they appear first in "bmap", straight after the "n_after" variables. + */ +static __isl_give isl_basic_map *add_ma_strides( + __isl_take isl_basic_map *bmap, __isl_keep isl_multi_aff *ma, + int n_before, int n_after, int n_div_ma) +{ + int i, k; + int div; + int total; + int n_param; + int n_in; + + total = isl_basic_map_total_dim(bmap); + n_param = isl_multi_aff_dim(ma, isl_dim_param); + n_in = isl_multi_aff_dim(ma, isl_dim_in); + for (i = 0; i < ma->n; ++i) { + int o_bmap = 0, o_ma = 1; + + if (isl_int_is_one(ma->p[i]->v->el[0])) + continue; + div = isl_basic_map_alloc_div(bmap); + k = isl_basic_map_alloc_equality(bmap); + if (div < 0 || k < 0) + goto error; + isl_int_set_si(bmap->div[div][0], 0); + isl_seq_cpy(bmap->eq[k] + o_bmap, + ma->p[i]->v->el + o_ma, 1 + n_param); + o_bmap += 1 + n_param; + o_ma += 1 + n_param; + isl_seq_clr(bmap->eq[k] + o_bmap, n_before); + o_bmap += n_before; + isl_seq_cpy(bmap->eq[k] + o_bmap, + ma->p[i]->v->el + o_ma, n_in); + o_bmap += n_in; + o_ma += n_in; + isl_seq_clr(bmap->eq[k] + o_bmap, n_after); + o_bmap += n_after; + isl_seq_cpy(bmap->eq[k] + o_bmap, + ma->p[i]->v->el + o_ma, n_div_ma); + o_bmap += n_div_ma; + o_ma += n_div_ma; + isl_seq_clr(bmap->eq[k] + o_bmap, 1 + total - o_bmap); + isl_int_neg(bmap->eq[k][1 + total], ma->p[i]->v->el[0]); + total++; + } + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Replace the domain or range space (depending on "type) of "space" by "set". + */ +static __isl_give isl_space *isl_space_set(__isl_take isl_space *space, + enum isl_dim_type type, __isl_take isl_space *set) +{ + if (type == isl_dim_in) { + space = isl_space_range(space); + space = isl_space_map_from_domain_and_range(set, space); + } else { + space = isl_space_domain(space); + space = isl_space_map_from_domain_and_range(space, set); + } + + return space; +} + +/* Compute the preimage of the domain or range (depending on "type") + * of "bmap" under the function represented by "ma". + * In other words, plug in "ma" in the domain or range of "bmap". + * The result is a basic map that lives in the same space as "bmap" + * except that the domain or range has been replaced by + * the domain space of "ma". + * + * If bmap is represented by + * + * A(p) + S u + B x + T v + C(divs) >= 0, + * + * where u and x are input and output dimensions if type == isl_dim_out + * while x and v are input and output dimensions if type == isl_dim_in, + * and ma is represented by + * + * x = D(p) + F(y) + G(divs') + * + * then the result is + * + * A(p) + B D(p) + S u + B F(y) + T v + B G(divs') + C(divs) >= 0 + * + * The divs in the input set are similarly adjusted. + * In particular + * + * floor((a_i(p) + s u + b_i x + t v + c_i(divs))/n_i) + * + * becomes + * + * floor((a_i(p) + b_i D(p) + s u + b_i F(y) + t v + + * B_i G(divs') + c_i(divs))/n_i) + * + * If bmap is not a rational map and if F(y) involves any denominators + * + * x_i = (f_i y + h_i)/m_i + * + * then additional constraints are added to ensure that we only + * map back integer points. That is we enforce + * + * f_i y + h_i = m_i alpha_i + * + * with alpha_i an additional existentially quantified variable. + * + * We first copy over the divs from "ma". + * Then we add the modified constraints and divs from "bmap". + * Finally, we add the stride constraints, if needed. + */ +__isl_give isl_basic_map *isl_basic_map_preimage_multi_aff( + __isl_take isl_basic_map *bmap, enum isl_dim_type type, + __isl_take isl_multi_aff *ma) +{ + int i, k; + isl_space *space; + isl_basic_map *res = NULL; + int n_before, n_after, n_div_bmap, n_div_ma; + isl_int f, c1, c2, g; + isl_bool rational; + int strides; + + isl_int_init(f); + isl_int_init(c1); + isl_int_init(c2); + isl_int_init(g); + + ma = isl_multi_aff_align_divs(ma); + if (!bmap || !ma) + goto error; + if (check_basic_map_compatible_range_multi_aff(bmap, type, ma) < 0) + goto error; + + if (type == isl_dim_in) { + n_before = 0; + n_after = isl_basic_map_dim(bmap, isl_dim_out); + } else { + n_before = isl_basic_map_dim(bmap, isl_dim_in); + n_after = 0; + } + n_div_bmap = isl_basic_map_dim(bmap, isl_dim_div); + n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0; + + space = isl_multi_aff_get_domain_space(ma); + space = isl_space_set(isl_basic_map_get_space(bmap), type, space); + rational = isl_basic_map_is_rational(bmap); + strides = rational ? 0 : multi_aff_strides(ma); + res = isl_basic_map_alloc_space(space, n_div_ma + n_div_bmap + strides, + bmap->n_eq + strides, bmap->n_ineq + 2 * n_div_ma); + if (rational) + res = isl_basic_map_set_rational(res); + + for (i = 0; i < n_div_ma + n_div_bmap; ++i) + if (isl_basic_map_alloc_div(res) < 0) + goto error; + + if (set_ma_divs(res, ma, n_before, n_after, n_div_ma) < 0) + goto error; + + for (i = 0; i < bmap->n_eq; ++i) { + k = isl_basic_map_alloc_equality(res); + if (k < 0) + goto error; + isl_seq_preimage(res->eq[k], bmap->eq[i], ma, n_before, + n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0); + } + + for (i = 0; i < bmap->n_ineq; ++i) { + k = isl_basic_map_alloc_inequality(res); + if (k < 0) + goto error; + isl_seq_preimage(res->ineq[k], bmap->ineq[i], ma, n_before, + n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0); + } + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) { + isl_int_set_si(res->div[n_div_ma + i][0], 0); + continue; + } + isl_seq_preimage(res->div[n_div_ma + i], bmap->div[i], ma, + n_before, n_after, n_div_ma, n_div_bmap, + f, c1, c2, g, 1); + } + + if (strides) + res = add_ma_strides(res, ma, n_before, n_after, n_div_ma); + + isl_int_clear(f); + isl_int_clear(c1); + isl_int_clear(c2); + isl_int_clear(g); + isl_basic_map_free(bmap); + isl_multi_aff_free(ma); + res = isl_basic_map_simplify(res); + return isl_basic_map_finalize(res); +error: + isl_int_clear(f); + isl_int_clear(c1); + isl_int_clear(c2); + isl_int_clear(g); + isl_basic_map_free(bmap); + isl_multi_aff_free(ma); + isl_basic_map_free(res); + return NULL; +} + +/* Compute the preimage of "bset" under the function represented by "ma". + * In other words, plug in "ma" in "bset". The result is a basic set + * that lives in the domain space of "ma". + */ +__isl_give isl_basic_set *isl_basic_set_preimage_multi_aff( + __isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma) +{ + return isl_basic_map_preimage_multi_aff(bset, isl_dim_set, ma); +} + +/* Compute the preimage of the domain of "bmap" under the function + * represented by "ma". + * In other words, plug in "ma" in the domain of "bmap". + * The result is a basic map that lives in the same space as "bmap" + * except that the domain has been replaced by the domain space of "ma". + */ +__isl_give isl_basic_map *isl_basic_map_preimage_domain_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma) +{ + return isl_basic_map_preimage_multi_aff(bmap, isl_dim_in, ma); +} + +/* Compute the preimage of the range of "bmap" under the function + * represented by "ma". + * In other words, plug in "ma" in the range of "bmap". + * The result is a basic map that lives in the same space as "bmap" + * except that the range has been replaced by the domain space of "ma". + */ +__isl_give isl_basic_map *isl_basic_map_preimage_range_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma) +{ + return isl_basic_map_preimage_multi_aff(bmap, isl_dim_out, ma); +} + +/* Check if the range of "ma" is compatible with the domain or range + * (depending on "type") of "map". + * Return isl_stat_error if anything is wrong. + */ +static isl_stat check_map_compatible_range_multi_aff( + __isl_keep isl_map *map, enum isl_dim_type type, + __isl_keep isl_multi_aff *ma) +{ + isl_bool m; + isl_space *ma_space; + + ma_space = isl_multi_aff_get_space(ma); + m = isl_space_tuple_is_equal(map->dim, type, ma_space, isl_dim_out); + isl_space_free(ma_space); + if (m < 0) + return isl_stat_error; + if (!m) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "spaces don't match", return isl_stat_error); + return isl_stat_ok; +} + +/* Compute the preimage of the domain or range (depending on "type") + * of "map" under the function represented by "ma". + * In other words, plug in "ma" in the domain or range of "map". + * The result is a map that lives in the same space as "map" + * except that the domain or range has been replaced by + * the domain space of "ma". + * + * The parameters are assumed to have been aligned. + */ +static __isl_give isl_map *map_preimage_multi_aff(__isl_take isl_map *map, + enum isl_dim_type type, __isl_take isl_multi_aff *ma) +{ + int i; + isl_space *space; + + map = isl_map_cow(map); + ma = isl_multi_aff_align_divs(ma); + if (!map || !ma) + goto error; + if (check_map_compatible_range_multi_aff(map, type, ma) < 0) + goto error; + + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_preimage_multi_aff(map->p[i], type, + isl_multi_aff_copy(ma)); + if (!map->p[i]) + goto error; + } + + space = isl_multi_aff_get_domain_space(ma); + space = isl_space_set(isl_map_get_space(map), type, space); + + isl_space_free(map->dim); + map->dim = space; + if (!map->dim) + goto error; + + isl_multi_aff_free(ma); + if (map->n > 1) + ISL_F_CLR(map, ISL_MAP_DISJOINT); + ISL_F_CLR(map, ISL_SET_NORMALIZED); + return map; +error: + isl_multi_aff_free(ma); + isl_map_free(map); + return NULL; +} + +/* Compute the preimage of the domain or range (depending on "type") + * of "map" under the function represented by "ma". + * In other words, plug in "ma" in the domain or range of "map". + * The result is a map that lives in the same space as "map" + * except that the domain or range has been replaced by + * the domain space of "ma". + */ +__isl_give isl_map *isl_map_preimage_multi_aff(__isl_take isl_map *map, + enum isl_dim_type type, __isl_take isl_multi_aff *ma) +{ + isl_bool aligned; + + if (!map || !ma) + goto error; + + aligned = isl_map_space_has_equal_params(map, ma->space); + if (aligned < 0) + goto error; + if (aligned) + return map_preimage_multi_aff(map, type, ma); + + if (isl_map_check_named_params(map) < 0) + goto error; + if (!isl_space_has_named_params(ma->space)) + isl_die(map->ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + map = isl_map_align_params(map, isl_multi_aff_get_space(ma)); + ma = isl_multi_aff_align_params(ma, isl_map_get_space(map)); + + return map_preimage_multi_aff(map, type, ma); +error: + isl_multi_aff_free(ma); + return isl_map_free(map); +} + +/* Compute the preimage of "set" under the function represented by "ma". + * In other words, plug in "ma" in "set". The result is a set + * that lives in the domain space of "ma". + */ +__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set, + __isl_take isl_multi_aff *ma) +{ + return isl_map_preimage_multi_aff(set, isl_dim_set, ma); +} + +/* Compute the preimage of the domain of "map" under the function + * represented by "ma". + * In other words, plug in "ma" in the domain of "map". + * The result is a map that lives in the same space as "map" + * except that the domain has been replaced by the domain space of "ma". + */ +__isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map, + __isl_take isl_multi_aff *ma) +{ + return isl_map_preimage_multi_aff(map, isl_dim_in, ma); +} + +/* Compute the preimage of the range of "map" under the function + * represented by "ma". + * In other words, plug in "ma" in the range of "map". + * The result is a map that lives in the same space as "map" + * except that the range has been replaced by the domain space of "ma". + */ +__isl_give isl_map *isl_map_preimage_range_multi_aff(__isl_take isl_map *map, + __isl_take isl_multi_aff *ma) +{ + return isl_map_preimage_multi_aff(map, isl_dim_out, ma); +} + +/* Compute the preimage of "map" under the function represented by "pma". + * In other words, plug in "pma" in the domain or range of "map". + * The result is a map that lives in the same space as "map", + * except that the space of type "type" has been replaced by + * the domain space of "pma". + * + * The parameters of "map" and "pma" are assumed to have been aligned. + */ +static __isl_give isl_map *isl_map_preimage_pw_multi_aff_aligned( + __isl_take isl_map *map, enum isl_dim_type type, + __isl_take isl_pw_multi_aff *pma) +{ + int i; + isl_map *res; + + if (!pma) + goto error; + + if (pma->n == 0) { + isl_pw_multi_aff_free(pma); + res = isl_map_empty(isl_map_get_space(map)); + isl_map_free(map); + return res; + } + + res = isl_map_preimage_multi_aff(isl_map_copy(map), type, + isl_multi_aff_copy(pma->p[0].maff)); + if (type == isl_dim_in) + res = isl_map_intersect_domain(res, + isl_map_copy(pma->p[0].set)); + else + res = isl_map_intersect_range(res, + isl_map_copy(pma->p[0].set)); + + for (i = 1; i < pma->n; ++i) { + isl_map *res_i; + + res_i = isl_map_preimage_multi_aff(isl_map_copy(map), type, + isl_multi_aff_copy(pma->p[i].maff)); + if (type == isl_dim_in) + res_i = isl_map_intersect_domain(res_i, + isl_map_copy(pma->p[i].set)); + else + res_i = isl_map_intersect_range(res_i, + isl_map_copy(pma->p[i].set)); + res = isl_map_union(res, res_i); + } + + isl_pw_multi_aff_free(pma); + isl_map_free(map); + return res; +error: + isl_pw_multi_aff_free(pma); + isl_map_free(map); + return NULL; +} + +/* Compute the preimage of "map" under the function represented by "pma". + * In other words, plug in "pma" in the domain or range of "map". + * The result is a map that lives in the same space as "map", + * except that the space of type "type" has been replaced by + * the domain space of "pma". + */ +__isl_give isl_map *isl_map_preimage_pw_multi_aff(__isl_take isl_map *map, + enum isl_dim_type type, __isl_take isl_pw_multi_aff *pma) +{ + isl_bool aligned; + + if (!map || !pma) + goto error; + + aligned = isl_map_space_has_equal_params(map, pma->dim); + if (aligned < 0) + goto error; + if (aligned) + return isl_map_preimage_pw_multi_aff_aligned(map, type, pma); + + if (isl_map_check_named_params(map) < 0) + goto error; + if (!isl_space_has_named_params(pma->dim)) + isl_die(map->ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + map = isl_map_align_params(map, isl_pw_multi_aff_get_space(pma)); + pma = isl_pw_multi_aff_align_params(pma, isl_map_get_space(map)); + + return isl_map_preimage_pw_multi_aff_aligned(map, type, pma); +error: + isl_pw_multi_aff_free(pma); + return isl_map_free(map); +} + +/* Compute the preimage of "set" under the function represented by "pma". + * In other words, plug in "pma" in "set". The result is a set + * that lives in the domain space of "pma". + */ +__isl_give isl_set *isl_set_preimage_pw_multi_aff(__isl_take isl_set *set, + __isl_take isl_pw_multi_aff *pma) +{ + return isl_map_preimage_pw_multi_aff(set, isl_dim_set, pma); +} + +/* Compute the preimage of the domain of "map" under the function + * represented by "pma". + * In other words, plug in "pma" in the domain of "map". + * The result is a map that lives in the same space as "map", + * except that domain space has been replaced by the domain space of "pma". + */ +__isl_give isl_map *isl_map_preimage_domain_pw_multi_aff( + __isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma) +{ + return isl_map_preimage_pw_multi_aff(map, isl_dim_in, pma); +} + +/* Compute the preimage of the range of "map" under the function + * represented by "pma". + * In other words, plug in "pma" in the range of "map". + * The result is a map that lives in the same space as "map", + * except that range space has been replaced by the domain space of "pma". + */ +__isl_give isl_map *isl_map_preimage_range_pw_multi_aff( + __isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma) +{ + return isl_map_preimage_pw_multi_aff(map, isl_dim_out, pma); +} + +/* Compute the preimage of "map" under the function represented by "mpa". + * In other words, plug in "mpa" in the domain or range of "map". + * The result is a map that lives in the same space as "map", + * except that the space of type "type" has been replaced by + * the domain space of "mpa". + * + * If the map does not involve any constraints that refer to the + * dimensions of the substituted space, then the only possible + * effect of "mpa" on the map is to map the space to a different space. + * We create a separate isl_multi_aff to effectuate this change + * in order to avoid spurious splitting of the map along the pieces + * of "mpa". + */ +__isl_give isl_map *isl_map_preimage_multi_pw_aff(__isl_take isl_map *map, + enum isl_dim_type type, __isl_take isl_multi_pw_aff *mpa) +{ + int n; + isl_pw_multi_aff *pma; + + if (!map || !mpa) + goto error; + + n = isl_map_dim(map, type); + if (!isl_map_involves_dims(map, type, 0, n)) { + isl_space *space; + isl_multi_aff *ma; + + space = isl_multi_pw_aff_get_space(mpa); + isl_multi_pw_aff_free(mpa); + ma = isl_multi_aff_zero(space); + return isl_map_preimage_multi_aff(map, type, ma); + } + + pma = isl_pw_multi_aff_from_multi_pw_aff(mpa); + return isl_map_preimage_pw_multi_aff(map, type, pma); +error: + isl_map_free(map); + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Compute the preimage of "map" under the function represented by "mpa". + * In other words, plug in "mpa" in the domain "map". + * The result is a map that lives in the same space as "map", + * except that domain space has been replaced by the domain space of "mpa". + */ +__isl_give isl_map *isl_map_preimage_domain_multi_pw_aff( + __isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa) +{ + return isl_map_preimage_multi_pw_aff(map, isl_dim_in, mpa); +} + +/* Compute the preimage of "set" by the function represented by "mpa". + * In other words, plug in "mpa" in "set". + */ +__isl_give isl_set *isl_set_preimage_multi_pw_aff(__isl_take isl_set *set, + __isl_take isl_multi_pw_aff *mpa) +{ + return isl_map_preimage_multi_pw_aff(set, isl_dim_set, mpa); +} + +/* Return a copy of the equality constraints of "bset" as a matrix. + */ +__isl_give isl_mat *isl_basic_set_extract_equalities( + __isl_keep isl_basic_set *bset) +{ + isl_ctx *ctx; + unsigned total; + + if (!bset) + return NULL; + + ctx = isl_basic_set_get_ctx(bset); + total = 1 + isl_basic_set_dim(bset, isl_dim_all); + return isl_mat_sub_alloc6(ctx, bset->eq, 0, bset->n_eq, 0, total); +} + +/* Are the "n" "coefficients" starting at "first" of the integer division + * expressions at position "pos1" in "bmap1" and "pos2" in "bmap2" equal + * to each other? + * The "coefficient" at position 0 is the denominator. + * The "coefficient" at position 1 is the constant term. + */ +isl_bool isl_basic_map_equal_div_expr_part(__isl_keep isl_basic_map *bmap1, + int pos1, __isl_keep isl_basic_map *bmap2, int pos2, + unsigned first, unsigned n) +{ + if (isl_basic_map_check_range(bmap1, isl_dim_div, pos1, 1) < 0) + return isl_bool_error; + if (isl_basic_map_check_range(bmap2, isl_dim_div, pos2, 1) < 0) + return isl_bool_error; + return isl_seq_eq(bmap1->div[pos1] + first, + bmap2->div[pos2] + first, n); +} + +/* Are the integer division expressions at position "pos1" in "bmap1" and + * "pos2" in "bmap2" equal to each other, except that the constant terms + * are different? + */ +isl_bool isl_basic_map_equal_div_expr_except_constant( + __isl_keep isl_basic_map *bmap1, int pos1, + __isl_keep isl_basic_map *bmap2, int pos2) +{ + isl_bool equal; + unsigned total; + + if (!bmap1 || !bmap2) + return isl_bool_error; + total = isl_basic_map_total_dim(bmap1); + if (total != isl_basic_map_total_dim(bmap2)) + isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, + "incomparable div expressions", return isl_bool_error); + equal = isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2, + 0, 1); + if (equal < 0 || !equal) + return equal; + equal = isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2, + 1, 1); + if (equal < 0 || equal) + return isl_bool_not(equal); + return isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2, + 2, total); +} + +/* Replace the numerator of the constant term of the integer division + * expression at position "div" in "bmap" by "value". + * The caller guarantees that this does not change the meaning + * of the input. + */ +__isl_give isl_basic_map *isl_basic_map_set_div_expr_constant_num_si_inplace( + __isl_take isl_basic_map *bmap, int div, int value) +{ + if (isl_basic_map_check_range(bmap, isl_dim_div, div, 1) < 0) + return isl_basic_map_free(bmap); + + isl_int_set_si(bmap->div[div][1], value); + + return bmap; +} + +/* Is the point "inner" internal to inequality constraint "ineq" + * of "bset"? + * The point is considered to be internal to the inequality constraint, + * if it strictly lies on the positive side of the inequality constraint, + * or if it lies on the constraint and the constraint is lexico-positive. + */ +static isl_bool is_internal(__isl_keep isl_vec *inner, + __isl_keep isl_basic_set *bset, int ineq) +{ + isl_ctx *ctx; + int pos; + unsigned total; + + if (!inner || !bset) + return isl_bool_error; + + ctx = isl_basic_set_get_ctx(bset); + isl_seq_inner_product(inner->el, bset->ineq[ineq], inner->size, + &ctx->normalize_gcd); + if (!isl_int_is_zero(ctx->normalize_gcd)) + return isl_int_is_nonneg(ctx->normalize_gcd); + + total = isl_basic_set_dim(bset, isl_dim_all); + pos = isl_seq_first_non_zero(bset->ineq[ineq] + 1, total); + return isl_int_is_pos(bset->ineq[ineq][1 + pos]); +} + +/* Tighten the inequality constraints of "bset" that are outward with respect + * to the point "vec". + * That is, tighten the constraints that are not satisfied by "vec". + * + * "vec" is a point internal to some superset S of "bset" that is used + * to make the subsets of S disjoint, by tightening one half of the constraints + * that separate two subsets. In particular, the constraints of S + * are all satisfied by "vec" and should not be tightened. + * Of the internal constraints, those that have "vec" on the outside + * are tightened. The shared facet is included in the adjacent subset + * with the opposite constraint. + * For constraints that saturate "vec", this criterion cannot be used + * to determine which of the two sides should be tightened. + * Instead, the sign of the first non-zero coefficient is used + * to make this choice. Note that this second criterion is never used + * on the constraints of S since "vec" is interior to "S". + */ +__isl_give isl_basic_set *isl_basic_set_tighten_outward( + __isl_take isl_basic_set *bset, __isl_keep isl_vec *vec) +{ + int j; + + bset = isl_basic_set_cow(bset); + if (!bset) + return NULL; + for (j = 0; j < bset->n_ineq; ++j) { + isl_bool internal; + + internal = is_internal(vec, bset, j); + if (internal < 0) + return isl_basic_set_free(bset); + if (internal) + continue; + isl_int_sub_ui(bset->ineq[j][0], bset->ineq[j][0], 1); + } + + return bset; +} + +/* Replace the variables x of type "type" starting at "first" in "bmap" + * 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_map *isl_basic_map_transform_dims( + __isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned first, + __isl_take isl_mat *trans) +{ + unsigned pos; + + bmap = isl_basic_map_cow(bmap); + if (!bmap || !trans) + goto error; + + 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_map_dim(bmap, type)) + isl_die(trans->ctx, isl_error_invalid, + "oversized transformation matrix", goto error); + + pos = isl_basic_map_offset(bmap, type) + first; + + if (isl_mat_sub_transform(bmap->eq, bmap->n_eq, pos, + isl_mat_copy(trans)) < 0) + goto error; + if (isl_mat_sub_transform(bmap->ineq, bmap->n_ineq, pos, + isl_mat_copy(trans)) < 0) + goto error; + if (isl_mat_sub_transform(bmap->div, bmap->n_div, 1 + pos, + isl_mat_copy(trans)) < 0) + goto error; + + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); + + isl_mat_free(trans); + return bmap; +error: + isl_mat_free(trans); + isl_basic_map_free(bmap); + return NULL; +} + +/* 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) +{ + return isl_basic_map_transform_dims(bset, type, first, trans); +} Index: contrib/isl/isl_map_lexopt_templ.c =================================================================== --- /dev/null +++ contrib/isl/isl_map_lexopt_templ.c @@ -0,0 +1,229 @@ +/* + * Copyright 2010 INRIA Saclay + * Copyright 2012 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * INRIA Saclay - Ile-de-France, Parc Club Orsay Universite, + * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +/* Function for computing the lexicographic optimum of a map + * in the form of either an isl_map or an isl_pw_multi_aff. + */ + +#define xSF(TYPE,SUFFIX) TYPE ## SUFFIX +#define SF(TYPE,SUFFIX) xSF(TYPE,SUFFIX) + +/* Compute the lexicographic minimum (or maximum if "flags" includes + * ISL_OPT_MAX) of "bmap" over the domain "dom" and return the result. + * If "empty" is not NULL, then *empty is assigned a set that + * contains those parts of the domain where there is no solution. + * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum + * should be computed over the domain of "bmap". "empty" is also NULL + * in this case. + * If "bmap" is marked as rational (ISL_BASIC_MAP_RATIONAL), + * then the rational optimum is computed. Otherwise, the integral optimum + * is computed. + */ +static __isl_give TYPE *SF(isl_basic_map_partial_lexopt,SUFFIX)( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, unsigned flags) +{ + return SF(isl_tab_basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty, + flags); +} + +__isl_give TYPE *SF(isl_basic_map_partial_lexmax,SUFFIX)( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty) +{ + unsigned flags = ISL_OPT_MAX; + return SF(isl_basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty, flags); +} + +__isl_give TYPE *SF(isl_basic_map_partial_lexmin,SUFFIX)( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty) +{ + unsigned flags = 0; + return SF(isl_basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty, flags); +} + +__isl_give TYPE *SF(isl_basic_set_partial_lexmin,SUFFIX)( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty) +{ + return SF(isl_basic_map_partial_lexmin,SUFFIX)(bset, dom, empty); +} + +__isl_give TYPE *SF(isl_basic_set_partial_lexmax,SUFFIX)( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty) +{ + return SF(isl_basic_map_partial_lexmax,SUFFIX)(bset, dom, empty); +} + +/* Given a basic map "bmap", compute the lexicographically minimal + * (or maximal) image element for each domain element in dom. + * If empty is not NULL, then set *empty to those elements in dom + * that do not have an image element. + * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum + * should be computed over the domain of "bmap". "empty" is also NULL + * in this case. + * + * We first make sure the basic sets in dom are disjoint and then + * simply collect the results over each of the basic sets separately. + * We could probably improve the efficiency a bit by moving the union + * domain down into the parametric integer programming. + * + * If a full optimum is being computed (i.e., "flags" includes ISL_OPT_FULL), + * then no domain is given and there is then also no need to consider + * the disjuncts of the domain. + */ +static __isl_give TYPE *SF(basic_map_partial_lexopt,SUFFIX)( + __isl_take isl_basic_map *bmap, __isl_take isl_set *dom, + __isl_give isl_set **empty, unsigned flags) +{ + int i; + TYPE *res; + isl_set *all_empty; + + if (ISL_FL_ISSET(flags, ISL_OPT_FULL)) + return SF(isl_basic_map_partial_lexopt,SUFFIX)(bmap, NULL, + empty, flags); + + dom = isl_set_make_disjoint(dom); + if (!dom) + goto error; + + if (isl_set_plain_is_empty(dom)) { + isl_space *space = isl_basic_map_get_space(bmap); + if (empty) + *empty = dom; + else + isl_set_free(dom); + isl_basic_map_free(bmap); + return EMPTY(space); + } + + res = SF(isl_basic_map_partial_lexopt,SUFFIX)(isl_basic_map_copy(bmap), + isl_basic_set_copy(dom->p[0]), empty, flags); + + if (empty) + all_empty = *empty; + for (i = 1; i < dom->n; ++i) { + TYPE *res_i; + + res_i = SF(isl_basic_map_partial_lexopt,SUFFIX)( + isl_basic_map_copy(bmap), + isl_basic_set_copy(dom->p[i]), empty, flags); + + res = ADD(res, res_i); + if (empty) + all_empty = isl_set_union_disjoint(all_empty, *empty); + } + + if (empty) + *empty = all_empty; + isl_set_free(dom); + isl_basic_map_free(bmap); + return res; +error: + if (empty) + *empty = NULL; + isl_set_free(dom); + isl_basic_map_free(bmap); + return NULL; +} + +/* Compute the lexicographic minimum (or maximum if "flags" includes + * ISL_OPT_MAX) of "bmap" over its domain. + */ +__isl_give TYPE *SF(isl_basic_map_lexopt,SUFFIX)( + __isl_take isl_basic_map *bmap, unsigned flags) +{ + ISL_FL_SET(flags, ISL_OPT_FULL); + return SF(isl_basic_map_partial_lexopt,SUFFIX)(bmap, NULL, NULL, flags); +} + +__isl_give TYPE *SF(isl_basic_map_lexmin,SUFFIX)(__isl_take isl_basic_map *bmap) +{ + return SF(isl_basic_map_lexopt,SUFFIX)(bmap, 0); +} + +static __isl_give TYPE *SF(isl_map_partial_lexopt_aligned,SUFFIX)( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty, unsigned flags); +/* This function is currently only used when TYPE is defined as isl_map. */ +static __isl_give TYPE *SF(isl_map_partial_lexopt,SUFFIX)( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty, unsigned flags) + __attribute__ ((unused)); + +/* Given a map "map", compute the lexicographically minimal + * (or maximal) image element for each domain element in dom. + * Set *empty to those elements in dom that do not have an image element. + * + * Align parameters if needed and then call isl_map_partial_lexopt_aligned. + */ +static __isl_give TYPE *SF(isl_map_partial_lexopt,SUFFIX)( + __isl_take isl_map *map, __isl_take isl_set *dom, + __isl_give isl_set **empty, unsigned flags) +{ + isl_bool aligned; + + aligned = isl_map_set_has_equal_params(map, dom); + if (aligned < 0) + goto error; + if (aligned) + return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom, + empty, flags); + if (!isl_space_has_named_params(map->dim) || + !isl_space_has_named_params(dom->dim)) + isl_die(map->ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + map = isl_map_align_params(map, isl_map_get_space(dom)); + dom = isl_map_align_params(dom, isl_map_get_space(map)); + return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom, empty, + flags); +error: + if (empty) + *empty = NULL; + isl_set_free(dom); + isl_map_free(map); + return NULL; +} + +/* Compute the lexicographic minimum (or maximum if "flags" includes + * ISL_OPT_MAX) of "map" over its domain. + */ +__isl_give TYPE *SF(isl_map_lexopt,SUFFIX)(__isl_take isl_map *map, + unsigned flags) +{ + ISL_FL_SET(flags, ISL_OPT_FULL); + return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, NULL, NULL, + flags); +} + +__isl_give TYPE *SF(isl_map_lexmin,SUFFIX)(__isl_take isl_map *map) +{ + return SF(isl_map_lexopt,SUFFIX)(map, 0); +} + +__isl_give TYPE *SF(isl_map_lexmax,SUFFIX)(__isl_take isl_map *map) +{ + return SF(isl_map_lexopt,SUFFIX)(map, ISL_OPT_MAX); +} + +__isl_give TYPE *SF(isl_set_lexmin,SUFFIX)(__isl_take isl_set *set) +{ + return SF(isl_map_lexmin,SUFFIX)(set); +} + +__isl_give TYPE *SF(isl_set_lexmax,SUFFIX)(__isl_take isl_set *set) +{ + return SF(isl_map_lexmax,SUFFIX)(set); +} Index: contrib/isl/isl_map_list.c =================================================================== --- /dev/null +++ contrib/isl/isl_map_list.c @@ -0,0 +1,32 @@ +#include +#include + +#undef EL +#define EL isl_basic_map + +#include + +#undef BASE +#define BASE basic_map + +#include + +#undef EL +#define EL isl_map + +#include + +#undef BASE +#define BASE map + +#include + +#undef EL +#define EL isl_union_map + +#include + +#undef BASE +#define BASE union_map + +#include Index: contrib/isl/isl_map_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_map_private.h @@ -0,0 +1,550 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_MAP_PRIVATE_H +#define ISL_MAP_PRIVATE_H + +#define isl_basic_set isl_basic_map +#define isl_maybe_isl_basic_set isl_maybe_isl_basic_map +#define isl_set isl_map +#define isl_basic_set_list isl_basic_map_list +#define isl_set_list isl_map_list +#include +#include +#include +#include +#include +#include +#include + +/* A "basic map" is a relation between two sets of variables, + * called the "in" and "out" variables. + * A "basic set" is a basic map with a zero-dimensional + * domain. + * + * It is implemented as a set with two extra fields: + * n_in is the number of in variables + * n_out is the number of out variables + * n_in + n_out should be equal to set.dim + */ +struct isl_basic_map { + int ref; +#define ISL_BASIC_MAP_FINAL (1 << 0) +#define ISL_BASIC_MAP_EMPTY (1 << 1) +#define ISL_BASIC_MAP_NO_IMPLICIT (1 << 2) +#define ISL_BASIC_MAP_NO_REDUNDANT (1 << 3) +#define ISL_BASIC_MAP_RATIONAL (1 << 4) +#define ISL_BASIC_MAP_NORMALIZED (1 << 5) +#define ISL_BASIC_MAP_NORMALIZED_DIVS (1 << 6) +#define ISL_BASIC_MAP_ALL_EQUALITIES (1 << 7) +#define ISL_BASIC_MAP_REDUCED_COEFFICIENTS (1 << 8) +#define ISL_BASIC_SET_FINAL (1 << 0) +#define ISL_BASIC_SET_EMPTY (1 << 1) +#define ISL_BASIC_SET_NO_IMPLICIT (1 << 2) +#define ISL_BASIC_SET_NO_REDUNDANT (1 << 3) +#define ISL_BASIC_SET_RATIONAL (1 << 4) +#define ISL_BASIC_SET_NORMALIZED (1 << 5) +#define ISL_BASIC_SET_NORMALIZED_DIVS (1 << 6) +#define ISL_BASIC_SET_ALL_EQUALITIES (1 << 7) +#define ISL_BASIC_SET_REDUCED_COEFFICIENTS (1 << 8) + unsigned flags; + + struct isl_ctx *ctx; + + isl_space *dim; + unsigned extra; + + unsigned n_eq; + unsigned n_ineq; + + size_t c_size; + isl_int **eq; + isl_int **ineq; + + unsigned n_div; + + isl_int **div; + + struct isl_vec *sample; + + struct isl_blk block; + struct isl_blk block2; +}; + +#undef EL +#define EL isl_basic_set + +#include + +/* A "map" is a (possibly disjoint) union of basic maps. + * A "set" is a (possibly disjoint) union of basic sets. + * + * Currently, the isl_set structure is identical to the isl_map structure + * and the library depends on this correspondence internally. + * However, users should not depend on this correspondence. + * + * "cached_simple_hull" contains copies of the unshifted and shifted + * simple hulls, if they have already been computed. Otherwise, + * the entries are NULL. + */ +struct isl_map { + int ref; +#define ISL_MAP_DISJOINT (1 << 0) +#define ISL_MAP_NORMALIZED (1 << 1) +#define ISL_SET_DISJOINT (1 << 0) +#define ISL_SET_NORMALIZED (1 << 1) + unsigned flags; + isl_basic_map *cached_simple_hull[2]; + + struct isl_ctx *ctx; + + isl_space *dim; + + int n; + + size_t size; + struct isl_basic_map *p[1]; +}; + +#undef EL +#define EL isl_set + +#include + +__isl_give isl_basic_set *isl_basic_set_alloc(isl_ctx *ctx, + unsigned nparam, unsigned dim, unsigned extra, + unsigned n_eq, unsigned n_ineq); +__isl_give isl_basic_set *isl_basic_set_extend(__isl_take isl_basic_set *base, + unsigned nparam, unsigned dim, unsigned extra, + unsigned n_eq, unsigned n_ineq); +__isl_give isl_basic_set *isl_basic_set_extend_constraints( + __isl_take isl_basic_set *base, unsigned n_eq, unsigned n_ineq); +__isl_give isl_basic_set *isl_basic_set_finalize( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_dup(__isl_keep isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_simplify( + __isl_take isl_basic_set *bset); + +__isl_give isl_basic_map *isl_basic_map_alloc(isl_ctx *ctx, + unsigned nparam, unsigned in, unsigned out, unsigned extra, + unsigned n_eq, unsigned n_ineq); +__isl_give isl_basic_map *isl_basic_map_mark_final( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_finalize( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_extend(__isl_take isl_basic_map *base, + unsigned nparam, unsigned n_in, unsigned n_out, unsigned extra, + unsigned n_eq, unsigned n_ineq); +__isl_give isl_basic_map *isl_basic_map_extend_constraints( + __isl_take isl_basic_map *base, unsigned n_eq, unsigned n_ineq); +__isl_give isl_basic_map *isl_basic_map_simplify( + __isl_take isl_basic_map *bmap); + +__isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *bset); + +__isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map, + __isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_dup(__isl_keep isl_map *map); + +__isl_give isl_basic_set *isl_basic_set_from_underlying_set( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *like); + +__isl_give isl_map *isl_map_realign(__isl_take isl_map *map, + __isl_take isl_reordering *r); +__isl_give isl_set *isl_set_realign(__isl_take isl_set *set, + __isl_take isl_reordering *r); + +__isl_give isl_basic_map *isl_basic_map_reset(__isl_take isl_basic_map *bmap, + enum isl_dim_type type); +__isl_give isl_map *isl_map_reset(__isl_take isl_map *map, + enum isl_dim_type type); + +__isl_keep isl_space *isl_basic_map_peek_space( + __isl_keep const isl_basic_map *bmap); +__isl_keep isl_space *isl_basic_set_peek_space(__isl_keep isl_basic_set *bset); + +__isl_give isl_basic_set *isl_basic_set_reset_space( + __isl_take isl_basic_set *bset, __isl_take isl_space *dim); +__isl_give isl_basic_map *isl_basic_map_reset_space( + __isl_take isl_basic_map *bmap, __isl_take isl_space *dim); +__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map, + __isl_take isl_space *dim); + +unsigned isl_basic_map_offset(struct isl_basic_map *bmap, + enum isl_dim_type type); +unsigned isl_basic_set_offset(__isl_keep isl_basic_set *bset, + enum isl_dim_type type); + +isl_bool isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap); +int isl_map_may_be_set(__isl_keep isl_map *map); +isl_bool isl_map_compatible_domain(__isl_keep isl_map *map, + __isl_keep isl_set *set); +isl_bool isl_basic_map_compatible_domain(__isl_keep isl_basic_map *bmap, + __isl_keep isl_basic_set *bset); +isl_bool isl_basic_map_compatible_range(__isl_keep isl_basic_map *bmap, + __isl_keep isl_basic_set *bset); + +__isl_give isl_basic_map *isl_basic_map_extend_space( + __isl_take isl_basic_map *base, __isl_take isl_space *dim, + unsigned extra, unsigned n_eq, unsigned n_ineq); +__isl_give isl_basic_set *isl_basic_set_extend_space( + __isl_take isl_basic_set *base, + __isl_take isl_space *dim, unsigned extra, + unsigned n_eq, unsigned n_ineq); +struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1, + struct isl_basic_set *bset2, unsigned pos); + +__isl_give isl_map *isl_map_grow(__isl_take isl_map *map, int n); +struct isl_set *isl_set_grow(struct isl_set *set, int n); + +isl_bool isl_basic_set_contains(__isl_keep isl_basic_set *bset, + __isl_keep isl_vec *vec); +isl_bool isl_basic_map_contains(__isl_keep isl_basic_map *bmap, + __isl_keep isl_vec *vec); + +__isl_give isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim, + unsigned extra, unsigned n_eq, unsigned n_ineq); +__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *dim, int n, + unsigned flags); +__isl_give isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim, + unsigned extra, unsigned n_eq, unsigned n_ineq); +__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n, + unsigned flags); + +int isl_basic_map_alloc_equality(struct isl_basic_map *bmap); +int isl_basic_set_alloc_equality(struct isl_basic_set *bset); +int isl_basic_set_free_inequality(struct isl_basic_set *bset, unsigned n); +int isl_basic_map_free_equality(struct isl_basic_map *bmap, unsigned n); +int isl_basic_set_free_equality(struct isl_basic_set *bset, unsigned n); +int isl_basic_set_alloc_inequality(__isl_keep isl_basic_set *bset); +int isl_basic_map_alloc_inequality(__isl_keep isl_basic_map *bmap); +int isl_basic_map_free_inequality(struct isl_basic_map *bmap, unsigned n); +int isl_basic_map_alloc_div(struct isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_insert_div( + __isl_take isl_basic_map *bmap, int pos, __isl_keep isl_vec *div); +int isl_basic_set_alloc_div(struct isl_basic_set *bset); +isl_stat isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n); +__isl_give isl_basic_map *isl_basic_map_drop_div( + __isl_take isl_basic_map *bmap, unsigned div); +void isl_basic_map_inequality_to_equality( + struct isl_basic_map *bmap, unsigned pos); +int isl_basic_map_drop_equality(struct isl_basic_map *bmap, unsigned pos); +int isl_basic_set_drop_inequality(struct isl_basic_set *bset, unsigned pos); +int isl_basic_map_drop_inequality(struct isl_basic_map *bmap, unsigned pos); +__isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset, + isl_int *eq); +__isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap, + isl_int *eq); +__isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset, + isl_int *ineq); +__isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap, + isl_int *ineq); + +__isl_give isl_basic_set *isl_basic_set_tighten_outward( + __isl_take isl_basic_set *bset, __isl_keep isl_vec *vec); + +int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos); + +__isl_give isl_basic_set *isl_basic_set_cow(__isl_take isl_basic_set *bset); +__isl_give isl_basic_map *isl_basic_map_cow(__isl_take isl_basic_map *bmap); +__isl_give isl_set *isl_set_cow(__isl_take isl_set *set); +__isl_give isl_map *isl_map_cow(__isl_take isl_map *map); + +uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap); + +__isl_give isl_set *isl_basic_set_list_union( + __isl_take isl_basic_set_list *list); + +__isl_give isl_basic_map *isl_basic_map_set_to_empty( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_set *isl_basic_set_set_to_empty( + __isl_take isl_basic_set *bset); +struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset); +void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b); +void isl_basic_set_swap_div(struct isl_basic_set *bset, int a, int b); +__isl_give isl_basic_map *isl_basic_map_order_divs( + __isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map); +__isl_give isl_basic_map *isl_basic_map_align_divs( + __isl_take isl_basic_map *dst, __isl_keep isl_basic_map *src); +__isl_give isl_map *isl_map_align_divs_to_basic_map_list( + __isl_take isl_map *map, __isl_keep isl_basic_map_list *list); +__isl_give isl_basic_map_list *isl_basic_map_list_align_divs_to_basic_map( + __isl_take isl_basic_map_list *list, __isl_keep isl_basic_map *bmap); +__isl_give isl_map *isl_map_align_divs_internal(__isl_take isl_map *map); +__isl_give isl_basic_set *isl_basic_set_sort_divs( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_map *isl_basic_map_sort_divs( + __isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map); +__isl_give isl_basic_map *isl_basic_map_gauss(__isl_take isl_basic_map *bmap, + int *progress); +__isl_give isl_basic_set *isl_basic_set_gauss( + __isl_take isl_basic_set *bset, int *progress); +int isl_basic_map_constraint_cmp(__isl_keep isl_basic_map *bmap, + isl_int *c1, isl_int *c2); +__isl_give isl_basic_map *isl_basic_map_sort_constraints( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_set *isl_basic_set_sort_constraints( + __isl_take isl_basic_set *bset); +int isl_basic_map_plain_cmp(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); +isl_bool isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2); +__isl_give isl_basic_map *isl_basic_map_normalize_constraints( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_set *isl_basic_set_normalize_constraints( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_map *isl_basic_map_implicit_equalities( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_set *isl_basic_map_underlying_set( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_set *isl_basic_set_underlying_set( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_set_list *isl_basic_map_list_underlying_set( + __isl_take isl_basic_map_list *list); +__isl_give isl_set *isl_map_underlying_set(__isl_take isl_map *map); +__isl_give isl_basic_map *isl_basic_map_overlying_set( + __isl_take isl_basic_set *bset, __isl_take isl_basic_map *like); +__isl_give isl_basic_map *isl_basic_map_drop_constraint_involving_unknown_divs( + __isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_drop_constraint_involving_unknown_divs( + __isl_take isl_map *map); +__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving( + __isl_take isl_basic_set *bset, unsigned first, unsigned n); +__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_map *isl_basic_map_drop(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_set *isl_set_drop(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_set *isl_basic_set_drop_dims( + __isl_take isl_basic_set *bset, unsigned first, unsigned n); +__isl_give isl_map *isl_map_drop(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_basic_map *isl_basic_map_drop_unrelated_constraints( + __isl_take isl_basic_map *bmap, __isl_take int *group); + +__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints( + __isl_take isl_basic_map *bmap, int *progress, int detect_divs); +__isl_give isl_basic_map *isl_basic_map_detect_inequality_pairs( + __isl_take isl_basic_map *bmap, int *progress); + +__isl_give isl_map *isl_map_remove_empty_parts(__isl_take isl_map *map); +struct isl_set *isl_set_remove_empty_parts(struct isl_set *set); +__isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map); + +struct isl_set *isl_set_normalize(struct isl_set *set); + +struct isl_set *isl_set_drop_vars( + struct isl_set *set, unsigned first, unsigned n); + +__isl_give isl_basic_map *isl_basic_map_eliminate_vars( + __isl_take isl_basic_map *bmap, unsigned pos, unsigned n); +struct isl_basic_set *isl_basic_set_eliminate_vars( + struct isl_basic_set *bset, unsigned pos, unsigned n); + +__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n); + +int isl_basic_map_add_div_constraint(__isl_keep isl_basic_map *bmap, + unsigned div, int sign); +int isl_basic_map_add_div_constraints(struct isl_basic_map *bmap, unsigned div); +__isl_give isl_basic_map *isl_basic_map_add_known_div_constraints( + __isl_take isl_basic_map *bmap); +__isl_give isl_basic_map *isl_basic_map_drop_redundant_divs( + __isl_take isl_basic_map *bmap); + +__isl_give isl_basic_set *isl_basic_set_recession_cone( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_lineality_space( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_set_combined_lineality_space( + __isl_take isl_set *set); + +__isl_give isl_basic_set *isl_basic_set_set_integral( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_set *isl_basic_set_set_rational( + __isl_take isl_basic_set *bset); +__isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set); +__isl_give isl_basic_map *isl_basic_map_set_rational( + __isl_take isl_basic_map *bmap); +__isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map); + +isl_bool isl_map_is_rational(__isl_keep isl_map *map); +isl_bool isl_set_is_rational(__isl_keep isl_set *set); + +isl_bool isl_map_has_rational(__isl_keep isl_map *map); +isl_bool isl_set_has_rational(__isl_keep isl_set *set); + +__isl_give isl_basic_map *isl_basic_map_from_multi_aff2( + __isl_take isl_multi_aff *maff, int rational); + +struct isl_mat; + +__isl_give isl_basic_set *isl_basic_set_preimage( + __isl_take isl_basic_set *bset, __isl_take isl_mat *mat); +__isl_give isl_set *isl_set_preimage( + __isl_take isl_set *set, __isl_take isl_mat *mat); + +__isl_give isl_basic_map *isl_basic_map_transform_dims( + __isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned first, + __isl_take isl_mat *trans); +__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); + +isl_bool isl_basic_map_contains_point(__isl_keep isl_basic_map *bmap, + __isl_keep isl_point *point); +isl_bool isl_set_contains_point(__isl_keep isl_set *set, + __isl_keep isl_point *point); + +isl_stat isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset, + unsigned first, unsigned n, int *signs); +isl_stat isl_set_foreach_orthant(__isl_keep isl_set *set, + isl_stat (*fn)(__isl_take isl_set *orthant, int *signs, void *user), + void *user); + +isl_bool isl_basic_set_eq_is_stride(__isl_keep isl_basic_set *bset, int i); + +int isl_basic_map_add_div_constraints_var(__isl_keep isl_basic_map *bmap, + unsigned pos, isl_int *div); +int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset, + unsigned pos, isl_int *div); +isl_bool isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap, + isl_int *constraint, unsigned div); +isl_bool isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset, + 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); +__isl_give isl_basic_map *isl_basic_map_expand_divs( + __isl_take isl_basic_set *bmap, __isl_take isl_mat *div, int *exp); + +int isl_basic_set_n_equality(__isl_keep isl_basic_set *bset); +int isl_basic_map_n_equality(__isl_keep isl_basic_map *bmap); +int isl_basic_set_n_inequality(__isl_keep isl_basic_set *bset); +int isl_basic_map_n_inequality(__isl_keep isl_basic_map *bmap); + +__isl_give isl_basic_map *isl_basic_map_mark_div_unknown( + __isl_take isl_basic_map *bmap, int div); +isl_bool isl_basic_map_div_is_marked_unknown(__isl_keep isl_basic_map *bmap, + int div); +isl_bool isl_basic_map_div_is_known(__isl_keep isl_basic_map *bmap, int div); +int isl_basic_set_first_unknown_div(__isl_keep isl_basic_set *bset); +int isl_basic_map_first_unknown_div(__isl_keep isl_basic_map *bmap); +isl_bool isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap); +isl_bool isl_map_divs_known(__isl_keep isl_map *map); +__isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset); +__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap); + +__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map, + __isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap)); + +isl_stat isl_map_check_named_params(__isl_keep isl_map *map); + +isl_bool isl_map_has_equal_params(__isl_keep isl_map *map1, + __isl_keep isl_map *map2); +isl_bool isl_basic_set_space_has_equal_params(__isl_keep isl_basic_set *bset, + __isl_keep isl_space *space); +isl_bool isl_set_space_has_equal_params(__isl_keep isl_set *set, + __isl_keep isl_space *space); +isl_bool isl_map_space_has_equal_params(__isl_keep isl_map *map, + __isl_keep isl_space *space); + +__isl_give isl_map *isl_map_align_params_map_map_and( + __isl_take isl_map *map1, __isl_take isl_map *map2, + __isl_give isl_map *(*fn)(__isl_take isl_map *map1, + __isl_take isl_map *map2)); +isl_bool isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1, + __isl_keep isl_map *map2, + isl_bool (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2)); + +__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs); + +__isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *context); + +isl_bool isl_map_compatible_range(__isl_keep isl_map *map, + __isl_keep isl_set *set); + +isl_bool isl_basic_map_plain_is_non_empty(__isl_keep isl_basic_map *bmap); +isl_bool isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap); + +isl_bool isl_map_is_set(__isl_keep isl_map *map); + +isl_bool isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset, + unsigned dim, isl_int *val); + +__isl_give isl_set *isl_set_plain_gist_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *context); +__isl_give isl_map *isl_map_plain_gist_basic_map(__isl_take isl_map *map, + __isl_take isl_basic_map *context); +__isl_give isl_map *isl_map_plain_gist(__isl_take isl_map *map, + __isl_take isl_map *context); + +__isl_give isl_basic_set *isl_basic_set_plain_affine_hull( + __isl_take isl_basic_set *bset); +__isl_give isl_basic_map *isl_basic_map_plain_affine_hull( + __isl_take isl_basic_map *bmap); + +isl_stat isl_basic_set_dim_residue_class(__isl_keep isl_basic_set *bset, + int pos, isl_int *modulo, isl_int *residue); +isl_stat isl_set_dim_residue_class(__isl_keep isl_set *set, + int pos, isl_int *modulo, isl_int *residue); + +__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned pos, isl_int value); +__isl_give isl_basic_map *isl_basic_map_fix(__isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned pos, isl_int value); +__isl_give isl_set *isl_set_fix(__isl_take isl_set *set, + enum isl_dim_type type, unsigned pos, isl_int value); +isl_bool isl_map_plain_is_fixed(__isl_keep isl_map *map, + enum isl_dim_type type, unsigned pos, isl_int *val); + +int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap, + int pos, int *div, int *ineq); + +__isl_give isl_basic_map *isl_basic_map_reduce_coefficients( + __isl_take isl_basic_map *bmap); + +__isl_give isl_basic_map *isl_basic_map_shift_div( + __isl_take isl_basic_map *bmap, int div, int pos, isl_int shift); + +__isl_give isl_basic_map_list *isl_map_get_basic_map_list( + __isl_keep isl_map *map); + +int isl_basic_set_count_upto(__isl_keep isl_basic_set *bset, + isl_int max, isl_int *count); +int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count); + +__isl_give isl_mat *isl_basic_set_extract_equalities( + __isl_keep isl_basic_set *bset); + +isl_bool isl_basic_map_equal_div_expr_part(__isl_keep isl_basic_map *bmap1, + int pos1, __isl_keep isl_basic_map *bmap2, int pos2, + unsigned first, unsigned n); +isl_bool isl_basic_map_equal_div_expr_except_constant( + __isl_keep isl_basic_map *bmap1, int pos1, + __isl_keep isl_basic_map *bmap2, int pos2); +__isl_give isl_basic_map *isl_basic_map_set_div_expr_constant_num_si_inplace( + __isl_take isl_basic_map *bmap, int div, int value); + +#endif Index: contrib/isl/isl_map_simplify.c =================================================================== --- /dev/null +++ contrib/isl/isl_map_simplify.c @@ -0,0 +1,5219 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2014-2015 INRIA Rocquencourt + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include "isl_equalities.h" +#include +#include +#include "isl_tab.h" +#include +#include +#include + +#include +#include +#include +#include + +static void swap_equality(struct isl_basic_map *bmap, int a, int b) +{ + isl_int *t = bmap->eq[a]; + bmap->eq[a] = bmap->eq[b]; + bmap->eq[b] = t; +} + +static void swap_inequality(struct isl_basic_map *bmap, int a, int b) +{ + if (a != b) { + isl_int *t = bmap->ineq[a]; + bmap->ineq[a] = bmap->ineq[b]; + bmap->ineq[b] = t; + } +} + +__isl_give isl_basic_map *isl_basic_map_normalize_constraints( + __isl_take isl_basic_map *bmap) +{ + int i; + isl_int gcd; + unsigned total = isl_basic_map_total_dim(bmap); + + if (!bmap) + return NULL; + + isl_int_init(gcd); + for (i = bmap->n_eq - 1; i >= 0; --i) { + isl_seq_gcd(bmap->eq[i]+1, total, &gcd); + if (isl_int_is_zero(gcd)) { + if (!isl_int_is_zero(bmap->eq[i][0])) { + bmap = isl_basic_map_set_to_empty(bmap); + break; + } + isl_basic_map_drop_equality(bmap, i); + continue; + } + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) + isl_int_gcd(gcd, gcd, bmap->eq[i][0]); + if (isl_int_is_one(gcd)) + continue; + if (!isl_int_is_divisible_by(bmap->eq[i][0], gcd)) { + bmap = isl_basic_map_set_to_empty(bmap); + break; + } + isl_seq_scale_down(bmap->eq[i], bmap->eq[i], gcd, 1+total); + } + + for (i = bmap->n_ineq - 1; i >= 0; --i) { + isl_seq_gcd(bmap->ineq[i]+1, total, &gcd); + if (isl_int_is_zero(gcd)) { + if (isl_int_is_neg(bmap->ineq[i][0])) { + bmap = isl_basic_map_set_to_empty(bmap); + break; + } + isl_basic_map_drop_inequality(bmap, i); + continue; + } + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) + isl_int_gcd(gcd, gcd, bmap->ineq[i][0]); + if (isl_int_is_one(gcd)) + continue; + isl_int_fdiv_q(bmap->ineq[i][0], bmap->ineq[i][0], gcd); + isl_seq_scale_down(bmap->ineq[i]+1, bmap->ineq[i]+1, gcd, total); + } + isl_int_clear(gcd); + + return bmap; +} + +__isl_give isl_basic_set *isl_basic_set_normalize_constraints( + __isl_take isl_basic_set *bset) +{ + isl_basic_map *bmap = bset_to_bmap(bset); + return bset_from_bmap(isl_basic_map_normalize_constraints(bmap)); +} + +/* Reduce the coefficient of the variable at position "pos" + * in integer division "div", such that it lies in the half-open + * interval (1/2,1/2], extracting any excess value from this integer division. + * "pos" is as determined by isl_basic_map_offset, i.e., pos == 0 + * corresponds to the constant term. + * + * That is, the integer division is of the form + * + * floor((... + (c * d + r) * x_pos + ...)/d) + * + * with -d < 2 * r <= d. + * Replace it by + * + * floor((... + r * x_pos + ...)/d) + c * x_pos + * + * If 2 * ((c * d + r) % d) <= d, then c = floor((c * d + r)/d). + * Otherwise, c = floor((c * d + r)/d) + 1. + * + * This is the same normalization that is performed by isl_aff_floor. + */ +static __isl_give isl_basic_map *reduce_coefficient_in_div( + __isl_take isl_basic_map *bmap, int div, int pos) +{ + isl_int shift; + int add_one; + + isl_int_init(shift); + isl_int_fdiv_r(shift, bmap->div[div][1 + pos], bmap->div[div][0]); + isl_int_mul_ui(shift, shift, 2); + add_one = isl_int_gt(shift, bmap->div[div][0]); + isl_int_fdiv_q(shift, bmap->div[div][1 + pos], bmap->div[div][0]); + if (add_one) + isl_int_add_ui(shift, shift, 1); + isl_int_neg(shift, shift); + bmap = isl_basic_map_shift_div(bmap, div, pos, shift); + isl_int_clear(shift); + + return bmap; +} + +/* Does the coefficient of the variable at position "pos" + * in integer division "div" need to be reduced? + * That is, does it lie outside the half-open interval (1/2,1/2]? + * The coefficient c/d lies outside this interval if abs(2 * c) >= d and + * 2 * c != d. + */ +static isl_bool needs_reduction(__isl_keep isl_basic_map *bmap, int div, + int pos) +{ + isl_bool r; + + if (isl_int_is_zero(bmap->div[div][1 + pos])) + return isl_bool_false; + + isl_int_mul_ui(bmap->div[div][1 + pos], bmap->div[div][1 + pos], 2); + r = isl_int_abs_ge(bmap->div[div][1 + pos], bmap->div[div][0]) && + !isl_int_eq(bmap->div[div][1 + pos], bmap->div[div][0]); + isl_int_divexact_ui(bmap->div[div][1 + pos], + bmap->div[div][1 + pos], 2); + + return r; +} + +/* Reduce the coefficients (including the constant term) of + * integer division "div", if needed. + * In particular, make sure all coefficients lie in + * the half-open interval (1/2,1/2]. + */ +static __isl_give isl_basic_map *reduce_div_coefficients_of_div( + __isl_take isl_basic_map *bmap, int div) +{ + int i; + unsigned total = 1 + isl_basic_map_total_dim(bmap); + + for (i = 0; i < total; ++i) { + isl_bool reduce; + + reduce = needs_reduction(bmap, div, i); + if (reduce < 0) + return isl_basic_map_free(bmap); + if (!reduce) + continue; + bmap = reduce_coefficient_in_div(bmap, div, i); + if (!bmap) + break; + } + + return bmap; +} + +/* Reduce the coefficients (including the constant term) of + * the known integer divisions, if needed + * In particular, make sure all coefficients lie in + * the half-open interval (1/2,1/2]. + */ +static __isl_give isl_basic_map *reduce_div_coefficients( + __isl_take isl_basic_map *bmap) +{ + int i; + + if (!bmap) + return NULL; + if (bmap->n_div == 0) + return bmap; + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + bmap = reduce_div_coefficients_of_div(bmap, i); + if (!bmap) + break; + } + + return bmap; +} + +/* Remove any common factor in numerator and denominator of the div expression, + * not taking into account the constant term. + * That is, if the div is of the form + * + * floor((a + m f(x))/(m d)) + * + * then replace it by + * + * floor((floor(a/m) + f(x))/d) + * + * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d + * and can therefore not influence the result of the floor. + */ +static void normalize_div_expression(__isl_keep isl_basic_map *bmap, int div) +{ + unsigned total = isl_basic_map_total_dim(bmap); + isl_ctx *ctx = bmap->ctx; + + if (isl_int_is_zero(bmap->div[div][0])) + return; + isl_seq_gcd(bmap->div[div] + 2, total, &ctx->normalize_gcd); + isl_int_gcd(ctx->normalize_gcd, ctx->normalize_gcd, bmap->div[div][0]); + if (isl_int_is_one(ctx->normalize_gcd)) + return; + isl_int_fdiv_q(bmap->div[div][1], bmap->div[div][1], + ctx->normalize_gcd); + isl_int_divexact(bmap->div[div][0], bmap->div[div][0], + ctx->normalize_gcd); + isl_seq_scale_down(bmap->div[div] + 2, bmap->div[div] + 2, + ctx->normalize_gcd, total); +} + +/* Remove any common factor in numerator and denominator of a div expression, + * not taking into account the constant term. + * That is, look for any div of the form + * + * floor((a + m f(x))/(m d)) + * + * and replace it by + * + * floor((floor(a/m) + f(x))/d) + * + * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d + * and can therefore not influence the result of the floor. + */ +static __isl_give isl_basic_map *normalize_div_expressions( + __isl_take isl_basic_map *bmap) +{ + int i; + + if (!bmap) + return NULL; + if (bmap->n_div == 0) + return bmap; + + for (i = 0; i < bmap->n_div; ++i) + normalize_div_expression(bmap, i); + + return bmap; +} + +/* Assumes divs have been ordered if keep_divs is set. + */ +static void eliminate_var_using_equality(struct isl_basic_map *bmap, + unsigned pos, isl_int *eq, int keep_divs, int *progress) +{ + unsigned total; + unsigned space_total; + int k; + int last_div; + + total = isl_basic_map_total_dim(bmap); + space_total = isl_space_dim(bmap->dim, isl_dim_all); + last_div = isl_seq_last_non_zero(eq + 1 + space_total, bmap->n_div); + for (k = 0; k < bmap->n_eq; ++k) { + if (bmap->eq[k] == eq) + continue; + if (isl_int_is_zero(bmap->eq[k][1+pos])) + continue; + if (progress) + *progress = 1; + isl_seq_elim(bmap->eq[k], eq, 1+pos, 1+total, NULL); + isl_seq_normalize(bmap->ctx, bmap->eq[k], 1 + total); + } + + for (k = 0; k < bmap->n_ineq; ++k) { + if (isl_int_is_zero(bmap->ineq[k][1+pos])) + continue; + if (progress) + *progress = 1; + isl_seq_elim(bmap->ineq[k], eq, 1+pos, 1+total, NULL); + isl_seq_normalize(bmap->ctx, bmap->ineq[k], 1 + total); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + } + + for (k = 0; k < bmap->n_div; ++k) { + if (isl_int_is_zero(bmap->div[k][0])) + continue; + if (isl_int_is_zero(bmap->div[k][1+1+pos])) + continue; + if (progress) + *progress = 1; + /* We need to be careful about circular definitions, + * so for now we just remove the definition of div k + * if the equality contains any divs. + * If keep_divs is set, then the divs have been ordered + * and we can keep the definition as long as the result + * is still ordered. + */ + if (last_div == -1 || (keep_divs && last_div < k)) { + isl_seq_elim(bmap->div[k]+1, eq, + 1+pos, 1+total, &bmap->div[k][0]); + normalize_div_expression(bmap, k); + } else + isl_seq_clr(bmap->div[k], 1 + total); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + } +} + +/* Assumes divs have been ordered if keep_divs is set. + */ +static __isl_give isl_basic_map *eliminate_div(__isl_take isl_basic_map *bmap, + isl_int *eq, unsigned div, int keep_divs) +{ + unsigned pos = isl_space_dim(bmap->dim, isl_dim_all) + div; + + eliminate_var_using_equality(bmap, pos, eq, keep_divs, NULL); + + bmap = isl_basic_map_drop_div(bmap, div); + + return bmap; +} + +/* Check if elimination of div "div" using equality "eq" would not + * result in a div depending on a later div. + */ +static isl_bool ok_to_eliminate_div(__isl_keep isl_basic_map *bmap, isl_int *eq, + unsigned div) +{ + int k; + int last_div; + unsigned space_total = isl_space_dim(bmap->dim, isl_dim_all); + unsigned pos = space_total + div; + + last_div = isl_seq_last_non_zero(eq + 1 + space_total, bmap->n_div); + if (last_div < 0 || last_div <= div) + return isl_bool_true; + + for (k = 0; k <= last_div; ++k) { + if (isl_int_is_zero(bmap->div[k][0])) + continue; + if (!isl_int_is_zero(bmap->div[k][1 + 1 + pos])) + return isl_bool_false; + } + + return isl_bool_true; +} + +/* Eliminate divs based on equalities + */ +static __isl_give isl_basic_map *eliminate_divs_eq( + __isl_take isl_basic_map *bmap, int *progress) +{ + int d; + int i; + int modified = 0; + unsigned off; + + bmap = isl_basic_map_order_divs(bmap); + + if (!bmap) + return NULL; + + off = 1 + isl_space_dim(bmap->dim, isl_dim_all); + + for (d = bmap->n_div - 1; d >= 0 ; --d) { + for (i = 0; i < bmap->n_eq; ++i) { + isl_bool ok; + + if (!isl_int_is_one(bmap->eq[i][off + d]) && + !isl_int_is_negone(bmap->eq[i][off + d])) + continue; + ok = ok_to_eliminate_div(bmap, bmap->eq[i], d); + if (ok < 0) + return isl_basic_map_free(bmap); + if (!ok) + continue; + modified = 1; + *progress = 1; + bmap = eliminate_div(bmap, bmap->eq[i], d, 1); + if (isl_basic_map_drop_equality(bmap, i) < 0) + return isl_basic_map_free(bmap); + break; + } + } + if (modified) + return eliminate_divs_eq(bmap, progress); + return bmap; +} + +/* Eliminate divs based on inequalities + */ +static __isl_give isl_basic_map *eliminate_divs_ineq( + __isl_take isl_basic_map *bmap, int *progress) +{ + int d; + int i; + unsigned off; + struct isl_ctx *ctx; + + if (!bmap) + return NULL; + + ctx = bmap->ctx; + off = 1 + isl_space_dim(bmap->dim, isl_dim_all); + + for (d = bmap->n_div - 1; d >= 0 ; --d) { + for (i = 0; i < bmap->n_eq; ++i) + if (!isl_int_is_zero(bmap->eq[i][off + d])) + break; + if (i < bmap->n_eq) + continue; + for (i = 0; i < bmap->n_ineq; ++i) + if (isl_int_abs_gt(bmap->ineq[i][off + d], ctx->one)) + break; + if (i < bmap->n_ineq) + continue; + *progress = 1; + bmap = isl_basic_map_eliminate_vars(bmap, (off-1)+d, 1); + if (!bmap || ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) + break; + bmap = isl_basic_map_drop_div(bmap, d); + if (!bmap) + break; + } + return bmap; +} + +/* Does the equality constraint at position "eq" in "bmap" involve + * any local variables in the range [first, first + n) + * that are not marked as having an explicit representation? + */ +static isl_bool bmap_eq_involves_unknown_divs(__isl_keep isl_basic_map *bmap, + int eq, unsigned first, unsigned n) +{ + unsigned o_div; + int i; + + if (!bmap) + return isl_bool_error; + + o_div = isl_basic_map_offset(bmap, isl_dim_div); + for (i = 0; i < n; ++i) { + isl_bool unknown; + + if (isl_int_is_zero(bmap->eq[eq][o_div + first + i])) + continue; + unknown = isl_basic_map_div_is_marked_unknown(bmap, first + i); + if (unknown < 0) + return isl_bool_error; + if (unknown) + return isl_bool_true; + } + + return isl_bool_false; +} + +/* The last local variable involved in the equality constraint + * at position "eq" in "bmap" is the local variable at position "div". + * It can therefore be used to extract an explicit representation + * for that variable. + * Do so unless the local variable already has an explicit representation or + * the explicit representation would involve any other local variables + * that in turn do not have an explicit representation. + * An equality constraint involving local variables without an explicit + * representation can be used in isl_basic_map_drop_redundant_divs + * to separate out an independent local variable. Introducing + * an explicit representation here would block this transformation, + * while the partial explicit representation in itself is not very useful. + * Set *progress if anything is changed. + * + * The equality constraint is of the form + * + * f(x) + n e >= 0 + * + * with n a positive number. The explicit representation derived from + * this constraint is + * + * floor((-f(x))/n) + */ +static __isl_give isl_basic_map *set_div_from_eq(__isl_take isl_basic_map *bmap, + int div, int eq, int *progress) +{ + unsigned total, o_div; + isl_bool involves; + + if (!bmap) + return NULL; + + if (!isl_int_is_zero(bmap->div[div][0])) + return bmap; + + involves = bmap_eq_involves_unknown_divs(bmap, eq, 0, div); + if (involves < 0) + return isl_basic_map_free(bmap); + if (involves) + return bmap; + + total = isl_basic_map_dim(bmap, isl_dim_all); + o_div = isl_basic_map_offset(bmap, isl_dim_div); + isl_seq_neg(bmap->div[div] + 1, bmap->eq[eq], 1 + total); + isl_int_set_si(bmap->div[div][1 + o_div + div], 0); + isl_int_set(bmap->div[div][0], bmap->eq[eq][o_div + div]); + if (progress) + *progress = 1; + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + + return bmap; +} + +__isl_give isl_basic_map *isl_basic_map_gauss(__isl_take isl_basic_map *bmap, + int *progress) +{ + int k; + int done; + int last_var; + unsigned total_var; + unsigned total; + + bmap = isl_basic_map_order_divs(bmap); + + if (!bmap) + return NULL; + + total = isl_basic_map_total_dim(bmap); + total_var = total - bmap->n_div; + + last_var = total - 1; + for (done = 0; done < bmap->n_eq; ++done) { + for (; last_var >= 0; --last_var) { + for (k = done; k < bmap->n_eq; ++k) + if (!isl_int_is_zero(bmap->eq[k][1+last_var])) + break; + if (k < bmap->n_eq) + break; + } + if (last_var < 0) + break; + if (k != done) + swap_equality(bmap, k, done); + if (isl_int_is_neg(bmap->eq[done][1+last_var])) + isl_seq_neg(bmap->eq[done], bmap->eq[done], 1+total); + + eliminate_var_using_equality(bmap, last_var, bmap->eq[done], 1, + progress); + + if (last_var >= total_var) + bmap = set_div_from_eq(bmap, last_var - total_var, + done, progress); + if (!bmap) + return NULL; + } + if (done == bmap->n_eq) + return bmap; + for (k = done; k < bmap->n_eq; ++k) { + if (isl_int_is_zero(bmap->eq[k][0])) + continue; + return isl_basic_map_set_to_empty(bmap); + } + isl_basic_map_free_equality(bmap, bmap->n_eq-done); + return bmap; +} + +__isl_give isl_basic_set *isl_basic_set_gauss( + __isl_take isl_basic_set *bset, int *progress) +{ + return bset_from_bmap(isl_basic_map_gauss(bset_to_bmap(bset), + progress)); +} + + +static unsigned int round_up(unsigned int v) +{ + int old_v = v; + + while (v) { + old_v = v; + v ^= v & -v; + } + return old_v << 1; +} + +/* Hash table of inequalities in a basic map. + * "index" is an array of addresses of inequalities in the basic map, some + * of which are NULL. The inequalities are hashed on the coefficients + * except the constant term. + * "size" is the number of elements in the array and is always a power of two + * "bits" is the number of bits need to represent an index into the array. + * "total" is the total dimension of the basic map. + */ +struct isl_constraint_index { + unsigned int size; + int bits; + isl_int ***index; + unsigned total; +}; + +/* Fill in the "ci" data structure for holding the inequalities of "bmap". + */ +static isl_stat create_constraint_index(struct isl_constraint_index *ci, + __isl_keep isl_basic_map *bmap) +{ + isl_ctx *ctx; + + ci->index = NULL; + if (!bmap) + return isl_stat_error; + ci->total = isl_basic_set_total_dim(bmap); + if (bmap->n_ineq == 0) + return isl_stat_ok; + ci->size = round_up(4 * (bmap->n_ineq + 1) / 3 - 1); + ci->bits = ffs(ci->size) - 1; + ctx = isl_basic_map_get_ctx(bmap); + ci->index = isl_calloc_array(ctx, isl_int **, ci->size); + if (!ci->index) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Free the memory allocated by create_constraint_index. + */ +static void constraint_index_free(struct isl_constraint_index *ci) +{ + free(ci->index); +} + +/* Return the position in ci->index that contains the address of + * an inequality that is equal to *ineq up to the constant term, + * provided this address is not identical to "ineq". + * If there is no such inequality, then return the position where + * such an inequality should be inserted. + */ +static int hash_index_ineq(struct isl_constraint_index *ci, isl_int **ineq) +{ + int h; + uint32_t hash = isl_seq_get_hash_bits((*ineq) + 1, ci->total, ci->bits); + for (h = hash; ci->index[h]; h = (h+1) % ci->size) + if (ineq != ci->index[h] && + isl_seq_eq((*ineq) + 1, ci->index[h][0]+1, ci->total)) + break; + return h; +} + +/* Return the position in ci->index that contains the address of + * an inequality that is equal to the k'th inequality of "bmap" + * up to the constant term, provided it does not point to the very + * same inequality. + * If there is no such inequality, then return the position where + * such an inequality should be inserted. + */ +static int hash_index(struct isl_constraint_index *ci, + __isl_keep isl_basic_map *bmap, int k) +{ + return hash_index_ineq(ci, &bmap->ineq[k]); +} + +static int set_hash_index(struct isl_constraint_index *ci, + __isl_keep isl_basic_set *bset, int k) +{ + return hash_index(ci, bset, k); +} + +/* Fill in the "ci" data structure with the inequalities of "bset". + */ +static isl_stat setup_constraint_index(struct isl_constraint_index *ci, + __isl_keep isl_basic_set *bset) +{ + int k, h; + + if (create_constraint_index(ci, bset) < 0) + return isl_stat_error; + + for (k = 0; k < bset->n_ineq; ++k) { + h = set_hash_index(ci, bset, k); + ci->index[h] = &bset->ineq[k]; + } + + return isl_stat_ok; +} + +/* Is the inequality ineq (obviously) redundant with respect + * to the constraints in "ci"? + * + * Look for an inequality in "ci" with the same coefficients and then + * check if the contant term of "ineq" is greater than or equal + * to the constant term of that inequality. If so, "ineq" is clearly + * redundant. + * + * Note that hash_index_ineq ignores a stored constraint if it has + * the same address as the passed inequality. It is ok to pass + * the address of a local variable here since it will never be + * the same as the address of a constraint in "ci". + */ +static isl_bool constraint_index_is_redundant(struct isl_constraint_index *ci, + isl_int *ineq) +{ + int h; + + h = hash_index_ineq(ci, &ineq); + if (!ci->index[h]) + return isl_bool_false; + return isl_int_ge(ineq[0], (*ci->index[h])[0]); +} + +/* If we can eliminate more than one div, then we need to make + * sure we do it from last div to first div, in order not to + * change the position of the other divs that still need to + * be removed. + */ +static __isl_give isl_basic_map *remove_duplicate_divs( + __isl_take isl_basic_map *bmap, int *progress) +{ + unsigned int size; + int *index; + int *elim_for; + int k, l, h; + int bits; + struct isl_blk eq; + unsigned total_var; + unsigned total; + struct isl_ctx *ctx; + + bmap = isl_basic_map_order_divs(bmap); + if (!bmap || bmap->n_div <= 1) + return bmap; + + total_var = isl_space_dim(bmap->dim, isl_dim_all); + total = total_var + bmap->n_div; + + ctx = bmap->ctx; + for (k = bmap->n_div - 1; k >= 0; --k) + if (!isl_int_is_zero(bmap->div[k][0])) + break; + if (k <= 0) + return bmap; + + size = round_up(4 * bmap->n_div / 3 - 1); + if (size == 0) + return bmap; + elim_for = isl_calloc_array(ctx, int, bmap->n_div); + bits = ffs(size) - 1; + index = isl_calloc_array(ctx, int, size); + if (!elim_for || !index) + goto out; + eq = isl_blk_alloc(ctx, 1+total); + if (isl_blk_is_error(eq)) + goto out; + + isl_seq_clr(eq.data, 1+total); + index[isl_seq_get_hash_bits(bmap->div[k], 2+total, bits)] = k + 1; + for (--k; k >= 0; --k) { + uint32_t hash; + + if (isl_int_is_zero(bmap->div[k][0])) + continue; + + hash = isl_seq_get_hash_bits(bmap->div[k], 2+total, bits); + for (h = hash; index[h]; h = (h+1) % size) + if (isl_seq_eq(bmap->div[k], + bmap->div[index[h]-1], 2+total)) + break; + if (index[h]) { + *progress = 1; + l = index[h] - 1; + elim_for[l] = k + 1; + } + index[h] = k+1; + } + for (l = bmap->n_div - 1; l >= 0; --l) { + if (!elim_for[l]) + continue; + k = elim_for[l] - 1; + isl_int_set_si(eq.data[1+total_var+k], -1); + isl_int_set_si(eq.data[1+total_var+l], 1); + bmap = eliminate_div(bmap, eq.data, l, 1); + if (!bmap) + break; + isl_int_set_si(eq.data[1+total_var+k], 0); + isl_int_set_si(eq.data[1+total_var+l], 0); + } + + isl_blk_free(ctx, eq); +out: + free(index); + free(elim_for); + return bmap; +} + +static int n_pure_div_eq(struct isl_basic_map *bmap) +{ + int i, j; + unsigned total; + + total = isl_space_dim(bmap->dim, isl_dim_all); + for (i = 0, j = bmap->n_div-1; i < bmap->n_eq; ++i) { + while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j])) + --j; + if (j < 0) + break; + if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total, j) != -1) + return 0; + } + return i; +} + +/* Normalize divs that appear in equalities. + * + * In particular, we assume that bmap contains some equalities + * of the form + * + * a x = m * e_i + * + * and we want to replace the set of e_i by a minimal set and + * such that the new e_i have a canonical representation in terms + * of the vector x. + * If any of the equalities involves more than one divs, then + * we currently simply bail out. + * + * Let us first additionally assume that all equalities involve + * a div. The equalities then express modulo constraints on the + * remaining variables and we can use "parameter compression" + * to find a minimal set of constraints. The result is a transformation + * + * x = T(x') = x_0 + G x' + * + * with G a lower-triangular matrix with all elements below the diagonal + * non-negative and smaller than the diagonal element on the same row. + * We first normalize x_0 by making the same property hold in the affine + * T matrix. + * The rows i of G with a 1 on the diagonal do not impose any modulo + * constraint and simply express x_i = x'_i. + * For each of the remaining rows i, we introduce a div and a corresponding + * equality. In particular + * + * g_ii e_j = x_i - g_i(x') + * + * where each x'_k is replaced either by x_k (if g_kk = 1) or the + * corresponding div (if g_kk != 1). + * + * If there are any equalities not involving any div, then we + * first apply a variable compression on the variables x: + * + * x = C x'' x'' = C_2 x + * + * and perform the above parameter compression on A C instead of on A. + * The resulting compression is then of the form + * + * x'' = T(x') = x_0 + G x' + * + * and in constructing the new divs and the corresponding equalities, + * we have to replace each x'', i.e., the x'_k with (g_kk = 1), + * by the corresponding row from C_2. + */ +static __isl_give isl_basic_map *normalize_divs(__isl_take isl_basic_map *bmap, + int *progress) +{ + int i, j, k; + int total; + int div_eq; + struct isl_mat *B; + struct isl_vec *d; + struct isl_mat *T = NULL; + struct isl_mat *C = NULL; + struct isl_mat *C2 = NULL; + isl_int v; + int *pos = NULL; + int dropped, needed; + + if (!bmap) + return NULL; + + if (bmap->n_div == 0) + return bmap; + + if (bmap->n_eq == 0) + return bmap; + + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS)) + return bmap; + + total = isl_space_dim(bmap->dim, isl_dim_all); + div_eq = n_pure_div_eq(bmap); + if (div_eq == 0) + return bmap; + + if (div_eq < bmap->n_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) + goto error; + if (C->n_col == 0) { + bmap = isl_basic_map_set_to_empty(bmap); + isl_mat_free(C); + isl_mat_free(C2); + goto done; + } + } + + d = isl_vec_alloc(bmap->ctx, div_eq); + if (!d) + goto error; + for (i = 0, j = bmap->n_div-1; i < div_eq; ++i) { + while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j])) + --j; + isl_int_set(d->block.data[i], bmap->eq[i][1 + total + j]); + } + B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, 0, div_eq, 0, 1 + total); + + if (C) { + B = isl_mat_product(B, C); + C = NULL; + } + + T = isl_mat_parameter_compression(B, d); + if (!T) + goto error; + if (T->n_col == 0) { + bmap = isl_basic_map_set_to_empty(bmap); + isl_mat_free(C2); + isl_mat_free(T); + goto done; + } + isl_int_init(v); + for (i = 0; i < T->n_row - 1; ++i) { + isl_int_fdiv_q(v, T->row[1 + i][0], T->row[1 + i][1 + i]); + if (isl_int_is_zero(v)) + continue; + isl_mat_col_submul(T, 0, v, 1 + i); + } + isl_int_clear(v); + pos = isl_alloc_array(bmap->ctx, int, T->n_row); + if (!pos) + goto error; + /* We have to be careful because dropping equalities may reorder them */ + dropped = 0; + for (j = bmap->n_div - 1; j >= 0; --j) { + for (i = 0; i < bmap->n_eq; ++i) + if (!isl_int_is_zero(bmap->eq[i][1 + total + j])) + break; + if (i < bmap->n_eq) { + bmap = isl_basic_map_drop_div(bmap, j); + isl_basic_map_drop_equality(bmap, i); + ++dropped; + } + } + pos[0] = 0; + needed = 0; + for (i = 1; i < T->n_row; ++i) { + if (isl_int_is_one(T->row[i][i])) + pos[i] = i; + else + needed++; + } + if (needed > dropped) { + bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim), + needed, needed, 0); + if (!bmap) + goto error; + } + for (i = 1; i < T->n_row; ++i) { + if (isl_int_is_one(T->row[i][i])) + continue; + k = isl_basic_map_alloc_div(bmap); + pos[i] = 1 + total + k; + isl_seq_clr(bmap->div[k] + 1, 1 + total + bmap->n_div); + isl_int_set(bmap->div[k][0], T->row[i][i]); + if (C2) + isl_seq_cpy(bmap->div[k] + 1, C2->row[i], 1 + total); + else + isl_int_set_si(bmap->div[k][1 + i], 1); + for (j = 0; j < i; ++j) { + if (isl_int_is_zero(T->row[i][j])) + continue; + if (pos[j] < T->n_row && C2) + isl_seq_submul(bmap->div[k] + 1, T->row[i][j], + C2->row[pos[j]], 1 + total); + else + isl_int_neg(bmap->div[k][1 + pos[j]], + T->row[i][j]); + } + j = isl_basic_map_alloc_equality(bmap); + isl_seq_neg(bmap->eq[j], bmap->div[k]+1, 1+total+bmap->n_div); + isl_int_set(bmap->eq[j][pos[i]], bmap->div[k][0]); + } + free(pos); + isl_mat_free(C2); + isl_mat_free(T); + + if (progress) + *progress = 1; +done: + ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); + + return bmap; +error: + free(pos); + isl_mat_free(C); + isl_mat_free(C2); + isl_mat_free(T); + return bmap; +} + +static __isl_give isl_basic_map *set_div_from_lower_bound( + __isl_take isl_basic_map *bmap, int div, int ineq) +{ + unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all); + + isl_seq_neg(bmap->div[div] + 1, bmap->ineq[ineq], total + bmap->n_div); + isl_int_set(bmap->div[div][0], bmap->ineq[ineq][total + div]); + isl_int_add(bmap->div[div][1], bmap->div[div][1], bmap->div[div][0]); + isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1); + isl_int_set_si(bmap->div[div][1 + total + div], 0); + + return bmap; +} + +/* Check whether it is ok to define a div based on an inequality. + * To avoid the introduction of circular definitions of divs, we + * do not allow such a definition if the resulting expression would refer to + * any other undefined divs or if any known div is defined in + * terms of the unknown div. + */ +static isl_bool ok_to_set_div_from_bound(__isl_keep isl_basic_map *bmap, + int div, int ineq) +{ + int j; + unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all); + + /* Not defined in terms of unknown divs */ + for (j = 0; j < bmap->n_div; ++j) { + if (div == j) + continue; + if (isl_int_is_zero(bmap->ineq[ineq][total + j])) + continue; + if (isl_int_is_zero(bmap->div[j][0])) + return isl_bool_false; + } + + /* No other div defined in terms of this one => avoid loops */ + for (j = 0; j < bmap->n_div; ++j) { + if (div == j) + continue; + if (isl_int_is_zero(bmap->div[j][0])) + continue; + if (!isl_int_is_zero(bmap->div[j][1 + total + div])) + return isl_bool_false; + } + + return isl_bool_true; +} + +/* Would an expression for div "div" based on inequality "ineq" of "bmap" + * be a better expression than the current one? + * + * If we do not have any expression yet, then any expression would be better. + * Otherwise we check if the last variable involved in the inequality + * (disregarding the div that it would define) is in an earlier position + * than the last variable involved in the current div expression. + */ +static isl_bool better_div_constraint(__isl_keep isl_basic_map *bmap, + int div, int ineq) +{ + unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all); + int last_div; + int last_ineq; + + if (isl_int_is_zero(bmap->div[div][0])) + return isl_bool_true; + + if (isl_seq_last_non_zero(bmap->ineq[ineq] + total + div + 1, + bmap->n_div - (div + 1)) >= 0) + return isl_bool_false; + + last_ineq = isl_seq_last_non_zero(bmap->ineq[ineq], total + div); + last_div = isl_seq_last_non_zero(bmap->div[div] + 1, + total + bmap->n_div); + + return last_ineq < last_div; +} + +/* Given two constraints "k" and "l" that are opposite to each other, + * except for the constant term, check if we can use them + * to obtain an expression for one of the hitherto unknown divs or + * a "better" expression for a div for which we already have an expression. + * "sum" is the sum of the constant terms of the constraints. + * If this sum is strictly smaller than the coefficient of one + * of the divs, then this pair can be used define the div. + * To avoid the introduction of circular definitions of divs, we + * do not use the pair if the resulting expression would refer to + * any other undefined divs or if any known div is defined in + * terms of the unknown div. + */ +static __isl_give isl_basic_map *check_for_div_constraints( + __isl_take isl_basic_map *bmap, int k, int l, isl_int sum, + int *progress) +{ + int i; + unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all); + + for (i = 0; i < bmap->n_div; ++i) { + isl_bool set_div; + + if (isl_int_is_zero(bmap->ineq[k][total + i])) + continue; + if (isl_int_abs_ge(sum, bmap->ineq[k][total + i])) + continue; + set_div = better_div_constraint(bmap, i, k); + if (set_div >= 0 && set_div) + set_div = ok_to_set_div_from_bound(bmap, i, k); + if (set_div < 0) + return isl_basic_map_free(bmap); + if (!set_div) + break; + if (isl_int_is_pos(bmap->ineq[k][total + i])) + bmap = set_div_from_lower_bound(bmap, i, k); + else + bmap = set_div_from_lower_bound(bmap, i, l); + if (progress) + *progress = 1; + break; + } + return bmap; +} + +__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints( + __isl_take isl_basic_map *bmap, int *progress, int detect_divs) +{ + struct isl_constraint_index ci; + int k, l, h; + unsigned total = isl_basic_map_total_dim(bmap); + isl_int sum; + + if (!bmap || bmap->n_ineq <= 1) + return bmap; + + if (create_constraint_index(&ci, bmap) < 0) + return bmap; + + h = isl_seq_get_hash_bits(bmap->ineq[0] + 1, total, ci.bits); + ci.index[h] = &bmap->ineq[0]; + for (k = 1; k < bmap->n_ineq; ++k) { + h = hash_index(&ci, bmap, k); + if (!ci.index[h]) { + ci.index[h] = &bmap->ineq[k]; + continue; + } + if (progress) + *progress = 1; + l = ci.index[h] - &bmap->ineq[0]; + if (isl_int_lt(bmap->ineq[k][0], bmap->ineq[l][0])) + swap_inequality(bmap, k, l); + isl_basic_map_drop_inequality(bmap, k); + --k; + } + isl_int_init(sum); + for (k = 0; k < bmap->n_ineq-1; ++k) { + isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total); + h = hash_index(&ci, bmap, k); + isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total); + if (!ci.index[h]) + continue; + l = ci.index[h] - &bmap->ineq[0]; + isl_int_add(sum, bmap->ineq[k][0], bmap->ineq[l][0]); + if (isl_int_is_pos(sum)) { + if (detect_divs) + bmap = check_for_div_constraints(bmap, k, l, + sum, progress); + continue; + } + if (isl_int_is_zero(sum)) { + /* We need to break out of the loop after these + * changes since the contents of the hash + * will no longer be valid. + * Plus, we probably we want to regauss first. + */ + if (progress) + *progress = 1; + isl_basic_map_drop_inequality(bmap, l); + isl_basic_map_inequality_to_equality(bmap, k); + } else + bmap = isl_basic_map_set_to_empty(bmap); + break; + } + isl_int_clear(sum); + + constraint_index_free(&ci); + return bmap; +} + +/* Detect all pairs of inequalities that form an equality. + * + * isl_basic_map_remove_duplicate_constraints detects at most one such pair. + * Call it repeatedly while it is making progress. + */ +__isl_give isl_basic_map *isl_basic_map_detect_inequality_pairs( + __isl_take isl_basic_map *bmap, int *progress) +{ + int duplicate; + + do { + duplicate = 0; + bmap = isl_basic_map_remove_duplicate_constraints(bmap, + &duplicate, 0); + if (progress && duplicate) + *progress = 1; + } while (duplicate); + + return bmap; +} + +/* Eliminate knowns divs from constraints where they appear with + * a (positive or negative) unit coefficient. + * + * That is, replace + * + * floor(e/m) + f >= 0 + * + * by + * + * e + m f >= 0 + * + * and + * + * -floor(e/m) + f >= 0 + * + * by + * + * -e + m f + m - 1 >= 0 + * + * The first conversion is valid because floor(e/m) >= -f is equivalent + * to e/m >= -f because -f is an integral expression. + * The second conversion follows from the fact that + * + * -floor(e/m) = ceil(-e/m) = floor((-e + m - 1)/m) + * + * + * Note that one of the div constraints may have been eliminated + * due to being redundant with respect to the constraint that is + * being modified by this function. The modified constraint may + * no longer imply this div constraint, so we add it back to make + * sure we do not lose any information. + * + * We skip integral divs, i.e., those with denominator 1, as we would + * risk eliminating the div from the div constraints. We do not need + * to handle those divs here anyway since the div constraints will turn + * out to form an equality and this equality can then be used to eliminate + * the div from all constraints. + */ +static __isl_give isl_basic_map *eliminate_unit_divs( + __isl_take isl_basic_map *bmap, int *progress) +{ + int i, j; + isl_ctx *ctx; + unsigned total; + + if (!bmap) + return NULL; + + ctx = isl_basic_map_get_ctx(bmap); + total = 1 + isl_space_dim(bmap->dim, isl_dim_all); + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_int_is_one(bmap->div[i][0])) + continue; + for (j = 0; j < bmap->n_ineq; ++j) { + int s; + + if (!isl_int_is_one(bmap->ineq[j][total + i]) && + !isl_int_is_negone(bmap->ineq[j][total + i])) + continue; + + *progress = 1; + + s = isl_int_sgn(bmap->ineq[j][total + i]); + isl_int_set_si(bmap->ineq[j][total + i], 0); + if (s < 0) + isl_seq_combine(bmap->ineq[j], + ctx->negone, bmap->div[i] + 1, + bmap->div[i][0], bmap->ineq[j], + total + bmap->n_div); + else + isl_seq_combine(bmap->ineq[j], + ctx->one, bmap->div[i] + 1, + bmap->div[i][0], bmap->ineq[j], + total + bmap->n_div); + if (s < 0) { + isl_int_add(bmap->ineq[j][0], + bmap->ineq[j][0], bmap->div[i][0]); + isl_int_sub_ui(bmap->ineq[j][0], + bmap->ineq[j][0], 1); + } + + bmap = isl_basic_map_extend_constraints(bmap, 0, 1); + if (isl_basic_map_add_div_constraint(bmap, i, s) < 0) + return isl_basic_map_free(bmap); + } + } + + return bmap; +} + +__isl_give isl_basic_map *isl_basic_map_simplify(__isl_take isl_basic_map *bmap) +{ + int progress = 1; + if (!bmap) + return NULL; + while (progress) { + isl_bool empty; + + progress = 0; + empty = isl_basic_map_plain_is_empty(bmap); + if (empty < 0) + return isl_basic_map_free(bmap); + if (empty) + break; + bmap = isl_basic_map_normalize_constraints(bmap); + bmap = reduce_div_coefficients(bmap); + bmap = normalize_div_expressions(bmap); + bmap = remove_duplicate_divs(bmap, &progress); + bmap = eliminate_unit_divs(bmap, &progress); + bmap = eliminate_divs_eq(bmap, &progress); + bmap = eliminate_divs_ineq(bmap, &progress); + bmap = isl_basic_map_gauss(bmap, &progress); + /* requires equalities in normal form */ + bmap = normalize_divs(bmap, &progress); + bmap = isl_basic_map_remove_duplicate_constraints(bmap, + &progress, 1); + if (bmap && progress) + ISL_F_CLR(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS); + } + return bmap; +} + +struct isl_basic_set *isl_basic_set_simplify(struct isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_simplify(bset_to_bmap(bset))); +} + + +isl_bool isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap, + isl_int *constraint, unsigned div) +{ + unsigned pos; + + if (!bmap) + return isl_bool_error; + + pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div; + + if (isl_int_eq(constraint[pos], bmap->div[div][0])) { + int neg; + isl_int_sub(bmap->div[div][1], + bmap->div[div][1], bmap->div[div][0]); + isl_int_add_ui(bmap->div[div][1], bmap->div[div][1], 1); + neg = isl_seq_is_neg(constraint, bmap->div[div]+1, pos); + isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1); + isl_int_add(bmap->div[div][1], + bmap->div[div][1], bmap->div[div][0]); + if (!neg) + return isl_bool_false; + if (isl_seq_first_non_zero(constraint+pos+1, + bmap->n_div-div-1) != -1) + return isl_bool_false; + } else if (isl_int_abs_eq(constraint[pos], bmap->div[div][0])) { + if (!isl_seq_eq(constraint, bmap->div[div]+1, pos)) + return isl_bool_false; + if (isl_seq_first_non_zero(constraint+pos+1, + bmap->n_div-div-1) != -1) + return isl_bool_false; + } else + return isl_bool_false; + + return isl_bool_true; +} + +isl_bool isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset, + isl_int *constraint, unsigned div) +{ + return isl_basic_map_is_div_constraint(bset, constraint, div); +} + + +/* If the only constraints a div d=floor(f/m) + * appears in are its two defining constraints + * + * f - m d >=0 + * -(f - (m - 1)) + m d >= 0 + * + * then it can safely be removed. + */ +static isl_bool div_is_redundant(__isl_keep isl_basic_map *bmap, int div) +{ + int i; + unsigned pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div; + + for (i = 0; i < bmap->n_eq; ++i) + if (!isl_int_is_zero(bmap->eq[i][pos])) + return isl_bool_false; + + for (i = 0; i < bmap->n_ineq; ++i) { + isl_bool red; + + if (isl_int_is_zero(bmap->ineq[i][pos])) + continue; + red = isl_basic_map_is_div_constraint(bmap, bmap->ineq[i], div); + if (red < 0 || !red) + return red; + } + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (!isl_int_is_zero(bmap->div[i][1+pos])) + return isl_bool_false; + } + + return isl_bool_true; +} + +/* + * Remove divs that don't occur in any of the constraints or other divs. + * These can arise when dropping constraints from a basic map or + * when the divs of a basic map have been temporarily aligned + * with the divs of another basic map. + */ +static __isl_give isl_basic_map *remove_redundant_divs( + __isl_take isl_basic_map *bmap) +{ + int i; + + if (!bmap) + return NULL; + + for (i = bmap->n_div-1; i >= 0; --i) { + isl_bool redundant; + + redundant = div_is_redundant(bmap, i); + if (redundant < 0) + return isl_basic_map_free(bmap); + if (!redundant) + continue; + bmap = isl_basic_map_drop_div(bmap, i); + } + return bmap; +} + +/* Mark "bmap" as final, without checking for obviously redundant + * integer divisions. This function should be used when "bmap" + * is known not to involve any such integer divisions. + */ +__isl_give isl_basic_map *isl_basic_map_mark_final( + __isl_take isl_basic_map *bmap) +{ + if (!bmap) + return NULL; + ISL_F_SET(bmap, ISL_BASIC_SET_FINAL); + return bmap; +} + +/* Mark "bmap" as final, after removing obviously redundant integer divisions. + */ +__isl_give isl_basic_map *isl_basic_map_finalize(__isl_take isl_basic_map *bmap) +{ + bmap = remove_redundant_divs(bmap); + bmap = isl_basic_map_mark_final(bmap); + return bmap; +} + +struct isl_basic_set *isl_basic_set_finalize(struct isl_basic_set *bset) +{ + return bset_from_bmap(isl_basic_map_finalize(bset_to_bmap(bset))); +} + +/* Remove definition of any div that is defined in terms of the given variable. + * The div itself is not removed. Functions such as + * eliminate_divs_ineq depend on the other divs remaining in place. + */ +static __isl_give isl_basic_map *remove_dependent_vars( + __isl_take isl_basic_map *bmap, int pos) +{ + int i; + + if (!bmap) + return NULL; + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_int_is_zero(bmap->div[i][1+1+pos])) + continue; + bmap = isl_basic_map_mark_div_unknown(bmap, i); + if (!bmap) + return NULL; + } + return bmap; +} + +/* Eliminate the specified variables from the constraints using + * Fourier-Motzkin. The variables themselves are not removed. + */ +__isl_give isl_basic_map *isl_basic_map_eliminate_vars( + __isl_take isl_basic_map *bmap, unsigned pos, unsigned n) +{ + int d; + int i, j, k; + unsigned total; + int need_gauss = 0; + + if (n == 0) + return bmap; + if (!bmap) + return NULL; + total = isl_basic_map_total_dim(bmap); + + bmap = isl_basic_map_cow(bmap); + for (d = pos + n - 1; d >= 0 && d >= pos; --d) + bmap = remove_dependent_vars(bmap, d); + if (!bmap) + return NULL; + + for (d = pos + n - 1; + d >= 0 && d >= total - bmap->n_div && d >= pos; --d) + isl_seq_clr(bmap->div[d-(total-bmap->n_div)], 2+total); + for (d = pos + n - 1; d >= 0 && d >= pos; --d) { + int n_lower, n_upper; + if (!bmap) + return NULL; + for (i = 0; i < bmap->n_eq; ++i) { + if (isl_int_is_zero(bmap->eq[i][1+d])) + continue; + eliminate_var_using_equality(bmap, d, bmap->eq[i], 0, NULL); + isl_basic_map_drop_equality(bmap, i); + need_gauss = 1; + break; + } + if (i < bmap->n_eq) + continue; + n_lower = 0; + n_upper = 0; + for (i = 0; i < bmap->n_ineq; ++i) { + if (isl_int_is_pos(bmap->ineq[i][1+d])) + n_lower++; + else if (isl_int_is_neg(bmap->ineq[i][1+d])) + n_upper++; + } + bmap = isl_basic_map_extend_constraints(bmap, + 0, n_lower * n_upper); + if (!bmap) + goto error; + for (i = bmap->n_ineq - 1; i >= 0; --i) { + int last; + if (isl_int_is_zero(bmap->ineq[i][1+d])) + continue; + last = -1; + for (j = 0; j < i; ++j) { + if (isl_int_is_zero(bmap->ineq[j][1+d])) + continue; + last = j; + if (isl_int_sgn(bmap->ineq[i][1+d]) == + isl_int_sgn(bmap->ineq[j][1+d])) + continue; + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + isl_seq_cpy(bmap->ineq[k], bmap->ineq[i], + 1+total); + isl_seq_elim(bmap->ineq[k], bmap->ineq[j], + 1+d, 1+total, NULL); + } + isl_basic_map_drop_inequality(bmap, i); + i = last + 1; + } + if (n_lower > 0 && n_upper > 0) { + bmap = isl_basic_map_normalize_constraints(bmap); + bmap = isl_basic_map_remove_duplicate_constraints(bmap, + NULL, 0); + bmap = isl_basic_map_gauss(bmap, NULL); + bmap = isl_basic_map_remove_redundancies(bmap); + need_gauss = 0; + if (!bmap) + goto error; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) + break; + } + } + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + if (need_gauss) + bmap = isl_basic_map_gauss(bmap, NULL); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +struct isl_basic_set *isl_basic_set_eliminate_vars( + struct isl_basic_set *bset, unsigned pos, unsigned n) +{ + return bset_from_bmap(isl_basic_map_eliminate_vars(bset_to_bmap(bset), + pos, n)); +} + +/* Eliminate the specified n dimensions starting at first from the + * constraints, without removing the dimensions from the space. + * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. + * Otherwise, they are projected out and the original space is restored. + */ +__isl_give isl_basic_map *isl_basic_map_eliminate( + __isl_take isl_basic_map *bmap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_space *space; + + if (!bmap) + return NULL; + if (n == 0) + return bmap; + + if (first + n > isl_basic_map_dim(bmap, type) || first + n < first) + isl_die(bmap->ctx, isl_error_invalid, + "index out of bounds", goto error); + + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) { + first += isl_basic_map_offset(bmap, type) - 1; + bmap = isl_basic_map_eliminate_vars(bmap, first, n); + return isl_basic_map_finalize(bmap); + } + + space = isl_basic_map_get_space(bmap); + bmap = isl_basic_map_project_out(bmap, type, first, n); + bmap = isl_basic_map_insert_dims(bmap, type, first, n); + bmap = isl_basic_map_reset_space(bmap, space); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_eliminate( + __isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_basic_map_eliminate(bset, type, first, n); +} + +/* Remove all constraints from "bmap" that reference any unknown local + * variables (directly or indirectly). + * + * Dropping all constraints on a local variable will make it redundant, + * so it will get removed implicitly by + * isl_basic_map_drop_constraints_involving_dims. Some other local + * variables may also end up becoming redundant if they only appear + * in constraints together with the unknown local variable. + * Therefore, start over after calling + * isl_basic_map_drop_constraints_involving_dims. + */ +__isl_give isl_basic_map *isl_basic_map_drop_constraint_involving_unknown_divs( + __isl_take isl_basic_map *bmap) +{ + isl_bool known; + int i, n_div, o_div; + + known = isl_basic_map_divs_known(bmap); + if (known < 0) + return isl_basic_map_free(bmap); + if (known) + return bmap; + + n_div = isl_basic_map_dim(bmap, isl_dim_div); + o_div = isl_basic_map_offset(bmap, isl_dim_div) - 1; + + for (i = 0; i < n_div; ++i) { + known = isl_basic_map_div_is_known(bmap, i); + if (known < 0) + return isl_basic_map_free(bmap); + if (known) + continue; + bmap = remove_dependent_vars(bmap, o_div + i); + bmap = isl_basic_map_drop_constraints_involving_dims(bmap, + isl_dim_div, i, 1); + if (!bmap) + return NULL; + n_div = isl_basic_map_dim(bmap, isl_dim_div); + i = -1; + } + + return bmap; +} + +/* Remove all constraints from "map" that reference any unknown local + * variables (directly or indirectly). + * + * Since constraints may get dropped from the basic maps, + * they may no longer be disjoint from each other. + */ +__isl_give isl_map *isl_map_drop_constraint_involving_unknown_divs( + __isl_take isl_map *map) +{ + int i; + isl_bool known; + + known = isl_map_divs_known(map); + if (known < 0) + return isl_map_free(map); + if (known) + return map; + + map = isl_map_cow(map); + if (!map) + return NULL; + + for (i = 0; i < map->n; ++i) { + map->p[i] = + isl_basic_map_drop_constraint_involving_unknown_divs( + map->p[i]); + if (!map->p[i]) + return isl_map_free(map); + } + + if (map->n > 1) + ISL_F_CLR(map, ISL_MAP_DISJOINT); + + return map; +} + +/* Don't assume equalities are in order, because align_divs + * may have changed the order of the divs. + */ +static void compute_elimination_index(__isl_keep isl_basic_map *bmap, int *elim) +{ + int d, i; + unsigned total; + + total = isl_space_dim(bmap->dim, isl_dim_all); + for (d = 0; d < total; ++d) + elim[d] = -1; + for (i = 0; i < bmap->n_eq; ++i) { + for (d = total - 1; d >= 0; --d) { + if (isl_int_is_zero(bmap->eq[i][1+d])) + continue; + elim[d] = i; + break; + } + } +} + +static void set_compute_elimination_index(__isl_keep isl_basic_set *bset, + int *elim) +{ + compute_elimination_index(bset_to_bmap(bset), elim); +} + +static int reduced_using_equalities(isl_int *dst, isl_int *src, + __isl_keep isl_basic_map *bmap, int *elim) +{ + int d; + int copied = 0; + unsigned total; + + total = isl_space_dim(bmap->dim, isl_dim_all); + for (d = total - 1; d >= 0; --d) { + if (isl_int_is_zero(src[1+d])) + continue; + if (elim[d] == -1) + continue; + if (!copied) { + isl_seq_cpy(dst, src, 1 + total); + copied = 1; + } + isl_seq_elim(dst, bmap->eq[elim[d]], 1 + d, 1 + total, NULL); + } + return copied; +} + +static int set_reduced_using_equalities(isl_int *dst, isl_int *src, + __isl_keep isl_basic_set *bset, int *elim) +{ + return reduced_using_equalities(dst, src, + bset_to_bmap(bset), elim); +} + +static __isl_give isl_basic_set *isl_basic_set_reduce_using_equalities( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *context) +{ + int i; + int *elim; + + if (!bset || !context) + goto error; + + if (context->n_eq == 0) { + isl_basic_set_free(context); + return bset; + } + + bset = isl_basic_set_cow(bset); + if (!bset) + goto error; + + elim = isl_alloc_array(bset->ctx, int, isl_basic_set_n_dim(bset)); + if (!elim) + goto error; + set_compute_elimination_index(context, elim); + for (i = 0; i < bset->n_eq; ++i) + set_reduced_using_equalities(bset->eq[i], bset->eq[i], + context, elim); + for (i = 0; i < bset->n_ineq; ++i) + set_reduced_using_equalities(bset->ineq[i], bset->ineq[i], + context, elim); + isl_basic_set_free(context); + free(elim); + bset = isl_basic_set_simplify(bset); + bset = isl_basic_set_finalize(bset); + return bset; +error: + isl_basic_set_free(bset); + isl_basic_set_free(context); + return NULL; +} + +/* For each inequality in "ineq" that is a shifted (more relaxed) + * copy of an inequality in "context", mark the corresponding entry + * in "row" with -1. + * If an inequality only has a non-negative constant term, then + * mark it as well. + */ +static isl_stat mark_shifted_constraints(__isl_keep isl_mat *ineq, + __isl_keep isl_basic_set *context, int *row) +{ + struct isl_constraint_index ci; + int n_ineq; + unsigned total; + int k; + + if (!ineq || !context) + return isl_stat_error; + if (context->n_ineq == 0) + return isl_stat_ok; + if (setup_constraint_index(&ci, context) < 0) + return isl_stat_error; + + n_ineq = isl_mat_rows(ineq); + total = isl_mat_cols(ineq) - 1; + for (k = 0; k < n_ineq; ++k) { + int l; + isl_bool redundant; + + l = isl_seq_first_non_zero(ineq->row[k] + 1, total); + if (l < 0 && isl_int_is_nonneg(ineq->row[k][0])) { + row[k] = -1; + continue; + } + redundant = constraint_index_is_redundant(&ci, ineq->row[k]); + if (redundant < 0) + goto error; + if (!redundant) + continue; + row[k] = -1; + } + constraint_index_free(&ci); + return isl_stat_ok; +error: + constraint_index_free(&ci); + return isl_stat_error; +} + +static __isl_give isl_basic_set *remove_shifted_constraints( + __isl_take isl_basic_set *bset, __isl_keep isl_basic_set *context) +{ + struct isl_constraint_index ci; + int k; + + if (!bset || !context) + return bset; + + if (context->n_ineq == 0) + return bset; + if (setup_constraint_index(&ci, context) < 0) + return bset; + + for (k = 0; k < bset->n_ineq; ++k) { + isl_bool redundant; + + redundant = constraint_index_is_redundant(&ci, bset->ineq[k]); + if (redundant < 0) + goto error; + if (!redundant) + continue; + bset = isl_basic_set_cow(bset); + if (!bset) + goto error; + isl_basic_set_drop_inequality(bset, k); + --k; + } + constraint_index_free(&ci); + return bset; +error: + constraint_index_free(&ci); + return bset; +} + +/* Remove constraints from "bmap" that are identical to constraints + * in "context" or that are more relaxed (greater constant term). + * + * We perform the test for shifted copies on the pure constraints + * in remove_shifted_constraints. + */ +static __isl_give isl_basic_map *isl_basic_map_remove_shifted_constraints( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context) +{ + isl_basic_set *bset, *bset_context; + + if (!bmap || !context) + goto error; + + if (bmap->n_ineq == 0 || context->n_ineq == 0) { + isl_basic_map_free(context); + return bmap; + } + + context = isl_basic_map_align_divs(context, bmap); + bmap = isl_basic_map_align_divs(bmap, context); + + bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap)); + bset_context = isl_basic_map_underlying_set(context); + bset = remove_shifted_constraints(bset, bset_context); + isl_basic_set_free(bset_context); + + bmap = isl_basic_map_overlying_set(bset, bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + isl_basic_map_free(context); + return NULL; +} + +/* Does the (linear part of a) constraint "c" involve any of the "len" + * "relevant" dimensions? + */ +static int is_related(isl_int *c, int len, int *relevant) +{ + int i; + + for (i = 0; i < len; ++i) { + if (!relevant[i]) + continue; + if (!isl_int_is_zero(c[i])) + return 1; + } + + return 0; +} + +/* Drop constraints from "bmap" that do not involve any of + * the dimensions marked "relevant". + */ +static __isl_give isl_basic_map *drop_unrelated_constraints( + __isl_take isl_basic_map *bmap, int *relevant) +{ + int i, dim; + + dim = isl_basic_map_dim(bmap, isl_dim_all); + for (i = 0; i < dim; ++i) + if (!relevant[i]) + break; + if (i >= dim) + return bmap; + + for (i = bmap->n_eq - 1; i >= 0; --i) + if (!is_related(bmap->eq[i] + 1, dim, relevant)) { + bmap = isl_basic_map_cow(bmap); + if (isl_basic_map_drop_equality(bmap, i) < 0) + return isl_basic_map_free(bmap); + } + + for (i = bmap->n_ineq - 1; i >= 0; --i) + if (!is_related(bmap->ineq[i] + 1, dim, relevant)) { + bmap = isl_basic_map_cow(bmap); + if (isl_basic_map_drop_inequality(bmap, i) < 0) + return isl_basic_map_free(bmap); + } + + return bmap; +} + +/* Update the groups in "group" based on the (linear part of a) constraint "c". + * + * In particular, for any variable involved in the constraint, + * find the actual group id from before and replace the group + * of the corresponding variable by the minimal group of all + * the variables involved in the constraint considered so far + * (if this minimum is smaller) or replace the minimum by this group + * (if the minimum is larger). + * + * At the end, all the variables in "c" will (indirectly) point + * to the minimal of the groups that they referred to originally. + */ +static void update_groups(int dim, int *group, isl_int *c) +{ + int j; + int min = dim; + + for (j = 0; j < dim; ++j) { + if (isl_int_is_zero(c[j])) + continue; + while (group[j] >= 0 && group[group[j]] != group[j]) + group[j] = group[group[j]]; + if (group[j] == min) + continue; + if (group[j] < min) { + if (min >= 0 && min < dim) + group[min] = group[j]; + min = group[j]; + } else + group[group[j]] = min; + } +} + +/* Allocate an array of groups of variables, one for each variable + * in "context", initialized to zero. + */ +static int *alloc_groups(__isl_keep isl_basic_set *context) +{ + isl_ctx *ctx; + int dim; + + dim = isl_basic_set_dim(context, isl_dim_set); + ctx = isl_basic_set_get_ctx(context); + return isl_calloc_array(ctx, int, dim); +} + +/* Drop constraints from "bmap" that only involve variables that are + * not related to any of the variables marked with a "-1" in "group". + * + * We construct groups of variables that collect variables that + * (indirectly) appear in some common constraint of "bmap". + * Each group is identified by the first variable in the group, + * except for the special group of variables that was already identified + * in the input as -1 (or are related to those variables). + * If group[i] is equal to i (or -1), then the group of i is i (or -1), + * otherwise the group of i is the group of group[i]. + * + * We first initialize groups for the remaining variables. + * Then we iterate over the constraints of "bmap" and update the + * group of the variables in the constraint by the smallest group. + * Finally, we resolve indirect references to groups by running over + * the variables. + * + * After computing the groups, we drop constraints that do not involve + * any variables in the -1 group. + */ +__isl_give isl_basic_map *isl_basic_map_drop_unrelated_constraints( + __isl_take isl_basic_map *bmap, __isl_take int *group) +{ + int dim; + int i; + int last; + + if (!bmap) + return NULL; + + dim = isl_basic_map_dim(bmap, isl_dim_all); + + last = -1; + for (i = 0; i < dim; ++i) + if (group[i] >= 0) + last = group[i] = i; + if (last < 0) { + free(group); + return bmap; + } + + for (i = 0; i < bmap->n_eq; ++i) + update_groups(dim, group, bmap->eq[i] + 1); + for (i = 0; i < bmap->n_ineq; ++i) + update_groups(dim, group, bmap->ineq[i] + 1); + + for (i = 0; i < dim; ++i) + if (group[i] >= 0) + group[i] = group[group[i]]; + + for (i = 0; i < dim; ++i) + group[i] = group[i] == -1; + + bmap = drop_unrelated_constraints(bmap, group); + + free(group); + return bmap; +} + +/* Drop constraints from "context" that are irrelevant for computing + * the gist of "bset". + * + * In particular, drop constraints in variables that are not related + * to any of the variables involved in the constraints of "bset" + * in the sense that there is no sequence of constraints that connects them. + * + * We first mark all variables that appear in "bset" as belonging + * to a "-1" group and then continue with group_and_drop_irrelevant_constraints. + */ +static __isl_give isl_basic_set *drop_irrelevant_constraints( + __isl_take isl_basic_set *context, __isl_keep isl_basic_set *bset) +{ + int *group; + int dim; + int i, j; + + if (!context || !bset) + return isl_basic_set_free(context); + + group = alloc_groups(context); + + if (!group) + return isl_basic_set_free(context); + + dim = isl_basic_set_dim(bset, isl_dim_set); + for (i = 0; i < dim; ++i) { + for (j = 0; j < bset->n_eq; ++j) + if (!isl_int_is_zero(bset->eq[j][1 + i])) + break; + if (j < bset->n_eq) { + group[i] = -1; + continue; + } + for (j = 0; j < bset->n_ineq; ++j) + if (!isl_int_is_zero(bset->ineq[j][1 + i])) + break; + if (j < bset->n_ineq) + group[i] = -1; + } + + return isl_basic_map_drop_unrelated_constraints(context, group); +} + +/* Drop constraints from "context" that are irrelevant for computing + * the gist of the inequalities "ineq". + * Inequalities in "ineq" for which the corresponding element of row + * is set to -1 have already been marked for removal and should be ignored. + * + * In particular, drop constraints in variables that are not related + * to any of the variables involved in "ineq" + * in the sense that there is no sequence of constraints that connects them. + * + * We first mark all variables that appear in "bset" as belonging + * to a "-1" group and then continue with group_and_drop_irrelevant_constraints. + */ +static __isl_give isl_basic_set *drop_irrelevant_constraints_marked( + __isl_take isl_basic_set *context, __isl_keep isl_mat *ineq, int *row) +{ + int *group; + int dim; + int i, j, n; + + if (!context || !ineq) + return isl_basic_set_free(context); + + group = alloc_groups(context); + + if (!group) + return isl_basic_set_free(context); + + dim = isl_basic_set_dim(context, isl_dim_set); + n = isl_mat_rows(ineq); + for (i = 0; i < dim; ++i) { + for (j = 0; j < n; ++j) { + if (row[j] < 0) + continue; + if (!isl_int_is_zero(ineq->row[j][1 + i])) + break; + } + if (j < n) + group[i] = -1; + } + + return isl_basic_map_drop_unrelated_constraints(context, group); +} + +/* Do all "n" entries of "row" contain a negative value? + */ +static int all_neg(int *row, int n) +{ + int i; + + for (i = 0; i < n; ++i) + if (row[i] >= 0) + return 0; + + return 1; +} + +/* Update the inequalities in "bset" based on the information in "row" + * and "tab". + * + * In particular, the array "row" contains either -1, meaning that + * the corresponding inequality of "bset" is redundant, or the index + * of an inequality in "tab". + * + * If the row entry is -1, then drop the inequality. + * Otherwise, if the constraint is marked redundant in the tableau, + * then drop the inequality. Similarly, if it is marked as an equality + * in the tableau, then turn the inequality into an equality and + * perform Gaussian elimination. + */ +static __isl_give isl_basic_set *update_ineq(__isl_take isl_basic_set *bset, + __isl_keep int *row, struct isl_tab *tab) +{ + int i; + unsigned n_ineq; + unsigned n_eq; + int found_equality = 0; + + if (!bset) + return NULL; + if (tab && tab->empty) + return isl_basic_set_set_to_empty(bset); + + n_ineq = bset->n_ineq; + for (i = n_ineq - 1; i >= 0; --i) { + if (row[i] < 0) { + if (isl_basic_set_drop_inequality(bset, i) < 0) + return isl_basic_set_free(bset); + continue; + } + if (!tab) + continue; + n_eq = tab->n_eq; + if (isl_tab_is_equality(tab, n_eq + row[i])) { + isl_basic_map_inequality_to_equality(bset, i); + found_equality = 1; + } else if (isl_tab_is_redundant(tab, n_eq + row[i])) { + if (isl_basic_set_drop_inequality(bset, i) < 0) + return isl_basic_set_free(bset); + } + } + + if (found_equality) + bset = isl_basic_set_gauss(bset, NULL); + bset = isl_basic_set_finalize(bset); + return bset; +} + +/* Update the inequalities in "bset" based on the information in "row" + * and "tab" and free all arguments (other than "bset"). + */ +static __isl_give isl_basic_set *update_ineq_free( + __isl_take isl_basic_set *bset, __isl_take isl_mat *ineq, + __isl_take isl_basic_set *context, __isl_take int *row, + struct isl_tab *tab) +{ + isl_mat_free(ineq); + isl_basic_set_free(context); + + bset = update_ineq(bset, row, tab); + + free(row); + isl_tab_free(tab); + return bset; +} + +/* Remove all information from bset that is redundant in the context + * of context. + * "ineq" contains the (possibly transformed) inequalities of "bset", + * in the same order. + * The (explicit) equalities of "bset" are assumed to have been taken + * into account by the transformation such that only the inequalities + * are relevant. + * "context" is assumed not to be empty. + * + * "row" keeps track of the constraint index of a "bset" inequality in "tab". + * A value of -1 means that the inequality is obviously redundant and may + * not even appear in "tab". + * + * We first mark the inequalities of "bset" + * that are obviously redundant with respect to some inequality in "context". + * Then we remove those constraints from "context" that have become + * irrelevant for computing the gist of "bset". + * Note that this removal of constraints cannot be replaced by + * a factorization because factors in "bset" may still be connected + * to each other through constraints in "context". + * + * If there are any inequalities left, we construct a tableau for + * the context and then add the inequalities of "bset". + * Before adding these inequalities, we freeze all constraints such that + * they won't be considered redundant in terms of the constraints of "bset". + * Then we detect all redundant constraints (among the + * constraints that weren't frozen), first by checking for redundancy in the + * the tableau and then by checking if replacing a constraint by its negation + * would lead to an empty set. This last step is fairly expensive + * and could be optimized by more reuse of the tableau. + * Finally, we update bset according to the results. + */ +static __isl_give isl_basic_set *uset_gist_full(__isl_take isl_basic_set *bset, + __isl_take isl_mat *ineq, __isl_take isl_basic_set *context) +{ + int i, r; + int *row = NULL; + isl_ctx *ctx; + isl_basic_set *combined = NULL; + struct isl_tab *tab = NULL; + unsigned n_eq, context_ineq; + + if (!bset || !ineq || !context) + goto error; + + if (bset->n_ineq == 0 || isl_basic_set_plain_is_universe(context)) { + isl_basic_set_free(context); + isl_mat_free(ineq); + return bset; + } + + ctx = isl_basic_set_get_ctx(context); + row = isl_calloc_array(ctx, int, bset->n_ineq); + if (!row) + goto error; + + if (mark_shifted_constraints(ineq, context, row) < 0) + goto error; + if (all_neg(row, bset->n_ineq)) + return update_ineq_free(bset, ineq, context, row, NULL); + + context = drop_irrelevant_constraints_marked(context, ineq, row); + if (!context) + goto error; + if (isl_basic_set_plain_is_universe(context)) + return update_ineq_free(bset, ineq, context, row, NULL); + + n_eq = context->n_eq; + context_ineq = context->n_ineq; + combined = isl_basic_set_cow(isl_basic_set_copy(context)); + combined = isl_basic_set_extend_constraints(combined, 0, bset->n_ineq); + tab = isl_tab_from_basic_set(combined, 0); + for (i = 0; i < context_ineq; ++i) + if (isl_tab_freeze_constraint(tab, n_eq + i) < 0) + goto error; + if (isl_tab_extend_cons(tab, bset->n_ineq) < 0) + goto error; + r = context_ineq; + for (i = 0; i < bset->n_ineq; ++i) { + if (row[i] < 0) + continue; + combined = isl_basic_set_add_ineq(combined, ineq->row[i]); + if (isl_tab_add_ineq(tab, ineq->row[i]) < 0) + goto error; + row[i] = r++; + } + if (isl_tab_detect_implicit_equalities(tab) < 0) + goto error; + if (isl_tab_detect_redundant(tab) < 0) + goto error; + for (i = bset->n_ineq - 1; i >= 0; --i) { + isl_basic_set *test; + int is_empty; + + if (row[i] < 0) + continue; + r = row[i]; + if (tab->con[n_eq + r].is_redundant) + continue; + test = isl_basic_set_dup(combined); + if (isl_inequality_negate(test, r) < 0) + test = isl_basic_set_free(test); + test = isl_basic_set_update_from_tab(test, tab); + is_empty = isl_basic_set_is_empty(test); + isl_basic_set_free(test); + if (is_empty < 0) + goto error; + if (is_empty) + tab->con[n_eq + r].is_redundant = 1; + } + bset = update_ineq_free(bset, ineq, context, row, tab); + if (bset) { + ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT); + ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT); + } + + isl_basic_set_free(combined); + return bset; +error: + free(row); + isl_mat_free(ineq); + isl_tab_free(tab); + isl_basic_set_free(combined); + isl_basic_set_free(context); + isl_basic_set_free(bset); + return NULL; +} + +/* Extract the inequalities of "bset" as an isl_mat. + */ +static __isl_give isl_mat *extract_ineq(__isl_keep isl_basic_set *bset) +{ + unsigned total; + isl_ctx *ctx; + isl_mat *ineq; + + if (!bset) + return NULL; + + ctx = isl_basic_set_get_ctx(bset); + total = isl_basic_set_total_dim(bset); + ineq = isl_mat_sub_alloc6(ctx, bset->ineq, 0, bset->n_ineq, + 0, 1 + total); + + return ineq; +} + +/* Remove all information from "bset" that is redundant in the context + * of "context", for the case where both "bset" and "context" are + * full-dimensional. + */ +static __isl_give isl_basic_set *uset_gist_uncompressed( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *context) +{ + isl_mat *ineq; + + ineq = extract_ineq(bset); + return uset_gist_full(bset, ineq, context); +} + +/* Remove all information from "bset" that is redundant in the context + * of "context", for the case where the combined equalities of + * "bset" and "context" allow for a compression that can be obtained + * by preapplication of "T". + * + * "bset" itself is not transformed by "T". Instead, the inequalities + * are extracted from "bset" and those are transformed by "T". + * uset_gist_full then determines which of the transformed inequalities + * are redundant with respect to the transformed "context" and removes + * the corresponding inequalities from "bset". + * + * After preapplying "T" to the inequalities, any common factor is + * removed from the coefficients. If this results in a tightening + * of the constant term, then the same tightening is applied to + * the corresponding untransformed inequality in "bset". + * That is, if after plugging in T, a constraint f(x) >= 0 is of the form + * + * g f'(x) + r >= 0 + * + * with 0 <= r < g, then it is equivalent to + * + * f'(x) >= 0 + * + * This means that f(x) >= 0 is equivalent to f(x) - r >= 0 in the affine + * subspace compressed by T since the latter would be transformed to + * + * g f'(x) >= 0 + */ +static __isl_give isl_basic_set *uset_gist_compressed( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *context, + __isl_take isl_mat *T) +{ + isl_ctx *ctx; + isl_mat *ineq; + int i, n_row, n_col; + isl_int rem; + + ineq = extract_ineq(bset); + ineq = isl_mat_product(ineq, isl_mat_copy(T)); + context = isl_basic_set_preimage(context, T); + + if (!ineq || !context) + goto error; + if (isl_basic_set_plain_is_empty(context)) { + isl_mat_free(ineq); + isl_basic_set_free(context); + return isl_basic_set_set_to_empty(bset); + } + + ctx = isl_mat_get_ctx(ineq); + n_row = isl_mat_rows(ineq); + n_col = isl_mat_cols(ineq); + isl_int_init(rem); + for (i = 0; i < n_row; ++i) { + isl_seq_gcd(ineq->row[i] + 1, n_col - 1, &ctx->normalize_gcd); + if (isl_int_is_zero(ctx->normalize_gcd)) + continue; + if (isl_int_is_one(ctx->normalize_gcd)) + continue; + isl_seq_scale_down(ineq->row[i] + 1, ineq->row[i] + 1, + ctx->normalize_gcd, n_col - 1); + isl_int_fdiv_r(rem, ineq->row[i][0], ctx->normalize_gcd); + isl_int_fdiv_q(ineq->row[i][0], + ineq->row[i][0], ctx->normalize_gcd); + if (isl_int_is_zero(rem)) + continue; + bset = isl_basic_set_cow(bset); + if (!bset) + break; + isl_int_sub(bset->ineq[i][0], bset->ineq[i][0], rem); + } + isl_int_clear(rem); + + return uset_gist_full(bset, ineq, context); +error: + isl_mat_free(ineq); + isl_basic_set_free(context); + isl_basic_set_free(bset); + return NULL; +} + +/* Project "bset" onto the variables that are involved in "template". + */ +static __isl_give isl_basic_set *project_onto_involved( + __isl_take isl_basic_set *bset, __isl_keep isl_basic_set *template) +{ + int i, n; + + if (!bset || !template) + return isl_basic_set_free(bset); + + n = isl_basic_set_dim(template, isl_dim_set); + + for (i = 0; i < n; ++i) { + isl_bool involved; + + involved = isl_basic_set_involves_dims(template, + isl_dim_set, i, 1); + if (involved < 0) + return isl_basic_set_free(bset); + if (involved) + continue; + bset = isl_basic_set_eliminate_vars(bset, i, 1); + } + + return bset; +} + +/* Remove all information from bset that is redundant in the context + * of context. In particular, equalities that are linear combinations + * of those in context are removed. Then the inequalities that are + * redundant in the context of the equalities and inequalities of + * context are removed. + * + * First of all, we drop those constraints from "context" + * that are irrelevant for computing the gist of "bset". + * Alternatively, we could factorize the intersection of "context" and "bset". + * + * We first compute the intersection of the integer affine hulls + * of "bset" and "context", + * compute the gist inside this intersection and then reduce + * the constraints with respect to the equalities of the context + * that only involve variables already involved in the input. + * + * If two constraints are mutually redundant, then uset_gist_full + * will remove the second of those constraints. We therefore first + * sort the constraints so that constraints not involving existentially + * quantified variables are given precedence over those that do. + * We have to perform this sorting before the variable compression, + * because that may effect the order of the variables. + */ +static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset, + __isl_take isl_basic_set *context) +{ + isl_mat *eq; + isl_mat *T; + isl_basic_set *aff; + isl_basic_set *aff_context; + unsigned total; + + if (!bset || !context) + goto error; + + context = drop_irrelevant_constraints(context, bset); + + bset = isl_basic_set_detect_equalities(bset); + aff = isl_basic_set_copy(bset); + aff = isl_basic_set_plain_affine_hull(aff); + context = isl_basic_set_detect_equalities(context); + aff_context = isl_basic_set_copy(context); + aff_context = isl_basic_set_plain_affine_hull(aff_context); + aff = isl_basic_set_intersect(aff, aff_context); + if (!aff) + goto error; + if (isl_basic_set_plain_is_empty(aff)) { + isl_basic_set_free(bset); + isl_basic_set_free(context); + return aff; + } + bset = isl_basic_set_sort_constraints(bset); + if (aff->n_eq == 0) { + isl_basic_set_free(aff); + return uset_gist_uncompressed(bset, context); + } + total = isl_basic_set_total_dim(bset); + 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, NULL); + isl_basic_set_free(aff); + if (T && T->n_col == 0) { + isl_mat_free(T); + isl_basic_set_free(context); + return isl_basic_set_set_to_empty(bset); + } + + aff_context = isl_basic_set_affine_hull(isl_basic_set_copy(context)); + aff_context = project_onto_involved(aff_context, bset); + + bset = uset_gist_compressed(bset, context, T); + bset = isl_basic_set_reduce_using_equalities(bset, aff_context); + + if (bset) { + ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT); + ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT); + } + + return bset; +error: + isl_basic_set_free(bset); + isl_basic_set_free(context); + return NULL; +} + +/* Return the number of equality constraints in "bmap" that involve + * local variables. This function assumes that Gaussian elimination + * has been applied to the equality constraints. + */ +static int n_div_eq(__isl_keep isl_basic_map *bmap) +{ + int i; + int total, n_div; + + if (!bmap) + return -1; + + if (bmap->n_eq == 0) + return 0; + + total = isl_basic_map_dim(bmap, isl_dim_all); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + total -= n_div; + + for (i = 0; i < bmap->n_eq; ++i) + if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total, + n_div) == -1) + return i; + + return bmap->n_eq; +} + +/* Construct a basic map in "space" defined by the equality constraints in "eq". + * The constraints are assumed not to involve any local variables. + */ +static __isl_give isl_basic_map *basic_map_from_equalities( + __isl_take isl_space *space, __isl_take isl_mat *eq) +{ + int i, k; + isl_basic_map *bmap = NULL; + + if (!space || !eq) + goto error; + + if (1 + isl_space_dim(space, isl_dim_all) != eq->n_col) + isl_die(isl_space_get_ctx(space), isl_error_internal, + "unexpected number of columns", goto error); + + bmap = isl_basic_map_alloc_space(isl_space_copy(space), + 0, eq->n_row, 0); + for (i = 0; i < eq->n_row; ++i) { + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + isl_seq_cpy(bmap->eq[k], eq->row[i], eq->n_col); + } + + isl_space_free(space); + isl_mat_free(eq); + return bmap; +error: + isl_space_free(space); + isl_mat_free(eq); + isl_basic_map_free(bmap); + return NULL; +} + +/* Construct and return a variable compression based on the equality + * constraints in "bmap1" and "bmap2" that do not involve the local variables. + * "n1" is the number of (initial) equality constraints in "bmap1" + * that do involve local variables. + * "n2" is the number of (initial) equality constraints in "bmap2" + * that do involve local variables. + * "total" is the total number of other variables. + * This function assumes that Gaussian elimination + * has been applied to the equality constraints in both "bmap1" and "bmap2" + * such that the equality constraints not involving local variables + * are those that start at "n1" or "n2". + * + * If either of "bmap1" and "bmap2" does not have such equality constraints, + * then simply compute the compression based on the equality constraints + * in the other basic map. + * Otherwise, combine the equality constraints from both into a new + * basic map such that Gaussian elimination can be applied to this combination + * and then construct a variable compression from the resulting + * equality constraints. + */ +static __isl_give isl_mat *combined_variable_compression( + __isl_keep isl_basic_map *bmap1, int n1, + __isl_keep isl_basic_map *bmap2, int n2, int total) +{ + isl_ctx *ctx; + isl_mat *E1, *E2, *V; + isl_basic_map *bmap; + + ctx = isl_basic_map_get_ctx(bmap1); + if (bmap1->n_eq == n1) { + E2 = isl_mat_sub_alloc6(ctx, bmap2->eq, + n2, bmap2->n_eq - n2, 0, 1 + total); + return isl_mat_variable_compression(E2, NULL); + } + if (bmap2->n_eq == n2) { + E1 = isl_mat_sub_alloc6(ctx, bmap1->eq, + n1, bmap1->n_eq - n1, 0, 1 + total); + return isl_mat_variable_compression(E1, NULL); + } + E1 = isl_mat_sub_alloc6(ctx, bmap1->eq, + n1, bmap1->n_eq - n1, 0, 1 + total); + E2 = isl_mat_sub_alloc6(ctx, bmap2->eq, + n2, bmap2->n_eq - n2, 0, 1 + total); + E1 = isl_mat_concat(E1, E2); + bmap = basic_map_from_equalities(isl_basic_map_get_space(bmap1), E1); + bmap = isl_basic_map_gauss(bmap, NULL); + if (!bmap) + return NULL; + E1 = isl_mat_sub_alloc6(ctx, bmap->eq, 0, bmap->n_eq, 0, 1 + total); + V = isl_mat_variable_compression(E1, NULL); + isl_basic_map_free(bmap); + + return V; +} + +/* Extract the stride constraints from "bmap", compressed + * with respect to both the stride constraints in "context" and + * the remaining equality constraints in both "bmap" and "context". + * "bmap_n_eq" is the number of (initial) stride constraints in "bmap". + * "context_n_eq" is the number of (initial) stride constraints in "context". + * + * Let x be all variables in "bmap" (and "context") other than the local + * variables. First compute a variable compression + * + * x = V x' + * + * based on the non-stride equality constraints in "bmap" and "context". + * Consider the stride constraints of "context", + * + * A(x) + B(y) = 0 + * + * with y the local variables and plug in the variable compression, + * resulting in + * + * A(V x') + B(y) = 0 + * + * Use these constraints to compute a parameter compression on x' + * + * x' = T x'' + * + * Now consider the stride constraints of "bmap" + * + * C(x) + D(y) = 0 + * + * and plug in x = V*T x''. + * That is, return A = [C*V*T D]. + */ +static __isl_give isl_mat *extract_compressed_stride_constraints( + __isl_keep isl_basic_map *bmap, int bmap_n_eq, + __isl_keep isl_basic_map *context, int context_n_eq) +{ + int total, n_div; + isl_ctx *ctx; + isl_mat *A, *B, *T, *V; + + total = isl_basic_map_dim(context, isl_dim_all); + n_div = isl_basic_map_dim(context, isl_dim_div); + total -= n_div; + + ctx = isl_basic_map_get_ctx(bmap); + + V = combined_variable_compression(bmap, bmap_n_eq, + context, context_n_eq, total); + + A = isl_mat_sub_alloc6(ctx, context->eq, 0, context_n_eq, 0, 1 + total); + B = isl_mat_sub_alloc6(ctx, context->eq, + 0, context_n_eq, 1 + total, n_div); + A = isl_mat_product(A, isl_mat_copy(V)); + T = isl_mat_parameter_compression_ext(A, B); + T = isl_mat_product(V, T); + + n_div = isl_basic_map_dim(bmap, isl_dim_div); + T = isl_mat_diagonal(T, isl_mat_identity(ctx, n_div)); + + A = isl_mat_sub_alloc6(ctx, bmap->eq, + 0, bmap_n_eq, 0, 1 + total + n_div); + A = isl_mat_product(A, T); + + return A; +} + +/* Remove the prime factors from *g that have an exponent that + * is strictly smaller than the exponent in "c". + * All exponents in *g are known to be smaller than or equal + * to those in "c". + * + * That is, if *g is equal to + * + * p_1^{e_1} p_2^{e_2} ... p_n^{e_n} + * + * and "c" is equal to + * + * p_1^{f_1} p_2^{f_2} ... p_n^{f_n} + * + * then update *g to + * + * p_1^{e_1 * (e_1 = f_1)} p_2^{e_2 * (e_2 = f_2)} ... + * p_n^{e_n * (e_n = f_n)} + * + * If e_i = f_i, then c / *g does not have any p_i factors and therefore + * neither does the gcd of *g and c / *g. + * If e_i < f_i, then the gcd of *g and c / *g has a positive + * power min(e_i, s_i) of p_i with s_i = f_i - e_i among its factors. + * Dividing *g by this gcd therefore strictly reduces the exponent + * of the prime factors that need to be removed, while leaving the + * other prime factors untouched. + * Repeating this process until gcd(*g, c / *g) = 1 therefore + * removes all undesired factors, without removing any others. + */ +static void remove_incomplete_powers(isl_int *g, isl_int c) +{ + isl_int t; + + isl_int_init(t); + for (;;) { + isl_int_divexact(t, c, *g); + isl_int_gcd(t, t, *g); + if (isl_int_is_one(t)) + break; + isl_int_divexact(*g, *g, t); + } + isl_int_clear(t); +} + +/* Reduce the "n" stride constraints in "bmap" based on a copy "A" + * of the same stride constraints in a compressed space that exploits + * all equalities in the context and the other equalities in "bmap". + * + * If the stride constraints of "bmap" are of the form + * + * C(x) + D(y) = 0 + * + * then A is of the form + * + * B(x') + D(y) = 0 + * + * If any of these constraints involves only a single local variable y, + * then the constraint appears as + * + * f(x) + m y_i = 0 + * + * in "bmap" and as + * + * h(x') + m y_i = 0 + * + * in "A". + * + * Let g be the gcd of m and the coefficients of h. + * Then, in particular, g is a divisor of the coefficients of h and + * + * f(x) = h(x') + * + * is known to be a multiple of g. + * If some prime factor in m appears with the same exponent in g, + * then it can be removed from m because f(x) is already known + * to be a multiple of g and therefore in particular of this power + * of the prime factors. + * Prime factors that appear with a smaller exponent in g cannot + * be removed from m. + * Let g' be the divisor of g containing all prime factors that + * appear with the same exponent in m and g, then + * + * f(x) + m y_i = 0 + * + * can be replaced by + * + * f(x) + m/g' y_i' = 0 + * + * Note that (if g' != 1) this changes the explicit representation + * of y_i to that of y_i', so the integer division at position i + * is marked unknown and later recomputed by a call to + * isl_basic_map_gauss. + */ +static __isl_give isl_basic_map *reduce_stride_constraints( + __isl_take isl_basic_map *bmap, int n, __isl_keep isl_mat *A) +{ + int i; + int total, n_div; + int any = 0; + isl_int gcd; + + if (!bmap || !A) + return isl_basic_map_free(bmap); + + total = isl_basic_map_dim(bmap, isl_dim_all); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + total -= n_div; + + isl_int_init(gcd); + for (i = 0; i < n; ++i) { + int div; + + div = isl_seq_first_non_zero(bmap->eq[i] + 1 + total, n_div); + if (div < 0) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_internal, + "equality constraints modified unexpectedly", + goto error); + if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total + div + 1, + n_div - div - 1) != -1) + continue; + if (isl_mat_row_gcd(A, i, &gcd) < 0) + goto error; + if (isl_int_is_one(gcd)) + continue; + remove_incomplete_powers(&gcd, bmap->eq[i][1 + total + div]); + if (isl_int_is_one(gcd)) + continue; + isl_int_divexact(bmap->eq[i][1 + total + div], + bmap->eq[i][1 + total + div], gcd); + bmap = isl_basic_map_mark_div_unknown(bmap, div); + if (!bmap) + goto error; + any = 1; + } + isl_int_clear(gcd); + + if (any) + bmap = isl_basic_map_gauss(bmap, NULL); + + return bmap; +error: + isl_int_clear(gcd); + isl_basic_map_free(bmap); + return NULL; +} + +/* Simplify the stride constraints in "bmap" based on + * the remaining equality constraints in "bmap" and all equality + * constraints in "context". + * Only do this if both "bmap" and "context" have stride constraints. + * + * First extract a copy of the stride constraints in "bmap" in a compressed + * space exploiting all the other equality constraints and then + * use this compressed copy to simplify the original stride constraints. + */ +static __isl_give isl_basic_map *gist_strides(__isl_take isl_basic_map *bmap, + __isl_keep isl_basic_map *context) +{ + int bmap_n_eq, context_n_eq; + isl_mat *A; + + if (!bmap || !context) + return isl_basic_map_free(bmap); + + bmap_n_eq = n_div_eq(bmap); + context_n_eq = n_div_eq(context); + + if (bmap_n_eq < 0 || context_n_eq < 0) + return isl_basic_map_free(bmap); + if (bmap_n_eq == 0 || context_n_eq == 0) + return bmap; + + A = extract_compressed_stride_constraints(bmap, bmap_n_eq, + context, context_n_eq); + bmap = reduce_stride_constraints(bmap, bmap_n_eq, A); + + isl_mat_free(A); + + return bmap; +} + +/* Return a basic map that has the same intersection with "context" as "bmap" + * and that is as "simple" as possible. + * + * The core computation is performed on the pure constraints. + * When we add back the meaning of the integer divisions, we need + * to (re)introduce the div constraints. If we happen to have + * discovered that some of these integer divisions are equal to + * some affine combination of other variables, then these div + * constraints may end up getting simplified in terms of the equalities, + * resulting in extra inequalities on the other variables that + * may have been removed already or that may not even have been + * part of the input. We try and remove those constraints of + * this form that are most obviously redundant with respect to + * the context. We also remove those div constraints that are + * redundant with respect to the other constraints in the result. + * + * The stride constraints among the equality constraints in "bmap" are + * also simplified with respecting to the other equality constraints + * in "bmap" and with respect to all equality constraints in "context". + */ +__isl_give isl_basic_map *isl_basic_map_gist(__isl_take isl_basic_map *bmap, + __isl_take isl_basic_map *context) +{ + isl_basic_set *bset, *eq; + isl_basic_map *eq_bmap; + unsigned total, n_div, extra, n_eq, n_ineq; + + if (!bmap || !context) + goto error; + + if (isl_basic_map_plain_is_universe(bmap)) { + isl_basic_map_free(context); + return bmap; + } + if (isl_basic_map_plain_is_empty(context)) { + isl_space *space = isl_basic_map_get_space(bmap); + isl_basic_map_free(bmap); + isl_basic_map_free(context); + return isl_basic_map_universe(space); + } + if (isl_basic_map_plain_is_empty(bmap)) { + isl_basic_map_free(context); + return bmap; + } + + bmap = isl_basic_map_remove_redundancies(bmap); + context = isl_basic_map_remove_redundancies(context); + if (!context) + goto error; + + context = isl_basic_map_align_divs(context, bmap); + n_div = isl_basic_map_dim(context, isl_dim_div); + total = isl_basic_map_dim(bmap, isl_dim_all); + extra = n_div - isl_basic_map_dim(bmap, isl_dim_div); + + bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap)); + bset = isl_basic_set_add_dims(bset, isl_dim_set, extra); + bset = uset_gist(bset, + isl_basic_map_underlying_set(isl_basic_map_copy(context))); + bset = isl_basic_set_project_out(bset, isl_dim_set, total, extra); + + if (!bset || bset->n_eq == 0 || n_div == 0 || + isl_basic_set_plain_is_empty(bset)) { + isl_basic_map_free(context); + return isl_basic_map_overlying_set(bset, bmap); + } + + n_eq = bset->n_eq; + n_ineq = bset->n_ineq; + eq = isl_basic_set_copy(bset); + eq = isl_basic_set_cow(eq); + if (isl_basic_set_free_inequality(eq, n_ineq) < 0) + eq = isl_basic_set_free(eq); + if (isl_basic_set_free_equality(bset, n_eq) < 0) + bset = isl_basic_set_free(bset); + + eq_bmap = isl_basic_map_overlying_set(eq, isl_basic_map_copy(bmap)); + eq_bmap = gist_strides(eq_bmap, context); + eq_bmap = isl_basic_map_remove_shifted_constraints(eq_bmap, context); + bmap = isl_basic_map_overlying_set(bset, bmap); + bmap = isl_basic_map_intersect(bmap, eq_bmap); + bmap = isl_basic_map_remove_redundancies(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + isl_basic_map_free(context); + return NULL; +} + +/* + * Assumes context has no implicit divs. + */ +__isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map, + __isl_take isl_basic_map *context) +{ + int i; + + if (!map || !context) + goto error; + + if (isl_basic_map_plain_is_empty(context)) { + isl_space *space = isl_map_get_space(map); + isl_map_free(map); + isl_basic_map_free(context); + return isl_map_universe(space); + } + + context = isl_basic_map_remove_redundancies(context); + map = isl_map_cow(map); + if (!map || !context) + goto error; + isl_assert(map->ctx, isl_space_is_equal(map->dim, context->dim), goto error); + map = isl_map_compute_divs(map); + if (!map) + goto error; + for (i = map->n - 1; i >= 0; --i) { + map->p[i] = isl_basic_map_gist(map->p[i], + isl_basic_map_copy(context)); + if (!map->p[i]) + goto error; + 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]; + map->n--; + } + } + isl_basic_map_free(context); + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + isl_basic_map_free(context); + return NULL; +} + +/* Drop all inequalities from "bmap" that also appear in "context". + * "context" is assumed to have only known local variables and + * the initial local variables of "bmap" are assumed to be the same + * as those of "context". + * The constraints of both "bmap" and "context" are assumed + * to have been sorted using isl_basic_map_sort_constraints. + * + * Run through the inequality constraints of "bmap" and "context" + * in sorted order. + * If a constraint of "bmap" involves variables not in "context", + * then it cannot appear in "context". + * If a matching constraint is found, it is removed from "bmap". + */ +static __isl_give isl_basic_map *drop_inequalities( + __isl_take isl_basic_map *bmap, __isl_keep isl_basic_map *context) +{ + int i1, i2; + unsigned total, extra; + + if (!bmap || !context) + return isl_basic_map_free(bmap); + + total = isl_basic_map_total_dim(context); + extra = isl_basic_map_total_dim(bmap) - total; + + i1 = bmap->n_ineq - 1; + i2 = context->n_ineq - 1; + while (bmap && i1 >= 0 && i2 >= 0) { + int cmp; + + if (isl_seq_first_non_zero(bmap->ineq[i1] + 1 + total, + extra) != -1) { + --i1; + continue; + } + cmp = isl_basic_map_constraint_cmp(context, bmap->ineq[i1], + context->ineq[i2]); + if (cmp < 0) { + --i2; + continue; + } + if (cmp > 0) { + --i1; + continue; + } + if (isl_int_eq(bmap->ineq[i1][0], context->ineq[i2][0])) { + bmap = isl_basic_map_cow(bmap); + if (isl_basic_map_drop_inequality(bmap, i1) < 0) + bmap = isl_basic_map_free(bmap); + } + --i1; + --i2; + } + + return bmap; +} + +/* Drop all equalities from "bmap" that also appear in "context". + * "context" is assumed to have only known local variables and + * the initial local variables of "bmap" are assumed to be the same + * as those of "context". + * + * Run through the equality constraints of "bmap" and "context" + * in sorted order. + * If a constraint of "bmap" involves variables not in "context", + * then it cannot appear in "context". + * If a matching constraint is found, it is removed from "bmap". + */ +static __isl_give isl_basic_map *drop_equalities( + __isl_take isl_basic_map *bmap, __isl_keep isl_basic_map *context) +{ + int i1, i2; + unsigned total, extra; + + if (!bmap || !context) + return isl_basic_map_free(bmap); + + total = isl_basic_map_total_dim(context); + extra = isl_basic_map_total_dim(bmap) - total; + + i1 = bmap->n_eq - 1; + i2 = context->n_eq - 1; + + while (bmap && i1 >= 0 && i2 >= 0) { + int last1, last2; + + if (isl_seq_first_non_zero(bmap->eq[i1] + 1 + total, + extra) != -1) + break; + last1 = isl_seq_last_non_zero(bmap->eq[i1] + 1, total); + last2 = isl_seq_last_non_zero(context->eq[i2] + 1, total); + if (last1 > last2) { + --i2; + continue; + } + if (last1 < last2) { + --i1; + continue; + } + if (isl_seq_eq(bmap->eq[i1], context->eq[i2], 1 + total)) { + bmap = isl_basic_map_cow(bmap); + if (isl_basic_map_drop_equality(bmap, i1) < 0) + bmap = isl_basic_map_free(bmap); + } + --i1; + --i2; + } + + return bmap; +} + +/* Remove the constraints in "context" from "bmap". + * "context" is assumed to have explicit representations + * for all local variables. + * + * First align the divs of "bmap" to those of "context" and + * sort the constraints. Then drop all constraints from "bmap" + * that appear in "context". + */ +__isl_give isl_basic_map *isl_basic_map_plain_gist( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context) +{ + isl_bool done, known; + + done = isl_basic_map_plain_is_universe(context); + if (done == isl_bool_false) + done = isl_basic_map_plain_is_universe(bmap); + if (done == isl_bool_false) + done = isl_basic_map_plain_is_empty(context); + if (done == isl_bool_false) + done = isl_basic_map_plain_is_empty(bmap); + if (done < 0) + goto error; + if (done) { + isl_basic_map_free(context); + return bmap; + } + known = isl_basic_map_divs_known(context); + if (known < 0) + goto error; + if (!known) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "context has unknown divs", goto error); + + bmap = isl_basic_map_align_divs(bmap, context); + bmap = isl_basic_map_gauss(bmap, NULL); + bmap = isl_basic_map_sort_constraints(bmap); + context = isl_basic_map_sort_constraints(context); + + bmap = drop_inequalities(bmap, context); + bmap = drop_equalities(bmap, context); + + isl_basic_map_free(context); + bmap = isl_basic_map_finalize(bmap); + return bmap; +error: + isl_basic_map_free(bmap); + isl_basic_map_free(context); + return NULL; +} + +/* Replace "map" by the disjunct at position "pos" and free "context". + */ +static __isl_give isl_map *replace_by_disjunct(__isl_take isl_map *map, + int pos, __isl_take isl_basic_map *context) +{ + isl_basic_map *bmap; + + bmap = isl_basic_map_copy(map->p[pos]); + isl_map_free(map); + isl_basic_map_free(context); + return isl_map_from_basic_map(bmap); +} + +/* Remove the constraints in "context" from "map". + * If any of the disjuncts in the result turns out to be the universe, + * then return this universe. + * "context" is assumed to have explicit representations + * for all local variables. + */ +__isl_give isl_map *isl_map_plain_gist_basic_map(__isl_take isl_map *map, + __isl_take isl_basic_map *context) +{ + int i; + isl_bool univ, known; + + univ = isl_basic_map_plain_is_universe(context); + if (univ < 0) + goto error; + if (univ) { + isl_basic_map_free(context); + return map; + } + known = isl_basic_map_divs_known(context); + if (known < 0) + goto error; + if (!known) + isl_die(isl_map_get_ctx(map), isl_error_invalid, + "context has unknown divs", goto error); + + map = isl_map_cow(map); + if (!map) + goto error; + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_plain_gist(map->p[i], + isl_basic_map_copy(context)); + univ = isl_basic_map_plain_is_universe(map->p[i]); + if (univ < 0) + goto error; + if (univ && map->n > 1) + return replace_by_disjunct(map, i, context); + } + + isl_basic_map_free(context); + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + if (map->n > 1) + ISL_F_CLR(map, ISL_MAP_DISJOINT); + return map; +error: + isl_map_free(map); + isl_basic_map_free(context); + return NULL; +} + +/* Remove the constraints in "context" from "set". + * If any of the disjuncts in the result turns out to be the universe, + * then return this universe. + * "context" is assumed to have explicit representations + * for all local variables. + */ +__isl_give isl_set *isl_set_plain_gist_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *context) +{ + return set_from_map(isl_map_plain_gist_basic_map(set_to_map(set), + bset_to_bmap(context))); +} + +/* Remove the constraints in "context" from "map". + * If any of the disjuncts in the result turns out to be the universe, + * then return this universe. + * "context" is assumed to consist of a single disjunct and + * to have explicit representations for all local variables. + */ +__isl_give isl_map *isl_map_plain_gist(__isl_take isl_map *map, + __isl_take isl_map *context) +{ + isl_basic_map *hull; + + hull = isl_map_unshifted_simple_hull(context); + return isl_map_plain_gist_basic_map(map, hull); +} + +/* Replace "map" by a universe map in the same space and free "drop". + */ +static __isl_give isl_map *replace_by_universe(__isl_take isl_map *map, + __isl_take isl_map *drop) +{ + isl_map *res; + + res = isl_map_universe(isl_map_get_space(map)); + isl_map_free(map); + isl_map_free(drop); + return res; +} + +/* Return a map that has the same intersection with "context" as "map" + * and that is as "simple" as possible. + * + * If "map" is already the universe, then we cannot make it any simpler. + * Similarly, if "context" is the universe, then we cannot exploit it + * to simplify "map" + * If "map" and "context" are identical to each other, then we can + * return the corresponding universe. + * + * If either "map" or "context" consists of multiple disjuncts, + * then check if "context" happens to be a subset of "map", + * in which case all constraints can be removed. + * In case of multiple disjuncts, the standard procedure + * may not be able to detect that all constraints can be removed. + * + * If none of these cases apply, we have to work a bit harder. + * During this computation, we make use of a single disjunct context, + * so if the original context consists of more than one disjunct + * then we need to approximate the context by a single disjunct set. + * Simply taking the simple hull may drop constraints that are + * only implicitly available in each disjunct. We therefore also + * look for constraints among those defining "map" that are valid + * for the context. These can then be used to simplify away + * the corresponding constraints in "map". + */ +static __isl_give isl_map *map_gist(__isl_take isl_map *map, + __isl_take isl_map *context) +{ + int equal; + int is_universe; + int single_disjunct_map, single_disjunct_context; + isl_bool subset; + isl_basic_map *hull; + + is_universe = isl_map_plain_is_universe(map); + if (is_universe >= 0 && !is_universe) + is_universe = isl_map_plain_is_universe(context); + if (is_universe < 0) + goto error; + if (is_universe) { + isl_map_free(context); + return map; + } + + equal = isl_map_plain_is_equal(map, context); + if (equal < 0) + goto error; + if (equal) + return replace_by_universe(map, context); + + single_disjunct_map = isl_map_n_basic_map(map) == 1; + single_disjunct_context = isl_map_n_basic_map(context) == 1; + if (!single_disjunct_map || !single_disjunct_context) { + subset = isl_map_is_subset(context, map); + if (subset < 0) + goto error; + if (subset) + return replace_by_universe(map, context); + } + + context = isl_map_compute_divs(context); + if (!context) + goto error; + if (single_disjunct_context) { + hull = isl_map_simple_hull(context); + } else { + isl_ctx *ctx; + isl_map_list *list; + + ctx = isl_map_get_ctx(map); + list = isl_map_list_alloc(ctx, 2); + list = isl_map_list_add(list, isl_map_copy(context)); + list = isl_map_list_add(list, isl_map_copy(map)); + hull = isl_map_unshifted_simple_hull_from_map_list(context, + list); + } + return isl_map_gist_basic_map(map, hull); +error: + isl_map_free(map); + isl_map_free(context); + return NULL; +} + +__isl_give isl_map *isl_map_gist(__isl_take isl_map *map, + __isl_take isl_map *context) +{ + return isl_map_align_params_map_map_and(map, context, &map_gist); +} + +struct isl_basic_set *isl_basic_set_gist(struct isl_basic_set *bset, + struct isl_basic_set *context) +{ + return bset_from_bmap(isl_basic_map_gist(bset_to_bmap(bset), + bset_to_bmap(context))); +} + +__isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *context) +{ + return set_from_map(isl_map_gist_basic_map(set_to_map(set), + bset_to_bmap(context))); +} + +__isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *context) +{ + isl_space *space = isl_set_get_space(set); + isl_basic_set *dom_context = isl_basic_set_universe(space); + dom_context = isl_basic_set_intersect_params(dom_context, context); + return isl_set_gist_basic_set(set, dom_context); +} + +__isl_give isl_set *isl_set_gist(__isl_take isl_set *set, + __isl_take isl_set *context) +{ + return set_from_map(isl_map_gist(set_to_map(set), set_to_map(context))); +} + +/* Compute the gist of "bmap" with respect to the constraints "context" + * on the domain. + */ +__isl_give isl_basic_map *isl_basic_map_gist_domain( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *context) +{ + isl_space *space = isl_basic_map_get_space(bmap); + isl_basic_map *bmap_context = isl_basic_map_universe(space); + + bmap_context = isl_basic_map_intersect_domain(bmap_context, context); + return isl_basic_map_gist(bmap, bmap_context); +} + +__isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map, + __isl_take isl_set *context) +{ + isl_map *map_context = isl_map_universe(isl_map_get_space(map)); + map_context = isl_map_intersect_domain(map_context, context); + return isl_map_gist(map, map_context); +} + +__isl_give isl_map *isl_map_gist_range(__isl_take isl_map *map, + __isl_take isl_set *context) +{ + isl_map *map_context = isl_map_universe(isl_map_get_space(map)); + map_context = isl_map_intersect_range(map_context, context); + return isl_map_gist(map, map_context); +} + +__isl_give isl_map *isl_map_gist_params(__isl_take isl_map *map, + __isl_take isl_set *context) +{ + isl_map *map_context = isl_map_universe(isl_map_get_space(map)); + map_context = isl_map_intersect_params(map_context, context); + return isl_map_gist(map, map_context); +} + +__isl_give isl_set *isl_set_gist_params(__isl_take isl_set *set, + __isl_take isl_set *context) +{ + return isl_map_gist_params(set, context); +} + +/* Quick check to see if two basic maps are disjoint. + * In particular, we reduce the equalities and inequalities of + * one basic map in the context of the equalities of the other + * basic map and check if we get a contradiction. + */ +isl_bool 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; + unsigned total; + int i; + + if (!bmap1 || !bmap2) + return isl_bool_error; + isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim), + return isl_bool_error); + if (bmap1->n_div || bmap2->n_div) + return isl_bool_false; + if (!bmap1->n_eq && !bmap2->n_eq) + return isl_bool_false; + + total = isl_space_dim(bmap1->dim, isl_dim_all); + if (total == 0) + return isl_bool_false; + v = isl_vec_alloc(bmap1->ctx, 1 + total); + if (!v) + goto error; + elim = isl_alloc_array(bmap1->ctx, int, total); + if (!elim) + goto error; + compute_elimination_index(bmap1, elim); + for (i = 0; i < bmap2->n_eq; ++i) { + int reduced; + reduced = reduced_using_equalities(v->block.data, bmap2->eq[i], + bmap1, elim); + if (reduced && !isl_int_is_zero(v->block.data[0]) && + isl_seq_first_non_zero(v->block.data + 1, total) == -1) + goto disjoint; + } + for (i = 0; i < bmap2->n_ineq; ++i) { + int reduced; + reduced = reduced_using_equalities(v->block.data, + bmap2->ineq[i], bmap1, elim); + if (reduced && isl_int_is_neg(v->block.data[0]) && + isl_seq_first_non_zero(v->block.data + 1, total) == -1) + goto disjoint; + } + compute_elimination_index(bmap2, elim); + for (i = 0; i < bmap1->n_ineq; ++i) { + int reduced; + reduced = reduced_using_equalities(v->block.data, + bmap1->ineq[i], bmap2, elim); + if (reduced && isl_int_is_neg(v->block.data[0]) && + isl_seq_first_non_zero(v->block.data + 1, total) == -1) + goto disjoint; + } + isl_vec_free(v); + free(elim); + return isl_bool_false; +disjoint: + isl_vec_free(v); + free(elim); + return isl_bool_true; +error: + isl_vec_free(v); + free(elim); + return isl_bool_error; +} + +int isl_basic_set_plain_is_disjoint(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2) +{ + return isl_basic_map_plain_is_disjoint(bset_to_bmap(bset1), + bset_to_bmap(bset2)); +} + +/* Does "test" hold for all pairs of basic maps in "map1" and "map2"? + */ +static isl_bool all_pairs(__isl_keep isl_map *map1, __isl_keep isl_map *map2, + isl_bool (*test)(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2)) +{ + int i, j; + + if (!map1 || !map2) + return isl_bool_error; + + for (i = 0; i < map1->n; ++i) { + for (j = 0; j < map2->n; ++j) { + isl_bool d = test(map1->p[i], map2->p[j]); + if (d != isl_bool_true) + return d; + } + } + + return isl_bool_true; +} + +/* Are "map1" and "map2" obviously disjoint, based on information + * that can be derived without looking at the individual basic maps? + * + * In particular, if one of them is empty or if they live in different spaces + * (ignoring parameters), then they are clearly disjoint. + */ +static isl_bool isl_map_plain_is_disjoint_global(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + isl_bool disjoint; + isl_bool match; + + if (!map1 || !map2) + return isl_bool_error; + + disjoint = isl_map_plain_is_empty(map1); + if (disjoint < 0 || disjoint) + return disjoint; + + disjoint = isl_map_plain_is_empty(map2); + if (disjoint < 0 || disjoint) + return disjoint; + + match = isl_space_tuple_is_equal(map1->dim, isl_dim_in, + map2->dim, isl_dim_in); + if (match < 0 || !match) + return match < 0 ? isl_bool_error : isl_bool_true; + + match = isl_space_tuple_is_equal(map1->dim, isl_dim_out, + map2->dim, isl_dim_out); + if (match < 0 || !match) + return match < 0 ? isl_bool_error : isl_bool_true; + + return isl_bool_false; +} + +/* Are "map1" and "map2" obviously disjoint? + * + * If one of them is empty or if they live in different spaces (ignoring + * parameters), then they are clearly disjoint. + * This is checked by isl_map_plain_is_disjoint_global. + * + * If they have different parameters, then we skip any further tests. + * + * If they are obviously equal, but not obviously empty, then we will + * not be able to detect if they are disjoint. + * + * Otherwise we check if each basic map in "map1" is obviously disjoint + * from each basic map in "map2". + */ +isl_bool isl_map_plain_is_disjoint(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + isl_bool disjoint; + isl_bool intersect; + isl_bool match; + + disjoint = isl_map_plain_is_disjoint_global(map1, map2); + if (disjoint < 0 || disjoint) + return disjoint; + + match = isl_map_has_equal_params(map1, map2); + if (match < 0 || !match) + return match < 0 ? isl_bool_error : isl_bool_false; + + intersect = isl_map_plain_is_equal(map1, map2); + if (intersect < 0 || intersect) + return intersect < 0 ? isl_bool_error : isl_bool_false; + + return all_pairs(map1, map2, &isl_basic_map_plain_is_disjoint); +} + +/* Are "map1" and "map2" disjoint? + * The parameters are assumed to have been aligned. + * + * In particular, check whether all pairs of basic maps are disjoint. + */ +static isl_bool isl_map_is_disjoint_aligned(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + return all_pairs(map1, map2, &isl_basic_map_is_disjoint); +} + +/* Are "map1" and "map2" disjoint? + * + * They are disjoint if they are "obviously disjoint" or if one of them + * is empty. Otherwise, they are not disjoint if one of them is universal. + * If the two inputs are (obviously) equal and not empty, then they are + * not disjoint. + * If none of these cases apply, then check if all pairs of basic maps + * are disjoint after aligning the parameters. + */ +isl_bool isl_map_is_disjoint(__isl_keep isl_map *map1, __isl_keep isl_map *map2) +{ + isl_bool disjoint; + isl_bool intersect; + + disjoint = isl_map_plain_is_disjoint_global(map1, map2); + if (disjoint < 0 || disjoint) + return disjoint; + + disjoint = isl_map_is_empty(map1); + if (disjoint < 0 || disjoint) + return disjoint; + + disjoint = isl_map_is_empty(map2); + if (disjoint < 0 || disjoint) + return disjoint; + + intersect = isl_map_plain_is_universe(map1); + if (intersect < 0 || intersect) + return intersect < 0 ? isl_bool_error : isl_bool_false; + + intersect = isl_map_plain_is_universe(map2); + if (intersect < 0 || intersect) + return intersect < 0 ? isl_bool_error : isl_bool_false; + + intersect = isl_map_plain_is_equal(map1, map2); + if (intersect < 0 || intersect) + return isl_bool_not(intersect); + + return isl_map_align_params_map_map_and_test(map1, map2, + &isl_map_is_disjoint_aligned); +} + +/* Are "bmap1" and "bmap2" disjoint? + * + * They are disjoint if they are "obviously disjoint" or if one of them + * is empty. Otherwise, they are not disjoint if one of them is universal. + * If none of these cases apply, we compute the intersection and see if + * the result is empty. + */ +isl_bool isl_basic_map_is_disjoint(__isl_keep isl_basic_map *bmap1, + __isl_keep isl_basic_map *bmap2) +{ + isl_bool disjoint; + isl_bool intersect; + isl_basic_map *test; + + disjoint = isl_basic_map_plain_is_disjoint(bmap1, bmap2); + if (disjoint < 0 || disjoint) + return disjoint; + + disjoint = isl_basic_map_is_empty(bmap1); + if (disjoint < 0 || disjoint) + return disjoint; + + disjoint = isl_basic_map_is_empty(bmap2); + if (disjoint < 0 || disjoint) + return disjoint; + + intersect = isl_basic_map_plain_is_universe(bmap1); + if (intersect < 0 || intersect) + return intersect < 0 ? isl_bool_error : isl_bool_false; + + intersect = isl_basic_map_plain_is_universe(bmap2); + if (intersect < 0 || intersect) + return intersect < 0 ? isl_bool_error : isl_bool_false; + + test = isl_basic_map_intersect(isl_basic_map_copy(bmap1), + isl_basic_map_copy(bmap2)); + disjoint = isl_basic_map_is_empty(test); + isl_basic_map_free(test); + + return disjoint; +} + +/* Are "bset1" and "bset2" disjoint? + */ +isl_bool isl_basic_set_is_disjoint(__isl_keep isl_basic_set *bset1, + __isl_keep isl_basic_set *bset2) +{ + return isl_basic_map_is_disjoint(bset1, bset2); +} + +isl_bool isl_set_plain_is_disjoint(__isl_keep isl_set *set1, + __isl_keep isl_set *set2) +{ + return isl_map_plain_is_disjoint(set_to_map(set1), set_to_map(set2)); +} + +/* Are "set1" and "set2" disjoint? + */ +isl_bool isl_set_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2) +{ + return isl_map_is_disjoint(set1, set2); +} + +/* Is "v" equal to 0, 1 or -1? + */ +static int is_zero_or_one(isl_int v) +{ + return isl_int_is_zero(v) || isl_int_is_one(v) || isl_int_is_negone(v); +} + +/* 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. + * + * We first check that + * - the bounds are opposites of each other (except for the constant + * term) + * - the bounds do not reference any other div + * - no div is defined in terms of this div + * + * Let m be the size of the range allowed on the div by the bounds. + * That is, the bounds are of the form + * + * e <= a <= e + m - 1 + * + * with e some expression in the other variables. + * We look for another div b such that no third div is defined in terms + * of this second div b and such that in any constraint that contains + * a (except for the given lower and upper bound), also contains b + * with a coefficient that is m times that of b. + * That is, all constraints (except for the lower and upper bound) + * are of the form + * + * e + f (a + m b) >= 0 + * + * Furthermore, in the constraints that only contain b, the coefficient + * of b should be equal to 1 or -1. + * If so, we return b so that "a + m b" can be replaced by + * a single div "c = a + m b". + */ +static int div_find_coalesce(struct isl_basic_map *bmap, int *pairs, + unsigned div, unsigned l, unsigned u) +{ + int i, j; + unsigned dim; + int coalesce = -1; + + if (bmap->n_div <= 1) + return -1; + dim = isl_space_dim(bmap->dim, isl_dim_all); + if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim, div) != -1) + return -1; + if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim + div + 1, + bmap->n_div - div - 1) != -1) + return -1; + if (!isl_seq_is_neg(bmap->ineq[l] + 1, bmap->ineq[u] + 1, + dim + bmap->n_div)) + return -1; + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (!isl_int_is_zero(bmap->div[i][1 + 1 + dim + div])) + return -1; + } + + isl_int_add(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]); + if (isl_int_is_neg(bmap->ineq[l][0])) { + isl_int_sub(bmap->ineq[l][0], + bmap->ineq[l][0], bmap->ineq[u][0]); + bmap = isl_basic_map_copy(bmap); + bmap = isl_basic_map_set_to_empty(bmap); + isl_basic_map_free(bmap); + return -1; + } + isl_int_add_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1); + for (i = 0; i < bmap->n_div; ++i) { + if (i == div) + continue; + if (!pairs[i]) + continue; + for (j = 0; j < bmap->n_div; ++j) { + if (isl_int_is_zero(bmap->div[j][0])) + continue; + if (!isl_int_is_zero(bmap->div[j][1 + 1 + dim + i])) + break; + } + if (j < bmap->n_div) + continue; + for (j = 0; j < bmap->n_ineq; ++j) { + int valid; + if (j == l || j == u) + continue; + if (isl_int_is_zero(bmap->ineq[j][1 + dim + div])) { + if (is_zero_or_one(bmap->ineq[j][1 + dim + i])) + continue; + break; + } + if (isl_int_is_zero(bmap->ineq[j][1 + dim + i])) + break; + isl_int_mul(bmap->ineq[j][1 + dim + div], + bmap->ineq[j][1 + dim + div], + bmap->ineq[l][0]); + valid = isl_int_eq(bmap->ineq[j][1 + dim + div], + bmap->ineq[j][1 + dim + i]); + isl_int_divexact(bmap->ineq[j][1 + dim + div], + bmap->ineq[j][1 + dim + div], + bmap->ineq[l][0]); + if (!valid) + break; + } + if (j < bmap->n_ineq) + continue; + coalesce = i; + break; + } + isl_int_sub_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1); + isl_int_sub(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]); + return coalesce; +} + +/* Internal data structure used during the construction and/or evaluation of + * an inequality that ensures that a pair of bounds always allows + * for an integer value. + * + * "tab" is the tableau in which the inequality is evaluated. It may + * be NULL until it is actually needed. + * "v" contains the inequality coefficients. + * "g", "fl" and "fu" are temporary scalars used during the construction and + * evaluation. + */ +struct test_ineq_data { + struct isl_tab *tab; + isl_vec *v; + isl_int g; + isl_int fl; + isl_int fu; +}; + +/* Free all the memory allocated by the fields of "data". + */ +static void test_ineq_data_clear(struct test_ineq_data *data) +{ + isl_tab_free(data->tab); + isl_vec_free(data->v); + isl_int_clear(data->g); + isl_int_clear(data->fl); + isl_int_clear(data->fu); +} + +/* Is the inequality stored in data->v satisfied by "bmap"? + * That is, does it only attain non-negative values? + * data->tab is a tableau corresponding to "bmap". + */ +static isl_bool test_ineq_is_satisfied(__isl_keep isl_basic_map *bmap, + struct test_ineq_data *data) +{ + isl_ctx *ctx; + enum isl_lp_result res; + + ctx = isl_basic_map_get_ctx(bmap); + if (!data->tab) + data->tab = isl_tab_from_basic_map(bmap, 0); + res = isl_tab_min(data->tab, data->v->el, ctx->one, &data->g, NULL, 0); + if (res == isl_lp_error) + return isl_bool_error; + return res == isl_lp_ok && isl_int_is_nonneg(data->g); +} + +/* Given a lower and an upper bound on div i, do they always allow + * for an integer value of the given div? + * Determine this property by constructing an inequality + * such that the property is guaranteed when the inequality is nonnegative. + * The lower bound is inequality l, while the upper bound is inequality u. + * The constructed inequality is stored in data->v. + * + * Let the upper bound be + * + * -n_u a + e_u >= 0 + * + * and the lower bound + * + * n_l a + e_l >= 0 + * + * Let n_u = f_u g and n_l = f_l g, with g = gcd(n_u, n_l). + * We have + * + * - f_u e_l <= f_u f_l g a <= f_l e_u + * + * Since all variables are integer valued, this is equivalent to + * + * - f_u e_l - (f_u - 1) <= f_u f_l g a <= f_l e_u + (f_l - 1) + * + * If this interval is at least f_u f_l g, then it contains at least + * one integer value for a. + * That is, the test constraint is + * + * f_l e_u + f_u e_l + f_l - 1 + f_u - 1 + 1 >= f_u f_l g + * + * or + * + * f_l e_u + f_u e_l + f_l - 1 + f_u - 1 + 1 - f_u f_l g >= 0 + * + * If the coefficients of f_l e_u + f_u e_l have a common divisor g', + * then the constraint can be scaled down by a factor g', + * with the constant term replaced by + * floor((f_l e_{u,0} + f_u e_{l,0} + f_l - 1 + f_u - 1 + 1 - f_u f_l g)/g'). + * Note that the result of applying Fourier-Motzkin to this pair + * of constraints is + * + * f_l e_u + f_u e_l >= 0 + * + * If the constant term of the scaled down version of this constraint, + * i.e., floor((f_l e_{u,0} + f_u e_{l,0})/g') is equal to the constant + * term of the scaled down test constraint, then the test constraint + * is known to hold and no explicit evaluation is required. + * This is essentially the Omega test. + * + * If the test constraint consists of only a constant term, then + * it is sufficient to look at the sign of this constant term. + */ +static isl_bool int_between_bounds(__isl_keep isl_basic_map *bmap, int i, + int l, int u, struct test_ineq_data *data) +{ + unsigned offset, n_div; + offset = isl_basic_map_offset(bmap, isl_dim_div); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + + isl_int_gcd(data->g, + bmap->ineq[l][offset + i], bmap->ineq[u][offset + i]); + isl_int_divexact(data->fl, bmap->ineq[l][offset + i], data->g); + isl_int_divexact(data->fu, bmap->ineq[u][offset + i], data->g); + isl_int_neg(data->fu, data->fu); + isl_seq_combine(data->v->el, data->fl, bmap->ineq[u], + data->fu, bmap->ineq[l], offset + n_div); + isl_int_mul(data->g, data->g, data->fl); + isl_int_mul(data->g, data->g, data->fu); + isl_int_sub(data->g, data->g, data->fl); + isl_int_sub(data->g, data->g, data->fu); + isl_int_add_ui(data->g, data->g, 1); + isl_int_sub(data->fl, data->v->el[0], data->g); + + isl_seq_gcd(data->v->el + 1, offset - 1 + n_div, &data->g); + if (isl_int_is_zero(data->g)) + return isl_int_is_nonneg(data->fl); + if (isl_int_is_one(data->g)) { + isl_int_set(data->v->el[0], data->fl); + return test_ineq_is_satisfied(bmap, data); + } + isl_int_fdiv_q(data->fl, data->fl, data->g); + isl_int_fdiv_q(data->v->el[0], data->v->el[0], data->g); + if (isl_int_eq(data->fl, data->v->el[0])) + return isl_bool_true; + isl_int_set(data->v->el[0], data->fl); + isl_seq_scale_down(data->v->el + 1, data->v->el + 1, data->g, + offset - 1 + n_div); + + return test_ineq_is_satisfied(bmap, data); +} + +/* Remove more kinds of divs that are not strictly needed. + * In particular, if all pairs of lower and upper bounds on a div + * are such that they allow at least one integer value of the div, + * then we can eliminate the div using Fourier-Motzkin without + * introducing any spurious solutions. + * + * If at least one of the two constraints has a unit coefficient for the div, + * then the presence of such a value is guaranteed so there is no need to check. + * In particular, the value attained by the bound with unit coefficient + * can serve as this intermediate value. + */ +static __isl_give isl_basic_map *drop_more_redundant_divs( + __isl_take isl_basic_map *bmap, __isl_take int *pairs, int n) +{ + isl_ctx *ctx; + struct test_ineq_data data = { NULL, NULL }; + unsigned off, n_div; + int remove = -1; + + isl_int_init(data.g); + isl_int_init(data.fl); + isl_int_init(data.fu); + + if (!bmap) + goto error; + + ctx = isl_basic_map_get_ctx(bmap); + off = isl_basic_map_offset(bmap, isl_dim_div); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + data.v = isl_vec_alloc(ctx, off + n_div); + if (!data.v) + goto error; + + while (n > 0) { + int i, l, u; + int best = -1; + isl_bool has_int; + + for (i = 0; i < n_div; ++i) { + if (!pairs[i]) + continue; + if (best >= 0 && pairs[best] <= pairs[i]) + continue; + best = i; + } + + i = best; + for (l = 0; l < bmap->n_ineq; ++l) { + if (!isl_int_is_pos(bmap->ineq[l][off + i])) + continue; + if (isl_int_is_one(bmap->ineq[l][off + i])) + continue; + for (u = 0; u < bmap->n_ineq; ++u) { + if (!isl_int_is_neg(bmap->ineq[u][off + i])) + continue; + if (isl_int_is_negone(bmap->ineq[u][off + i])) + continue; + has_int = int_between_bounds(bmap, i, l, u, + &data); + if (has_int < 0) + goto error; + if (data.tab && data.tab->empty) + break; + if (!has_int) + break; + } + if (u < bmap->n_ineq) + break; + } + if (data.tab && data.tab->empty) { + bmap = isl_basic_map_set_to_empty(bmap); + break; + } + if (l == bmap->n_ineq) { + remove = i; + break; + } + pairs[i] = 0; + --n; + } + + test_ineq_data_clear(&data); + + free(pairs); + + if (remove < 0) + return bmap; + + bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, remove, 1); + return isl_basic_map_drop_redundant_divs(bmap); +error: + free(pairs); + isl_basic_map_free(bmap); + test_ineq_data_clear(&data); + return NULL; +} + +/* Given a pair of divs div1 and div2 such that, except for the lower bound l + * and the upper bound u, div1 always occurs together with div2 in the form + * (div1 + m div2), where m is the constant range on the variable div1 + * allowed by l and u, replace the pair div1 and div2 by a single + * div that is equal to div1 + m div2. + * + * The new div will appear in the location that contains div2. + * We need to modify all constraints that contain + * div2 = (div - div1) / m + * The coefficient of div2 is known to be equal to 1 or -1. + * (If a constraint does not contain div2, it will also not contain div1.) + * If the constraint also contains div1, then we know they appear + * as f (div1 + m div2) and we can simply replace (div1 + m div2) by div, + * i.e., the coefficient of div is f. + * + * Otherwise, we first need to introduce div1 into the constraint. + * Let l be + * + * div1 + f >=0 + * + * and u + * + * -div1 + f' >= 0 + * + * A lower bound on div2 + * + * div2 + t >= 0 + * + * can be replaced by + * + * m div2 + div1 + m t + f >= 0 + * + * An upper bound + * + * -div2 + t >= 0 + * + * can be replaced by + * + * -(m div2 + div1) + m t + f' >= 0 + * + * These constraint are those that we would obtain from eliminating + * div1 using Fourier-Motzkin. + * + * After all constraints have been modified, we drop the lower and upper + * bound and then drop div1. + * Since the new div is only placed in the same location that used + * to store div2, but otherwise has a different meaning, any possible + * explicit representation of the original div2 is removed. + */ +static __isl_give isl_basic_map *coalesce_divs(__isl_take isl_basic_map *bmap, + unsigned div1, unsigned div2, unsigned l, unsigned u) +{ + isl_ctx *ctx; + isl_int m; + unsigned dim, total; + int i; + + ctx = isl_basic_map_get_ctx(bmap); + + dim = isl_space_dim(bmap->dim, isl_dim_all); + total = 1 + dim + bmap->n_div; + + isl_int_init(m); + isl_int_add(m, bmap->ineq[l][0], bmap->ineq[u][0]); + isl_int_add_ui(m, m, 1); + + for (i = 0; i < bmap->n_ineq; ++i) { + if (i == l || i == u) + continue; + if (isl_int_is_zero(bmap->ineq[i][1 + dim + div2])) + continue; + if (isl_int_is_zero(bmap->ineq[i][1 + dim + div1])) { + if (isl_int_is_pos(bmap->ineq[i][1 + dim + div2])) + isl_seq_combine(bmap->ineq[i], m, bmap->ineq[i], + ctx->one, bmap->ineq[l], total); + else + isl_seq_combine(bmap->ineq[i], m, bmap->ineq[i], + ctx->one, bmap->ineq[u], total); + } + isl_int_set(bmap->ineq[i][1 + dim + div2], + bmap->ineq[i][1 + dim + div1]); + isl_int_set_si(bmap->ineq[i][1 + dim + div1], 0); + } + + isl_int_clear(m); + if (l > u) { + isl_basic_map_drop_inequality(bmap, l); + isl_basic_map_drop_inequality(bmap, u); + } else { + isl_basic_map_drop_inequality(bmap, u); + isl_basic_map_drop_inequality(bmap, l); + } + bmap = isl_basic_map_mark_div_unknown(bmap, div2); + bmap = isl_basic_map_drop_div(bmap, div1); + return bmap; +} + +/* First check if we can coalesce any pair of divs and + * then continue with dropping more redundant divs. + * + * We loop over all pairs of lower and upper bounds on a div + * with coefficient 1 and -1, respectively, check if there + * is any other div "c" with which we can coalesce the div + * and if so, perform the coalescing. + */ +static __isl_give isl_basic_map *coalesce_or_drop_more_redundant_divs( + __isl_take isl_basic_map *bmap, int *pairs, int n) +{ + int i, l, u; + unsigned dim; + + dim = isl_space_dim(bmap->dim, isl_dim_all); + + for (i = 0; i < bmap->n_div; ++i) { + if (!pairs[i]) + continue; + for (l = 0; l < bmap->n_ineq; ++l) { + if (!isl_int_is_one(bmap->ineq[l][1 + dim + i])) + continue; + for (u = 0; u < bmap->n_ineq; ++u) { + int c; + + if (!isl_int_is_negone(bmap->ineq[u][1+dim+i])) + continue; + c = div_find_coalesce(bmap, pairs, i, l, u); + if (c < 0) + continue; + free(pairs); + bmap = coalesce_divs(bmap, i, c, l, u); + return isl_basic_map_drop_redundant_divs(bmap); + } + } + } + + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) { + free(pairs); + return bmap; + } + + return drop_more_redundant_divs(bmap, pairs, n); +} + +/* Are the "n" coefficients starting at "first" of inequality constraints + * "i" and "j" of "bmap" equal to each other? + */ +static int is_parallel_part(__isl_keep isl_basic_map *bmap, int i, int j, + int first, int n) +{ + return isl_seq_eq(bmap->ineq[i] + first, bmap->ineq[j] + first, n); +} + +/* Are the "n" coefficients starting at "first" of inequality constraints + * "i" and "j" of "bmap" opposite to each other? + */ +static int is_opposite_part(__isl_keep isl_basic_map *bmap, int i, int j, + int first, int n) +{ + return isl_seq_is_neg(bmap->ineq[i] + first, bmap->ineq[j] + first, n); +} + +/* Are inequality constraints "i" and "j" of "bmap" opposite to each other, + * apart from the constant term? + */ +static isl_bool is_opposite(__isl_keep isl_basic_map *bmap, int i, int j) +{ + unsigned total; + + total = isl_basic_map_dim(bmap, isl_dim_all); + return is_opposite_part(bmap, i, j, 1, total); +} + +/* Are inequality constraints "i" and "j" of "bmap" equal to each other, + * apart from the constant term and the coefficient at position "pos"? + */ +static int is_parallel_except(__isl_keep isl_basic_map *bmap, int i, int j, + int pos) +{ + unsigned total; + + total = isl_basic_map_dim(bmap, isl_dim_all); + return is_parallel_part(bmap, i, j, 1, pos - 1) && + is_parallel_part(bmap, i, j, pos + 1, total - pos); +} + +/* Are inequality constraints "i" and "j" of "bmap" opposite to each other, + * apart from the constant term and the coefficient at position "pos"? + */ +static int is_opposite_except(__isl_keep isl_basic_map *bmap, int i, int j, + int pos) +{ + unsigned total; + + total = isl_basic_map_dim(bmap, isl_dim_all); + return is_opposite_part(bmap, i, j, 1, pos - 1) && + is_opposite_part(bmap, i, j, pos + 1, total - pos); +} + +/* Restart isl_basic_map_drop_redundant_divs after "bmap" has + * been modified, simplying it if "simplify" is set. + * Free the temporary data structure "pairs" that was associated + * to the old version of "bmap". + */ +static __isl_give isl_basic_map *drop_redundant_divs_again( + __isl_take isl_basic_map *bmap, __isl_take int *pairs, int simplify) +{ + if (simplify) + bmap = isl_basic_map_simplify(bmap); + free(pairs); + return isl_basic_map_drop_redundant_divs(bmap); +} + +/* Is "div" the single unknown existentially quantified variable + * in inequality constraint "ineq" of "bmap"? + * "div" is known to have a non-zero coefficient in "ineq". + */ +static isl_bool single_unknown(__isl_keep isl_basic_map *bmap, int ineq, + int div) +{ + int i; + unsigned n_div, o_div; + isl_bool known; + + known = isl_basic_map_div_is_known(bmap, div); + if (known < 0 || known) + return isl_bool_not(known); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + if (n_div == 1) + return isl_bool_true; + o_div = isl_basic_map_offset(bmap, isl_dim_div); + for (i = 0; i < n_div; ++i) { + isl_bool known; + + if (i == div) + continue; + if (isl_int_is_zero(bmap->ineq[ineq][o_div + i])) + continue; + known = isl_basic_map_div_is_known(bmap, i); + if (known < 0 || !known) + return known; + } + + return isl_bool_true; +} + +/* Does integer division "div" have coefficient 1 in inequality constraint + * "ineq" of "map"? + */ +static isl_bool has_coef_one(__isl_keep isl_basic_map *bmap, int div, int ineq) +{ + unsigned o_div; + + o_div = isl_basic_map_offset(bmap, isl_dim_div); + if (isl_int_is_one(bmap->ineq[ineq][o_div + div])) + return isl_bool_true; + + return isl_bool_false; +} + +/* Turn inequality constraint "ineq" of "bmap" into an equality and + * then try and drop redundant divs again, + * freeing the temporary data structure "pairs" that was associated + * to the old version of "bmap". + */ +static __isl_give isl_basic_map *set_eq_and_try_again( + __isl_take isl_basic_map *bmap, int ineq, __isl_take int *pairs) +{ + bmap = isl_basic_map_cow(bmap); + isl_basic_map_inequality_to_equality(bmap, ineq); + return drop_redundant_divs_again(bmap, pairs, 1); +} + +/* Drop the integer division at position "div", along with the two + * inequality constraints "ineq1" and "ineq2" in which it appears + * from "bmap" and then try and drop redundant divs again, + * freeing the temporary data structure "pairs" that was associated + * to the old version of "bmap". + */ +static __isl_give isl_basic_map *drop_div_and_try_again( + __isl_take isl_basic_map *bmap, int div, int ineq1, int ineq2, + __isl_take int *pairs) +{ + if (ineq1 > ineq2) { + isl_basic_map_drop_inequality(bmap, ineq1); + isl_basic_map_drop_inequality(bmap, ineq2); + } else { + isl_basic_map_drop_inequality(bmap, ineq2); + isl_basic_map_drop_inequality(bmap, ineq1); + } + bmap = isl_basic_map_drop_div(bmap, div); + return drop_redundant_divs_again(bmap, pairs, 0); +} + +/* Given two inequality constraints + * + * f(x) + n d + c >= 0, (ineq) + * + * with d the variable at position "pos", and + * + * f(x) + c0 >= 0, (lower) + * + * compute the maximal value of the lower bound ceil((-f(x) - c)/n) + * determined by the first constraint. + * That is, store + * + * ceil((c0 - c)/n) + * + * in *l. + */ +static void lower_bound_from_parallel(__isl_keep isl_basic_map *bmap, + int ineq, int lower, int pos, isl_int *l) +{ + isl_int_neg(*l, bmap->ineq[ineq][0]); + isl_int_add(*l, *l, bmap->ineq[lower][0]); + isl_int_cdiv_q(*l, *l, bmap->ineq[ineq][pos]); +} + +/* Given two inequality constraints + * + * f(x) + n d + c >= 0, (ineq) + * + * with d the variable at position "pos", and + * + * -f(x) - c0 >= 0, (upper) + * + * compute the minimal value of the lower bound ceil((-f(x) - c)/n) + * determined by the first constraint. + * That is, store + * + * ceil((-c1 - c)/n) + * + * in *u. + */ +static void lower_bound_from_opposite(__isl_keep isl_basic_map *bmap, + int ineq, int upper, int pos, isl_int *u) +{ + isl_int_neg(*u, bmap->ineq[ineq][0]); + isl_int_sub(*u, *u, bmap->ineq[upper][0]); + isl_int_cdiv_q(*u, *u, bmap->ineq[ineq][pos]); +} + +/* Given a lower bound constraint "ineq" on "div" in "bmap", + * does the corresponding lower bound have a fixed value in "bmap"? + * + * In particular, "ineq" is of the form + * + * f(x) + n d + c >= 0 + * + * with n > 0, c the constant term and + * d the existentially quantified variable "div". + * That is, the lower bound is + * + * ceil((-f(x) - c)/n) + * + * Look for a pair of constraints + * + * f(x) + c0 >= 0 + * -f(x) + c1 >= 0 + * + * i.e., -c1 <= -f(x) <= c0, that fix ceil((-f(x) - c)/n) to a constant value. + * That is, check that + * + * ceil((-c1 - c)/n) = ceil((c0 - c)/n) + * + * If so, return the index of inequality f(x) + c0 >= 0. + * Otherwise, return -1. + */ +static int lower_bound_is_cst(__isl_keep isl_basic_map *bmap, int div, int ineq) +{ + int i; + int lower = -1, upper = -1; + unsigned o_div; + isl_int l, u; + int equal; + + o_div = isl_basic_map_offset(bmap, isl_dim_div); + for (i = 0; i < bmap->n_ineq && (lower < 0 || upper < 0); ++i) { + if (i == ineq) + continue; + if (!isl_int_is_zero(bmap->ineq[i][o_div + div])) + continue; + if (lower < 0 && + is_parallel_except(bmap, ineq, i, o_div + div)) { + lower = i; + continue; + } + if (upper < 0 && + is_opposite_except(bmap, ineq, i, o_div + div)) { + upper = i; + } + } + + if (lower < 0 || upper < 0) + return -1; + + isl_int_init(l); + isl_int_init(u); + + lower_bound_from_parallel(bmap, ineq, lower, o_div + div, &l); + lower_bound_from_opposite(bmap, ineq, upper, o_div + div, &u); + + equal = isl_int_eq(l, u); + + isl_int_clear(l); + isl_int_clear(u); + + return equal ? lower : -1; +} + +/* Given a lower bound constraint "ineq" on the existentially quantified + * variable "div", such that the corresponding lower bound has + * a fixed value in "bmap", assign this fixed value to the variable and + * then try and drop redundant divs again, + * freeing the temporary data structure "pairs" that was associated + * to the old version of "bmap". + * "lower" determines the constant value for the lower bound. + * + * In particular, "ineq" is of the form + * + * f(x) + n d + c >= 0, + * + * while "lower" is of the form + * + * f(x) + c0 >= 0 + * + * The lower bound is ceil((-f(x) - c)/n) and its constant value + * is ceil((c0 - c)/n). + */ +static __isl_give isl_basic_map *fix_cst_lower(__isl_take isl_basic_map *bmap, + int div, int ineq, int lower, int *pairs) +{ + isl_int c; + unsigned o_div; + + isl_int_init(c); + + o_div = isl_basic_map_offset(bmap, isl_dim_div); + lower_bound_from_parallel(bmap, ineq, lower, o_div + div, &c); + bmap = isl_basic_map_fix(bmap, isl_dim_div, div, c); + free(pairs); + + isl_int_clear(c); + + return isl_basic_map_drop_redundant_divs(bmap); +} + +/* Remove divs that are not strictly needed based on the inequality + * constraints. + * In particular, if a div only occurs positively (or negatively) + * in constraints, then it can simply be dropped. + * Also, if a div occurs in only two constraints and if moreover + * those two constraints are opposite to each other, except for the constant + * term and if the sum of the constant terms is such that for any value + * of the other values, there is always at least one integer value of the + * div, i.e., if one plus this sum is greater than or equal to + * the (absolute value) of the coefficient of the div in the constraints, + * then we can also simply drop the div. + * + * If an existentially quantified variable does not have an explicit + * representation, appears in only a single lower bound that does not + * involve any other such existentially quantified variables and appears + * in this lower bound with coefficient 1, + * then fix the variable to the value of the lower bound. That is, + * turn the inequality into an equality. + * If for any value of the other variables, there is any value + * for the existentially quantified variable satisfying the constraints, + * then this lower bound also satisfies the constraints. + * It is therefore safe to pick this lower bound. + * + * The same reasoning holds even if the coefficient is not one. + * However, fixing the variable to the value of the lower bound may + * in general introduce an extra integer division, in which case + * it may be better to pick another value. + * If this integer division has a known constant value, then plugging + * in this constant value removes the existentially quantified variable + * completely. In particular, if the lower bound is of the form + * ceil((-f(x) - c)/n) and there are two constraints, f(x) + c0 >= 0 and + * -f(x) + c1 >= 0 such that ceil((-c1 - c)/n) = ceil((c0 - c)/n), + * then the existentially quantified variable can be assigned this + * shared value. + * + * We skip divs that appear in equalities or in the definition of other divs. + * Divs that appear in the definition of other divs usually occur in at least + * 4 constraints, but the constraints may have been simplified. + * + * If any divs are left after these simple checks then we move on + * to more complicated cases in drop_more_redundant_divs. + */ +static __isl_give isl_basic_map *isl_basic_map_drop_redundant_divs_ineq( + __isl_take isl_basic_map *bmap) +{ + int i, j; + unsigned off; + int *pairs = NULL; + int n = 0; + + if (!bmap) + goto error; + if (bmap->n_div == 0) + return bmap; + + off = isl_space_dim(bmap->dim, isl_dim_all); + pairs = isl_calloc_array(bmap->ctx, int, bmap->n_div); + if (!pairs) + goto error; + + for (i = 0; i < bmap->n_div; ++i) { + int pos, neg; + int last_pos, last_neg; + int redundant; + int defined; + isl_bool opp, set_div; + + defined = !isl_int_is_zero(bmap->div[i][0]); + for (j = i; j < bmap->n_div; ++j) + if (!isl_int_is_zero(bmap->div[j][1 + 1 + off + i])) + break; + if (j < bmap->n_div) + continue; + for (j = 0; j < bmap->n_eq; ++j) + if (!isl_int_is_zero(bmap->eq[j][1 + off + i])) + break; + if (j < bmap->n_eq) + continue; + ++n; + pos = neg = 0; + for (j = 0; j < bmap->n_ineq; ++j) { + if (isl_int_is_pos(bmap->ineq[j][1 + off + i])) { + last_pos = j; + ++pos; + } + if (isl_int_is_neg(bmap->ineq[j][1 + off + i])) { + last_neg = j; + ++neg; + } + } + pairs[i] = pos * neg; + if (pairs[i] == 0) { + for (j = bmap->n_ineq - 1; j >= 0; --j) + if (!isl_int_is_zero(bmap->ineq[j][1+off+i])) + isl_basic_map_drop_inequality(bmap, j); + bmap = isl_basic_map_drop_div(bmap, i); + return drop_redundant_divs_again(bmap, pairs, 0); + } + if (pairs[i] != 1) + opp = isl_bool_false; + else + opp = is_opposite(bmap, last_pos, last_neg); + if (opp < 0) + goto error; + if (!opp) { + int lower; + isl_bool single, one; + + if (pos != 1) + continue; + single = single_unknown(bmap, last_pos, i); + if (single < 0) + goto error; + if (!single) + continue; + one = has_coef_one(bmap, i, last_pos); + if (one < 0) + goto error; + if (one) + return set_eq_and_try_again(bmap, last_pos, + pairs); + lower = lower_bound_is_cst(bmap, i, last_pos); + if (lower >= 0) + return fix_cst_lower(bmap, i, last_pos, lower, + pairs); + continue; + } + + isl_int_add(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]); + isl_int_add_ui(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][0], 1); + redundant = isl_int_ge(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][1+off+i]); + isl_int_sub_ui(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][0], 1); + isl_int_sub(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]); + if (redundant) + return drop_div_and_try_again(bmap, i, + last_pos, last_neg, pairs); + if (defined) + set_div = isl_bool_false; + else + set_div = ok_to_set_div_from_bound(bmap, i, last_pos); + if (set_div < 0) + return isl_basic_map_free(bmap); + if (set_div) { + bmap = set_div_from_lower_bound(bmap, i, last_pos); + return drop_redundant_divs_again(bmap, pairs, 1); + } + pairs[i] = 0; + --n; + } + + if (n > 0) + return coalesce_or_drop_more_redundant_divs(bmap, pairs, n); + + free(pairs); + return bmap; +error: + free(pairs); + isl_basic_map_free(bmap); + return NULL; +} + +/* Consider the coefficients at "c" as a row vector and replace + * them with their product with "T". "T" is assumed to be a square matrix. + */ +static isl_stat preimage(isl_int *c, __isl_keep isl_mat *T) +{ + int n; + isl_ctx *ctx; + isl_vec *v; + + if (!T) + return isl_stat_error; + n = isl_mat_rows(T); + if (isl_seq_first_non_zero(c, n) == -1) + return isl_stat_ok; + ctx = isl_mat_get_ctx(T); + v = isl_vec_alloc(ctx, n); + if (!v) + return isl_stat_error; + isl_seq_swp_or_cpy(v->el, c, n); + v = isl_vec_mat_product(v, isl_mat_copy(T)); + if (!v) + return isl_stat_error; + isl_seq_swp_or_cpy(c, v->el, n); + isl_vec_free(v); + + return isl_stat_ok; +} + +/* Plug in T for the variables in "bmap" starting at "pos". + * T is a linear unimodular matrix, i.e., without constant term. + */ +static __isl_give isl_basic_map *isl_basic_map_preimage_vars( + __isl_take isl_basic_map *bmap, unsigned pos, __isl_take isl_mat *T) +{ + int i; + unsigned n, total; + + bmap = isl_basic_map_cow(bmap); + if (!bmap || !T) + goto error; + + n = isl_mat_cols(T); + if (n != isl_mat_rows(T)) + isl_die(isl_mat_get_ctx(T), isl_error_invalid, + "expecting square matrix", goto error); + + total = isl_basic_map_dim(bmap, isl_dim_all); + if (pos + n > total || pos + n < pos) + isl_die(isl_mat_get_ctx(T), isl_error_invalid, + "invalid range", goto error); + + for (i = 0; i < bmap->n_eq; ++i) + if (preimage(bmap->eq[i] + 1 + pos, T) < 0) + goto error; + for (i = 0; i < bmap->n_ineq; ++i) + if (preimage(bmap->ineq[i] + 1 + pos, T) < 0) + goto error; + for (i = 0; i < bmap->n_div; ++i) { + if (isl_basic_map_div_is_marked_unknown(bmap, i)) + continue; + if (preimage(bmap->div[i] + 1 + 1 + pos, T) < 0) + goto error; + } + + isl_mat_free(T); + return bmap; +error: + isl_basic_map_free(bmap); + isl_mat_free(T); + return NULL; +} + +/* Remove divs that are not strictly needed. + * + * First look for an equality constraint involving two or more + * existentially quantified variables without an explicit + * representation. Replace the combination that appears + * in the equality constraint by a single existentially quantified + * variable such that the equality can be used to derive + * an explicit representation for the variable. + * If there are no more such equality constraints, then continue + * with isl_basic_map_drop_redundant_divs_ineq. + * + * In particular, if the equality constraint is of the form + * + * f(x) + \sum_i c_i a_i = 0 + * + * with a_i existentially quantified variable without explicit + * representation, then apply a transformation on the existentially + * quantified variables to turn the constraint into + * + * f(x) + g a_1' = 0 + * + * with g the gcd of the c_i. + * In order to easily identify which existentially quantified variables + * have a complete explicit representation, i.e., without being defined + * in terms of other existentially quantified variables without + * an explicit representation, the existentially quantified variables + * are first sorted. + * + * The variable transformation is computed by extending the row + * [c_1/g ... c_n/g] to a unimodular matrix, obtaining the transformation + * + * [a_1'] [c_1/g ... c_n/g] [ a_1 ] + * [a_2'] [ a_2 ] + * ... = U .... + * [a_n'] [ a_n ] + * + * with [c_1/g ... c_n/g] representing the first row of U. + * The inverse of U is then plugged into the original constraints. + * The call to isl_basic_map_simplify makes sure the explicit + * representation for a_1' is extracted from the equality constraint. + */ +__isl_give isl_basic_map *isl_basic_map_drop_redundant_divs( + __isl_take isl_basic_map *bmap) +{ + int first; + int i; + unsigned o_div, n_div; + int l; + isl_ctx *ctx; + isl_mat *T; + + if (!bmap) + return NULL; + if (isl_basic_map_divs_known(bmap)) + return isl_basic_map_drop_redundant_divs_ineq(bmap); + if (bmap->n_eq == 0) + return isl_basic_map_drop_redundant_divs_ineq(bmap); + bmap = isl_basic_map_sort_divs(bmap); + if (!bmap) + return NULL; + + first = isl_basic_map_first_unknown_div(bmap); + if (first < 0) + return isl_basic_map_free(bmap); + + o_div = isl_basic_map_offset(bmap, isl_dim_div); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + + for (i = 0; i < bmap->n_eq; ++i) { + l = isl_seq_first_non_zero(bmap->eq[i] + o_div + first, + n_div - (first)); + if (l < 0) + continue; + l += first; + if (isl_seq_first_non_zero(bmap->eq[i] + o_div + l + 1, + n_div - (l + 1)) == -1) + continue; + break; + } + if (i >= bmap->n_eq) + return isl_basic_map_drop_redundant_divs_ineq(bmap); + + ctx = isl_basic_map_get_ctx(bmap); + T = isl_mat_alloc(ctx, n_div - l, n_div - l); + if (!T) + return isl_basic_map_free(bmap); + isl_seq_cpy(T->row[0], bmap->eq[i] + o_div + l, n_div - l); + T = isl_mat_normalize_row(T, 0); + T = isl_mat_unimodular_complete(T, 1); + T = isl_mat_right_inverse(T); + + for (i = l; i < n_div; ++i) + bmap = isl_basic_map_mark_div_unknown(bmap, i); + bmap = isl_basic_map_preimage_vars(bmap, o_div - 1 + l, T); + bmap = isl_basic_map_simplify(bmap); + + return isl_basic_map_drop_redundant_divs(bmap); +} + +/* Does "bmap" satisfy any equality that involves more than 2 variables + * and/or has coefficients different from -1 and 1? + */ +static int has_multiple_var_equality(__isl_keep isl_basic_map *bmap) +{ + int i; + unsigned total; + + total = isl_basic_map_dim(bmap, isl_dim_all); + + for (i = 0; i < bmap->n_eq; ++i) { + int j, k; + + j = isl_seq_first_non_zero(bmap->eq[i] + 1, total); + if (j < 0) + continue; + if (!isl_int_is_one(bmap->eq[i][1 + j]) && + !isl_int_is_negone(bmap->eq[i][1 + j])) + return 1; + + j += 1; + k = isl_seq_first_non_zero(bmap->eq[i] + 1 + j, total - j); + if (k < 0) + continue; + j += k; + if (!isl_int_is_one(bmap->eq[i][1 + j]) && + !isl_int_is_negone(bmap->eq[i][1 + j])) + return 1; + + j += 1; + k = isl_seq_first_non_zero(bmap->eq[i] + 1 + j, total - j); + if (k >= 0) + return 1; + } + + return 0; +} + +/* Remove any common factor g from the constraint coefficients in "v". + * The constant term is stored in the first position and is replaced + * by floor(c/g). If any common factor is removed and if this results + * in a tightening of the constraint, then set *tightened. + */ +static __isl_give isl_vec *normalize_constraint(__isl_take isl_vec *v, + int *tightened) +{ + isl_ctx *ctx; + + if (!v) + return NULL; + ctx = isl_vec_get_ctx(v); + isl_seq_gcd(v->el + 1, v->size - 1, &ctx->normalize_gcd); + if (isl_int_is_zero(ctx->normalize_gcd)) + return v; + if (isl_int_is_one(ctx->normalize_gcd)) + return v; + v = isl_vec_cow(v); + if (!v) + return NULL; + if (tightened && !isl_int_is_divisible_by(v->el[0], ctx->normalize_gcd)) + *tightened = 1; + isl_int_fdiv_q(v->el[0], v->el[0], ctx->normalize_gcd); + isl_seq_scale_down(v->el + 1, v->el + 1, ctx->normalize_gcd, + v->size - 1); + return v; +} + +/* If "bmap" is an integer set that satisfies any equality involving + * more than 2 variables and/or has coefficients different from -1 and 1, + * then use variable compression to reduce the coefficients by removing + * any (hidden) common factor. + * In particular, apply the variable compression to each constraint, + * factor out any common factor in the non-constant coefficients and + * then apply the inverse of the compression. + * At the end, we mark the basic map as having reduced constants. + * If this flag is still set on the next invocation of this function, + * then we skip the computation. + * + * Removing a common factor may result in a tightening of some of + * the constraints. If this happens, then we may end up with two + * opposite inequalities that can be replaced by an equality. + * We therefore call isl_basic_map_detect_inequality_pairs, + * which checks for such pairs of inequalities as well as eliminate_divs_eq + * and isl_basic_map_gauss if such a pair was found. + * + * Note that this function may leave the result in an inconsistent state. + * In particular, the constraints may not be gaussed. + * Unfortunately, isl_map_coalesce actually depends on this inconsistent state + * for some of the test cases to pass successfully. + * Any potential modification of the representation is therefore only + * performed on a single copy of the basic map. + */ +__isl_give isl_basic_map *isl_basic_map_reduce_coefficients( + __isl_take isl_basic_map *bmap) +{ + unsigned total; + isl_ctx *ctx; + isl_vec *v; + isl_mat *eq, *T, *T2; + int i; + int tightened; + + if (!bmap) + return NULL; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS)) + return bmap; + if (isl_basic_map_is_rational(bmap)) + return bmap; + if (bmap->n_eq == 0) + return bmap; + if (!has_multiple_var_equality(bmap)) + return bmap; + + total = isl_basic_map_dim(bmap, isl_dim_all); + ctx = isl_basic_map_get_ctx(bmap); + v = isl_vec_alloc(ctx, 1 + total); + if (!v) + return isl_basic_map_free(bmap); + + eq = isl_mat_sub_alloc6(ctx, bmap->eq, 0, bmap->n_eq, 0, 1 + total); + T = isl_mat_variable_compression(eq, &T2); + if (!T || !T2) + goto error; + if (T->n_col == 0) { + isl_mat_free(T); + isl_mat_free(T2); + isl_vec_free(v); + return isl_basic_map_set_to_empty(bmap); + } + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + goto error; + + tightened = 0; + for (i = 0; i < bmap->n_ineq; ++i) { + isl_seq_cpy(v->el, bmap->ineq[i], 1 + total); + v = isl_vec_mat_product(v, isl_mat_copy(T)); + v = normalize_constraint(v, &tightened); + v = isl_vec_mat_product(v, isl_mat_copy(T2)); + if (!v) + goto error; + isl_seq_cpy(bmap->ineq[i], v->el, 1 + total); + } + + isl_mat_free(T); + isl_mat_free(T2); + isl_vec_free(v); + + ISL_F_SET(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS); + + if (tightened) { + int progress = 0; + + bmap = isl_basic_map_detect_inequality_pairs(bmap, &progress); + if (progress) { + bmap = eliminate_divs_eq(bmap, &progress); + bmap = isl_basic_map_gauss(bmap, NULL); + } + } + + return bmap; +error: + isl_mat_free(T); + isl_mat_free(T2); + isl_vec_free(v); + return isl_basic_map_free(bmap); +} + +/* Shift the integer division at position "div" of "bmap" + * by "shift" times the variable at position "pos". + * "pos" is as determined by isl_basic_map_offset, i.e., pos == 0 + * corresponds to the constant term. + * + * That is, if the integer division has the form + * + * floor(f(x)/d) + * + * then replace it by + * + * floor((f(x) + shift * d * x_pos)/d) - shift * x_pos + */ +__isl_give isl_basic_map *isl_basic_map_shift_div( + __isl_take isl_basic_map *bmap, int div, int pos, isl_int shift) +{ + int i; + unsigned total; + + if (isl_int_is_zero(shift)) + return bmap; + if (!bmap) + return NULL; + + total = isl_basic_map_dim(bmap, isl_dim_all); + total -= isl_basic_map_dim(bmap, isl_dim_div); + + isl_int_addmul(bmap->div[div][1 + pos], shift, bmap->div[div][0]); + + for (i = 0; i < bmap->n_eq; ++i) { + if (isl_int_is_zero(bmap->eq[i][1 + total + div])) + continue; + isl_int_submul(bmap->eq[i][pos], + shift, bmap->eq[i][1 + total + div]); + } + for (i = 0; i < bmap->n_ineq; ++i) { + if (isl_int_is_zero(bmap->ineq[i][1 + total + div])) + continue; + isl_int_submul(bmap->ineq[i][pos], + shift, bmap->ineq[i][1 + total + div]); + } + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_int_is_zero(bmap->div[i][1 + 1 + total + div])) + continue; + isl_int_submul(bmap->div[i][1 + pos], + shift, bmap->div[i][1 + 1 + total + div]); + } + + return bmap; +} Index: contrib/isl/isl_map_subtract.c =================================================================== --- /dev/null +++ contrib/isl/isl_map_subtract.c @@ -0,0 +1,943 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include +#include "isl_tab.h" +#include +#include + +#include +#include + +/* Expand the constraint "c" into "v". The initial "dim" dimensions + * are the same, but "v" may have more divs than "c" and the divs of "c" + * may appear in different positions in "v". + * The number of divs in "c" is given by "n_div" and the mapping + * of divs in "c" to divs in "v" is given by "div_map". + * + * Although it shouldn't happen in practice, it is theoretically + * possible that two or more divs in "c" are mapped to the same div in "v". + * These divs are then necessarily the same, so we simply add their + * coefficients. + */ +static void expand_constraint(isl_vec *v, unsigned dim, + isl_int *c, int *div_map, unsigned n_div) +{ + int i; + + isl_seq_cpy(v->el, c, 1 + dim); + isl_seq_clr(v->el + 1 + dim, v->size - (1 + dim)); + + for (i = 0; i < n_div; ++i) { + int pos = 1 + dim + div_map[i]; + isl_int_add(v->el[pos], v->el[pos], c[1 + dim + i]); + } +} + +/* Add all constraints of bmap to tab. The equalities of bmap + * are added as a pair of inequalities. + */ +static isl_stat tab_add_constraints(struct isl_tab *tab, + __isl_keep isl_basic_map *bmap, int *div_map) +{ + int i; + unsigned dim; + unsigned tab_total; + unsigned bmap_total; + isl_vec *v; + + if (!tab || !bmap) + return isl_stat_error; + + tab_total = isl_basic_map_total_dim(tab->bmap); + bmap_total = isl_basic_map_total_dim(bmap); + dim = isl_space_dim(tab->bmap->dim, isl_dim_all); + + if (isl_tab_extend_cons(tab, 2 * bmap->n_eq + bmap->n_ineq) < 0) + return isl_stat_error; + + v = isl_vec_alloc(bmap->ctx, 1 + tab_total); + if (!v) + return isl_stat_error; + + for (i = 0; i < bmap->n_eq; ++i) { + expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div); + if (isl_tab_add_ineq(tab, v->el) < 0) + goto error; + isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total); + expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div); + if (isl_tab_add_ineq(tab, v->el) < 0) + goto error; + isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total); + if (tab->empty) + break; + } + + for (i = 0; i < bmap->n_ineq; ++i) { + expand_constraint(v, dim, bmap->ineq[i], div_map, bmap->n_div); + if (isl_tab_add_ineq(tab, v->el) < 0) + goto error; + if (tab->empty) + break; + } + + isl_vec_free(v); + return isl_stat_ok; +error: + isl_vec_free(v); + return isl_stat_error; +} + +/* Add a specific constraint of bmap (or its opposite) to tab. + * The position of the constraint is specified by "c", where + * the equalities of bmap are counted twice, once for the inequality + * that is equal to the equality, and once for its negation. + * + * Each of these constraints has been added to "tab" before by + * tab_add_constraints (and later removed again), so there should + * already be a row available for the constraint. + */ +static isl_stat tab_add_constraint(struct isl_tab *tab, + __isl_keep isl_basic_map *bmap, int *div_map, int c, int oppose) +{ + unsigned dim; + unsigned tab_total; + unsigned bmap_total; + isl_vec *v; + isl_stat r; + + if (!tab || !bmap) + return isl_stat_error; + + tab_total = isl_basic_map_total_dim(tab->bmap); + bmap_total = isl_basic_map_total_dim(bmap); + dim = isl_space_dim(tab->bmap->dim, isl_dim_all); + + v = isl_vec_alloc(bmap->ctx, 1 + tab_total); + if (!v) + return isl_stat_error; + + if (c < 2 * bmap->n_eq) { + if ((c % 2) != oppose) + isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2], + 1 + bmap_total); + if (oppose) + isl_int_sub_ui(bmap->eq[c/2][0], bmap->eq[c/2][0], 1); + expand_constraint(v, dim, bmap->eq[c/2], div_map, bmap->n_div); + r = isl_tab_add_ineq(tab, v->el); + if (oppose) + isl_int_add_ui(bmap->eq[c/2][0], bmap->eq[c/2][0], 1); + if ((c % 2) != oppose) + isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2], + 1 + bmap_total); + } else { + c -= 2 * bmap->n_eq; + if (oppose) { + isl_seq_neg(bmap->ineq[c], bmap->ineq[c], + 1 + bmap_total); + isl_int_sub_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1); + } + expand_constraint(v, dim, bmap->ineq[c], div_map, bmap->n_div); + r = isl_tab_add_ineq(tab, v->el); + if (oppose) { + isl_int_add_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1); + isl_seq_neg(bmap->ineq[c], bmap->ineq[c], + 1 + bmap_total); + } + } + + isl_vec_free(v); + return r; +} + +static isl_stat tab_add_divs(struct isl_tab *tab, + __isl_keep isl_basic_map *bmap, int **div_map) +{ + int i, j; + struct isl_vec *vec; + unsigned total; + unsigned dim; + + if (!bmap) + return isl_stat_error; + if (!bmap->n_div) + return isl_stat_ok; + + if (!*div_map) + *div_map = isl_alloc_array(bmap->ctx, int, bmap->n_div); + if (!*div_map) + return isl_stat_error; + + total = isl_basic_map_total_dim(tab->bmap); + dim = total - tab->bmap->n_div; + vec = isl_vec_alloc(bmap->ctx, 2 + total + bmap->n_div); + if (!vec) + return isl_stat_error; + + for (i = 0; i < bmap->n_div; ++i) { + isl_seq_cpy(vec->el, bmap->div[i], 2 + dim); + isl_seq_clr(vec->el + 2 + dim, tab->bmap->n_div); + for (j = 0; j < i; ++j) + isl_int_set(vec->el[2 + dim + (*div_map)[j]], + bmap->div[i][2 + dim + j]); + for (j = 0; j < tab->bmap->n_div; ++j) + if (isl_seq_eq(tab->bmap->div[j], + vec->el, 2 + dim + tab->bmap->n_div)) + break; + (*div_map)[i] = j; + if (j == tab->bmap->n_div) { + vec->size = 2 + dim + tab->bmap->n_div; + if (isl_tab_add_div(tab, vec) < 0) + goto error; + } + } + + isl_vec_free(vec); + + return isl_stat_ok; +error: + isl_vec_free(vec); + + return isl_stat_error; +} + +/* Freeze all constraints of tableau tab. + */ +static int tab_freeze_constraints(struct isl_tab *tab) +{ + int i; + + for (i = 0; i < tab->n_con; ++i) + if (isl_tab_freeze_constraint(tab, i) < 0) + return -1; + + return 0; +} + +/* Check for redundant constraints starting at offset. + * Put the indices of the redundant constraints in index + * and return the number of redundant constraints. + */ +static int n_non_redundant(isl_ctx *ctx, struct isl_tab *tab, + int offset, int **index) +{ + int i, n; + int n_test = tab->n_con - offset; + + if (isl_tab_detect_redundant(tab) < 0) + return -1; + + if (n_test == 0) + return 0; + if (!*index) + *index = isl_alloc_array(ctx, int, n_test); + if (!*index) + return -1; + + for (n = 0, i = 0; i < n_test; ++i) { + int r; + r = isl_tab_is_redundant(tab, offset + i); + if (r < 0) + return -1; + if (r) + continue; + (*index)[n++] = i; + } + + return n; +} + +/* basic_map_collect_diff calls add on each of the pieces of + * the set difference between bmap and map until the add method + * return a negative value. + */ +struct isl_diff_collector { + isl_stat (*add)(struct isl_diff_collector *dc, + __isl_take isl_basic_map *bmap); +}; + +/* Compute the set difference between bmap and map and call + * dc->add on each of the piece until this function returns + * a negative value. + * Return 0 on success and -1 on error. dc->add returning + * a negative value is treated as an error, but the calling + * function can interpret the results based on the state of dc. + * + * Assumes that map has known divs. + * + * The difference is computed by a backtracking algorithm. + * Each level corresponds to a basic map in "map". + * When a node in entered for the first time, we check + * if the corresonding basic map intersects the current piece + * of "bmap". If not, we move to the next level. + * Otherwise, we split the current piece into as many + * pieces as there are non-redundant constraints of the current + * basic map in the intersection. Each of these pieces is + * handled by a child of the current node. + * In particular, if there are n non-redundant constraints, + * then for each 0 <= i < n, a piece is cut off by adding + * constraints 0 <= j < i and adding the opposite of constraint i. + * If there are no non-redundant constraints, meaning that the current + * piece is a subset of the current basic map, then we simply backtrack. + * + * In the leaves, we check if the remaining piece has any integer points + * and if so, pass it along to dc->add. As a special case, if nothing + * has been removed when we end up in a leaf, we simply pass along + * the original basic map. + */ +static isl_stat basic_map_collect_diff(__isl_take isl_basic_map *bmap, + __isl_take isl_map *map, struct isl_diff_collector *dc) +{ + int i; + int modified; + int level; + int init; + isl_bool empty; + isl_ctx *ctx; + struct isl_tab *tab = NULL; + struct isl_tab_undo **snap = NULL; + int *k = NULL; + int *n = NULL; + int **index = NULL; + int **div_map = NULL; + + empty = isl_basic_map_is_empty(bmap); + if (empty) { + isl_basic_map_free(bmap); + isl_map_free(map); + return empty < 0 ? isl_stat_error : isl_stat_ok; + } + + bmap = isl_basic_map_cow(bmap); + map = isl_map_cow(map); + + if (!bmap || !map) + goto error; + + ctx = map->ctx; + snap = isl_alloc_array(map->ctx, struct isl_tab_undo *, map->n); + k = isl_alloc_array(map->ctx, int, map->n); + n = isl_alloc_array(map->ctx, int, map->n); + index = isl_calloc_array(map->ctx, int *, map->n); + div_map = isl_calloc_array(map->ctx, int *, map->n); + if (!snap || !k || !n || !index || !div_map) + goto error; + + bmap = isl_basic_map_order_divs(bmap); + map = isl_map_order_divs(map); + + tab = isl_tab_from_basic_map(bmap, 1); + if (!tab) + goto error; + + modified = 0; + level = 0; + init = 1; + + while (level >= 0) { + if (level >= map->n) { + int empty; + struct isl_basic_map *bm; + if (!modified) { + if (dc->add(dc, isl_basic_map_copy(bmap)) < 0) + goto error; + break; + } + bm = isl_basic_map_copy(tab->bmap); + bm = isl_basic_map_cow(bm); + bm = isl_basic_map_update_from_tab(bm, tab); + bm = isl_basic_map_simplify(bm); + bm = isl_basic_map_finalize(bm); + empty = isl_basic_map_is_empty(bm); + if (empty) + isl_basic_map_free(bm); + else if (dc->add(dc, bm) < 0) + goto error; + if (empty < 0) + goto error; + level--; + init = 0; + continue; + } + if (init) { + int offset; + struct isl_tab_undo *snap2; + snap2 = isl_tab_snap(tab); + if (tab_add_divs(tab, map->p[level], + &div_map[level]) < 0) + goto error; + offset = tab->n_con; + snap[level] = isl_tab_snap(tab); + if (tab_freeze_constraints(tab) < 0) + goto error; + if (tab_add_constraints(tab, map->p[level], + div_map[level]) < 0) + goto error; + k[level] = 0; + n[level] = 0; + if (tab->empty) { + if (isl_tab_rollback(tab, snap2) < 0) + goto error; + level++; + continue; + } + modified = 1; + n[level] = n_non_redundant(ctx, tab, offset, + &index[level]); + if (n[level] < 0) + goto error; + if (n[level] == 0) { + level--; + init = 0; + continue; + } + if (isl_tab_rollback(tab, snap[level]) < 0) + goto error; + if (tab_add_constraint(tab, map->p[level], + div_map[level], index[level][0], 1) < 0) + goto error; + level++; + continue; + } else { + if (k[level] + 1 >= n[level]) { + level--; + continue; + } + if (isl_tab_rollback(tab, snap[level]) < 0) + goto error; + if (tab_add_constraint(tab, map->p[level], + div_map[level], + index[level][k[level]], 0) < 0) + goto error; + snap[level] = isl_tab_snap(tab); + k[level]++; + if (tab_add_constraint(tab, map->p[level], + div_map[level], + index[level][k[level]], 1) < 0) + goto error; + level++; + init = 1; + continue; + } + } + + isl_tab_free(tab); + free(snap); + free(n); + free(k); + for (i = 0; index && i < map->n; ++i) + free(index[i]); + free(index); + for (i = 0; div_map && i < map->n; ++i) + free(div_map[i]); + free(div_map); + + isl_basic_map_free(bmap); + isl_map_free(map); + + return isl_stat_ok; +error: + isl_tab_free(tab); + free(snap); + free(n); + free(k); + for (i = 0; index && i < map->n; ++i) + free(index[i]); + free(index); + for (i = 0; div_map && i < map->n; ++i) + free(div_map[i]); + free(div_map); + isl_basic_map_free(bmap); + isl_map_free(map); + return isl_stat_error; +} + +/* A diff collector that actually collects all parts of the + * set difference in the field diff. + */ +struct isl_subtract_diff_collector { + struct isl_diff_collector dc; + struct isl_map *diff; +}; + +/* isl_subtract_diff_collector callback. + */ +static isl_stat basic_map_subtract_add(struct isl_diff_collector *dc, + __isl_take isl_basic_map *bmap) +{ + struct isl_subtract_diff_collector *sdc; + sdc = (struct isl_subtract_diff_collector *)dc; + + sdc->diff = isl_map_union_disjoint(sdc->diff, + isl_map_from_basic_map(bmap)); + + return sdc->diff ? isl_stat_ok : isl_stat_error; +} + +/* Return the set difference between bmap and map. + */ +static __isl_give isl_map *basic_map_subtract(__isl_take isl_basic_map *bmap, + __isl_take isl_map *map) +{ + struct isl_subtract_diff_collector sdc; + sdc.dc.add = &basic_map_subtract_add; + sdc.diff = isl_map_empty(isl_basic_map_get_space(bmap)); + if (basic_map_collect_diff(bmap, map, &sdc.dc) < 0) { + isl_map_free(sdc.diff); + sdc.diff = NULL; + } + return sdc.diff; +} + +/* Return an empty map living in the same space as "map1" and "map2". + */ +static __isl_give isl_map *replace_pair_by_empty( __isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + isl_space *space; + + space = isl_map_get_space(map1); + isl_map_free(map1); + isl_map_free(map2); + return isl_map_empty(space); +} + +/* Return the set difference between map1 and map2. + * (U_i A_i) \ (U_j B_j) is computed as U_i (A_i \ (U_j B_j)) + * + * If "map1" and "map2" are obviously equal to each other, + * then return an empty map in the same space. + * + * If "map1" and "map2" are disjoint, then simply return "map1". + */ +static __isl_give isl_map *map_subtract( __isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + int i; + int equal, disjoint; + struct isl_map *diff; + + if (!map1 || !map2) + goto error; + + isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error); + + equal = isl_map_plain_is_equal(map1, map2); + if (equal < 0) + goto error; + if (equal) + return replace_pair_by_empty(map1, map2); + + disjoint = isl_map_is_disjoint(map1, map2); + if (disjoint < 0) + goto error; + if (disjoint) { + isl_map_free(map2); + return map1; + } + + map1 = isl_map_compute_divs(map1); + map2 = isl_map_compute_divs(map2); + if (!map1 || !map2) + goto error; + + map1 = isl_map_remove_empty_parts(map1); + map2 = isl_map_remove_empty_parts(map2); + + diff = isl_map_empty(isl_map_get_space(map1)); + for (i = 0; i < map1->n; ++i) { + struct isl_map *d; + d = basic_map_subtract(isl_basic_map_copy(map1->p[i]), + isl_map_copy(map2)); + if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT)) + diff = isl_map_union_disjoint(diff, d); + else + diff = isl_map_union(diff, d); + } + + isl_map_free(map1); + isl_map_free(map2); + + return diff; +error: + isl_map_free(map1); + isl_map_free(map2); + return NULL; +} + +__isl_give isl_map *isl_map_subtract( __isl_take isl_map *map1, + __isl_take isl_map *map2) +{ + return isl_map_align_params_map_map_and(map1, map2, &map_subtract); +} + +struct isl_set *isl_set_subtract(struct isl_set *set1, struct isl_set *set2) +{ + return set_from_map(isl_map_subtract(set_to_map(set1), + set_to_map(set2))); +} + +/* Remove the elements of "dom" from the domain of "map". + */ +static __isl_give isl_map *map_subtract_domain(__isl_take isl_map *map, + __isl_take isl_set *dom) +{ + isl_bool ok; + isl_map *ext_dom; + + ok = isl_map_compatible_domain(map, dom); + if (ok < 0) + goto error; + if (!ok) + isl_die(isl_set_get_ctx(dom), isl_error_invalid, + "incompatible spaces", goto error); + + ext_dom = isl_map_universe(isl_map_get_space(map)); + ext_dom = isl_map_intersect_domain(ext_dom, dom); + return isl_map_subtract(map, ext_dom); +error: + isl_map_free(map); + isl_set_free(dom); + return NULL; +} + +__isl_give isl_map *isl_map_subtract_domain(__isl_take isl_map *map, + __isl_take isl_set *dom) +{ + return isl_map_align_params_map_map_and(map, dom, &map_subtract_domain); +} + +/* Remove the elements of "dom" from the range of "map". + */ +static __isl_give isl_map *map_subtract_range(__isl_take isl_map *map, + __isl_take isl_set *dom) +{ + isl_bool ok; + isl_map *ext_dom; + + ok = isl_map_compatible_range(map, dom); + if (ok < 0) + goto error; + if (!ok) + isl_die(isl_set_get_ctx(dom), isl_error_invalid, + "incompatible spaces", goto error); + + ext_dom = isl_map_universe(isl_map_get_space(map)); + ext_dom = isl_map_intersect_range(ext_dom, dom); + return isl_map_subtract(map, ext_dom); +error: + isl_map_free(map); + isl_set_free(dom); + return NULL; +} + +__isl_give isl_map *isl_map_subtract_range(__isl_take isl_map *map, + __isl_take isl_set *dom) +{ + return isl_map_align_params_map_map_and(map, dom, &map_subtract_range); +} + +/* A diff collector that aborts as soon as its add function is called, + * setting empty to 0. + */ +struct isl_is_empty_diff_collector { + struct isl_diff_collector dc; + isl_bool empty; +}; + +/* isl_is_empty_diff_collector callback. + */ +static isl_stat basic_map_is_empty_add(struct isl_diff_collector *dc, + __isl_take isl_basic_map *bmap) +{ + struct isl_is_empty_diff_collector *edc; + edc = (struct isl_is_empty_diff_collector *)dc; + + edc->empty = 0; + + isl_basic_map_free(bmap); + return isl_stat_error; +} + +/* Check if bmap \ map is empty by computing this set difference + * and breaking off as soon as the difference is known to be non-empty. + */ +static isl_bool basic_map_diff_is_empty(__isl_keep isl_basic_map *bmap, + __isl_keep isl_map *map) +{ + isl_bool empty; + isl_stat r; + struct isl_is_empty_diff_collector edc; + + empty = isl_basic_map_plain_is_empty(bmap); + if (empty) + return empty; + + edc.dc.add = &basic_map_is_empty_add; + edc.empty = isl_bool_true; + r = basic_map_collect_diff(isl_basic_map_copy(bmap), + isl_map_copy(map), &edc.dc); + if (!edc.empty) + return isl_bool_false; + + return r < 0 ? isl_bool_error : isl_bool_true; +} + +/* Check if map1 \ map2 is empty by checking if the set difference is empty + * for each of the basic maps in map1. + */ +static isl_bool map_diff_is_empty(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + int i; + isl_bool is_empty = isl_bool_true; + + if (!map1 || !map2) + return isl_bool_error; + + for (i = 0; i < map1->n; ++i) { + is_empty = basic_map_diff_is_empty(map1->p[i], map2); + if (is_empty < 0 || !is_empty) + break; + } + + return is_empty; +} + +/* Return true if "bmap" contains a single element. + */ +isl_bool isl_basic_map_plain_is_singleton(__isl_keep isl_basic_map *bmap) +{ + if (!bmap) + return isl_bool_error; + if (bmap->n_div) + return isl_bool_false; + if (bmap->n_ineq) + return isl_bool_false; + return bmap->n_eq == isl_basic_map_total_dim(bmap); +} + +/* Return true if "map" contains a single element. + */ +isl_bool isl_map_plain_is_singleton(__isl_keep isl_map *map) +{ + if (!map) + return isl_bool_error; + if (map->n != 1) + return isl_bool_false; + + return isl_basic_map_plain_is_singleton(map->p[0]); +} + +/* Given a singleton basic map, extract the single element + * as an isl_point. + */ +static __isl_give isl_point *singleton_extract_point( + __isl_keep isl_basic_map *bmap) +{ + int j; + unsigned dim; + struct isl_vec *point; + isl_int m; + + if (!bmap) + return NULL; + + dim = isl_basic_map_total_dim(bmap); + isl_assert(bmap->ctx, bmap->n_eq == dim, return NULL); + point = isl_vec_alloc(bmap->ctx, 1 + dim); + if (!point) + return NULL; + + isl_int_init(m); + + isl_int_set_si(point->el[0], 1); + for (j = 0; j < bmap->n_eq; ++j) { + int i = dim - 1 - j; + isl_assert(bmap->ctx, + isl_seq_first_non_zero(bmap->eq[j] + 1, i) == -1, + goto error); + isl_assert(bmap->ctx, + isl_int_is_one(bmap->eq[j][1 + i]) || + isl_int_is_negone(bmap->eq[j][1 + i]), + goto error); + isl_assert(bmap->ctx, + isl_seq_first_non_zero(bmap->eq[j]+1+i+1, dim-i-1) == -1, + goto error); + + isl_int_gcd(m, point->el[0], bmap->eq[j][1 + i]); + isl_int_divexact(m, bmap->eq[j][1 + i], m); + isl_int_abs(m, m); + isl_seq_scale(point->el, point->el, m, 1 + i); + isl_int_divexact(m, point->el[0], bmap->eq[j][1 + i]); + isl_int_neg(m, m); + isl_int_mul(point->el[1 + i], m, bmap->eq[j][0]); + } + + isl_int_clear(m); + return isl_point_alloc(isl_basic_map_get_space(bmap), point); +error: + isl_int_clear(m); + isl_vec_free(point); + return NULL; +} + +/* Return isl_bool_true if the singleton map "map1" is a subset of "map2", + * i.e., if the single element of "map1" is also an element of "map2". + * Assumes "map2" has known divs. + */ +static isl_bool map_is_singleton_subset(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + int i; + isl_bool is_subset = isl_bool_false; + struct isl_point *point; + + if (!map1 || !map2) + return isl_bool_error; + if (map1->n != 1) + isl_die(isl_map_get_ctx(map1), isl_error_invalid, + "expecting single-disjunct input", + return isl_bool_error); + + point = singleton_extract_point(map1->p[0]); + if (!point) + return isl_bool_error; + + for (i = 0; i < map2->n; ++i) { + is_subset = isl_basic_map_contains_point(map2->p[i], point); + if (is_subset) + break; + } + + isl_point_free(point); + return is_subset; +} + +static isl_bool map_is_subset(__isl_keep isl_map *map1, + __isl_keep isl_map *map2) +{ + isl_bool is_subset = isl_bool_false; + isl_bool empty, single; + isl_bool rat1, rat2; + + if (!map1 || !map2) + return isl_bool_error; + + if (!isl_map_has_equal_space(map1, map2)) + return isl_bool_false; + + empty = isl_map_is_empty(map1); + if (empty < 0) + return isl_bool_error; + if (empty) + return isl_bool_true; + + empty = isl_map_is_empty(map2); + if (empty < 0) + return isl_bool_error; + if (empty) + return isl_bool_false; + + rat1 = isl_map_has_rational(map1); + rat2 = isl_map_has_rational(map2); + if (rat1 < 0 || rat2 < 0) + return isl_bool_error; + if (rat1 && !rat2) + return isl_bool_false; + + if (isl_map_plain_is_universe(map2)) + return isl_bool_true; + + single = isl_map_plain_is_singleton(map1); + if (single < 0) + return isl_bool_error; + map2 = isl_map_compute_divs(isl_map_copy(map2)); + if (single) { + is_subset = map_is_singleton_subset(map1, map2); + isl_map_free(map2); + return is_subset; + } + is_subset = map_diff_is_empty(map1, map2); + isl_map_free(map2); + + return is_subset; +} + +isl_bool isl_map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2) +{ + return isl_map_align_params_map_map_and_test(map1, map2, + &map_is_subset); +} + +isl_bool isl_set_is_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2) +{ + return isl_map_is_subset(set_to_map(set1), set_to_map(set2)); +} + +__isl_give isl_map *isl_map_make_disjoint(__isl_take isl_map *map) +{ + int i; + struct isl_subtract_diff_collector sdc; + sdc.dc.add = &basic_map_subtract_add; + + if (!map) + return NULL; + if (ISL_F_ISSET(map, ISL_MAP_DISJOINT)) + return map; + if (map->n <= 1) + return map; + + map = isl_map_compute_divs(map); + map = isl_map_remove_empty_parts(map); + + if (!map || map->n <= 1) + return map; + + sdc.diff = isl_map_from_basic_map(isl_basic_map_copy(map->p[0])); + + for (i = 1; i < map->n; ++i) { + struct isl_basic_map *bmap = isl_basic_map_copy(map->p[i]); + struct isl_map *copy = isl_map_copy(sdc.diff); + if (basic_map_collect_diff(bmap, copy, &sdc.dc) < 0) { + isl_map_free(sdc.diff); + sdc.diff = NULL; + break; + } + } + + isl_map_free(map); + + return sdc.diff; +} + +__isl_give isl_set *isl_set_make_disjoint(__isl_take isl_set *set) +{ + return set_from_map(isl_map_make_disjoint(set_to_map(set))); +} + +__isl_give isl_map *isl_map_complement(__isl_take isl_map *map) +{ + isl_map *universe; + + if (!map) + return NULL; + + universe = isl_map_universe(isl_map_get_space(map)); + + return isl_map_subtract(universe, map); +} + +__isl_give isl_set *isl_set_complement(__isl_take isl_set *set) +{ + return isl_map_complement(set); +} Index: contrib/isl/isl_map_to_basic_set.c =================================================================== --- /dev/null +++ contrib/isl/isl_map_to_basic_set.c @@ -0,0 +1,14 @@ +#include +#include +#include + +#define ISL_KEY isl_map +#define ISL_VAL isl_basic_set +#define ISL_HMAP_SUFFIX map_to_basic_set +#define ISL_HMAP isl_map_to_basic_set +#define ISL_KEY_IS_EQUAL isl_map_plain_is_equal +#define ISL_VAL_IS_EQUAL isl_basic_set_plain_is_equal +#define ISL_KEY_PRINT isl_printer_print_map +#define ISL_VAL_PRINT isl_printer_print_basic_set + +#include Index: contrib/isl/isl_mat.c =================================================================== --- /dev/null +++ contrib/isl/isl_mat.c @@ -0,0 +1,2099 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2014 Ecole Normale Superieure + * Copyright 2017 Sven Verdoolaege + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat) +{ + return mat ? mat->ctx : NULL; +} + +/* Return a hash value that digests "mat". + */ +uint32_t isl_mat_get_hash(__isl_keep isl_mat *mat) +{ + int i; + uint32_t hash; + + if (!mat) + return 0; + + hash = isl_hash_init(); + isl_hash_byte(hash, mat->n_row & 0xFF); + isl_hash_byte(hash, mat->n_col & 0xFF); + for (i = 0; i < mat->n_row; ++i) { + uint32_t row_hash; + + row_hash = isl_seq_get_hash(mat->row[i], mat->n_col); + isl_hash_hash(hash, row_hash); + } + + return hash; +} + +struct isl_mat *isl_mat_alloc(struct isl_ctx *ctx, + unsigned n_row, unsigned n_col) +{ + int i; + struct isl_mat *mat; + + mat = isl_alloc_type(ctx, struct isl_mat); + if (!mat) + return NULL; + + mat->row = NULL; + mat->block = isl_blk_alloc(ctx, n_row * n_col); + if (isl_blk_is_error(mat->block)) + goto error; + mat->row = isl_alloc_array(ctx, isl_int *, n_row); + if (n_row && !mat->row) + goto error; + + for (i = 0; i < n_row; ++i) + mat->row[i] = mat->block.data + i * n_col; + + mat->ctx = ctx; + isl_ctx_ref(ctx); + mat->ref = 1; + mat->n_row = n_row; + mat->n_col = n_col; + mat->max_col = n_col; + mat->flags = 0; + + return mat; +error: + isl_blk_free(ctx, mat->block); + free(mat); + return NULL; +} + +struct isl_mat *isl_mat_extend(struct isl_mat *mat, + unsigned n_row, unsigned n_col) +{ + int i; + isl_int *old; + isl_int **row; + + if (!mat) + return NULL; + + if (mat->max_col >= n_col && mat->n_row >= n_row) { + if (mat->n_col < n_col) + mat->n_col = n_col; + return mat; + } + + if (mat->max_col < n_col) { + struct isl_mat *new_mat; + + if (n_row < mat->n_row) + n_row = mat->n_row; + new_mat = isl_mat_alloc(mat->ctx, n_row, n_col); + if (!new_mat) + goto error; + for (i = 0; i < mat->n_row; ++i) + isl_seq_cpy(new_mat->row[i], mat->row[i], mat->n_col); + isl_mat_free(mat); + return new_mat; + } + + mat = isl_mat_cow(mat); + if (!mat) + goto error; + + old = mat->block.data; + mat->block = isl_blk_extend(mat->ctx, mat->block, n_row * mat->max_col); + if (isl_blk_is_error(mat->block)) + goto error; + row = isl_realloc_array(mat->ctx, mat->row, isl_int *, n_row); + if (n_row && !row) + goto error; + mat->row = row; + + for (i = 0; i < mat->n_row; ++i) + mat->row[i] = mat->block.data + (mat->row[i] - old); + for (i = mat->n_row; i < n_row; ++i) + mat->row[i] = mat->block.data + i * mat->max_col; + mat->n_row = n_row; + if (mat->n_col < n_col) + mat->n_col = n_col; + + return mat; +error: + isl_mat_free(mat); + return NULL; +} + +__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; + struct isl_mat *mat; + + mat = isl_alloc_type(ctx, struct isl_mat); + if (!mat) + return NULL; + mat->row = isl_alloc_array(ctx, isl_int *, n_row); + if (n_row && !mat->row) + goto error; + for (i = 0; i < n_row; ++i) + mat->row[i] = row[first_row+i] + first_col; + mat->ctx = ctx; + isl_ctx_ref(ctx); + mat->ref = 1; + mat->n_row = n_row; + mat->n_col = n_col; + mat->block = isl_blk_empty(); + mat->flags = ISL_MAT_BORROWED; + return mat; +error: + free(mat); + 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) +{ + int i; + + for (i = 0; i < n_row; ++i) + isl_seq_cpy(dst[i]+dst_col, src[i]+src_col, 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) +{ + int i; + + for (i = 0; i < n_row; ++i) + isl_seq_neg(dst[i]+dst_col, src[i]+src_col, n_col); +} + +__isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat) +{ + if (!mat) + return NULL; + + mat->ref++; + return mat; +} + +__isl_give isl_mat *isl_mat_dup(__isl_keep isl_mat *mat) +{ + int i; + struct isl_mat *mat2; + + if (!mat) + return NULL; + mat2 = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col); + if (!mat2) + return NULL; + for (i = 0; i < mat->n_row; ++i) + isl_seq_cpy(mat2->row[i], mat->row[i], mat->n_col); + return mat2; +} + +__isl_give isl_mat *isl_mat_cow(__isl_take isl_mat *mat) +{ + struct isl_mat *mat2; + if (!mat) + return NULL; + + if (mat->ref == 1 && !ISL_F_ISSET(mat, ISL_MAT_BORROWED)) + return mat; + + mat2 = isl_mat_dup(mat); + isl_mat_free(mat); + return mat2; +} + +__isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat) +{ + if (!mat) + return NULL; + + if (--mat->ref > 0) + return NULL; + + if (!ISL_F_ISSET(mat, ISL_MAT_BORROWED)) + isl_blk_free(mat->ctx, mat->block); + isl_ctx_deref(mat->ctx); + free(mat->row); + free(mat); + + return NULL; +} + +int isl_mat_rows(__isl_keep isl_mat *mat) +{ + return mat ? mat->n_row : -1; +} + +int isl_mat_cols(__isl_keep isl_mat *mat) +{ + return mat ? mat->n_col : -1; +} + +/* Check that "col" is a valid column position for "mat". + */ +static isl_stat check_col(__isl_keep isl_mat *mat, int col) +{ + if (!mat) + return isl_stat_error; + if (col < 0 || col >= mat->n_col) + isl_die(isl_mat_get_ctx(mat), isl_error_invalid, + "column out of range", return isl_stat_error); + return isl_stat_ok; +} + +/* Check that "row" is a valid row position for "mat". + */ +static isl_stat check_row(__isl_keep isl_mat *mat, int row) +{ + if (!mat) + return isl_stat_error; + if (row < 0 || row >= mat->n_row) + isl_die(isl_mat_get_ctx(mat), isl_error_invalid, + "row out of range", return isl_stat_error); + return isl_stat_ok; +} + +/* Check that there are "n" columns starting at position "first" in "mat". + */ +static isl_stat check_col_range(__isl_keep isl_mat *mat, unsigned first, + unsigned n) +{ + if (!mat) + return isl_stat_error; + if (first + n > mat->n_col || first + n < first) + isl_die(isl_mat_get_ctx(mat), isl_error_invalid, + "column position or range out of bounds", + return isl_stat_error); + return isl_stat_ok; +} + +/* Check that there are "n" rows starting at position "first" in "mat". + */ +static isl_stat check_row_range(__isl_keep isl_mat *mat, unsigned first, + unsigned n) +{ + if (!mat) + return isl_stat_error; + if (first + n > mat->n_row || first + n < first) + isl_die(isl_mat_get_ctx(mat), isl_error_invalid, + "row position or range out of bounds", + return isl_stat_error); + return isl_stat_ok; +} + +int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v) +{ + if (check_row(mat, row) < 0) + return -1; + if (check_col(mat, col) < 0) + return -1; + isl_int_set(*v, mat->row[row][col]); + return 0; +} + +/* Extract the element at row "row", oolumn "col" of "mat". + */ +__isl_give isl_val *isl_mat_get_element_val(__isl_keep isl_mat *mat, + int row, int col) +{ + isl_ctx *ctx; + + if (check_row(mat, row) < 0) + return NULL; + if (check_col(mat, col) < 0) + return NULL; + ctx = isl_mat_get_ctx(mat); + return isl_val_int_from_isl_int(ctx, mat->row[row][col]); +} + +__isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat, + int row, int col, isl_int v) +{ + mat = isl_mat_cow(mat); + if (check_row(mat, row) < 0) + return isl_mat_free(mat); + if (check_col(mat, col) < 0) + return isl_mat_free(mat); + isl_int_set(mat->row[row][col], v); + return mat; +} + +__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 (check_row(mat, row) < 0) + return isl_mat_free(mat); + if (check_col(mat, col) < 0) + return isl_mat_free(mat); + isl_int_set_si(mat->row[row][col], v); + return mat; +} + +/* Replace the element at row "row", column "col" of "mat" by "v". + */ +__isl_give isl_mat *isl_mat_set_element_val(__isl_take isl_mat *mat, + int row, int col, __isl_take isl_val *v) +{ + if (!v) + return isl_mat_free(mat); + if (!isl_val_is_int(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting integer value", goto error); + mat = isl_mat_set_element(mat, row, col, v->n); + isl_val_free(v); + return mat; +error: + isl_val_free(v); + return isl_mat_free(mat); +} + +__isl_give isl_mat *isl_mat_diag(isl_ctx *ctx, unsigned n_row, isl_int d) +{ + int i; + struct isl_mat *mat; + + mat = isl_mat_alloc(ctx, n_row, n_row); + if (!mat) + return NULL; + for (i = 0; i < n_row; ++i) { + isl_seq_clr(mat->row[i], i); + isl_int_set(mat->row[i][i], d); + isl_seq_clr(mat->row[i]+i+1, n_row-(i+1)); + } + + return mat; +} + +/* Create an "n_row" by "n_col" matrix with zero elements. + */ +__isl_give isl_mat *isl_mat_zero(isl_ctx *ctx, unsigned n_row, unsigned n_col) +{ + int i; + isl_mat *mat; + + mat = isl_mat_alloc(ctx, n_row, n_col); + if (!mat) + return NULL; + for (i = 0; i < n_row; ++i) + isl_seq_clr(mat->row[i], n_col); + + return mat; +} + +__isl_give isl_mat *isl_mat_identity(isl_ctx *ctx, unsigned n_row) +{ + if (!ctx) + return NULL; + return isl_mat_diag(ctx, n_row, ctx->one); +} + +/* Is "mat" a (possibly scaled) identity matrix? + */ +int isl_mat_is_scaled_identity(__isl_keep isl_mat *mat) +{ + int i; + + if (!mat) + return -1; + if (mat->n_row != mat->n_col) + return 0; + + for (i = 0; i < mat->n_row; ++i) { + if (isl_seq_first_non_zero(mat->row[i], i) != -1) + return 0; + if (isl_int_ne(mat->row[0][0], mat->row[i][i])) + return 0; + if (isl_seq_first_non_zero(mat->row[i] + i + 1, + mat->n_col - (i + 1)) != -1) + return 0; + } + + return 1; +} + +__isl_give isl_vec *isl_mat_vec_product(__isl_take isl_mat *mat, + __isl_take isl_vec *vec) +{ + int i; + struct isl_vec *prod; + + if (!mat || !vec) + goto error; + + isl_assert(mat->ctx, mat->n_col == vec->size, goto error); + + prod = isl_vec_alloc(mat->ctx, mat->n_row); + if (!prod) + goto error; + + for (i = 0; i < prod->size; ++i) + isl_seq_inner_product(mat->row[i], vec->el, vec->size, + &prod->block.data[i]); + isl_mat_free(mat); + isl_vec_free(vec); + return prod; +error: + isl_mat_free(mat); + isl_vec_free(vec); + return NULL; +} + +__isl_give isl_vec *isl_mat_vec_inverse_product(__isl_take isl_mat *mat, + __isl_take isl_vec *vec) +{ + struct isl_mat *vec_mat; + int i; + + if (!mat || !vec) + goto error; + vec_mat = isl_mat_alloc(vec->ctx, vec->size, 1); + if (!vec_mat) + goto error; + for (i = 0; i < vec->size; ++i) + isl_int_set(vec_mat->row[i][0], vec->el[i]); + vec_mat = isl_mat_inverse_product(mat, vec_mat); + isl_vec_free(vec); + if (!vec_mat) + return NULL; + vec = isl_vec_alloc(vec_mat->ctx, vec_mat->n_row); + if (vec) + for (i = 0; i < vec->size; ++i) + isl_int_set(vec->el[i], vec_mat->row[i][0]); + isl_mat_free(vec_mat); + return vec; +error: + isl_mat_free(mat); + isl_vec_free(vec); + return NULL; +} + +__isl_give isl_vec *isl_vec_mat_product(__isl_take isl_vec *vec, + __isl_take isl_mat *mat) +{ + int i, j; + struct isl_vec *prod; + + if (!mat || !vec) + goto error; + + isl_assert(mat->ctx, mat->n_row == vec->size, goto error); + + prod = isl_vec_alloc(mat->ctx, mat->n_col); + if (!prod) + goto error; + + for (i = 0; i < prod->size; ++i) { + isl_int_set_si(prod->el[i], 0); + for (j = 0; j < vec->size; ++j) + isl_int_addmul(prod->el[i], vec->el[j], mat->row[j][i]); + } + isl_mat_free(mat); + isl_vec_free(vec); + return prod; +error: + isl_mat_free(mat); + isl_vec_free(vec); + return NULL; +} + +__isl_give isl_mat *isl_mat_aff_direct_sum(__isl_take isl_mat *left, + __isl_take isl_mat *right) +{ + int i; + struct isl_mat *sum; + + if (!left || !right) + goto error; + + isl_assert(left->ctx, left->n_row == right->n_row, goto error); + isl_assert(left->ctx, left->n_row >= 1, goto error); + isl_assert(left->ctx, left->n_col >= 1, goto error); + isl_assert(left->ctx, right->n_col >= 1, goto error); + isl_assert(left->ctx, + isl_seq_first_non_zero(left->row[0]+1, left->n_col-1) == -1, + goto error); + isl_assert(left->ctx, + isl_seq_first_non_zero(right->row[0]+1, right->n_col-1) == -1, + goto error); + + sum = isl_mat_alloc(left->ctx, left->n_row, left->n_col + right->n_col - 1); + if (!sum) + goto error; + isl_int_lcm(sum->row[0][0], left->row[0][0], right->row[0][0]); + isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]); + isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]); + + isl_seq_clr(sum->row[0]+1, sum->n_col-1); + for (i = 1; i < sum->n_row; ++i) { + isl_int_mul(sum->row[i][0], left->row[0][0], left->row[i][0]); + isl_int_addmul(sum->row[i][0], + right->row[0][0], right->row[i][0]); + isl_seq_scale(sum->row[i]+1, left->row[i]+1, left->row[0][0], + left->n_col-1); + isl_seq_scale(sum->row[i]+left->n_col, + right->row[i]+1, right->row[0][0], + right->n_col-1); + } + + isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]); + isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]); + isl_mat_free(left); + isl_mat_free(right); + return sum; +error: + isl_mat_free(left); + isl_mat_free(right); + return NULL; +} + +static void exchange(struct isl_mat *M, struct isl_mat **U, + struct isl_mat **Q, unsigned row, unsigned i, unsigned j) +{ + int r; + for (r = row; r < M->n_row; ++r) + isl_int_swap(M->row[r][i], M->row[r][j]); + if (U) { + for (r = 0; r < (*U)->n_row; ++r) + isl_int_swap((*U)->row[r][i], (*U)->row[r][j]); + } + if (Q) + isl_mat_swap_rows(*Q, i, j); +} + +static void subtract(struct isl_mat *M, struct isl_mat **U, + struct isl_mat **Q, unsigned row, unsigned i, unsigned j, isl_int m) +{ + int r; + for (r = row; r < M->n_row; ++r) + isl_int_submul(M->row[r][j], m, M->row[r][i]); + if (U) { + for (r = 0; r < (*U)->n_row; ++r) + isl_int_submul((*U)->row[r][j], m, (*U)->row[r][i]); + } + if (Q) { + for (r = 0; r < (*Q)->n_col; ++r) + isl_int_addmul((*Q)->row[i][r], m, (*Q)->row[j][r]); + } +} + +static void oppose(struct isl_mat *M, struct isl_mat **U, + struct isl_mat **Q, unsigned row, unsigned col) +{ + int r; + for (r = row; r < M->n_row; ++r) + isl_int_neg(M->row[r][col], M->row[r][col]); + if (U) { + for (r = 0; r < (*U)->n_row; ++r) + isl_int_neg((*U)->row[r][col], (*U)->row[r][col]); + } + if (Q) + isl_seq_neg((*Q)->row[col], (*Q)->row[col], (*Q)->n_col); +} + +/* Given matrix M, compute + * + * M U = H + * M = H Q + * + * with U and Q unimodular matrices and H a matrix in column echelon form + * such that on each echelon row the entries in the non-echelon column + * are non-negative (if neg == 0) or non-positive (if neg == 1) + * and strictly smaller (in absolute value) than the entries in the echelon + * column. + * If U or Q are NULL, then these matrices are not computed. + */ +__isl_give isl_mat *isl_mat_left_hermite(__isl_take isl_mat *M, int neg, + __isl_give isl_mat **U, __isl_give isl_mat **Q) +{ + isl_int c; + int row, col; + + if (U) + *U = NULL; + if (Q) + *Q = NULL; + if (!M) + goto error; + M = isl_mat_cow(M); + if (!M) + goto error; + if (U) { + *U = isl_mat_identity(M->ctx, M->n_col); + if (!*U) + goto error; + } + if (Q) { + *Q = isl_mat_identity(M->ctx, M->n_col); + if (!*Q) + goto error; + } + + col = 0; + isl_int_init(c); + for (row = 0; row < M->n_row; ++row) { + int first, i, off; + first = isl_seq_abs_min_non_zero(M->row[row]+col, M->n_col-col); + if (first == -1) + continue; + first += col; + if (first != col) + exchange(M, U, Q, row, first, col); + if (isl_int_is_neg(M->row[row][col])) + oppose(M, U, Q, row, col); + first = col+1; + while ((off = isl_seq_first_non_zero(M->row[row]+first, + M->n_col-first)) != -1) { + first += off; + isl_int_fdiv_q(c, M->row[row][first], M->row[row][col]); + subtract(M, U, Q, row, col, first, c); + if (!isl_int_is_zero(M->row[row][first])) + exchange(M, U, Q, row, first, col); + else + ++first; + } + for (i = 0; i < col; ++i) { + if (isl_int_is_zero(M->row[row][i])) + continue; + if (neg) + isl_int_cdiv_q(c, M->row[row][i], M->row[row][col]); + else + isl_int_fdiv_q(c, M->row[row][i], M->row[row][col]); + if (isl_int_is_zero(c)) + continue; + subtract(M, U, Q, row, col, i, c); + } + ++col; + } + isl_int_clear(c); + + return M; +error: + if (Q) { + isl_mat_free(*Q); + *Q = NULL; + } + if (U) { + isl_mat_free(*U); + *U = NULL; + } + isl_mat_free(M); + return NULL; +} + +/* Use row "row" of "mat" to eliminate column "col" from all other rows. + */ +static __isl_give isl_mat *eliminate(__isl_take isl_mat *mat, int row, int col) +{ + int k, nr, nc; + isl_ctx *ctx; + + if (!mat) + return NULL; + + ctx = isl_mat_get_ctx(mat); + nr = isl_mat_rows(mat); + nc = isl_mat_cols(mat); + + for (k = 0; k < nr; ++k) { + if (k == row) + continue; + if (isl_int_is_zero(mat->row[k][col])) + continue; + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + isl_seq_elim(mat->row[k], mat->row[row], col, nc, NULL); + isl_seq_normalize(ctx, mat->row[k], nc); + } + + return mat; +} + +/* Perform Gaussian elimination on the rows of "mat", but start + * from the final row and the final column. + * Any zero rows that result from the elimination are removed. + * + * In particular, for each column from last to first, + * look for the last row with a non-zero coefficient in that column, + * move it last (but before other rows moved last in previous steps) and + * use it to eliminate the column from the other rows. + */ +__isl_give isl_mat *isl_mat_reverse_gauss(__isl_take isl_mat *mat) +{ + int k, row, last, nr, nc; + + if (!mat) + return NULL; + + nr = isl_mat_rows(mat); + nc = isl_mat_cols(mat); + + last = nc - 1; + for (row = nr - 1; row >= 0; --row) { + for (; last >= 0; --last) { + for (k = row; k >= 0; --k) + if (!isl_int_is_zero(mat->row[k][last])) + break; + if (k >= 0) + break; + } + if (last < 0) + break; + if (k != row) + mat = isl_mat_swap_rows(mat, k, row); + if (!mat) + return NULL; + if (isl_int_is_neg(mat->row[row][last])) + mat = isl_mat_row_neg(mat, row); + mat = eliminate(mat, row, last); + if (!mat) + return NULL; + } + mat = isl_mat_drop_rows(mat, 0, row + 1); + + return mat; +} + +/* Negate the lexicographically negative rows of "mat" such that + * all rows in the result are lexicographically non-negative. + */ +__isl_give isl_mat *isl_mat_lexnonneg_rows(__isl_take isl_mat *mat) +{ + int i, nr, nc; + + if (!mat) + return NULL; + + nr = isl_mat_rows(mat); + nc = isl_mat_cols(mat); + + for (i = 0; i < nr; ++i) { + int pos; + + pos = isl_seq_first_non_zero(mat->row[i], nc); + if (pos < 0) + continue; + if (isl_int_is_nonneg(mat->row[i][pos])) + continue; + mat = isl_mat_row_neg(mat, i); + if (!mat) + return NULL; + } + + return mat; +} + +/* Given a matrix "H" is column echelon form, what is the first + * zero column? That is how many initial columns are non-zero? + * Start looking at column "first_col" and only consider + * the columns to be of size "n_row". + * "H" is assumed to be non-NULL. + * + * Since "H" is in column echelon form, the first non-zero entry + * in a column is always in a later position compared to the previous column. + */ +static int hermite_first_zero_col(__isl_keep isl_mat *H, int first_col, + int n_row) +{ + int row, col; + + for (col = first_col, row = 0; col < H->n_col; ++col) { + for (; row < n_row; ++row) + if (!isl_int_is_zero(H->row[row][col])) + break; + if (row == n_row) + return col; + } + + return H->n_col; +} + +/* Return the rank of "mat", or -1 in case of error. + */ +int isl_mat_rank(__isl_keep isl_mat *mat) +{ + int rank; + isl_mat *H; + + H = isl_mat_left_hermite(isl_mat_copy(mat), 0, NULL, NULL); + if (!H) + return -1; + + rank = hermite_first_zero_col(H, 0, H->n_row); + isl_mat_free(H); + + return rank; +} + +__isl_give isl_mat *isl_mat_right_kernel(__isl_take isl_mat *mat) +{ + int rank; + struct isl_mat *U = NULL; + struct isl_mat *K; + + mat = isl_mat_left_hermite(mat, 0, &U, NULL); + if (!mat || !U) + goto error; + + rank = hermite_first_zero_col(mat, 0, mat->n_row); + K = isl_mat_alloc(U->ctx, U->n_row, U->n_col - rank); + if (!K) + goto error; + isl_mat_sub_copy(K->ctx, K->row, U->row, U->n_row, 0, rank, U->n_col-rank); + isl_mat_free(mat); + isl_mat_free(U); + return K; +error: + isl_mat_free(mat); + isl_mat_free(U); + return NULL; +} + +__isl_give isl_mat *isl_mat_lin_to_aff(__isl_take isl_mat *mat) +{ + int i; + struct isl_mat *mat2; + + if (!mat) + return NULL; + mat2 = isl_mat_alloc(mat->ctx, 1+mat->n_row, 1+mat->n_col); + if (!mat2) + goto error; + isl_int_set_si(mat2->row[0][0], 1); + isl_seq_clr(mat2->row[0]+1, mat->n_col); + for (i = 0; i < mat->n_row; ++i) { + isl_int_set_si(mat2->row[1+i][0], 0); + isl_seq_cpy(mat2->row[1+i]+1, mat->row[i], mat->n_col); + } + isl_mat_free(mat); + return mat2; +error: + isl_mat_free(mat); + return NULL; +} + +/* Given two matrices M1 and M2, return the block matrix + * + * [ M1 0 ] + * [ 0 M2 ] + */ +__isl_give isl_mat *isl_mat_diagonal(__isl_take isl_mat *mat1, + __isl_take isl_mat *mat2) +{ + int i; + isl_mat *mat; + + if (!mat1 || !mat2) + goto error; + + mat = isl_mat_alloc(mat1->ctx, mat1->n_row + mat2->n_row, + mat1->n_col + mat2->n_col); + if (!mat) + goto error; + for (i = 0; i < mat1->n_row; ++i) { + isl_seq_cpy(mat->row[i], mat1->row[i], mat1->n_col); + isl_seq_clr(mat->row[i] + mat1->n_col, mat2->n_col); + } + for (i = 0; i < mat2->n_row; ++i) { + isl_seq_clr(mat->row[mat1->n_row + i], mat1->n_col); + isl_seq_cpy(mat->row[mat1->n_row + i] + mat1->n_col, + mat2->row[i], mat2->n_col); + } + isl_mat_free(mat1); + isl_mat_free(mat2); + return mat; +error: + isl_mat_free(mat1); + isl_mat_free(mat2); + return NULL; +} + +static int row_first_non_zero(isl_int **row, unsigned n_row, unsigned col) +{ + int i; + + for (i = 0; i < n_row; ++i) + if (!isl_int_is_zero(row[i][col])) + return i; + return -1; +} + +static int row_abs_min_non_zero(isl_int **row, unsigned n_row, unsigned col) +{ + int i, min = row_first_non_zero(row, n_row, col); + if (min < 0) + return -1; + for (i = min + 1; i < n_row; ++i) { + if (isl_int_is_zero(row[i][col])) + continue; + if (isl_int_abs_lt(row[i][col], row[min][col])) + min = i; + } + return min; +} + +static isl_stat inv_exchange(__isl_keep isl_mat **left, + __isl_keep isl_mat **right, unsigned i, unsigned j) +{ + *left = isl_mat_swap_rows(*left, i, j); + *right = isl_mat_swap_rows(*right, i, j); + + if (!*left || !*right) + return isl_stat_error; + return isl_stat_ok; +} + +static void inv_oppose( + struct isl_mat *left, struct isl_mat *right, unsigned row) +{ + isl_seq_neg(left->row[row]+row, left->row[row]+row, left->n_col-row); + isl_seq_neg(right->row[row], right->row[row], right->n_col); +} + +static void inv_subtract(struct isl_mat *left, struct isl_mat *right, + unsigned row, unsigned i, isl_int m) +{ + isl_int_neg(m, m); + isl_seq_combine(left->row[i]+row, + left->ctx->one, left->row[i]+row, + m, left->row[row]+row, + left->n_col-row); + isl_seq_combine(right->row[i], right->ctx->one, right->row[i], + m, right->row[row], right->n_col); +} + +/* Compute inv(left)*right + */ +__isl_give isl_mat *isl_mat_inverse_product(__isl_take isl_mat *left, + __isl_take isl_mat *right) +{ + int row; + isl_int a, b; + + if (!left || !right) + goto error; + + isl_assert(left->ctx, left->n_row == left->n_col, goto error); + isl_assert(left->ctx, left->n_row == right->n_row, goto error); + + if (left->n_row == 0) { + isl_mat_free(left); + return right; + } + + left = isl_mat_cow(left); + right = isl_mat_cow(right); + if (!left || !right) + goto error; + + isl_int_init(a); + isl_int_init(b); + for (row = 0; row < left->n_row; ++row) { + int pivot, first, i, off; + pivot = row_abs_min_non_zero(left->row+row, left->n_row-row, row); + if (pivot < 0) { + isl_int_clear(a); + isl_int_clear(b); + isl_assert(left->ctx, pivot >= 0, goto error); + } + pivot += row; + if (pivot != row) + if (inv_exchange(&left, &right, pivot, row) < 0) + goto error; + if (isl_int_is_neg(left->row[row][row])) + inv_oppose(left, right, row); + first = row+1; + while ((off = row_first_non_zero(left->row+first, + left->n_row-first, row)) != -1) { + first += off; + isl_int_fdiv_q(a, left->row[first][row], + left->row[row][row]); + inv_subtract(left, right, row, first, a); + if (!isl_int_is_zero(left->row[first][row])) { + if (inv_exchange(&left, &right, row, first) < 0) + goto error; + } else { + ++first; + } + } + for (i = 0; i < row; ++i) { + if (isl_int_is_zero(left->row[i][row])) + continue; + isl_int_gcd(a, left->row[row][row], left->row[i][row]); + isl_int_divexact(b, left->row[i][row], a); + isl_int_divexact(a, left->row[row][row], a); + isl_int_neg(b, b); + isl_seq_combine(left->row[i] + i, + a, left->row[i] + i, + b, left->row[row] + i, + left->n_col - i); + isl_seq_combine(right->row[i], a, right->row[i], + b, right->row[row], right->n_col); + } + } + isl_int_clear(b); + + isl_int_set(a, left->row[0][0]); + for (row = 1; row < left->n_row; ++row) + isl_int_lcm(a, a, left->row[row][row]); + if (isl_int_is_zero(a)){ + isl_int_clear(a); + isl_assert(left->ctx, 0, goto error); + } + for (row = 0; row < left->n_row; ++row) { + isl_int_divexact(left->row[row][row], a, left->row[row][row]); + if (isl_int_is_one(left->row[row][row])) + continue; + isl_seq_scale(right->row[row], right->row[row], + left->row[row][row], right->n_col); + } + isl_int_clear(a); + + isl_mat_free(left); + return right; +error: + isl_mat_free(left); + isl_mat_free(right); + return NULL; +} + +void isl_mat_col_scale(struct isl_mat *mat, unsigned col, isl_int m) +{ + int i; + + for (i = 0; i < mat->n_row; ++i) + isl_int_mul(mat->row[i][col], mat->row[i][col], m); +} + +void isl_mat_col_combine(struct isl_mat *mat, unsigned dst, + isl_int m1, unsigned src1, isl_int m2, unsigned src2) +{ + int i; + isl_int tmp; + + isl_int_init(tmp); + for (i = 0; i < mat->n_row; ++i) { + isl_int_mul(tmp, m1, mat->row[i][src1]); + isl_int_addmul(tmp, m2, mat->row[i][src2]); + isl_int_set(mat->row[i][dst], tmp); + } + isl_int_clear(tmp); +} + +__isl_give isl_mat *isl_mat_right_inverse(__isl_take isl_mat *mat) +{ + struct isl_mat *inv; + int row; + isl_int a, b; + + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + + inv = isl_mat_identity(mat->ctx, mat->n_col); + inv = isl_mat_cow(inv); + if (!inv) + goto error; + + isl_int_init(a); + isl_int_init(b); + for (row = 0; row < mat->n_row; ++row) { + int pivot, first, i, off; + pivot = isl_seq_abs_min_non_zero(mat->row[row]+row, mat->n_col-row); + if (pivot < 0) { + isl_int_clear(a); + isl_int_clear(b); + isl_assert(mat->ctx, pivot >= 0, goto error); + } + pivot += row; + if (pivot != row) + exchange(mat, &inv, NULL, row, pivot, row); + if (isl_int_is_neg(mat->row[row][row])) + oppose(mat, &inv, NULL, row, row); + first = row+1; + while ((off = isl_seq_first_non_zero(mat->row[row]+first, + mat->n_col-first)) != -1) { + first += off; + isl_int_fdiv_q(a, mat->row[row][first], + mat->row[row][row]); + subtract(mat, &inv, NULL, row, row, first, a); + if (!isl_int_is_zero(mat->row[row][first])) + exchange(mat, &inv, NULL, row, row, first); + else + ++first; + } + for (i = 0; i < row; ++i) { + if (isl_int_is_zero(mat->row[row][i])) + continue; + isl_int_gcd(a, mat->row[row][row], mat->row[row][i]); + isl_int_divexact(b, mat->row[row][i], a); + isl_int_divexact(a, mat->row[row][row], a); + isl_int_neg(a, a); + isl_mat_col_combine(mat, i, a, i, b, row); + isl_mat_col_combine(inv, i, a, i, b, row); + } + } + isl_int_clear(b); + + isl_int_set(a, mat->row[0][0]); + for (row = 1; row < mat->n_row; ++row) + isl_int_lcm(a, a, mat->row[row][row]); + if (isl_int_is_zero(a)){ + isl_int_clear(a); + goto error; + } + for (row = 0; row < mat->n_row; ++row) { + isl_int_divexact(mat->row[row][row], a, mat->row[row][row]); + if (isl_int_is_one(mat->row[row][row])) + continue; + isl_mat_col_scale(inv, row, mat->row[row][row]); + } + isl_int_clear(a); + + isl_mat_free(mat); + + return inv; +error: + isl_mat_free(mat); + isl_mat_free(inv); + return NULL; +} + +__isl_give isl_mat *isl_mat_transpose(__isl_take isl_mat *mat) +{ + struct isl_mat *transpose = NULL; + int i, j; + + if (!mat) + return NULL; + + if (mat->n_col == mat->n_row) { + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + for (i = 0; i < mat->n_row; ++i) + for (j = i + 1; j < mat->n_col; ++j) + isl_int_swap(mat->row[i][j], mat->row[j][i]); + return mat; + } + transpose = isl_mat_alloc(mat->ctx, mat->n_col, mat->n_row); + if (!transpose) + goto error; + for (i = 0; i < mat->n_row; ++i) + for (j = 0; j < mat->n_col; ++j) + isl_int_set(transpose->row[j][i], mat->row[i][j]); + isl_mat_free(mat); + return transpose; +error: + isl_mat_free(mat); + return NULL; +} + +__isl_give isl_mat *isl_mat_swap_cols(__isl_take isl_mat *mat, + unsigned i, unsigned j) +{ + int r; + + mat = isl_mat_cow(mat); + if (check_col_range(mat, i, 1) < 0 || + check_col_range(mat, j, 1) < 0) + return isl_mat_free(mat); + + for (r = 0; r < mat->n_row; ++r) + isl_int_swap(mat->row[r][i], mat->row[r][j]); + return mat; +} + +__isl_give isl_mat *isl_mat_swap_rows(__isl_take isl_mat *mat, + unsigned i, unsigned j) +{ + isl_int *t; + + if (!mat) + return NULL; + mat = isl_mat_cow(mat); + if (check_row_range(mat, i, 1) < 0 || + check_row_range(mat, j, 1) < 0) + return isl_mat_free(mat); + + t = mat->row[i]; + mat->row[i] = mat->row[j]; + mat->row[j] = t; + return mat; +} + +/* Calculate the product of two matrices. + * + * This function is optimized for operand matrices that contain many zeros and + * skips multiplications where we know one of the operands is zero. + */ +__isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left, + __isl_take isl_mat *right) +{ + int i, j, k; + struct isl_mat *prod; + + if (!left || !right) + goto error; + isl_assert(left->ctx, left->n_col == right->n_row, goto error); + prod = isl_mat_alloc(left->ctx, left->n_row, right->n_col); + if (!prod) + goto error; + if (left->n_col == 0) { + for (i = 0; i < prod->n_row; ++i) + isl_seq_clr(prod->row[i], prod->n_col); + isl_mat_free(left); + isl_mat_free(right); + return prod; + } + for (i = 0; i < prod->n_row; ++i) { + for (j = 0; j < prod->n_col; ++j) + isl_int_mul(prod->row[i][j], + left->row[i][0], right->row[0][j]); + for (k = 1; k < left->n_col; ++k) { + if (isl_int_is_zero(left->row[i][k])) + continue; + for (j = 0; j < prod->n_col; ++j) + isl_int_addmul(prod->row[i][j], + left->row[i][k], right->row[k][j]); + } + } + isl_mat_free(left); + isl_mat_free(right); + return prod; +error: + isl_mat_free(left); + isl_mat_free(right); + return NULL; +} + +/* Replace the variables x in the rows q by x' given by x = M x', + * with M the matrix mat. + * + * If the number of new variables is greater than the original + * number of variables, then the rows q have already been + * preextended. If the new number is smaller, then the coefficients + * of the divs, which are not changed, need to be shifted down. + * The row q may be the equalities, the inequalities or the + * div expressions. In the latter case, has_div is true and + * we need to take into account the extra denominator column. + */ +static int preimage(struct isl_ctx *ctx, isl_int **q, unsigned n, + unsigned n_div, int has_div, struct isl_mat *mat) +{ + int i; + struct isl_mat *t; + int e; + + if (mat->n_col >= mat->n_row) + e = 0; + else + e = mat->n_row - mat->n_col; + 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_alloc6(mat->ctx, q, 0, n, has_div, 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] + has_div, t->row[i], t->n_col); + isl_seq_cpy(q[i] + has_div + t->n_col, + q[i] + has_div + t->n_col + e, n_div); + isl_seq_clr(q[i] + has_div + t->n_col + n_div, e); + } + isl_mat_free(t); + return 0; +} + +/* Replace the variables x in bset by x' given by x = M x', with + * M the matrix mat. + * + * If there are fewer variables x' then there are x, then we perform + * the transformation in place, which means that, in principle, + * this frees up some extra variables as the number + * of columns remains constant, but we would have to extend + * the div array too as the number of rows in this array is assumed + * to be equal to extra. + */ +__isl_give isl_basic_set *isl_basic_set_preimage( + __isl_take isl_basic_set *bset, __isl_take isl_mat *mat) +{ + struct isl_ctx *ctx; + + if (!bset || !mat) + goto error; + + ctx = bset->ctx; + bset = isl_basic_set_cow(bset); + if (!bset) + goto error; + + isl_assert(ctx, bset->dim->nparam == 0, goto error); + isl_assert(ctx, 1+bset->dim->n_out == mat->n_row, goto error); + isl_assert(ctx, mat->n_col > 0, goto error); + + if (mat->n_col > mat->n_row) { + bset = isl_basic_set_extend(bset, 0, mat->n_col-1, 0, 0, 0); + if (!bset) + goto error; + } else if (mat->n_col < mat->n_row) { + bset->dim = isl_space_cow(bset->dim); + if (!bset->dim) + goto error; + bset->dim->n_out -= mat->n_row - mat->n_col; + } + + if (preimage(ctx, bset->eq, bset->n_eq, bset->n_div, 0, + isl_mat_copy(mat)) < 0) + goto error; + + if (preimage(ctx, bset->ineq, bset->n_ineq, bset->n_div, 0, + isl_mat_copy(mat)) < 0) + goto error; + + if (preimage(ctx, bset->div, bset->n_div, bset->n_div, 1, mat) < 0) + goto error2; + + ISL_F_CLR(bset, ISL_BASIC_SET_NO_IMPLICIT); + ISL_F_CLR(bset, ISL_BASIC_SET_NO_REDUNDANT); + ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED); + ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED_DIVS); + ISL_F_CLR(bset, ISL_BASIC_SET_ALL_EQUALITIES); + + bset = isl_basic_set_simplify(bset); + bset = isl_basic_set_finalize(bset); + + return bset; +error: + isl_mat_free(mat); +error2: + isl_basic_set_free(bset); + return NULL; +} + +__isl_give isl_set *isl_set_preimage( + __isl_take isl_set *set, __isl_take isl_mat *mat) +{ + int i; + + set = isl_set_cow(set); + if (!set) + goto error; + + for (i = 0; i < set->n; ++i) { + set->p[i] = isl_basic_set_preimage(set->p[i], + isl_mat_copy(mat)); + if (!set->p[i]) + goto error; + } + if (mat->n_col != mat->n_row) { + set->dim = isl_space_cow(set->dim); + if (!set->dim) + goto error; + set->dim->n_out += mat->n_col; + set->dim->n_out -= mat->n_row; + } + isl_mat_free(mat); + ISL_F_CLR(set, ISL_SET_NORMALIZED); + return set; +error: + isl_set_free(set); + isl_mat_free(mat); + return NULL; +} + +/* Replace the variables x starting at "first_col" in the rows "rows" + * of some coefficient matrix by x' with x = M x' with M the matrix mat. + * That is, replace the corresponding coefficients c by c M. + */ +isl_stat isl_mat_sub_transform(isl_int **row, unsigned n_row, + unsigned first_col, __isl_take isl_mat *mat) +{ + int i; + isl_ctx *ctx; + isl_mat *t; + + if (!mat) + return isl_stat_error; + ctx = isl_mat_get_ctx(mat); + t = isl_mat_sub_alloc6(ctx, row, 0, n_row, first_col, mat->n_row); + t = isl_mat_product(t, mat); + if (!t) + return isl_stat_error; + for (i = 0; i < n_row; ++i) + isl_seq_swp_or_cpy(row[i] + first_col, t->row[i], t->n_col); + isl_mat_free(t); + return isl_stat_ok; +} + +void isl_mat_print_internal(__isl_keep isl_mat *mat, FILE *out, int indent) +{ + int i, j; + + if (!mat) { + fprintf(out, "%*snull mat\n", indent, ""); + return; + } + + if (mat->n_row == 0) + fprintf(out, "%*s[]\n", indent, ""); + + for (i = 0; i < mat->n_row; ++i) { + if (!i) + fprintf(out, "%*s[[", indent, ""); + else + fprintf(out, "%*s[", indent+1, ""); + for (j = 0; j < mat->n_col; ++j) { + if (j) + fprintf(out, ","); + isl_int_print(out, mat->row[i][j], 0); + } + if (i == mat->n_row-1) + fprintf(out, "]]\n"); + else + fprintf(out, "]\n"); + } +} + +void isl_mat_dump(__isl_keep isl_mat *mat) +{ + isl_mat_print_internal(mat, stderr, 0); +} + +__isl_give isl_mat *isl_mat_drop_cols(__isl_take isl_mat *mat, + unsigned col, unsigned n) +{ + int r; + + if (n == 0) + return mat; + + mat = isl_mat_cow(mat); + if (check_col_range(mat, col, n) < 0) + return isl_mat_free(mat); + + if (col != mat->n_col-n) { + for (r = 0; r < mat->n_row; ++r) + isl_seq_cpy(mat->row[r]+col, mat->row[r]+col+n, + mat->n_col - col - n); + } + mat->n_col -= n; + return mat; +} + +__isl_give isl_mat *isl_mat_drop_rows(__isl_take isl_mat *mat, + unsigned row, unsigned n) +{ + int r; + + mat = isl_mat_cow(mat); + if (check_row_range(mat, row, n) < 0) + return isl_mat_free(mat); + + for (r = row; r+n < mat->n_row; ++r) + mat->row[r] = mat->row[r+n]; + + mat->n_row -= n; + return mat; +} + +__isl_give isl_mat *isl_mat_insert_cols(__isl_take isl_mat *mat, + unsigned col, unsigned n) +{ + isl_mat *ext; + + if (check_col_range(mat, col, 0) < 0) + return isl_mat_free(mat); + if (n == 0) + return mat; + + ext = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col + n); + if (!ext) + goto error; + + isl_mat_sub_copy(mat->ctx, ext->row, mat->row, mat->n_row, 0, 0, col); + isl_mat_sub_copy(mat->ctx, ext->row, mat->row, mat->n_row, + col + n, col, mat->n_col - col); + + isl_mat_free(mat); + return ext; +error: + isl_mat_free(mat); + return NULL; +} + +__isl_give isl_mat *isl_mat_insert_zero_cols(__isl_take isl_mat *mat, + unsigned first, unsigned n) +{ + int i; + + if (!mat) + return NULL; + mat = isl_mat_insert_cols(mat, first, n); + if (!mat) + return NULL; + + for (i = 0; i < mat->n_row; ++i) + isl_seq_clr(mat->row[i] + first, n); + + return mat; +} + +__isl_give isl_mat *isl_mat_add_zero_cols(__isl_take isl_mat *mat, unsigned n) +{ + if (!mat) + return NULL; + + return isl_mat_insert_zero_cols(mat, mat->n_col, n); +} + +__isl_give isl_mat *isl_mat_insert_rows(__isl_take isl_mat *mat, + unsigned row, unsigned n) +{ + isl_mat *ext; + + if (check_row_range(mat, row, 0) < 0) + return isl_mat_free(mat); + if (n == 0) + return mat; + + ext = isl_mat_alloc(mat->ctx, mat->n_row + n, mat->n_col); + if (!ext) + goto error; + + isl_mat_sub_copy(mat->ctx, ext->row, mat->row, row, 0, 0, mat->n_col); + isl_mat_sub_copy(mat->ctx, ext->row + row + n, mat->row + row, + mat->n_row - row, 0, 0, mat->n_col); + + isl_mat_free(mat); + return ext; +error: + isl_mat_free(mat); + return NULL; +} + +__isl_give isl_mat *isl_mat_add_rows(__isl_take isl_mat *mat, unsigned n) +{ + if (!mat) + return NULL; + + 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) +{ + int i; + + for (i = 0; i < mat->n_row; ++i) + isl_int_submul(mat->row[i][dst_col], f, mat->row[i][src_col]); +} + +void isl_mat_col_add(__isl_keep isl_mat *mat, int dst_col, int src_col) +{ + int i; + + if (!mat) + return; + + for (i = 0; i < mat->n_row; ++i) + isl_int_add(mat->row[i][dst_col], + mat->row[i][dst_col], mat->row[i][src_col]); +} + +void isl_mat_col_mul(struct isl_mat *mat, int dst_col, isl_int f, int src_col) +{ + int i; + + for (i = 0; i < mat->n_row; ++i) + isl_int_mul(mat->row[i][dst_col], f, mat->row[i][src_col]); +} + +/* Add "f" times column "src_col" to column "dst_col" of "mat" and + * return the result. + */ +__isl_give isl_mat *isl_mat_col_addmul(__isl_take isl_mat *mat, int dst_col, + isl_int f, int src_col) +{ + int i; + + if (check_col(mat, dst_col) < 0 || check_col(mat, src_col) < 0) + return isl_mat_free(mat); + + for (i = 0; i < mat->n_row; ++i) { + if (isl_int_is_zero(mat->row[i][src_col])) + continue; + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + isl_int_addmul(mat->row[i][dst_col], f, mat->row[i][src_col]); + } + + return mat; +} + +/* Negate column "col" of "mat" and return the result. + */ +__isl_give isl_mat *isl_mat_col_neg(__isl_take isl_mat *mat, int col) +{ + int i; + + if (check_col(mat, col) < 0) + return isl_mat_free(mat); + + for (i = 0; i < mat->n_row; ++i) { + if (isl_int_is_zero(mat->row[i][col])) + continue; + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + isl_int_neg(mat->row[i][col], mat->row[i][col]); + } + + return mat; +} + +/* Negate row "row" of "mat" and return the result. + */ +__isl_give isl_mat *isl_mat_row_neg(__isl_take isl_mat *mat, int row) +{ + if (check_row(mat, row) < 0) + return isl_mat_free(mat); + if (isl_seq_first_non_zero(mat->row[row], mat->n_col) == -1) + return mat; + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + isl_seq_neg(mat->row[row], mat->row[row], mat->n_col); + return mat; +} + +__isl_give isl_mat *isl_mat_unimodular_complete(__isl_take isl_mat *M, int row) +{ + int r; + struct isl_mat *H = NULL, *Q = NULL; + + if (!M) + return NULL; + + isl_assert(M->ctx, M->n_row == M->n_col, goto error); + M->n_row = row; + H = isl_mat_left_hermite(isl_mat_copy(M), 0, NULL, &Q); + M->n_row = M->n_col; + if (!H) + goto error; + for (r = 0; r < row; ++r) + isl_assert(M->ctx, isl_int_is_one(H->row[r][r]), goto error); + for (r = row; r < M->n_row; ++r) + isl_seq_cpy(M->row[r], Q->row[r], M->n_col); + isl_mat_free(H); + isl_mat_free(Q); + return M; +error: + isl_mat_free(H); + isl_mat_free(Q); + isl_mat_free(M); + return NULL; +} + +__isl_give isl_mat *isl_mat_concat(__isl_take isl_mat *top, + __isl_take isl_mat *bot) +{ + struct isl_mat *mat; + + if (!top || !bot) + goto error; + + isl_assert(top->ctx, top->n_col == bot->n_col, goto error); + if (top->n_row == 0) { + isl_mat_free(top); + return bot; + } + if (bot->n_row == 0) { + isl_mat_free(bot); + return top; + } + + mat = isl_mat_alloc(top->ctx, top->n_row + bot->n_row, top->n_col); + if (!mat) + goto error; + isl_mat_sub_copy(mat->ctx, mat->row, top->row, top->n_row, + 0, 0, mat->n_col); + isl_mat_sub_copy(mat->ctx, mat->row + top->n_row, bot->row, bot->n_row, + 0, 0, mat->n_col); + isl_mat_free(top); + isl_mat_free(bot); + return mat; +error: + isl_mat_free(top); + isl_mat_free(bot); + return NULL; +} + +isl_bool isl_mat_is_equal(__isl_keep isl_mat *mat1, __isl_keep isl_mat *mat2) +{ + int i; + + if (!mat1 || !mat2) + return isl_bool_error; + + if (mat1->n_row != mat2->n_row) + return isl_bool_false; + + if (mat1->n_col != mat2->n_col) + return isl_bool_false; + + for (i = 0; i < mat1->n_row; ++i) + if (!isl_seq_eq(mat1->row[i], mat2->row[i], mat1->n_col)) + return isl_bool_false; + + return isl_bool_true; +} + +__isl_give isl_mat *isl_mat_from_row_vec(__isl_take isl_vec *vec) +{ + struct isl_mat *mat; + + if (!vec) + return NULL; + mat = isl_mat_alloc(vec->ctx, 1, vec->size); + if (!mat) + goto error; + + isl_seq_cpy(mat->row[0], vec->el, vec->size); + + isl_vec_free(vec); + return mat; +error: + isl_vec_free(vec); + return NULL; +} + +/* Return a copy of row "row" of "mat" as an isl_vec. + */ +__isl_give isl_vec *isl_mat_get_row(__isl_keep isl_mat *mat, unsigned row) +{ + isl_vec *v; + + if (!mat) + return NULL; + if (row >= mat->n_row) + isl_die(mat->ctx, isl_error_invalid, "row out of range", + return NULL); + + v = isl_vec_alloc(isl_mat_get_ctx(mat), mat->n_col); + if (!v) + return NULL; + isl_seq_cpy(v->el, mat->row[row], mat->n_col); + + return v; +} + +__isl_give isl_mat *isl_mat_vec_concat(__isl_take isl_mat *top, + __isl_take isl_vec *bot) +{ + return isl_mat_concat(top, isl_mat_from_row_vec(bot)); +} + +__isl_give isl_mat *isl_mat_move_cols(__isl_take isl_mat *mat, + unsigned dst_col, unsigned src_col, unsigned n) +{ + isl_mat *res; + + if (!mat) + return NULL; + if (n == 0 || dst_col == src_col) + return mat; + + res = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col); + if (!res) + goto error; + + if (dst_col < src_col) { + isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row, + 0, 0, dst_col); + isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row, + dst_col, src_col, n); + isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row, + dst_col + n, dst_col, src_col - dst_col); + isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row, + src_col + n, src_col + n, + res->n_col - src_col - n); + } else { + isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row, + 0, 0, src_col); + isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row, + src_col, src_col + n, dst_col - src_col); + isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row, + dst_col, src_col, n); + isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row, + dst_col + n, dst_col + n, + res->n_col - dst_col - n); + } + isl_mat_free(mat); + + return res; +error: + isl_mat_free(mat); + return NULL; +} + +/* Return the gcd of the elements in row "row" of "mat" in *gcd. + * Return isl_stat_ok on success and isl_stat_error on failure. + */ +isl_stat isl_mat_row_gcd(__isl_keep isl_mat *mat, int row, isl_int *gcd) +{ + if (check_row(mat, row) < 0) + return isl_stat_error; + + isl_seq_gcd(mat->row[row], mat->n_col, gcd); + + return isl_stat_ok; +} + +void isl_mat_gcd(__isl_keep isl_mat *mat, isl_int *gcd) +{ + int i; + isl_int g; + + isl_int_set_si(*gcd, 0); + if (!mat) + return; + + isl_int_init(g); + for (i = 0; i < mat->n_row; ++i) { + isl_seq_gcd(mat->row[i], mat->n_col, &g); + isl_int_gcd(*gcd, *gcd, g); + } + isl_int_clear(g); +} + +/* Return the result of scaling "mat" by a factor of "m". + */ +__isl_give isl_mat *isl_mat_scale(__isl_take isl_mat *mat, isl_int m) +{ + int i; + + if (isl_int_is_one(m)) + return mat; + + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + + for (i = 0; i < mat->n_row; ++i) + isl_seq_scale(mat->row[i], mat->row[i], m, mat->n_col); + + return mat; +} + +__isl_give isl_mat *isl_mat_scale_down(__isl_take isl_mat *mat, isl_int m) +{ + int i; + + if (isl_int_is_one(m)) + return mat; + + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + + for (i = 0; i < mat->n_row; ++i) + isl_seq_scale_down(mat->row[i], mat->row[i], m, mat->n_col); + + return mat; +} + +__isl_give isl_mat *isl_mat_scale_down_row(__isl_take isl_mat *mat, int row, + isl_int m) +{ + if (isl_int_is_one(m)) + return mat; + + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + + isl_seq_scale_down(mat->row[row], mat->row[row], m, mat->n_col); + + return mat; +} + +__isl_give isl_mat *isl_mat_normalize(__isl_take isl_mat *mat) +{ + isl_int gcd; + + if (!mat) + return NULL; + + isl_int_init(gcd); + isl_mat_gcd(mat, &gcd); + mat = isl_mat_scale_down(mat, gcd); + isl_int_clear(gcd); + + return mat; +} + +__isl_give isl_mat *isl_mat_normalize_row(__isl_take isl_mat *mat, int row) +{ + mat = isl_mat_cow(mat); + if (!mat) + return NULL; + + isl_seq_normalize(mat->ctx, mat->row[row], mat->n_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; +} + +/* Return a basis for the space spanned by the rows of "mat". + * Any basis will do, so simply perform Gaussian elimination and + * remove the empty rows. + */ +__isl_give isl_mat *isl_mat_row_basis(__isl_take isl_mat *mat) +{ + return isl_mat_reverse_gauss(mat); +} + +/* Return rows that extend a basis of "mat1" to one + * that covers both "mat1" and "mat2". + * The Hermite normal form of the concatenation of the two matrices is + * + * [ Q1 ] + * [ M1 ] = [ H1 0 0 ] [ Q2 ] + * [ M2 ] = [ H2 H3 0 ] [ Q3 ] + * + * The number of columns in H1 and H3 determine the number of rows + * in Q1 and Q2. Q1 is a basis for M1, while Q2 extends this basis + * to also cover M2. + */ +__isl_give isl_mat *isl_mat_row_basis_extension( + __isl_take isl_mat *mat1, __isl_take isl_mat *mat2) +{ + int n_row; + int r1, r, n1; + isl_mat *H, *Q; + + n1 = isl_mat_rows(mat1); + H = isl_mat_concat(mat1, mat2); + H = isl_mat_left_hermite(H, 0, NULL, &Q); + if (!H || !Q) + goto error; + + r1 = hermite_first_zero_col(H, 0, n1); + r = hermite_first_zero_col(H, r1, H->n_row); + n_row = isl_mat_rows(Q); + Q = isl_mat_drop_rows(Q, r, n_row - r); + Q = isl_mat_drop_rows(Q, 0, r1); + + isl_mat_free(H); + return Q; +error: + isl_mat_free(H); + isl_mat_free(Q); + return NULL; +} + +/* Are the rows of "mat1" linearly independent of those of "mat2"? + * That is, is there no linear dependence among the combined rows + * that is not already present in either "mat1" or "mat2"? + * In other words, is the rank of "mat1" and "mat2" combined equal + * to the sum of the ranks of "mat1" and "mat2"? + */ +isl_bool isl_mat_has_linearly_independent_rows(__isl_keep isl_mat *mat1, + __isl_keep isl_mat *mat2) +{ + int r1, r2, r; + isl_mat *mat; + + r1 = isl_mat_rank(mat1); + if (r1 < 0) + return isl_bool_error; + if (r1 == 0) + return isl_bool_true; + r2 = isl_mat_rank(mat2); + if (r2 < 0) + return isl_bool_error; + if (r2 == 0) + return isl_bool_true; + + mat = isl_mat_concat(isl_mat_copy(mat1), isl_mat_copy(mat2)); + r = isl_mat_rank(mat); + isl_mat_free(mat); + if (r < 0) + return isl_bool_error; + return r == r1 + r2; +} Index: contrib/isl/isl_mat_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_mat_private.h @@ -0,0 +1,62 @@ +#include +#include + +struct isl_mat { + int ref; + + struct isl_ctx *ctx; + +#define ISL_MAT_BORROWED (1 << 0) + unsigned flags; + + unsigned n_row; + unsigned n_col; + + isl_int **row; + + /* actual size of the rows in memory; n_col <= max_col */ + unsigned max_col; + + struct isl_blk block; +}; + +uint32_t isl_mat_get_hash(__isl_keep isl_mat *mat); + +__isl_give isl_mat *isl_mat_zero(isl_ctx *ctx, unsigned n_row, unsigned n_col); +__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_stat isl_mat_sub_transform(isl_int **row, unsigned n_row, + unsigned first_col, __isl_take isl_mat *mat); +__isl_give isl_mat *isl_mat_diag(isl_ctx *ctx, unsigned n_row, isl_int d); + +__isl_give isl_mat *isl_mat_reverse_gauss(__isl_take isl_mat *mat); + +__isl_give isl_mat *isl_mat_scale(__isl_take isl_mat *mat, isl_int m); +__isl_give isl_mat *isl_mat_scale_down_row(__isl_take isl_mat *mat, int row, + isl_int m); + +__isl_give isl_vec *isl_mat_get_row(__isl_keep isl_mat *mat, unsigned row); + +__isl_give isl_mat *isl_mat_lexnonneg_rows(__isl_take isl_mat *mat); + +int isl_mat_is_scaled_identity(__isl_keep isl_mat *mat); + +isl_stat isl_mat_row_gcd(__isl_keep isl_mat *mat, int row, isl_int *gcd); + +void isl_mat_col_mul(struct isl_mat *mat, int dst_col, isl_int f, int src_col); +void isl_mat_col_submul(struct isl_mat *mat, + int dst_col, isl_int f, int src_col); +__isl_give isl_mat *isl_mat_col_addmul(__isl_take isl_mat *mat, int dst_col, + isl_int f, int src_col); +__isl_give isl_mat *isl_mat_col_neg(__isl_take isl_mat *mat, int col); +__isl_give isl_mat *isl_mat_row_neg(__isl_take isl_mat *mat, int row); + +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); Index: contrib/isl/isl_maybe_map.h =================================================================== --- /dev/null +++ contrib/isl/isl_maybe_map.h @@ -0,0 +1,10 @@ +#ifndef ISL_MAYBE_MAP_H +#define ISL_MAYBE_MAP_H + +#include + +#define ISL_TYPE isl_map +#include +#undef ISL_TYPE + +#endif Index: contrib/isl/isl_morph.h =================================================================== --- /dev/null +++ contrib/isl/isl_morph.h @@ -0,0 +1,89 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#ifndef ISL_MORHP_H +#define ISL_MORHP_H + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* An isl_morph is a "morphism" on (basic) sets. + * "map" is an affine mapping from "dom" to "ran" + * and "inv" is the inverse mapping. + */ +struct isl_morph { + int ref; + + isl_basic_set *dom; + isl_basic_set *ran; + + isl_mat *map; + isl_mat *inv; +}; +typedef struct isl_morph isl_morph; + +isl_ctx *isl_morph_get_ctx(__isl_keep isl_morph *morph); + +__isl_give isl_morph *isl_morph_alloc( + __isl_take isl_basic_set *dom, __isl_take isl_basic_set *ran, + __isl_take isl_mat *map, __isl_take isl_mat *inv); +__isl_give isl_morph *isl_morph_copy(__isl_keep isl_morph *morph); +__isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset); +__isl_null isl_morph *isl_morph_free(__isl_take isl_morph *morph); + +__isl_give isl_space *isl_morph_get_dom_space(__isl_keep isl_morph *morph); +__isl_give isl_space *isl_morph_get_ran_space(__isl_keep isl_morph *morph); +__isl_give isl_multi_aff *isl_morph_get_var_multi_aff( + __isl_keep isl_morph *morph); +unsigned isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type); +unsigned isl_morph_ran_dim(__isl_keep isl_morph *morph, enum isl_dim_type type); + +__isl_give isl_morph *isl_morph_remove_dom_dims(__isl_take isl_morph *morph, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_morph *isl_morph_remove_ran_dims(__isl_take isl_morph *morph, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_morph *isl_morph_dom_params(__isl_take isl_morph *morph); +__isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph); + +__isl_give isl_morph *isl_morph_compose(__isl_take isl_morph *morph1, + __isl_take isl_morph *morph2); +__isl_give isl_morph *isl_morph_inverse(__isl_take isl_morph *morph); + +void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out); +void isl_morph_dump(__isl_take isl_morph *morph); + +__isl_give isl_morph *isl_basic_set_variable_compression( + __isl_keep isl_basic_set *bset, enum isl_dim_type type); +__isl_give isl_morph *isl_basic_set_variable_compression_with_id( + __isl_keep isl_basic_set *bset, enum isl_dim_type type, + __isl_keep isl_id *id); +__isl_give isl_morph *isl_basic_set_parameter_compression( + __isl_keep isl_basic_set *bset); +__isl_give isl_morph *isl_basic_set_full_compression( + __isl_keep isl_basic_set *bset); + +__isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph, + __isl_take isl_basic_set *bset); +__isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph, + __isl_take isl_set *set); +__isl_give isl_vec *isl_morph_vec(__isl_take isl_morph *morph, + __isl_take isl_vec *vec); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/isl_morph.c =================================================================== --- /dev/null +++ contrib/isl/isl_morph.c @@ -0,0 +1,836 @@ +/* + * Copyright 2010-2011 INRIA Saclay + * Copyright 2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +isl_ctx *isl_morph_get_ctx(__isl_keep isl_morph *morph) +{ + if (!morph) + return NULL; + return isl_basic_set_get_ctx(morph->dom); +} + +__isl_give isl_morph *isl_morph_alloc( + __isl_take isl_basic_set *dom, __isl_take isl_basic_set *ran, + __isl_take isl_mat *map, __isl_take isl_mat *inv) +{ + isl_morph *morph; + + if (!dom || !ran || !map || !inv) + goto error; + + morph = isl_alloc_type(dom->ctx, struct isl_morph); + if (!morph) + goto error; + + morph->ref = 1; + morph->dom = dom; + morph->ran = ran; + morph->map = map; + morph->inv = inv; + + return morph; +error: + isl_basic_set_free(dom); + isl_basic_set_free(ran); + isl_mat_free(map); + isl_mat_free(inv); + return NULL; +} + +__isl_give isl_morph *isl_morph_copy(__isl_keep isl_morph *morph) +{ + if (!morph) + return NULL; + + morph->ref++; + return morph; +} + +__isl_give isl_morph *isl_morph_dup(__isl_keep isl_morph *morph) +{ + if (!morph) + return NULL; + + return isl_morph_alloc(isl_basic_set_copy(morph->dom), + isl_basic_set_copy(morph->ran), + isl_mat_copy(morph->map), isl_mat_copy(morph->inv)); +} + +__isl_give isl_morph *isl_morph_cow(__isl_take isl_morph *morph) +{ + if (!morph) + return NULL; + + if (morph->ref == 1) + return morph; + morph->ref--; + return isl_morph_dup(morph); +} + +__isl_null isl_morph *isl_morph_free(__isl_take isl_morph *morph) +{ + if (!morph) + return NULL; + + if (--morph->ref > 0) + return NULL; + + isl_basic_set_free(morph->dom); + isl_basic_set_free(morph->ran); + isl_mat_free(morph->map); + isl_mat_free(morph->inv); + free(morph); + + return NULL; +} + +/* Is "morph" an identity on the parameters? + */ +static int identity_on_parameters(__isl_keep isl_morph *morph) +{ + int is_identity; + unsigned nparam; + isl_mat *sub; + + nparam = isl_morph_dom_dim(morph, isl_dim_param); + if (nparam != isl_morph_ran_dim(morph, isl_dim_param)) + return 0; + if (nparam == 0) + return 1; + sub = isl_mat_sub_alloc(morph->map, 0, 1 + nparam, 0, 1 + nparam); + is_identity = isl_mat_is_scaled_identity(sub); + isl_mat_free(sub); + + return is_identity; +} + +/* Return an affine expression of the variables of the range of "morph" + * in terms of the parameters and the variables of the domain on "morph". + * + * In order for the space manipulations to make sense, we require + * that the parameters are not modified by "morph". + */ +__isl_give isl_multi_aff *isl_morph_get_var_multi_aff( + __isl_keep isl_morph *morph) +{ + isl_space *dom, *ran, *space; + isl_local_space *ls; + isl_multi_aff *ma; + unsigned nparam, nvar; + int i; + int is_identity; + + if (!morph) + return NULL; + + is_identity = identity_on_parameters(morph); + if (is_identity < 0) + return NULL; + if (!is_identity) + isl_die(isl_morph_get_ctx(morph), isl_error_invalid, + "cannot handle parameter compression", return NULL); + + dom = isl_morph_get_dom_space(morph); + ls = isl_local_space_from_space(isl_space_copy(dom)); + ran = isl_morph_get_ran_space(morph); + space = isl_space_map_from_domain_and_range(dom, ran); + ma = isl_multi_aff_zero(space); + + nparam = isl_multi_aff_dim(ma, isl_dim_param); + nvar = isl_multi_aff_dim(ma, isl_dim_out); + for (i = 0; i < nvar; ++i) { + isl_val *val; + isl_vec *v; + isl_aff *aff; + + v = isl_mat_get_row(morph->map, 1 + nparam + i); + v = isl_vec_insert_els(v, 0, 1); + val = isl_mat_get_element_val(morph->map, 0, 0); + v = isl_vec_set_element_val(v, 0, val); + aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + + isl_local_space_free(ls); + return ma; +} + +/* Return the domain space of "morph". + */ +__isl_give isl_space *isl_morph_get_dom_space(__isl_keep isl_morph *morph) +{ + if (!morph) + return NULL; + + return isl_basic_set_get_space(morph->dom); +} + +__isl_give isl_space *isl_morph_get_ran_space(__isl_keep isl_morph *morph) +{ + if (!morph) + return NULL; + + return isl_space_copy(morph->ran->dim); +} + +unsigned isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type) +{ + if (!morph) + return 0; + + return isl_basic_set_dim(morph->dom, type); +} + +unsigned isl_morph_ran_dim(__isl_keep isl_morph *morph, enum isl_dim_type type) +{ + if (!morph) + return 0; + + return isl_basic_set_dim(morph->ran, type); +} + +__isl_give isl_morph *isl_morph_remove_dom_dims(__isl_take isl_morph *morph, + enum isl_dim_type type, unsigned first, unsigned n) +{ + unsigned dom_offset; + + if (n == 0) + return morph; + + morph = isl_morph_cow(morph); + if (!morph) + return NULL; + + dom_offset = 1 + isl_space_offset(morph->dom->dim, type); + + morph->dom = isl_basic_set_remove_dims(morph->dom, type, first, n); + + morph->map = isl_mat_drop_cols(morph->map, dom_offset + first, n); + + morph->inv = isl_mat_drop_rows(morph->inv, dom_offset + first, n); + + if (morph->dom && morph->ran && morph->map && morph->inv) + return morph; + + isl_morph_free(morph); + return NULL; +} + +__isl_give isl_morph *isl_morph_remove_ran_dims(__isl_take isl_morph *morph, + enum isl_dim_type type, unsigned first, unsigned n) +{ + unsigned ran_offset; + + if (n == 0) + return morph; + + morph = isl_morph_cow(morph); + if (!morph) + return NULL; + + ran_offset = 1 + isl_space_offset(morph->ran->dim, type); + + morph->ran = isl_basic_set_remove_dims(morph->ran, type, first, n); + + morph->map = isl_mat_drop_rows(morph->map, ran_offset + first, n); + + morph->inv = isl_mat_drop_cols(morph->inv, ran_offset + first, n); + + if (morph->dom && morph->ran && morph->map && morph->inv) + return morph; + + isl_morph_free(morph); + return NULL; +} + +/* Project domain of morph onto its parameter domain. + */ +__isl_give isl_morph *isl_morph_dom_params(__isl_take isl_morph *morph) +{ + unsigned n; + + morph = isl_morph_cow(morph); + if (!morph) + return NULL; + n = isl_basic_set_dim(morph->dom, isl_dim_set); + morph = isl_morph_remove_dom_dims(morph, isl_dim_set, 0, n); + if (!morph) + return NULL; + morph->dom = isl_basic_set_params(morph->dom); + if (morph->dom) + return morph; + + isl_morph_free(morph); + return NULL; +} + +/* Project range of morph onto its parameter domain. + */ +__isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph) +{ + unsigned n; + + morph = isl_morph_cow(morph); + if (!morph) + return NULL; + n = isl_basic_set_dim(morph->ran, isl_dim_set); + morph = isl_morph_remove_ran_dims(morph, isl_dim_set, 0, n); + if (!morph) + return NULL; + morph->ran = isl_basic_set_params(morph->ran); + if (morph->ran) + return morph; + + isl_morph_free(morph); + return NULL; +} + +void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out) +{ + if (!morph) + return; + + isl_basic_set_dump(morph->dom); + isl_basic_set_dump(morph->ran); + isl_mat_print_internal(morph->map, out, 4); + isl_mat_print_internal(morph->inv, out, 4); +} + +void isl_morph_dump(__isl_take isl_morph *morph) +{ + isl_morph_print_internal(morph, stderr); +} + +__isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset) +{ + isl_mat *id; + isl_basic_set *universe; + unsigned total; + + if (!bset) + return NULL; + + total = isl_basic_set_total_dim(bset); + id = isl_mat_identity(bset->ctx, 1 + total); + universe = isl_basic_set_universe(isl_space_copy(bset->dim)); + + return isl_morph_alloc(universe, isl_basic_set_copy(universe), + id, isl_mat_copy(id)); +} + +/* Create a(n identity) morphism between empty sets of the same dimension + * a "bset". + */ +__isl_give isl_morph *isl_morph_empty(__isl_keep isl_basic_set *bset) +{ + isl_mat *id; + isl_basic_set *empty; + unsigned total; + + if (!bset) + return NULL; + + total = isl_basic_set_total_dim(bset); + id = isl_mat_identity(bset->ctx, 1 + total); + empty = isl_basic_set_empty(isl_space_copy(bset->dim)); + + return isl_morph_alloc(empty, isl_basic_set_copy(empty), + id, isl_mat_copy(id)); +} + +/* Construct a basic set described by the "n" equalities of "bset" starting + * at "first". + */ +static __isl_give isl_basic_set *copy_equalities(__isl_keep isl_basic_set *bset, + unsigned first, unsigned n) +{ + int i, k; + isl_basic_set *eq; + unsigned total; + + isl_assert(bset->ctx, bset->n_div == 0, return NULL); + + total = isl_basic_set_total_dim(bset); + eq = isl_basic_set_alloc_space(isl_space_copy(bset->dim), 0, n, 0); + if (!eq) + return NULL; + for (i = 0; i < n; ++i) { + k = isl_basic_set_alloc_equality(eq); + if (k < 0) + goto error; + isl_seq_cpy(eq->eq[k], bset->eq[first + i], 1 + total); + } + + return eq; +error: + isl_basic_set_free(eq); + return NULL; +} + +/* Given a basic set, exploit the equalities in the basic set to construct + * a morphism that maps the basic set to a lower-dimensional space + * with identifier "id". + * Specifically, the morphism reduces the number of dimensions of type "type". + * + * We first select the equalities of interest, that is those that involve + * variables of type "type" and no later variables. + * Denote those equalities as + * + * -C(p) + M x = 0 + * + * where C(p) depends on the parameters if type == isl_dim_set and + * is a constant if type == isl_dim_param. + * + * Use isl_mat_final_variable_compression to construct a compression + * + * x = T x' + * + * x' = Q x + * + * If T is a zero-column matrix, then the set of equality constraints + * do not admit a solution. In this case, an empty morphism is returned. + * + * Both matrices are extended to map the full original space to the full + * compressed space. + */ +__isl_give isl_morph *isl_basic_set_variable_compression_with_id( + __isl_keep isl_basic_set *bset, enum isl_dim_type type, + __isl_keep isl_id *id) +{ + unsigned otype; + unsigned ntype; + unsigned orest; + unsigned nrest; + int f_eq, n_eq; + isl_space *space; + isl_mat *E, *Q, *C; + isl_basic_set *dom, *ran; + + if (!bset) + return NULL; + + if (isl_basic_set_plain_is_empty(bset)) + return isl_morph_empty(bset); + + isl_assert(bset->ctx, bset->n_div == 0, return NULL); + + otype = 1 + isl_space_offset(bset->dim, type); + ntype = isl_basic_set_dim(bset, type); + orest = otype + ntype; + nrest = isl_basic_set_total_dim(bset) - (orest - 1); + + for (f_eq = 0; f_eq < bset->n_eq; ++f_eq) + if (isl_seq_first_non_zero(bset->eq[f_eq] + orest, nrest) == -1) + break; + for (n_eq = 0; f_eq + n_eq < bset->n_eq; ++n_eq) + if (isl_seq_first_non_zero(bset->eq[f_eq + n_eq] + otype, ntype) == -1) + break; + if (n_eq == 0) + return isl_morph_identity(bset); + + E = isl_mat_sub_alloc6(bset->ctx, bset->eq, f_eq, n_eq, 0, orest); + C = isl_mat_final_variable_compression(E, otype - 1, &Q); + if (!Q) + C = isl_mat_free(C); + if (C && C->n_col == 0) { + isl_mat_free(C); + isl_mat_free(Q); + return isl_morph_empty(bset); + } + + Q = isl_mat_diagonal(Q, isl_mat_identity(bset->ctx, nrest)); + C = isl_mat_diagonal(C, isl_mat_identity(bset->ctx, nrest)); + + space = isl_space_copy(bset->dim); + space = isl_space_drop_dims(space, type, 0, ntype); + space = isl_space_add_dims(space, type, ntype - n_eq); + space = isl_space_set_tuple_id(space, isl_dim_set, isl_id_copy(id)); + ran = isl_basic_set_universe(space); + dom = copy_equalities(bset, f_eq, n_eq); + + return isl_morph_alloc(dom, ran, Q, C); +} + +/* Given a basic set, exploit the equalities in the basic set to construct + * a morphism that maps the basic set to a lower-dimensional space. + * Specifically, the morphism reduces the number of dimensions of type "type". + */ +__isl_give isl_morph *isl_basic_set_variable_compression( + __isl_keep isl_basic_set *bset, enum isl_dim_type type) +{ + return isl_basic_set_variable_compression_with_id(bset, type, + &isl_id_none); +} + +/* Construct a parameter compression for "bset". + * We basically just call isl_mat_parameter_compression with the right input + * and then extend the resulting matrix to include the variables. + * + * The implementation assumes that "bset" does not have any equalities + * that only involve the parameters and that isl_basic_set_gauss has + * been applied to "bset". + * + * Let the equalities be given as + * + * B(p) + A x = 0. + * + * We use isl_mat_parameter_compression_ext to compute the compression + * + * p = T p'. + */ +__isl_give isl_morph *isl_basic_set_parameter_compression( + __isl_keep isl_basic_set *bset) +{ + unsigned nparam; + unsigned nvar; + unsigned n_div; + int n_eq; + isl_mat *H, *B; + isl_mat *map, *inv; + isl_basic_set *dom, *ran; + + if (!bset) + return NULL; + + if (isl_basic_set_plain_is_empty(bset)) + return isl_morph_empty(bset); + if (bset->n_eq == 0) + return isl_morph_identity(bset); + + n_eq = bset->n_eq; + nparam = isl_basic_set_dim(bset, isl_dim_param); + nvar = isl_basic_set_dim(bset, isl_dim_set); + n_div = isl_basic_set_dim(bset, isl_dim_div); + + if (isl_seq_first_non_zero(bset->eq[bset->n_eq - 1] + 1 + nparam, + nvar + n_div) == -1) + isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, + "input not allowed to have parameter equalities", + return NULL); + if (n_eq > nvar + n_div) + isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, + "input not gaussed", return NULL); + + 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 + n_div); + inv = isl_mat_parameter_compression_ext(B, H); + inv = isl_mat_diagonal(inv, isl_mat_identity(bset->ctx, nvar)); + map = isl_mat_right_inverse(isl_mat_copy(inv)); + + dom = isl_basic_set_universe(isl_space_copy(bset->dim)); + ran = isl_basic_set_universe(isl_space_copy(bset->dim)); + + return isl_morph_alloc(dom, ran, map, inv); +} + +/* Add stride constraints to "bset" based on the inverse mapping + * that was plugged in. In particular, if morph maps x' to x, + * the constraints of the original input + * + * A x' + b >= 0 + * + * have been rewritten to + * + * A inv x + b >= 0 + * + * However, this substitution may loose information on the integrality of x', + * so we need to impose that + * + * inv x + * + * is integral. If inv = B/d, this means that we need to impose that + * + * B x = 0 mod d + * + * or + * + * exists alpha in Z^m: B x = d alpha + * + * This function is similar to add_strides in isl_affine_hull.c + */ +static __isl_give isl_basic_set *add_strides(__isl_take isl_basic_set *bset, + __isl_keep isl_morph *morph) +{ + int i, div, k; + isl_int gcd; + + if (isl_int_is_one(morph->inv->row[0][0])) + return bset; + + isl_int_init(gcd); + + for (i = 0; 1 + i < morph->inv->n_row; ++i) { + isl_seq_gcd(morph->inv->row[1 + i], morph->inv->n_col, &gcd); + if (isl_int_is_divisible_by(gcd, morph->inv->row[0][0])) + continue; + div = isl_basic_set_alloc_div(bset); + if (div < 0) + goto error; + isl_int_set_si(bset->div[div][0], 0); + k = isl_basic_set_alloc_equality(bset); + if (k < 0) + goto error; + isl_seq_cpy(bset->eq[k], morph->inv->row[1 + i], + morph->inv->n_col); + isl_seq_clr(bset->eq[k] + morph->inv->n_col, bset->n_div); + isl_int_set(bset->eq[k][morph->inv->n_col + div], + morph->inv->row[0][0]); + } + + isl_int_clear(gcd); + + return bset; +error: + isl_int_clear(gcd); + isl_basic_set_free(bset); + return NULL; +} + +/* Apply the morphism to the basic set. + * We basically just compute the preimage of "bset" under the inverse mapping + * in morph, add in stride constraints and intersect with the range + * of the morphism. + */ +__isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph, + __isl_take isl_basic_set *bset) +{ + isl_basic_set *res = NULL; + isl_mat *mat = NULL; + int i, k; + int max_stride; + + if (!morph || !bset) + goto error; + + isl_assert(bset->ctx, isl_space_is_equal(bset->dim, morph->dom->dim), + goto error); + + max_stride = morph->inv->n_row - 1; + if (isl_int_is_one(morph->inv->row[0][0])) + max_stride = 0; + res = isl_basic_set_alloc_space(isl_space_copy(morph->ran->dim), + bset->n_div + max_stride, bset->n_eq + max_stride, bset->n_ineq); + + for (i = 0; i < bset->n_div; ++i) + if (isl_basic_set_alloc_div(res) < 0) + goto error; + + 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) + goto error; + for (i = 0; i < bset->n_eq; ++i) { + k = isl_basic_set_alloc_equality(res); + if (k < 0) + goto error; + isl_seq_cpy(res->eq[k], mat->row[i], mat->n_col); + isl_seq_scale(res->eq[k] + mat->n_col, bset->eq[i] + mat->n_col, + morph->inv->row[0][0], bset->n_div); + } + isl_mat_free(mat); + + 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) + goto error; + for (i = 0; i < bset->n_ineq; ++i) { + k = isl_basic_set_alloc_inequality(res); + if (k < 0) + goto error; + isl_seq_cpy(res->ineq[k], mat->row[i], mat->n_col); + isl_seq_scale(res->ineq[k] + mat->n_col, + bset->ineq[i] + mat->n_col, + morph->inv->row[0][0], bset->n_div); + } + isl_mat_free(mat); + + 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) + goto error; + for (i = 0; i < bset->n_div; ++i) { + isl_int_mul(res->div[i][0], + morph->inv->row[0][0], bset->div[i][0]); + isl_seq_cpy(res->div[i] + 1, mat->row[i], mat->n_col); + isl_seq_scale(res->div[i] + 1 + mat->n_col, + bset->div[i] + 1 + mat->n_col, + morph->inv->row[0][0], bset->n_div); + } + isl_mat_free(mat); + + res = add_strides(res, morph); + + if (isl_basic_set_is_rational(bset)) + res = isl_basic_set_set_rational(res); + + res = isl_basic_set_simplify(res); + res = isl_basic_set_finalize(res); + + res = isl_basic_set_intersect(res, isl_basic_set_copy(morph->ran)); + + isl_morph_free(morph); + isl_basic_set_free(bset); + return res; +error: + isl_mat_free(mat); + isl_morph_free(morph); + isl_basic_set_free(bset); + isl_basic_set_free(res); + return NULL; +} + +/* Apply the morphism to the set. + */ +__isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph, + __isl_take isl_set *set) +{ + int i; + + if (!morph || !set) + goto error; + + isl_assert(set->ctx, isl_space_is_equal(set->dim, morph->dom->dim), goto error); + + set = isl_set_cow(set); + if (!set) + goto error; + + isl_space_free(set->dim); + set->dim = isl_space_copy(morph->ran->dim); + if (!set->dim) + goto error; + + for (i = 0; i < set->n; ++i) { + set->p[i] = isl_morph_basic_set(isl_morph_copy(morph), set->p[i]); + if (!set->p[i]) + goto error; + } + + isl_morph_free(morph); + + ISL_F_CLR(set, ISL_SET_NORMALIZED); + + return set; +error: + isl_set_free(set); + isl_morph_free(morph); + return NULL; +} + +/* Construct a morphism that first does morph2 and then morph1. + */ +__isl_give isl_morph *isl_morph_compose(__isl_take isl_morph *morph1, + __isl_take isl_morph *morph2) +{ + isl_mat *map, *inv; + isl_basic_set *dom, *ran; + + if (!morph1 || !morph2) + goto error; + + map = isl_mat_product(isl_mat_copy(morph1->map), isl_mat_copy(morph2->map)); + inv = isl_mat_product(isl_mat_copy(morph2->inv), isl_mat_copy(morph1->inv)); + dom = isl_morph_basic_set(isl_morph_inverse(isl_morph_copy(morph2)), + isl_basic_set_copy(morph1->dom)); + dom = isl_basic_set_intersect(dom, isl_basic_set_copy(morph2->dom)); + ran = isl_morph_basic_set(isl_morph_copy(morph1), + isl_basic_set_copy(morph2->ran)); + ran = isl_basic_set_intersect(ran, isl_basic_set_copy(morph1->ran)); + + isl_morph_free(morph1); + isl_morph_free(morph2); + + return isl_morph_alloc(dom, ran, map, inv); +error: + isl_morph_free(morph1); + isl_morph_free(morph2); + return NULL; +} + +__isl_give isl_morph *isl_morph_inverse(__isl_take isl_morph *morph) +{ + isl_basic_set *bset; + isl_mat *mat; + + morph = isl_morph_cow(morph); + if (!morph) + return NULL; + + bset = morph->dom; + morph->dom = morph->ran; + morph->ran = bset; + + mat = morph->map; + morph->map = morph->inv; + morph->inv = mat; + + return morph; +} + +/* We detect all the equalities first to avoid implicit equalities + * being discovered during the computations. In particular, + * the compression on the variables could expose additional stride + * constraints on the parameters. This would result in existentially + * quantified variables after applying the resulting morph, which + * in turn could break invariants of the calling functions. + */ +__isl_give isl_morph *isl_basic_set_full_compression( + __isl_keep isl_basic_set *bset) +{ + isl_morph *morph, *morph2; + + bset = isl_basic_set_copy(bset); + bset = isl_basic_set_detect_equalities(bset); + + morph = isl_basic_set_variable_compression(bset, isl_dim_param); + bset = isl_morph_basic_set(isl_morph_copy(morph), bset); + + morph2 = isl_basic_set_parameter_compression(bset); + bset = isl_morph_basic_set(isl_morph_copy(morph2), bset); + + morph = isl_morph_compose(morph2, morph); + + morph2 = isl_basic_set_variable_compression(bset, isl_dim_set); + isl_basic_set_free(bset); + + morph = isl_morph_compose(morph2, morph); + + return morph; +} + +__isl_give isl_vec *isl_morph_vec(__isl_take isl_morph *morph, + __isl_take isl_vec *vec) +{ + if (!morph) + goto error; + + vec = isl_mat_vec_product(isl_mat_copy(morph->map), vec); + + isl_morph_free(morph); + return vec; +error: + isl_morph_free(morph); + isl_vec_free(vec); + return NULL; +} Index: contrib/isl/isl_multi_apply_set.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_apply_set.c @@ -0,0 +1,7 @@ +#define APPLY_DOMBASE set +#define APPLY_DOM isl_set + +#include + +#undef APPLY_DOMBASE +#undef APPLY_DOM Index: contrib/isl/isl_multi_apply_templ.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_apply_templ.c @@ -0,0 +1,84 @@ +/* + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include + +/* Transform the elements of "multi" by applying "fn" to them + * with extra argument "set". + * + * The parameters of "multi" and "set" are assumed to have been aligned. + */ +__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)( + __isl_take MULTI(BASE) *multi, __isl_take APPLY_DOM *set, + __isl_give EL *(*fn)(EL *el, __isl_take APPLY_DOM *set)) +{ + int i; + + if (!multi || !set) + goto error; + + if (multi->n == 0) { + FN(APPLY_DOM,free)(set); + return multi; + } + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + goto error; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = fn(multi->p[i], FN(APPLY_DOM,copy)(set)); + if (!multi->p[i]) + goto error; + } + + FN(APPLY_DOM,free)(set); + return multi; +error: + FN(APPLY_DOM,free)(set); + FN(MULTI(BASE),free)(multi); + return NULL; +} + +/* Transform the elements of "multi" by applying "fn" to them + * with extra argument "set". + * + * Align the parameters if needed and call apply_set_aligned. + */ +static __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),apply),APPLY_DOMBASE)( + __isl_take MULTI(BASE) *multi, __isl_take APPLY_DOM *set, + __isl_give EL *(*fn)(EL *el, __isl_take APPLY_DOM *set)) +{ + isl_bool aligned; + isl_ctx *ctx; + + if (!multi || !set) + goto error; + + aligned = FN(APPLY_DOM,space_has_equal_params)(set, multi->space); + if (aligned < 0) + goto error; + if (aligned) + return FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)(multi, + set, fn); + ctx = FN(MULTI(BASE),get_ctx)(multi); + if (!isl_space_has_named_params(multi->space) || + !isl_space_has_named_params(set->dim)) + isl_die(ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + multi = FN(MULTI(BASE),align_params)(multi, + FN(APPLY_DOM,get_space)(set)); + set = FN(APPLY_DOM,align_params)(set, FN(MULTI(BASE),get_space)(multi)); + return FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)(multi, set, fn); +error: + FN(MULTI(BASE),free)(multi); + FN(APPLY_DOM,free)(set); + return NULL; +} Index: contrib/isl/isl_multi_apply_union_set.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_apply_union_set.c @@ -0,0 +1,7 @@ +#define APPLY_DOMBASE union_set +#define APPLY_DOM isl_union_set + +#include + +#undef APPLY_DOMBASE +#undef APPLY_DOM Index: contrib/isl/isl_multi_cmp.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_cmp.c @@ -0,0 +1,40 @@ +/* + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege + */ + +#include + +/* Compare two multi expressions. + * + * Return -1 if "multi1" is "smaller" than "multi2", 1 if "multi1" is "greater" + * than "multi2" and 0 if they are equal. + */ +int FN(MULTI(BASE),plain_cmp)(__isl_keep MULTI(BASE) *multi1, + __isl_keep MULTI(BASE) *multi2) +{ + int i; + int cmp; + + if (multi1 == multi2) + return 0; + if (!multi1) + return -1; + if (!multi2) + return 1; + + cmp = isl_space_cmp(multi1->space, multi2->space); + if (cmp != 0) + return cmp; + + for (i = 0; i < multi1->n; ++i) { + cmp = FN(EL,plain_cmp)(multi1->p[i], multi2->p[i]); + if (cmp != 0) + return cmp; + } + + return 0; +} Index: contrib/isl/isl_multi_coalesce.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_coalesce.c @@ -0,0 +1,35 @@ +/* + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include + +/* Coalesce the elements of "multi". + * + * Note that such coalescing does not change the meaning of "multi" + * so there is no need to cow. We do need to be careful not to + * destroy any other copies of "multi" in case of failure. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),coalesce)(__isl_take MULTI(BASE) *multi) +{ + int i; + + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + EL *el = FN(EL,copy)(multi->p[i]); + el = FN(EL,coalesce)(el); + if (!el) + return FN(MULTI(BASE),free)(multi); + FN(EL,free)(multi->p[i]); + multi->p[i] = el; + } + + return multi; +} Index: contrib/isl/isl_multi_floor.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_floor.c @@ -0,0 +1,29 @@ +/* + * Copyright 2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include + +/* Given f, return floor(f). + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),floor)(__isl_take MULTI(BASE) *multi) +{ + int i; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,floor)(multi->p[i]); + if (!multi->p[i]) + return FN(MULTI(BASE),free)(multi); + } + + return multi; +} Index: contrib/isl/isl_multi_gist.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_gist.c @@ -0,0 +1,29 @@ +/* + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include + +/* Compute the gist of "multi" with respect to the domain constraints + * of "context". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),gist)(__isl_take MULTI(BASE) *multi, + __isl_take DOM *context) +{ + return FN(FN(MULTI(BASE),apply),DOMBASE)(multi, context, &FN(EL,gist)); +} + +/* Compute the gist of "multi" with respect to the parameter constraints + * of "context". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),gist_params)( + __isl_take MULTI(BASE) *multi, __isl_take isl_set *context) +{ + return FN(MULTI(BASE),apply_set)(multi, context, &FN(EL,gist_params)); +} Index: contrib/isl/isl_multi_hash.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_hash.c @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege + */ + +#include +#include + +/* Return a hash value that digests "multi". + */ +uint32_t FN(MULTI(BASE),get_hash)(__isl_keep MULTI(BASE) *multi) +{ + int i; + uint32_t hash; + + if (!multi) + return 0; + + hash = isl_hash_init(); + for (i = 0; i < multi->n; ++i) { + uint32_t el_hash; + el_hash = FN(EL,get_hash)(multi->p[i]); + isl_hash_hash(hash, el_hash); + } + + return hash; +} Index: contrib/isl/isl_multi_intersect.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_intersect.c @@ -0,0 +1,29 @@ +/* + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include + +/* Intersect the domain of "multi" with "domain". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain)( + __isl_take MULTI(BASE) *multi, __isl_take DOM *domain) +{ + return FN(FN(MULTI(BASE),apply),DOMBASE)(multi, domain, + &FN(EL,intersect_domain)); +} + +/* Intersect the parameter domain of "multi" with "domain". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params)( + __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain) +{ + return FN(MULTI(BASE),apply_set)(multi, domain, + &FN(EL,intersect_params)); +} Index: contrib/isl/isl_multi_macro.h =================================================================== --- /dev/null +++ contrib/isl/isl_multi_macro.h @@ -0,0 +1,10 @@ +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef EL +#define EL CAT(isl_,BASE) +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) +#define xMULTI(BASE) isl_multi_ ## BASE +#define MULTI(BASE) xMULTI(BASE) +#undef DOM +#define DOM CAT(isl_,DOMBASE) Index: contrib/isl/isl_multi_templ.h =================================================================== --- /dev/null +++ contrib/isl/isl_multi_templ.h @@ -0,0 +1,13 @@ +#include + +#include + +struct MULTI(BASE) { + int ref; + isl_space *space; + + int n; + EL *p[1]; +}; + +__isl_give MULTI(BASE) *CAT(MULTI(BASE),_alloc)(__isl_take isl_space *space); Index: contrib/isl/isl_multi_templ.c =================================================================== --- /dev/null +++ contrib/isl/isl_multi_templ.c @@ -0,0 +1,1514 @@ +/* + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include + +#include + +#define MULTI_NAME(BASE) "isl_multi_" #BASE +#define xLIST(EL) EL ## _list +#define LIST(EL) xLIST(EL) + +isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi) +{ + return multi ? isl_space_get_ctx(multi->space) : NULL; +} + +__isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi) +{ + return multi ? isl_space_copy(multi->space) : NULL; +} + +/* Return the position of the dimension of the given type and name + * in "multi". + * Return -1 if no such dimension can be found. + */ +int FN(MULTI(BASE),find_dim_by_name)(__isl_keep MULTI(BASE) *multi, + enum isl_dim_type type, const char *name) +{ + if (!multi) + return -1; + return isl_space_find_dim_by_name(multi->space, type, name); +} + +__isl_give isl_space *FN(MULTI(BASE),get_domain_space)( + __isl_keep MULTI(BASE) *multi) +{ + return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL; +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space) +{ + isl_ctx *ctx; + int n; + MULTI(BASE) *multi; + + if (!space) + return NULL; + + ctx = isl_space_get_ctx(space); + n = isl_space_dim(space, isl_dim_out); + multi = isl_calloc(ctx, MULTI(BASE), + sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *)); + if (!multi) + goto error; + + multi->space = space; + multi->n = n; + multi->ref = 1; + return multi; +error: + isl_space_free(space); + return NULL; +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi) +{ + int i; + MULTI(BASE) *dup; + + if (!multi) + return NULL; + + dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space)); + if (!dup) + return NULL; + + for (i = 0; i < multi->n; ++i) + dup = FN(FN(MULTI(BASE),set),BASE)(dup, i, + FN(EL,copy)(multi->p[i])); + + return dup; +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi) +{ + if (!multi) + return NULL; + + if (multi->ref == 1) + return multi; + + multi->ref--; + return FN(MULTI(BASE),dup)(multi); +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi) +{ + if (!multi) + return NULL; + + multi->ref++; + return multi; +} + +__isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi) +{ + int i; + + if (!multi) + return NULL; + + if (--multi->ref > 0) + return NULL; + + isl_space_free(multi->space); + for (i = 0; i < multi->n; ++i) + FN(EL,free)(multi->p[i]); + free(multi); + + return NULL; +} + +#ifndef NO_DIMS +/* Check whether "multi" has non-zero coefficients for any dimension + * in the given range or if any of these dimensions appear + * with non-zero coefficients in any of the integer divisions involved. + */ +isl_bool FN(MULTI(BASE),involves_dims)(__isl_keep MULTI(BASE) *multi, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!multi) + return isl_bool_error; + if (multi->n == 0 || n == 0) + return isl_bool_false; + + for (i = 0; i < multi->n; ++i) { + isl_bool involves; + + involves = FN(EL,involves_dims)(multi->p[i], type, first, n); + if (involves < 0 || involves) + return involves; + } + + return isl_bool_false; +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),insert_dims)( + __isl_take MULTI(BASE) *multi, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!multi) + return NULL; + if (type == isl_dim_out) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "cannot insert output/set dimensions", + return FN(MULTI(BASE),free)(multi)); + if (n == 0 && !isl_space_is_named_or_nested(multi->space, type)) + return multi; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + multi->space = isl_space_insert_dims(multi->space, type, first, n); + if (!multi->space) + return FN(MULTI(BASE),free)(multi); + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,insert_dims)(multi->p[i], type, first, n); + if (!multi->p[i]) + return FN(MULTI(BASE),free)(multi); + } + + return multi; +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),add_dims)(__isl_take MULTI(BASE) *multi, + enum isl_dim_type type, unsigned n) +{ + unsigned pos; + + pos = FN(MULTI(BASE),dim)(multi, type); + + return FN(MULTI(BASE),insert_dims)(multi, type, pos, n); +} +#endif + +unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi, + enum isl_dim_type type) +{ + return multi ? isl_space_dim(multi->space, type) : 0; +} + +/* Return the position of the first dimension of "type" with id "id". + * Return -1 if there is no such dimension. + */ +int FN(MULTI(BASE),find_dim_by_id)(__isl_keep MULTI(BASE) *multi, + enum isl_dim_type type, __isl_keep isl_id *id) +{ + if (!multi) + return -1; + return isl_space_find_dim_by_id(multi->space, type, id); +} + +/* Return the id of the given dimension. + */ +__isl_give isl_id *FN(MULTI(BASE),get_dim_id)(__isl_keep MULTI(BASE) *multi, + enum isl_dim_type type, unsigned pos) +{ + return multi ? isl_space_get_dim_id(multi->space, type, pos) : NULL; +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)( + __isl_take MULTI(BASE) *multi, + enum isl_dim_type type, unsigned pos, const char *s) +{ + int i; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + multi->space = isl_space_set_dim_name(multi->space, type, pos, s); + if (!multi->space) + return FN(MULTI(BASE),free)(multi); + + if (type == isl_dim_out) + return multi; + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,set_dim_name)(multi->p[i], type, pos, s); + if (!multi->p[i]) + return FN(MULTI(BASE),free)(multi); + } + + return multi; +} + +const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi, + enum isl_dim_type type) +{ + return multi ? isl_space_get_tuple_name(multi->space, type) : NULL; +} + +/* Does the specified tuple have an id? + */ +isl_bool FN(MULTI(BASE),has_tuple_id)(__isl_keep MULTI(BASE) *multi, + enum isl_dim_type type) +{ + if (!multi) + return isl_bool_error; + return isl_space_has_tuple_id(multi->space, type); +} + +/* Return the id of the specified tuple. + */ +__isl_give isl_id *FN(MULTI(BASE),get_tuple_id)(__isl_keep MULTI(BASE) *multi, + enum isl_dim_type type) +{ + return multi ? isl_space_get_tuple_id(multi->space, type) : NULL; +} + +__isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi, + int pos) +{ + isl_ctx *ctx; + + if (!multi) + return NULL; + ctx = FN(MULTI(BASE),get_ctx)(multi); + if (pos < 0 || pos >= multi->n) + isl_die(ctx, isl_error_invalid, + "index out of bounds", return NULL); + return FN(EL,copy)(multi->p[pos]); +} + +__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)( + __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el) +{ + isl_space *multi_space = NULL; + isl_space *el_space = NULL; + isl_bool match; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi || !el) + goto error; + + multi_space = FN(MULTI(BASE),get_space)(multi); + match = FN(EL,matching_params)(el, multi_space); + if (match < 0) + goto error; + if (!match) { + multi = FN(MULTI(BASE),align_params)(multi, + FN(EL,get_space)(el)); + isl_space_free(multi_space); + multi_space = FN(MULTI(BASE),get_space)(multi); + el = FN(EL,align_params)(el, isl_space_copy(multi_space)); + } + if (FN(EL,check_match_domain_space)(el, multi_space) < 0) + goto error; + + if (pos < 0 || pos >= multi->n) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "index out of bounds", goto error); + + FN(EL,free)(multi->p[pos]); + multi->p[pos] = el; + + isl_space_free(multi_space); + isl_space_free(el_space); + + return multi; +error: + FN(MULTI(BASE),free)(multi); + FN(EL,free)(el); + isl_space_free(multi_space); + isl_space_free(el_space); + return NULL; +} + +/* Reset the space of "multi". This function is called from isl_pw_templ.c + * and doesn't know if the space of an element object is represented + * directly or through its domain. It therefore passes along both, + * which we pass along to the element function since we don't know how + * that is represented either. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)( + __isl_take MULTI(BASE) *multi, __isl_take isl_space *space, + __isl_take isl_space *domain) +{ + int i; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi || !space || !domain) + goto error; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,reset_domain_space)(multi->p[i], + isl_space_copy(domain)); + if (!multi->p[i]) + goto error; + } + isl_space_free(domain); + isl_space_free(multi->space); + multi->space = space; + + return multi; +error: + isl_space_free(domain); + isl_space_free(space); + FN(MULTI(BASE),free)(multi); + return NULL; +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)( + __isl_take MULTI(BASE) *multi, __isl_take isl_space *domain) +{ + isl_space *space; + + space = isl_space_extend_domain_with_range(isl_space_copy(domain), + isl_space_copy(multi->space)); + return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain); +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)( + __isl_take MULTI(BASE) *multi, __isl_take isl_space *space) +{ + isl_space *domain; + + domain = isl_space_domain(isl_space_copy(space)); + return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain); +} + +/* Set the id of the given dimension of "multi" to "id". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_id)( + __isl_take MULTI(BASE) *multi, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) +{ + isl_space *space; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi || !id) + goto error; + + space = FN(MULTI(BASE),get_space)(multi); + space = isl_space_set_dim_id(space, type, pos, id); + + return FN(MULTI(BASE),reset_space)(multi, space); +error: + isl_id_free(id); + FN(MULTI(BASE),free)(multi); + return NULL; +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)( + __isl_keep MULTI(BASE) *multi, enum isl_dim_type type, + const char *s) +{ + isl_space *space; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + space = FN(MULTI(BASE),get_space)(multi); + space = isl_space_set_tuple_name(space, type, s); + + return FN(MULTI(BASE),reset_space)(multi, space); +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_id)( + __isl_take MULTI(BASE) *multi, enum isl_dim_type type, + __isl_take isl_id *id) +{ + isl_space *space; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + goto error; + + space = FN(MULTI(BASE),get_space)(multi); + space = isl_space_set_tuple_id(space, type, id); + + return FN(MULTI(BASE),reset_space)(multi, space); +error: + isl_id_free(id); + return NULL; +} + +/* Drop the id on the specified tuple. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_tuple_id)( + __isl_take MULTI(BASE) *multi, enum isl_dim_type type) +{ + isl_space *space; + + if (!multi) + return NULL; + if (!FN(MULTI(BASE),has_tuple_id)(multi, type)) + return multi; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + space = FN(MULTI(BASE),get_space)(multi); + space = isl_space_reset_tuple_id(space, type); + + return FN(MULTI(BASE),reset_space)(multi, space); +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the space of "multi". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_user)( + __isl_take MULTI(BASE) *multi) +{ + isl_space *space; + + space = FN(MULTI(BASE),get_space)(multi); + space = isl_space_reset_user(space); + + return FN(MULTI(BASE),reset_space)(multi, space); +} + +__isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)( + __isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp) +{ + int i; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi || !exp) + goto error; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,realign_domain)(multi->p[i], + isl_reordering_copy(exp)); + if (!multi->p[i]) + goto error; + } + + multi = FN(MULTI(BASE),reset_domain_space)(multi, + isl_space_copy(exp->dim)); + + isl_reordering_free(exp); + return multi; +error: + isl_reordering_free(exp); + FN(MULTI(BASE),free)(multi); + return NULL; +} + +/* Align the parameters of "multi" to those of "model". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)( + __isl_take MULTI(BASE) *multi, __isl_take isl_space *model) +{ + isl_ctx *ctx; + isl_bool equal_params; + isl_reordering *exp; + + if (!multi || !model) + goto error; + + equal_params = isl_space_has_equal_params(multi->space, model); + if (equal_params < 0) + goto error; + if (equal_params) { + isl_space_free(model); + return multi; + } + + ctx = isl_space_get_ctx(model); + if (!isl_space_has_named_params(model)) + isl_die(ctx, isl_error_invalid, + "model has unnamed parameters", goto error); + if (!isl_space_has_named_params(multi->space)) + isl_die(ctx, isl_error_invalid, + "input has unnamed parameters", goto error); + + model = isl_space_params(model); + exp = isl_parameter_alignment_reordering(multi->space, model); + exp = isl_reordering_extend_space(exp, + FN(MULTI(BASE),get_domain_space)(multi)); + multi = FN(MULTI(BASE),realign_domain)(multi, exp); + + isl_space_free(model); + return multi; +error: + isl_space_free(model); + FN(MULTI(BASE),free)(multi); + return NULL; +} + +__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))( + __isl_take isl_space *space, __isl_take LIST(EL) *list) +{ + int i; + int n; + isl_ctx *ctx; + MULTI(BASE) *multi; + + if (!space || !list) + goto error; + + ctx = isl_space_get_ctx(space); + n = FN(FN(LIST(EL),n),BASE)(list); + if (n != isl_space_dim(space, isl_dim_out)) + isl_die(ctx, isl_error_invalid, + "invalid number of elements in list", goto error); + + multi = FN(MULTI(BASE),alloc)(isl_space_copy(space)); + for (i = 0; i < n; ++i) { + multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, + FN(FN(LIST(EL),get),BASE)(list, i)); + } + + isl_space_free(space); + FN(LIST(EL),free)(list); + return multi; +error: + isl_space_free(space); + FN(LIST(EL),free)(list); + return NULL; +} + +#ifndef NO_IDENTITY +/* Create a multi expression in the given space that maps each + * input dimension to the corresponding output dimension. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),identity)(__isl_take isl_space *space) +{ + int i, n; + isl_local_space *ls; + MULTI(BASE) *multi; + + if (!space) + return NULL; + + if (isl_space_is_set(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "expecting map space", goto error); + + n = isl_space_dim(space, isl_dim_out); + if (n != isl_space_dim(space, isl_dim_in)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "number of input and output dimensions needs to be " + "the same", goto error); + + multi = FN(MULTI(BASE),alloc)(isl_space_copy(space)); + + if (!n) { + isl_space_free(space); + return multi; + } + + space = isl_space_domain(space); + ls = isl_local_space_from_space(space); + + for (i = 0; i < n; ++i) { + EL *el; + el = FN(EL,var_on_domain)(isl_local_space_copy(ls), + isl_dim_set, i); + multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, el); + } + + isl_local_space_free(ls); + + return multi; +error: + isl_space_free(space); + return NULL; +} +#endif + +#ifndef NO_ZERO +/* Construct a multi expression in the given space with value zero in + * each of the output dimensions. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space) +{ + int n; + MULTI(BASE) *multi; + + if (!space) + return NULL; + + n = isl_space_dim(space , isl_dim_out); + multi = FN(MULTI(BASE),alloc)(isl_space_copy(space)); + + if (!n) + isl_space_free(space); + else { + int i; + isl_local_space *ls; + EL *el; + + space = isl_space_domain(space); + ls = isl_local_space_from_space(space); + el = FN(EL,zero_on_domain)(ls); + + for (i = 0; i < n; ++i) + multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, + FN(EL,copy)(el)); + + FN(EL,free)(el); + } + + return multi; +} +#endif + +#ifndef NO_FROM_BASE +/* Create a multiple expression with a single output/set dimension + * equal to "el". + * For most multiple expression types, the base type has a single + * output/set dimension and the space of the result is therefore + * the same as the space of the input. + * In the case of isl_multi_union_pw_aff, however, the base type + * lives in a parameter space and we therefore need to add + * a single set dimension. + */ +__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),BASE)(__isl_take EL *el) +{ + isl_space *space; + MULTI(BASE) *multi; + + space = FN(EL,get_space(el)); + if (isl_space_is_params(space)) { + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, 1); + } + multi = FN(MULTI(BASE),alloc)(space); + multi = FN(FN(MULTI(BASE),set),BASE)(multi, 0, el); + + return multi; +} +#endif + +__isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)( + __isl_take MULTI(BASE) *multi, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + unsigned dim; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + dim = FN(MULTI(BASE),dim)(multi, type); + if (first + n > dim || first + n < first) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "index out of bounds", + return FN(MULTI(BASE),free)(multi)); + + multi->space = isl_space_drop_dims(multi->space, type, first, n); + if (!multi->space) + return FN(MULTI(BASE),free)(multi); + + if (type == isl_dim_out) { + for (i = 0; i < n; ++i) + FN(EL,free)(multi->p[first + i]); + for (i = first; i + n < multi->n; ++i) + multi->p[i] = multi->p[i + n]; + multi->n -= n; + + return multi; + } + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,drop_dims)(multi->p[i], type, first, n); + if (!multi->p[i]) + return FN(MULTI(BASE),free)(multi); + } + + return multi; +} + +/* Align the parameters of "multi1" and "multi2" (if needed) and call "fn". + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2, + __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1, + __isl_take MULTI(BASE) *multi2)) +{ + isl_ctx *ctx; + isl_bool equal_params; + + if (!multi1 || !multi2) + goto error; + equal_params = isl_space_has_equal_params(multi1->space, multi2->space); + if (equal_params < 0) + goto error; + if (equal_params) + return fn(multi1, multi2); + ctx = FN(MULTI(BASE),get_ctx)(multi1); + if (!isl_space_has_named_params(multi1->space) || + !isl_space_has_named_params(multi2->space)) + isl_die(ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + multi1 = FN(MULTI(BASE),align_params)(multi1, + FN(MULTI(BASE),get_space)(multi2)); + multi2 = FN(MULTI(BASE),align_params)(multi2, + FN(MULTI(BASE),get_space)(multi1)); + return fn(multi1, multi2); +error: + FN(MULTI(BASE),free)(multi1); + FN(MULTI(BASE),free)(multi2); + return NULL; +} + +/* Given two MULTI(BASE)s A -> B and C -> D, + * construct a MULTI(BASE) (A * C) -> [B -> D]. + * + * The parameters are assumed to have been aligned. + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2) +{ + int i, n1, n2; + EL *el; + isl_space *space; + MULTI(BASE) *res; + + if (!multi1 || !multi2) + goto error; + + space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1), + FN(MULTI(BASE),get_space)(multi2)); + res = FN(MULTI(BASE),alloc)(space); + + n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out); + n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out); + + for (i = 0; i < n1; ++i) { + el = FN(FN(MULTI(BASE),get),BASE)(multi1, i); + res = FN(FN(MULTI(BASE),set),BASE)(res, i, el); + } + + for (i = 0; i < n2; ++i) { + el = FN(FN(MULTI(BASE),get),BASE)(multi2, i); + res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el); + } + + FN(MULTI(BASE),free)(multi1); + FN(MULTI(BASE),free)(multi2); + return res; +error: + FN(MULTI(BASE),free)(multi1); + FN(MULTI(BASE),free)(multi2); + return NULL; +} + +/* Given two MULTI(BASE)s A -> B and C -> D, + * construct a MULTI(BASE) (A * C) -> [B -> D]. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2) +{ + return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2, + &FN(MULTI(BASE),range_product_aligned)); +} + +/* Is the range of "multi" a wrapped relation? + */ +isl_bool FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi) +{ + if (!multi) + return isl_bool_error; + return isl_space_range_is_wrapping(multi->space); +} + +/* Given a function A -> [B -> C], extract the function A -> B. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)( + __isl_take MULTI(BASE) *multi) +{ + isl_space *space; + int total, keep; + + if (!multi) + return NULL; + if (!isl_space_range_is_wrapping(multi->space)) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "range is not a product", + return FN(MULTI(BASE),free)(multi)); + + space = FN(MULTI(BASE),get_space)(multi); + total = isl_space_dim(space, isl_dim_out); + space = isl_space_range_factor_domain(space); + keep = isl_space_dim(space, isl_dim_out); + multi = FN(MULTI(BASE),drop_dims)(multi, + isl_dim_out, keep, total - keep); + multi = FN(MULTI(BASE),reset_space)(multi, space); + + return multi; +} + +/* Given a function A -> [B -> C], extract the function A -> C. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)( + __isl_take MULTI(BASE) *multi) +{ + isl_space *space; + int total, keep; + + if (!multi) + return NULL; + if (!isl_space_range_is_wrapping(multi->space)) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "range is not a product", + return FN(MULTI(BASE),free)(multi)); + + space = FN(MULTI(BASE),get_space)(multi); + total = isl_space_dim(space, isl_dim_out); + space = isl_space_range_factor_range(space); + keep = isl_space_dim(space, isl_dim_out); + multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep); + multi = FN(MULTI(BASE),reset_space)(multi, space); + + return multi; +} + +/* Given a function [B -> C], extract the function C. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)( + __isl_take MULTI(BASE) *multi) +{ + isl_space *space; + int total, keep; + + if (!multi) + return NULL; + if (!isl_space_is_wrapping(multi->space)) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "not a product", return FN(MULTI(BASE),free)(multi)); + + space = FN(MULTI(BASE),get_space)(multi); + total = isl_space_dim(space, isl_dim_out); + space = isl_space_factor_range(space); + keep = isl_space_dim(space, isl_dim_out); + multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep); + multi = FN(MULTI(BASE),reset_space)(multi, space); + + return multi; +} + +#ifndef NO_PRODUCT +/* Given two MULTI(BASE)s A -> B and C -> D, + * construct a MULTI(BASE) [A -> C] -> [B -> D]. + * + * The parameters are assumed to have been aligned. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),product_aligned)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2) +{ + int i; + EL *el; + isl_space *space; + MULTI(BASE) *res; + int in1, in2, out1, out2; + + in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in); + in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in); + out1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out); + out2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out); + space = isl_space_product(FN(MULTI(BASE),get_space)(multi1), + FN(MULTI(BASE),get_space)(multi2)); + res = FN(MULTI(BASE),alloc)(isl_space_copy(space)); + space = isl_space_domain(space); + + for (i = 0; i < out1; ++i) { + el = FN(FN(MULTI(BASE),get),BASE)(multi1, i); + el = FN(EL,insert_dims)(el, isl_dim_in, in1, in2); + el = FN(EL,reset_domain_space)(el, isl_space_copy(space)); + res = FN(FN(MULTI(BASE),set),BASE)(res, i, el); + } + + for (i = 0; i < out2; ++i) { + el = FN(FN(MULTI(BASE),get),BASE)(multi2, i); + el = FN(EL,insert_dims)(el, isl_dim_in, 0, in1); + el = FN(EL,reset_domain_space)(el, isl_space_copy(space)); + res = FN(FN(MULTI(BASE),set),BASE)(res, out1 + i, el); + } + + isl_space_free(space); + FN(MULTI(BASE),free)(multi1); + FN(MULTI(BASE),free)(multi2); + return res; +} + +/* Given two MULTI(BASE)s A -> B and C -> D, + * construct a MULTI(BASE) [A -> C] -> [B -> D]. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),product)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2) +{ + return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2, + &FN(MULTI(BASE),product_aligned)); +} +#endif + +__isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)( + __isl_take MULTI(BASE) *multi) +{ + if (!multi) + return NULL; + + if (!multi->space->nested[1]) + return multi; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + multi->space = isl_space_flatten_range(multi->space); + if (!multi->space) + return FN(MULTI(BASE),free)(multi); + + return multi; +} + +/* Given two MULTI(BASE)s A -> B and C -> D, + * construct a MULTI(BASE) (A * C) -> (B, D). + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2) +{ + MULTI(BASE) *multi; + + multi = FN(MULTI(BASE),range_product)(multi1, multi2); + multi = FN(MULTI(BASE),flatten_range)(multi); + return multi; +} + +/* Given two multi expressions, "multi1" + * + * [A] -> [B1 B2] + * + * where B2 starts at position "pos", and "multi2" + * + * [A] -> [D] + * + * return the multi expression + * + * [A] -> [B1 D B2] + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)( + __isl_take MULTI(BASE) *multi1, unsigned pos, + __isl_take MULTI(BASE) *multi2) +{ + MULTI(BASE) *res; + unsigned dim; + + if (!multi1 || !multi2) + goto error; + + dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out); + if (pos > dim) + isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid, + "index out of bounds", goto error); + + res = FN(MULTI(BASE),copy)(multi1); + res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos); + multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos); + + res = FN(MULTI(BASE),flat_range_product)(res, multi2); + res = FN(MULTI(BASE),flat_range_product)(res, multi1); + + return res; +error: + FN(MULTI(BASE),free)(multi1); + FN(MULTI(BASE),free)(multi2); + return NULL; +} + +#ifndef NO_SPLICE +/* Given two multi expressions, "multi1" + * + * [A1 A2] -> [B1 B2] + * + * where A2 starts at position "in_pos" and B2 starts at position "out_pos", + * and "multi2" + * + * [C] -> [D] + * + * return the multi expression + * + * [A1 C A2] -> [B1 D B2] + * + * We first insert input dimensions to obtain + * + * [A1 C A2] -> [B1 B2] + * + * and + * + * [A1 C A2] -> [D] + * + * and then apply range_splice. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),splice)( + __isl_take MULTI(BASE) *multi1, unsigned in_pos, unsigned out_pos, + __isl_take MULTI(BASE) *multi2) +{ + unsigned n_in1; + unsigned n_in2; + + if (!multi1 || !multi2) + goto error; + + n_in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in); + if (in_pos > n_in1) + isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid, + "index out of bounds", goto error); + + n_in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in); + + multi1 = FN(MULTI(BASE),insert_dims)(multi1, isl_dim_in, in_pos, n_in2); + multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, n_in2, + n_in1 - in_pos); + multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, 0, in_pos); + + return FN(MULTI(BASE),range_splice)(multi1, out_pos, multi2); +error: + FN(MULTI(BASE),free)(multi1); + FN(MULTI(BASE),free)(multi2); + return NULL; +} +#endif + +/* This function is currently only used from isl_aff.c + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2, + __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *)) + __attribute__ ((unused)); + +/* Pairwise perform "fn" to the elements of "multi1" and "multi2" and + * return the result. + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2, + __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *)) +{ + int i; + isl_ctx *ctx; + + multi1 = FN(MULTI(BASE),cow)(multi1); + if (!multi1 || !multi2) + goto error; + + ctx = FN(MULTI(BASE),get_ctx)(multi1); + if (!isl_space_is_equal(multi1->space, multi2->space)) + isl_die(ctx, isl_error_invalid, + "spaces don't match", goto error); + + for (i = 0; i < multi1->n; ++i) { + multi1->p[i] = fn(multi1->p[i], FN(EL,copy)(multi2->p[i])); + if (!multi1->p[i]) + goto error; + } + + FN(MULTI(BASE),free)(multi2); + return multi1; +error: + FN(MULTI(BASE),free)(multi1); + FN(MULTI(BASE),free)(multi2); + return NULL; +} + +/* Add "multi2" from "multi1" and return the result. + * + * The parameters of "multi1" and "multi2" are assumed to have been aligned. + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),add_aligned)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2) +{ + return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,add)); +} + +/* Add "multi2" from "multi1" and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),add)(__isl_take MULTI(BASE) *multi1, + __isl_take MULTI(BASE) *multi2) +{ + return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2, + &FN(MULTI(BASE),add_aligned)); +} + +/* Subtract "multi2" from "multi1" and return the result. + * + * The parameters of "multi1" and "multi2" are assumed to have been aligned. + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),sub_aligned)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2) +{ + return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub)); +} + +/* Subtract "multi2" from "multi1" and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1, + __isl_take MULTI(BASE) *multi2) +{ + return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2, + &FN(MULTI(BASE),sub_aligned)); +} + +/* Multiply the elements of "multi" by "v" and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi, + __isl_take isl_val *v) +{ + int i; + + if (!multi || !v) + goto error; + + if (isl_val_is_one(v)) { + isl_val_free(v); + return multi; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational factor", goto error); + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,scale_val)(multi->p[i], isl_val_copy(v)); + if (!multi->p[i]) + goto error; + } + + isl_val_free(v); + return multi; +error: + isl_val_free(v); + return FN(MULTI(BASE),free)(multi); +} + +/* Divide the elements of "multi" by "v" and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)( + __isl_take MULTI(BASE) *multi, __isl_take isl_val *v) +{ + int i; + + if (!multi || !v) + goto error; + + if (isl_val_is_one(v)) { + isl_val_free(v); + return multi; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational factor", goto error); + if (isl_val_is_zero(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "cannot scale down by zero", goto error); + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,scale_down_val)(multi->p[i], + isl_val_copy(v)); + if (!multi->p[i]) + goto error; + } + + isl_val_free(v); + return multi; +error: + isl_val_free(v); + return FN(MULTI(BASE),free)(multi); +} + +/* Multiply the elements of "multi" by the corresponding element of "mv" + * and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)( + __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv) +{ + int i; + + if (!multi || !mv) + goto error; + + if (!isl_space_tuple_is_equal(multi->space, isl_dim_out, + mv->space, isl_dim_set)) + isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid, + "spaces don't match", goto error); + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + goto error; + + for (i = 0; i < multi->n; ++i) { + isl_val *v; + + v = isl_multi_val_get_val(mv, i); + multi->p[i] = FN(EL,scale_val)(multi->p[i], v); + if (!multi->p[i]) + goto error; + } + + isl_multi_val_free(mv); + return multi; +error: + isl_multi_val_free(mv); + return FN(MULTI(BASE),free)(multi); +} + +/* Divide the elements of "multi" by the corresponding element of "mv" + * and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)( + __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv) +{ + int i; + + if (!multi || !mv) + goto error; + + if (!isl_space_tuple_is_equal(multi->space, isl_dim_out, + mv->space, isl_dim_set)) + isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid, + "spaces don't match", goto error); + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + isl_val *v; + + v = isl_multi_val_get_val(mv, i); + multi->p[i] = FN(EL,scale_down_val)(multi->p[i], v); + if (!multi->p[i]) + goto error; + } + + isl_multi_val_free(mv); + return multi; +error: + isl_multi_val_free(mv); + return FN(MULTI(BASE),free)(multi); +} + +/* Compute the residues of the elements of "multi" modulo + * the corresponding element of "mv" and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),mod_multi_val)( + __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv) +{ + int i; + + if (!multi || !mv) + goto error; + + if (!isl_space_tuple_is_equal(multi->space, isl_dim_out, + mv->space, isl_dim_set)) + isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid, + "spaces don't match", goto error); + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + isl_val *v; + + v = isl_multi_val_get_val(mv, i); + multi->p[i] = FN(EL,mod_val)(multi->p[i], v); + if (!multi->p[i]) + goto error; + } + + isl_multi_val_free(mv); + return multi; +error: + isl_multi_val_free(mv); + return FN(MULTI(BASE),free)(multi); +} + +#ifndef NO_MOVE_DIMS +/* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi" + * to dimensions of "dst_type" at "dst_pos". + * + * We only support moving input dimensions to parameters and vice versa. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + int i; + + if (!multi) + return NULL; + + if (n == 0 && + !isl_space_is_named_or_nested(multi->space, src_type) && + !isl_space_is_named_or_nested(multi->space, dst_type)) + return multi; + + if (dst_type == isl_dim_out || src_type == isl_dim_out) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "cannot move output/set dimension", + return FN(MULTI(BASE),free)(multi)); + if (dst_type == isl_dim_div || src_type == isl_dim_div) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "cannot move divs", + return FN(MULTI(BASE),free)(multi)); + if (src_pos + n > isl_space_dim(multi->space, src_type)) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "range out of bounds", + return FN(MULTI(BASE),free)(multi)); + if (dst_type == src_type) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_unsupported, + "moving dims within the same type not supported", + return FN(MULTI(BASE),free)(multi)); + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos, + src_type, src_pos, n); + if (!multi->space) + return FN(MULTI(BASE),free)(multi); + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,move_dims)(multi->p[i], dst_type, dst_pos, + src_type, src_pos, n); + if (!multi->p[i]) + return FN(MULTI(BASE),free)(multi); + } + + return multi; +} +#endif + +/* Convert a multiple expression defined over a parameter domain + * into one that is defined over a zero-dimensional set. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)( + __isl_take MULTI(BASE) *multi) +{ + isl_space *space; + + if (!multi) + return NULL; + if (!isl_space_is_set(multi->space)) + isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, + "not living in a set space", + return FN(MULTI(BASE),free)(multi)); + + space = FN(MULTI(BASE),get_space)(multi); + space = isl_space_from_range(space); + multi = FN(MULTI(BASE),reset_space)(multi, space); + + return multi; +} + +/* Are "multi1" and "multi2" obviously equal? + */ +isl_bool FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1, + __isl_keep MULTI(BASE) *multi2) +{ + int i; + isl_bool equal; + + if (!multi1 || !multi2) + return isl_bool_error; + if (multi1->n != multi2->n) + return isl_bool_false; + equal = isl_space_is_equal(multi1->space, multi2->space); + if (equal < 0 || !equal) + return equal; + + for (i = 0; i < multi1->n; ++i) { + equal = FN(EL,plain_is_equal)(multi1->p[i], multi2->p[i]); + if (equal < 0 || !equal) + return equal; + } + + return isl_bool_true; +} + +/* Does "multi" involve any NaNs? + */ +isl_bool FN(MULTI(BASE),involves_nan)(__isl_keep MULTI(BASE) *multi) +{ + int i; + + if (!multi) + return isl_bool_error; + if (multi->n == 0) + return isl_bool_false; + + for (i = 0; i < multi->n; ++i) { + isl_bool has_nan = FN(EL,involves_nan)(multi->p[i]); + if (has_nan < 0 || has_nan) + return has_nan; + } + + return isl_bool_false; +} + +#ifndef NO_DOMAIN +/* Return the shared domain of the elements of "multi". + */ +__isl_give isl_set *FN(MULTI(BASE),domain)(__isl_take MULTI(BASE) *multi) +{ + int i; + isl_set *dom; + + if (!multi) + return NULL; + + dom = isl_set_universe(FN(MULTI(BASE),get_domain_space)(multi)); + for (i = 0; i < multi->n; ++i) { + isl_set *dom_i; + + dom_i = FN(EL,domain)(FN(FN(MULTI(BASE),get),BASE)(multi, i)); + dom = isl_set_intersect(dom, dom_i); + } + + FN(MULTI(BASE),free)(multi); + return dom; +} +#endif + +#ifndef NO_NEG +/* Return the opposite of "multi". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),neg)(__isl_take MULTI(BASE) *multi) +{ + int i; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,neg)(multi->p[i]); + if (!multi->p[i]) + return FN(MULTI(BASE),free)(multi); + } + + return multi; +} +#endif Index: contrib/isl/isl_obj.c =================================================================== --- /dev/null +++ contrib/isl/isl_obj.c @@ -0,0 +1,365 @@ +/* + * Copyright 2010 INRIA Saclay + * Copyright 2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void *isl_obj_val_copy(void *v) +{ + return isl_val_copy((isl_val *)v); +} + +static void isl_obj_val_free(void *v) +{ + isl_val_free((isl_val *)v); +} + +static __isl_give isl_printer *isl_obj_val_print(__isl_take isl_printer *p, + void *v) +{ + return isl_printer_print_val(p, (isl_val *)v); +} + +static void *isl_obj_val_add(void *v1, void *v2) +{ + return isl_val_add((isl_val *) v1, (isl_val *) v2); +} + +struct isl_obj_vtable isl_obj_val_vtable = { + isl_obj_val_copy, + isl_obj_val_add, + isl_obj_val_print, + isl_obj_val_free +}; + +static void *isl_obj_map_copy(void *v) +{ + return isl_map_copy((struct isl_map *)v); +} + +static void isl_obj_map_free(void *v) +{ + isl_map_free((struct isl_map *)v); +} + +static __isl_give isl_printer *isl_obj_map_print(__isl_take isl_printer *p, + void *v) +{ + return isl_printer_print_map(p, (struct isl_map *)v); +} + +static void *isl_obj_map_add(void *v1, void *v2) +{ + return isl_map_union((struct isl_map *)v1, (struct isl_map *)v2); +} + +struct isl_obj_vtable isl_obj_map_vtable = { + isl_obj_map_copy, + isl_obj_map_add, + isl_obj_map_print, + isl_obj_map_free +}; + +static void *isl_obj_union_map_copy(void *v) +{ + return isl_union_map_copy((isl_union_map *)v); +} + +static void isl_obj_union_map_free(void *v) +{ + isl_union_map_free((isl_union_map *)v); +} + +static __isl_give isl_printer *isl_obj_union_map_print(__isl_take isl_printer *p, + void *v) +{ + return isl_printer_print_union_map(p, (isl_union_map *)v); +} + +static void *isl_obj_union_map_add(void *v1, void *v2) +{ + return isl_union_map_union((isl_union_map *)v1, (isl_union_map *)v2); +} + +struct isl_obj_vtable isl_obj_union_map_vtable = { + isl_obj_union_map_copy, + isl_obj_union_map_add, + isl_obj_union_map_print, + isl_obj_union_map_free +}; + +static void *isl_obj_set_copy(void *v) +{ + return isl_set_copy((struct isl_set *)v); +} + +static void isl_obj_set_free(void *v) +{ + isl_set_free((struct isl_set *)v); +} + +static __isl_give isl_printer *isl_obj_set_print(__isl_take isl_printer *p, + void *v) +{ + return isl_printer_print_set(p, (struct isl_set *)v); +} + +static void *isl_obj_set_add(void *v1, void *v2) +{ + return isl_set_union((struct isl_set *)v1, (struct isl_set *)v2); +} + +struct isl_obj_vtable isl_obj_set_vtable = { + isl_obj_set_copy, + isl_obj_set_add, + isl_obj_set_print, + isl_obj_set_free +}; + +static void *isl_obj_union_set_copy(void *v) +{ + return isl_union_set_copy((isl_union_set *)v); +} + +static void isl_obj_union_set_free(void *v) +{ + isl_union_set_free((isl_union_set *)v); +} + +static __isl_give isl_printer *isl_obj_union_set_print(__isl_take isl_printer *p, + void *v) +{ + return isl_printer_print_union_set(p, (isl_union_set *)v); +} + +static void *isl_obj_union_set_add(void *v1, void *v2) +{ + return isl_union_set_union((isl_union_set *)v1, (isl_union_set *)v2); +} + +struct isl_obj_vtable isl_obj_union_set_vtable = { + isl_obj_union_set_copy, + isl_obj_union_set_add, + isl_obj_union_set_print, + isl_obj_union_set_free +}; + +static void *isl_obj_pw_multi_aff_copy(void *v) +{ + return isl_pw_multi_aff_copy((isl_pw_multi_aff *) v); +} + +static void isl_obj_pw_multi_aff_free(void *v) +{ + isl_pw_multi_aff_free((isl_pw_multi_aff *) v); +} + +static __isl_give isl_printer *isl_obj_pw_multi_aff_print( + __isl_take isl_printer *p, void *v) +{ + return isl_printer_print_pw_multi_aff(p, (isl_pw_multi_aff *) v); +} + +static void *isl_obj_pw_multi_aff_add(void *v1, void *v2) +{ + return isl_pw_multi_aff_add((isl_pw_multi_aff *) v1, + (isl_pw_multi_aff *) v2); +} + +struct isl_obj_vtable isl_obj_pw_multi_aff_vtable = { + isl_obj_pw_multi_aff_copy, + isl_obj_pw_multi_aff_add, + isl_obj_pw_multi_aff_print, + isl_obj_pw_multi_aff_free +}; + +static void *isl_obj_none_copy(void *v) +{ + return v; +} + +static void isl_obj_none_free(void *v) +{ +} + +static __isl_give isl_printer *isl_obj_none_print(__isl_take isl_printer *p, + void *v) +{ + return p; +} + +static void *isl_obj_none_add(void *v1, void *v2) +{ + return NULL; +} + +struct isl_obj_vtable isl_obj_none_vtable = { + isl_obj_none_copy, + isl_obj_none_add, + isl_obj_none_print, + isl_obj_none_free +}; + +static void *isl_obj_pw_qp_copy(void *v) +{ + return isl_pw_qpolynomial_copy((struct isl_pw_qpolynomial *)v); +} + +static void isl_obj_pw_qp_free(void *v) +{ + isl_pw_qpolynomial_free((struct isl_pw_qpolynomial *)v); +} + +static __isl_give isl_printer *isl_obj_pw_qp_print(__isl_take isl_printer *p, + void *v) +{ + return isl_printer_print_pw_qpolynomial(p, + (struct isl_pw_qpolynomial *)v); +} + +static void *isl_obj_pw_qp_add(void *v1, void *v2) +{ + return isl_pw_qpolynomial_add((struct isl_pw_qpolynomial *)v1, + (struct isl_pw_qpolynomial *)v2); +} + +struct isl_obj_vtable isl_obj_pw_qpolynomial_vtable = { + isl_obj_pw_qp_copy, + isl_obj_pw_qp_add, + isl_obj_pw_qp_print, + isl_obj_pw_qp_free +}; + +static void *isl_obj_union_pw_qp_copy(void *v) +{ + return isl_union_pw_qpolynomial_copy((struct isl_union_pw_qpolynomial *)v); +} + +static void isl_obj_union_pw_qp_free(void *v) +{ + isl_union_pw_qpolynomial_free((struct isl_union_pw_qpolynomial *)v); +} + +static __isl_give isl_printer *isl_obj_union_pw_qp_print( + __isl_take isl_printer *p, void *v) +{ + return isl_printer_print_union_pw_qpolynomial(p, + (struct isl_union_pw_qpolynomial *)v); +} + +static void *isl_obj_union_pw_qp_add(void *v1, void *v2) +{ + return isl_union_pw_qpolynomial_add( + (struct isl_union_pw_qpolynomial *)v1, + (struct isl_union_pw_qpolynomial *)v2); +} + +struct isl_obj_vtable isl_obj_union_pw_qpolynomial_vtable = { + isl_obj_union_pw_qp_copy, + isl_obj_union_pw_qp_add, + isl_obj_union_pw_qp_print, + isl_obj_union_pw_qp_free +}; + +static void *isl_obj_pw_qpf_copy(void *v) +{ + return isl_pw_qpolynomial_fold_copy((struct isl_pw_qpolynomial_fold *)v); +} + +static void isl_obj_pw_qpf_free(void *v) +{ + isl_pw_qpolynomial_fold_free((struct isl_pw_qpolynomial_fold *)v); +} + +static __isl_give isl_printer *isl_obj_pw_qpf_print(__isl_take isl_printer *p, + void *v) +{ + return isl_printer_print_pw_qpolynomial_fold(p, + (struct isl_pw_qpolynomial_fold *)v); +} + +static void *isl_obj_pw_qpf_add(void *v1, void *v2) +{ + return isl_pw_qpolynomial_fold_fold((struct isl_pw_qpolynomial_fold *)v1, + (struct isl_pw_qpolynomial_fold *)v2); +} + +struct isl_obj_vtable isl_obj_pw_qpolynomial_fold_vtable = { + isl_obj_pw_qpf_copy, + isl_obj_pw_qpf_add, + isl_obj_pw_qpf_print, + isl_obj_pw_qpf_free +}; + +static void *isl_obj_union_pw_qpf_copy(void *v) +{ + return isl_union_pw_qpolynomial_fold_copy((struct isl_union_pw_qpolynomial_fold *)v); +} + +static void isl_obj_union_pw_qpf_free(void *v) +{ + isl_union_pw_qpolynomial_fold_free((struct isl_union_pw_qpolynomial_fold *)v); +} + +static __isl_give isl_printer *isl_obj_union_pw_qpf_print( + __isl_take isl_printer *p, void *v) +{ + return isl_printer_print_union_pw_qpolynomial_fold(p, + (struct isl_union_pw_qpolynomial_fold *)v); +} + +static void *isl_obj_union_pw_qpf_add(void *v1, void *v2) +{ + return isl_union_pw_qpolynomial_fold_fold( + (struct isl_union_pw_qpolynomial_fold *)v1, + (struct isl_union_pw_qpolynomial_fold *)v2); +} + +struct isl_obj_vtable isl_obj_union_pw_qpolynomial_fold_vtable = { + isl_obj_union_pw_qpf_copy, + isl_obj_union_pw_qpf_add, + isl_obj_union_pw_qpf_print, + isl_obj_union_pw_qpf_free +}; + +static void *isl_obj_schedule_copy(void *v) +{ + return isl_schedule_copy((isl_schedule *) v); +} + +static void isl_obj_schedule_free(void *v) +{ + isl_schedule_free((isl_schedule *) v); +} + +static __isl_give isl_printer *isl_obj_schedule_print( + __isl_take isl_printer *p, void *v) +{ + return isl_printer_print_schedule(p, (isl_schedule *) v); +} + +struct isl_obj_vtable isl_obj_schedule_vtable = { + isl_obj_schedule_copy, + NULL, + isl_obj_schedule_print, + isl_obj_schedule_free +}; Index: contrib/isl/isl_options.c =================================================================== --- /dev/null +++ contrib/isl/isl_options.c @@ -0,0 +1,377 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +struct isl_arg_choice isl_pip_context_choice[] = { + {"gbr", ISL_CONTEXT_GBR}, + {"lexmin", ISL_CONTEXT_LEXMIN}, + {0} +}; + +struct isl_arg_choice isl_gbr_choice[] = { + {"never", ISL_GBR_NEVER}, + {"once", ISL_GBR_ONCE}, + {"always", ISL_GBR_ALWAYS}, + {0} +}; + +struct isl_arg_choice isl_closure_choice[] = { + {"isl", ISL_CLOSURE_ISL}, + {"box", ISL_CLOSURE_BOX}, + {0} +}; + +static struct isl_arg_choice bound[] = { + {"bernstein", ISL_BOUND_BERNSTEIN}, + {"range", ISL_BOUND_RANGE}, + {0} +}; + +static struct isl_arg_choice on_error[] = { + {"warn", ISL_ON_ERROR_WARN}, + {"continue", ISL_ON_ERROR_CONTINUE}, + {"abort", ISL_ON_ERROR_ABORT}, + {0} +}; + +static struct isl_arg_choice isl_schedule_algorithm_choice[] = { + {"isl", ISL_SCHEDULE_ALGORITHM_ISL}, + {"feautrier", ISL_SCHEDULE_ALGORITHM_FEAUTRIER}, + {0} +}; + +static struct isl_arg_flags bernstein_recurse[] = { + {"none", ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS, 0}, + {"factors", ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS, + ISL_BERNSTEIN_FACTORS}, + {"intervals", ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS, + ISL_BERNSTEIN_INTERVALS}, + {"full", ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS, + ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS}, + {0} +}; + +static struct isl_arg_choice convex[] = { + {"wrap", ISL_CONVEX_HULL_WRAP}, + {"fm", ISL_CONVEX_HULL_FM}, + {0} +}; + +#define ISL_SCHEDULE_FUSE_MAX 0 +#define ISL_SCHEDULE_FUSE_MIN 1 + +static struct isl_arg_choice fuse[] = { + {"max", ISL_SCHEDULE_FUSE_MAX}, + {"min", ISL_SCHEDULE_FUSE_MIN}, + {0} +}; + +/* Callback for setting the "schedule-fuse" option. + * This (now hidden) option tries to mimic an option that was + * replaced by the schedule-serialize-sccs option. + * Setting the old option to ISL_SCHEDULE_FUSE_MIN is now + * expressed by turning on the schedule-serialize-sccs option. + */ +static int set_fuse(void *opt, unsigned val) +{ + struct isl_options *options = opt; + + options->schedule_serialize_sccs = (val == ISL_SCHEDULE_FUSE_MIN); + + return 0; +} + +static struct isl_arg_choice separation_bounds[] = { + {"explicit", ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT}, + {"implicit", ISL_AST_BUILD_SEPARATION_BOUNDS_IMPLICIT}, + {0} +}; + +static void print_version(void) +{ + printf("%s", isl_version()); +} + +ISL_ARGS_START(struct isl_options, isl_options_args) +ISL_ARG_CHOICE(struct isl_options, context, 0, "context", \ + isl_pip_context_choice, ISL_CONTEXT_GBR, + "how to handle the pip context tableau") +ISL_ARG_CHOICE(struct isl_options, gbr, 0, "gbr", \ + isl_gbr_choice, ISL_GBR_ALWAYS, + "how often to use generalized basis reduction") +ISL_ARG_CHOICE(struct isl_options, closure, 0, "closure", \ + isl_closure_choice, ISL_CLOSURE_ISL, + "closure operation to use") +ISL_ARG_BOOL(struct isl_options, gbr_only_first, 0, "gbr-only-first", 0, + "only perform basis reduction in first direction") +ISL_ARG_CHOICE(struct isl_options, bound, 0, "bound", bound, + ISL_BOUND_BERNSTEIN, "algorithm to use for computing bounds") +ISL_ARG_CHOICE(struct isl_options, on_error, 0, "on-error", on_error, + ISL_ON_ERROR_WARN, "how to react if an error is detected") +ISL_ARG_FLAGS(struct isl_options, bernstein_recurse, 0, + "bernstein-recurse", bernstein_recurse, ISL_BERNSTEIN_FACTORS, NULL) +ISL_ARG_BOOL(struct isl_options, bernstein_triangulate, 0, + "bernstein-triangulate", 1, + "triangulate domains during Bernstein expansion") +ISL_ARG_BOOL(struct isl_options, pip_symmetry, 0, "pip-symmetry", 1, + "detect simple symmetries in PIP input") +ISL_ARG_CHOICE(struct isl_options, convex, 0, "convex-hull", \ + convex, ISL_CONVEX_HULL_WRAP, "convex hull algorithm to use") +ISL_ARG_BOOL(struct isl_options, coalesce_bounded_wrapping, 0, + "coalesce-bounded-wrapping", 1, "bound wrapping during coalescing") +ISL_ARG_INT(struct isl_options, schedule_max_coefficient, 0, + "schedule-max-coefficient", "limit", -1, "Only consider schedules " + "where the coefficients of the variable and parameter dimensions " + "do not exceed . A value of -1 allows arbitrary coefficients.") +ISL_ARG_INT(struct isl_options, schedule_max_constant_term, 0, + "schedule-max-constant-term", "limit", -1, "Only consider schedules " + "where the coefficients of the constant dimension do not exceed " + ". A value of -1 allows arbitrary coefficients.") +ISL_ARG_BOOL(struct isl_options, schedule_parametric, 0, + "schedule-parametric", 1, "construct possibly parametric schedules") +ISL_ARG_BOOL(struct isl_options, schedule_outer_coincidence, 0, + "schedule-outer-coincidence", 0, + "try to construct schedules where the outer member of each band " + "satisfies the coincidence constraints") +ISL_ARG_BOOL(struct isl_options, schedule_maximize_band_depth, 0, + "schedule-maximize-band-depth", 0, + "maximize the number of scheduling dimensions in a band") +ISL_ARG_BOOL(struct isl_options, schedule_maximize_coincidence, 0, + "schedule-maximize-coincidence", 0, + "maximize the number of coincident dimensions in a band") +ISL_ARG_BOOL(struct isl_options, schedule_split_scaled, 0, + "schedule-split-scaled", 1, + "split non-tilable bands with scaled schedules") +ISL_ARG_BOOL(struct isl_options, schedule_treat_coalescing, 0, + "schedule-treat-coalescing", 1, + "try and prevent or adjust schedules that perform loop coalescing") +ISL_ARG_BOOL(struct isl_options, schedule_separate_components, 0, + "schedule-separate-components", 1, + "separate components in dependence graph") +ISL_ARG_BOOL(struct isl_options, schedule_whole_component, 0, + "schedule-whole-component", 1, + "try and compute schedule for entire component first") +ISL_ARG_CHOICE(struct isl_options, schedule_algorithm, 0, + "schedule-algorithm", isl_schedule_algorithm_choice, + ISL_SCHEDULE_ALGORITHM_ISL, "scheduling algorithm to use") +ISL_ARG_BOOL(struct isl_options, schedule_carry_self_first, 0, + "schedule-carry-self-first", 1, "try and carry self-dependences first") +ISL_ARG_BOOL(struct isl_options, schedule_serialize_sccs, 0, + "schedule-serialize-sccs", 0, + "serialize strongly connected components in dependence graph") +ISL_ARG_PHANTOM_USER_CHOICE_F(0, "schedule-fuse", fuse, &set_fuse, + ISL_SCHEDULE_FUSE_MAX, "level of fusion during scheduling", + ISL_ARG_HIDDEN) +ISL_ARG_BOOL(struct isl_options, tile_scale_tile_loops, 0, + "tile-scale-tile-loops", 1, "scale tile loops") +ISL_ARG_BOOL(struct isl_options, tile_shift_point_loops, 0, + "tile-shift-point-loops", 1, "shift point loops to start at zero") +ISL_ARG_STR(struct isl_options, ast_iterator_type, 0, + "ast-iterator-type", "type", "int", + "type used for iterators during printing of AST") +ISL_ARG_BOOL(struct isl_options, ast_always_print_block, 0, + "ast-always-print-block", 0, "print for and if bodies as a block " + "regardless of the number of statements in the body") +ISL_ARG_BOOL(struct isl_options, ast_print_macro_once, 0, + "ast-print-macro-once", 0, "only print macro definitions once") +ISL_ARG_BOOL(struct isl_options, ast_build_atomic_upper_bound, 0, + "ast-build-atomic-upper-bound", 1, "generate atomic upper bounds") +ISL_ARG_BOOL(struct isl_options, ast_build_prefer_pdiv, 0, + "ast-build-prefer-pdiv", 1, "prefer pdiv operation over fdiv") +ISL_ARG_BOOL(struct isl_options, ast_build_detect_min_max, 0, + "ast-build-detect-min-max", 0, "detect min/max expressions") +ISL_ARG_BOOL(struct isl_options, ast_build_exploit_nested_bounds, 0, + "ast-build-exploit-nested-bounds", 1, + "simplify conditions based on bounds of nested for loops") +ISL_ARG_BOOL(struct isl_options, ast_build_group_coscheduled, 0, + "ast-build-group-coscheduled", 0, + "keep coscheduled domain elements together") +ISL_ARG_CHOICE(struct isl_options, ast_build_separation_bounds, 0, + "ast-build-separation-bounds", separation_bounds, + ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT, + "bounds to use during separation") +ISL_ARG_BOOL(struct isl_options, ast_build_scale_strides, 0, + "ast-build-scale-strides", 1, + "allow iterators of strided loops to be scaled down") +ISL_ARG_BOOL(struct isl_options, ast_build_allow_else, 0, + "ast-build-allow-else", 1, "generate if statements with else branches") +ISL_ARG_BOOL(struct isl_options, ast_build_allow_or, 0, + "ast-build-allow-or", 1, "generate if conditions with disjunctions") +ISL_ARG_BOOL(struct isl_options, print_stats, 0, "print-stats", 0, + "print statistics for every isl_ctx") +ISL_ARG_ULONG(struct isl_options, max_operations, 0, + "max-operations", 0, "default number of maximal operations per isl_ctx") +ISL_ARG_VERSION(print_version) +ISL_ARGS_END + +ISL_ARG_DEF(isl_options, struct isl_options, isl_options_args) + +ISL_ARG_CTX_DEF(isl_options, struct isl_options, isl_options_args) + +ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, bound) +ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, bound) + +ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, + on_error) +ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, + on_error) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + pip_symmetry) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + pip_symmetry) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + coalesce_bounded_wrapping) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + coalesce_bounded_wrapping) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + gbr_only_first) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + gbr_only_first) + +ISL_CTX_SET_INT_DEF(isl_options, struct isl_options, isl_options_args, + schedule_max_coefficient) +ISL_CTX_GET_INT_DEF(isl_options, struct isl_options, isl_options_args, + schedule_max_coefficient) + +ISL_CTX_SET_INT_DEF(isl_options, struct isl_options, isl_options_args, + schedule_max_constant_term) +ISL_CTX_GET_INT_DEF(isl_options, struct isl_options, isl_options_args, + schedule_max_constant_term) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_maximize_band_depth) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_maximize_band_depth) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_maximize_coincidence) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_maximize_coincidence) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_split_scaled) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_split_scaled) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_treat_coalescing) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_treat_coalescing) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_separate_components) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_separate_components) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_whole_component) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_whole_component) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_outer_coincidence) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_outer_coincidence) + +ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, + schedule_algorithm) +ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, + schedule_algorithm) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_carry_self_first) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_carry_self_first) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_serialize_sccs) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + schedule_serialize_sccs) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + tile_scale_tile_loops) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + tile_scale_tile_loops) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + tile_shift_point_loops) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + tile_shift_point_loops) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_atomic_upper_bound) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_atomic_upper_bound) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_prefer_pdiv) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_prefer_pdiv) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_detect_min_max) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_detect_min_max) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_exploit_nested_bounds) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_exploit_nested_bounds) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_group_coscheduled) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_group_coscheduled) + +ISL_CTX_SET_STR_DEF(isl_options, struct isl_options, isl_options_args, + ast_iterator_type) +ISL_CTX_GET_STR_DEF(isl_options, struct isl_options, isl_options_args, + ast_iterator_type) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_always_print_block) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_always_print_block) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_print_macro_once) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_print_macro_once) + +ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_separation_bounds) +ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_separation_bounds) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_scale_strides) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_scale_strides) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_allow_else) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_allow_else) + +ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_allow_or) +ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args, + ast_build_allow_or) Index: contrib/isl/isl_options_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_options_private.h @@ -0,0 +1,73 @@ +#ifndef ISL_OPTIONS_PRIVATE_H +#define ISL_OPTIONS_PRIVATE_H + +#include + +struct isl_options { + #define ISL_CONTEXT_GBR 0 + #define ISL_CONTEXT_LEXMIN 1 + unsigned context; + + #define ISL_GBR_NEVER 0 + #define ISL_GBR_ONCE 1 + #define ISL_GBR_ALWAYS 2 + unsigned gbr; + unsigned gbr_only_first; + + #define ISL_CLOSURE_ISL 0 + #define ISL_CLOSURE_BOX 1 + unsigned closure; + + int bound; + unsigned on_error; + + #define ISL_BERNSTEIN_FACTORS 1 + #define ISL_BERNSTEIN_INTERVALS 2 + int bernstein_recurse; + + int bernstein_triangulate; + + int pip_symmetry; + + #define ISL_CONVEX_HULL_WRAP 0 + #define ISL_CONVEX_HULL_FM 1 + int convex; + + int coalesce_bounded_wrapping; + + int schedule_max_coefficient; + int schedule_max_constant_term; + int schedule_parametric; + int schedule_outer_coincidence; + int schedule_maximize_band_depth; + int schedule_maximize_coincidence; + int schedule_split_scaled; + int schedule_treat_coalescing; + int schedule_separate_components; + int schedule_whole_component; + unsigned schedule_algorithm; + int schedule_carry_self_first; + int schedule_serialize_sccs; + + int tile_scale_tile_loops; + int tile_shift_point_loops; + + char *ast_iterator_type; + int ast_always_print_block; + int ast_print_macro_once; + + int ast_build_atomic_upper_bound; + int ast_build_prefer_pdiv; + int ast_build_detect_min_max; + int ast_build_exploit_nested_bounds; + int ast_build_group_coscheduled; + int ast_build_separation_bounds; + int ast_build_scale_strides; + int ast_build_allow_else; + int ast_build_allow_or; + + int print_stats; + unsigned long max_operations; +}; + +#endif Index: contrib/isl/isl_output.c =================================================================== --- /dev/null +++ contrib/isl/isl_output.c @@ -0,0 +1,3294 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const char *s_to[2] = { " -> ", " \\to " }; +static const char *s_and[2] = { " and ", " \\wedge " }; +static const char *s_or[2] = { " or ", " \\vee " }; +static const char *s_le[2] = { "<=", "\\le" }; +static const char *s_ge[2] = { ">=", "\\ge" }; +static const char *s_open_set[2] = { "{ ", "\\{\\, " }; +static const char *s_close_set[2] = { " }", " \\,\\}" }; +static const char *s_open_list[2] = { "[", "(" }; +static const char *s_close_list[2] = { "]", ")" }; +static const char *s_such_that[2] = { " : ", " \\mid " }; +static const char *s_open_exists[2] = { "exists (", "\\exists \\, " }; +static const char *s_close_exists[2] = { ")", "" }; +static const char *s_div_prefix[2] = { "e", "\\alpha_" }; +static const char *s_mod[2] = { "mod", "\\bmod" }; +static const char *s_param_prefix[2] = { "p", "p_" }; +static const char *s_input_prefix[2] = { "i", "i_" }; +static const char *s_output_prefix[2] = { "o", "o_" }; + +static __isl_give isl_printer *print_constraint_polylib( + struct isl_basic_map *bmap, int ineq, int n, __isl_take isl_printer *p) +{ + int i; + unsigned n_in = isl_basic_map_dim(bmap, isl_dim_in); + unsigned n_out = isl_basic_map_dim(bmap, isl_dim_out); + unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param); + isl_int *c = ineq ? bmap->ineq[n] : bmap->eq[n]; + + p = isl_printer_start_line(p); + p = isl_printer_print_int(p, ineq); + for (i = 0; i < n_out; ++i) { + p = isl_printer_print_str(p, " "); + p = isl_printer_print_isl_int(p, c[1+nparam+n_in+i]); + } + for (i = 0; i < n_in; ++i) { + p = isl_printer_print_str(p, " "); + p = isl_printer_print_isl_int(p, c[1+nparam+i]); + } + for (i = 0; i < bmap->n_div; ++i) { + p = isl_printer_print_str(p, " "); + p = isl_printer_print_isl_int(p, c[1+nparam+n_in+n_out+i]); + } + for (i = 0; i < nparam; ++i) { + p = isl_printer_print_str(p, " "); + p = isl_printer_print_isl_int(p, c[1+i]); + } + p = isl_printer_print_str(p, " "); + p = isl_printer_print_isl_int(p, c[0]); + p = isl_printer_end_line(p); + return p; +} + +static __isl_give isl_printer *print_constraints_polylib( + struct isl_basic_map *bmap, __isl_take isl_printer *p) +{ + int i; + + p = isl_printer_set_isl_int_width(p, 5); + + for (i = 0; i < bmap->n_eq; ++i) + p = print_constraint_polylib(bmap, 0, i, p); + for (i = 0; i < bmap->n_ineq; ++i) + p = print_constraint_polylib(bmap, 1, i, p); + + return p; +} + +static __isl_give isl_printer *bset_print_constraints_polylib( + struct isl_basic_set *bset, __isl_take isl_printer *p) +{ + return print_constraints_polylib(bset_to_bmap(bset), p); +} + +static __isl_give isl_printer *isl_basic_map_print_polylib( + __isl_keep isl_basic_map *bmap, __isl_take isl_printer *p, int ext) +{ + unsigned total = isl_basic_map_total_dim(bmap); + p = isl_printer_start_line(p); + p = isl_printer_print_int(p, bmap->n_eq + bmap->n_ineq); + p = isl_printer_print_str(p, " "); + p = isl_printer_print_int(p, 1 + total + 1); + if (ext) { + p = isl_printer_print_str(p, " "); + p = isl_printer_print_int(p, + isl_basic_map_dim(bmap, isl_dim_out)); + p = isl_printer_print_str(p, " "); + p = isl_printer_print_int(p, + isl_basic_map_dim(bmap, isl_dim_in)); + p = isl_printer_print_str(p, " "); + p = isl_printer_print_int(p, + isl_basic_map_dim(bmap, isl_dim_div)); + p = isl_printer_print_str(p, " "); + p = isl_printer_print_int(p, + isl_basic_map_dim(bmap, isl_dim_param)); + } + p = isl_printer_end_line(p); + return print_constraints_polylib(bmap, p); +} + +static __isl_give isl_printer *isl_basic_set_print_polylib( + __isl_keep isl_basic_set *bset, __isl_take isl_printer *p, int ext) +{ + return isl_basic_map_print_polylib(bset_to_bmap(bset), p, ext); +} + +static __isl_give isl_printer *isl_map_print_polylib(__isl_keep isl_map *map, + __isl_take isl_printer *p, int ext) +{ + int i; + + p = isl_printer_start_line(p); + p = isl_printer_print_int(p, map->n); + p = isl_printer_end_line(p); + for (i = 0; i < map->n; ++i) { + p = isl_printer_start_line(p); + p = isl_printer_end_line(p); + p = isl_basic_map_print_polylib(map->p[i], p, ext); + } + return p; +} + +static __isl_give isl_printer *isl_set_print_polylib(__isl_keep isl_set *set, + __isl_take isl_printer *p, int ext) +{ + return isl_map_print_polylib(set_to_map(set), p, ext); +} + +static int count_same_name(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos, const char *name) +{ + enum isl_dim_type t; + unsigned p, s; + int count = 0; + + for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) { + s = t == type ? pos : isl_space_dim(dim, t); + for (p = 0; p < s; ++p) { + const char *n = isl_space_get_dim_name(dim, t, p); + if (n && !strcmp(n, name)) + count++; + } + } + return count; +} + +/* Print the name of the variable of type "type" and position "pos" + * in "space" to "p". + */ +static __isl_give isl_printer *print_name(__isl_keep isl_space *space, + __isl_take isl_printer *p, enum isl_dim_type type, unsigned pos, + int latex) +{ + const char *name; + char buffer[20]; + int primes; + + name = type == isl_dim_div ? NULL + : isl_space_get_dim_name(space, type, pos); + + if (!name) { + const char *prefix; + if (type == isl_dim_param) + prefix = s_param_prefix[latex]; + else if (type == isl_dim_div) + prefix = s_div_prefix[latex]; + else if (isl_space_is_set(space) || type == isl_dim_in) + prefix = s_input_prefix[latex]; + else + prefix = s_output_prefix[latex]; + snprintf(buffer, sizeof(buffer), "%s%d", prefix, pos); + name = buffer; + } + primes = count_same_name(space, name == buffer ? isl_dim_div : type, + pos, name); + p = isl_printer_print_str(p, name); + while (primes-- > 0) + p = isl_printer_print_str(p, "'"); + return p; +} + +static enum isl_dim_type pos2type(__isl_keep isl_space *dim, unsigned *pos) +{ + enum isl_dim_type type; + unsigned n_in = isl_space_dim(dim, isl_dim_in); + unsigned n_out = isl_space_dim(dim, isl_dim_out); + unsigned nparam = isl_space_dim(dim, isl_dim_param); + + if (*pos < 1 + nparam) { + type = isl_dim_param; + *pos -= 1; + } else if (*pos < 1 + nparam + n_in) { + type = isl_dim_in; + *pos -= 1 + nparam; + } else if (*pos < 1 + nparam + n_in + n_out) { + type = isl_dim_out; + *pos -= 1 + nparam + n_in; + } else { + type = isl_dim_div; + *pos -= 1 + nparam + n_in + n_out; + } + + return type; +} + +/* Can the div expression of the integer division at position "row" of "div" + * be printed? + * In particular, are the div expressions available and does the selected + * variable have a known explicit representation? + * Furthermore, the Omega format does not allow any div expressions + * to be printed. + */ +static isl_bool can_print_div_expr(__isl_keep isl_printer *p, + __isl_keep isl_mat *div, int pos) +{ + if (p->output_format == ISL_FORMAT_OMEGA) + return isl_bool_false; + if (!div) + return isl_bool_false; + return !isl_int_is_zero(div->row[pos][0]); +} + +static __isl_give isl_printer *print_div(__isl_keep isl_space *dim, + __isl_keep isl_mat *div, int pos, __isl_take isl_printer *p); + +static __isl_give isl_printer *print_term(__isl_keep isl_space *space, + __isl_keep isl_mat *div, + isl_int c, unsigned pos, __isl_take isl_printer *p, int latex) +{ + enum isl_dim_type type; + int print_div_def; + + if (pos == 0) + return isl_printer_print_isl_int(p, c); + + type = pos2type(space, &pos); + print_div_def = type == isl_dim_div && can_print_div_expr(p, div, pos); + + if (isl_int_is_one(c)) + ; + else if (isl_int_is_negone(c)) + p = isl_printer_print_str(p, "-"); + else { + p = isl_printer_print_isl_int(p, c); + if (p->output_format == ISL_FORMAT_C || print_div_def) + p = isl_printer_print_str(p, "*"); + } + if (print_div_def) + p = print_div(space, div, pos, p); + else + p = print_name(space, p, type, pos, latex); + return p; +} + +static __isl_give isl_printer *print_affine_of_len(__isl_keep isl_space *dim, + __isl_keep isl_mat *div, + __isl_take isl_printer *p, isl_int *c, int len) +{ + int i; + int first; + + for (i = 0, first = 1; i < len; ++i) { + int flip = 0; + if (isl_int_is_zero(c[i])) + continue; + if (!first) { + if (isl_int_is_neg(c[i])) { + flip = 1; + isl_int_neg(c[i], c[i]); + p = isl_printer_print_str(p, " - "); + } else + p = isl_printer_print_str(p, " + "); + } + first = 0; + p = print_term(dim, div, c[i], i, p, 0); + if (flip) + isl_int_neg(c[i], c[i]); + } + if (first) + p = isl_printer_print_str(p, "0"); + return p; +} + +/* Print an affine expression "c" + * to "p", with the variable names taken from "space" and + * the integer division definitions taken from "div". + */ +static __isl_give isl_printer *print_affine(__isl_take isl_printer *p, + __isl_keep isl_space *space, __isl_keep isl_mat *div, isl_int *c) +{ + unsigned n_div; + unsigned len; + + if (!space || !div) + return isl_printer_free(p); + n_div = isl_mat_rows(div); + len = 1 + isl_space_dim(space, isl_dim_all) + n_div; + return print_affine_of_len(space, div, p, c, len); +} + +/* offset is the offset of local_dim inside data->type of data->space. + */ +static __isl_give isl_printer *print_nested_var_list(__isl_take isl_printer *p, + __isl_keep isl_space *local_dim, enum isl_dim_type local_type, + struct isl_print_space_data *data, int offset) +{ + int i; + + if (data->space != local_dim && local_type == isl_dim_out) + offset += local_dim->n_in; + + for (i = 0; i < isl_space_dim(local_dim, local_type); ++i) { + if (i) + p = isl_printer_print_str(p, ", "); + if (data->print_dim) + p = data->print_dim(p, data, offset + i); + else + p = print_name(data->space, p, data->type, offset + i, + data->latex); + } + return p; +} + +static __isl_give isl_printer *print_var_list(__isl_take isl_printer *p, + __isl_keep isl_space *space, enum isl_dim_type type) +{ + struct isl_print_space_data data = { .space = space, .type = type }; + + return print_nested_var_list(p, space, type, &data, 0); +} + +static __isl_give isl_printer *print_nested_map_dim(__isl_take isl_printer *p, + __isl_keep isl_space *local_dim, + struct isl_print_space_data *data, int offset); + +static __isl_give isl_printer *print_nested_tuple(__isl_take isl_printer *p, + __isl_keep isl_space *local_dim, enum isl_dim_type local_type, + struct isl_print_space_data *data, int offset) +{ + const char *name = NULL; + unsigned n = isl_space_dim(local_dim, local_type); + if ((local_type == isl_dim_in || local_type == isl_dim_out)) { + name = isl_space_get_tuple_name(local_dim, local_type); + if (name) { + if (data->latex) + p = isl_printer_print_str(p, "\\mathrm{"); + p = isl_printer_print_str(p, name); + if (data->latex) + p = isl_printer_print_str(p, "}"); + } + } + if (!data->latex || n != 1 || name) + p = isl_printer_print_str(p, s_open_list[data->latex]); + if ((local_type == isl_dim_in || local_type == isl_dim_out) && + local_dim->nested[local_type - isl_dim_in]) { + if (data->space != local_dim && local_type == isl_dim_out) + offset += local_dim->n_in; + p = print_nested_map_dim(p, + local_dim->nested[local_type - isl_dim_in], + data, offset); + } else + p = print_nested_var_list(p, local_dim, local_type, data, + offset); + if (!data->latex || n != 1 || name) + p = isl_printer_print_str(p, s_close_list[data->latex]); + return p; +} + +static __isl_give isl_printer *print_tuple(__isl_keep isl_space *dim, + __isl_take isl_printer *p, enum isl_dim_type type, + struct isl_print_space_data *data) +{ + data->space = dim; + data->type = type; + return print_nested_tuple(p, dim, type, data, 0); +} + +static __isl_give isl_printer *print_nested_map_dim(__isl_take isl_printer *p, + __isl_keep isl_space *local_dim, + struct isl_print_space_data *data, int offset) +{ + p = print_nested_tuple(p, local_dim, isl_dim_in, data, offset); + p = isl_printer_print_str(p, s_to[data->latex]); + p = print_nested_tuple(p, local_dim, isl_dim_out, data, offset); + + return p; +} + +__isl_give isl_printer *isl_print_space(__isl_keep isl_space *space, + __isl_take isl_printer *p, int rational, + struct isl_print_space_data *data) +{ + if (rational && !data->latex) + p = isl_printer_print_str(p, "rat: "); + if (isl_space_is_params(space)) + ; + else if (isl_space_is_set(space)) + p = print_tuple(space, p, isl_dim_set, data); + else { + p = print_tuple(space, p, isl_dim_in, data); + p = isl_printer_print_str(p, s_to[data->latex]); + p = print_tuple(space, p, isl_dim_out, data); + } + + return p; +} + +static __isl_give isl_printer *print_omega_parameters(__isl_keep isl_space *dim, + __isl_take isl_printer *p) +{ + if (isl_space_dim(dim, isl_dim_param) == 0) + return p; + + p = isl_printer_start_line(p); + p = isl_printer_print_str(p, "symbolic "); + p = print_var_list(p, dim, isl_dim_param); + p = isl_printer_print_str(p, ";"); + p = isl_printer_end_line(p); + return p; +} + +/* Does the inequality constraint following "i" in "bmap" + * have an opposite value for the same last coefficient? + * "last" is the position of the last coefficient of inequality "i". + * If the next constraint is a div constraint, then it is ignored + * since div constraints are not printed. + */ +static int next_is_opposite(__isl_keep isl_basic_map *bmap, int i, int last) +{ + unsigned total = isl_basic_map_total_dim(bmap); + unsigned o_div = isl_basic_map_offset(bmap, isl_dim_div); + + if (i + 1 >= bmap->n_ineq) + return 0; + if (isl_seq_last_non_zero(bmap->ineq[i + 1], 1 + total) != last) + return 0; + if (last >= o_div) { + isl_bool is_div; + is_div = isl_basic_map_is_div_constraint(bmap, + bmap->ineq[i + 1], last - o_div); + if (is_div < 0) + return -1; + if (is_div) + return 0; + } + return isl_int_abs_eq(bmap->ineq[i][last], bmap->ineq[i + 1][last]) && + !isl_int_eq(bmap->ineq[i][last], bmap->ineq[i + 1][last]); +} + +/* Return a string representation of the operator used when + * printing a constraint where the LHS is greater than or equal to the LHS + * (sign > 0) or smaller than or equal to the LHS (sign < 0). + * If "strict" is set, then return the strict version of the comparison + * operator. + */ +static const char *constraint_op(int sign, int strict, int latex) +{ + if (strict) + return sign < 0 ? "<" : ">"; + if (sign < 0) + return s_le[latex]; + else + return s_ge[latex]; +} + +/* Print one side of a constraint "c" to "p", with + * the variable names taken from "space" and the integer division definitions + * taken from "div". + * "last" is the position of the last non-zero coefficient. + * Let c' be the result of zeroing out this coefficient, then + * the partial constraint + * + * c' op + * + * is printed. + */ +static __isl_give isl_printer *print_half_constraint(__isl_take isl_printer *p, + __isl_keep isl_space *space, __isl_keep isl_mat *div, + isl_int *c, int last, const char *op, int latex) +{ + isl_int_set_si(c[last], 0); + p = print_affine(p, space, div, c); + + p = isl_printer_print_str(p, " "); + p = isl_printer_print_str(p, op); + p = isl_printer_print_str(p, " "); + + return p; +} + +/* Print a constraint "c" to "p", with the variable names + * taken from "space" and the integer division definitions taken from "div". + * "last" is the position of the last non-zero coefficient, which is + * moreover assumed to be negative. + * Let c' be the result of zeroing out this coefficient, then + * the constraint is printed in the form + * + * -c[last] op c' + */ +static __isl_give isl_printer *print_constraint(__isl_take isl_printer *p, + __isl_keep isl_space *space, __isl_keep isl_mat *div, + isl_int *c, int last, const char *op, int latex) +{ + isl_int_abs(c[last], c[last]); + + p = print_term(space, div, c[last], last, p, latex); + + p = isl_printer_print_str(p, " "); + p = isl_printer_print_str(p, op); + p = isl_printer_print_str(p, " "); + + isl_int_set_si(c[last], 0); + p = print_affine(p, space, div, c); + + return p; +} + +/* Given an integer division + * + * floor(f/m) + * + * at position "pos" in "div", print the corresponding modulo expression + * + * (f) mod m + * + * to "p". The variable names are taken from "space", while any + * nested integer division definitions are taken from "div". + */ +static __isl_give isl_printer *print_mod(__isl_take isl_printer *p, + __isl_keep isl_space *space, __isl_keep isl_mat *div, int pos, + int latex) +{ + if (!p || !div) + return isl_printer_free(p); + + p = isl_printer_print_str(p, "("); + p = print_affine_of_len(space, div, p, + div->row[pos] + 1, div->n_col - 1); + p = isl_printer_print_str(p, ") "); + p = isl_printer_print_str(p, s_mod[latex]); + p = isl_printer_print_str(p, " "); + p = isl_printer_print_isl_int(p, div->row[pos][0]); + return p; +} + +/* Can the equality constraints "c" be printed as a modulo constraint? + * In particular, is of the form + * + * f - a m floor(g/m) = 0, + * + * with c = -a m the coefficient at position "pos"? + * Return the position of the corresponding integer division if so. + * Return the number of integer divisions if not. + * Return -1 on error. + * + * Modulo constraints are currently not printed in C format. + * Other than that, "pos" needs to correspond to an integer division + * with explicit representation and "c" needs to be a multiple + * of the denominator of the integer division. + */ +static int print_as_modulo_pos(__isl_keep isl_printer *p, + __isl_keep isl_space *space, __isl_keep isl_mat *div, unsigned pos, + isl_int c) +{ + isl_bool can_print; + unsigned n_div; + enum isl_dim_type type; + + if (!p) + return -1; + n_div = isl_mat_rows(div); + if (p->output_format == ISL_FORMAT_C) + return n_div; + type = pos2type(space, &pos); + if (type != isl_dim_div) + return n_div; + can_print = can_print_div_expr(p, div, pos); + if (can_print < 0) + return -1; + if (!can_print) + return n_div; + if (!isl_int_is_divisible_by(c, div->row[pos][0])) + return n_div; + return pos; +} + +/* Print equality constraint "c" to "p" as a modulo constraint, + * with the variable names taken from "space" and + * the integer division definitions taken from "div". + * "last" is the position of the last non-zero coefficient, which is + * moreover assumed to be negative and a multiple of the denominator + * of the corresponding integer division. "div_pos" is the corresponding + * position in the sequence of integer divisions. + * + * The equality is of the form + * + * f - a m floor(g/m) = 0. + * + * Print it as + * + * a (g mod m) = -f + a g + */ +static __isl_give isl_printer *print_eq_mod_constraint( + __isl_take isl_printer *p, __isl_keep isl_space *space, + __isl_keep isl_mat *div, unsigned div_pos, + isl_int *c, int last, int latex) +{ + isl_ctx *ctx; + int multiple; + + ctx = isl_printer_get_ctx(p); + isl_int_divexact(c[last], c[last], div->row[div_pos][0]); + isl_int_abs(c[last], c[last]); + multiple = !isl_int_is_one(c[last]); + if (multiple) { + p = isl_printer_print_isl_int(p, c[last]); + p = isl_printer_print_str(p, "*("); + } + p = print_mod(p, space, div, div_pos, latex); + if (multiple) + p = isl_printer_print_str(p, ")"); + p = isl_printer_print_str(p, " = "); + isl_seq_combine(c, ctx->negone, c, + c[last], div->row[div_pos] + 1, last); + isl_int_set_si(c[last], 0); + p = print_affine(p, space, div, c); + return p; +} + +/* Print equality constraint "c" to "p", with the variable names + * taken from "space" and the integer division definitions taken from "div". + * "last" is the position of the last non-zero coefficient, which is + * moreover assumed to be negative. + * + * If possible, print the equality constraint as a modulo constraint. + */ +static __isl_give isl_printer *print_eq_constraint(__isl_take isl_printer *p, + __isl_keep isl_space *space, __isl_keep isl_mat *div, isl_int *c, + int last, int latex) +{ + unsigned n_div; + int div_pos; + + n_div = isl_mat_rows(div); + div_pos = print_as_modulo_pos(p, space, div, last, c[last]); + if (div_pos < 0) + return isl_printer_free(p); + if (div_pos < n_div) + return print_eq_mod_constraint(p, space, div, div_pos, + c, last, latex); + return print_constraint(p, space, div, c, last, "=", latex); +} + +/* Print the constraints of "bmap" to "p". + * The names of the variables are taken from "space" and + * the integer division definitions are taken from "div". + * Div constraints are only printed in "dump" mode. + * The constraints are sorted prior to printing (except in "dump" mode). + * + * If x is the last variable with a non-zero coefficient, + * then a lower bound + * + * f - a x >= 0 + * + * is printed as + * + * a x <= f + * + * while an upper bound + * + * f + a x >= 0 + * + * is printed as + * + * a x >= -f + * + * If the next constraint has an opposite sign for the same last coefficient, + * then it is printed as + * + * f >= a x + * + * or + * + * -f <= a x + * + * instead. In fact, the "a x" part is not printed explicitly, but + * reused from the next constraint, which is therefore treated as + * a first constraint in the conjunction. + * + * If the constant term of "f" is -1, then "f" is replaced by "f + 1" and + * the comparison operator is replaced by the strict variant. + * Essentially, ">= 1" is replaced by "> 0". + */ +static __isl_give isl_printer *print_constraints(__isl_keep isl_basic_map *bmap, + __isl_keep isl_space *space, __isl_keep isl_mat *div, + __isl_take isl_printer *p, int latex) +{ + int i; + isl_vec *c = NULL; + int rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); + unsigned total = isl_basic_map_total_dim(bmap); + unsigned o_div = isl_basic_map_offset(bmap, isl_dim_div); + int first = 1; + int dump; + + if (!p) + return NULL; + bmap = isl_basic_map_copy(bmap); + dump = p->dump; + if (!dump) + bmap = isl_basic_map_sort_constraints(bmap); + if (!bmap) + goto error; + + c = isl_vec_alloc(bmap->ctx, 1 + total); + if (!c) + goto error; + + for (i = bmap->n_eq - 1; i >= 0; --i) { + int l = isl_seq_last_non_zero(bmap->eq[i], 1 + total); + 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 (!first) + p = isl_printer_print_str(p, s_and[latex]); + if (isl_int_is_neg(bmap->eq[i][l])) + isl_seq_cpy(c->el, bmap->eq[i], 1 + total); + else + isl_seq_neg(c->el, bmap->eq[i], 1 + total); + p = print_eq_constraint(p, space, div, c->el, l, latex); + first = 0; + } + for (i = 0; i < bmap->n_ineq; ++i) { + int l = isl_seq_last_non_zero(bmap->ineq[i], 1 + total); + int strict; + int s; + const char *op; + if (l < 0) + continue; + if (!dump && l >= o_div && + can_print_div_expr(p, div, l - o_div)) { + isl_bool is_div; + is_div = isl_basic_map_is_div_constraint(bmap, + bmap->ineq[i], l - o_div); + if (is_div < 0) + goto error; + if (is_div) + continue; + } + if (!first) + p = isl_printer_print_str(p, s_and[latex]); + s = isl_int_sgn(bmap->ineq[i][l]); + strict = !rational && isl_int_is_negone(bmap->ineq[i][0]); + if (s < 0) + isl_seq_cpy(c->el, bmap->ineq[i], 1 + total); + else + isl_seq_neg(c->el, bmap->ineq[i], 1 + total); + if (strict) + isl_int_set_si(c->el[0], 0); + if (!dump && next_is_opposite(bmap, i, l)) { + op = constraint_op(-s, strict, latex); + p = print_half_constraint(p, space, div, c->el, l, + op, latex); + first = 1; + } else { + op = constraint_op(s, strict, latex); + p = print_constraint(p, space, div, c->el, l, + op, latex); + first = 0; + } + } + + isl_basic_map_free(bmap); + isl_vec_free(c); + + return p; +error: + isl_basic_map_free(bmap); + isl_vec_free(c); + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *print_div(__isl_keep isl_space *dim, + __isl_keep isl_mat *div, int pos, __isl_take isl_printer *p) +{ + int c; + + if (!p || !div) + return isl_printer_free(p); + + c = p->output_format == ISL_FORMAT_C; + p = isl_printer_print_str(p, c ? "floord(" : "floor(("); + p = print_affine_of_len(dim, div, p, + div->row[pos] + 1, div->n_col - 1); + p = isl_printer_print_str(p, c ? ", " : ")/"); + p = isl_printer_print_isl_int(p, div->row[pos][0]); + p = isl_printer_print_str(p, ")"); + return p; +} + +/* Print a comma separated list of div names, except those that have + * a definition that can be printed. + * If "print_defined_divs" is set, then those div names are printed + * as well, along with their definitions. + */ +static __isl_give isl_printer *print_div_list(__isl_take isl_printer *p, + __isl_keep isl_space *space, __isl_keep isl_mat *div, int latex, + int print_defined_divs) +{ + int i; + int first = 1; + unsigned n_div; + + if (!p || !space || !div) + return isl_printer_free(p); + + n_div = isl_mat_rows(div); + + for (i = 0; i < n_div; ++i) { + if (!print_defined_divs && can_print_div_expr(p, div, i)) + continue; + if (!first) + p = isl_printer_print_str(p, ", "); + p = print_name(space, p, isl_dim_div, i, latex); + first = 0; + if (!can_print_div_expr(p, div, i)) + continue; + p = isl_printer_print_str(p, " = "); + p = print_div(space, div, i, p); + } + + return p; +} + +/* Does printing an object with local variables described by "div" + * require an "exists" clause? + * That is, are there any local variables without an explicit representation? + * An exists clause is also needed in "dump" mode because + * explicit div representations are not printed inline in that case. + */ +static isl_bool need_exists(__isl_keep isl_printer *p, __isl_keep isl_mat *div) +{ + int i, n; + + if (!p || !div) + return isl_bool_error; + n = isl_mat_rows(div); + if (n == 0) + return isl_bool_false; + if (p->dump) + return isl_bool_true; + for (i = 0; i < n; ++i) + if (!can_print_div_expr(p, div, i)) + return isl_bool_true; + return isl_bool_false; +} + +/* Print the start of an exists clause, i.e., + * + * (exists variables: + * + * In dump mode, local variables with an explicit definition are printed + * as well because they will not be printed inline. + */ +static __isl_give isl_printer *open_exists(__isl_take isl_printer *p, + __isl_keep isl_space *space, __isl_keep isl_mat *div, int latex) +{ + int dump; + + if (!p) + return NULL; + + dump = p->dump; + p = isl_printer_print_str(p, s_open_exists[latex]); + p = print_div_list(p, space, div, latex, dump); + p = isl_printer_print_str(p, ": "); + + return p; +} + +/* Remove the explicit representations of all local variables in "div". + */ +static __isl_give isl_mat *mark_all_unknown(__isl_take isl_mat *div) +{ + int i, n_div; + + if (!div) + return NULL; + + n_div = isl_mat_rows(div); + for (i = 0; i < n_div; ++i) + div = isl_mat_set_element_si(div, i, 0, 0); + return div; +} + +/* Print the constraints of "bmap" to "p". + * The names of the variables are taken from "space". + * "latex" is set if the constraints should be printed in LaTeX format. + * Do not print inline explicit div representations in "dump" mode. + */ +static __isl_give isl_printer *print_disjunct(__isl_keep isl_basic_map *bmap, + __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) +{ + int dump; + isl_mat *div; + isl_bool exists; + + if (!p) + return NULL; + dump = p->dump; + div = isl_basic_map_get_divs(bmap); + exists = need_exists(p, div); + if (exists >= 0 && exists) + p = open_exists(p, space, div, latex); + + if (dump) + div = mark_all_unknown(div); + p = print_constraints(bmap, space, div, p, latex); + isl_mat_free(div); + + if (exists >= 0 && exists) + p = isl_printer_print_str(p, s_close_exists[latex]); + return p; +} + +/* Print a colon followed by the constraints of "bmap" + * to "p", provided there are any constraints. + * The names of the variables are taken from "space". + * "latex" is set if the constraints should be printed in LaTeX format. + */ +static __isl_give isl_printer *print_optional_disjunct( + __isl_keep isl_basic_map *bmap, __isl_keep isl_space *space, + __isl_take isl_printer *p, int latex) +{ + if (isl_basic_map_plain_is_universe(bmap)) + return p; + + p = isl_printer_print_str(p, ": "); + p = print_disjunct(bmap, space, p, latex); + + return p; +} + +static __isl_give isl_printer *basic_map_print_omega( + __isl_keep isl_basic_map *bmap, __isl_take isl_printer *p) +{ + p = isl_printer_print_str(p, "{ ["); + p = print_var_list(p, bmap->dim, isl_dim_in); + p = isl_printer_print_str(p, "] -> ["); + p = print_var_list(p, bmap->dim, isl_dim_out); + p = isl_printer_print_str(p, "] "); + p = print_optional_disjunct(bmap, bmap->dim, p, 0); + p = isl_printer_print_str(p, " }"); + return p; +} + +static __isl_give isl_printer *basic_set_print_omega( + __isl_keep isl_basic_set *bset, __isl_take isl_printer *p) +{ + p = isl_printer_print_str(p, "{ ["); + p = print_var_list(p, bset->dim, isl_dim_set); + p = isl_printer_print_str(p, "] "); + p = print_optional_disjunct(bset, bset->dim, p, 0); + p = isl_printer_print_str(p, " }"); + return p; +} + +static __isl_give isl_printer *isl_map_print_omega(__isl_keep isl_map *map, + __isl_take isl_printer *p) +{ + int i; + + for (i = 0; i < map->n; ++i) { + if (i) + p = isl_printer_print_str(p, " union "); + p = basic_map_print_omega(map->p[i], p); + } + return p; +} + +static __isl_give isl_printer *isl_set_print_omega(__isl_keep isl_set *set, + __isl_take isl_printer *p) +{ + int i; + + for (i = 0; i < set->n; ++i) { + if (i) + p = isl_printer_print_str(p, " union "); + p = basic_set_print_omega(set->p[i], p); + } + return p; +} + +/* Print the list of parameters in "space", followed by an arrow, to "p", + * if there are any parameters. + */ +static __isl_give isl_printer *print_param_tuple(__isl_take isl_printer *p, + __isl_keep isl_space *space, struct isl_print_space_data *data) +{ + if (!p || !space) + return isl_printer_free(p); + if (isl_space_dim(space, isl_dim_param) == 0) + return p; + + p = print_tuple(space, p, isl_dim_param, data); + p = isl_printer_print_str(p, s_to[data->latex]); + + return p; +} + +static __isl_give isl_printer *isl_basic_map_print_isl( + __isl_keep isl_basic_map *bmap, __isl_take isl_printer *p, + int latex) +{ + struct isl_print_space_data data = { .latex = latex }; + int rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); + + p = print_param_tuple(p, bmap->dim, &data); + p = isl_printer_print_str(p, "{ "); + p = isl_print_space(bmap->dim, p, rational, &data); + p = isl_printer_print_str(p, " : "); + p = print_disjunct(bmap, bmap->dim, p, latex); + p = isl_printer_print_str(p, " }"); + return p; +} + +/* Print the disjuncts of a map (or set) "map" to "p". + * The names of the variables are taken from "space". + * "latex" is set if the constraints should be printed in LaTeX format. + */ +static __isl_give isl_printer *print_disjuncts_core(__isl_keep isl_map *map, + __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) +{ + int i; + + if (map->n == 0) + p = isl_printer_print_str(p, "false"); + for (i = 0; i < map->n; ++i) { + if (i) + p = isl_printer_print_str(p, s_or[latex]); + if (map->n > 1 && map->p[i]->n_eq + map->p[i]->n_ineq > 1) + p = isl_printer_print_str(p, "("); + p = print_disjunct(map->p[i], space, p, latex); + if (map->n > 1 && map->p[i]->n_eq + map->p[i]->n_ineq > 1) + p = isl_printer_print_str(p, ")"); + } + return p; +} + +/* Print the disjuncts of a map (or set) "map" to "p". + * The names of the variables are taken from "space". + * "hull" describes constraints shared by all disjuncts of "map". + * "latex" is set if the constraints should be printed in LaTeX format. + * + * Print the disjuncts as a conjunction of "hull" and + * the result of removing the constraints of "hull" from "map". + * If this result turns out to be the universe, then simply print "hull". + */ +static __isl_give isl_printer *print_disjuncts_in_hull(__isl_keep isl_map *map, + __isl_keep isl_space *space, __isl_take isl_basic_map *hull, + __isl_take isl_printer *p, int latex) +{ + isl_bool is_universe; + + p = print_disjunct(hull, space, p, latex); + map = isl_map_plain_gist_basic_map(isl_map_copy(map), hull); + is_universe = isl_map_plain_is_universe(map); + if (is_universe < 0) + goto error; + if (!is_universe) { + p = isl_printer_print_str(p, s_and[latex]); + p = isl_printer_print_str(p, "("); + p = print_disjuncts_core(map, space, p, latex); + p = isl_printer_print_str(p, ")"); + } + isl_map_free(map); + + return p; +error: + isl_map_free(map); + isl_printer_free(p); + return NULL; +} + +/* Print the disjuncts of a map (or set) "map" to "p". + * The names of the variables are taken from "space". + * "latex" is set if the constraints should be printed in LaTeX format. + * + * If there are at least two disjuncts and "dump" mode is not turned out, + * check for any shared constraints among all disjuncts. + * If there are any, then print them separately in print_disjuncts_in_hull. + */ +static __isl_give isl_printer *print_disjuncts(__isl_keep isl_map *map, + __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) +{ + if (isl_map_plain_is_universe(map)) + return p; + + p = isl_printer_print_str(p, s_such_that[latex]); + if (!p) + return NULL; + + if (!p->dump && map->n >= 2) { + isl_basic_map *hull; + isl_bool is_universe; + + hull = isl_map_plain_unshifted_simple_hull(isl_map_copy(map)); + is_universe = isl_basic_map_plain_is_universe(hull); + if (is_universe < 0) + p = isl_printer_free(p); + else if (!is_universe) + return print_disjuncts_in_hull(map, space, hull, + p, latex); + isl_basic_map_free(hull); + } + + return print_disjuncts_core(map, space, p, latex); +} + +/* Print the disjuncts of a map (or set). + * The names of the variables are taken from "space". + * "latex" is set if the constraints should be printed in LaTeX format. + * + * If the map turns out to be a universal parameter domain, then + * we need to print the colon. Otherwise, the output looks identical + * to the empty set. + */ +static __isl_give isl_printer *print_disjuncts_map(__isl_keep isl_map *map, + __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) +{ + if (isl_map_plain_is_universe(map) && isl_space_is_params(map->dim)) + return isl_printer_print_str(p, s_such_that[latex]); + else + return print_disjuncts(map, space, p, latex); +} + +struct isl_aff_split { + isl_basic_map *aff; + isl_map *map; +}; + +static void free_split(__isl_take struct isl_aff_split *split, int n) +{ + int i; + + if (!split) + return; + + for (i = 0; i < n; ++i) { + isl_basic_map_free(split[i].aff); + isl_map_free(split[i].map); + } + + free(split); +} + +static __isl_give isl_basic_map *get_aff(__isl_take isl_basic_map *bmap) +{ + int i, j; + unsigned nparam, n_in, n_out, total; + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + return NULL; + if (isl_basic_map_free_inequality(bmap, bmap->n_ineq) < 0) + goto error; + + nparam = isl_basic_map_dim(bmap, isl_dim_param); + n_in = isl_basic_map_dim(bmap, isl_dim_in); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + total = isl_basic_map_dim(bmap, isl_dim_all); + for (i = bmap->n_eq - 1; i >= 0; --i) { + j = isl_seq_last_non_zero(bmap->eq[i] + 1, total); + if (j >= nparam && j < nparam + n_in + n_out && + (isl_int_is_one(bmap->eq[i][1 + j]) || + isl_int_is_negone(bmap->eq[i][1 + j]))) + continue; + if (isl_basic_map_drop_equality(bmap, i) < 0) + goto error; + } + + bmap = isl_basic_map_finalize(bmap); + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +static int aff_split_cmp(const void *p1, const void *p2, void *user) +{ + const struct isl_aff_split *s1, *s2; + s1 = (const struct isl_aff_split *) p1; + s2 = (const struct isl_aff_split *) p2; + + return isl_basic_map_plain_cmp(s1->aff, s2->aff); +} + +static __isl_give isl_basic_map *drop_aff(__isl_take isl_basic_map *bmap, + __isl_keep isl_basic_map *aff) +{ + int i, j; + unsigned total; + + if (!bmap || !aff) + goto error; + + total = isl_space_dim(bmap->dim, isl_dim_all); + + for (i = bmap->n_eq - 1; i >= 0; --i) { + if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total, + bmap->n_div) != -1) + continue; + for (j = 0; j < aff->n_eq; ++j) { + if (!isl_seq_eq(bmap->eq[i], aff->eq[j], 1 + total) && + !isl_seq_is_neg(bmap->eq[i], aff->eq[j], 1 + total)) + continue; + if (isl_basic_map_drop_equality(bmap, i) < 0) + goto error; + break; + } + } + + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +static __isl_give struct isl_aff_split *split_aff(__isl_keep isl_map *map) +{ + int i, n; + struct isl_aff_split *split; + isl_ctx *ctx; + + ctx = isl_map_get_ctx(map); + split = isl_calloc_array(ctx, struct isl_aff_split, map->n); + if (!split) + return NULL; + + for (i = 0; i < map->n; ++i) { + isl_basic_map *bmap; + split[i].aff = get_aff(isl_basic_map_copy(map->p[i])); + bmap = isl_basic_map_copy(map->p[i]); + bmap = isl_basic_map_cow(bmap); + bmap = drop_aff(bmap, split[i].aff); + split[i].map = isl_map_from_basic_map(bmap); + if (!split[i].aff || !split[i].map) + goto error; + } + + if (isl_sort(split, map->n, sizeof(struct isl_aff_split), + &aff_split_cmp, NULL) < 0) + goto error; + + n = map->n; + for (i = n - 1; i >= 1; --i) { + if (!isl_basic_map_plain_is_equal(split[i - 1].aff, + split[i].aff)) + continue; + isl_basic_map_free(split[i].aff); + split[i - 1].map = isl_map_union(split[i - 1].map, + split[i].map); + if (i != n - 1) + split[i] = split[n - 1]; + split[n - 1].aff = NULL; + split[n - 1].map = NULL; + --n; + } + + return split; +error: + free_split(split, map->n); + return NULL; +} + +static int defining_equality(__isl_keep isl_basic_map *eq, + __isl_keep isl_space *dim, enum isl_dim_type type, int pos) +{ + int i; + unsigned total; + + if (!eq) + return -1; + + pos += isl_space_offset(dim, type); + total = isl_basic_map_total_dim(eq); + + for (i = 0; i < eq->n_eq; ++i) { + if (isl_seq_last_non_zero(eq->eq[i] + 1, total) != pos) + continue; + if (isl_int_is_one(eq->eq[i][1 + pos])) + isl_seq_neg(eq->eq[i], eq->eq[i], 1 + total); + return i; + } + + return -1; +} + +/* Print dimension "pos" of data->space to "p". + * + * data->user is assumed to be an isl_basic_map keeping track of equalities. + * + * If the current dimension is defined by these equalities, then print + * the corresponding expression, assigned to the name of the dimension + * if there is any. Otherwise, print the name of the dimension. + */ +static __isl_give isl_printer *print_dim_eq(__isl_take isl_printer *p, + struct isl_print_space_data *data, unsigned pos) +{ + isl_basic_map *eq = data->user; + int j; + + j = defining_equality(eq, data->space, data->type, pos); + if (j >= 0) { + if (isl_space_has_dim_name(data->space, data->type, pos)) { + p = print_name(data->space, p, data->type, pos, + data->latex); + p = isl_printer_print_str(p, " = "); + } + pos += 1 + isl_space_offset(data->space, data->type); + p = print_affine_of_len(data->space, NULL, p, eq->eq[j], pos); + } else { + p = print_name(data->space, p, data->type, pos, data->latex); + } + + return p; +} + +static __isl_give isl_printer *print_split_map(__isl_take isl_printer *p, + struct isl_aff_split *split, int n, __isl_keep isl_space *space) +{ + struct isl_print_space_data data = { 0 }; + int i; + int rational; + + data.print_dim = &print_dim_eq; + for (i = 0; i < n; ++i) { + if (!split[i].map) + break; + rational = split[i].map->n > 0 && + ISL_F_ISSET(split[i].map->p[0], ISL_BASIC_MAP_RATIONAL); + if (i) + p = isl_printer_print_str(p, "; "); + data.user = split[i].aff; + p = isl_print_space(space, p, rational, &data); + p = print_disjuncts_map(split[i].map, space, p, 0); + } + + return p; +} + +static __isl_give isl_printer *isl_map_print_isl_body(__isl_keep isl_map *map, + __isl_take isl_printer *p) +{ + struct isl_print_space_data data = { 0 }; + struct isl_aff_split *split = NULL; + int rational; + + if (!p || !map) + return isl_printer_free(p); + if (!p->dump && map->n > 0) + split = split_aff(map); + if (split) { + p = print_split_map(p, split, map->n, map->dim); + } else { + rational = map->n > 0 && + ISL_F_ISSET(map->p[0], ISL_BASIC_MAP_RATIONAL); + p = isl_print_space(map->dim, p, rational, &data); + p = print_disjuncts_map(map, map->dim, p, 0); + } + free_split(split, map->n); + return p; +} + +static __isl_give isl_printer *isl_map_print_isl(__isl_keep isl_map *map, + __isl_take isl_printer *p) +{ + struct isl_print_space_data data = { 0 }; + + p = print_param_tuple(p, map->dim, &data); + p = isl_printer_print_str(p, s_open_set[0]); + p = isl_map_print_isl_body(map, p); + p = isl_printer_print_str(p, s_close_set[0]); + return p; +} + +static __isl_give isl_printer *print_latex_map(__isl_keep isl_map *map, + __isl_take isl_printer *p, __isl_keep isl_basic_map *aff) +{ + struct isl_print_space_data data = { 0 }; + + data.latex = 1; + p = print_param_tuple(p, map->dim, &data); + p = isl_printer_print_str(p, s_open_set[1]); + data.print_dim = &print_dim_eq; + data.user = aff; + p = isl_print_space(map->dim, p, 0, &data); + p = print_disjuncts_map(map, map->dim, p, 1); + p = isl_printer_print_str(p, s_close_set[1]); + + return p; +} + +static __isl_give isl_printer *isl_map_print_latex(__isl_keep isl_map *map, + __isl_take isl_printer *p) +{ + int i; + struct isl_aff_split *split = NULL; + + if (map->n > 0) + split = split_aff(map); + + if (!split) + return print_latex_map(map, p, NULL); + + for (i = 0; i < map->n; ++i) { + if (!split[i].map) + break; + if (i) + p = isl_printer_print_str(p, " \\cup "); + p = print_latex_map(split[i].map, p, split[i].aff); + } + + free_split(split, map->n); + return p; +} + +__isl_give isl_printer *isl_printer_print_basic_map(__isl_take isl_printer *p, + __isl_keep isl_basic_map *bmap) +{ + if (!p || !bmap) + goto error; + if (p->output_format == ISL_FORMAT_ISL) + return isl_basic_map_print_isl(bmap, p, 0); + else if (p->output_format == ISL_FORMAT_OMEGA) + return basic_map_print_omega(bmap, p); + isl_assert(bmap->ctx, 0, goto error); +error: + isl_printer_free(p); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_basic_set(__isl_take isl_printer *p, + __isl_keep isl_basic_set *bset) +{ + if (!p || !bset) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return isl_basic_map_print_isl(bset, p, 0); + else if (p->output_format == ISL_FORMAT_POLYLIB) + return isl_basic_set_print_polylib(bset, p, 0); + else if (p->output_format == ISL_FORMAT_EXT_POLYLIB) + return isl_basic_set_print_polylib(bset, p, 1); + else if (p->output_format == ISL_FORMAT_POLYLIB_CONSTRAINTS) + return bset_print_constraints_polylib(bset, p); + else if (p->output_format == ISL_FORMAT_OMEGA) + return basic_set_print_omega(bset, p); + isl_assert(p->ctx, 0, goto error); +error: + isl_printer_free(p); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_set(__isl_take isl_printer *p, + __isl_keep isl_set *set) +{ + if (!p || !set) + goto error; + if (p->output_format == ISL_FORMAT_ISL) + return isl_map_print_isl(set_to_map(set), p); + else if (p->output_format == ISL_FORMAT_POLYLIB) + return isl_set_print_polylib(set, p, 0); + else if (p->output_format == ISL_FORMAT_EXT_POLYLIB) + return isl_set_print_polylib(set, p, 1); + else if (p->output_format == ISL_FORMAT_OMEGA) + return isl_set_print_omega(set, p); + else if (p->output_format == ISL_FORMAT_LATEX) + return isl_map_print_latex(set_to_map(set), p); + isl_assert(set->ctx, 0, goto error); +error: + isl_printer_free(p); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_map(__isl_take isl_printer *p, + __isl_keep isl_map *map) +{ + if (!p || !map) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return isl_map_print_isl(map, p); + else if (p->output_format == ISL_FORMAT_POLYLIB) + return isl_map_print_polylib(map, p, 0); + else if (p->output_format == ISL_FORMAT_EXT_POLYLIB) + return isl_map_print_polylib(map, p, 1); + else if (p->output_format == ISL_FORMAT_OMEGA) + return isl_map_print_omega(map, p); + else if (p->output_format == ISL_FORMAT_LATEX) + return isl_map_print_latex(map, p); + isl_assert(map->ctx, 0, goto error); +error: + isl_printer_free(p); + return NULL; +} + +struct isl_union_print_data { + isl_printer *p; + int first; +}; + +static isl_stat print_map_body(__isl_take isl_map *map, void *user) +{ + struct isl_union_print_data *data; + data = (struct isl_union_print_data *)user; + + if (!data->first) + data->p = isl_printer_print_str(data->p, "; "); + data->first = 0; + + data->p = isl_map_print_isl_body(map, data->p); + isl_map_free(map); + + return isl_stat_ok; +} + +static __isl_give isl_printer *isl_union_map_print_isl( + __isl_keep isl_union_map *umap, __isl_take isl_printer *p) +{ + struct isl_union_print_data data; + struct isl_print_space_data space_data = { 0 }; + isl_space *space; + + space = isl_union_map_get_space(umap); + p = print_param_tuple(p, space, &space_data); + isl_space_free(space); + p = isl_printer_print_str(p, s_open_set[0]); + data.p = p; + data.first = 1; + isl_union_map_foreach_map(umap, &print_map_body, &data); + p = data.p; + p = isl_printer_print_str(p, s_close_set[0]); + return p; +} + +static isl_stat print_latex_map_body(__isl_take isl_map *map, void *user) +{ + struct isl_union_print_data *data; + data = (struct isl_union_print_data *)user; + + if (!data->first) + data->p = isl_printer_print_str(data->p, " \\cup "); + data->first = 0; + + data->p = isl_map_print_latex(map, data->p); + isl_map_free(map); + + return isl_stat_ok; +} + +static __isl_give isl_printer *isl_union_map_print_latex( + __isl_keep isl_union_map *umap, __isl_take isl_printer *p) +{ + struct isl_union_print_data data = { p, 1 }; + isl_union_map_foreach_map(umap, &print_latex_map_body, &data); + p = data.p; + return p; +} + +__isl_give isl_printer *isl_printer_print_union_map(__isl_take isl_printer *p, + __isl_keep isl_union_map *umap) +{ + if (!p || !umap) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return isl_union_map_print_isl(umap, p); + if (p->output_format == ISL_FORMAT_LATEX) + return isl_union_map_print_latex(umap, p); + + isl_die(p->ctx, isl_error_invalid, + "invalid output format for isl_union_map", goto error); +error: + isl_printer_free(p); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_union_set(__isl_take isl_printer *p, + __isl_keep isl_union_set *uset) +{ + if (!p || !uset) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return isl_union_map_print_isl((isl_union_map *)uset, p); + if (p->output_format == ISL_FORMAT_LATEX) + return isl_union_map_print_latex((isl_union_map *)uset, p); + + isl_die(p->ctx, isl_error_invalid, + "invalid output format for isl_union_set", goto error); +error: + isl_printer_free(p); + return NULL; +} + +static int upoly_rec_n_non_zero(__isl_keep struct isl_upoly_rec *rec) +{ + int i; + int n; + + for (i = 0, n = 0; i < rec->n; ++i) + if (!isl_upoly_is_zero(rec->p[i])) + ++n; + + return n; +} + +static __isl_give isl_printer *upoly_print_cst(__isl_keep struct isl_upoly *up, + __isl_take isl_printer *p, int first) +{ + struct isl_upoly_cst *cst; + int neg; + + cst = isl_upoly_as_cst(up); + if (!cst) + goto error; + neg = !first && isl_int_is_neg(cst->n); + if (!first) + p = isl_printer_print_str(p, neg ? " - " : " + "); + if (neg) + isl_int_neg(cst->n, cst->n); + if (isl_int_is_zero(cst->d)) { + int sgn = isl_int_sgn(cst->n); + p = isl_printer_print_str(p, sgn < 0 ? "-infty" : + sgn == 0 ? "NaN" : "infty"); + } else + p = isl_printer_print_isl_int(p, cst->n); + if (neg) + isl_int_neg(cst->n, cst->n); + if (!isl_int_is_zero(cst->d) && !isl_int_is_one(cst->d)) { + p = isl_printer_print_str(p, "/"); + p = isl_printer_print_isl_int(p, cst->d); + } + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *print_base(__isl_take isl_printer *p, + __isl_keep isl_space *dim, __isl_keep isl_mat *div, int var) +{ + unsigned total; + + total = isl_space_dim(dim, isl_dim_all); + if (var < total) + p = print_term(dim, NULL, dim->ctx->one, 1 + var, p, 0); + else + p = print_div(dim, div, var - total, p); + return p; +} + +static __isl_give isl_printer *print_pow(__isl_take isl_printer *p, + __isl_keep isl_space *dim, __isl_keep isl_mat *div, int var, int exp) +{ + p = print_base(p, dim, div, var); + if (exp == 1) + return p; + if (p->output_format == ISL_FORMAT_C) { + int i; + for (i = 1; i < exp; ++i) { + p = isl_printer_print_str(p, "*"); + p = print_base(p, dim, div, var); + } + } else { + p = isl_printer_print_str(p, "^"); + p = isl_printer_print_int(p, exp); + } + return p; +} + +/* Print the polynomial "up" defined over the domain space "space" and + * local variables defined by "div" to "p". + */ +static __isl_give isl_printer *upoly_print(__isl_keep struct isl_upoly *up, + __isl_keep isl_space *space, __isl_keep isl_mat *div, + __isl_take isl_printer *p) +{ + int i, n, first, print_parens; + struct isl_upoly_rec *rec; + + if (!p || !up || !space || !div) + goto error; + + if (isl_upoly_is_cst(up)) + return upoly_print_cst(up, p, 1); + + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + n = upoly_rec_n_non_zero(rec); + print_parens = n > 1; + if (print_parens) + p = isl_printer_print_str(p, "("); + for (i = 0, first = 1; i < rec->n; ++i) { + if (isl_upoly_is_zero(rec->p[i])) + continue; + if (isl_upoly_is_negone(rec->p[i])) { + if (!i) + p = isl_printer_print_str(p, "-1"); + else if (first) + p = isl_printer_print_str(p, "-"); + else + p = isl_printer_print_str(p, " - "); + } else if (isl_upoly_is_cst(rec->p[i]) && + !isl_upoly_is_one(rec->p[i])) + p = upoly_print_cst(rec->p[i], p, first); + else { + if (!first) + p = isl_printer_print_str(p, " + "); + if (i == 0 || !isl_upoly_is_one(rec->p[i])) + p = upoly_print(rec->p[i], space, div, p); + } + first = 0; + if (i == 0) + continue; + if (!isl_upoly_is_one(rec->p[i]) && + !isl_upoly_is_negone(rec->p[i])) + p = isl_printer_print_str(p, " * "); + p = print_pow(p, space, div, rec->up.var, i); + } + if (print_parens) + p = isl_printer_print_str(p, ")"); + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *print_qpolynomial(__isl_take isl_printer *p, + __isl_keep isl_qpolynomial *qp) +{ + if (!p || !qp) + goto error; + p = upoly_print(qp->upoly, qp->dim, qp->div, p); + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *print_qpolynomial_isl(__isl_take isl_printer *p, + __isl_keep isl_qpolynomial *qp) +{ + struct isl_print_space_data data = { 0 }; + + if (!p || !qp) + goto error; + + p = print_param_tuple(p, qp->dim, &data); + p = isl_printer_print_str(p, "{ "); + if (!isl_space_is_params(qp->dim)) { + p = isl_print_space(qp->dim, p, 0, &data); + 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; +} + +/* Print the quasi-polynomial "qp" to "p" in C format, with the variable names + * taken from the domain space "space". + */ +static __isl_give isl_printer *print_qpolynomial_c(__isl_take isl_printer *p, + __isl_keep isl_space *space, __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_on_domain(isl_space_copy(qp->dim), + den, qp->dim->ctx->one); + qp = isl_qpolynomial_mul(qp, f); + } + if (qp) + p = upoly_print(qp->upoly, space, qp->div, p); + else + p = isl_printer_free(p); + 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) +{ + isl_printer *p; + + if (!qp) + return; + + isl_assert(qp->dim->ctx, output_format == ISL_FORMAT_ISL, return); + p = isl_printer_to_file(qp->dim->ctx, out); + p = isl_printer_print_qpolynomial(p, qp); + isl_printer_free(p); +} + +static __isl_give isl_printer *qpolynomial_fold_print( + __isl_keep isl_qpolynomial_fold *fold, __isl_take isl_printer *p) +{ + int i; + + if (fold->type == isl_fold_min) + p = isl_printer_print_str(p, "min"); + else if (fold->type == isl_fold_max) + p = isl_printer_print_str(p, "max"); + p = isl_printer_print_str(p, "("); + for (i = 0; i < fold->n; ++i) { + if (i) + p = isl_printer_print_str(p, ", "); + p = print_qpolynomial(p, fold->qp[i]); + } + p = isl_printer_print_str(p, ")"); + return p; +} + +void isl_qpolynomial_fold_print(__isl_keep isl_qpolynomial_fold *fold, + FILE *out, unsigned output_format) +{ + isl_printer *p; + + if (!fold) + return; + + isl_assert(fold->dim->ctx, output_format == ISL_FORMAT_ISL, return); + + p = isl_printer_to_file(fold->dim->ctx, out); + p = isl_printer_print_qpolynomial_fold(p, fold); + + isl_printer_free(p); +} + +static __isl_give isl_printer *isl_pwqp_print_isl_body( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) +{ + struct isl_print_space_data data = { 0 }; + int i = 0; + + for (i = 0; i < pwqp->n; ++i) { + isl_space *space; + + if (i) + p = isl_printer_print_str(p, "; "); + space = isl_qpolynomial_get_domain_space(pwqp->p[i].qp); + if (!isl_space_is_params(space)) { + p = isl_print_space(space, p, 0, &data); + p = isl_printer_print_str(p, " -> "); + } + p = print_qpolynomial(p, pwqp->p[i].qp); + p = print_disjuncts(set_to_map(pwqp->p[i].set), space, p, 0); + isl_space_free(space); + } + + return p; +} + +static __isl_give isl_printer *print_pw_qpolynomial_isl( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) +{ + struct isl_print_space_data data = { 0 }; + + if (!p || !pwqp) + goto error; + + p = print_param_tuple(p, pwqp->dim, &data); + p = isl_printer_print_str(p, "{ "); + if (pwqp->n == 0) { + if (!isl_space_is_set(pwqp->dim)) { + p = print_tuple(pwqp->dim, p, isl_dim_in, &data); + p = isl_printer_print_str(p, " -> "); + } + p = isl_printer_print_str(p, "0"); + } + p = isl_pwqp_print_isl_body(p, pwqp); + p = isl_printer_print_str(p, " }"); + return p; +error: + isl_printer_free(p); + return NULL; +} + +void isl_pw_qpolynomial_print(__isl_keep isl_pw_qpolynomial *pwqp, FILE *out, + unsigned output_format) +{ + isl_printer *p; + + if (!pwqp) + return; + + p = isl_printer_to_file(pwqp->dim->ctx, out); + p = isl_printer_set_output_format(p, output_format); + p = isl_printer_print_pw_qpolynomial(p, pwqp); + + isl_printer_free(p); +} + +static __isl_give isl_printer *isl_pwf_print_isl_body( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) +{ + struct isl_print_space_data data = { 0 }; + int i = 0; + + for (i = 0; i < pwf->n; ++i) { + isl_space *space; + + if (i) + p = isl_printer_print_str(p, "; "); + space = isl_qpolynomial_fold_get_domain_space(pwf->p[i].fold); + if (!isl_space_is_params(space)) { + p = isl_print_space(space, p, 0, &data); + p = isl_printer_print_str(p, " -> "); + } + p = qpolynomial_fold_print(pwf->p[i].fold, p); + p = print_disjuncts(set_to_map(pwf->p[i].set), space, p, 0); + isl_space_free(space); + } + + return p; +} + +static __isl_give isl_printer *print_pw_qpolynomial_fold_isl( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) +{ + struct isl_print_space_data data = { 0 }; + + p = print_param_tuple(p, pwf->dim, &data); + p = isl_printer_print_str(p, "{ "); + if (pwf->n == 0) { + if (!isl_space_is_set(pwf->dim)) { + p = print_tuple(pwf->dim, p, isl_dim_in, &data); + p = isl_printer_print_str(p, " -> "); + } + p = isl_printer_print_str(p, "0"); + } + p = isl_pwf_print_isl_body(p, pwf); + p = isl_printer_print_str(p, " }"); + return p; +} + +static __isl_give isl_printer *print_affine_c(__isl_take isl_printer *p, + __isl_keep isl_space *dim, __isl_keep isl_basic_set *bset, isl_int *c); + +static __isl_give isl_printer *print_name_c(__isl_take isl_printer *p, + __isl_keep isl_space *dim, + __isl_keep isl_basic_set *bset, enum isl_dim_type type, unsigned pos) +{ + if (type == isl_dim_div) { + p = isl_printer_print_str(p, "floord("); + p = print_affine_c(p, dim, bset, bset->div[pos] + 1); + p = isl_printer_print_str(p, ", "); + p = isl_printer_print_isl_int(p, bset->div[pos][0]); + p = isl_printer_print_str(p, ")"); + } else { + const char *name; + + name = isl_space_get_dim_name(dim, type, pos); + if (!name) + name = "UNNAMED"; + p = isl_printer_print_str(p, name); + } + return p; +} + +static __isl_give isl_printer *print_term_c(__isl_take isl_printer *p, + __isl_keep isl_space *dim, + __isl_keep isl_basic_set *bset, isl_int c, unsigned pos) +{ + enum isl_dim_type type; + + if (pos == 0) + return isl_printer_print_isl_int(p, c); + + if (isl_int_is_one(c)) + ; + else if (isl_int_is_negone(c)) + p = isl_printer_print_str(p, "-"); + else { + p = isl_printer_print_isl_int(p, c); + p = isl_printer_print_str(p, "*"); + } + type = pos2type(dim, &pos); + p = print_name_c(p, dim, bset, type, pos); + return p; +} + +static __isl_give isl_printer *print_partial_affine_c(__isl_take isl_printer *p, + __isl_keep isl_space *dim, + __isl_keep isl_basic_set *bset, isl_int *c, unsigned len) +{ + int i; + int first; + + for (i = 0, first = 1; i < len; ++i) { + int flip = 0; + if (isl_int_is_zero(c[i])) + continue; + if (!first) { + if (isl_int_is_neg(c[i])) { + flip = 1; + isl_int_neg(c[i], c[i]); + p = isl_printer_print_str(p, " - "); + } else + p = isl_printer_print_str(p, " + "); + } + first = 0; + p = print_term_c(p, dim, bset, c[i], i); + if (flip) + isl_int_neg(c[i], c[i]); + } + if (first) + p = isl_printer_print_str(p, "0"); + return p; +} + +static __isl_give isl_printer *print_affine_c(__isl_take isl_printer *p, + __isl_keep isl_space *dim, __isl_keep isl_basic_set *bset, isl_int *c) +{ + unsigned len = 1 + isl_basic_set_total_dim(bset); + return print_partial_affine_c(p, dim, bset, c, len); +} + +/* We skip the constraint if it is implied by the div expression. + * + * *first indicates whether this is the first constraint in the conjunction and + * is updated if the constraint is actually printed. + */ +static __isl_give isl_printer *print_constraint_c(__isl_take isl_printer *p, + __isl_keep isl_space *dim, + __isl_keep isl_basic_set *bset, isl_int *c, const char *op, int *first) +{ + unsigned o_div; + unsigned n_div; + int div; + + o_div = isl_basic_set_offset(bset, isl_dim_div); + n_div = isl_basic_set_dim(bset, isl_dim_div); + div = isl_seq_last_non_zero(c + o_div, n_div); + if (div >= 0) { + isl_bool is_div = isl_basic_set_is_div_constraint(bset, c, div); + if (is_div < 0) + return isl_printer_free(p); + if (is_div) + return p; + } + + if (!*first) + p = isl_printer_print_str(p, " && "); + + p = print_affine_c(p, dim, bset, c); + p = isl_printer_print_str(p, " "); + p = isl_printer_print_str(p, op); + p = isl_printer_print_str(p, " 0"); + + *first = 0; + + return p; +} + +static __isl_give isl_printer *print_basic_set_c(__isl_take isl_printer *p, + __isl_keep isl_space *dim, __isl_keep isl_basic_set *bset) +{ + int i, j; + int first = 1; + unsigned n_div = isl_basic_set_dim(bset, isl_dim_div); + unsigned total = isl_basic_set_total_dim(bset) - n_div; + + for (i = 0; i < bset->n_eq; ++i) { + j = isl_seq_last_non_zero(bset->eq[i] + 1 + total, n_div); + if (j < 0) + p = print_constraint_c(p, dim, bset, + bset->eq[i], "==", &first); + else { + if (i) + p = isl_printer_print_str(p, " && "); + p = isl_printer_print_str(p, "("); + p = print_partial_affine_c(p, dim, bset, bset->eq[i], + 1 + total + j); + p = isl_printer_print_str(p, ") % "); + p = isl_printer_print_isl_int(p, + bset->eq[i][1 + total + j]); + p = isl_printer_print_str(p, " == 0"); + first = 0; + } + } + for (i = 0; i < bset->n_ineq; ++i) + p = print_constraint_c(p, dim, bset, bset->ineq[i], ">=", + &first); + return p; +} + +static __isl_give isl_printer *print_set_c(__isl_take isl_printer *p, + __isl_keep isl_space *dim, __isl_keep isl_set *set) +{ + int i; + + if (!set) + return isl_printer_free(p); + + if (set->n == 0) + p = isl_printer_print_str(p, "0"); + + for (i = 0; i < set->n; ++i) { + if (i) + p = isl_printer_print_str(p, " || "); + if (set->n > 1) + p = isl_printer_print_str(p, "("); + p = print_basic_set_c(p, dim, set->p[i]); + if (set->n > 1) + p = isl_printer_print_str(p, ")"); + } + return p; +} + +/* Print the piecewise quasi-polynomial "pwqp" to "p" in C format. + */ +static __isl_give isl_printer *print_pw_qpolynomial_c( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) +{ + int i; + isl_space *space; + + space = isl_pw_qpolynomial_get_domain_space(pwqp); + if (pwqp->n == 1 && isl_set_plain_is_universe(pwqp->p[0].set)) { + p = print_qpolynomial_c(p, space, pwqp->p[0].qp); + isl_space_free(space); + return p; + } + + for (i = 0; i < pwqp->n; ++i) { + p = isl_printer_print_str(p, "("); + p = print_set_c(p, space, pwqp->p[i].set); + p = isl_printer_print_str(p, ") ? ("); + p = print_qpolynomial_c(p, space, pwqp->p[i].qp); + p = isl_printer_print_str(p, ") : "); + } + + isl_space_free(space); + p = isl_printer_print_str(p, "0"); + return p; +} + +__isl_give isl_printer *isl_printer_print_pw_qpolynomial( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) +{ + if (!p || !pwqp) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_pw_qpolynomial_isl(p, pwqp); + else if (p->output_format == ISL_FORMAT_C) + return print_pw_qpolynomial_c(p, pwqp); + isl_assert(p->ctx, 0, goto error); +error: + isl_printer_free(p); + return NULL; +} + +static isl_stat print_pwqp_body(__isl_take isl_pw_qpolynomial *pwqp, void *user) +{ + struct isl_union_print_data *data; + data = (struct isl_union_print_data *)user; + + if (!data->first) + data->p = isl_printer_print_str(data->p, "; "); + data->first = 0; + + data->p = isl_pwqp_print_isl_body(data->p, pwqp); + isl_pw_qpolynomial_free(pwqp); + + return isl_stat_ok; +} + +static __isl_give isl_printer *print_union_pw_qpolynomial_isl( + __isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp) +{ + struct isl_union_print_data data; + struct isl_print_space_data space_data = { 0 }; + isl_space *space; + + space = isl_union_pw_qpolynomial_get_space(upwqp); + p = print_param_tuple(p, space, &space_data); + isl_space_free(space); + p = isl_printer_print_str(p, "{ "); + data.p = p; + data.first = 1; + isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &print_pwqp_body, + &data); + p = data.p; + p = isl_printer_print_str(p, " }"); + return p; +} + +__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial( + __isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp) +{ + if (!p || !upwqp) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_union_pw_qpolynomial_isl(p, upwqp); + isl_die(p->ctx, isl_error_invalid, + "invalid output format for isl_union_pw_qpolynomial", + goto error); +error: + isl_printer_free(p); + return NULL; +} + +/* Print the quasi-polynomial reduction "fold" to "p" in C format, + * with the variable names taken from the domain space "space". + */ +static __isl_give isl_printer *print_qpolynomial_fold_c( + __isl_take isl_printer *p, __isl_keep isl_space *space, + __isl_keep isl_qpolynomial_fold *fold) +{ + int i; + + for (i = 0; i < fold->n - 1; ++i) + if (fold->type == isl_fold_min) + p = isl_printer_print_str(p, "min("); + else if (fold->type == isl_fold_max) + p = isl_printer_print_str(p, "max("); + + for (i = 0; i < fold->n; ++i) { + if (i) + p = isl_printer_print_str(p, ", "); + p = print_qpolynomial_c(p, space, fold->qp[i]); + if (i) + p = isl_printer_print_str(p, ")"); + } + return p; +} + +__isl_give isl_printer *isl_printer_print_qpolynomial_fold( + __isl_take isl_printer *p, __isl_keep isl_qpolynomial_fold *fold) +{ + if (!p || !fold) + goto error; + if (p->output_format == ISL_FORMAT_ISL) + return qpolynomial_fold_print(fold, p); + else if (p->output_format == ISL_FORMAT_C) + return print_qpolynomial_fold_c(p, fold->dim, fold); + isl_die(p->ctx, isl_error_unsupported, "unsupported output format", + goto error); +error: + isl_printer_free(p); + return NULL; +} + +/* Print the piecewise quasi-polynomial reduction "pwf" to "p" in C format. + */ +static __isl_give isl_printer *print_pw_qpolynomial_fold_c( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) +{ + int i; + isl_space *space; + + space = isl_pw_qpolynomial_fold_get_domain_space(pwf); + if (pwf->n == 1 && isl_set_plain_is_universe(pwf->p[0].set)) { + p = print_qpolynomial_fold_c(p, space, pwf->p[0].fold); + isl_space_free(space); + return p; + } + + for (i = 0; i < pwf->n; ++i) { + p = isl_printer_print_str(p, "("); + p = print_set_c(p, space, pwf->p[i].set); + p = isl_printer_print_str(p, ") ? ("); + p = print_qpolynomial_fold_c(p, space, pwf->p[i].fold); + p = isl_printer_print_str(p, ") : "); + } + + isl_space_free(space); + p = isl_printer_print_str(p, "0"); + return p; +} + +__isl_give isl_printer *isl_printer_print_pw_qpolynomial_fold( + __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) +{ + if (!p || !pwf) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_pw_qpolynomial_fold_isl(p, pwf); + else if (p->output_format == ISL_FORMAT_C) + return print_pw_qpolynomial_fold_c(p, pwf); + isl_assert(p->ctx, 0, goto error); +error: + isl_printer_free(p); + return NULL; +} + +void isl_pw_qpolynomial_fold_print(__isl_keep isl_pw_qpolynomial_fold *pwf, + FILE *out, unsigned output_format) +{ + isl_printer *p; + + if (!pwf) + return; + + p = isl_printer_to_file(pwf->dim->ctx, out); + p = isl_printer_set_output_format(p, output_format); + p = isl_printer_print_pw_qpolynomial_fold(p, pwf); + + isl_printer_free(p); +} + +static isl_stat print_pwf_body(__isl_take isl_pw_qpolynomial_fold *pwf, + void *user) +{ + struct isl_union_print_data *data; + data = (struct isl_union_print_data *)user; + + if (!data->first) + data->p = isl_printer_print_str(data->p, "; "); + data->first = 0; + + data->p = isl_pwf_print_isl_body(data->p, pwf); + isl_pw_qpolynomial_fold_free(pwf); + + return isl_stat_ok; +} + +static __isl_give isl_printer *print_union_pw_qpolynomial_fold_isl( + __isl_take isl_printer *p, + __isl_keep isl_union_pw_qpolynomial_fold *upwf) +{ + struct isl_union_print_data data; + struct isl_print_space_data space_data = { 0 }; + isl_space *space; + + space = isl_union_pw_qpolynomial_fold_get_space(upwf); + p = print_param_tuple(p, space, &space_data); + isl_space_free(space); + p = isl_printer_print_str(p, "{ "); + data.p = p; + data.first = 1; + isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(upwf, + &print_pwf_body, &data); + p = data.p; + p = isl_printer_print_str(p, " }"); + return p; +} + +__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial_fold( + __isl_take isl_printer *p, + __isl_keep isl_union_pw_qpolynomial_fold *upwf) +{ + if (!p || !upwf) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_union_pw_qpolynomial_fold_isl(p, upwf); + isl_die(p->ctx, isl_error_invalid, + "invalid output format for isl_union_pw_qpolynomial_fold", + goto error); +error: + isl_printer_free(p); + return NULL; +} + +/* Print the isl_constraint "c" to "p". + */ +__isl_give isl_printer *isl_printer_print_constraint(__isl_take isl_printer *p, + __isl_keep isl_constraint *c) +{ + struct isl_print_space_data data = { 0 }; + isl_local_space *ls; + isl_space *space; + isl_bool exists; + + if (!p || !c) + goto error; + + ls = isl_constraint_get_local_space(c); + if (!ls) + return isl_printer_free(p); + space = isl_local_space_get_space(ls); + p = print_param_tuple(p, space, &data); + p = isl_printer_print_str(p, "{ "); + p = isl_print_space(space, p, 0, &data); + p = isl_printer_print_str(p, " : "); + exists = need_exists(p, ls->div); + if (exists < 0) + p = isl_printer_free(p); + if (exists >= 0 && exists) + p = open_exists(p, space, ls->div, 0); + p = print_affine_of_len(space, ls->div, p, c->v->el, c->v->size); + if (isl_constraint_is_equality(c)) + p = isl_printer_print_str(p, " = 0"); + else + p = isl_printer_print_str(p, " >= 0"); + if (exists >= 0 && exists) + p = isl_printer_print_str(p, s_close_exists[0]); + p = isl_printer_print_str(p, " }"); + isl_space_free(space); + isl_local_space_free(ls); + + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *isl_printer_print_space_isl( + __isl_take isl_printer *p, __isl_keep isl_space *space) +{ + struct isl_print_space_data data = { 0 }; + + if (!space) + goto error; + + p = print_param_tuple(p, space, &data); + + p = isl_printer_print_str(p, "{ "); + if (isl_space_is_params(space)) + p = isl_printer_print_str(p, s_such_that[0]); + else + p = isl_print_space(space, p, 0, &data); + p = isl_printer_print_str(p, " }"); + + return p; +error: + isl_printer_free(p); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_space(__isl_take isl_printer *p, + __isl_keep isl_space *space) +{ + if (!p || !space) + return isl_printer_free(p); + if (p->output_format == ISL_FORMAT_ISL) + return isl_printer_print_space_isl(p, space); + else if (p->output_format == ISL_FORMAT_OMEGA) + return print_omega_parameters(space, p); + + isl_die(isl_space_get_ctx(space), isl_error_unsupported, + "output format not supported for space", + return isl_printer_free(p)); +} + +__isl_give isl_printer *isl_printer_print_local_space(__isl_take isl_printer *p, + __isl_keep isl_local_space *ls) +{ + struct isl_print_space_data data = { 0 }; + unsigned n_div; + + if (!ls) + goto error; + + p = print_param_tuple(p, ls->dim, &data); + p = isl_printer_print_str(p, "{ "); + p = isl_print_space(ls->dim, p, 0, &data); + n_div = isl_local_space_dim(ls, isl_dim_div); + if (n_div > 0) { + p = isl_printer_print_str(p, " : "); + p = isl_printer_print_str(p, s_open_exists[0]); + p = print_div_list(p, ls->dim, ls->div, 0, 1); + p = isl_printer_print_str(p, s_close_exists[0]); + } else if (isl_space_is_params(ls->dim)) + p = isl_printer_print_str(p, s_such_that[0]); + p = isl_printer_print_str(p, " }"); + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *print_aff_body(__isl_take isl_printer *p, + __isl_keep isl_aff *aff) +{ + unsigned total; + + if (isl_aff_is_nan(aff)) + return isl_printer_print_str(p, "NaN"); + + total = isl_local_space_dim(aff->ls, isl_dim_all); + p = isl_printer_print_str(p, "("); + p = print_affine_of_len(aff->ls->dim, aff->ls->div, p, + aff->v->el + 1, 1 + total); + if (isl_int_is_one(aff->v->el[0])) + p = isl_printer_print_str(p, ")"); + else { + p = isl_printer_print_str(p, ")/"); + p = isl_printer_print_isl_int(p, aff->v->el[0]); + } + + return p; +} + +static __isl_give isl_printer *print_aff(__isl_take isl_printer *p, + __isl_keep isl_aff *aff) +{ + struct isl_print_space_data data = { 0 }; + + if (isl_space_is_params(aff->ls->dim)) + ; + else { + p = print_tuple(aff->ls->dim, p, isl_dim_set, &data); + p = isl_printer_print_str(p, " -> "); + } + p = isl_printer_print_str(p, "["); + p = print_aff_body(p, aff); + p = isl_printer_print_str(p, "]"); + + return p; +} + +static __isl_give isl_printer *print_aff_isl(__isl_take isl_printer *p, + __isl_keep isl_aff *aff) +{ + struct isl_print_space_data data = { 0 }; + + if (!aff) + goto error; + + p = print_param_tuple(p, aff->ls->dim, &data); + p = isl_printer_print_str(p, "{ "); + p = print_aff(p, aff); + p = isl_printer_print_str(p, " }"); + return p; +error: + isl_printer_free(p); + return NULL; +} + +/* Print the body of an isl_pw_aff, i.e., a semicolon delimited + * sequence of affine expressions, each followed by constraints. + */ +static __isl_give isl_printer *print_pw_aff_body( + __isl_take isl_printer *p, __isl_keep isl_pw_aff *pa) +{ + int i; + + if (!pa) + return isl_printer_free(p); + + for (i = 0; i < pa->n; ++i) { + isl_space *space; + + if (i) + p = isl_printer_print_str(p, "; "); + p = print_aff(p, pa->p[i].aff); + space = isl_aff_get_domain_space(pa->p[i].aff); + p = print_disjuncts(set_to_map(pa->p[i].set), space, p, 0); + isl_space_free(space); + } + + return p; +} + +static __isl_give isl_printer *print_pw_aff_isl(__isl_take isl_printer *p, + __isl_keep isl_pw_aff *pwaff) +{ + struct isl_print_space_data data = { 0 }; + + if (!pwaff) + goto error; + + p = print_param_tuple(p, pwaff->dim, &data); + p = isl_printer_print_str(p, "{ "); + p = print_pw_aff_body(p, pwaff); + p = isl_printer_print_str(p, " }"); + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *print_ls_affine_c(__isl_take isl_printer *p, + __isl_keep isl_local_space *ls, isl_int *c); + +static __isl_give isl_printer *print_ls_name_c(__isl_take isl_printer *p, + __isl_keep isl_local_space *ls, enum isl_dim_type type, unsigned pos) +{ + if (type == isl_dim_div) { + p = isl_printer_print_str(p, "floord("); + p = print_ls_affine_c(p, ls, ls->div->row[pos] + 1); + p = isl_printer_print_str(p, ", "); + p = isl_printer_print_isl_int(p, ls->div->row[pos][0]); + p = isl_printer_print_str(p, ")"); + } else { + const char *name; + + name = isl_space_get_dim_name(ls->dim, type, pos); + if (!name) + name = "UNNAMED"; + p = isl_printer_print_str(p, name); + } + return p; +} + +static __isl_give isl_printer *print_ls_term_c(__isl_take isl_printer *p, + __isl_keep isl_local_space *ls, isl_int c, unsigned pos) +{ + enum isl_dim_type type; + + if (pos == 0) + return isl_printer_print_isl_int(p, c); + + if (isl_int_is_one(c)) + ; + else if (isl_int_is_negone(c)) + p = isl_printer_print_str(p, "-"); + else { + p = isl_printer_print_isl_int(p, c); + p = isl_printer_print_str(p, "*"); + } + type = pos2type(ls->dim, &pos); + p = print_ls_name_c(p, ls, type, pos); + return p; +} + +static __isl_give isl_printer *print_ls_partial_affine_c( + __isl_take isl_printer *p, __isl_keep isl_local_space *ls, + isl_int *c, unsigned len) +{ + int i; + int first; + + for (i = 0, first = 1; i < len; ++i) { + int flip = 0; + if (isl_int_is_zero(c[i])) + continue; + if (!first) { + if (isl_int_is_neg(c[i])) { + flip = 1; + isl_int_neg(c[i], c[i]); + p = isl_printer_print_str(p, " - "); + } else + p = isl_printer_print_str(p, " + "); + } + first = 0; + p = print_ls_term_c(p, ls, c[i], i); + if (flip) + isl_int_neg(c[i], c[i]); + } + if (first) + p = isl_printer_print_str(p, "0"); + return p; +} + +static __isl_give isl_printer *print_ls_affine_c(__isl_take isl_printer *p, + __isl_keep isl_local_space *ls, isl_int *c) +{ + unsigned len = 1 + isl_local_space_dim(ls, isl_dim_all); + return print_ls_partial_affine_c(p, ls, c, len); +} + +static __isl_give isl_printer *print_aff_c(__isl_take isl_printer *p, + __isl_keep isl_aff *aff) +{ + unsigned total; + + total = isl_local_space_dim(aff->ls, isl_dim_all); + if (!isl_int_is_one(aff->v->el[0])) + p = isl_printer_print_str(p, "("); + p = print_ls_partial_affine_c(p, aff->ls, aff->v->el + 1, 1 + total); + 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]); + } + return p; +} + +/* In the C format, we cannot express that "pwaff" may be undefined + * on parts of the domain space. We therefore assume that the expression + * will only be evaluated on its definition domain and compute the gist + * of each cell with respect to this domain. + */ +static __isl_give isl_printer *print_pw_aff_c(__isl_take isl_printer *p, + __isl_keep isl_pw_aff *pwaff) +{ + isl_set *domain; + isl_ast_build *build; + isl_ast_expr *expr; + + if (pwaff->n < 1) + isl_die(p->ctx, isl_error_unsupported, + "cannot print empty isl_pw_aff in C format", + return isl_printer_free(p)); + + domain = isl_pw_aff_domain(isl_pw_aff_copy(pwaff)); + build = isl_ast_build_from_context(domain); + expr = isl_ast_build_expr_from_pw_aff(build, isl_pw_aff_copy(pwaff)); + p = isl_printer_print_ast_expr(p, expr); + isl_ast_expr_free(expr); + isl_ast_build_free(build); + + return p; +} + +__isl_give isl_printer *isl_printer_print_aff(__isl_take isl_printer *p, + __isl_keep isl_aff *aff) +{ + if (!p || !aff) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_aff_isl(p, aff); + else if (p->output_format == ISL_FORMAT_C) + return print_aff_c(p, aff); + isl_die(p->ctx, isl_error_unsupported, "unsupported output format", + goto error); +error: + isl_printer_free(p); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_pw_aff(__isl_take isl_printer *p, + __isl_keep isl_pw_aff *pwaff) +{ + if (!p || !pwaff) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_pw_aff_isl(p, pwaff); + else if (p->output_format == ISL_FORMAT_C) + return print_pw_aff_c(p, pwaff); + isl_die(p->ctx, isl_error_unsupported, "unsupported output format", + goto error); +error: + isl_printer_free(p); + return NULL; +} + +/* Print "pa" in a sequence of isl_pw_affs delimited by semicolons. + * Each isl_pw_aff itself is also printed as semicolon delimited + * sequence of pieces. + * If data->first = 1, then this is the first in the sequence. + * Update data->first to tell the next element that it is not the first. + */ +static isl_stat print_pw_aff_body_wrap(__isl_take isl_pw_aff *pa, + void *user) +{ + struct isl_union_print_data *data; + data = (struct isl_union_print_data *) user; + + if (!data->first) + data->p = isl_printer_print_str(data->p, "; "); + data->first = 0; + + data->p = print_pw_aff_body(data->p, pa); + isl_pw_aff_free(pa); + + return data->p ? isl_stat_ok : isl_stat_error; +} + +/* Print the body of an isl_union_pw_aff, i.e., a semicolon delimited + * sequence of affine expressions, each followed by constraints, + * with the sequence enclosed in braces. + */ +static __isl_give isl_printer *print_union_pw_aff_body( + __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa) +{ + struct isl_union_print_data data = { p, 1 }; + + p = isl_printer_print_str(p, s_open_set[0]); + data.p = p; + if (isl_union_pw_aff_foreach_pw_aff(upa, + &print_pw_aff_body_wrap, &data) < 0) + data.p = isl_printer_free(p); + p = data.p; + p = isl_printer_print_str(p, s_close_set[0]); + + return p; +} + +/* Print the isl_union_pw_aff "upa" to "p" in isl format. + * + * The individual isl_pw_affs are delimited by a semicolon. + */ +static __isl_give isl_printer *print_union_pw_aff_isl( + __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa) +{ + struct isl_print_space_data data = { 0 }; + isl_space *space; + + space = isl_union_pw_aff_get_space(upa); + p = print_param_tuple(p, space, &data); + isl_space_free(space); + p = print_union_pw_aff_body(p, upa); + return p; +} + +/* Print the isl_union_pw_aff "upa" to "p". + * + * We currently only support an isl format. + */ +__isl_give isl_printer *isl_printer_print_union_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa) +{ + if (!p || !upa) + return isl_printer_free(p); + + if (p->output_format == ISL_FORMAT_ISL) + return print_union_pw_aff_isl(p, upa); + isl_die(isl_printer_get_ctx(p), isl_error_unsupported, + "unsupported output format", return isl_printer_free(p)); +} + +/* Print dimension "pos" of data->space to "p". + * + * data->user is assumed to be an isl_multi_aff. + * + * If the current dimension is an output dimension, then print + * the corresponding expression. Otherwise, print the name of the dimension. + */ +static __isl_give isl_printer *print_dim_ma(__isl_take isl_printer *p, + struct isl_print_space_data *data, unsigned pos) +{ + isl_multi_aff *ma = data->user; + + if (data->type == isl_dim_out) + p = print_aff_body(p, ma->p[pos]); + else + p = print_name(data->space, p, data->type, pos, data->latex); + + return p; +} + +static __isl_give isl_printer *print_multi_aff(__isl_take isl_printer *p, + __isl_keep isl_multi_aff *maff) +{ + struct isl_print_space_data data = { 0 }; + + data.print_dim = &print_dim_ma; + data.user = maff; + return isl_print_space(maff->space, p, 0, &data); +} + +static __isl_give isl_printer *print_multi_aff_isl(__isl_take isl_printer *p, + __isl_keep isl_multi_aff *maff) +{ + struct isl_print_space_data data = { 0 }; + + if (!maff) + goto error; + + p = print_param_tuple(p, maff->space, &data); + p = isl_printer_print_str(p, "{ "); + p = print_multi_aff(p, maff); + p = isl_printer_print_str(p, " }"); + return p; +error: + isl_printer_free(p); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_multi_aff(__isl_take isl_printer *p, + __isl_keep isl_multi_aff *maff) +{ + if (!p || !maff) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_multi_aff_isl(p, maff); + isl_die(p->ctx, isl_error_unsupported, "unsupported output format", + goto error); +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *print_pw_multi_aff_body( + __isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma) +{ + int i; + + if (!pma) + goto error; + + for (i = 0; i < pma->n; ++i) { + isl_space *space; + + if (i) + p = isl_printer_print_str(p, "; "); + p = print_multi_aff(p, pma->p[i].maff); + space = isl_multi_aff_get_domain_space(pma->p[i].maff); + p = print_disjuncts(set_to_map(pma->p[i].set), space, p, 0); + isl_space_free(space); + } + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *print_pw_multi_aff_isl(__isl_take isl_printer *p, + __isl_keep isl_pw_multi_aff *pma) +{ + struct isl_print_space_data data = { 0 }; + + if (!pma) + goto error; + + p = print_param_tuple(p, pma->dim, &data); + p = isl_printer_print_str(p, "{ "); + p = print_pw_multi_aff_body(p, pma); + p = isl_printer_print_str(p, " }"); + return p; +error: + isl_printer_free(p); + return NULL; +} + +/* Print the unnamed, single-dimensional piecewise multi affine expression "pma" + * to "p". + */ +static __isl_give isl_printer *print_unnamed_pw_multi_aff_c( + __isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma) +{ + int i; + isl_space *space; + + space = isl_pw_multi_aff_get_domain_space(pma); + for (i = 0; i < pma->n - 1; ++i) { + p = isl_printer_print_str(p, "("); + p = print_set_c(p, space, pma->p[i].set); + p = isl_printer_print_str(p, ") ? ("); + p = print_aff_c(p, pma->p[i].maff->p[0]); + p = isl_printer_print_str(p, ") : "); + } + isl_space_free(space); + + return print_aff_c(p, pma->p[pma->n - 1].maff->p[0]); +} + +static __isl_give isl_printer *print_pw_multi_aff_c(__isl_take isl_printer *p, + __isl_keep isl_pw_multi_aff *pma) +{ + int n; + const char *name; + + if (!pma) + goto error; + if (pma->n < 1) + isl_die(p->ctx, isl_error_unsupported, + "cannot print empty isl_pw_multi_aff in C format", + goto error); + name = isl_pw_multi_aff_get_tuple_name(pma, isl_dim_out); + if (!name && isl_pw_multi_aff_dim(pma, isl_dim_out) == 1) + return print_unnamed_pw_multi_aff_c(p, pma); + if (!name) + isl_die(p->ctx, isl_error_unsupported, + "cannot print unnamed isl_pw_multi_aff in C format", + goto error); + + p = isl_printer_print_str(p, name); + n = isl_pw_multi_aff_dim(pma, isl_dim_out); + if (n != 0) + isl_die(p->ctx, isl_error_unsupported, + "not supported yet", goto error); + + return p; +error: + isl_printer_free(p); + return NULL; +} + +__isl_give isl_printer *isl_printer_print_pw_multi_aff( + __isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma) +{ + if (!p || !pma) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_pw_multi_aff_isl(p, pma); + if (p->output_format == ISL_FORMAT_C) + return print_pw_multi_aff_c(p, pma); + isl_die(p->ctx, isl_error_unsupported, "unsupported output format", + goto error); +error: + isl_printer_free(p); + return NULL; +} + +static isl_stat print_pw_multi_aff_body_wrap(__isl_take isl_pw_multi_aff *pma, + void *user) +{ + struct isl_union_print_data *data; + data = (struct isl_union_print_data *) user; + + if (!data->first) + data->p = isl_printer_print_str(data->p, "; "); + data->first = 0; + + data->p = print_pw_multi_aff_body(data->p, pma); + isl_pw_multi_aff_free(pma); + + return isl_stat_ok; +} + +static __isl_give isl_printer *print_union_pw_multi_aff_isl( + __isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma) +{ + struct isl_union_print_data data; + struct isl_print_space_data space_data = { 0 }; + isl_space *space; + + space = isl_union_pw_multi_aff_get_space(upma); + p = print_param_tuple(p, space, &space_data); + isl_space_free(space); + p = isl_printer_print_str(p, s_open_set[0]); + data.p = p; + data.first = 1; + isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, + &print_pw_multi_aff_body_wrap, &data); + p = data.p; + p = isl_printer_print_str(p, s_close_set[0]); + return p; +} + +__isl_give isl_printer *isl_printer_print_union_pw_multi_aff( + __isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma) +{ + if (!p || !upma) + goto error; + + if (p->output_format == ISL_FORMAT_ISL) + return print_union_pw_multi_aff_isl(p, upma); + isl_die(p->ctx, isl_error_unsupported, "unsupported output format", + goto error); +error: + isl_printer_free(p); + return NULL; +} + +/* Print dimension "pos" of data->space to "p". + * + * data->user is assumed to be an isl_multi_pw_aff. + * + * If the current dimension is an output dimension, then print + * the corresponding piecewise affine expression. + * Otherwise, print the name of the dimension. + */ +static __isl_give isl_printer *print_dim_mpa(__isl_take isl_printer *p, + struct isl_print_space_data *data, unsigned pos) +{ + int i; + int need_parens; + isl_multi_pw_aff *mpa = data->user; + isl_pw_aff *pa; + + if (data->type != isl_dim_out) + return print_name(data->space, p, data->type, pos, data->latex); + + pa = mpa->p[pos]; + if (pa->n == 0) + return isl_printer_print_str(p, "(0 : false)"); + + need_parens = pa->n != 1 || !isl_set_plain_is_universe(pa->p[0].set); + if (need_parens) + p = isl_printer_print_str(p, "("); + for (i = 0; i < pa->n; ++i) { + isl_space *space; + + if (i) + p = isl_printer_print_str(p, "; "); + p = print_aff_body(p, pa->p[i].aff); + space = isl_aff_get_domain_space(pa->p[i].aff); + p = print_disjuncts(pa->p[i].set, space, p, 0); + isl_space_free(space); + } + if (need_parens) + p = isl_printer_print_str(p, ")"); + + return p; +} + +/* Print "mpa" to "p" in isl format. + */ +static __isl_give isl_printer *print_multi_pw_aff_isl(__isl_take isl_printer *p, + __isl_keep isl_multi_pw_aff *mpa) +{ + struct isl_print_space_data data = { 0 }; + + if (!mpa) + return isl_printer_free(p); + + p = print_param_tuple(p, mpa->space, &data); + p = isl_printer_print_str(p, "{ "); + data.print_dim = &print_dim_mpa; + data.user = mpa; + p = isl_print_space(mpa->space, p, 0, &data); + p = isl_printer_print_str(p, " }"); + return p; +} + +__isl_give isl_printer *isl_printer_print_multi_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_multi_pw_aff *mpa) +{ + if (!p || !mpa) + return isl_printer_free(p); + + if (p->output_format == ISL_FORMAT_ISL) + return print_multi_pw_aff_isl(p, mpa); + isl_die(p->ctx, isl_error_unsupported, "unsupported output format", + return isl_printer_free(p)); +} + +/* Print dimension "pos" of data->space to "p". + * + * data->user is assumed to be an isl_multi_val. + * + * If the current dimension is an output dimension, then print + * the corresponding value. Otherwise, print the name of the dimension. + */ +static __isl_give isl_printer *print_dim_mv(__isl_take isl_printer *p, + struct isl_print_space_data *data, unsigned pos) +{ + isl_multi_val *mv = data->user; + + if (data->type == isl_dim_out) + return isl_printer_print_val(p, mv->p[pos]); + else + return print_name(data->space, p, data->type, pos, data->latex); +} + +/* Print the isl_multi_val "mv" to "p" in isl format. + */ +static __isl_give isl_printer *print_multi_val_isl(__isl_take isl_printer *p, + __isl_keep isl_multi_val *mv) +{ + struct isl_print_space_data data = { 0 }; + + if (!mv) + return isl_printer_free(p); + + p = print_param_tuple(p, mv->space, &data); + p = isl_printer_print_str(p, "{ "); + data.print_dim = &print_dim_mv; + data.user = mv; + p = isl_print_space(mv->space, p, 0, &data); + p = isl_printer_print_str(p, " }"); + return p; +} + +/* Print the isl_multi_val "mv" to "p". + * + * Currently only supported in isl format. + */ +__isl_give isl_printer *isl_printer_print_multi_val( + __isl_take isl_printer *p, __isl_keep isl_multi_val *mv) +{ + if (!p || !mv) + return isl_printer_free(p); + + if (p->output_format == ISL_FORMAT_ISL) + return print_multi_val_isl(p, mv); + isl_die(p->ctx, isl_error_unsupported, "unsupported output format", + return isl_printer_free(p)); +} + +/* Print dimension "pos" of data->space to "p". + * + * data->user is assumed to be an isl_multi_union_pw_aff. + * + * The current dimension is necessarily a set dimension, so + * we print the corresponding isl_union_pw_aff, including + * the braces. + */ +static __isl_give isl_printer *print_union_pw_aff_dim(__isl_take isl_printer *p, + struct isl_print_space_data *data, unsigned pos) +{ + isl_multi_union_pw_aff *mupa = data->user; + isl_union_pw_aff *upa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, pos); + p = print_union_pw_aff_body(p, upa); + isl_union_pw_aff_free(upa); + + return p; +} + +/* Print the isl_multi_union_pw_aff "mupa" to "p" in isl format. + */ +static __isl_give isl_printer *print_multi_union_pw_aff_isl( + __isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa) +{ + struct isl_print_space_data data = { 0 }; + isl_space *space; + + space = isl_multi_union_pw_aff_get_space(mupa); + p = print_param_tuple(p, space, &data); + + data.print_dim = &print_union_pw_aff_dim; + data.user = mupa; + + p = isl_print_space(space, p, 0, &data); + isl_space_free(space); + + return p; +} + +/* Print the isl_multi_union_pw_aff "mupa" to "p" in isl format. + * + * We currently only support an isl format. + */ +__isl_give isl_printer *isl_printer_print_multi_union_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa) +{ + if (!p || !mupa) + return isl_printer_free(p); + + if (p->output_format == ISL_FORMAT_ISL) + return print_multi_union_pw_aff_isl(p, mupa); + isl_die(isl_printer_get_ctx(p), isl_error_unsupported, + "unsupported output format", return isl_printer_free(p)); +} Index: contrib/isl/isl_output_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_output_private.h @@ -0,0 +1,27 @@ +#include +#include + +/* Internal data structure for isl_print_space. + * + * latex is set if that is the output format. + * print_dim (if not NULL) is called on each dimension. + * user is set by the caller of print_space and may be used inside print_dim. + * + * space is the global space that is being printed. This field is set by + * print_space. + * type is the tuple of the global space that is currently being printed. + * This field is set by print_space. + */ +struct isl_print_space_data { + int latex; + __isl_give isl_printer *(*print_dim)(__isl_take isl_printer *p, + struct isl_print_space_data *data, unsigned pos); + void *user; + + isl_space *space; + enum isl_dim_type type; +}; + +__isl_give isl_printer *isl_print_space(__isl_keep isl_space *space, + __isl_take isl_printer *p, int rational, + struct isl_print_space_data *data); Index: contrib/isl/isl_point.c =================================================================== --- /dev/null +++ contrib/isl/isl_point.c @@ -0,0 +1,580 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt) +{ + return pnt ? isl_space_get_ctx(pnt->dim) : NULL; +} + +__isl_give isl_space *isl_point_get_space(__isl_keep isl_point *pnt) +{ + return pnt ? isl_space_copy(pnt->dim) : NULL; +} + +__isl_give isl_point *isl_point_alloc(__isl_take isl_space *dim, + __isl_take isl_vec *vec) +{ + struct isl_point *pnt; + + if (!dim || !vec) + goto error; + + if (vec->size > 1 + isl_space_dim(dim, isl_dim_all)) { + vec = isl_vec_cow(vec); + if (!vec) + goto error; + vec->size = 1 + isl_space_dim(dim, isl_dim_all); + } + + pnt = isl_alloc_type(dim->ctx, struct isl_point); + if (!pnt) + goto error; + + pnt->ref = 1; + pnt->dim = dim; + pnt->vec = vec; + + return pnt; +error: + isl_space_free(dim); + isl_vec_free(vec); + return NULL; +} + +__isl_give isl_point *isl_point_zero(__isl_take isl_space *dim) +{ + isl_vec *vec; + + if (!dim) + return NULL; + vec = isl_vec_alloc(dim->ctx, 1 + isl_space_dim(dim, isl_dim_all)); + if (!vec) + goto error; + isl_int_set_si(vec->el[0], 1); + isl_seq_clr(vec->el + 1, vec->size - 1); + return isl_point_alloc(dim, vec); +error: + isl_space_free(dim); + return NULL; +} + +__isl_give isl_point *isl_point_dup(__isl_keep isl_point *pnt) +{ + struct isl_point *pnt2; + + if (!pnt) + return NULL; + pnt2 = isl_point_alloc(isl_space_copy(pnt->dim), isl_vec_copy(pnt->vec)); + return pnt2; +} + +__isl_give isl_point *isl_point_cow(__isl_take isl_point *pnt) +{ + struct isl_point *pnt2; + if (!pnt) + return NULL; + + if (pnt->ref == 1) + return pnt; + + pnt2 = isl_point_dup(pnt); + isl_point_free(pnt); + return pnt2; +} + +__isl_give isl_point *isl_point_copy(__isl_keep isl_point *pnt) +{ + if (!pnt) + return NULL; + + pnt->ref++; + return pnt; +} + +__isl_null isl_point *isl_point_free(__isl_take isl_point *pnt) +{ + if (!pnt) + return NULL; + + if (--pnt->ref > 0) + return NULL; + + isl_space_free(pnt->dim); + isl_vec_free(pnt->vec); + free(pnt); + return NULL; +} + +__isl_give isl_point *isl_point_void(__isl_take isl_space *dim) +{ + if (!dim) + return NULL; + + return isl_point_alloc(dim, isl_vec_alloc(dim->ctx, 0)); +} + +isl_bool isl_point_is_void(__isl_keep isl_point *pnt) +{ + if (!pnt) + return isl_bool_error; + + return pnt->vec->size == 0; +} + +/* Return the value of coordinate "pos" of type "type" of "pnt". + */ +__isl_give isl_val *isl_point_get_coordinate_val(__isl_keep isl_point *pnt, + enum isl_dim_type type, int pos) +{ + isl_ctx *ctx; + isl_val *v; + + if (!pnt) + return NULL; + + ctx = isl_point_get_ctx(pnt); + if (isl_point_is_void(pnt)) + isl_die(ctx, isl_error_invalid, + "void point does not have coordinates", return NULL); + if (pos < 0 || pos >= isl_space_dim(pnt->dim, type)) + isl_die(ctx, isl_error_invalid, + "position out of bounds", return NULL); + + if (type == isl_dim_set) + pos += isl_space_dim(pnt->dim, isl_dim_param); + + v = isl_val_rat_from_isl_int(ctx, pnt->vec->el[1 + pos], + pnt->vec->el[0]); + return isl_val_normalize(v); +} + +/* Replace coordinate "pos" of type "type" of "pnt" by "v". + */ +__isl_give isl_point *isl_point_set_coordinate_val(__isl_take isl_point *pnt, + enum isl_dim_type type, int pos, __isl_take isl_val *v) +{ + if (!pnt || !v) + goto error; + if (isl_point_is_void(pnt)) + isl_die(isl_point_get_ctx(pnt), isl_error_invalid, + "void point does not have coordinates", goto error); + if (pos < 0 || pos >= isl_space_dim(pnt->dim, type)) + isl_die(isl_point_get_ctx(pnt), isl_error_invalid, + "position out of bounds", goto error); + if (!isl_val_is_rat(v)) + isl_die(isl_point_get_ctx(pnt), isl_error_invalid, + "expecting rational value", goto error); + + if (isl_int_eq(pnt->vec->el[1 + pos], v->n) && + isl_int_eq(pnt->vec->el[0], v->d)) { + isl_val_free(v); + return pnt; + } + + pnt = isl_point_cow(pnt); + if (!pnt) + goto error; + pnt->vec = isl_vec_cow(pnt->vec); + if (!pnt->vec) + goto error; + + if (isl_int_eq(pnt->vec->el[0], v->d)) { + isl_int_set(pnt->vec->el[1 + pos], v->n); + } else if (isl_int_is_one(v->d)) { + isl_int_mul(pnt->vec->el[1 + pos], pnt->vec->el[0], v->n); + } else { + isl_seq_scale(pnt->vec->el + 1, + pnt->vec->el + 1, v->d, pnt->vec->size - 1); + isl_int_mul(pnt->vec->el[1 + pos], pnt->vec->el[0], v->n); + isl_int_mul(pnt->vec->el[0], pnt->vec->el[0], v->d); + pnt->vec = isl_vec_normalize(pnt->vec); + if (!pnt->vec) + goto error; + } + + isl_val_free(v); + return pnt; +error: + isl_val_free(v); + isl_point_free(pnt); + return NULL; +} + +__isl_give isl_point *isl_point_add_ui(__isl_take isl_point *pnt, + enum isl_dim_type type, int pos, unsigned val) +{ + if (!pnt || isl_point_is_void(pnt)) + return pnt; + + pnt = isl_point_cow(pnt); + if (!pnt) + return NULL; + pnt->vec = isl_vec_cow(pnt->vec); + if (!pnt->vec) + goto error; + + if (type == isl_dim_set) + pos += isl_space_dim(pnt->dim, isl_dim_param); + + isl_int_add_ui(pnt->vec->el[1 + pos], pnt->vec->el[1 + pos], val); + + return pnt; +error: + isl_point_free(pnt); + return NULL; +} + +__isl_give isl_point *isl_point_sub_ui(__isl_take isl_point *pnt, + enum isl_dim_type type, int pos, unsigned val) +{ + if (!pnt || isl_point_is_void(pnt)) + return pnt; + + pnt = isl_point_cow(pnt); + if (!pnt) + return NULL; + pnt->vec = isl_vec_cow(pnt->vec); + if (!pnt->vec) + goto error; + + if (type == isl_dim_set) + pos += isl_space_dim(pnt->dim, isl_dim_param); + + isl_int_sub_ui(pnt->vec->el[1 + pos], pnt->vec->el[1 + pos], val); + + return pnt; +error: + isl_point_free(pnt); + return NULL; +} + +struct isl_foreach_point { + struct isl_scan_callback callback; + isl_stat (*fn)(__isl_take isl_point *pnt, void *user); + void *user; + isl_space *dim; +}; + +static isl_stat foreach_point(struct isl_scan_callback *cb, + __isl_take isl_vec *sample) +{ + struct isl_foreach_point *fp = (struct isl_foreach_point *)cb; + isl_point *pnt; + + pnt = isl_point_alloc(isl_space_copy(fp->dim), sample); + + return fp->fn(pnt, fp->user); +} + +isl_stat isl_set_foreach_point(__isl_keep isl_set *set, + isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user) +{ + struct isl_foreach_point fp = { { &foreach_point }, fn, user }; + int i; + + if (!set) + return isl_stat_error; + + fp.dim = isl_set_get_space(set); + if (!fp.dim) + return isl_stat_error; + + set = isl_set_copy(set); + set = isl_set_cow(set); + set = isl_set_make_disjoint(set); + set = isl_set_compute_divs(set); + if (!set) + goto error; + + for (i = 0; i < set->n; ++i) + if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]), + &fp.callback) < 0) + goto error; + + isl_set_free(set); + isl_space_free(fp.dim); + + return isl_stat_ok; +error: + isl_set_free(set); + isl_space_free(fp.dim); + return isl_stat_error; +} + +/* Return 1 if "bmap" contains the point "point". + * "bmap" is assumed to have known divs. + * The point is first extended with the divs and then passed + * to basic_map_contains. + */ +isl_bool isl_basic_map_contains_point(__isl_keep isl_basic_map *bmap, + __isl_keep isl_point *point) +{ + int i; + struct isl_vec *vec; + unsigned dim; + isl_bool contains; + + if (!bmap || !point) + return isl_bool_error; + isl_assert(bmap->ctx, isl_space_is_equal(bmap->dim, point->dim), + return isl_bool_error); + if (bmap->n_div == 0) + return isl_basic_map_contains(bmap, point->vec); + + dim = isl_basic_map_total_dim(bmap) - bmap->n_div; + vec = isl_vec_alloc(bmap->ctx, 1 + dim + bmap->n_div); + if (!vec) + return isl_bool_error; + + isl_seq_cpy(vec->el, point->vec->el, point->vec->size); + for (i = 0; i < bmap->n_div; ++i) { + isl_seq_inner_product(bmap->div[i] + 1, vec->el, + 1 + dim + i, &vec->el[1+dim+i]); + isl_int_fdiv_q(vec->el[1+dim+i], vec->el[1+dim+i], + bmap->div[i][0]); + } + + contains = isl_basic_map_contains(bmap, vec); + + isl_vec_free(vec); + return contains; +} + +isl_bool isl_map_contains_point(__isl_keep isl_map *map, + __isl_keep isl_point *point) +{ + int i; + isl_bool found = isl_bool_false; + + if (!map || !point) + return isl_bool_error; + + map = isl_map_copy(map); + map = isl_map_compute_divs(map); + if (!map) + return isl_bool_error; + + for (i = 0; i < map->n; ++i) { + found = isl_basic_map_contains_point(map->p[i], point); + if (found < 0) + goto error; + if (found) + break; + } + isl_map_free(map); + + return found; +error: + isl_map_free(map); + return isl_bool_error; +} + +isl_bool isl_set_contains_point(__isl_keep isl_set *set, + __isl_keep isl_point *point) +{ + return isl_map_contains_point(set_to_map(set), point); +} + +__isl_give isl_basic_set *isl_basic_set_from_point(__isl_take isl_point *pnt) +{ + isl_basic_set *bset; + isl_basic_set *model; + + if (!pnt) + return NULL; + + model = isl_basic_set_empty(isl_space_copy(pnt->dim)); + bset = isl_basic_set_from_vec(isl_vec_copy(pnt->vec)); + bset = isl_basic_set_from_underlying_set(bset, model); + isl_point_free(pnt); + + return bset; +} + +__isl_give isl_set *isl_set_from_point(__isl_take isl_point *pnt) +{ + isl_basic_set *bset; + bset = isl_basic_set_from_point(pnt); + return isl_set_from_basic_set(bset); +} + +/* Construct a union set, containing the single element "pnt". + * If "pnt" is void, then return an empty union set. + */ +__isl_give isl_union_set *isl_union_set_from_point(__isl_take isl_point *pnt) +{ + if (!pnt) + return NULL; + if (isl_point_is_void(pnt)) { + isl_space *space; + + space = isl_point_get_space(pnt); + isl_point_free(pnt); + return isl_union_set_empty(space); + } + + return isl_union_set_from_set(isl_set_from_point(pnt)); +} + +__isl_give isl_basic_set *isl_basic_set_box_from_points( + __isl_take isl_point *pnt1, __isl_take isl_point *pnt2) +{ + isl_basic_set *bset = NULL; + unsigned total; + int i; + int k; + isl_int t; + + isl_int_init(t); + + if (!pnt1 || !pnt2) + goto error; + + isl_assert(pnt1->dim->ctx, + isl_space_is_equal(pnt1->dim, pnt2->dim), goto error); + + if (isl_point_is_void(pnt1) && isl_point_is_void(pnt2)) { + isl_space *dim = isl_space_copy(pnt1->dim); + isl_point_free(pnt1); + isl_point_free(pnt2); + isl_int_clear(t); + return isl_basic_set_empty(dim); + } + if (isl_point_is_void(pnt1)) { + isl_point_free(pnt1); + isl_int_clear(t); + return isl_basic_set_from_point(pnt2); + } + if (isl_point_is_void(pnt2)) { + isl_point_free(pnt2); + isl_int_clear(t); + return isl_basic_set_from_point(pnt1); + } + + total = isl_space_dim(pnt1->dim, isl_dim_all); + bset = isl_basic_set_alloc_space(isl_space_copy(pnt1->dim), 0, 0, 2 * total); + + for (i = 0; i < total; ++i) { + isl_int_mul(t, pnt1->vec->el[1 + i], pnt2->vec->el[0]); + isl_int_submul(t, pnt2->vec->el[1 + i], pnt1->vec->el[0]); + + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_clr(bset->ineq[k] + 1, total); + if (isl_int_is_pos(t)) { + isl_int_set_si(bset->ineq[k][1 + i], -1); + isl_int_set(bset->ineq[k][0], pnt1->vec->el[1 + i]); + } else { + isl_int_set_si(bset->ineq[k][1 + i], 1); + isl_int_neg(bset->ineq[k][0], pnt1->vec->el[1 + i]); + } + isl_int_fdiv_q(bset->ineq[k][0], bset->ineq[k][0], pnt1->vec->el[0]); + + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_clr(bset->ineq[k] + 1, total); + if (isl_int_is_pos(t)) { + isl_int_set_si(bset->ineq[k][1 + i], 1); + isl_int_neg(bset->ineq[k][0], pnt2->vec->el[1 + i]); + } else { + isl_int_set_si(bset->ineq[k][1 + i], -1); + isl_int_set(bset->ineq[k][0], pnt2->vec->el[1 + i]); + } + isl_int_fdiv_q(bset->ineq[k][0], bset->ineq[k][0], pnt2->vec->el[0]); + } + + bset = isl_basic_set_finalize(bset); + + isl_point_free(pnt1); + isl_point_free(pnt2); + + isl_int_clear(t); + + return bset; +error: + isl_point_free(pnt1); + isl_point_free(pnt2); + isl_int_clear(t); + isl_basic_set_free(bset); + return NULL; +} + +__isl_give isl_set *isl_set_box_from_points(__isl_take isl_point *pnt1, + __isl_take isl_point *pnt2) +{ + isl_basic_set *bset; + bset = isl_basic_set_box_from_points(pnt1, pnt2); + return isl_set_from_basic_set(bset); +} + +/* Print the coordinate at position "pos" of the point "pnt". + */ +static __isl_give isl_printer *print_coordinate(__isl_take isl_printer *p, + struct isl_print_space_data *data, unsigned pos) +{ + isl_point *pnt = data->user; + + p = isl_printer_print_isl_int(p, pnt->vec->el[1 + pos]); + if (!isl_int_is_one(pnt->vec->el[0])) { + p = isl_printer_print_str(p, "/"); + p = isl_printer_print_isl_int(p, pnt->vec->el[0]); + } + + return p; +} + +__isl_give isl_printer *isl_printer_print_point( + __isl_take isl_printer *p, __isl_keep isl_point *pnt) +{ + struct isl_print_space_data data = { 0 }; + int i; + unsigned nparam; + + if (!pnt) + return p; + if (isl_point_is_void(pnt)) { + p = isl_printer_print_str(p, "void"); + return p; + } + + nparam = isl_space_dim(pnt->dim, isl_dim_param); + if (nparam > 0) { + p = isl_printer_print_str(p, "["); + for (i = 0; i < nparam; ++i) { + const char *name; + if (i) + p = isl_printer_print_str(p, ", "); + name = isl_space_get_dim_name(pnt->dim, isl_dim_param, i); + if (name) { + p = isl_printer_print_str(p, name); + p = isl_printer_print_str(p, " = "); + } + p = isl_printer_print_isl_int(p, pnt->vec->el[1 + i]); + if (!isl_int_is_one(pnt->vec->el[0])) { + p = isl_printer_print_str(p, "/"); + p = isl_printer_print_isl_int(p, pnt->vec->el[0]); + } + } + p = isl_printer_print_str(p, "]"); + p = isl_printer_print_str(p, " -> "); + } + data.print_dim = &print_coordinate; + data.user = pnt; + p = isl_printer_print_str(p, "{ "); + p = isl_print_space(pnt->dim, p, 0, &data); + p = isl_printer_print_str(p, " }"); + return p; +} Index: contrib/isl/isl_point_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_point_private.h @@ -0,0 +1,12 @@ +#include +#include +#include + +struct isl_point { + int ref; + isl_space *dim; + struct isl_vec *vec; +}; + +__isl_give isl_point *isl_point_alloc(__isl_take isl_space *dim, + __isl_take isl_vec *vec); Index: contrib/isl/isl_polynomial.c =================================================================== --- /dev/null +++ contrib/isl/isl_polynomial.c @@ -0,0 +1,5012 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#include +#define ISL_DIM_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned pos(__isl_keep isl_space *dim, enum isl_dim_type type) +{ + switch (type) { + case isl_dim_param: return 0; + case isl_dim_in: return dim->nparam; + case isl_dim_out: return dim->nparam + dim->n_in; + default: return 0; + } +} + +int isl_upoly_is_cst(__isl_keep struct isl_upoly *up) +{ + if (!up) + return -1; + + return up->var < 0; +} + +__isl_keep struct isl_upoly_cst *isl_upoly_as_cst(__isl_keep struct isl_upoly *up) +{ + if (!up) + return NULL; + + isl_assert(up->ctx, up->var < 0, return NULL); + + return (struct isl_upoly_cst *)up; +} + +__isl_keep struct isl_upoly_rec *isl_upoly_as_rec(__isl_keep struct isl_upoly *up) +{ + if (!up) + return NULL; + + isl_assert(up->ctx, up->var >= 0, return NULL); + + return (struct isl_upoly_rec *)up; +} + +/* Compare two polynomials. + * + * Return -1 if "up1" is "smaller" than "up2", 1 if "up1" is "greater" + * than "up2" and 0 if they are equal. + */ +static int isl_upoly_plain_cmp(__isl_keep struct isl_upoly *up1, + __isl_keep struct isl_upoly *up2) +{ + int i; + struct isl_upoly_rec *rec1, *rec2; + + if (up1 == up2) + return 0; + if (!up1) + return -1; + if (!up2) + return 1; + if (up1->var != up2->var) + return up1->var - up2->var; + + if (isl_upoly_is_cst(up1)) { + struct isl_upoly_cst *cst1, *cst2; + int cmp; + + cst1 = isl_upoly_as_cst(up1); + cst2 = isl_upoly_as_cst(up2); + if (!cst1 || !cst2) + return 0; + cmp = isl_int_cmp(cst1->n, cst2->n); + if (cmp != 0) + return cmp; + return isl_int_cmp(cst1->d, cst2->d); + } + + rec1 = isl_upoly_as_rec(up1); + rec2 = isl_upoly_as_rec(up2); + if (!rec1 || !rec2) + return 0; + + if (rec1->n != rec2->n) + return rec1->n - rec2->n; + + for (i = 0; i < rec1->n; ++i) { + int cmp = isl_upoly_plain_cmp(rec1->p[i], rec2->p[i]); + if (cmp != 0) + return cmp; + } + + return 0; +} + +isl_bool isl_upoly_is_equal(__isl_keep struct isl_upoly *up1, + __isl_keep struct isl_upoly *up2) +{ + int i; + struct isl_upoly_rec *rec1, *rec2; + + if (!up1 || !up2) + return isl_bool_error; + if (up1 == up2) + return isl_bool_true; + if (up1->var != up2->var) + return isl_bool_false; + if (isl_upoly_is_cst(up1)) { + struct isl_upoly_cst *cst1, *cst2; + cst1 = isl_upoly_as_cst(up1); + cst2 = isl_upoly_as_cst(up2); + if (!cst1 || !cst2) + return isl_bool_error; + return isl_int_eq(cst1->n, cst2->n) && + isl_int_eq(cst1->d, cst2->d); + } + + rec1 = isl_upoly_as_rec(up1); + rec2 = isl_upoly_as_rec(up2); + if (!rec1 || !rec2) + return isl_bool_error; + + if (rec1->n != rec2->n) + return isl_bool_false; + + for (i = 0; i < rec1->n; ++i) { + isl_bool eq = isl_upoly_is_equal(rec1->p[i], rec2->p[i]); + if (eq < 0 || !eq) + return eq; + } + + return isl_bool_true; +} + +int isl_upoly_is_zero(__isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + + if (!up) + return -1; + if (!isl_upoly_is_cst(up)) + return 0; + + cst = isl_upoly_as_cst(up); + if (!cst) + return -1; + + return isl_int_is_zero(cst->n) && isl_int_is_pos(cst->d); +} + +int isl_upoly_sgn(__isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + + if (!up) + return 0; + if (!isl_upoly_is_cst(up)) + return 0; + + cst = isl_upoly_as_cst(up); + if (!cst) + return 0; + + return isl_int_sgn(cst->n); +} + +int isl_upoly_is_nan(__isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + + if (!up) + return -1; + if (!isl_upoly_is_cst(up)) + return 0; + + cst = isl_upoly_as_cst(up); + if (!cst) + return -1; + + return isl_int_is_zero(cst->n) && isl_int_is_zero(cst->d); +} + +int isl_upoly_is_infty(__isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + + if (!up) + return -1; + if (!isl_upoly_is_cst(up)) + return 0; + + cst = isl_upoly_as_cst(up); + if (!cst) + return -1; + + return isl_int_is_pos(cst->n) && isl_int_is_zero(cst->d); +} + +int isl_upoly_is_neginfty(__isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + + if (!up) + return -1; + if (!isl_upoly_is_cst(up)) + return 0; + + cst = isl_upoly_as_cst(up); + if (!cst) + return -1; + + return isl_int_is_neg(cst->n) && isl_int_is_zero(cst->d); +} + +int isl_upoly_is_one(__isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + + if (!up) + return -1; + if (!isl_upoly_is_cst(up)) + return 0; + + cst = isl_upoly_as_cst(up); + if (!cst) + return -1; + + return isl_int_eq(cst->n, cst->d) && isl_int_is_pos(cst->d); +} + +int isl_upoly_is_negone(__isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + + if (!up) + return -1; + if (!isl_upoly_is_cst(up)) + return 0; + + cst = isl_upoly_as_cst(up); + if (!cst) + return -1; + + return isl_int_is_negone(cst->n) && isl_int_is_one(cst->d); +} + +__isl_give struct isl_upoly_cst *isl_upoly_cst_alloc(struct isl_ctx *ctx) +{ + struct isl_upoly_cst *cst; + + cst = isl_alloc_type(ctx, struct isl_upoly_cst); + if (!cst) + return NULL; + + cst->up.ref = 1; + cst->up.ctx = ctx; + isl_ctx_ref(ctx); + cst->up.var = -1; + + isl_int_init(cst->n); + isl_int_init(cst->d); + + return cst; +} + +__isl_give struct isl_upoly *isl_upoly_zero(struct isl_ctx *ctx) +{ + struct isl_upoly_cst *cst; + + cst = isl_upoly_cst_alloc(ctx); + if (!cst) + return NULL; + + isl_int_set_si(cst->n, 0); + isl_int_set_si(cst->d, 1); + + return &cst->up; +} + +__isl_give struct isl_upoly *isl_upoly_one(struct isl_ctx *ctx) +{ + struct isl_upoly_cst *cst; + + cst = isl_upoly_cst_alloc(ctx); + if (!cst) + return NULL; + + isl_int_set_si(cst->n, 1); + isl_int_set_si(cst->d, 1); + + return &cst->up; +} + +__isl_give struct isl_upoly *isl_upoly_infty(struct isl_ctx *ctx) +{ + struct isl_upoly_cst *cst; + + cst = isl_upoly_cst_alloc(ctx); + if (!cst) + return NULL; + + isl_int_set_si(cst->n, 1); + isl_int_set_si(cst->d, 0); + + return &cst->up; +} + +__isl_give struct isl_upoly *isl_upoly_neginfty(struct isl_ctx *ctx) +{ + struct isl_upoly_cst *cst; + + cst = isl_upoly_cst_alloc(ctx); + if (!cst) + return NULL; + + isl_int_set_si(cst->n, -1); + isl_int_set_si(cst->d, 0); + + return &cst->up; +} + +__isl_give struct isl_upoly *isl_upoly_nan(struct isl_ctx *ctx) +{ + struct isl_upoly_cst *cst; + + cst = isl_upoly_cst_alloc(ctx); + if (!cst) + return NULL; + + isl_int_set_si(cst->n, 0); + isl_int_set_si(cst->d, 0); + + return &cst->up; +} + +__isl_give struct isl_upoly *isl_upoly_rat_cst(struct isl_ctx *ctx, + isl_int n, isl_int d) +{ + struct isl_upoly_cst *cst; + + cst = isl_upoly_cst_alloc(ctx); + if (!cst) + return NULL; + + isl_int_set(cst->n, n); + isl_int_set(cst->d, d); + + return &cst->up; +} + +__isl_give struct isl_upoly_rec *isl_upoly_alloc_rec(struct isl_ctx *ctx, + int var, int size) +{ + struct isl_upoly_rec *rec; + + isl_assert(ctx, var >= 0, return NULL); + isl_assert(ctx, size >= 0, return NULL); + rec = isl_calloc(ctx, struct isl_upoly_rec, + sizeof(struct isl_upoly_rec) + + size * sizeof(struct isl_upoly *)); + if (!rec) + return NULL; + + rec->up.ref = 1; + rec->up.ctx = ctx; + isl_ctx_ref(ctx); + rec->up.var = var; + + rec->n = 0; + rec->size = size; + + return rec; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_reset_domain_space( + __isl_take isl_qpolynomial *qp, __isl_take isl_space *dim) +{ + qp = isl_qpolynomial_cow(qp); + if (!qp || !dim) + goto error; + + isl_space_free(qp->dim); + qp->dim = dim; + + return qp; +error: + isl_qpolynomial_free(qp); + isl_space_free(dim); + return NULL; +} + +/* Reset the space of "qp". This function is called from isl_pw_templ.c + * and doesn't know if the space of an element object is represented + * directly or through its domain. It therefore passes along both. + */ +__isl_give isl_qpolynomial *isl_qpolynomial_reset_space_and_domain( + __isl_take isl_qpolynomial *qp, __isl_take isl_space *space, + __isl_take isl_space *domain) +{ + isl_space_free(space); + return isl_qpolynomial_reset_domain_space(qp, domain); +} + +isl_ctx *isl_qpolynomial_get_ctx(__isl_keep isl_qpolynomial *qp) +{ + return qp ? qp->dim->ctx : NULL; +} + +__isl_give isl_space *isl_qpolynomial_get_domain_space( + __isl_keep isl_qpolynomial *qp) +{ + return qp ? isl_space_copy(qp->dim) : NULL; +} + +__isl_give isl_space *isl_qpolynomial_get_space(__isl_keep isl_qpolynomial *qp) +{ + isl_space *space; + if (!qp) + return NULL; + space = isl_space_copy(qp->dim); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, 1); + return space; +} + +/* Return the number of variables of the given type in the domain of "qp". + */ +unsigned isl_qpolynomial_domain_dim(__isl_keep isl_qpolynomial *qp, + enum isl_dim_type type) +{ + if (!qp) + return 0; + if (type == isl_dim_div) + return qp->div->n_row; + if (type == isl_dim_all) + return isl_space_dim(qp->dim, isl_dim_all) + + isl_qpolynomial_domain_dim(qp, isl_dim_div); + return isl_space_dim(qp->dim, type); +} + +/* Externally, an isl_qpolynomial has a map space, but internally, the + * ls field corresponds to the domain of that space. + */ +unsigned isl_qpolynomial_dim(__isl_keep isl_qpolynomial *qp, + enum isl_dim_type type) +{ + if (!qp) + return 0; + if (type == isl_dim_out) + return 1; + if (type == isl_dim_in) + type = isl_dim_set; + return isl_qpolynomial_domain_dim(qp, type); +} + +/* Return the offset of the first coefficient of type "type" in + * the domain of "qp". + */ +unsigned isl_qpolynomial_domain_offset(__isl_keep isl_qpolynomial *qp, + enum isl_dim_type type) +{ + if (!qp) + return 0; + switch (type) { + case isl_dim_cst: + return 0; + case isl_dim_param: + case isl_dim_set: + return 1 + isl_space_offset(qp->dim, type); + case isl_dim_div: + return 1 + isl_space_dim(qp->dim, isl_dim_all); + default: + return 0; + } +} + +isl_bool isl_qpolynomial_is_zero(__isl_keep isl_qpolynomial *qp) +{ + return qp ? isl_upoly_is_zero(qp->upoly) : isl_bool_error; +} + +isl_bool isl_qpolynomial_is_one(__isl_keep isl_qpolynomial *qp) +{ + return qp ? isl_upoly_is_one(qp->upoly) : isl_bool_error; +} + +isl_bool isl_qpolynomial_is_nan(__isl_keep isl_qpolynomial *qp) +{ + return qp ? isl_upoly_is_nan(qp->upoly) : isl_bool_error; +} + +isl_bool isl_qpolynomial_is_infty(__isl_keep isl_qpolynomial *qp) +{ + return qp ? isl_upoly_is_infty(qp->upoly) : isl_bool_error; +} + +isl_bool isl_qpolynomial_is_neginfty(__isl_keep isl_qpolynomial *qp) +{ + return qp ? isl_upoly_is_neginfty(qp->upoly) : isl_bool_error; +} + +int isl_qpolynomial_sgn(__isl_keep isl_qpolynomial *qp) +{ + return qp ? isl_upoly_sgn(qp->upoly) : 0; +} + +static void upoly_free_cst(__isl_take struct isl_upoly_cst *cst) +{ + isl_int_clear(cst->n); + isl_int_clear(cst->d); +} + +static void upoly_free_rec(__isl_take struct isl_upoly_rec *rec) +{ + int i; + + for (i = 0; i < rec->n; ++i) + isl_upoly_free(rec->p[i]); +} + +__isl_give struct isl_upoly *isl_upoly_copy(__isl_keep struct isl_upoly *up) +{ + if (!up) + return NULL; + + up->ref++; + return up; +} + +__isl_give struct isl_upoly *isl_upoly_dup_cst(__isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + struct isl_upoly_cst *dup; + + cst = isl_upoly_as_cst(up); + if (!cst) + return NULL; + + dup = isl_upoly_as_cst(isl_upoly_zero(up->ctx)); + if (!dup) + return NULL; + isl_int_set(dup->n, cst->n); + isl_int_set(dup->d, cst->d); + + return &dup->up; +} + +__isl_give struct isl_upoly *isl_upoly_dup_rec(__isl_keep struct isl_upoly *up) +{ + int i; + struct isl_upoly_rec *rec; + struct isl_upoly_rec *dup; + + rec = isl_upoly_as_rec(up); + if (!rec) + return NULL; + + dup = isl_upoly_alloc_rec(up->ctx, up->var, rec->n); + if (!dup) + return NULL; + + for (i = 0; i < rec->n; ++i) { + dup->p[i] = isl_upoly_copy(rec->p[i]); + if (!dup->p[i]) + goto error; + dup->n++; + } + + return &dup->up; +error: + isl_upoly_free(&dup->up); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_dup(__isl_keep struct isl_upoly *up) +{ + if (!up) + return NULL; + + if (isl_upoly_is_cst(up)) + return isl_upoly_dup_cst(up); + else + return isl_upoly_dup_rec(up); +} + +__isl_give struct isl_upoly *isl_upoly_cow(__isl_take struct isl_upoly *up) +{ + if (!up) + return NULL; + + if (up->ref == 1) + return up; + up->ref--; + return isl_upoly_dup(up); +} + +__isl_null struct isl_upoly *isl_upoly_free(__isl_take struct isl_upoly *up) +{ + if (!up) + return NULL; + + if (--up->ref > 0) + return NULL; + + if (up->var < 0) + upoly_free_cst((struct isl_upoly_cst *)up); + else + upoly_free_rec((struct isl_upoly_rec *)up); + + isl_ctx_deref(up->ctx); + free(up); + return NULL; +} + +static void isl_upoly_cst_reduce(__isl_keep struct isl_upoly_cst *cst) +{ + isl_int gcd; + + isl_int_init(gcd); + isl_int_gcd(gcd, cst->n, cst->d); + if (!isl_int_is_zero(gcd) && !isl_int_is_one(gcd)) { + isl_int_divexact(cst->n, cst->n, gcd); + isl_int_divexact(cst->d, cst->d, gcd); + } + isl_int_clear(gcd); +} + +__isl_give struct isl_upoly *isl_upoly_sum_cst(__isl_take struct isl_upoly *up1, + __isl_take struct isl_upoly *up2) +{ + struct isl_upoly_cst *cst1; + struct isl_upoly_cst *cst2; + + up1 = isl_upoly_cow(up1); + if (!up1 || !up2) + goto error; + + cst1 = isl_upoly_as_cst(up1); + cst2 = isl_upoly_as_cst(up2); + + if (isl_int_eq(cst1->d, cst2->d)) + isl_int_add(cst1->n, cst1->n, cst2->n); + else { + isl_int_mul(cst1->n, cst1->n, cst2->d); + isl_int_addmul(cst1->n, cst2->n, cst1->d); + isl_int_mul(cst1->d, cst1->d, cst2->d); + } + + isl_upoly_cst_reduce(cst1); + + isl_upoly_free(up2); + return up1; +error: + isl_upoly_free(up1); + isl_upoly_free(up2); + return NULL; +} + +static __isl_give struct isl_upoly *replace_by_zero( + __isl_take struct isl_upoly *up) +{ + struct isl_ctx *ctx; + + if (!up) + return NULL; + ctx = up->ctx; + isl_upoly_free(up); + return isl_upoly_zero(ctx); +} + +static __isl_give struct isl_upoly *replace_by_constant_term( + __isl_take struct isl_upoly *up) +{ + struct isl_upoly_rec *rec; + struct isl_upoly *cst; + + if (!up) + return NULL; + + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + cst = isl_upoly_copy(rec->p[0]); + isl_upoly_free(up); + return cst; +error: + isl_upoly_free(up); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_sum(__isl_take struct isl_upoly *up1, + __isl_take struct isl_upoly *up2) +{ + int i; + struct isl_upoly_rec *rec1, *rec2; + + if (!up1 || !up2) + goto error; + + if (isl_upoly_is_nan(up1)) { + isl_upoly_free(up2); + return up1; + } + + if (isl_upoly_is_nan(up2)) { + isl_upoly_free(up1); + return up2; + } + + if (isl_upoly_is_zero(up1)) { + isl_upoly_free(up1); + return up2; + } + + if (isl_upoly_is_zero(up2)) { + isl_upoly_free(up2); + return up1; + } + + if (up1->var < up2->var) + return isl_upoly_sum(up2, up1); + + if (up2->var < up1->var) { + struct isl_upoly_rec *rec; + if (isl_upoly_is_infty(up2) || isl_upoly_is_neginfty(up2)) { + isl_upoly_free(up1); + return up2; + } + up1 = isl_upoly_cow(up1); + rec = isl_upoly_as_rec(up1); + if (!rec) + goto error; + rec->p[0] = isl_upoly_sum(rec->p[0], up2); + if (rec->n == 1) + up1 = replace_by_constant_term(up1); + return up1; + } + + if (isl_upoly_is_cst(up1)) + return isl_upoly_sum_cst(up1, up2); + + rec1 = isl_upoly_as_rec(up1); + rec2 = isl_upoly_as_rec(up2); + if (!rec1 || !rec2) + goto error; + + if (rec1->n < rec2->n) + return isl_upoly_sum(up2, up1); + + up1 = isl_upoly_cow(up1); + rec1 = isl_upoly_as_rec(up1); + if (!rec1) + goto error; + + for (i = rec2->n - 1; i >= 0; --i) { + rec1->p[i] = isl_upoly_sum(rec1->p[i], + isl_upoly_copy(rec2->p[i])); + if (!rec1->p[i]) + goto error; + if (i == rec1->n - 1 && isl_upoly_is_zero(rec1->p[i])) { + isl_upoly_free(rec1->p[i]); + rec1->n--; + } + } + + if (rec1->n == 0) + up1 = replace_by_zero(up1); + else if (rec1->n == 1) + up1 = replace_by_constant_term(up1); + + isl_upoly_free(up2); + + return up1; +error: + isl_upoly_free(up1); + isl_upoly_free(up2); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_cst_add_isl_int( + __isl_take struct isl_upoly *up, isl_int v) +{ + struct isl_upoly_cst *cst; + + up = isl_upoly_cow(up); + if (!up) + return NULL; + + cst = isl_upoly_as_cst(up); + + isl_int_addmul(cst->n, cst->d, v); + + return up; +} + +__isl_give struct isl_upoly *isl_upoly_add_isl_int( + __isl_take struct isl_upoly *up, isl_int v) +{ + struct isl_upoly_rec *rec; + + if (!up) + return NULL; + + if (isl_upoly_is_cst(up)) + return isl_upoly_cst_add_isl_int(up, v); + + up = isl_upoly_cow(up); + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + rec->p[0] = isl_upoly_add_isl_int(rec->p[0], v); + if (!rec->p[0]) + goto error; + + return up; +error: + isl_upoly_free(up); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_cst_mul_isl_int( + __isl_take struct isl_upoly *up, isl_int v) +{ + struct isl_upoly_cst *cst; + + if (isl_upoly_is_zero(up)) + return up; + + up = isl_upoly_cow(up); + if (!up) + return NULL; + + cst = isl_upoly_as_cst(up); + + isl_int_mul(cst->n, cst->n, v); + + return up; +} + +__isl_give struct isl_upoly *isl_upoly_mul_isl_int( + __isl_take struct isl_upoly *up, isl_int v) +{ + int i; + struct isl_upoly_rec *rec; + + if (!up) + return NULL; + + if (isl_upoly_is_cst(up)) + return isl_upoly_cst_mul_isl_int(up, v); + + up = isl_upoly_cow(up); + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + for (i = 0; i < rec->n; ++i) { + rec->p[i] = isl_upoly_mul_isl_int(rec->p[i], v); + if (!rec->p[i]) + goto error; + } + + return up; +error: + isl_upoly_free(up); + return NULL; +} + +/* Multiply the constant polynomial "up" by "v". + */ +static __isl_give struct isl_upoly *isl_upoly_cst_scale_val( + __isl_take struct isl_upoly *up, __isl_keep isl_val *v) +{ + struct isl_upoly_cst *cst; + + if (isl_upoly_is_zero(up)) + return up; + + up = isl_upoly_cow(up); + if (!up) + return NULL; + + cst = isl_upoly_as_cst(up); + + isl_int_mul(cst->n, cst->n, v->n); + isl_int_mul(cst->d, cst->d, v->d); + isl_upoly_cst_reduce(cst); + + return up; +} + +/* Multiply the polynomial "up" by "v". + */ +static __isl_give struct isl_upoly *isl_upoly_scale_val( + __isl_take struct isl_upoly *up, __isl_keep isl_val *v) +{ + int i; + struct isl_upoly_rec *rec; + + if (!up) + return NULL; + + if (isl_upoly_is_cst(up)) + return isl_upoly_cst_scale_val(up, v); + + up = isl_upoly_cow(up); + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + for (i = 0; i < rec->n; ++i) { + rec->p[i] = isl_upoly_scale_val(rec->p[i], v); + if (!rec->p[i]) + goto error; + } + + return up; +error: + isl_upoly_free(up); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_mul_cst(__isl_take struct isl_upoly *up1, + __isl_take struct isl_upoly *up2) +{ + struct isl_upoly_cst *cst1; + struct isl_upoly_cst *cst2; + + up1 = isl_upoly_cow(up1); + if (!up1 || !up2) + goto error; + + cst1 = isl_upoly_as_cst(up1); + cst2 = isl_upoly_as_cst(up2); + + isl_int_mul(cst1->n, cst1->n, cst2->n); + isl_int_mul(cst1->d, cst1->d, cst2->d); + + isl_upoly_cst_reduce(cst1); + + isl_upoly_free(up2); + return up1; +error: + isl_upoly_free(up1); + isl_upoly_free(up2); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_mul_rec(__isl_take struct isl_upoly *up1, + __isl_take struct isl_upoly *up2) +{ + struct isl_upoly_rec *rec1; + struct isl_upoly_rec *rec2; + struct isl_upoly_rec *res = NULL; + int i, j; + int size; + + rec1 = isl_upoly_as_rec(up1); + rec2 = isl_upoly_as_rec(up2); + if (!rec1 || !rec2) + goto error; + size = rec1->n + rec2->n - 1; + res = isl_upoly_alloc_rec(up1->ctx, up1->var, size); + if (!res) + goto error; + + for (i = 0; i < rec1->n; ++i) { + res->p[i] = isl_upoly_mul(isl_upoly_copy(rec2->p[0]), + isl_upoly_copy(rec1->p[i])); + if (!res->p[i]) + goto error; + res->n++; + } + for (; i < size; ++i) { + res->p[i] = isl_upoly_zero(up1->ctx); + if (!res->p[i]) + goto error; + res->n++; + } + for (i = 0; i < rec1->n; ++i) { + for (j = 1; j < rec2->n; ++j) { + struct isl_upoly *up; + up = isl_upoly_mul(isl_upoly_copy(rec2->p[j]), + isl_upoly_copy(rec1->p[i])); + res->p[i + j] = isl_upoly_sum(res->p[i + j], up); + if (!res->p[i + j]) + goto error; + } + } + + isl_upoly_free(up1); + isl_upoly_free(up2); + + return &res->up; +error: + isl_upoly_free(up1); + isl_upoly_free(up2); + isl_upoly_free(&res->up); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_mul(__isl_take struct isl_upoly *up1, + __isl_take struct isl_upoly *up2) +{ + if (!up1 || !up2) + goto error; + + if (isl_upoly_is_nan(up1)) { + isl_upoly_free(up2); + return up1; + } + + if (isl_upoly_is_nan(up2)) { + isl_upoly_free(up1); + return up2; + } + + if (isl_upoly_is_zero(up1)) { + isl_upoly_free(up2); + return up1; + } + + if (isl_upoly_is_zero(up2)) { + isl_upoly_free(up1); + return up2; + } + + if (isl_upoly_is_one(up1)) { + isl_upoly_free(up1); + return up2; + } + + if (isl_upoly_is_one(up2)) { + isl_upoly_free(up2); + return up1; + } + + if (up1->var < up2->var) + return isl_upoly_mul(up2, up1); + + if (up2->var < up1->var) { + int i; + struct isl_upoly_rec *rec; + if (isl_upoly_is_infty(up2) || isl_upoly_is_neginfty(up2)) { + isl_ctx *ctx = up1->ctx; + isl_upoly_free(up1); + isl_upoly_free(up2); + return isl_upoly_nan(ctx); + } + up1 = isl_upoly_cow(up1); + rec = isl_upoly_as_rec(up1); + if (!rec) + goto error; + + for (i = 0; i < rec->n; ++i) { + rec->p[i] = isl_upoly_mul(rec->p[i], + isl_upoly_copy(up2)); + if (!rec->p[i]) + goto error; + } + isl_upoly_free(up2); + return up1; + } + + if (isl_upoly_is_cst(up1)) + return isl_upoly_mul_cst(up1, up2); + + return isl_upoly_mul_rec(up1, up2); +error: + isl_upoly_free(up1); + isl_upoly_free(up2); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_pow(__isl_take struct isl_upoly *up, + unsigned power) +{ + struct isl_upoly *res; + + if (!up) + return NULL; + if (power == 1) + return up; + + if (power % 2) + res = isl_upoly_copy(up); + else + res = isl_upoly_one(up->ctx); + + while (power >>= 1) { + up = isl_upoly_mul(up, isl_upoly_copy(up)); + if (power % 2) + res = isl_upoly_mul(res, isl_upoly_copy(up)); + } + + isl_upoly_free(up); + return res; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_alloc(__isl_take isl_space *dim, + unsigned n_div, __isl_take struct isl_upoly *up) +{ + struct isl_qpolynomial *qp = NULL; + unsigned total; + + if (!dim || !up) + goto error; + + if (!isl_space_is_set(dim)) + isl_die(isl_space_get_ctx(dim), isl_error_invalid, + "domain of polynomial should be a set", goto error); + + total = isl_space_dim(dim, isl_dim_all); + + qp = isl_calloc_type(dim->ctx, struct isl_qpolynomial); + if (!qp) + goto error; + + qp->ref = 1; + qp->div = isl_mat_alloc(dim->ctx, n_div, 1 + 1 + total + n_div); + if (!qp->div) + goto error; + + qp->dim = dim; + qp->upoly = up; + + return qp; +error: + isl_space_free(dim); + isl_upoly_free(up); + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_copy(__isl_keep isl_qpolynomial *qp) +{ + if (!qp) + return NULL; + + qp->ref++; + return qp; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_dup(__isl_keep isl_qpolynomial *qp) +{ + struct isl_qpolynomial *dup; + + if (!qp) + return NULL; + + dup = isl_qpolynomial_alloc(isl_space_copy(qp->dim), qp->div->n_row, + isl_upoly_copy(qp->upoly)); + if (!dup) + return NULL; + isl_mat_free(dup->div); + dup->div = isl_mat_copy(qp->div); + if (!dup->div) + goto error; + + return dup; +error: + isl_qpolynomial_free(dup); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_cow(__isl_take isl_qpolynomial *qp) +{ + if (!qp) + return NULL; + + if (qp->ref == 1) + return qp; + qp->ref--; + return isl_qpolynomial_dup(qp); +} + +__isl_null isl_qpolynomial *isl_qpolynomial_free( + __isl_take isl_qpolynomial *qp) +{ + if (!qp) + return NULL; + + if (--qp->ref > 0) + return NULL; + + isl_space_free(qp->dim); + isl_mat_free(qp->div); + isl_upoly_free(qp->upoly); + + free(qp); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_var_pow(isl_ctx *ctx, int pos, int power) +{ + int i; + struct isl_upoly_rec *rec; + struct isl_upoly_cst *cst; + + rec = isl_upoly_alloc_rec(ctx, pos, 1 + power); + if (!rec) + return NULL; + for (i = 0; i < 1 + power; ++i) { + rec->p[i] = isl_upoly_zero(ctx); + if (!rec->p[i]) + goto error; + rec->n++; + } + cst = isl_upoly_as_cst(rec->p[power]); + isl_int_set_si(cst->n, 1); + + return &rec->up; +error: + isl_upoly_free(&rec->up); + return NULL; +} + +/* r array maps original positions to new positions. + */ +static __isl_give struct isl_upoly *reorder(__isl_take struct isl_upoly *up, + int *r) +{ + int i; + struct isl_upoly_rec *rec; + struct isl_upoly *base; + struct isl_upoly *res; + + if (isl_upoly_is_cst(up)) + return up; + + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + isl_assert(up->ctx, rec->n >= 1, goto error); + + base = isl_upoly_var_pow(up->ctx, r[up->var], 1); + res = reorder(isl_upoly_copy(rec->p[rec->n - 1]), r); + + for (i = rec->n - 2; i >= 0; --i) { + res = isl_upoly_mul(res, isl_upoly_copy(base)); + res = isl_upoly_sum(res, reorder(isl_upoly_copy(rec->p[i]), r)); + } + + isl_upoly_free(base); + isl_upoly_free(up); + + return res; +error: + isl_upoly_free(up); + return NULL; +} + +static isl_bool compatible_divs(__isl_keep isl_mat *div1, + __isl_keep isl_mat *div2) +{ + int n_row, n_col; + isl_bool equal; + + isl_assert(div1->ctx, div1->n_row >= div2->n_row && + div1->n_col >= div2->n_col, + return isl_bool_error); + + if (div1->n_row == div2->n_row) + return isl_mat_is_equal(div1, div2); + + n_row = div1->n_row; + n_col = div1->n_col; + div1->n_row = div2->n_row; + div1->n_col = div2->n_col; + + equal = isl_mat_is_equal(div1, div2); + + div1->n_row = n_row; + div1->n_col = n_col; + + return equal; +} + +static int cmp_row(__isl_keep isl_mat *div, int i, int j) +{ + int li, lj; + + 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); +} + +struct isl_div_sort_info { + isl_mat *div; + int row; +}; + +static int div_sort_cmp(const void *p1, const void *p2) +{ + const struct isl_div_sort_info *i1, *i2; + i1 = (const struct isl_div_sort_info *) p1; + i2 = (const struct isl_div_sort_info *) p2; + + return cmp_row(i1->div, i1->row, i2->row); +} + +/* Sort divs and remove duplicates. + */ +static __isl_give isl_qpolynomial *sort_divs(__isl_take isl_qpolynomial *qp) +{ + int i; + int skip; + int len; + struct isl_div_sort_info *array = NULL; + int *pos = NULL, *at = NULL; + int *reordering = NULL; + unsigned div_pos; + + if (!qp) + return NULL; + if (qp->div->n_row <= 1) + return qp; + + div_pos = isl_space_dim(qp->dim, isl_dim_all); + + array = isl_alloc_array(qp->div->ctx, struct isl_div_sort_info, + qp->div->n_row); + pos = isl_alloc_array(qp->div->ctx, int, qp->div->n_row); + at = isl_alloc_array(qp->div->ctx, int, qp->div->n_row); + len = qp->div->n_col - 2; + reordering = isl_alloc_array(qp->div->ctx, int, len); + if (!array || !pos || !at || !reordering) + goto error; + + for (i = 0; i < qp->div->n_row; ++i) { + array[i].div = qp->div; + array[i].row = i; + pos[i] = i; + at[i] = i; + } + + qsort(array, qp->div->n_row, sizeof(struct isl_div_sort_info), + div_sort_cmp); + + for (i = 0; i < div_pos; ++i) + reordering[i] = i; + + for (i = 0; i < qp->div->n_row; ++i) { + if (pos[array[i].row] == i) + continue; + qp->div = isl_mat_swap_rows(qp->div, i, pos[array[i].row]); + pos[at[i]] = pos[array[i].row]; + at[pos[array[i].row]] = at[i]; + at[i] = array[i].row; + pos[array[i].row] = i; + } + + skip = 0; + for (i = 0; i < len - div_pos; ++i) { + if (i > 0 && + isl_seq_eq(qp->div->row[i - skip - 1], + qp->div->row[i - skip], qp->div->n_col)) { + qp->div = isl_mat_drop_rows(qp->div, i - skip, 1); + isl_mat_col_add(qp->div, 2 + div_pos + i - skip - 1, + 2 + div_pos + i - skip); + qp->div = isl_mat_drop_cols(qp->div, + 2 + div_pos + i - skip, 1); + skip++; + } + reordering[div_pos + array[i].row] = div_pos + i - skip; + } + + qp->upoly = reorder(qp->upoly, reordering); + + if (!qp->upoly || !qp->div) + goto error; + + free(at); + free(pos); + free(array); + free(reordering); + + return qp; +error: + free(at); + free(pos); + free(array); + free(reordering); + isl_qpolynomial_free(qp); + return NULL; +} + +static __isl_give struct isl_upoly *expand(__isl_take struct isl_upoly *up, + int *exp, int first) +{ + int i; + struct isl_upoly_rec *rec; + + if (isl_upoly_is_cst(up)) + return up; + + if (up->var < first) + return up; + + if (exp[up->var - first] == up->var - first) + return up; + + up = isl_upoly_cow(up); + if (!up) + goto error; + + up->var = exp[up->var - first] + first; + + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + for (i = 0; i < rec->n; ++i) { + rec->p[i] = expand(rec->p[i], exp, first); + if (!rec->p[i]) + goto error; + } + + return up; +error: + isl_upoly_free(up); + return NULL; +} + +static __isl_give isl_qpolynomial *with_merged_divs( + __isl_give isl_qpolynomial *(*fn)(__isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2), + __isl_take isl_qpolynomial *qp1, __isl_take isl_qpolynomial *qp2) +{ + int *exp1 = NULL; + int *exp2 = NULL; + isl_mat *div = NULL; + int n_div1, n_div2; + + qp1 = isl_qpolynomial_cow(qp1); + qp2 = isl_qpolynomial_cow(qp2); + + if (!qp1 || !qp2) + goto error; + + isl_assert(qp1->div->ctx, qp1->div->n_row >= qp2->div->n_row && + qp1->div->n_col >= qp2->div->n_col, goto error); + + n_div1 = qp1->div->n_row; + n_div2 = qp2->div->n_row; + exp1 = isl_alloc_array(qp1->div->ctx, int, n_div1); + exp2 = isl_alloc_array(qp2->div->ctx, int, n_div2); + if ((n_div1 && !exp1) || (n_div2 && !exp2)) + goto error; + + div = isl_merge_divs(qp1->div, qp2->div, exp1, exp2); + if (!div) + goto error; + + isl_mat_free(qp1->div); + qp1->div = isl_mat_copy(div); + isl_mat_free(qp2->div); + qp2->div = isl_mat_copy(div); + + qp1->upoly = expand(qp1->upoly, exp1, div->n_col - div->n_row - 2); + qp2->upoly = expand(qp2->upoly, exp2, div->n_col - div->n_row - 2); + + if (!qp1->upoly || !qp2->upoly) + goto error; + + isl_mat_free(div); + free(exp1); + free(exp2); + + return fn(qp1, qp2); +error: + isl_mat_free(div); + free(exp1); + free(exp2); + isl_qpolynomial_free(qp1); + isl_qpolynomial_free(qp2); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_add(__isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2) +{ + isl_bool compatible; + + qp1 = isl_qpolynomial_cow(qp1); + + if (!qp1 || !qp2) + goto error; + + if (qp1->div->n_row < qp2->div->n_row) + return isl_qpolynomial_add(qp2, qp1); + + isl_assert(qp1->dim->ctx, isl_space_is_equal(qp1->dim, qp2->dim), goto error); + compatible = compatible_divs(qp1->div, qp2->div); + if (compatible < 0) + goto error; + if (!compatible) + return with_merged_divs(isl_qpolynomial_add, qp1, qp2); + + qp1->upoly = isl_upoly_sum(qp1->upoly, isl_upoly_copy(qp2->upoly)); + if (!qp1->upoly) + goto error; + + isl_qpolynomial_free(qp2); + + return qp1; +error: + isl_qpolynomial_free(qp1); + isl_qpolynomial_free(qp2); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_add_on_domain( + __isl_keep isl_set *dom, + __isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2) +{ + qp1 = isl_qpolynomial_add(qp1, qp2); + qp1 = isl_qpolynomial_gist(qp1, isl_set_copy(dom)); + return qp1; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_sub(__isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2) +{ + return isl_qpolynomial_add(qp1, isl_qpolynomial_neg(qp2)); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_add_isl_int( + __isl_take isl_qpolynomial *qp, isl_int v) +{ + if (isl_int_is_zero(v)) + return qp; + + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + + qp->upoly = isl_upoly_add_isl_int(qp->upoly, v); + if (!qp->upoly) + goto error; + + return qp; +error: + isl_qpolynomial_free(qp); + return NULL; + +} + +__isl_give isl_qpolynomial *isl_qpolynomial_neg(__isl_take isl_qpolynomial *qp) +{ + if (!qp) + return NULL; + + return isl_qpolynomial_mul_isl_int(qp, qp->dim->ctx->negone); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_mul_isl_int( + __isl_take isl_qpolynomial *qp, isl_int v) +{ + if (isl_int_is_one(v)) + return qp; + + if (qp && isl_int_is_zero(v)) { + isl_qpolynomial *zero; + zero = isl_qpolynomial_zero_on_domain(isl_space_copy(qp->dim)); + isl_qpolynomial_free(qp); + return zero; + } + + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + + qp->upoly = isl_upoly_mul_isl_int(qp->upoly, v); + if (!qp->upoly) + goto error; + + return qp; +error: + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_scale( + __isl_take isl_qpolynomial *qp, isl_int v) +{ + return isl_qpolynomial_mul_isl_int(qp, v); +} + +/* Multiply "qp" by "v". + */ +__isl_give isl_qpolynomial *isl_qpolynomial_scale_val( + __isl_take isl_qpolynomial *qp, __isl_take isl_val *v) +{ + if (!qp || !v) + goto error; + + if (!isl_val_is_rat(v)) + isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid, + "expecting rational factor", goto error); + + if (isl_val_is_one(v)) { + isl_val_free(v); + return qp; + } + + if (isl_val_is_zero(v)) { + isl_space *space; + + space = isl_qpolynomial_get_domain_space(qp); + isl_qpolynomial_free(qp); + isl_val_free(v); + return isl_qpolynomial_zero_on_domain(space); + } + + qp = isl_qpolynomial_cow(qp); + if (!qp) + goto error; + + qp->upoly = isl_upoly_scale_val(qp->upoly, v); + if (!qp->upoly) + qp = isl_qpolynomial_free(qp); + + isl_val_free(v); + return qp; +error: + isl_val_free(v); + isl_qpolynomial_free(qp); + return NULL; +} + +/* Divide "qp" by "v". + */ +__isl_give isl_qpolynomial *isl_qpolynomial_scale_down_val( + __isl_take isl_qpolynomial *qp, __isl_take isl_val *v) +{ + if (!qp || !v) + goto error; + + if (!isl_val_is_rat(v)) + isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid, + "expecting rational factor", goto error); + if (isl_val_is_zero(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "cannot scale down by zero", goto error); + + return isl_qpolynomial_scale_val(qp, isl_val_inv(v)); +error: + isl_val_free(v); + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_mul(__isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2) +{ + isl_bool compatible; + + qp1 = isl_qpolynomial_cow(qp1); + + if (!qp1 || !qp2) + goto error; + + if (qp1->div->n_row < qp2->div->n_row) + return isl_qpolynomial_mul(qp2, qp1); + + isl_assert(qp1->dim->ctx, isl_space_is_equal(qp1->dim, qp2->dim), goto error); + compatible = compatible_divs(qp1->div, qp2->div); + if (compatible < 0) + goto error; + if (!compatible) + return with_merged_divs(isl_qpolynomial_mul, qp1, qp2); + + qp1->upoly = isl_upoly_mul(qp1->upoly, isl_upoly_copy(qp2->upoly)); + if (!qp1->upoly) + goto error; + + isl_qpolynomial_free(qp2); + + return qp1; +error: + isl_qpolynomial_free(qp1); + isl_qpolynomial_free(qp2); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_pow(__isl_take isl_qpolynomial *qp, + unsigned power) +{ + qp = isl_qpolynomial_cow(qp); + + if (!qp) + return NULL; + + qp->upoly = isl_upoly_pow(qp->upoly, power); + if (!qp->upoly) + goto error; + + return qp; +error: + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_pow( + __isl_take isl_pw_qpolynomial *pwqp, unsigned power) +{ + int i; + + if (power == 1) + return pwqp; + + pwqp = isl_pw_qpolynomial_cow(pwqp); + if (!pwqp) + return NULL; + + for (i = 0; i < pwqp->n; ++i) { + pwqp->p[i].qp = isl_qpolynomial_pow(pwqp->p[i].qp, power); + if (!pwqp->p[i].qp) + return isl_pw_qpolynomial_free(pwqp); + } + + return pwqp; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_zero_on_domain( + __isl_take isl_space *dim) +{ + if (!dim) + return NULL; + return isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx)); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_one_on_domain( + __isl_take isl_space *dim) +{ + if (!dim) + return NULL; + return isl_qpolynomial_alloc(dim, 0, isl_upoly_one(dim->ctx)); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_infty_on_domain( + __isl_take isl_space *dim) +{ + if (!dim) + return NULL; + return isl_qpolynomial_alloc(dim, 0, isl_upoly_infty(dim->ctx)); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_neginfty_on_domain( + __isl_take isl_space *dim) +{ + if (!dim) + return NULL; + return isl_qpolynomial_alloc(dim, 0, isl_upoly_neginfty(dim->ctx)); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_nan_on_domain( + __isl_take isl_space *dim) +{ + if (!dim) + return NULL; + return isl_qpolynomial_alloc(dim, 0, isl_upoly_nan(dim->ctx)); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_cst_on_domain( + __isl_take isl_space *dim, + isl_int v) +{ + struct isl_qpolynomial *qp; + struct isl_upoly_cst *cst; + + if (!dim) + return NULL; + + qp = isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx)); + if (!qp) + return NULL; + + cst = isl_upoly_as_cst(qp->upoly); + isl_int_set(cst->n, v); + + return qp; +} + +int isl_qpolynomial_is_cst(__isl_keep isl_qpolynomial *qp, + isl_int *n, isl_int *d) +{ + struct isl_upoly_cst *cst; + + if (!qp) + return -1; + + if (!isl_upoly_is_cst(qp->upoly)) + return 0; + + cst = isl_upoly_as_cst(qp->upoly); + if (!cst) + return -1; + + if (n) + isl_int_set(*n, cst->n); + if (d) + isl_int_set(*d, cst->d); + + return 1; +} + +/* Return the constant term of "up". + */ +static __isl_give isl_val *isl_upoly_get_constant_val( + __isl_keep struct isl_upoly *up) +{ + struct isl_upoly_cst *cst; + + if (!up) + return NULL; + + while (!isl_upoly_is_cst(up)) { + struct isl_upoly_rec *rec; + + rec = isl_upoly_as_rec(up); + if (!rec) + return NULL; + up = rec->p[0]; + } + + cst = isl_upoly_as_cst(up); + if (!cst) + return NULL; + return isl_val_rat_from_isl_int(cst->up.ctx, cst->n, cst->d); +} + +/* Return the constant term of "qp". + */ +__isl_give isl_val *isl_qpolynomial_get_constant_val( + __isl_keep isl_qpolynomial *qp) +{ + if (!qp) + return NULL; + + return isl_upoly_get_constant_val(qp->upoly); +} + +int isl_upoly_is_affine(__isl_keep struct isl_upoly *up) +{ + int is_cst; + struct isl_upoly_rec *rec; + + if (!up) + return -1; + + if (up->var < 0) + return 1; + + rec = isl_upoly_as_rec(up); + if (!rec) + return -1; + + if (rec->n > 2) + return 0; + + isl_assert(up->ctx, rec->n > 1, return -1); + + is_cst = isl_upoly_is_cst(rec->p[1]); + if (is_cst < 0) + return -1; + if (!is_cst) + return 0; + + return isl_upoly_is_affine(rec->p[0]); +} + +int isl_qpolynomial_is_affine(__isl_keep isl_qpolynomial *qp) +{ + if (!qp) + return -1; + + if (qp->div->n_row > 0) + return 0; + + return isl_upoly_is_affine(qp->upoly); +} + +static void update_coeff(__isl_keep isl_vec *aff, + __isl_keep struct isl_upoly_cst *cst, int pos) +{ + isl_int gcd; + isl_int f; + + if (isl_int_is_zero(cst->n)) + return; + + isl_int_init(gcd); + isl_int_init(f); + isl_int_gcd(gcd, cst->d, aff->el[0]); + isl_int_divexact(f, cst->d, gcd); + isl_int_divexact(gcd, aff->el[0], gcd); + isl_seq_scale(aff->el, aff->el, f, aff->size); + isl_int_mul(aff->el[1 + pos], gcd, cst->n); + isl_int_clear(gcd); + isl_int_clear(f); +} + +int isl_upoly_update_affine(__isl_keep struct isl_upoly *up, + __isl_keep isl_vec *aff) +{ + struct isl_upoly_cst *cst; + struct isl_upoly_rec *rec; + + if (!up || !aff) + return -1; + + if (up->var < 0) { + struct isl_upoly_cst *cst; + + cst = isl_upoly_as_cst(up); + if (!cst) + return -1; + update_coeff(aff, cst, 0); + return 0; + } + + rec = isl_upoly_as_rec(up); + if (!rec) + return -1; + isl_assert(up->ctx, rec->n == 2, return -1); + + cst = isl_upoly_as_cst(rec->p[1]); + if (!cst) + return -1; + update_coeff(aff, cst, 1 + up->var); + + return isl_upoly_update_affine(rec->p[0], aff); +} + +__isl_give isl_vec *isl_qpolynomial_extract_affine( + __isl_keep isl_qpolynomial *qp) +{ + isl_vec *aff; + unsigned d; + + if (!qp) + return NULL; + + d = isl_space_dim(qp->dim, isl_dim_all); + aff = isl_vec_alloc(qp->div->ctx, 2 + d + qp->div->n_row); + if (!aff) + return NULL; + + isl_seq_clr(aff->el + 1, 1 + d + qp->div->n_row); + isl_int_set_si(aff->el[0], 1); + + if (isl_upoly_update_affine(qp->upoly, aff) < 0) + goto error; + + return aff; +error: + isl_vec_free(aff); + return NULL; +} + +/* Compare two quasi-polynomials. + * + * Return -1 if "qp1" is "smaller" than "qp2", 1 if "qp1" is "greater" + * than "qp2" and 0 if they are equal. + */ +int isl_qpolynomial_plain_cmp(__isl_keep isl_qpolynomial *qp1, + __isl_keep isl_qpolynomial *qp2) +{ + int cmp; + + if (qp1 == qp2) + return 0; + if (!qp1) + return -1; + if (!qp2) + return 1; + + cmp = isl_space_cmp(qp1->dim, qp2->dim); + if (cmp != 0) + return cmp; + + cmp = isl_local_cmp(qp1->div, qp2->div); + if (cmp != 0) + return cmp; + + return isl_upoly_plain_cmp(qp1->upoly, qp2->upoly); +} + +/* Is "qp1" obviously equal to "qp2"? + * + * NaN is not equal to anything, not even to another NaN. + */ +isl_bool isl_qpolynomial_plain_is_equal(__isl_keep isl_qpolynomial *qp1, + __isl_keep isl_qpolynomial *qp2) +{ + isl_bool equal; + + if (!qp1 || !qp2) + return isl_bool_error; + + if (isl_qpolynomial_is_nan(qp1) || isl_qpolynomial_is_nan(qp2)) + return isl_bool_false; + + equal = isl_space_is_equal(qp1->dim, qp2->dim); + if (equal < 0 || !equal) + return equal; + + equal = isl_mat_is_equal(qp1->div, qp2->div); + if (equal < 0 || !equal) + return equal; + + return isl_upoly_is_equal(qp1->upoly, qp2->upoly); +} + +static void upoly_update_den(__isl_keep struct isl_upoly *up, isl_int *d) +{ + int i; + struct isl_upoly_rec *rec; + + if (isl_upoly_is_cst(up)) { + struct isl_upoly_cst *cst; + cst = isl_upoly_as_cst(up); + if (!cst) + return; + isl_int_lcm(*d, *d, cst->d); + return; + } + + rec = isl_upoly_as_rec(up); + if (!rec) + return; + + for (i = 0; i < rec->n; ++i) + upoly_update_den(rec->p[i], d); +} + +void isl_qpolynomial_get_den(__isl_keep isl_qpolynomial *qp, isl_int *d) +{ + isl_int_set_si(*d, 1); + if (!qp) + return; + upoly_update_den(qp->upoly, d); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_var_pow_on_domain( + __isl_take isl_space *dim, int pos, int power) +{ + struct isl_ctx *ctx; + + if (!dim) + return NULL; + + ctx = dim->ctx; + + return isl_qpolynomial_alloc(dim, 0, isl_upoly_var_pow(ctx, pos, power)); +} + +__isl_give isl_qpolynomial *isl_qpolynomial_var_on_domain(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned pos) +{ + if (!dim) + return NULL; + + isl_assert(dim->ctx, isl_space_dim(dim, isl_dim_in) == 0, goto error); + isl_assert(dim->ctx, pos < isl_space_dim(dim, type), goto error); + + if (type == isl_dim_set) + pos += isl_space_dim(dim, isl_dim_param); + + return isl_qpolynomial_var_pow_on_domain(dim, pos, 1); +error: + isl_space_free(dim); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_subs(__isl_take struct isl_upoly *up, + unsigned first, unsigned n, __isl_keep struct isl_upoly **subs) +{ + int i; + struct isl_upoly_rec *rec; + struct isl_upoly *base, *res; + + if (!up) + return NULL; + + if (isl_upoly_is_cst(up)) + return up; + + if (up->var < first) + return up; + + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + isl_assert(up->ctx, rec->n >= 1, goto error); + + if (up->var >= first + n) + base = isl_upoly_var_pow(up->ctx, up->var, 1); + else + base = isl_upoly_copy(subs[up->var - first]); + + res = isl_upoly_subs(isl_upoly_copy(rec->p[rec->n - 1]), first, n, subs); + for (i = rec->n - 2; i >= 0; --i) { + struct isl_upoly *t; + t = isl_upoly_subs(isl_upoly_copy(rec->p[i]), first, n, subs); + res = isl_upoly_mul(res, isl_upoly_copy(base)); + res = isl_upoly_sum(res, t); + } + + isl_upoly_free(base); + isl_upoly_free(up); + + return res; +error: + isl_upoly_free(up); + return NULL; +} + +__isl_give struct isl_upoly *isl_upoly_from_affine(isl_ctx *ctx, isl_int *f, + isl_int denom, unsigned len) +{ + int i; + struct isl_upoly *up; + + isl_assert(ctx, len >= 1, return NULL); + + up = isl_upoly_rat_cst(ctx, f[0], denom); + for (i = 0; i < len - 1; ++i) { + struct isl_upoly *t; + struct isl_upoly *c; + + if (isl_int_is_zero(f[1 + i])) + continue; + + c = isl_upoly_rat_cst(ctx, f[1 + i], denom); + t = isl_upoly_var_pow(ctx, i, 1); + t = isl_upoly_mul(c, t); + up = isl_upoly_sum(up, t); + } + + return up; +} + +/* Remove common factor of non-constant terms and denominator. + */ +static void normalize_div(__isl_keep isl_qpolynomial *qp, int div) +{ + isl_ctx *ctx = qp->div->ctx; + unsigned total = qp->div->n_col - 2; + + isl_seq_gcd(qp->div->row[div] + 2, total, &ctx->normalize_gcd); + isl_int_gcd(ctx->normalize_gcd, + ctx->normalize_gcd, qp->div->row[div][0]); + if (isl_int_is_one(ctx->normalize_gcd)) + return; + + isl_seq_scale_down(qp->div->row[div] + 2, qp->div->row[div] + 2, + ctx->normalize_gcd, total); + isl_int_divexact(qp->div->row[div][0], qp->div->row[div][0], + ctx->normalize_gcd); + isl_int_fdiv_q(qp->div->row[div][1], qp->div->row[div][1], + ctx->normalize_gcd); +} + +/* Replace the integer division identified by "div" by the polynomial "s". + * The integer division is assumed not to appear in the definition + * of any other integer divisions. + */ +static __isl_give isl_qpolynomial *substitute_div( + __isl_take isl_qpolynomial *qp, + int div, __isl_take struct isl_upoly *s) +{ + int i; + int total; + int *reordering; + + if (!qp || !s) + goto error; + + qp = isl_qpolynomial_cow(qp); + if (!qp) + goto error; + + total = isl_space_dim(qp->dim, isl_dim_all); + qp->upoly = isl_upoly_subs(qp->upoly, total + div, 1, &s); + if (!qp->upoly) + goto error; + + reordering = isl_alloc_array(qp->dim->ctx, int, total + qp->div->n_row); + if (!reordering) + goto error; + for (i = 0; i < total + div; ++i) + reordering[i] = i; + for (i = total + div + 1; i < total + qp->div->n_row; ++i) + reordering[i] = i - 1; + qp->div = isl_mat_drop_rows(qp->div, div, 1); + qp->div = isl_mat_drop_cols(qp->div, 2 + total + div, 1); + qp->upoly = reorder(qp->upoly, reordering); + free(reordering); + + if (!qp->upoly || !qp->div) + goto error; + + isl_upoly_free(s); + return qp; +error: + isl_qpolynomial_free(qp); + isl_upoly_free(s); + return NULL; +} + +/* Replace all integer divisions [e/d] that turn out to not actually be integer + * divisions because d is equal to 1 by their definition, i.e., e. + */ +static __isl_give isl_qpolynomial *substitute_non_divs( + __isl_take isl_qpolynomial *qp) +{ + int i, j; + int total; + struct isl_upoly *s; + + if (!qp) + return NULL; + + total = isl_space_dim(qp->dim, isl_dim_all); + for (i = 0; qp && i < qp->div->n_row; ++i) { + if (!isl_int_is_one(qp->div->row[i][0])) + continue; + for (j = i + 1; j < qp->div->n_row; ++j) { + if (isl_int_is_zero(qp->div->row[j][2 + total + i])) + continue; + isl_seq_combine(qp->div->row[j] + 1, + qp->div->ctx->one, qp->div->row[j] + 1, + qp->div->row[j][2 + total + i], + qp->div->row[i] + 1, 1 + total + i); + isl_int_set_si(qp->div->row[j][2 + total + i], 0); + normalize_div(qp, j); + } + s = isl_upoly_from_affine(qp->dim->ctx, qp->div->row[i] + 1, + qp->div->row[i][0], qp->div->n_col - 1); + qp = substitute_div(qp, i, s); + --i; + } + + return qp; +} + +/* Reduce the coefficients of div "div" to lie in the interval [0, d-1], + * with d the denominator. When replacing the coefficient e of x by + * d * frac(e/d) = e - d * floor(e/d), we are subtracting d * floor(e/d) * x + * inside the division, so we need to add floor(e/d) * x outside. + * That is, we replace q by q' + floor(e/d) * x and we therefore need + * to adjust the coefficient of x in each later div that depends on the + * current div "div" and also in the affine expressions in the rows of "mat" + * (if they too depend on "div"). + */ +static void reduce_div(__isl_keep isl_qpolynomial *qp, int div, + __isl_keep isl_mat **mat) +{ + int i, j; + isl_int v; + unsigned total = qp->div->n_col - qp->div->n_row - 2; + + isl_int_init(v); + for (i = 0; i < 1 + total + div; ++i) { + if (isl_int_is_nonneg(qp->div->row[div][1 + i]) && + isl_int_lt(qp->div->row[div][1 + i], qp->div->row[div][0])) + continue; + isl_int_fdiv_q(v, qp->div->row[div][1 + i], qp->div->row[div][0]); + isl_int_fdiv_r(qp->div->row[div][1 + i], + qp->div->row[div][1 + i], qp->div->row[div][0]); + *mat = isl_mat_col_addmul(*mat, i, v, 1 + total + div); + for (j = div + 1; j < qp->div->n_row; ++j) { + if (isl_int_is_zero(qp->div->row[j][2 + total + div])) + continue; + isl_int_addmul(qp->div->row[j][1 + i], + v, qp->div->row[j][2 + total + div]); + } + } + isl_int_clear(v); +} + +/* Check if the last non-zero coefficient is bigger that half of the + * denominator. If so, we will invert the div to further reduce the number + * of distinct divs that may appear. + * If the last non-zero coefficient is exactly half the denominator, + * then we continue looking for earlier coefficients that are bigger + * than half the denominator. + */ +static int needs_invert(__isl_keep isl_mat *div, int row) +{ + int i; + int cmp; + + for (i = div->n_col - 1; i >= 1; --i) { + if (isl_int_is_zero(div->row[row][i])) + continue; + isl_int_mul_ui(div->row[row][i], div->row[row][i], 2); + cmp = isl_int_cmp(div->row[row][i], div->row[row][0]); + isl_int_divexact_ui(div->row[row][i], div->row[row][i], 2); + if (cmp) + return cmp > 0; + if (i == 1) + return 1; + } + + return 0; +} + +/* Replace div "div" q = [e/d] by -[(-e+(d-1))/d]. + * We only invert the coefficients of e (and the coefficient of q in + * later divs and in the rows of "mat"). After calling this function, the + * coefficients of e should be reduced again. + */ +static void invert_div(__isl_keep isl_qpolynomial *qp, int div, + __isl_keep isl_mat **mat) +{ + unsigned total = qp->div->n_col - qp->div->n_row - 2; + + isl_seq_neg(qp->div->row[div] + 1, + qp->div->row[div] + 1, qp->div->n_col - 1); + isl_int_sub_ui(qp->div->row[div][1], qp->div->row[div][1], 1); + isl_int_add(qp->div->row[div][1], + qp->div->row[div][1], qp->div->row[div][0]); + *mat = isl_mat_col_neg(*mat, 1 + total + div); + isl_mat_col_mul(qp->div, 2 + total + div, + qp->div->ctx->negone, 2 + total + div); +} + +/* Reduce all divs of "qp" to have coefficients + * in the interval [0, d-1], with d the denominator and such that the + * last non-zero coefficient that is not equal to d/2 is smaller than d/2. + * The modifications to the integer divisions need to be reflected + * in the factors of the polynomial that refer to the original + * integer divisions. To this end, the modifications are collected + * as a set of affine expressions and then plugged into the polynomial. + * + * 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 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. + */ +static __isl_give isl_qpolynomial *reduce_divs(__isl_take isl_qpolynomial *qp) +{ + int i; + isl_ctx *ctx; + isl_mat *mat; + struct isl_upoly **s; + unsigned o_div, n_div, total; + + if (!qp) + return NULL; + + total = isl_qpolynomial_domain_dim(qp, isl_dim_all); + n_div = isl_qpolynomial_domain_dim(qp, isl_dim_div); + o_div = isl_qpolynomial_domain_offset(qp, isl_dim_div); + ctx = isl_qpolynomial_get_ctx(qp); + mat = isl_mat_zero(ctx, n_div, 1 + total); + + for (i = 0; i < n_div; ++i) + mat = isl_mat_set_element_si(mat, i, o_div + i, 1); + + for (i = 0; i < qp->div->n_row; ++i) { + normalize_div(qp, i); + reduce_div(qp, i, &mat); + if (needs_invert(qp->div, i)) { + invert_div(qp, i, &mat); + reduce_div(qp, i, &mat); + } + } + if (!mat) + goto error; + + s = isl_alloc_array(ctx, struct isl_upoly *, n_div); + if (n_div && !s) + goto error; + for (i = 0; i < n_div; ++i) + s[i] = isl_upoly_from_affine(ctx, mat->row[i], ctx->one, + 1 + total); + qp->upoly = isl_upoly_subs(qp->upoly, o_div - 1, n_div, s); + for (i = 0; i < n_div; ++i) + isl_upoly_free(s[i]); + free(s); + if (!qp->upoly) + goto error; + + isl_mat_free(mat); + + qp = substitute_non_divs(qp); + qp = sort_divs(qp); + if (qp && isl_qpolynomial_domain_dim(qp, isl_dim_div) < n_div) + return reduce_divs(qp); + + return qp; +error: + isl_qpolynomial_free(qp); + isl_mat_free(mat); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_rat_cst_on_domain( + __isl_take isl_space *dim, const isl_int n, const isl_int d) +{ + struct isl_qpolynomial *qp; + struct isl_upoly_cst *cst; + + if (!dim) + return NULL; + + qp = isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx)); + if (!qp) + return NULL; + + cst = isl_upoly_as_cst(qp->upoly); + isl_int_set(cst->n, n); + isl_int_set(cst->d, d); + + return qp; +} + +/* Return an isl_qpolynomial that is equal to "val" on domain space "domain". + */ +__isl_give isl_qpolynomial *isl_qpolynomial_val_on_domain( + __isl_take isl_space *domain, __isl_take isl_val *val) +{ + isl_qpolynomial *qp; + struct isl_upoly_cst *cst; + + if (!domain || !val) + goto error; + + qp = isl_qpolynomial_alloc(isl_space_copy(domain), 0, + isl_upoly_zero(domain->ctx)); + if (!qp) + goto error; + + cst = isl_upoly_as_cst(qp->upoly); + isl_int_set(cst->n, val->n); + isl_int_set(cst->d, val->d); + + isl_space_free(domain); + isl_val_free(val); + return qp; +error: + isl_space_free(domain); + isl_val_free(val); + return NULL; +} + +static int up_set_active(__isl_keep struct isl_upoly *up, int *active, int d) +{ + struct isl_upoly_rec *rec; + int i; + + if (!up) + return -1; + + if (isl_upoly_is_cst(up)) + return 0; + + if (up->var < d) + active[up->var] = 1; + + rec = isl_upoly_as_rec(up); + for (i = 0; i < rec->n; ++i) + if (up_set_active(rec->p[i], active, d) < 0) + return -1; + + return 0; +} + +static int set_active(__isl_keep isl_qpolynomial *qp, int *active) +{ + int i, j; + int d = isl_space_dim(qp->dim, isl_dim_all); + + if (!qp || !active) + return -1; + + for (i = 0; i < d; ++i) + for (j = 0; j < qp->div->n_row; ++j) { + if (isl_int_is_zero(qp->div->row[j][2 + i])) + continue; + active[i] = 1; + break; + } + + return up_set_active(qp->upoly, active, d); +} + +isl_bool isl_qpolynomial_involves_dims(__isl_keep isl_qpolynomial *qp, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + int *active = NULL; + isl_bool involves = isl_bool_false; + + if (!qp) + return isl_bool_error; + if (n == 0) + return isl_bool_false; + + isl_assert(qp->dim->ctx, + first + n <= isl_qpolynomial_dim(qp, type), + return isl_bool_error); + isl_assert(qp->dim->ctx, type == isl_dim_param || + type == isl_dim_in, return isl_bool_error); + + active = isl_calloc_array(qp->dim->ctx, int, + isl_space_dim(qp->dim, isl_dim_all)); + if (set_active(qp, active) < 0) + goto error; + + if (type == isl_dim_in) + first += isl_space_dim(qp->dim, isl_dim_param); + for (i = 0; i < n; ++i) + if (active[first + i]) { + involves = isl_bool_true; + break; + } + + free(active); + + return involves; +error: + free(active); + return isl_bool_error; +} + +/* 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; + isl_ctx *ctx; + + if (!qp) + return NULL; + if (qp->div->n_row == 0) + return qp; + + d = isl_space_dim(qp->dim, isl_dim_all); + len = qp->div->n_col - 2; + ctx = isl_qpolynomial_get_ctx(qp); + active = isl_calloc_array(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) +{ + int i; + struct isl_upoly_rec *rec; + + if (!up) + return NULL; + if (n == 0 || up->var < 0 || up->var < first) + return up; + if (up->var < first + n) { + up = replace_by_constant_term(up); + return isl_upoly_drop(up, first, n); + } + up = isl_upoly_cow(up); + if (!up) + return NULL; + up->var -= n; + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + for (i = 0; i < rec->n; ++i) { + rec->p[i] = isl_upoly_drop(rec->p[i], first, n); + if (!rec->p[i]) + goto error; + } + + return up; +error: + isl_upoly_free(up); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_set_dim_name( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type type, unsigned pos, const char *s) +{ + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + if (type == isl_dim_out) + isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid, + "cannot set name of output/set dimension", + return isl_qpolynomial_free(qp)); + if (type == isl_dim_in) + type = isl_dim_set; + qp->dim = isl_space_set_dim_name(qp->dim, type, pos, s); + if (!qp->dim) + goto error; + return qp; +error: + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_drop_dims( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type type, unsigned first, unsigned n) +{ + if (!qp) + return NULL; + if (type == isl_dim_out) + isl_die(qp->dim->ctx, isl_error_invalid, + "cannot drop output/set dimension", + goto error); + if (type == isl_dim_in) + type = isl_dim_set; + if (n == 0 && !isl_space_is_named_or_nested(qp->dim, type)) + return qp; + + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + + isl_assert(qp->dim->ctx, first + n <= isl_space_dim(qp->dim, type), + goto error); + isl_assert(qp->dim->ctx, type == isl_dim_param || + type == isl_dim_set, goto error); + + qp->dim = isl_space_drop_dims(qp->dim, type, first, n); + if (!qp->dim) + goto error; + + if (type == isl_dim_set) + first += isl_space_dim(qp->dim, isl_dim_param); + + qp->div = isl_mat_drop_cols(qp->div, 2 + first, n); + if (!qp->div) + goto error; + + qp->upoly = isl_upoly_drop(qp->upoly, first, n); + if (!qp->upoly) + goto error; + + return qp; +error: + isl_qpolynomial_free(qp); + return NULL; +} + +/* Project the domain of the quasi-polynomial onto its parameter space. + * The quasi-polynomial may not involve any of the domain dimensions. + */ +__isl_give isl_qpolynomial *isl_qpolynomial_project_domain_on_params( + __isl_take isl_qpolynomial *qp) +{ + isl_space *space; + unsigned n; + int involves; + + n = isl_qpolynomial_dim(qp, isl_dim_in); + involves = isl_qpolynomial_involves_dims(qp, isl_dim_in, 0, n); + if (involves < 0) + return isl_qpolynomial_free(qp); + if (involves) + isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid, + "polynomial involves some of the domain dimensions", + return isl_qpolynomial_free(qp)); + qp = isl_qpolynomial_drop_dims(qp, isl_dim_in, 0, n); + space = isl_qpolynomial_get_domain_space(qp); + space = isl_space_params(space); + qp = isl_qpolynomial_reset_domain_space(qp, space); + return qp; +} + +static __isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities_lifted( + __isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq) +{ + int i, j, k; + isl_int denom; + unsigned total; + unsigned n_div; + struct isl_upoly *up; + + if (!eq) + goto error; + if (eq->n_eq == 0) { + isl_basic_set_free(eq); + return qp; + } + + qp = isl_qpolynomial_cow(qp); + if (!qp) + goto error; + qp->div = isl_mat_cow(qp->div); + if (!qp->div) + goto error; + + total = 1 + isl_space_dim(eq->dim, isl_dim_all); + n_div = eq->n_div; + isl_int_init(denom); + for (i = 0; i < eq->n_eq; ++i) { + j = isl_seq_last_non_zero(eq->eq[i], total + n_div); + if (j < 0 || j == 0 || j >= total) + continue; + + for (k = 0; k < qp->div->n_row; ++k) { + if (isl_int_is_zero(qp->div->row[k][1 + j])) + continue; + isl_seq_elim(qp->div->row[k] + 1, eq->eq[i], j, total, + &qp->div->row[k][0]); + normalize_div(qp, k); + } + + if (isl_int_is_pos(eq->eq[i][j])) + isl_seq_neg(eq->eq[i], eq->eq[i], total); + isl_int_abs(denom, eq->eq[i][j]); + isl_int_set_si(eq->eq[i][j], 0); + + up = isl_upoly_from_affine(qp->dim->ctx, + eq->eq[i], denom, total); + qp->upoly = isl_upoly_subs(qp->upoly, j - 1, 1, &up); + isl_upoly_free(up); + } + isl_int_clear(denom); + + if (!qp->upoly) + goto error; + + isl_basic_set_free(eq); + + qp = substitute_non_divs(qp); + qp = sort_divs(qp); + + return qp; +error: + isl_basic_set_free(eq); + isl_qpolynomial_free(qp); + return NULL; +} + +/* Exploit the equalities in "eq" to simplify the quasi-polynomial. + */ +__isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities( + __isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq) +{ + if (!qp || !eq) + goto error; + if (qp->div->n_row > 0) + eq = isl_basic_set_add_dims(eq, isl_dim_set, qp->div->n_row); + return isl_qpolynomial_substitute_equalities_lifted(qp, eq); +error: + isl_basic_set_free(eq); + isl_qpolynomial_free(qp); + return NULL; +} + +static __isl_give isl_basic_set *add_div_constraints( + __isl_take isl_basic_set *bset, __isl_take isl_mat *div) +{ + int i; + unsigned total; + + if (!bset || !div) + goto error; + + bset = isl_basic_set_extend_constraints(bset, 0, 2 * div->n_row); + if (!bset) + goto error; + total = isl_basic_set_total_dim(bset); + for (i = 0; i < div->n_row; ++i) + if (isl_basic_set_add_div_constraints_var(bset, + total - div->n_row + i, div->row[i]) < 0) + goto error; + + isl_mat_free(div); + return bset; +error: + isl_mat_free(div); + isl_basic_set_free(bset); + return NULL; +} + +/* Look for equalities among the variables shared by context and qp + * and the integer divisions of qp, if any. + * The equalities are then used to eliminate variables and/or integer + * divisions from qp. + */ +__isl_give isl_qpolynomial *isl_qpolynomial_gist( + __isl_take isl_qpolynomial *qp, __isl_take isl_set *context) +{ + isl_basic_set *aff; + + if (!qp) + goto error; + if (qp->div->n_row > 0) { + isl_basic_set *bset; + context = isl_set_add_dims(context, isl_dim_set, + qp->div->n_row); + bset = isl_basic_set_universe(isl_set_get_space(context)); + bset = add_div_constraints(bset, isl_mat_copy(qp->div)); + context = isl_set_intersect(context, + isl_set_from_basic_set(bset)); + } + + aff = isl_set_affine_hull(context); + return isl_qpolynomial_substitute_equalities_lifted(qp, aff); +error: + isl_qpolynomial_free(qp); + isl_set_free(context); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_gist_params( + __isl_take isl_qpolynomial *qp, __isl_take isl_set *context) +{ + isl_space *space = isl_qpolynomial_get_domain_space(qp); + isl_set *dom_context = isl_set_universe(space); + dom_context = isl_set_intersect_params(dom_context, context); + return isl_qpolynomial_gist(qp, dom_context); +} + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_qpolynomial( + __isl_take isl_qpolynomial *qp) +{ + isl_set *dom; + + if (!qp) + return NULL; + if (isl_qpolynomial_is_zero(qp)) { + isl_space *dim = isl_qpolynomial_get_space(qp); + isl_qpolynomial_free(qp); + return isl_pw_qpolynomial_zero(dim); + } + + dom = isl_set_universe(isl_qpolynomial_get_domain_space(qp)); + return isl_pw_qpolynomial_alloc(dom, qp); +} + +#define isl_qpolynomial_involves_nan isl_qpolynomial_is_nan + +#undef PW +#define PW isl_pw_qpolynomial +#undef EL +#define EL isl_qpolynomial +#undef EL_IS_ZERO +#define EL_IS_ZERO is_zero +#undef ZERO +#define ZERO zero +#undef IS_ZERO +#define IS_ZERO is_zero +#undef FIELD +#define FIELD qp +#undef DEFAULT_IS_ZERO +#define DEFAULT_IS_ZERO 1 + +#define NO_PULLBACK + +#include + +#undef UNION +#define UNION isl_union_pw_qpolynomial +#undef PART +#define PART isl_pw_qpolynomial +#undef PARTS +#define PARTS pw_qpolynomial + +#include +#include +#include + +int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp) +{ + if (!pwqp) + return -1; + + if (pwqp->n != -1) + return 0; + + if (!isl_set_plain_is_universe(pwqp->p[0].set)) + return 0; + + return isl_qpolynomial_is_one(pwqp->p[0].qp); +} + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2) +{ + return isl_pw_qpolynomial_union_add_(pwqp1, pwqp2); +} + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul( + __isl_take isl_pw_qpolynomial *pwqp1, + __isl_take isl_pw_qpolynomial *pwqp2) +{ + int i, j, n; + struct isl_pw_qpolynomial *res; + + if (!pwqp1 || !pwqp2) + goto error; + + isl_assert(pwqp1->dim->ctx, isl_space_is_equal(pwqp1->dim, pwqp2->dim), + goto error); + + if (isl_pw_qpolynomial_is_zero(pwqp1)) { + isl_pw_qpolynomial_free(pwqp2); + return pwqp1; + } + + if (isl_pw_qpolynomial_is_zero(pwqp2)) { + isl_pw_qpolynomial_free(pwqp1); + return pwqp2; + } + + if (isl_pw_qpolynomial_is_one(pwqp1)) { + isl_pw_qpolynomial_free(pwqp1); + return pwqp2; + } + + if (isl_pw_qpolynomial_is_one(pwqp2)) { + isl_pw_qpolynomial_free(pwqp2); + return pwqp1; + } + + n = pwqp1->n * pwqp2->n; + res = isl_pw_qpolynomial_alloc_size(isl_space_copy(pwqp1->dim), n); + + for (i = 0; i < pwqp1->n; ++i) { + for (j = 0; j < pwqp2->n; ++j) { + struct isl_set *common; + 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_plain_is_empty(common)) { + isl_set_free(common); + continue; + } + + prod = isl_qpolynomial_mul( + isl_qpolynomial_copy(pwqp1->p[i].qp), + isl_qpolynomial_copy(pwqp2->p[j].qp)); + + res = isl_pw_qpolynomial_add_piece(res, common, prod); + } + } + + isl_pw_qpolynomial_free(pwqp1); + isl_pw_qpolynomial_free(pwqp2); + + return res; +error: + isl_pw_qpolynomial_free(pwqp1); + isl_pw_qpolynomial_free(pwqp2); + return NULL; +} + +__isl_give isl_val *isl_upoly_eval(__isl_take struct isl_upoly *up, + __isl_take isl_vec *vec) +{ + int i; + struct isl_upoly_rec *rec; + isl_val *res; + isl_val *base; + + if (isl_upoly_is_cst(up)) { + isl_vec_free(vec); + res = isl_upoly_get_constant_val(up); + isl_upoly_free(up); + return res; + } + + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + isl_assert(up->ctx, rec->n >= 1, goto error); + + base = isl_val_rat_from_isl_int(up->ctx, + vec->el[1 + up->var], vec->el[0]); + + res = isl_upoly_eval(isl_upoly_copy(rec->p[rec->n - 1]), + isl_vec_copy(vec)); + + for (i = rec->n - 2; i >= 0; --i) { + res = isl_val_mul(res, isl_val_copy(base)); + res = isl_val_add(res, + isl_upoly_eval(isl_upoly_copy(rec->p[i]), + isl_vec_copy(vec))); + } + + isl_val_free(base); + isl_upoly_free(up); + isl_vec_free(vec); + return res; +error: + isl_upoly_free(up); + isl_vec_free(vec); + return NULL; +} + +/* Evaluate "qp" in the void point "pnt". + * In particular, return the value NaN. + */ +static __isl_give isl_val *eval_void(__isl_take isl_qpolynomial *qp, + __isl_take isl_point *pnt) +{ + isl_ctx *ctx; + + ctx = isl_point_get_ctx(pnt); + isl_qpolynomial_free(qp); + isl_point_free(pnt); + return isl_val_nan(ctx); +} + +__isl_give isl_val *isl_qpolynomial_eval(__isl_take isl_qpolynomial *qp, + __isl_take isl_point *pnt) +{ + isl_bool is_void; + isl_vec *ext; + isl_val *v; + + if (!qp || !pnt) + goto error; + isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, qp->dim), goto error); + is_void = isl_point_is_void(pnt); + if (is_void < 0) + goto error; + if (is_void) + return eval_void(qp, pnt); + + if (qp->div->n_row == 0) + ext = isl_vec_copy(pnt->vec); + else { + int i; + unsigned dim = isl_space_dim(qp->dim, isl_dim_all); + ext = isl_vec_alloc(qp->dim->ctx, 1 + dim + qp->div->n_row); + if (!ext) + goto error; + + isl_seq_cpy(ext->el, pnt->vec->el, pnt->vec->size); + for (i = 0; i < qp->div->n_row; ++i) { + isl_seq_inner_product(qp->div->row[i] + 1, ext->el, + 1 + dim + i, &ext->el[1+dim+i]); + isl_int_fdiv_q(ext->el[1+dim+i], ext->el[1+dim+i], + qp->div->row[i][0]); + } + } + + v = isl_upoly_eval(isl_upoly_copy(qp->upoly), ext); + + isl_qpolynomial_free(qp); + isl_point_free(pnt); + + return v; +error: + isl_qpolynomial_free(qp); + isl_point_free(pnt); + return NULL; +} + +int isl_upoly_cmp(__isl_keep struct isl_upoly_cst *cst1, + __isl_keep struct isl_upoly_cst *cst2) +{ + int cmp; + isl_int t; + isl_int_init(t); + isl_int_mul(t, cst1->n, cst2->d); + isl_int_submul(t, cst2->n, cst1->d); + cmp = isl_int_sgn(t); + isl_int_clear(t); + return cmp; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_insert_dims( + __isl_take isl_qpolynomial *qp, enum isl_dim_type type, + unsigned first, unsigned n) +{ + unsigned total; + unsigned g_pos; + int *exp; + + if (!qp) + return NULL; + if (type == isl_dim_out) + isl_die(qp->div->ctx, isl_error_invalid, + "cannot insert output/set dimensions", + goto error); + if (type == isl_dim_in) + type = isl_dim_set; + if (n == 0 && !isl_space_is_named_or_nested(qp->dim, type)) + return qp; + + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + + isl_assert(qp->div->ctx, first <= isl_space_dim(qp->dim, type), + goto error); + + g_pos = pos(qp->dim, type) + first; + + qp->div = isl_mat_insert_zero_cols(qp->div, 2 + g_pos, n); + if (!qp->div) + goto error; + + total = qp->div->n_col - 2; + if (total > g_pos) { + int i; + exp = isl_alloc_array(qp->div->ctx, int, total - g_pos); + if (!exp) + goto error; + for (i = 0; i < total - g_pos; ++i) + exp[i] = i + n; + qp->upoly = expand(qp->upoly, exp, g_pos); + free(exp); + if (!qp->upoly) + goto error; + } + + qp->dim = isl_space_insert_dims(qp->dim, type, first, n); + if (!qp->dim) + goto error; + + return qp; +error: + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_add_dims( + __isl_take isl_qpolynomial *qp, enum isl_dim_type type, unsigned n) +{ + unsigned pos; + + pos = isl_qpolynomial_dim(qp, type); + + return isl_qpolynomial_insert_dims(qp, type, pos, n); +} + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_dims( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned n) +{ + unsigned pos; + + pos = isl_pw_qpolynomial_dim(pwqp, type); + + return isl_pw_qpolynomial_insert_dims(pwqp, type, pos, n); +} + +static int *reordering_move(isl_ctx *ctx, + unsigned len, unsigned dst, unsigned src, unsigned n) +{ + int i; + int *reordering; + + reordering = isl_alloc_array(ctx, int, len); + if (!reordering) + return NULL; + + if (dst <= src) { + for (i = 0; i < dst; ++i) + reordering[i] = i; + for (i = 0; i < n; ++i) + reordering[src + i] = dst + i; + for (i = 0; i < src - dst; ++i) + reordering[dst + i] = dst + n + i; + for (i = 0; i < len - src - n; ++i) + reordering[src + n + i] = src + n + i; + } else { + for (i = 0; i < src; ++i) + reordering[i] = i; + for (i = 0; i < n; ++i) + reordering[src + i] = dst + i; + for (i = 0; i < dst - src; ++i) + reordering[src + n + i] = src + i; + for (i = 0; i < len - dst - n; ++i) + reordering[dst + n + i] = dst + n + i; + } + + return reordering; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_move_dims( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + unsigned g_dst_pos; + unsigned g_src_pos; + int *reordering; + + if (!qp) + return NULL; + + if (dst_type == isl_dim_out || src_type == isl_dim_out) + isl_die(qp->dim->ctx, isl_error_invalid, + "cannot move output/set dimension", + goto error); + if (dst_type == isl_dim_in) + dst_type = isl_dim_set; + if (src_type == isl_dim_in) + src_type = isl_dim_set; + + if (n == 0 && + !isl_space_is_named_or_nested(qp->dim, src_type) && + !isl_space_is_named_or_nested(qp->dim, dst_type)) + return qp; + + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + + isl_assert(qp->dim->ctx, src_pos + n <= isl_space_dim(qp->dim, src_type), + goto error); + + g_dst_pos = pos(qp->dim, dst_type) + dst_pos; + g_src_pos = pos(qp->dim, src_type) + src_pos; + if (dst_type > src_type) + g_dst_pos -= n; + + qp->div = isl_mat_move_cols(qp->div, 2 + g_dst_pos, 2 + g_src_pos, n); + if (!qp->div) + goto error; + qp = sort_divs(qp); + if (!qp) + goto error; + + reordering = reordering_move(qp->dim->ctx, + qp->div->n_col - 2, g_dst_pos, g_src_pos, n); + if (!reordering) + goto error; + + qp->upoly = reorder(qp->upoly, reordering); + free(reordering); + if (!qp->upoly) + goto error; + + qp->dim = isl_space_move_dims(qp->dim, dst_type, dst_pos, src_type, src_pos, n); + if (!qp->dim) + goto error; + + return qp; +error: + isl_qpolynomial_free(qp); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_from_affine(__isl_take isl_space *dim, + isl_int *f, isl_int denom) +{ + struct isl_upoly *up; + + dim = isl_space_domain(dim); + if (!dim) + return NULL; + + up = isl_upoly_from_affine(dim->ctx, f, denom, + 1 + isl_space_dim(dim, isl_dim_all)); + + 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_domain_space(aff), + aff->ls->div->n_row, up); + if (!qp) + goto error; + + isl_mat_free(qp->div); + qp->div = isl_mat_copy(aff->ls->div); + qp->div = isl_mat_cow(qp->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 isl_qpolynomial_free(qp); +} + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_pw_aff( + __isl_take isl_pw_aff *pwaff) +{ + int i; + isl_pw_qpolynomial *pwqp; + + if (!pwaff) + return NULL; + + pwqp = isl_pw_qpolynomial_alloc_size(isl_pw_aff_get_space(pwaff), + pwaff->n); + + for (i = 0; i < pwaff->n; ++i) { + isl_set *dom; + isl_qpolynomial *qp; + + dom = isl_set_copy(pwaff->p[i].set); + qp = isl_qpolynomial_from_aff(isl_aff_copy(pwaff->p[i].aff)); + pwqp = isl_pw_qpolynomial_add_piece(pwqp, dom, qp); + } + + isl_pw_aff_free(pwaff); + return pwqp; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_from_constraint( + __isl_take isl_constraint *c, enum isl_dim_type type, unsigned pos) +{ + isl_aff *aff; + + aff = isl_constraint_get_bound(c, type, pos); + isl_constraint_free(c); + return isl_qpolynomial_from_aff(aff); +} + +/* For each 0 <= i < "n", replace variable "first" + i of type "type" + * in "qp" by subs[i]. + */ +__isl_give isl_qpolynomial *isl_qpolynomial_substitute( + __isl_take isl_qpolynomial *qp, + enum isl_dim_type type, unsigned first, unsigned n, + __isl_keep isl_qpolynomial **subs) +{ + int i; + struct isl_upoly **ups; + + if (n == 0) + return qp; + + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + + if (type == isl_dim_out) + isl_die(qp->dim->ctx, isl_error_invalid, + "cannot substitute output/set dimension", + goto error); + if (type == isl_dim_in) + type = isl_dim_set; + + for (i = 0; i < n; ++i) + if (!subs[i]) + goto error; + + isl_assert(qp->dim->ctx, first + n <= isl_space_dim(qp->dim, type), + goto error); + + for (i = 0; i < n; ++i) + isl_assert(qp->dim->ctx, isl_space_is_equal(qp->dim, subs[i]->dim), + goto error); + + isl_assert(qp->dim->ctx, qp->div->n_row == 0, goto error); + for (i = 0; i < n; ++i) + isl_assert(qp->dim->ctx, subs[i]->div->n_row == 0, goto error); + + first += pos(qp->dim, type); + + ups = isl_alloc_array(qp->dim->ctx, struct isl_upoly *, n); + if (!ups) + goto error; + for (i = 0; i < n; ++i) + ups[i] = subs[i]->upoly; + + qp->upoly = isl_upoly_subs(qp->upoly, first, n, ups); + + free(ups); + + if (!qp->upoly) + goto error; + + return qp; +error: + isl_qpolynomial_free(qp); + return NULL; +} + +/* Extend "bset" with extra set dimensions for each integer division + * in "qp" and then call "fn" with the extended bset and the polynomial + * that results from replacing each of the integer divisions by the + * corresponding extra set dimension. + */ +isl_stat isl_qpolynomial_as_polynomial_on_domain(__isl_keep isl_qpolynomial *qp, + __isl_keep isl_basic_set *bset, + isl_stat (*fn)(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, void *user), void *user) +{ + isl_space *dim; + isl_mat *div; + isl_qpolynomial *poly; + + if (!qp || !bset) + return isl_stat_error; + if (qp->div->n_row == 0) + return fn(isl_basic_set_copy(bset), isl_qpolynomial_copy(qp), + user); + + div = isl_mat_copy(qp->div); + dim = isl_space_copy(qp->dim); + dim = isl_space_add_dims(dim, isl_dim_set, qp->div->n_row); + poly = isl_qpolynomial_alloc(dim, 0, isl_upoly_copy(qp->upoly)); + bset = isl_basic_set_copy(bset); + bset = isl_basic_set_add_dims(bset, isl_dim_set, qp->div->n_row); + bset = add_div_constraints(bset, div); + + return fn(bset, poly, user); +} + +/* Return total degree in variables first (inclusive) up to last (exclusive). + */ +int isl_upoly_degree(__isl_keep struct isl_upoly *up, int first, int last) +{ + int deg = -1; + int i; + struct isl_upoly_rec *rec; + + if (!up) + return -2; + if (isl_upoly_is_zero(up)) + return -1; + if (isl_upoly_is_cst(up) || up->var < first) + return 0; + + rec = isl_upoly_as_rec(up); + if (!rec) + return -2; + + for (i = 0; i < rec->n; ++i) { + int d; + + if (isl_upoly_is_zero(rec->p[i])) + continue; + d = isl_upoly_degree(rec->p[i], first, last); + if (up->var < last) + d += i; + if (d > deg) + deg = d; + } + + return deg; +} + +/* Return total degree in set variables. + */ +int isl_qpolynomial_degree(__isl_keep isl_qpolynomial *poly) +{ + unsigned ovar; + unsigned nvar; + + if (!poly) + return -2; + + ovar = isl_space_offset(poly->dim, isl_dim_set); + nvar = isl_space_dim(poly->dim, isl_dim_set); + return isl_upoly_degree(poly->upoly, ovar, ovar + nvar); +} + +__isl_give struct isl_upoly *isl_upoly_coeff(__isl_keep struct isl_upoly *up, + unsigned pos, int deg) +{ + int i; + struct isl_upoly_rec *rec; + + if (!up) + return NULL; + + if (isl_upoly_is_cst(up) || up->var < pos) { + if (deg == 0) + return isl_upoly_copy(up); + else + return isl_upoly_zero(up->ctx); + } + + rec = isl_upoly_as_rec(up); + if (!rec) + return NULL; + + if (up->var == pos) { + if (deg < rec->n) + return isl_upoly_copy(rec->p[deg]); + else + return isl_upoly_zero(up->ctx); + } + + up = isl_upoly_copy(up); + up = isl_upoly_cow(up); + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + for (i = 0; i < rec->n; ++i) { + struct isl_upoly *t; + t = isl_upoly_coeff(rec->p[i], pos, deg); + if (!t) + goto error; + isl_upoly_free(rec->p[i]); + rec->p[i] = t; + } + + return up; +error: + isl_upoly_free(up); + return NULL; +} + +/* Return coefficient of power "deg" of variable "t_pos" of type "type". + */ +__isl_give isl_qpolynomial *isl_qpolynomial_coeff( + __isl_keep isl_qpolynomial *qp, + enum isl_dim_type type, unsigned t_pos, int deg) +{ + unsigned g_pos; + struct isl_upoly *up; + isl_qpolynomial *c; + + if (!qp) + return NULL; + + if (type == isl_dim_out) + isl_die(qp->div->ctx, isl_error_invalid, + "output/set dimension does not have a coefficient", + return NULL); + if (type == isl_dim_in) + type = isl_dim_set; + + isl_assert(qp->div->ctx, t_pos < isl_space_dim(qp->dim, type), + return NULL); + + g_pos = pos(qp->dim, type) + t_pos; + up = isl_upoly_coeff(qp->upoly, g_pos, deg); + + c = isl_qpolynomial_alloc(isl_space_copy(qp->dim), qp->div->n_row, up); + if (!c) + return NULL; + isl_mat_free(c->div); + c->div = isl_mat_copy(qp->div); + if (!c->div) + goto error; + return c; +error: + isl_qpolynomial_free(c); + return NULL; +} + +/* Homogenize the polynomial in the variables first (inclusive) up to + * last (exclusive) by inserting powers of variable first. + * Variable first is assumed not to appear in the input. + */ +__isl_give struct isl_upoly *isl_upoly_homogenize( + __isl_take struct isl_upoly *up, int deg, int target, + int first, int last) +{ + int i; + struct isl_upoly_rec *rec; + + if (!up) + return NULL; + if (isl_upoly_is_zero(up)) + return up; + if (deg == target) + return up; + if (isl_upoly_is_cst(up) || up->var < first) { + struct isl_upoly *hom; + + hom = isl_upoly_var_pow(up->ctx, first, target - deg); + if (!hom) + goto error; + rec = isl_upoly_as_rec(hom); + rec->p[target - deg] = isl_upoly_mul(rec->p[target - deg], up); + + return hom; + } + + up = isl_upoly_cow(up); + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + for (i = 0; i < rec->n; ++i) { + if (isl_upoly_is_zero(rec->p[i])) + continue; + rec->p[i] = isl_upoly_homogenize(rec->p[i], + up->var < last ? deg + i : i, target, + first, last); + if (!rec->p[i]) + goto error; + } + + return up; +error: + isl_upoly_free(up); + return NULL; +} + +/* Homogenize the polynomial in the set variables by introducing + * powers of an extra set variable at position 0. + */ +__isl_give isl_qpolynomial *isl_qpolynomial_homogenize( + __isl_take isl_qpolynomial *poly) +{ + unsigned ovar; + unsigned nvar; + int deg = isl_qpolynomial_degree(poly); + + if (deg < -1) + goto error; + + poly = isl_qpolynomial_insert_dims(poly, isl_dim_in, 0, 1); + poly = isl_qpolynomial_cow(poly); + if (!poly) + goto error; + + ovar = isl_space_offset(poly->dim, isl_dim_set); + nvar = isl_space_dim(poly->dim, isl_dim_set); + poly->upoly = isl_upoly_homogenize(poly->upoly, 0, deg, + ovar, ovar + nvar); + if (!poly->upoly) + goto error; + + return poly; +error: + isl_qpolynomial_free(poly); + return NULL; +} + +__isl_give isl_term *isl_term_alloc(__isl_take isl_space *dim, + __isl_take isl_mat *div) +{ + isl_term *term; + int n; + + if (!dim || !div) + goto error; + + n = isl_space_dim(dim, isl_dim_all) + div->n_row; + + term = isl_calloc(dim->ctx, struct isl_term, + sizeof(struct isl_term) + (n - 1) * sizeof(int)); + if (!term) + goto error; + + term->ref = 1; + term->dim = dim; + term->div = div; + isl_int_init(term->n); + isl_int_init(term->d); + + return term; +error: + isl_space_free(dim); + isl_mat_free(div); + return NULL; +} + +__isl_give isl_term *isl_term_copy(__isl_keep isl_term *term) +{ + if (!term) + return NULL; + + term->ref++; + return term; +} + +__isl_give isl_term *isl_term_dup(__isl_keep isl_term *term) +{ + int i; + isl_term *dup; + unsigned total; + + if (!term) + return NULL; + + total = isl_space_dim(term->dim, isl_dim_all) + term->div->n_row; + + dup = isl_term_alloc(isl_space_copy(term->dim), isl_mat_copy(term->div)); + if (!dup) + return NULL; + + isl_int_set(dup->n, term->n); + isl_int_set(dup->d, term->d); + + for (i = 0; i < total; ++i) + dup->pow[i] = term->pow[i]; + + return dup; +} + +__isl_give isl_term *isl_term_cow(__isl_take isl_term *term) +{ + if (!term) + return NULL; + + if (term->ref == 1) + return term; + term->ref--; + return isl_term_dup(term); +} + +void isl_term_free(__isl_take isl_term *term) +{ + if (!term) + return; + + if (--term->ref > 0) + return; + + isl_space_free(term->dim); + isl_mat_free(term->div); + isl_int_clear(term->n); + isl_int_clear(term->d); + free(term); +} + +unsigned isl_term_dim(__isl_keep isl_term *term, enum isl_dim_type type) +{ + if (!term) + return 0; + + switch (type) { + case isl_dim_param: + case isl_dim_in: + case isl_dim_out: return isl_space_dim(term->dim, type); + case isl_dim_div: return term->div->n_row; + case isl_dim_all: return isl_space_dim(term->dim, isl_dim_all) + + term->div->n_row; + default: return 0; + } +} + +isl_ctx *isl_term_get_ctx(__isl_keep isl_term *term) +{ + return term ? term->dim->ctx : NULL; +} + +void isl_term_get_num(__isl_keep isl_term *term, isl_int *n) +{ + if (!term) + return; + isl_int_set(*n, term->n); +} + +/* Return the coefficient of the term "term". + */ +__isl_give isl_val *isl_term_get_coefficient_val(__isl_keep isl_term *term) +{ + if (!term) + return NULL; + + return isl_val_rat_from_isl_int(isl_term_get_ctx(term), + term->n, term->d); +} + +int isl_term_get_exp(__isl_keep isl_term *term, + enum isl_dim_type type, unsigned pos) +{ + if (!term) + return -1; + + isl_assert(term->dim->ctx, pos < isl_term_dim(term, type), return -1); + + if (type >= isl_dim_set) + pos += isl_space_dim(term->dim, isl_dim_param); + if (type >= isl_dim_div) + pos += isl_space_dim(term->dim, isl_dim_set); + + return term->pow[pos]; +} + +__isl_give isl_aff *isl_term_get_div(__isl_keep isl_term *term, unsigned pos) +{ + isl_local_space *ls; + isl_aff *aff; + + if (!term) + return NULL; + + isl_assert(term->dim->ctx, pos < isl_term_dim(term, isl_dim_div), + return NULL); + + ls = isl_local_space_alloc_div(isl_space_copy(term->dim), + isl_mat_copy(term->div)); + aff = isl_aff_alloc(ls); + if (!aff) + return NULL; + + isl_seq_cpy(aff->v->el, term->div->row[pos], aff->v->size); + + aff = isl_aff_normalize(aff); + + return aff; +} + +__isl_give isl_term *isl_upoly_foreach_term(__isl_keep struct isl_upoly *up, + isl_stat (*fn)(__isl_take isl_term *term, void *user), + __isl_take isl_term *term, void *user) +{ + int i; + struct isl_upoly_rec *rec; + + if (!up || !term) + goto error; + + if (isl_upoly_is_zero(up)) + return term; + + isl_assert(up->ctx, !isl_upoly_is_nan(up), goto error); + isl_assert(up->ctx, !isl_upoly_is_infty(up), goto error); + isl_assert(up->ctx, !isl_upoly_is_neginfty(up), goto error); + + if (isl_upoly_is_cst(up)) { + struct isl_upoly_cst *cst; + cst = isl_upoly_as_cst(up); + if (!cst) + goto error; + term = isl_term_cow(term); + if (!term) + goto error; + isl_int_set(term->n, cst->n); + isl_int_set(term->d, cst->d); + if (fn(isl_term_copy(term), user) < 0) + goto error; + return term; + } + + rec = isl_upoly_as_rec(up); + if (!rec) + goto error; + + for (i = 0; i < rec->n; ++i) { + term = isl_term_cow(term); + if (!term) + goto error; + term->pow[up->var] = i; + term = isl_upoly_foreach_term(rec->p[i], fn, term, user); + if (!term) + goto error; + } + term->pow[up->var] = 0; + + return term; +error: + isl_term_free(term); + return NULL; +} + +isl_stat isl_qpolynomial_foreach_term(__isl_keep isl_qpolynomial *qp, + isl_stat (*fn)(__isl_take isl_term *term, void *user), void *user) +{ + isl_term *term; + + if (!qp) + return isl_stat_error; + + term = isl_term_alloc(isl_space_copy(qp->dim), isl_mat_copy(qp->div)); + if (!term) + return isl_stat_error; + + term = isl_upoly_foreach_term(qp->upoly, fn, term, user); + + isl_term_free(term); + + return term ? isl_stat_ok : isl_stat_error; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_from_term(__isl_take isl_term *term) +{ + struct isl_upoly *up; + isl_qpolynomial *qp; + int i, n; + + if (!term) + return NULL; + + n = isl_space_dim(term->dim, isl_dim_all) + term->div->n_row; + + up = isl_upoly_rat_cst(term->dim->ctx, term->n, term->d); + for (i = 0; i < n; ++i) { + if (!term->pow[i]) + continue; + up = isl_upoly_mul(up, + isl_upoly_var_pow(term->dim->ctx, i, term->pow[i])); + } + + qp = isl_qpolynomial_alloc(isl_space_copy(term->dim), term->div->n_row, up); + if (!qp) + goto error; + isl_mat_free(qp->div); + qp->div = isl_mat_copy(term->div); + if (!qp->div) + goto error; + + isl_term_free(term); + return qp; +error: + isl_qpolynomial_free(qp); + isl_term_free(term); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_lift(__isl_take isl_qpolynomial *qp, + __isl_take isl_space *dim) +{ + int i; + int extra; + unsigned total; + + if (!qp || !dim) + goto error; + + if (isl_space_is_equal(qp->dim, dim)) { + isl_space_free(dim); + return qp; + } + + qp = isl_qpolynomial_cow(qp); + if (!qp) + goto error; + + extra = isl_space_dim(dim, isl_dim_set) - + isl_space_dim(qp->dim, isl_dim_set); + total = isl_space_dim(qp->dim, isl_dim_all); + if (qp->div->n_row) { + int *exp; + + exp = isl_alloc_array(qp->div->ctx, int, qp->div->n_row); + if (!exp) + goto error; + for (i = 0; i < qp->div->n_row; ++i) + exp[i] = extra + i; + qp->upoly = expand(qp->upoly, exp, total); + free(exp); + if (!qp->upoly) + goto error; + } + qp->div = isl_mat_insert_cols(qp->div, 2 + total, extra); + if (!qp->div) + goto error; + for (i = 0; i < qp->div->n_row; ++i) + isl_seq_clr(qp->div->row[i] + 2 + total, extra); + + isl_space_free(qp->dim); + qp->dim = dim; + + return qp; +error: + isl_space_free(dim); + isl_qpolynomial_free(qp); + return NULL; +} + +/* For each parameter or variable that does not appear in qp, + * first eliminate the variable from all constraints and then set it to zero. + */ +static __isl_give isl_set *fix_inactive(__isl_take isl_set *set, + __isl_keep isl_qpolynomial *qp) +{ + int *active = NULL; + int i; + int d; + unsigned nparam; + unsigned nvar; + + if (!set || !qp) + goto error; + + d = isl_space_dim(set->dim, isl_dim_all); + active = isl_calloc_array(set->ctx, int, d); + if (set_active(qp, active) < 0) + goto error; + + for (i = 0; i < d; ++i) + if (!active[i]) + break; + + if (i == d) { + free(active); + return set; + } + + nparam = isl_space_dim(set->dim, isl_dim_param); + nvar = isl_space_dim(set->dim, isl_dim_set); + for (i = 0; i < nparam; ++i) { + if (active[i]) + continue; + set = isl_set_eliminate(set, isl_dim_param, i, 1); + set = isl_set_fix_si(set, isl_dim_param, i, 0); + } + for (i = 0; i < nvar; ++i) { + if (active[nparam + i]) + continue; + set = isl_set_eliminate(set, isl_dim_set, i, 1); + set = isl_set_fix_si(set, isl_dim_set, i, 0); + } + + free(active); + + return set; +error: + free(active); + isl_set_free(set); + return NULL; +} + +struct isl_opt_data { + isl_qpolynomial *qp; + int first; + isl_val *opt; + int max; +}; + +static isl_stat opt_fn(__isl_take isl_point *pnt, void *user) +{ + struct isl_opt_data *data = (struct isl_opt_data *)user; + isl_val *val; + + val = isl_qpolynomial_eval(isl_qpolynomial_copy(data->qp), pnt); + if (data->first) { + data->first = 0; + data->opt = val; + } else if (data->max) { + data->opt = isl_val_max(data->opt, val); + } else { + data->opt = isl_val_min(data->opt, val); + } + + return isl_stat_ok; +} + +__isl_give isl_val *isl_qpolynomial_opt_on_domain( + __isl_take isl_qpolynomial *qp, __isl_take isl_set *set, int max) +{ + struct isl_opt_data data = { NULL, 1, NULL, max }; + + if (!set || !qp) + goto error; + + if (isl_upoly_is_cst(qp->upoly)) { + isl_set_free(set); + data.opt = isl_qpolynomial_get_constant_val(qp); + isl_qpolynomial_free(qp); + return data.opt; + } + + set = fix_inactive(set, qp); + + data.qp = qp; + if (isl_set_foreach_point(set, opt_fn, &data) < 0) + goto error; + + if (data.first) + data.opt = isl_val_zero(isl_set_get_ctx(set)); + + isl_set_free(set); + isl_qpolynomial_free(qp); + return data.opt; +error: + isl_set_free(set); + isl_qpolynomial_free(qp); + isl_val_free(data.opt); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_morph_domain( + __isl_take isl_qpolynomial *qp, __isl_take isl_morph *morph) +{ + int i; + int n_sub; + isl_ctx *ctx; + struct isl_upoly **subs; + isl_mat *mat, *diag; + + qp = isl_qpolynomial_cow(qp); + if (!qp || !morph) + goto error; + + ctx = qp->dim->ctx; + isl_assert(ctx, isl_space_is_equal(qp->dim, morph->dom->dim), goto error); + + n_sub = morph->inv->n_row - 1; + if (morph->inv->n_row != morph->inv->n_col) + n_sub += qp->div->n_row; + subs = isl_calloc_array(ctx, struct isl_upoly *, n_sub); + if (n_sub && !subs) + goto error; + + for (i = 0; 1 + i < morph->inv->n_row; ++i) + subs[i] = isl_upoly_from_affine(ctx, morph->inv->row[1 + i], + morph->inv->row[0][0], morph->inv->n_col); + if (morph->inv->n_row != morph->inv->n_col) + for (i = 0; i < qp->div->n_row; ++i) + subs[morph->inv->n_row - 1 + i] = + isl_upoly_var_pow(ctx, morph->inv->n_col - 1 + i, 1); + + qp->upoly = isl_upoly_subs(qp->upoly, 0, n_sub, subs); + + for (i = 0; i < n_sub; ++i) + isl_upoly_free(subs[i]); + free(subs); + + diag = isl_mat_diag(ctx, 1, morph->inv->row[0][0]); + mat = isl_mat_diagonal(diag, isl_mat_copy(morph->inv)); + diag = isl_mat_diag(ctx, qp->div->n_row, morph->inv->row[0][0]); + mat = isl_mat_diagonal(mat, diag); + qp->div = isl_mat_product(qp->div, mat); + isl_space_free(qp->dim); + qp->dim = isl_space_copy(morph->ran->dim); + + if (!qp->upoly || !qp->div || !qp->dim) + goto error; + + isl_morph_free(morph); + + return qp; +error: + isl_qpolynomial_free(qp); + isl_morph_free(morph); + return NULL; +} + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul( + __isl_take isl_union_pw_qpolynomial *upwqp1, + __isl_take isl_union_pw_qpolynomial *upwqp2) +{ + return isl_union_pw_qpolynomial_match_bin_op(upwqp1, upwqp2, + &isl_pw_qpolynomial_mul); +} + +/* Reorder the columns of the given div definitions according to the + * given reordering. + */ +static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div, + __isl_take isl_reordering *r) +{ + int i, j; + isl_mat *mat; + int extra; + + if (!div || !r) + goto error; + + extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len; + mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra); + if (!mat) + goto error; + + for (i = 0; i < div->n_row; ++i) { + isl_seq_cpy(mat->row[i], div->row[i], 2); + isl_seq_clr(mat->row[i] + 2, mat->n_col - 2); + for (j = 0; j < r->len; ++j) + isl_int_set(mat->row[i][2 + r->pos[j]], + div->row[i][2 + j]); + } + + isl_reordering_free(r); + isl_mat_free(div); + return mat; +error: + isl_reordering_free(r); + isl_mat_free(div); + return NULL; +} + +/* Reorder the dimension of "qp" according to the given reordering. + */ +__isl_give isl_qpolynomial *isl_qpolynomial_realign_domain( + __isl_take isl_qpolynomial *qp, __isl_take isl_reordering *r) +{ + qp = isl_qpolynomial_cow(qp); + if (!qp) + goto error; + + r = isl_reordering_extend(r, qp->div->n_row); + if (!r) + goto error; + + qp->div = reorder_divs(qp->div, isl_reordering_copy(r)); + if (!qp->div) + goto error; + + qp->upoly = reorder(qp->upoly, r->pos); + if (!qp->upoly) + goto error; + + qp = isl_qpolynomial_reset_domain_space(qp, isl_space_copy(r->dim)); + + isl_reordering_free(r); + return qp; +error: + isl_qpolynomial_free(qp); + isl_reordering_free(r); + return NULL; +} + +__isl_give isl_qpolynomial *isl_qpolynomial_align_params( + __isl_take isl_qpolynomial *qp, __isl_take isl_space *model) +{ + isl_bool equal_params; + + if (!qp || !model) + goto error; + + equal_params = isl_space_has_equal_params(qp->dim, model); + if (equal_params < 0) + goto error; + if (!equal_params) { + isl_reordering *exp; + + model = isl_space_drop_dims(model, isl_dim_in, + 0, isl_space_dim(model, isl_dim_in)); + model = isl_space_drop_dims(model, isl_dim_out, + 0, isl_space_dim(model, isl_dim_out)); + exp = isl_parameter_alignment_reordering(qp->dim, model); + exp = isl_reordering_extend_space(exp, + isl_qpolynomial_get_domain_space(qp)); + qp = isl_qpolynomial_realign_domain(qp, exp); + } + + isl_space_free(model); + return qp; +error: + isl_space_free(model); + isl_qpolynomial_free(qp); + return NULL; +} + +struct isl_split_periods_data { + int max_periods; + isl_pw_qpolynomial *res; +}; + +/* Create a slice where the integer division "div" has the fixed value "v". + * In particular, if "div" refers to floor(f/m), then create a slice + * + * m v <= f <= m v + (m - 1) + * + * or + * + * f - m v >= 0 + * -f + m v + (m - 1) >= 0 + */ +static __isl_give isl_set *set_div_slice(__isl_take isl_space *dim, + __isl_keep isl_qpolynomial *qp, int div, isl_int v) +{ + int total; + isl_basic_set *bset = NULL; + int k; + + if (!dim || !qp) + goto error; + + total = isl_space_dim(dim, isl_dim_all); + bset = isl_basic_set_alloc_space(isl_space_copy(dim), 0, 0, 2); + + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_cpy(bset->ineq[k], qp->div->row[div] + 1, 1 + total); + isl_int_submul(bset->ineq[k][0], v, qp->div->row[div][0]); + + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_neg(bset->ineq[k], qp->div->row[div] + 1, 1 + total); + isl_int_addmul(bset->ineq[k][0], v, qp->div->row[div][0]); + isl_int_add(bset->ineq[k][0], bset->ineq[k][0], qp->div->row[div][0]); + isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1); + + isl_space_free(dim); + return isl_set_from_basic_set(bset); +error: + isl_basic_set_free(bset); + isl_space_free(dim); + return NULL; +} + +static isl_stat split_periods(__isl_take isl_set *set, + __isl_take isl_qpolynomial *qp, void *user); + +/* Create a slice of the domain "set" such that integer division "div" + * has the fixed value "v" and add the results to data->res, + * replacing the integer division by "v" in "qp". + */ +static isl_stat set_div(__isl_take isl_set *set, + __isl_take isl_qpolynomial *qp, int div, isl_int v, + struct isl_split_periods_data *data) +{ + int i; + int total; + isl_set *slice; + struct isl_upoly *cst; + + slice = set_div_slice(isl_set_get_space(set), qp, div, v); + set = isl_set_intersect(set, slice); + + if (!qp) + goto error; + + total = isl_space_dim(qp->dim, isl_dim_all); + + for (i = div + 1; i < qp->div->n_row; ++i) { + if (isl_int_is_zero(qp->div->row[i][2 + total + div])) + continue; + isl_int_addmul(qp->div->row[i][1], + qp->div->row[i][2 + total + div], v); + isl_int_set_si(qp->div->row[i][2 + total + div], 0); + } + + cst = isl_upoly_rat_cst(qp->dim->ctx, v, qp->dim->ctx->one); + qp = substitute_div(qp, div, cst); + + return split_periods(set, qp, data); +error: + isl_set_free(set); + isl_qpolynomial_free(qp); + return -1; +} + +/* Split the domain "set" such that integer division "div" + * has a fixed value (ranging from "min" to "max") on each slice + * and add the results to data->res. + */ +static isl_stat split_div(__isl_take isl_set *set, + __isl_take isl_qpolynomial *qp, int div, isl_int min, isl_int max, + struct isl_split_periods_data *data) +{ + for (; isl_int_le(min, max); isl_int_add_ui(min, min, 1)) { + isl_set *set_i = isl_set_copy(set); + isl_qpolynomial *qp_i = isl_qpolynomial_copy(qp); + + if (set_div(set_i, qp_i, div, min, data) < 0) + goto error; + } + isl_set_free(set); + isl_qpolynomial_free(qp); + return isl_stat_ok; +error: + isl_set_free(set); + isl_qpolynomial_free(qp); + return isl_stat_error; +} + +/* If "qp" refers to any integer division + * that can only attain "max_periods" distinct values on "set" + * then split the domain along those distinct values. + * Add the results (or the original if no splitting occurs) + * to data->res. + */ +static isl_stat split_periods(__isl_take isl_set *set, + __isl_take isl_qpolynomial *qp, void *user) +{ + int i; + isl_pw_qpolynomial *pwqp; + struct isl_split_periods_data *data; + isl_int min, max; + int total; + isl_stat r = isl_stat_ok; + + data = (struct isl_split_periods_data *)user; + + if (!set || !qp) + goto error; + + if (qp->div->n_row == 0) { + pwqp = isl_pw_qpolynomial_alloc(set, qp); + data->res = isl_pw_qpolynomial_add_disjoint(data->res, pwqp); + return isl_stat_ok; + } + + isl_int_init(min); + isl_int_init(max); + total = isl_space_dim(qp->dim, isl_dim_all); + for (i = 0; i < qp->div->n_row; ++i) { + enum isl_lp_result lp_res; + + if (isl_seq_first_non_zero(qp->div->row[i] + 2 + total, + qp->div->n_row) != -1) + continue; + + lp_res = isl_set_solve_lp(set, 0, qp->div->row[i] + 1, + set->ctx->one, &min, NULL, NULL); + if (lp_res == isl_lp_error) + goto error2; + if (lp_res == isl_lp_unbounded || lp_res == isl_lp_empty) + continue; + isl_int_fdiv_q(min, min, qp->div->row[i][0]); + + lp_res = isl_set_solve_lp(set, 1, qp->div->row[i] + 1, + set->ctx->one, &max, NULL, NULL); + if (lp_res == isl_lp_error) + goto error2; + if (lp_res == isl_lp_unbounded || lp_res == isl_lp_empty) + continue; + isl_int_fdiv_q(max, max, qp->div->row[i][0]); + + isl_int_sub(max, max, min); + if (isl_int_cmp_si(max, data->max_periods) < 0) { + isl_int_add(max, max, min); + break; + } + } + + if (i < qp->div->n_row) { + r = split_div(set, qp, i, min, max, data); + } else { + pwqp = isl_pw_qpolynomial_alloc(set, qp); + data->res = isl_pw_qpolynomial_add_disjoint(data->res, pwqp); + } + + isl_int_clear(max); + isl_int_clear(min); + + return r; +error2: + isl_int_clear(max); + isl_int_clear(min); +error: + isl_set_free(set); + isl_qpolynomial_free(qp); + return isl_stat_error; +} + +/* If any quasi-polynomial in pwqp refers to any integer division + * that can only attain "max_periods" distinct values on its domain + * then split the domain along those distinct values. + */ +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_split_periods( + __isl_take isl_pw_qpolynomial *pwqp, int max_periods) +{ + struct isl_split_periods_data data; + + data.max_periods = max_periods; + data.res = isl_pw_qpolynomial_zero(isl_pw_qpolynomial_get_space(pwqp)); + + if (isl_pw_qpolynomial_foreach_piece(pwqp, &split_periods, &data) < 0) + goto error; + + isl_pw_qpolynomial_free(pwqp); + + return data.res; +error: + isl_pw_qpolynomial_free(data.res); + isl_pw_qpolynomial_free(pwqp); + return NULL; +} + +/* Construct a piecewise quasipolynomial that is constant on the given + * domain. In particular, it is + * 0 if cst == 0 + * 1 if cst == 1 + * infinity if cst == -1 + * + * If cst == -1, then explicitly check whether the domain is empty and, + * if so, return 0 instead. + */ +static __isl_give isl_pw_qpolynomial *constant_on_domain( + __isl_take isl_basic_set *bset, int cst) +{ + isl_space *dim; + isl_qpolynomial *qp; + + if (cst < 0 && isl_basic_set_is_empty(bset) == isl_bool_true) + cst = 0; + if (!bset) + return NULL; + + bset = isl_basic_set_params(bset); + dim = isl_basic_set_get_space(bset); + if (cst < 0) + qp = isl_qpolynomial_infty_on_domain(dim); + else if (cst == 0) + qp = isl_qpolynomial_zero_on_domain(dim); + else + qp = isl_qpolynomial_one_on_domain(dim); + return isl_pw_qpolynomial_alloc(isl_set_from_basic_set(bset), qp); +} + +/* Factor bset, call fn on each of the factors and return the product. + * + * If no factors can be found, simply call fn on the input. + * Otherwise, construct the factors based on the factorizer, + * call fn on each factor and compute the product. + */ +static __isl_give isl_pw_qpolynomial *compressed_multiplicative_call( + __isl_take isl_basic_set *bset, + __isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset)) +{ + int i, n; + isl_space *space; + isl_set *set; + isl_factorizer *f; + isl_qpolynomial *qp; + isl_pw_qpolynomial *pwqp; + unsigned nparam; + unsigned nvar; + + f = isl_basic_set_factorizer(bset); + if (!f) + goto error; + if (f->n_group == 0) { + isl_factorizer_free(f); + return fn(bset); + } + + nparam = isl_basic_set_dim(bset, isl_dim_param); + nvar = isl_basic_set_dim(bset, isl_dim_set); + + space = isl_basic_set_get_space(bset); + space = isl_space_params(space); + set = isl_set_universe(isl_space_copy(space)); + qp = isl_qpolynomial_one_on_domain(space); + pwqp = isl_pw_qpolynomial_alloc(set, qp); + + bset = isl_morph_basic_set(isl_morph_copy(f->morph), bset); + + for (i = 0, n = 0; i < f->n_group; ++i) { + isl_basic_set *bset_i; + isl_pw_qpolynomial *pwqp_i; + + bset_i = isl_basic_set_copy(bset); + bset_i = isl_basic_set_drop_constraints_involving(bset_i, + nparam + n + f->len[i], nvar - n - f->len[i]); + bset_i = isl_basic_set_drop_constraints_involving(bset_i, + nparam, n); + bset_i = isl_basic_set_drop(bset_i, isl_dim_set, + n + f->len[i], nvar - n - f->len[i]); + bset_i = isl_basic_set_drop(bset_i, isl_dim_set, 0, n); + + pwqp_i = fn(bset_i); + pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp_i); + + n += f->len[i]; + } + + isl_basic_set_free(bset); + isl_factorizer_free(f); + + return pwqp; +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Factor bset, call fn on each of the factors and return the product. + * The function is assumed to evaluate to zero on empty domains, + * to one on zero-dimensional domains and to infinity on unbounded domains + * and will not be called explicitly on zero-dimensional or unbounded domains. + * + * We first check for some special cases and remove all equalities. + * Then we hand over control to compressed_multiplicative_call. + */ +__isl_give isl_pw_qpolynomial *isl_basic_set_multiplicative_call( + __isl_take isl_basic_set *bset, + __isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset)) +{ + isl_bool bounded; + isl_morph *morph; + isl_pw_qpolynomial *pwqp; + + if (!bset) + return NULL; + + if (isl_basic_set_plain_is_empty(bset)) + return constant_on_domain(bset, 0); + + if (isl_basic_set_dim(bset, isl_dim_set) == 0) + return constant_on_domain(bset, 1); + + bounded = isl_basic_set_is_bounded(bset); + if (bounded < 0) + goto error; + if (!bounded) + return constant_on_domain(bset, -1); + + if (bset->n_eq == 0) + return compressed_multiplicative_call(bset, fn); + + morph = isl_basic_set_full_compression(bset); + bset = isl_morph_basic_set(isl_morph_copy(morph), bset); + + pwqp = compressed_multiplicative_call(bset, fn); + + morph = isl_morph_dom_params(morph); + morph = isl_morph_ran_params(morph); + morph = isl_morph_inverse(morph); + + pwqp = isl_pw_qpolynomial_morph_domain(pwqp, morph); + + return pwqp; +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Drop all floors in "qp", turning each integer division [a/m] into + * a rational division a/m. If "down" is set, then the integer division + * is replaced by (a-(m-1))/m instead. + */ +static __isl_give isl_qpolynomial *qp_drop_floors( + __isl_take isl_qpolynomial *qp, int down) +{ + int i; + struct isl_upoly *s; + + if (!qp) + return NULL; + if (qp->div->n_row == 0) + return qp; + + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + + for (i = qp->div->n_row - 1; i >= 0; --i) { + if (down) { + isl_int_sub(qp->div->row[i][1], + qp->div->row[i][1], qp->div->row[i][0]); + isl_int_add_ui(qp->div->row[i][1], + qp->div->row[i][1], 1); + } + s = isl_upoly_from_affine(qp->dim->ctx, qp->div->row[i] + 1, + qp->div->row[i][0], qp->div->n_col - 1); + qp = substitute_div(qp, i, s); + if (!qp) + return NULL; + } + + return qp; +} + +/* Drop all floors in "pwqp", turning each integer division [a/m] into + * a rational division a/m. + */ +static __isl_give isl_pw_qpolynomial *pwqp_drop_floors( + __isl_take isl_pw_qpolynomial *pwqp) +{ + int i; + + if (!pwqp) + return NULL; + + if (isl_pw_qpolynomial_is_zero(pwqp)) + return pwqp; + + pwqp = isl_pw_qpolynomial_cow(pwqp); + if (!pwqp) + return NULL; + + for (i = 0; i < pwqp->n; ++i) { + pwqp->p[i].qp = qp_drop_floors(pwqp->p[i].qp, 0); + if (!pwqp->p[i].qp) + goto error; + } + + return pwqp; +error: + isl_pw_qpolynomial_free(pwqp); + return NULL; +} + +/* Adjust all the integer divisions in "qp" such that they are at least + * one over the given orthant (identified by "signs"). This ensures + * that they will still be non-negative even after subtracting (m-1)/m. + * + * In particular, f is replaced by f' + v, changing f = [a/m] + * to f' = [(a - m v)/m]. + * If the constant term k in a is smaller than m, + * the constant term of v is set to floor(k/m) - 1. + * For any other term, if the coefficient c and the variable x have + * the same sign, then no changes are needed. + * Otherwise, if the variable is positive (and c is negative), + * then the coefficient of x in v is set to floor(c/m). + * If the variable is negative (and c is positive), + * then the coefficient of x in v is set to ceil(c/m). + */ +static __isl_give isl_qpolynomial *make_divs_pos(__isl_take isl_qpolynomial *qp, + int *signs) +{ + int i, j; + int total; + isl_vec *v = NULL; + struct isl_upoly *s; + + qp = isl_qpolynomial_cow(qp); + if (!qp) + return NULL; + qp->div = isl_mat_cow(qp->div); + if (!qp->div) + goto error; + + total = isl_space_dim(qp->dim, isl_dim_all); + v = isl_vec_alloc(qp->div->ctx, qp->div->n_col - 1); + + for (i = 0; i < qp->div->n_row; ++i) { + isl_int *row = qp->div->row[i]; + v = isl_vec_clr(v); + if (!v) + goto error; + if (isl_int_lt(row[1], row[0])) { + isl_int_fdiv_q(v->el[0], row[1], row[0]); + isl_int_sub_ui(v->el[0], v->el[0], 1); + isl_int_submul(row[1], row[0], v->el[0]); + } + for (j = 0; j < total; ++j) { + if (isl_int_sgn(row[2 + j]) * signs[j] >= 0) + continue; + if (signs[j] < 0) + isl_int_cdiv_q(v->el[1 + j], row[2 + j], row[0]); + else + isl_int_fdiv_q(v->el[1 + j], row[2 + j], row[0]); + isl_int_submul(row[2 + j], row[0], v->el[1 + j]); + } + for (j = 0; j < i; ++j) { + if (isl_int_sgn(row[2 + total + j]) >= 0) + continue; + isl_int_fdiv_q(v->el[1 + total + j], + row[2 + total + j], row[0]); + isl_int_submul(row[2 + total + j], + row[0], v->el[1 + total + j]); + } + for (j = i + 1; j < qp->div->n_row; ++j) { + if (isl_int_is_zero(qp->div->row[j][2 + total + i])) + continue; + isl_seq_combine(qp->div->row[j] + 1, + qp->div->ctx->one, qp->div->row[j] + 1, + qp->div->row[j][2 + total + i], v->el, v->size); + } + isl_int_set_si(v->el[1 + total + i], 1); + s = isl_upoly_from_affine(qp->dim->ctx, v->el, + qp->div->ctx->one, v->size); + qp->upoly = isl_upoly_subs(qp->upoly, total + i, 1, &s); + isl_upoly_free(s); + if (!qp->upoly) + goto error; + } + + isl_vec_free(v); + return qp; +error: + isl_vec_free(v); + isl_qpolynomial_free(qp); + return NULL; +} + +struct isl_to_poly_data { + int sign; + isl_pw_qpolynomial *res; + isl_qpolynomial *qp; +}; + +/* Appoximate data->qp by a polynomial on the orthant identified by "signs". + * We first make all integer divisions positive and then split the + * quasipolynomials into terms with sign data->sign (the direction + * of the requested approximation) and terms with the opposite sign. + * In the first set of terms, each integer division [a/m] is + * overapproximated by a/m, while in the second it is underapproximated + * by (a-(m-1))/m. + */ +static isl_stat to_polynomial_on_orthant(__isl_take isl_set *orthant, + int *signs, void *user) +{ + struct isl_to_poly_data *data = user; + isl_pw_qpolynomial *t; + isl_qpolynomial *qp, *up, *down; + + qp = isl_qpolynomial_copy(data->qp); + qp = make_divs_pos(qp, signs); + + up = isl_qpolynomial_terms_of_sign(qp, signs, data->sign); + up = qp_drop_floors(up, 0); + down = isl_qpolynomial_terms_of_sign(qp, signs, -data->sign); + down = qp_drop_floors(down, 1); + + isl_qpolynomial_free(qp); + qp = isl_qpolynomial_add(up, down); + + t = isl_pw_qpolynomial_alloc(orthant, qp); + data->res = isl_pw_qpolynomial_add_disjoint(data->res, t); + + return isl_stat_ok; +} + +/* Approximate each quasipolynomial by a polynomial. If "sign" is positive, + * the polynomial will be an overapproximation. If "sign" is negative, + * it will be an underapproximation. If "sign" is zero, the approximation + * will lie somewhere in between. + * + * In particular, is sign == 0, we simply drop the floors, turning + * the integer divisions into rational divisions. + * Otherwise, we split the domains into orthants, make all integer divisions + * positive and then approximate each [a/m] by either a/m or (a-(m-1))/m, + * depending on the requested sign and the sign of the term in which + * the integer division appears. + */ +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_to_polynomial( + __isl_take isl_pw_qpolynomial *pwqp, int sign) +{ + int i; + struct isl_to_poly_data data; + + if (sign == 0) + return pwqp_drop_floors(pwqp); + + if (!pwqp) + return NULL; + + data.sign = sign; + data.res = isl_pw_qpolynomial_zero(isl_pw_qpolynomial_get_space(pwqp)); + + for (i = 0; i < pwqp->n; ++i) { + if (pwqp->p[i].qp->div->n_row == 0) { + isl_pw_qpolynomial *t; + t = isl_pw_qpolynomial_alloc( + isl_set_copy(pwqp->p[i].set), + isl_qpolynomial_copy(pwqp->p[i].qp)); + data.res = isl_pw_qpolynomial_add_disjoint(data.res, t); + continue; + } + data.qp = pwqp->p[i].qp; + if (isl_set_foreach_orthant(pwqp->p[i].set, + &to_polynomial_on_orthant, &data) < 0) + goto error; + } + + isl_pw_qpolynomial_free(pwqp); + + return data.res; +error: + isl_pw_qpolynomial_free(pwqp); + isl_pw_qpolynomial_free(data.res); + return NULL; +} + +static __isl_give isl_pw_qpolynomial *poly_entry( + __isl_take isl_pw_qpolynomial *pwqp, void *user) +{ + int *sign = user; + + return isl_pw_qpolynomial_to_polynomial(pwqp, *sign); +} + +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_to_polynomial( + __isl_take isl_union_pw_qpolynomial *upwqp, int sign) +{ + return isl_union_pw_qpolynomial_transform_inplace(upwqp, + &poly_entry, &sign); +} + +__isl_give isl_basic_map *isl_basic_map_from_qpolynomial( + __isl_take isl_qpolynomial *qp) +{ + int i, k; + isl_space *dim; + isl_vec *aff = NULL; + isl_basic_map *bmap = NULL; + unsigned pos; + unsigned n_div; + + if (!qp) + return NULL; + if (!isl_upoly_is_affine(qp->upoly)) + isl_die(qp->dim->ctx, isl_error_invalid, + "input quasi-polynomial not affine", goto error); + aff = isl_qpolynomial_extract_affine(qp); + if (!aff) + goto error; + dim = isl_qpolynomial_get_space(qp); + pos = 1 + isl_space_offset(dim, isl_dim_out); + n_div = qp->div->n_row; + bmap = isl_basic_map_alloc_space(dim, n_div, 1, 2 * n_div); + + for (i = 0; i < n_div; ++i) { + k = isl_basic_map_alloc_div(bmap); + if (k < 0) + goto error; + isl_seq_cpy(bmap->div[k], qp->div->row[i], qp->div->n_col); + isl_int_set_si(bmap->div[k][qp->div->n_col], 0); + if (isl_basic_map_add_div_constraints(bmap, k) < 0) + goto error; + } + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + isl_int_neg(bmap->eq[k][pos], aff->el[0]); + isl_seq_cpy(bmap->eq[k], aff->el + 1, pos); + isl_seq_cpy(bmap->eq[k] + pos + 1, aff->el + 1 + pos, n_div); + + isl_vec_free(aff); + isl_qpolynomial_free(qp); + bmap = isl_basic_map_finalize(bmap); + return bmap; +error: + isl_vec_free(aff); + isl_qpolynomial_free(qp); + isl_basic_map_free(bmap); + return NULL; +} Index: contrib/isl/isl_polynomial_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_polynomial_private.h @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include +#include +#include + +struct isl_upoly { + int ref; + struct isl_ctx *ctx; + + int var; +}; + +struct isl_upoly_cst { + struct isl_upoly up; + isl_int n; + isl_int d; +}; + +struct isl_upoly_rec { + struct isl_upoly up; + int n; + + size_t size; + struct isl_upoly *p[]; +}; + +/* dim represents the domain space. + */ +struct isl_qpolynomial { + int ref; + + isl_space *dim; + struct isl_mat *div; + struct isl_upoly *upoly; +}; + +struct isl_term { + int ref; + + isl_int n; + isl_int d; + + isl_space *dim; + struct isl_mat *div; + + int pow[1]; +}; + +struct isl_pw_qpolynomial_piece { + struct isl_set *set; + struct isl_qpolynomial *qp; +}; + +struct isl_pw_qpolynomial { + int ref; + + isl_space *dim; + + int n; + + size_t size; + struct isl_pw_qpolynomial_piece p[1]; +}; + +/* dim represents the domain space. + */ +struct isl_qpolynomial_fold { + int ref; + + enum isl_fold type; + isl_space *dim; + + int n; + + size_t size; + struct isl_qpolynomial *qp[1]; +}; + +struct isl_pw_qpolynomial_fold_piece { + struct isl_set *set; + struct isl_qpolynomial_fold *fold; +}; + +struct isl_pw_qpolynomial_fold { + int ref; + + enum isl_fold type; + isl_space *dim; + + int n; + + size_t size; + struct isl_pw_qpolynomial_fold_piece p[1]; +}; + +void isl_term_get_num(__isl_keep isl_term *term, isl_int *n); + +__isl_give struct isl_upoly *isl_upoly_zero(struct isl_ctx *ctx); +__isl_give struct isl_upoly *isl_upoly_copy(__isl_keep struct isl_upoly *up); +__isl_give struct isl_upoly *isl_upoly_cow(__isl_take struct isl_upoly *up); +__isl_give struct isl_upoly *isl_upoly_dup(__isl_keep struct isl_upoly *up); +__isl_null struct isl_upoly *isl_upoly_free(__isl_take struct isl_upoly *up); +__isl_give struct isl_upoly *isl_upoly_mul(__isl_take struct isl_upoly *up1, + __isl_take struct isl_upoly *up2); + +int isl_upoly_is_cst(__isl_keep struct isl_upoly *up); +int isl_upoly_is_zero(__isl_keep struct isl_upoly *up); +int isl_upoly_is_one(__isl_keep struct isl_upoly *up); +int isl_upoly_is_negone(__isl_keep struct isl_upoly *up); +__isl_keep struct isl_upoly_cst *isl_upoly_as_cst(__isl_keep struct isl_upoly *up); +__isl_keep struct isl_upoly_rec *isl_upoly_as_rec(__isl_keep struct isl_upoly *up); + +__isl_give struct isl_upoly *isl_upoly_sum(__isl_take struct isl_upoly *up1, + __isl_take struct isl_upoly *up2); +__isl_give struct isl_upoly *isl_upoly_mul_isl_int( + __isl_take struct isl_upoly *up, isl_int v); + +__isl_give isl_qpolynomial *isl_qpolynomial_alloc(__isl_take isl_space *dim, + unsigned n_div, __isl_take struct isl_upoly *up); +__isl_give isl_qpolynomial *isl_qpolynomial_cow(__isl_take isl_qpolynomial *qp); +__isl_give isl_qpolynomial *isl_qpolynomial_dup(__isl_keep isl_qpolynomial *qp); + +__isl_give isl_qpolynomial *isl_qpolynomial_cst_on_domain(__isl_take isl_space *dim, + isl_int v); +__isl_give isl_qpolynomial *isl_qpolynomial_rat_cst_on_domain( + __isl_take isl_space *space, const isl_int n, const isl_int d); +__isl_give isl_qpolynomial *isl_qpolynomial_var_pow_on_domain(__isl_take isl_space *dim, + int pos, int power); +isl_bool isl_qpolynomial_is_one(__isl_keep isl_qpolynomial *qp); +int isl_qpolynomial_is_affine(__isl_keep isl_qpolynomial *qp); +int isl_qpolynomial_is_cst(__isl_keep isl_qpolynomial *qp, + isl_int *n, isl_int *d); + +unsigned isl_qpolynomial_domain_offset(__isl_keep isl_qpolynomial *qp, + enum isl_dim_type type); + +__isl_give isl_qpolynomial *isl_qpolynomial_add_on_domain( + __isl_keep isl_set *dom, + __isl_take isl_qpolynomial *qp1, + __isl_take isl_qpolynomial *qp2); + +int isl_qpolynomial_plain_cmp(__isl_keep isl_qpolynomial *qp1, + __isl_keep isl_qpolynomial *qp2); + +int isl_qpolynomial_degree(__isl_keep isl_qpolynomial *poly); +__isl_give isl_qpolynomial *isl_qpolynomial_coeff( + __isl_keep isl_qpolynomial *poly, + enum isl_dim_type type, unsigned pos, int deg); + +__isl_give isl_vec *isl_qpolynomial_extract_affine( + __isl_keep isl_qpolynomial *qp); +__isl_give isl_qpolynomial *isl_qpolynomial_from_affine(__isl_take isl_space *dim, + isl_int *f, isl_int denom); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_cow( + __isl_take isl_pw_qpolynomial *pwqp); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_piece( + __isl_take isl_pw_qpolynomial *pwqp, + __isl_take isl_set *set, __isl_take isl_qpolynomial *qp); +int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_project_out( + __isl_take isl_pw_qpolynomial *pwqp, + enum isl_dim_type type, unsigned first, unsigned n); + +__isl_give isl_val *isl_qpolynomial_opt_on_domain( + __isl_take isl_qpolynomial *qp, __isl_take isl_set *set, int max); + +enum isl_fold isl_fold_type_negate(enum isl_fold type); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow( + __isl_take isl_qpolynomial_fold *fold); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup( + __isl_keep isl_qpolynomial_fold *fold); + +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_cow( + __isl_take isl_pw_qpolynomial_fold *pwf); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain( + __isl_keep isl_set *set, + __isl_take isl_qpolynomial_fold *fold1, + __isl_take isl_qpolynomial_fold *fold2); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain( + __isl_keep isl_set *set, + __isl_take isl_qpolynomial_fold *fold1, + __isl_take isl_qpolynomial_fold *fold2); + +int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1, + __isl_keep isl_qpolynomial_fold *fold2); + +__isl_give isl_val *isl_qpolynomial_fold_opt_on_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max); + +int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1, + __isl_keep isl_pw_qpolynomial_fold *pwf2); + +__isl_give isl_qpolynomial *isl_qpolynomial_morph_domain( + __isl_take isl_qpolynomial *qp, __isl_take isl_morph *morph); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_morph_domain( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_morph *morph); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_morph_domain( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_morph *morph); + +__isl_give isl_qpolynomial *isl_qpolynomial_lift(__isl_take isl_qpolynomial *qp, + __isl_take isl_space *dim); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim); + +__isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities( + __isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context); + +__isl_give isl_qpolynomial *isl_qpolynomial_realign_domain( + __isl_take isl_qpolynomial *qp, __isl_take isl_reordering *r); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_realign_domain( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_reordering *r); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_realign_domain( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_reordering *r); + +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_space( + __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_space *space); +__isl_give isl_qpolynomial *isl_qpolynomial_reset_domain_space( + __isl_take isl_qpolynomial *qp, __isl_take isl_space *dim); +__isl_give isl_qpolynomial *isl_qpolynomial_reset_space_and_domain( + __isl_take isl_qpolynomial *qp, __isl_take isl_space *space, + __isl_take isl_space *domain); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim); +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain( + __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space, + __isl_take isl_space *domain); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_reset_domain_space( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_space *dim); + +void isl_qpolynomial_get_den(__isl_keep isl_qpolynomial *qp, isl_int *d); +__isl_give isl_qpolynomial *isl_qpolynomial_add_isl_int( + __isl_take isl_qpolynomial *qp, isl_int v); +__isl_give isl_qpolynomial *isl_qpolynomial_mul_isl_int( + __isl_take isl_qpolynomial *qp, isl_int v); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul_isl_int( + __isl_take isl_pw_qpolynomial *pwqp, isl_int v); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale( + __isl_take isl_qpolynomial_fold *fold, isl_int v); + +__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int( + __isl_take isl_qpolynomial_fold *fold, isl_int v); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_mul_isl_int( + __isl_take isl_pw_qpolynomial_fold *pwf, isl_int v); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul_isl_int( + __isl_take isl_union_pw_qpolynomial *upwqp, isl_int v); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_mul_isl_int( + __isl_take isl_union_pw_qpolynomial_fold *upwf, isl_int v); Index: contrib/isl/isl_power_templ.c =================================================================== --- /dev/null +++ contrib/isl/isl_power_templ.c @@ -0,0 +1,81 @@ +#include + +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +/* Compute the given non-zero power of "map" and return the result. + * If the exponent "exp" is negative, then the -exp th power of the inverse + * relation is computed. + */ +__isl_give TYPE *FN(TYPE,fixed_power)(__isl_take TYPE *map, isl_int exp) +{ + isl_ctx *ctx; + TYPE *res = NULL; + isl_int r; + + if (!map) + return NULL; + + ctx = FN(TYPE,get_ctx)(map); + if (isl_int_is_zero(exp)) + isl_die(ctx, isl_error_invalid, + "expecting non-zero exponent", goto error); + + if (isl_int_is_neg(exp)) { + isl_int_neg(exp, exp); + map = FN(TYPE,reverse)(map); + return FN(TYPE,fixed_power)(map, exp); + } + + isl_int_init(r); + for (;;) { + isl_int_fdiv_r(r, exp, ctx->two); + + if (!isl_int_is_zero(r)) { + if (!res) + res = FN(TYPE,copy)(map); + else { + res = FN(TYPE,apply_range)(res, + FN(TYPE,copy)(map)); + res = FN(TYPE,coalesce)(res); + } + if (!res) + break; + } + + isl_int_fdiv_q(exp, exp, ctx->two); + if (isl_int_is_zero(exp)) + break; + + map = FN(TYPE,apply_range)(map, FN(TYPE,copy)(map)); + map = FN(TYPE,coalesce)(map); + } + isl_int_clear(r); + + FN(TYPE,free)(map); + return res; +error: + FN(TYPE,free)(map); + return NULL; +} + +/* Compute the given non-zero power of "map" and return the result. + * If the exponent "exp" is negative, then the -exp th power of the inverse + * relation is computed. + */ +__isl_give TYPE *FN(TYPE,fixed_power_val)(__isl_take TYPE *map, + __isl_take isl_val *exp) +{ + if (!map || !exp) + goto error; + if (!isl_val_is_int(exp)) + isl_die(FN(TYPE,get_ctx)(map), isl_error_invalid, + "expecting integer exponent", goto error); + map = FN(TYPE,fixed_power)(map, exp->n); + isl_val_free(exp); + return map; +error: + FN(TYPE,free)(map); + isl_val_free(exp); + return NULL; +} Index: contrib/isl/isl_printer.c =================================================================== --- /dev/null +++ contrib/isl/isl_printer.c @@ -0,0 +1,848 @@ +#include +#include +#include + +static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p) +{ + fprintf(p->file, "%s%*s%s", p->indent_prefix ? p->indent_prefix : "", + p->indent, "", p->prefix ? p->prefix : ""); + return p; +} + +static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p) +{ + fprintf(p->file, "%s\n", p->suffix ? p->suffix : ""); + return p; +} + +static __isl_give isl_printer *file_flush(__isl_take isl_printer *p) +{ + fflush(p->file); + return p; +} + +static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p, + const char *s) +{ + fprintf(p->file, "%s", s); + return p; +} + +static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p, + double d) +{ + fprintf(p->file, "%g", d); + return p; +} + +static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i) +{ + fprintf(p->file, "%d", i); + return p; +} + +static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i) +{ + isl_int_print(p->file, i, p->width); + return p; +} + +static int grow_buf(__isl_keep isl_printer *p, int extra) +{ + int new_size; + char *new_buf; + + if (p->buf_size == 0) + return -1; + + new_size = ((p->buf_n + extra + 1) * 3) / 2; + new_buf = isl_realloc_array(p->ctx, p->buf, char, new_size); + if (!new_buf) { + p->buf_size = 0; + return -1; + } + p->buf = new_buf; + p->buf_size = new_size; + + return 0; +} + +static __isl_give isl_printer *str_print(__isl_take isl_printer *p, + const char *s, int len) +{ + if (p->buf_n + len + 1 >= p->buf_size && grow_buf(p, len)) + goto error; + memcpy(p->buf + p->buf_n, s, len); + p->buf_n += len; + + p->buf[p->buf_n] = '\0'; + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p, + int indent) +{ + int i; + + if (p->buf_n + indent + 1 >= p->buf_size && grow_buf(p, indent)) + goto error; + for (i = 0; i < indent; ++i) + p->buf[p->buf_n++] = ' '; + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p) +{ + if (p->indent_prefix) + p = str_print(p, p->indent_prefix, strlen(p->indent_prefix)); + p = str_print_indent(p, p->indent); + if (p->prefix) + p = str_print(p, p->prefix, strlen(p->prefix)); + return p; +} + +static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p) +{ + if (p->suffix) + p = str_print(p, p->suffix, strlen(p->suffix)); + p = str_print(p, "\n", strlen("\n")); + return p; +} + +static __isl_give isl_printer *str_flush(__isl_take isl_printer *p) +{ + p->buf_n = 0; + p->buf[p->buf_n] = '\0'; + return p; +} + +static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p, + const char *s) +{ + return str_print(p, s, strlen(s)); +} + +static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p, + double d) +{ + int left = p->buf_size - p->buf_n; + int need = snprintf(p->buf + p->buf_n, left, "%g", d); + if (need >= left) { + if (grow_buf(p, need)) + goto error; + left = p->buf_size - p->buf_n; + need = snprintf(p->buf + p->buf_n, left, "%g", d); + } + p->buf_n += need; + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i) +{ + int left = p->buf_size - p->buf_n; + int need = snprintf(p->buf + p->buf_n, left, "%d", i); + if (need >= left) { + if (grow_buf(p, need)) + goto error; + left = p->buf_size - p->buf_n; + need = snprintf(p->buf + p->buf_n, left, "%d", i); + } + p->buf_n += need; + return p; +error: + isl_printer_free(p); + return NULL; +} + +static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p, + isl_int i) +{ + char *s; + int len; + + s = isl_int_get_str(i); + len = strlen(s); + if (len < p->width) + p = str_print_indent(p, p->width - len); + p = str_print(p, s, len); + isl_int_free_str(s); + return p; +} + +struct isl_printer_ops { + __isl_give isl_printer *(*start_line)(__isl_take isl_printer *p); + __isl_give isl_printer *(*end_line)(__isl_take isl_printer *p); + __isl_give isl_printer *(*print_double)(__isl_take isl_printer *p, + double d); + __isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i); + __isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p, + isl_int i); + __isl_give isl_printer *(*print_str)(__isl_take isl_printer *p, + const char *s); + __isl_give isl_printer *(*flush)(__isl_take isl_printer *p); +}; + +static struct isl_printer_ops file_ops = { + file_start_line, + file_end_line, + file_print_double, + file_print_int, + file_print_isl_int, + file_print_str, + file_flush +}; + +static struct isl_printer_ops str_ops = { + str_start_line, + str_end_line, + str_print_double, + str_print_int, + str_print_isl_int, + str_print_str, + str_flush +}; + +__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file) +{ + struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer); + if (!p) + return NULL; + p->ctx = ctx; + isl_ctx_ref(p->ctx); + p->ops = &file_ops; + p->file = file; + p->buf = NULL; + p->buf_n = 0; + p->buf_size = 0; + p->indent = 0; + p->output_format = ISL_FORMAT_ISL; + p->indent_prefix = NULL; + p->prefix = NULL; + p->suffix = NULL; + p->width = 0; + p->yaml_style = ISL_YAML_STYLE_FLOW; + + return p; +} + +__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx) +{ + struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer); + if (!p) + return NULL; + p->ctx = ctx; + isl_ctx_ref(p->ctx); + p->ops = &str_ops; + p->file = NULL; + p->buf = isl_alloc_array(ctx, char, 256); + if (!p->buf) + goto error; + p->buf_n = 0; + p->buf[0] = '\0'; + p->buf_size = 256; + p->indent = 0; + p->output_format = ISL_FORMAT_ISL; + p->indent_prefix = NULL; + p->prefix = NULL; + p->suffix = NULL; + p->width = 0; + p->yaml_style = ISL_YAML_STYLE_FLOW; + + return p; +error: + isl_printer_free(p); + return NULL; +} + +__isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p) +{ + if (!p) + return NULL; + free(p->buf); + free(p->indent_prefix); + free(p->prefix); + free(p->suffix); + free(p->yaml_state); + isl_id_to_id_free(p->notes); + isl_ctx_deref(p->ctx); + free(p); + + return NULL; +} + +isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer) +{ + return printer ? printer->ctx : NULL; +} + +FILE *isl_printer_get_file(__isl_keep isl_printer *printer) +{ + if (!printer) + return NULL; + if (!printer->file) + isl_die(isl_printer_get_ctx(printer), isl_error_invalid, + "not a file printer", return NULL); + return printer->file; +} + +__isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p, + int width) +{ + if (!p) + return NULL; + + p->width = width; + + return p; +} + +__isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p, + int indent) +{ + if (!p) + return NULL; + + p->indent = indent; + + return p; +} + +__isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p, + int indent) +{ + if (!p) + return NULL; + + p->indent += indent; + if (p->indent < 0) + p->indent = 0; + + return p; +} + +/* Replace the indent prefix of "p" by "prefix". + */ +__isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p, + const char *prefix) +{ + if (!p) + return NULL; + + free(p->indent_prefix); + p->indent_prefix = prefix ? strdup(prefix) : NULL; + + return p; +} + +__isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p, + const char *prefix) +{ + if (!p) + return NULL; + + free(p->prefix); + p->prefix = prefix ? strdup(prefix) : NULL; + + return p; +} + +__isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p, + const char *suffix) +{ + if (!p) + return NULL; + + free(p->suffix); + p->suffix = suffix ? strdup(suffix) : NULL; + + return p; +} + +__isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p, + int output_format) +{ + if (!p) + return NULL; + + p->output_format = output_format; + + return p; +} + +int isl_printer_get_output_format(__isl_keep isl_printer *p) +{ + if (!p) + return -1; + return p->output_format; +} + +/* Does "p" have a note with identifier "id"? + */ +isl_bool isl_printer_has_note(__isl_keep isl_printer *p, + __isl_keep isl_id *id) +{ + if (!p || !id) + return isl_bool_error; + if (!p->notes) + return isl_bool_false; + return isl_id_to_id_has(p->notes, id); +} + +/* Retrieve the note identified by "id" from "p". + * The note is assumed to exist. + */ +__isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p, + __isl_take isl_id *id) +{ + isl_bool has_note; + + has_note = isl_printer_has_note(p, id); + if (has_note < 0) + goto error; + if (!has_note) + isl_die(isl_printer_get_ctx(p), isl_error_invalid, + "no such note", goto error); + + return isl_id_to_id_get(p->notes, id); +error: + isl_id_free(id); + return NULL; +} + +/* Associate "note" to the identifier "id" in "p", + * replacing the previous note associated to the identifier, if any. + */ +__isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p, + __isl_take isl_id *id, __isl_take isl_id *note) +{ + if (!p || !id || !note) + goto error; + if (!p->notes) { + p->notes = isl_id_to_id_alloc(isl_printer_get_ctx(p), 1); + if (!p->notes) + goto error; + } + p->notes = isl_id_to_id_set(p->notes, id, note); + if (!p->notes) + return isl_printer_free(p); + return p; +error: + isl_printer_free(p); + isl_id_free(id); + isl_id_free(note); + return NULL; +} + +/* Keep track of whether the printing to "p" is being performed from + * an isl_*_dump function as specified by "dump". + */ +__isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p, + int dump) +{ + if (!p) + return NULL; + + p->dump = dump; + + return p; +} + +/* Set the YAML style of "p" to "yaml_style" and return the updated printer. + */ +__isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p, + int yaml_style) +{ + if (!p) + return NULL; + + p->yaml_style = yaml_style; + + return p; +} + +/* Return the YAML style of "p" or -1 on error. + */ +int isl_printer_get_yaml_style(__isl_keep isl_printer *p) +{ + if (!p) + return -1; + return p->yaml_style; +} + +/* Push "state" onto the stack of currently active YAML elements and + * return the updated printer. + */ +static __isl_give isl_printer *push_state(__isl_take isl_printer *p, + enum isl_yaml_state state) +{ + if (!p) + return NULL; + + if (p->yaml_size < p->yaml_depth + 1) { + enum isl_yaml_state *state; + state = isl_realloc_array(p->ctx, p->yaml_state, + enum isl_yaml_state, p->yaml_depth + 1); + if (!state) + return isl_printer_free(p); + p->yaml_state = state; + p->yaml_size = p->yaml_depth + 1; + } + + p->yaml_state[p->yaml_depth] = state; + p->yaml_depth++; + + return p; +} + +/* Remove the innermost active YAML element from the stack and + * return the updated printer. + */ +static __isl_give isl_printer *pop_state(__isl_take isl_printer *p) +{ + if (!p) + return NULL; + p->yaml_depth--; + return p; +} + +/* Set the state of the innermost active YAML element to "state" and + * return the updated printer. + */ +static __isl_give isl_printer *update_state(__isl_take isl_printer *p, + enum isl_yaml_state state) +{ + if (!p) + return NULL; + if (p->yaml_depth < 1) + isl_die(isl_printer_get_ctx(p), isl_error_invalid, + "not in YAML construct", return isl_printer_free(p)); + + p->yaml_state[p->yaml_depth - 1] = state; + + return p; +} + +/* Return the state of the innermost active YAML element. + * Return isl_yaml_none if we are not inside any YAML element. + */ +static enum isl_yaml_state current_state(__isl_keep isl_printer *p) +{ + if (!p) + return isl_yaml_none; + if (p->yaml_depth < 1) + return isl_yaml_none; + return p->yaml_state[p->yaml_depth - 1]; +} + +/* If we are printing a YAML document and we are at the start of an element, + * print whatever is needed before we can print the actual element and + * keep track of the fact that we are now printing the element. + * If "eol" is set, then whatever we print is going to be the last + * thing that gets printed on this line. + * + * If we are about the print the first key of a mapping, then nothing + * extra needs to be printed. For any other key, however, we need + * to either move to the next line (in block format) or print a comma + * (in flow format). + * Before printing a value in a mapping, we need to print a colon. + * + * For sequences, in flow format, we only need to print a comma + * for each element except the first. + * In block format, before the first element in the sequence, + * we move to a new line, print a dash and increase the indentation. + * Before any other element, we print a dash on a new line, + * temporarily moving the indentation back. + */ +static __isl_give isl_printer *enter_state(__isl_take isl_printer *p, + int eol) +{ + enum isl_yaml_state state; + + if (!p) + return NULL; + + state = current_state(p); + if (state == isl_yaml_mapping_val_start) { + if (eol) + p = p->ops->print_str(p, ":"); + else + p = p->ops->print_str(p, ": "); + p = update_state(p, isl_yaml_mapping_val); + } else if (state == isl_yaml_mapping_first_key_start) { + p = update_state(p, isl_yaml_mapping_key); + } else if (state == isl_yaml_mapping_key_start) { + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + p = p->ops->print_str(p, ", "); + else { + p = p->ops->end_line(p); + p = p->ops->start_line(p); + } + p = update_state(p, isl_yaml_mapping_key); + } else if (state == isl_yaml_sequence_first_start) { + if (p->yaml_style != ISL_YAML_STYLE_FLOW) { + p = p->ops->end_line(p); + p = p->ops->start_line(p); + p = p->ops->print_str(p, "- "); + p = isl_printer_indent(p, 2); + } + p = update_state(p, isl_yaml_sequence); + } else if (state == isl_yaml_sequence_start) { + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + p = p->ops->print_str(p, ", "); + else { + p = p->ops->end_line(p); + p = isl_printer_indent(p, -2); + p = p->ops->start_line(p); + p = p->ops->print_str(p, "- "); + p = isl_printer_indent(p, 2); + } + p = update_state(p, isl_yaml_sequence); + } + + return p; +} + +__isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p, + const char *s) +{ + if (!p) + return NULL; + if (!s) + return isl_printer_free(p); + p = enter_state(p, 0); + if (!p) + return NULL; + return p->ops->print_str(p, s); +} + +__isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p, + double d) +{ + p = enter_state(p, 0); + if (!p) + return NULL; + + return p->ops->print_double(p, d); +} + +__isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i) +{ + p = enter_state(p, 0); + if (!p) + return NULL; + + return p->ops->print_int(p, i); +} + +__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p, + isl_int i) +{ + p = enter_state(p, 0); + if (!p) + return NULL; + + return p->ops->print_isl_int(p, i); +} + +__isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p) +{ + if (!p) + return NULL; + + return p->ops->start_line(p); +} + +__isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p) +{ + if (!p) + return NULL; + + return p->ops->end_line(p); +} + +/* Return a copy of the string constructed by the string printer "printer". + */ +__isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer) +{ + if (!printer) + return NULL; + if (printer->ops != &str_ops) + isl_die(isl_printer_get_ctx(printer), isl_error_invalid, + "isl_printer_get_str can only be called on a string " + "printer", return NULL); + if (!printer->buf) + return NULL; + return strdup(printer->buf); +} + +__isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p) +{ + if (!p) + return NULL; + + return p->ops->flush(p); +} + +/* Start a YAML mapping and push a new state to reflect that we + * are about to print the first key in a mapping. + * + * In flow style, print the opening brace. + * In block style, move to the next line with an increased indentation, + * except if this is the outer mapping or if we are inside a sequence + * (in which case we have already increased the indentation and we want + * to print the first key on the same line as the dash). + */ +__isl_give isl_printer *isl_printer_yaml_start_mapping( + __isl_take isl_printer *p) +{ + enum isl_yaml_state state; + + if (!p) + return NULL; + p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK); + if (!p) + return NULL; + state = current_state(p); + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + p = p->ops->print_str(p, "{ "); + else if (state != isl_yaml_none && state != isl_yaml_sequence) { + p = p->ops->end_line(p); + p = isl_printer_indent(p, 2); + p = p->ops->start_line(p); + } + p = push_state(p, isl_yaml_mapping_first_key_start); + return p; +} + +/* Finish a YAML mapping and pop it from the state stack. + * + * In flow style, print the closing brace. + * + * In block style, first check if we are still in the + * isl_yaml_mapping_first_key_start state. If so, we have not printed + * anything yet, so print "{}" to indicate an empty mapping. + * If we increased the indentation in isl_printer_yaml_start_mapping, + * then decrease it again. + * If this is the outer mapping then print a newline. + */ +__isl_give isl_printer *isl_printer_yaml_end_mapping( + __isl_take isl_printer *p) +{ + enum isl_yaml_state state; + + state = current_state(p); + p = pop_state(p); + if (!p) + return NULL; + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + return p->ops->print_str(p, " }"); + if (state == isl_yaml_mapping_first_key_start) + p = p->ops->print_str(p, "{}"); + if (!p) + return NULL; + state = current_state(p); + if (state != isl_yaml_none && state != isl_yaml_sequence) + p = isl_printer_indent(p, -2); + if (state == isl_yaml_none) + p = p->ops->end_line(p); + return p; +} + +/* Start a YAML sequence and push a new state to reflect that we + * are about to print the first element in a sequence. + * + * In flow style, print the opening bracket. + */ +__isl_give isl_printer *isl_printer_yaml_start_sequence( + __isl_take isl_printer *p) +{ + if (!p) + return NULL; + p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK); + p = push_state(p, isl_yaml_sequence_first_start); + if (!p) + return NULL; + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + p = p->ops->print_str(p, "[ "); + return p; +} + +/* Finish a YAML sequence and pop it from the state stack. + * + * In flow style, print the closing bracket. + * + * In block style, check if we are still in the + * isl_yaml_sequence_first_start state. If so, we have not printed + * anything yet, so print "[]" or " []" to indicate an empty sequence. + * We print the extra space when we instructed enter_state not + * to print a space at the end of the line. + * Otherwise, undo the increase in indentation performed by + * enter_state when moving away from the isl_yaml_sequence_first_start + * state. + * If this is the outer sequence then print a newline. + */ +__isl_give isl_printer *isl_printer_yaml_end_sequence( + __isl_take isl_printer *p) +{ + enum isl_yaml_state state, up; + + state = current_state(p); + p = pop_state(p); + if (!p) + return NULL; + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + return p->ops->print_str(p, " ]"); + up = current_state(p); + if (state == isl_yaml_sequence_first_start) { + if (up == isl_yaml_mapping_val) + p = p->ops->print_str(p, " []"); + else + p = p->ops->print_str(p, "[]"); + } else { + p = isl_printer_indent(p, -2); + } + if (!p) + return NULL; + state = current_state(p); + if (state == isl_yaml_none) + p = p->ops->end_line(p); + return p; +} + +/* Mark the fact that the current element is finished and that + * the next output belongs to the next element. + * In particular, if we are printing a key, then prepare for + * printing the subsequent value. If we are printing a value, + * prepare for printing the next key. If we are printing an + * element in a sequence, prepare for printing the next element. + */ +__isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p) +{ + enum isl_yaml_state state; + + if (!p) + return NULL; + if (p->yaml_depth < 1) + isl_die(isl_printer_get_ctx(p), isl_error_invalid, + "not in YAML construct", return isl_printer_free(p)); + + state = current_state(p); + if (state == isl_yaml_mapping_key) + state = isl_yaml_mapping_val_start; + else if (state == isl_yaml_mapping_val) + state = isl_yaml_mapping_key_start; + else if (state == isl_yaml_sequence) + state = isl_yaml_sequence_start; + p = update_state(p, state); + + return p; +} Index: contrib/isl/isl_printer_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_printer_private.h @@ -0,0 +1,52 @@ +#ifndef ISL_PRINTER_PRIVATE_H +#define ISL_PRINTER_PRIVATE_H + +#include +#include +#include + +struct isl_printer_ops; + +/* A printer to a file or a string. + * + * "dump" is set if the printing is performed from an isl_*_dump function. + * + * yaml_style is the YAML style in which the next elements should + * be printed and may be either ISL_YAML_STYLE_BLOCK or ISL_YAML_STYLE_FLOW, + * with ISL_YAML_STYLE_FLOW being the default. + * yaml_state keeps track of the currently active YAML elements. + * yaml_size is the size of this arrays, while yaml_depth + * is the number of elements currently in use. + * yaml_state may be NULL if no YAML printing is being performed. + * + * notes keeps track of arbitrary notes as a mapping between + * name identifiers and note identifiers. It may be NULL + * if there are no notes yet. + */ +struct isl_printer { + struct isl_ctx *ctx; + struct isl_printer_ops *ops; + FILE *file; + int buf_n; + int buf_size; + char *buf; + int indent; + int output_format; + int dump; + char *indent_prefix; + char *prefix; + char *suffix; + int width; + + int yaml_style; + int yaml_depth; + int yaml_size; + enum isl_yaml_state *yaml_state; + + isl_id_to_id *notes; +}; + +__isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p, + int dump); + +#endif Index: contrib/isl/isl_pw_hash.c =================================================================== --- /dev/null +++ contrib/isl/isl_pw_hash.c @@ -0,0 +1,33 @@ +/* + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege + */ + +#include +#include + +/* Return a hash value that digests "pw". + */ +uint32_t FN(PW,get_hash)(__isl_keep PW *pw) +{ + int i; + uint32_t hash; + + if (!pw) + return 0; + + hash = isl_hash_init(); + for (i = 0; i < pw->n; ++i) { + uint32_t set_hash, el_hash; + + set_hash = isl_set_get_hash(pw->p[i].set); + isl_hash_hash(hash, set_hash); + el_hash = FN(EL,get_hash)(pw->p[i].FIELD); + isl_hash_hash(hash, el_hash); + } + + return hash; +} Index: contrib/isl/isl_pw_macro.h =================================================================== --- /dev/null +++ contrib/isl/isl_pw_macro.h @@ -0,0 +1,4 @@ +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) +#define xS(TYPE,NAME) struct TYPE ## _ ## NAME +#define S(TYPE,NAME) xS(TYPE,NAME) Index: contrib/isl/isl_pw_templ.c =================================================================== --- /dev/null +++ contrib/isl/isl_pw_templ.c @@ -0,0 +1,2252 @@ +/* + * Copyright 2010-2011 INRIA Saclay + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include + +#include + +#ifdef HAS_TYPE +__isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim, + enum isl_fold type, int n) +#else +__isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim, int n) +#endif +{ + isl_ctx *ctx; + struct PW *pw; + + if (!dim) + return NULL; + ctx = isl_space_get_ctx(dim); + isl_assert(ctx, n >= 0, goto error); + pw = isl_alloc(ctx, struct PW, + sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece))); + if (!pw) + goto error; + + pw->ref = 1; +#ifdef HAS_TYPE + pw->type = type; +#endif + pw->size = n; + pw->n = 0; + pw->dim = dim; + return pw; +error: + isl_space_free(dim); + return NULL; +} + +#ifdef HAS_TYPE +__isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim, enum isl_fold type) +{ + return FN(PW,alloc_size)(dim, type, 0); +} +#else +__isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim) +{ + return FN(PW,alloc_size)(dim, 0); +} +#endif + +__isl_give PW *FN(PW,add_piece)(__isl_take PW *pw, + __isl_take isl_set *set, __isl_take EL *el) +{ + isl_ctx *ctx; + isl_space *el_dim = NULL; + + if (!pw || !set || !el) + goto error; + + if (isl_set_plain_is_empty(set) || FN(EL,EL_IS_ZERO)(el)) { + isl_set_free(set); + FN(EL,free)(el); + return pw; + } + + ctx = isl_set_get_ctx(set); +#ifdef HAS_TYPE + if (pw->type != el->type) + isl_die(ctx, isl_error_invalid, "fold types don't match", + goto error); +#endif + el_dim = FN(EL,get_space(el)); + isl_assert(ctx, isl_space_is_equal(pw->dim, el_dim), goto error); + isl_assert(ctx, pw->n < pw->size, goto error); + + pw->p[pw->n].set = set; + pw->p[pw->n].FIELD = el; + pw->n++; + + isl_space_free(el_dim); + return pw; +error: + isl_space_free(el_dim); + FN(PW,free)(pw); + isl_set_free(set); + FN(EL,free)(el); + return NULL; +} + +/* Does the space of "set" correspond to that of the domain of "el". + */ +static isl_bool FN(PW,compatible_domain)(__isl_keep EL *el, + __isl_keep isl_set *set) +{ + isl_bool ok; + isl_space *el_space, *set_space; + + if (!set || !el) + return isl_bool_error; + set_space = isl_set_get_space(set); + el_space = FN(EL,get_space)(el); + ok = isl_space_is_domain_internal(set_space, el_space); + isl_space_free(el_space); + isl_space_free(set_space); + return ok; +} + +/* Check that the space of "set" corresponds to that of the domain of "el". + */ +static isl_stat FN(PW,check_compatible_domain)(__isl_keep EL *el, + __isl_keep isl_set *set) +{ + isl_bool ok; + + ok = FN(PW,compatible_domain)(el, set); + if (ok < 0) + return isl_stat_error; + if (!ok) + isl_die(isl_set_get_ctx(set), isl_error_invalid, + "incompatible spaces", return isl_stat_error); + + return isl_stat_ok; +} + +#ifdef HAS_TYPE +__isl_give PW *FN(PW,alloc)(enum isl_fold type, + __isl_take isl_set *set, __isl_take EL *el) +#else +__isl_give PW *FN(PW,alloc)(__isl_take isl_set *set, __isl_take EL *el) +#endif +{ + PW *pw; + + if (FN(PW,check_compatible_domain)(el, set) < 0) + goto error; + +#ifdef HAS_TYPE + pw = FN(PW,alloc_size)(FN(EL,get_space)(el), type, 1); +#else + pw = FN(PW,alloc_size)(FN(EL,get_space)(el), 1); +#endif + + return FN(PW,add_piece)(pw, set, el); +error: + isl_set_free(set); + FN(EL,free)(el); + return NULL; +} + +__isl_give PW *FN(PW,dup)(__isl_keep PW *pw) +{ + int i; + PW *dup; + + if (!pw) + return NULL; + +#ifdef HAS_TYPE + dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, pw->n); +#else + dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->n); +#endif + if (!dup) + return NULL; + + for (i = 0; i < pw->n; ++i) + dup = FN(PW,add_piece)(dup, isl_set_copy(pw->p[i].set), + FN(EL,copy)(pw->p[i].FIELD)); + + return dup; +} + +__isl_give PW *FN(PW,cow)(__isl_take PW *pw) +{ + if (!pw) + return NULL; + + if (pw->ref == 1) + return pw; + pw->ref--; + return FN(PW,dup)(pw); +} + +__isl_give PW *FN(PW,copy)(__isl_keep PW *pw) +{ + if (!pw) + return NULL; + + pw->ref++; + return pw; +} + +__isl_null PW *FN(PW,free)(__isl_take PW *pw) +{ + int i; + + if (!pw) + return NULL; + if (--pw->ref > 0) + return NULL; + + for (i = 0; i < pw->n; ++i) { + isl_set_free(pw->p[i].set); + FN(EL,free)(pw->p[i].FIELD); + } + isl_space_free(pw->dim); + free(pw); + + return NULL; +} + +const char *FN(PW,get_dim_name)(__isl_keep PW *pw, enum isl_dim_type type, + unsigned pos) +{ + return pw ? isl_space_get_dim_name(pw->dim, type, pos) : NULL; +} + +isl_bool FN(PW,has_dim_id)(__isl_keep PW *pw, enum isl_dim_type type, + unsigned pos) +{ + return pw ? isl_space_has_dim_id(pw->dim, type, pos) : isl_bool_error; +} + +__isl_give isl_id *FN(PW,get_dim_id)(__isl_keep PW *pw, enum isl_dim_type type, + unsigned pos) +{ + return pw ? isl_space_get_dim_id(pw->dim, type, pos) : NULL; +} + +isl_bool FN(PW,has_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type) +{ + return pw ? isl_space_has_tuple_name(pw->dim, type) : isl_bool_error; +} + +const char *FN(PW,get_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type) +{ + return pw ? isl_space_get_tuple_name(pw->dim, type) : NULL; +} + +isl_bool FN(PW,has_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type) +{ + return pw ? isl_space_has_tuple_id(pw->dim, type) : isl_bool_error; +} + +__isl_give isl_id *FN(PW,get_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type) +{ + return pw ? isl_space_get_tuple_id(pw->dim, type) : NULL; +} + +isl_bool FN(PW,IS_ZERO)(__isl_keep PW *pw) +{ + if (!pw) + return isl_bool_error; + + return pw->n == 0; +} + +#ifndef NO_REALIGN +__isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw, + __isl_take isl_reordering *exp) +{ + int i; + + pw = FN(PW,cow)(pw); + if (!pw || !exp) + goto error; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_realign(pw->p[i].set, + isl_reordering_copy(exp)); + if (!pw->p[i].set) + goto error; + pw->p[i].FIELD = FN(EL,realign_domain)(pw->p[i].FIELD, + isl_reordering_copy(exp)); + if (!pw->p[i].FIELD) + goto error; + } + + pw = FN(PW,reset_domain_space)(pw, isl_space_copy(exp->dim)); + + isl_reordering_free(exp); + return pw; +error: + isl_reordering_free(exp); + FN(PW,free)(pw); + return NULL; +} + +/* Align the parameters of "pw" to those of "model". + */ +__isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *model) +{ + isl_ctx *ctx; + isl_bool equal_params; + + if (!pw || !model) + goto error; + + ctx = isl_space_get_ctx(model); + if (!isl_space_has_named_params(model)) + isl_die(ctx, isl_error_invalid, + "model has unnamed parameters", goto error); + if (!isl_space_has_named_params(pw->dim)) + isl_die(ctx, isl_error_invalid, + "input has unnamed parameters", goto error); + equal_params = isl_space_has_equal_params(pw->dim, model); + if (equal_params < 0) + goto error; + if (!equal_params) { + isl_reordering *exp; + + model = isl_space_drop_dims(model, isl_dim_in, + 0, isl_space_dim(model, isl_dim_in)); + model = isl_space_drop_dims(model, isl_dim_out, + 0, isl_space_dim(model, isl_dim_out)); + exp = isl_parameter_alignment_reordering(pw->dim, model); + exp = isl_reordering_extend_space(exp, + FN(PW,get_domain_space)(pw)); + pw = FN(PW,realign_domain)(pw, exp); + } + + isl_space_free(model); + return pw; +error: + isl_space_free(model); + FN(PW,free)(pw); + return NULL; +} + +static __isl_give PW *FN(PW,align_params_pw_pw_and)(__isl_take PW *pw1, + __isl_take PW *pw2, + __isl_give PW *(*fn)(__isl_take PW *pw1, __isl_take PW *pw2)) +{ + isl_ctx *ctx; + isl_bool equal_params; + + if (!pw1 || !pw2) + goto error; + equal_params = isl_space_has_equal_params(pw1->dim, pw2->dim); + if (equal_params < 0) + goto error; + if (equal_params) + return fn(pw1, pw2); + ctx = FN(PW,get_ctx)(pw1); + if (!isl_space_has_named_params(pw1->dim) || + !isl_space_has_named_params(pw2->dim)) + isl_die(ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + pw1 = FN(PW,align_params)(pw1, FN(PW,get_space)(pw2)); + pw2 = FN(PW,align_params)(pw2, FN(PW,get_space)(pw1)); + return fn(pw1, pw2); +error: + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return NULL; +} + +static __isl_give PW *FN(PW,align_params_pw_set_and)(__isl_take PW *pw, + __isl_take isl_set *set, + __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_set *set)) +{ + isl_ctx *ctx; + isl_bool aligned; + + if (!pw || !set) + goto error; + aligned = isl_set_space_has_equal_params(set, pw->dim); + if (aligned < 0) + goto error; + if (aligned) + return fn(pw, set); + ctx = FN(PW,get_ctx)(pw); + if (!isl_space_has_named_params(pw->dim) || + !isl_space_has_named_params(set->dim)) + isl_die(ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + pw = FN(PW,align_params)(pw, isl_set_get_space(set)); + set = isl_set_align_params(set, FN(PW,get_space)(pw)); + return fn(pw, set); +error: + FN(PW,free)(pw); + isl_set_free(set); + return NULL; +} +#endif + +static __isl_give PW *FN(PW,union_add_aligned)(__isl_take PW *pw1, + __isl_take PW *pw2) +{ + int i, j, n; + struct PW *res; + isl_ctx *ctx; + isl_set *set; + + if (!pw1 || !pw2) + goto error; + + ctx = isl_space_get_ctx(pw1->dim); +#ifdef HAS_TYPE + if (pw1->type != pw2->type) + isl_die(ctx, isl_error_invalid, + "fold types don't match", goto error); +#endif + isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error); + + if (FN(PW,IS_ZERO)(pw1)) { + FN(PW,free)(pw1); + return pw2; + } + + if (FN(PW,IS_ZERO)(pw2)) { + FN(PW,free)(pw2); + return pw1; + } + + n = (pw1->n + 1) * (pw2->n + 1); +#ifdef HAS_TYPE + res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->type, n); +#else + res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), n); +#endif + + for (i = 0; i < pw1->n; ++i) { + set = isl_set_copy(pw1->p[i].set); + for (j = 0; j < pw2->n; ++j) { + struct isl_set *common; + EL *sum; + common = isl_set_intersect(isl_set_copy(pw1->p[i].set), + isl_set_copy(pw2->p[j].set)); + if (isl_set_plain_is_empty(common)) { + isl_set_free(common); + continue; + } + set = isl_set_subtract(set, + isl_set_copy(pw2->p[j].set)); + + sum = FN(EL,add_on_domain)(common, + FN(EL,copy)(pw1->p[i].FIELD), + FN(EL,copy)(pw2->p[j].FIELD)); + + res = FN(PW,add_piece)(res, common, sum); + } + res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD)); + } + + for (j = 0; j < pw2->n; ++j) { + set = isl_set_copy(pw2->p[j].set); + for (i = 0; i < pw1->n; ++i) + set = isl_set_subtract(set, + isl_set_copy(pw1->p[i].set)); + res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD)); + } + + FN(PW,free)(pw1); + FN(PW,free)(pw2); + + return res; +error: + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return NULL; +} + +/* Private version of "union_add". For isl_pw_qpolynomial and + * isl_pw_qpolynomial_fold, we prefer to simply call it "add". + */ +static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2) +{ + return FN(PW,align_params_pw_pw_and)(pw1, pw2, + &FN(PW,union_add_aligned)); +} + +/* Make sure "pw" has room for at least "n" more pieces. + * + * If there is only one reference to pw, we extend it in place. + * Otherwise, we create a new PW and copy the pieces. + */ +static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n) +{ + int i; + isl_ctx *ctx; + PW *res; + + if (!pw) + return NULL; + if (pw->n + n <= pw->size) + return pw; + ctx = FN(PW,get_ctx)(pw); + n += pw->n; + if (pw->ref == 1) { + res = isl_realloc(ctx, pw, struct PW, + sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece))); + if (!res) + return FN(PW,free)(pw); + res->size = n; + return res; + } +#ifdef HAS_TYPE + res = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, n); +#else + res = FN(PW,alloc_size)(isl_space_copy(pw->dim), n); +#endif + if (!res) + return FN(PW,free)(pw); + for (i = 0; i < pw->n; ++i) + res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set), + FN(EL,copy)(pw->p[i].FIELD)); + FN(PW,free)(pw); + return res; +} + +static __isl_give PW *FN(PW,add_disjoint_aligned)(__isl_take PW *pw1, + __isl_take PW *pw2) +{ + int i; + isl_ctx *ctx; + + if (!pw1 || !pw2) + goto error; + + if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n) + return FN(PW,add_disjoint_aligned)(pw2, pw1); + + ctx = isl_space_get_ctx(pw1->dim); +#ifdef HAS_TYPE + if (pw1->type != pw2->type) + isl_die(ctx, isl_error_invalid, + "fold types don't match", goto error); +#endif + isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error); + + if (FN(PW,IS_ZERO)(pw1)) { + FN(PW,free)(pw1); + return pw2; + } + + if (FN(PW,IS_ZERO)(pw2)) { + FN(PW,free)(pw2); + return pw1; + } + + pw1 = FN(PW,grow)(pw1, pw2->n); + if (!pw1) + goto error; + + for (i = 0; i < pw2->n; ++i) + pw1 = FN(PW,add_piece)(pw1, + isl_set_copy(pw2->p[i].set), + FN(EL,copy)(pw2->p[i].FIELD)); + + FN(PW,free)(pw2); + + return pw1; +error: + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return NULL; +} + +__isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2) +{ + return FN(PW,align_params_pw_pw_and)(pw1, pw2, + &FN(PW,add_disjoint_aligned)); +} + +/* This function is currently only used from isl_aff.c + */ +static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1, + __isl_take PW *pw2, __isl_take isl_space *space, + __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2)) + __attribute__ ((unused)); + +/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains. + * The result of "fn" (and therefore also of this function) lives in "space". + */ +static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1, + __isl_take PW *pw2, __isl_take isl_space *space, + __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2)) +{ + int i, j, n; + PW *res = NULL; + + if (!pw1 || !pw2) + goto error; + + n = pw1->n * pw2->n; +#ifdef HAS_TYPE + res = FN(PW,alloc_size)(isl_space_copy(space), pw1->type, n); +#else + res = FN(PW,alloc_size)(isl_space_copy(space), n); +#endif + + for (i = 0; i < pw1->n; ++i) { + for (j = 0; j < pw2->n; ++j) { + isl_set *common; + EL *res_ij; + int empty; + + common = isl_set_intersect( + isl_set_copy(pw1->p[i].set), + isl_set_copy(pw2->p[j].set)); + empty = isl_set_plain_is_empty(common); + if (empty < 0 || empty) { + isl_set_free(common); + if (empty < 0) + goto error; + continue; + } + + res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD), + FN(EL,copy)(pw2->p[j].FIELD)); + res_ij = FN(EL,gist)(res_ij, isl_set_copy(common)); + + res = FN(PW,add_piece)(res, common, res_ij); + } + } + + isl_space_free(space); + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return res; +error: + isl_space_free(space); + FN(PW,free)(pw1); + FN(PW,free)(pw2); + FN(PW,free)(res); + return NULL; +} + +/* This function is currently only used from isl_aff.c + */ +static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1, + __isl_take PW *pw2, + __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2)) + __attribute__ ((unused)); + +/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains. + * The result of "fn" is assumed to live in the same space as "pw1" and "pw2". + */ +static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1, + __isl_take PW *pw2, + __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2)) +{ + isl_space *space; + + if (!pw1 || !pw2) + goto error; + + space = isl_space_copy(pw1->dim); + return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn); +error: + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return NULL; +} + +#ifndef NO_NEG +__isl_give PW *FN(PW,neg)(__isl_take PW *pw) +{ + int i; + + if (!pw) + return NULL; + + if (FN(PW,IS_ZERO)(pw)) + return pw; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].FIELD = FN(EL,neg)(pw->p[i].FIELD); + if (!pw->p[i].FIELD) + return FN(PW,free)(pw); + } + + return pw; +} +#endif + +#ifndef NO_SUB +__isl_give PW *FN(PW,sub)(__isl_take PW *pw1, __isl_take PW *pw2) +{ + return FN(PW,add)(pw1, FN(PW,neg)(pw2)); +} +#endif + +#ifndef NO_EVAL +__isl_give isl_val *FN(PW,eval)(__isl_take PW *pw, __isl_take isl_point *pnt) +{ + int i; + int found = 0; + isl_ctx *ctx; + isl_space *pnt_dim = NULL; + isl_val *v; + + if (!pw || !pnt) + goto error; + ctx = isl_point_get_ctx(pnt); + pnt_dim = isl_point_get_space(pnt); + isl_assert(ctx, isl_space_is_domain_internal(pnt_dim, pw->dim), + goto error); + + for (i = 0; i < pw->n; ++i) { + found = isl_set_contains_point(pw->p[i].set, pnt); + if (found < 0) + goto error; + if (found) + break; + } + if (found) + v = FN(EL,eval)(FN(EL,copy)(pw->p[i].FIELD), + isl_point_copy(pnt)); + else + v = isl_val_zero(ctx); + FN(PW,free)(pw); + isl_space_free(pnt_dim); + isl_point_free(pnt); + return v; +error: + FN(PW,free)(pw); + isl_space_free(pnt_dim); + isl_point_free(pnt); + return NULL; +} +#endif + +/* Return the parameter domain of "pw". + */ +__isl_give isl_set *FN(PW,params)(__isl_take PW *pw) +{ + return isl_set_params(FN(PW,domain)(pw)); +} + +__isl_give isl_set *FN(PW,domain)(__isl_take PW *pw) +{ + int i; + isl_set *dom; + + if (!pw) + return NULL; + + dom = isl_set_empty(FN(PW,get_domain_space)(pw)); + for (i = 0; i < pw->n; ++i) + dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set)); + + FN(PW,free)(pw); + + return dom; +} + +/* Exploit the equalities in the domain of piece "i" of "pw" + * to simplify the associated function. + * If the domain of piece "i" is empty, then remove it entirely, + * replacing it with the final piece. + */ +static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw, + int i) +{ + isl_basic_set *aff; + int empty = isl_set_plain_is_empty(pw->p[i].set); + + if (empty < 0) + return -1; + if (empty) { + isl_set_free(pw->p[i].set); + FN(EL,free)(pw->p[i].FIELD); + if (i != pw->n - 1) + pw->p[i] = pw->p[pw->n - 1]; + pw->n--; + + return 0; + } + + 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 (!pw->p[i].FIELD) + return -1; + + return 0; +} + +/* Convert a piecewise expression defined over a parameter domain + * into one that is defined over a zero-dimensional set. + */ +__isl_give PW *FN(PW,from_range)(__isl_take PW *pw) +{ + isl_space *space; + + if (!pw) + return NULL; + if (!isl_space_is_set(pw->dim)) + isl_die(FN(PW,get_ctx)(pw), isl_error_invalid, + "not living in a set space", return FN(PW,free)(pw)); + + space = FN(PW,get_space)(pw); + space = isl_space_from_range(space); + pw = FN(PW,reset_space)(pw, space); + + return pw; +} + +/* Fix the value of the given parameter or domain dimension of "pw" + * to be equal to "value". + */ +__isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type, + unsigned pos, int value) +{ + int i; + + if (!pw) + return NULL; + + if (type == isl_dim_out) + isl_die(FN(PW,get_ctx)(pw), isl_error_invalid, + "cannot fix output dimension", return FN(PW,free)(pw)); + + if (pw->n == 0) + return pw; + + if (type == isl_dim_in) + type = isl_dim_set; + + pw = FN(PW,cow)(pw); + if (!pw) + return FN(PW,free)(pw); + + for (i = pw->n - 1; i >= 0; --i) { + pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value); + if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0) + return FN(PW,free)(pw); + } + + return pw; +} + +/* Restrict the domain of "pw" by combining each cell + * with "set" through a call to "fn", where "fn" may be + * isl_set_intersect, isl_set_intersect_params or isl_set_subtract. + */ +static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw, + __isl_take isl_set *set, + __isl_give isl_set *(*fn)(__isl_take isl_set *set1, + __isl_take isl_set *set2)) +{ + int i; + + if (!pw || !set) + goto error; + + if (pw->n == 0) { + isl_set_free(set); + return pw; + } + + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + + for (i = pw->n - 1; i >= 0; --i) { + pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set)); + if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0) + goto error; + } + + isl_set_free(set); + return pw; +error: + isl_set_free(set); + FN(PW,free)(pw); + return NULL; +} + +static __isl_give PW *FN(PW,intersect_domain_aligned)(__isl_take PW *pw, + __isl_take isl_set *set) +{ + return FN(PW,restrict_domain_aligned)(pw, set, &isl_set_intersect); +} + +__isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw, + __isl_take isl_set *context) +{ + return FN(PW,align_params_pw_set_and)(pw, context, + &FN(PW,intersect_domain_aligned)); +} + +static __isl_give PW *FN(PW,intersect_params_aligned)(__isl_take PW *pw, + __isl_take isl_set *set) +{ + return FN(PW,restrict_domain_aligned)(pw, set, + &isl_set_intersect_params); +} + +/* Intersect the domain of "pw" with the parameter domain "context". + */ +__isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw, + __isl_take isl_set *context) +{ + return FN(PW,align_params_pw_set_and)(pw, context, + &FN(PW,intersect_params_aligned)); +} + +/* Subtract "domain' from the domain of "pw", assuming their + * parameters have been aligned. + */ +static __isl_give PW *FN(PW,subtract_domain_aligned)(__isl_take PW *pw, + __isl_take isl_set *domain) +{ + return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract); +} + +/* Subtract "domain' from the domain of "pw". + */ +__isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw, + __isl_take isl_set *domain) +{ + return FN(PW,align_params_pw_set_and)(pw, domain, + &FN(PW,subtract_domain_aligned)); +} + +/* Compute the gist of "pw" with respect to the domain constraints + * of "context" for the case where the domain of the last element + * of "pw" is equal to "context". + * Call "fn_el" to compute the gist of this element, replace + * its domain by the universe and drop all other elements + * as their domains are necessarily disjoint from "context". + */ +static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw, + __isl_take isl_set *context, + __isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set)) +{ + int i; + isl_space *space; + + for (i = 0; i < pw->n - 1; ++i) { + isl_set_free(pw->p[i].set); + FN(EL,free)(pw->p[i].FIELD); + } + pw->p[0].FIELD = pw->p[pw->n - 1].FIELD; + pw->p[0].set = pw->p[pw->n - 1].set; + pw->n = 1; + + space = isl_set_get_space(context); + pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context); + context = isl_set_universe(space); + isl_set_free(pw->p[0].set); + pw->p[0].set = context; + + if (!pw->p[0].FIELD || !pw->p[0].set) + return FN(PW,free)(pw); + + return pw; +} + +/* Compute the gist of "pw" with respect to the domain constraints + * of "context". Call "fn_el" to compute the gist of the elements + * and "fn_dom" to compute the gist of the domains. + * + * If the piecewise expression is empty or the context is the universe, + * then nothing can be simplified. + */ +static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw, + __isl_take isl_set *context, + __isl_give EL *(*fn_el)(__isl_take EL *el, + __isl_take isl_set *set), + __isl_give isl_set *(*fn_dom)(__isl_take isl_set *set, + __isl_take isl_basic_set *bset)) +{ + int i; + int is_universe; + isl_bool aligned; + isl_basic_set *hull = NULL; + + if (!pw || !context) + goto error; + + if (pw->n == 0) { + isl_set_free(context); + return pw; + } + + is_universe = isl_set_plain_is_universe(context); + if (is_universe < 0) + goto error; + if (is_universe) { + isl_set_free(context); + return pw; + } + + aligned = isl_set_space_has_equal_params(context, pw->dim); + if (aligned < 0) + goto error; + if (!aligned) { + pw = FN(PW,align_params)(pw, isl_set_get_space(context)); + context = isl_set_align_params(context, FN(PW,get_space)(pw)); + } + + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + + if (pw->n == 1) { + int equal; + + equal = isl_set_plain_is_equal(pw->p[0].set, context); + if (equal < 0) + goto error; + if (equal) + return FN(PW,gist_last)(pw, context, fn_el); + } + + context = isl_set_compute_divs(context); + hull = isl_set_simple_hull(isl_set_copy(context)); + + for (i = pw->n - 1; i >= 0; --i) { + isl_set *set_i; + int empty; + + if (i == pw->n - 1) { + int equal; + equal = isl_set_plain_is_equal(pw->p[i].set, context); + if (equal < 0) + goto error; + if (equal) { + isl_basic_set_free(hull); + return FN(PW,gist_last)(pw, context, fn_el); + } + } + set_i = isl_set_intersect(isl_set_copy(pw->p[i].set), + isl_set_copy(context)); + empty = isl_set_plain_is_empty(set_i); + pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i); + pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull)); + if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set) + goto error; + if (empty) { + isl_set_free(pw->p[i].set); + FN(EL,free)(pw->p[i].FIELD); + if (i != pw->n - 1) + pw->p[i] = pw->p[pw->n - 1]; + pw->n--; + } + } + + isl_basic_set_free(hull); + isl_set_free(context); + + return pw; +error: + FN(PW,free)(pw); + isl_basic_set_free(hull); + isl_set_free(context); + return NULL; +} + +static __isl_give PW *FN(PW,gist_domain_aligned)(__isl_take PW *pw, + __isl_take isl_set *set) +{ + return FN(PW,gist_aligned)(pw, set, &FN(EL,gist), + &isl_set_gist_basic_set); +} + +__isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context) +{ + return FN(PW,align_params_pw_set_and)(pw, context, + &FN(PW,gist_domain_aligned)); +} + +static __isl_give PW *FN(PW,gist_params_aligned)(__isl_take PW *pw, + __isl_take isl_set *set) +{ + return FN(PW,gist_aligned)(pw, set, &FN(EL,gist_params), + &isl_set_gist_params_basic_set); +} + +__isl_give PW *FN(PW,gist_params)(__isl_take PW *pw, + __isl_take isl_set *context) +{ + return FN(PW,align_params_pw_set_and)(pw, context, + &FN(PW,gist_params_aligned)); +} + +/* Return -1 if the piece "p1" should be sorted before "p2" + * and 1 if it should be sorted after "p2". + * Return 0 if they do not need to be sorted in a specific order. + * + * The two pieces are compared on the basis of their function value expressions. + */ +static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg) +{ + struct FN(PW,piece) const *pc1 = p1; + struct FN(PW,piece) const *pc2 = p2; + + return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD); +} + +/* Sort the pieces of "pw" according to their function value + * expressions and then combine pairs of adjacent pieces with + * the same such expression. + * + * The sorting is performed in place because it does not + * change the meaning of "pw", but care needs to be + * taken not to change any possible other copies of "pw" + * in case anything goes wrong. + */ +__isl_give PW *FN(PW,sort)(__isl_take PW *pw) +{ + int i, j; + isl_set *set; + + if (!pw) + return NULL; + if (pw->n <= 1) + return pw; + if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]), + &FN(PW,sort_field_cmp), NULL) < 0) + return FN(PW,free)(pw); + for (i = pw->n - 1; i >= 1; --i) { + if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD)) + continue; + set = isl_set_union(isl_set_copy(pw->p[i - 1].set), + isl_set_copy(pw->p[i].set)); + if (!set) + return FN(PW,free)(pw); + isl_set_free(pw->p[i].set); + FN(EL,free)(pw->p[i].FIELD); + isl_set_free(pw->p[i - 1].set); + pw->p[i - 1].set = set; + for (j = i + 1; j < pw->n; ++j) + pw->p[j - 1] = pw->p[j]; + pw->n--; + } + + return pw; +} + +/* Coalesce the domains of "pw". + * + * Prior to the actual coalescing, first sort the pieces such that + * pieces with the same function value expression are combined + * into a single piece, the combined domain of which can then + * be coalesced. + */ +__isl_give PW *FN(PW,coalesce)(__isl_take PW *pw) +{ + int i; + + pw = FN(PW,sort)(pw); + if (!pw) + return NULL; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_coalesce(pw->p[i].set); + if (!pw->p[i].set) + goto error; + } + + return pw; +error: + FN(PW,free)(pw); + return NULL; +} + +isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw) +{ + return pw ? isl_space_get_ctx(pw->dim) : NULL; +} + +#ifndef NO_INVOLVES_DIMS +isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type, + unsigned first, unsigned n) +{ + int i; + enum isl_dim_type set_type; + + if (!pw) + return isl_bool_error; + if (pw->n == 0 || n == 0) + return isl_bool_false; + + set_type = type == isl_dim_in ? isl_dim_set : type; + + for (i = 0; i < pw->n; ++i) { + isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD, + type, first, n); + if (involves < 0 || involves) + return involves; + involves = isl_set_involves_dims(pw->p[i].set, + set_type, first, n); + if (involves < 0 || involves) + return involves; + } + return isl_bool_false; +} +#endif + +__isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw, + enum isl_dim_type type, unsigned pos, const char *s) +{ + int i; + enum isl_dim_type set_type; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + + set_type = type == isl_dim_in ? isl_dim_set : type; + + pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s); + if (!pw->dim) + goto error; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_set_dim_name(pw->p[i].set, + set_type, pos, s); + if (!pw->p[i].set) + goto error; + pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s); + if (!pw->p[i].FIELD) + goto error; + } + + return pw; +error: + FN(PW,free)(pw); + return NULL; +} + +#ifndef NO_DROP_DIMS +__isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + enum isl_dim_type set_type; + + if (!pw) + return NULL; + if (n == 0 && !isl_space_get_tuple_name(pw->dim, type)) + return pw; + + set_type = type == isl_dim_in ? isl_dim_set : type; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + pw->dim = isl_space_drop_dims(pw->dim, type, first, n); + if (!pw->dim) + goto error; + for (i = 0; i < pw->n; ++i) { + pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n); + if (!pw->p[i].FIELD) + goto error; + if (type == isl_dim_out) + continue; + pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n); + if (!pw->p[i].set) + goto error; + } + + return pw; +error: + FN(PW,free)(pw); + return NULL; +} + +/* This function is very similar to drop_dims. + * The only difference is that the cells may still involve + * the specified dimensions. They are removed using + * isl_set_project_out instead of isl_set_drop. + */ +__isl_give PW *FN(PW,project_out)(__isl_take PW *pw, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + enum isl_dim_type set_type; + + if (!pw) + return NULL; + if (n == 0 && !isl_space_get_tuple_name(pw->dim, type)) + return pw; + + set_type = type == isl_dim_in ? isl_dim_set : type; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + pw->dim = isl_space_drop_dims(pw->dim, type, first, n); + if (!pw->dim) + goto error; + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_project_out(pw->p[i].set, + set_type, first, n); + if (!pw->p[i].set) + goto error; + pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n); + if (!pw->p[i].FIELD) + goto error; + } + + return pw; +error: + FN(PW,free)(pw); + return NULL; +} + +/* Project the domain of pw onto its parameter space. + */ +__isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw) +{ + isl_space *space; + unsigned n; + + n = FN(PW,dim)(pw, isl_dim_in); + pw = FN(PW,project_out)(pw, isl_dim_in, 0, n); + space = FN(PW,get_domain_space)(pw); + space = isl_space_params(space); + pw = FN(PW,reset_domain_space)(pw, space); + return pw; +} +#endif + +#ifndef NO_INSERT_DIMS +__isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type, + unsigned first, unsigned n) +{ + int i; + enum isl_dim_type set_type; + + if (!pw) + return NULL; + if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type)) + return pw; + + set_type = type == isl_dim_in ? isl_dim_set : type; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + + pw->dim = isl_space_insert_dims(pw->dim, type, first, n); + if (!pw->dim) + goto error; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_insert_dims(pw->p[i].set, + set_type, first, n); + if (!pw->p[i].set) + goto error; + pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD, + type, first, n); + if (!pw->p[i].FIELD) + goto error; + } + + return pw; +error: + FN(PW,free)(pw); + return NULL; +} +#endif + +__isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw, + enum isl_dim_type type, unsigned pos, isl_int v) +{ + int i; + + if (!pw) + return NULL; + + if (type == isl_dim_in) + type = isl_dim_set; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v); + if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0) + return FN(PW,free)(pw); + } + + return pw; +} + +/* Fix the value of the variable at position "pos" of type "type" of "pw" + * to be equal to "v". + */ +__isl_give PW *FN(PW,fix_val)(__isl_take PW *pw, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) +{ + if (!v) + return FN(PW,free)(pw); + if (!isl_val_is_int(v)) + isl_die(FN(PW,get_ctx)(pw), isl_error_invalid, + "expecting integer value", goto error); + + pw = FN(PW,fix_dim)(pw, type, pos, v->n); + isl_val_free(v); + + return pw; +error: + isl_val_free(v); + return FN(PW,free)(pw); +} + +unsigned FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type) +{ + return pw ? isl_space_dim(pw->dim, type) : 0; +} + +__isl_give PW *FN(PW,split_dims)(__isl_take PW *pw, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + + if (!pw) + return NULL; + if (n == 0) + return pw; + + if (type == isl_dim_in) + type = isl_dim_set; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + if (!pw->dim) + goto error; + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n); + if (!pw->p[i].set) + goto error; + } + + return pw; +error: + FN(PW,free)(pw); + return NULL; +} + +#ifndef NO_OPT +/* Compute the maximal value attained by the piecewise quasipolynomial + * on its domain or zero if the domain is empty. + * In the worst case, the domain is scanned completely, + * so the domain is assumed to be bounded. + */ +__isl_give isl_val *FN(PW,opt)(__isl_take PW *pw, int max) +{ + int i; + isl_val *opt; + + if (!pw) + return NULL; + + if (pw->n == 0) { + opt = isl_val_zero(FN(PW,get_ctx)(pw)); + FN(PW,free)(pw); + return opt; + } + + opt = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[0].FIELD), + isl_set_copy(pw->p[0].set), max); + for (i = 1; i < pw->n; ++i) { + isl_val *opt_i; + opt_i = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[i].FIELD), + isl_set_copy(pw->p[i].set), max); + if (max) + opt = isl_val_max(opt, opt_i); + else + opt = isl_val_min(opt, opt_i); + } + + FN(PW,free)(pw); + return opt; +} + +__isl_give isl_val *FN(PW,max)(__isl_take PW *pw) +{ + return FN(PW,opt)(pw, 1); +} + +__isl_give isl_val *FN(PW,min)(__isl_take PW *pw) +{ + return FN(PW,opt)(pw, 0); +} +#endif + +__isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw) +{ + return pw ? isl_space_copy(pw->dim) : NULL; +} + +__isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw) +{ + return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL; +} + +/* Return the position of the dimension of the given type and name + * in "pw". + * Return -1 if no such dimension can be found. + */ +int FN(PW,find_dim_by_name)(__isl_keep PW *pw, + enum isl_dim_type type, const char *name) +{ + if (!pw) + return -1; + return isl_space_find_dim_by_name(pw->dim, type, name); +} + +#ifndef NO_RESET_DIM +/* Reset the space of "pw". Since we don't know if the elements + * represent the spaces themselves or their domains, we pass along + * both when we call their reset_space_and_domain. + */ +static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw, + __isl_take isl_space *space, __isl_take isl_space *domain) +{ + int i; + + pw = FN(PW,cow)(pw); + if (!pw || !space || !domain) + goto error; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_reset_space(pw->p[i].set, + isl_space_copy(domain)); + if (!pw->p[i].set) + goto error; + pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD, + isl_space_copy(space), isl_space_copy(domain)); + if (!pw->p[i].FIELD) + goto error; + } + + isl_space_free(domain); + + isl_space_free(pw->dim); + pw->dim = space; + + return pw; +error: + isl_space_free(domain); + isl_space_free(space); + FN(PW,free)(pw); + return NULL; +} + +__isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw, + __isl_take isl_space *domain) +{ + isl_space *space; + + space = isl_space_extend_domain_with_range(isl_space_copy(domain), + FN(PW,get_space)(pw)); + return FN(PW,reset_space_and_domain)(pw, space, domain); +} + +__isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim) +{ + isl_space *domain; + + domain = isl_space_domain(isl_space_copy(dim)); + return FN(PW,reset_space_and_domain)(pw, dim, domain); +} + +__isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type, + __isl_take isl_id *id) +{ + isl_space *space; + + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + + space = FN(PW,get_space)(pw); + space = isl_space_set_tuple_id(space, type, id); + + return FN(PW,reset_space)(pw, space); +error: + isl_id_free(id); + return FN(PW,free)(pw); +} + +/* Drop the id on the specified tuple. + */ +__isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type) +{ + isl_space *space; + + if (!pw) + return NULL; + if (!FN(PW,has_tuple_id)(pw, type)) + return pw; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + + space = FN(PW,get_space)(pw); + space = isl_space_reset_tuple_id(space, type); + + return FN(PW,reset_space)(pw, space); +} + +__isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) +{ + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id); + return FN(PW,reset_space)(pw, isl_space_copy(pw->dim)); +error: + isl_id_free(id); + return FN(PW,free)(pw); +} +#endif + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the space of "pw". + */ +__isl_give PW *FN(PW,reset_user)(__isl_take PW *pw) +{ + isl_space *space; + + space = FN(PW,get_space)(pw); + space = isl_space_reset_user(space); + + return FN(PW,reset_space)(pw, space); +} + +isl_bool FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2) +{ + if (!pw1 || !pw2) + return isl_bool_error; + + return isl_space_is_equal(pw1->dim, pw2->dim); +} + +#ifndef NO_MORPH +__isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw, + __isl_take isl_morph *morph) +{ + int i; + isl_ctx *ctx; + + if (!pw || !morph) + goto error; + + ctx = isl_space_get_ctx(pw->dim); + isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim), + goto error); + + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + pw->dim = isl_space_extend_domain_with_range( + isl_space_copy(morph->ran->dim), pw->dim); + if (!pw->dim) + goto error; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set); + if (!pw->p[i].set) + goto error; + pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD, + isl_morph_copy(morph)); + if (!pw->p[i].FIELD) + goto error; + } + + isl_morph_free(morph); + + return pw; +error: + FN(PW,free)(pw); + isl_morph_free(morph); + return NULL; +} +#endif + +int FN(PW,n_piece)(__isl_keep PW *pw) +{ + return pw ? pw->n : 0; +} + +isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw, + isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user), + void *user) +{ + int i; + + if (!pw) + return isl_stat_error; + + for (i = 0; i < pw->n; ++i) + if (fn(isl_set_copy(pw->p[i].set), + FN(EL,copy)(pw->p[i].FIELD), user) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +#ifndef NO_LIFT +static isl_bool any_divs(__isl_keep isl_set *set) +{ + int i; + + if (!set) + return isl_bool_error; + + for (i = 0; i < set->n; ++i) + if (set->p[i]->n_div > 0) + return isl_bool_true; + + return isl_bool_false; +} + +static isl_stat foreach_lifted_subset(__isl_take isl_set *set, + __isl_take EL *el, + isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, + void *user), void *user) +{ + int i; + + if (!set || !el) + goto error; + + for (i = 0; i < set->n; ++i) { + isl_set *lift; + EL *copy; + + lift = isl_set_from_basic_set(isl_basic_set_copy(set->p[i])); + lift = isl_set_lift(lift); + + copy = FN(EL,copy)(el); + copy = FN(EL,lift)(copy, isl_set_get_space(lift)); + + if (fn(lift, copy, user) < 0) + goto error; + } + + isl_set_free(set); + FN(EL,free)(el); + + return isl_stat_ok; +error: + isl_set_free(set); + FN(EL,free)(el); + return isl_stat_error; +} + +isl_stat FN(PW,foreach_lifted_piece)(__isl_keep PW *pw, + isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, + void *user), void *user) +{ + int i; + + if (!pw) + return isl_stat_error; + + for (i = 0; i < pw->n; ++i) { + isl_bool any; + isl_set *set; + EL *el; + + any = any_divs(pw->p[i].set); + if (any < 0) + return isl_stat_error; + set = isl_set_copy(pw->p[i].set); + el = FN(EL,copy)(pw->p[i].FIELD); + if (!any) { + if (fn(set, el, user) < 0) + return isl_stat_error; + continue; + } + if (foreach_lifted_subset(set, el, fn, user) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} +#endif + +#ifndef NO_MOVE_DIMS +__isl_give PW *FN(PW,move_dims)(__isl_take PW *pw, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + int i; + + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + + pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n); + if (!pw->dim) + goto error; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD, + dst_type, dst_pos, src_type, src_pos, n); + if (!pw->p[i].FIELD) + goto error; + } + + if (dst_type == isl_dim_in) + dst_type = isl_dim_set; + if (src_type == isl_dim_in) + src_type = isl_dim_set; + + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_move_dims(pw->p[i].set, + dst_type, dst_pos, + src_type, src_pos, n); + if (!pw->p[i].set) + goto error; + } + + return pw; +error: + FN(PW,free)(pw); + return NULL; +} +#endif + +__isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v) +{ + int i; + + if (isl_int_is_one(v)) + return pw; + if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) { + PW *zero; + isl_space *dim = FN(PW,get_space)(pw); +#ifdef HAS_TYPE + zero = FN(PW,ZERO)(dim, pw->type); +#else + zero = FN(PW,ZERO)(dim); +#endif + FN(PW,free)(pw); + return zero; + } + pw = FN(PW,cow)(pw); + if (!pw) + return NULL; + if (pw->n == 0) + return pw; + +#ifdef HAS_TYPE + if (isl_int_is_neg(v)) + pw->type = isl_fold_type_negate(pw->type); +#endif + for (i = 0; i < pw->n; ++i) { + pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v); + if (!pw->p[i].FIELD) + goto error; + } + + return pw; +error: + FN(PW,free)(pw); + return NULL; +} + +/* Multiply the pieces of "pw" by "v" and return the result. + */ +__isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v) +{ + int i; + + if (!pw || !v) + goto error; + + if (isl_val_is_one(v)) { + isl_val_free(v); + return pw; + } + if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) { + PW *zero; + isl_space *space = FN(PW,get_space)(pw); +#ifdef HAS_TYPE + zero = FN(PW,ZERO)(space, pw->type); +#else + zero = FN(PW,ZERO)(space); +#endif + FN(PW,free)(pw); + isl_val_free(v); + return zero; + } + if (pw->n == 0) { + isl_val_free(v); + return pw; + } + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + +#ifdef HAS_TYPE + if (isl_val_is_neg(v)) + pw->type = isl_fold_type_negate(pw->type); +#endif + for (i = 0; i < pw->n; ++i) { + pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD, + isl_val_copy(v)); + if (!pw->p[i].FIELD) + goto error; + } + + isl_val_free(v); + return pw; +error: + isl_val_free(v); + FN(PW,free)(pw); + return NULL; +} + +/* Divide the pieces of "pw" by "v" and return the result. + */ +__isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v) +{ + int i; + + if (!pw || !v) + goto error; + + if (isl_val_is_one(v)) { + isl_val_free(v); + return pw; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational factor", goto error); + if (isl_val_is_zero(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "cannot scale down by zero", goto error); + + if (pw->n == 0) { + isl_val_free(v); + return pw; + } + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + +#ifdef HAS_TYPE + if (isl_val_is_neg(v)) + pw->type = isl_fold_type_negate(pw->type); +#endif + for (i = 0; i < pw->n; ++i) { + pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD, + isl_val_copy(v)); + if (!pw->p[i].FIELD) + goto error; + } + + isl_val_free(v); + return pw; +error: + isl_val_free(v); + FN(PW,free)(pw); + return NULL; +} + +__isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v) +{ + return FN(PW,mul_isl_int)(pw, v); +} + +/* Apply some normalization to "pw". + * In particular, sort the pieces according to their function value + * expressions, combining pairs of adjacent pieces with + * the same such expression, and then normalize the domains of the pieces. + * + * We normalize in place, but if anything goes wrong we need + * to return NULL, so we need to make sure we don't change the + * meaning of any possible other copies of "pw". + */ +__isl_give PW *FN(PW,normalize)(__isl_take PW *pw) +{ + int i; + isl_set *set; + + pw = FN(PW,sort)(pw); + if (!pw) + return NULL; + for (i = 0; i < pw->n; ++i) { + set = isl_set_normalize(isl_set_copy(pw->p[i].set)); + if (!set) + return FN(PW,free)(pw); + isl_set_free(pw->p[i].set); + pw->p[i].set = set; + } + + return pw; +} + +/* Is pw1 obviously equal to pw2? + * That is, do they have obviously identical cells and obviously identical + * elements on each cell? + * + * If "pw1" or "pw2" contain any NaNs, then they are considered + * not to be the same. A NaN is not equal to anything, not even + * to another NaN. + */ +isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2) +{ + int i; + isl_bool equal, has_nan; + + if (!pw1 || !pw2) + return isl_bool_error; + + has_nan = FN(PW,involves_nan)(pw1); + if (has_nan >= 0 && !has_nan) + has_nan = FN(PW,involves_nan)(pw2); + if (has_nan < 0 || has_nan) + return isl_bool_not(has_nan); + + if (pw1 == pw2) + return isl_bool_true; + if (!isl_space_is_equal(pw1->dim, pw2->dim)) + return isl_bool_false; + + pw1 = FN(PW,copy)(pw1); + pw2 = FN(PW,copy)(pw2); + pw1 = FN(PW,normalize)(pw1); + pw2 = FN(PW,normalize)(pw2); + if (!pw1 || !pw2) + goto error; + + equal = pw1->n == pw2->n; + for (i = 0; equal && i < pw1->n; ++i) { + equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set); + if (equal < 0) + goto error; + if (!equal) + break; + equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD); + if (equal < 0) + goto error; + } + + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return equal; +error: + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return isl_bool_error; +} + +/* Does "pw" involve any NaNs? + */ +isl_bool FN(PW,involves_nan)(__isl_keep PW *pw) +{ + int i; + + if (!pw) + return isl_bool_error; + if (pw->n == 0) + return isl_bool_false; + + for (i = 0; i < pw->n; ++i) { + isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD); + if (has_nan < 0 || has_nan) + return has_nan; + } + + return isl_bool_false; +} + +#ifndef NO_PULLBACK +static __isl_give PW *FN(PW,align_params_pw_multi_aff_and)(__isl_take PW *pw, + __isl_take isl_multi_aff *ma, + __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_multi_aff *ma)) +{ + isl_ctx *ctx; + isl_bool equal_params; + isl_space *ma_space; + + ma_space = isl_multi_aff_get_space(ma); + if (!pw || !ma || !ma_space) + goto error; + equal_params = isl_space_has_equal_params(pw->dim, ma_space); + if (equal_params < 0) + goto error; + if (equal_params) { + isl_space_free(ma_space); + return fn(pw, ma); + } + ctx = FN(PW,get_ctx)(pw); + if (!isl_space_has_named_params(pw->dim) || + !isl_space_has_named_params(ma_space)) + isl_die(ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + pw = FN(PW,align_params)(pw, ma_space); + ma = isl_multi_aff_align_params(ma, FN(PW,get_space)(pw)); + return fn(pw, ma); +error: + isl_space_free(ma_space); + FN(PW,free)(pw); + isl_multi_aff_free(ma); + return NULL; +} + +static __isl_give PW *FN(PW,align_params_pw_pw_multi_aff_and)(__isl_take PW *pw, + __isl_take isl_pw_multi_aff *pma, + __isl_give PW *(*fn)(__isl_take PW *pw, + __isl_take isl_pw_multi_aff *ma)) +{ + isl_ctx *ctx; + isl_bool equal_params; + isl_space *pma_space; + + pma_space = isl_pw_multi_aff_get_space(pma); + if (!pw || !pma || !pma_space) + goto error; + equal_params = isl_space_has_equal_params(pw->dim, pma_space); + if (equal_params < 0) + goto error; + if (equal_params) { + isl_space_free(pma_space); + return fn(pw, pma); + } + ctx = FN(PW,get_ctx)(pw); + if (!isl_space_has_named_params(pw->dim) || + !isl_space_has_named_params(pma_space)) + isl_die(ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + pw = FN(PW,align_params)(pw, pma_space); + pma = isl_pw_multi_aff_align_params(pma, FN(PW,get_space)(pw)); + return fn(pw, pma); +error: + isl_space_free(pma_space); + FN(PW,free)(pw); + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* Compute the pullback of "pw" by the function represented by "ma". + * In other words, plug in "ma" in "pw". + */ +static __isl_give PW *FN(PW,pullback_multi_aff_aligned)(__isl_take PW *pw, + __isl_take isl_multi_aff *ma) +{ + int i; + isl_space *space = NULL; + + ma = isl_multi_aff_align_divs(ma); + pw = FN(PW,cow)(pw); + if (!pw || !ma) + goto error; + + space = isl_space_join(isl_multi_aff_get_space(ma), + FN(PW,get_space)(pw)); + + for (i = 0; i < pw->n; ++i) { + pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set, + isl_multi_aff_copy(ma)); + if (!pw->p[i].set) + goto error; + pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD, + isl_multi_aff_copy(ma)); + if (!pw->p[i].FIELD) + goto error; + } + + pw = FN(PW,reset_space)(pw, space); + isl_multi_aff_free(ma); + return pw; +error: + isl_space_free(space); + isl_multi_aff_free(ma); + FN(PW,free)(pw); + return NULL; +} + +__isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw, + __isl_take isl_multi_aff *ma) +{ + return FN(PW,align_params_pw_multi_aff_and)(pw, ma, + &FN(PW,pullback_multi_aff_aligned)); +} + +/* Compute the pullback of "pw" by the function represented by "pma". + * In other words, plug in "pma" in "pw". + */ +static __isl_give PW *FN(PW,pullback_pw_multi_aff_aligned)(__isl_take PW *pw, + __isl_take isl_pw_multi_aff *pma) +{ + int i; + PW *res; + + if (!pma) + goto error; + + if (pma->n == 0) { + isl_space *space; + space = isl_space_join(isl_pw_multi_aff_get_space(pma), + FN(PW,get_space)(pw)); + isl_pw_multi_aff_free(pma); + res = FN(PW,empty)(space); + FN(PW,free)(pw); + return res; + } + + res = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw), + isl_multi_aff_copy(pma->p[0].maff)); + res = FN(PW,intersect_domain)(res, isl_set_copy(pma->p[0].set)); + + for (i = 1; i < pma->n; ++i) { + PW *res_i; + + res_i = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw), + isl_multi_aff_copy(pma->p[i].maff)); + res_i = FN(PW,intersect_domain)(res_i, + isl_set_copy(pma->p[i].set)); + res = FN(PW,add_disjoint)(res, res_i); + } + + isl_pw_multi_aff_free(pma); + FN(PW,free)(pw); + return res; +error: + isl_pw_multi_aff_free(pma); + FN(PW,free)(pw); + return NULL; +} + +__isl_give PW *FN(PW,pullback_pw_multi_aff)(__isl_take PW *pw, + __isl_take isl_pw_multi_aff *pma) +{ + return FN(PW,align_params_pw_pw_multi_aff_and)(pw, pma, + &FN(PW,pullback_pw_multi_aff_aligned)); +} +#endif Index: contrib/isl/isl_pw_union_opt.c =================================================================== --- /dev/null +++ contrib/isl/isl_pw_union_opt.c @@ -0,0 +1,253 @@ +/* + * Copyright 2011 INRIA Saclay + * Copyright 2012 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include + +/* Given a function "cmp" that returns the set of elements where + * "el1" is "better" than "el2", return this set. + */ +static __isl_give isl_set *FN(PW,better)(__isl_keep EL *el1, __isl_keep EL *el2, + __isl_give isl_set *(*cmp)(__isl_take EL *el1, __isl_take EL *el2)) +{ + return cmp(FN(EL,copy)(el1), FN(EL,copy)(el2)); +} + +/* Return a list containing the domains of the pieces of "pw". + */ +static __isl_give isl_set_list *FN(PW,extract_domains)(__isl_keep PW *pw) +{ + int i; + isl_ctx *ctx; + isl_set_list *list; + + if (!pw) + return NULL; + ctx = FN(PW,get_ctx)(pw); + list = isl_set_list_alloc(ctx, pw->n); + for (i = 0; i < pw->n; ++i) + list = isl_set_list_add(list, isl_set_copy(pw->p[i].set)); + + return list; +} + +/* Given sets B ("set"), C ("better") and A' ("out"), return + * + * (B \cap C) \cup ((B \setminus C) \setminus A') + */ +static __isl_give isl_set *FN(PW,better_or_out)(__isl_take isl_set *set, + __isl_take isl_set *better, __isl_take isl_set *out) +{ + isl_set *set_better, *set_out; + + set_better = isl_set_intersect(isl_set_copy(set), isl_set_copy(better)); + set_out = isl_set_subtract(isl_set_subtract(set, better), out); + + return isl_set_union(set_better, set_out); +} + +/* Given sets A ("set"), C ("better") and B' ("out"), return + * + * (A \setminus C) \cup ((A \cap C) \setminus B') + */ +static __isl_give isl_set *FN(PW,worse_or_out)(__isl_take isl_set *set, + __isl_take isl_set *better, __isl_take isl_set *out) +{ + isl_set *set_worse, *set_out; + + set_worse = isl_set_subtract(isl_set_copy(set), isl_set_copy(better)); + set_out = isl_set_subtract(isl_set_intersect(set, better), out); + + return isl_set_union(set_worse, set_out); +} + +/* Given two piecewise expressions "pw1" and "pw2", replace their domains + * by the sets in "list1" and "list2" and combine the results into + * a single piecewise expression. + * The pieces of "pw1" and "pw2" are assumed to have been sorted + * according to the function value expressions. + * The pieces of the result are also sorted in this way. + * + * Run through the pieces of "pw1" and "pw2" in order until they + * have both been exhausted, picking the piece from "pw1" or "pw2" + * depending on which should come first, together with the corresponding + * domain from "list1" or "list2". In cases where the next pieces + * in both "pw1" and "pw2" have the same function value expression, + * construct only a single piece in the result with as domain + * the union of the domains in "list1" and "list2". + */ +static __isl_give PW *FN(PW,merge)(__isl_take PW *pw1, __isl_take PW *pw2, + __isl_take isl_set_list *list1, __isl_take isl_set_list *list2) +{ + int i, j; + PW *res; + + if (!pw1 || !pw2) + goto error; + + res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->n + pw2->n); + + i = 0; j = 0; + while (i < pw1->n || j < pw2->n) { + int cmp; + isl_set *set; + EL *el; + + if (i < pw1->n && j < pw2->n) + cmp = FN(EL,plain_cmp)(pw1->p[i].FIELD, + pw2->p[j].FIELD); + else + cmp = i < pw1->n ? -1 : 1; + + if (cmp < 0) { + set = isl_set_list_get_set(list1, i); + el = FN(EL,copy)(pw1->p[i].FIELD); + ++i; + } else if (cmp > 0) { + set = isl_set_list_get_set(list2, j); + el = FN(EL,copy)(pw2->p[j].FIELD); + ++j; + } else { + set = isl_set_union(isl_set_list_get_set(list1, i), + isl_set_list_get_set(list2, j)); + el = FN(EL,copy)(pw1->p[i].FIELD); + ++i; + ++j; + } + res = FN(PW,add_piece)(res, set, el); + } + + isl_set_list_free(list1); + isl_set_list_free(list2); + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return res; +error: + isl_set_list_free(list1); + isl_set_list_free(list2); + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return NULL; +} + +/* Given a function "cmp" that returns the set of elements where + * "el1" is "better" than "el2", return a piecewise + * expression defined on the union of the definition domains + * of "pw1" and "pw2" that maps to the "best" of "pw1" and + * "pw2" on each cell. If only one of the two input functions + * is defined on a given cell, then it is considered the best. + * + * Run through all pairs of pieces in "pw1" and "pw2". + * If the domains of these pieces intersect, then the intersection + * needs to be distributed over the two pieces based on "cmp". + * Let C be the set where the piece from "pw2" is better (according to "cmp") + * than the piece from "pw1". Let A be the domain of the piece from "pw1" and + * B the domain of the piece from "pw2". + * + * The elements in C need to be removed from A, except for those parts + * that lie outside of B. That is, + * + * A <- (A \setminus C) \cup ((A \cap C) \setminus B') + * + * Conversely, the elements in B need to be restricted to C, except + * for those parts that lie outside of A. That is + * + * B <- (B \cap C) \cup ((B \setminus C) \setminus A') + * + * Since all pairs of pieces are considered, the domains are updated + * several times. A and B refer to these updated domains + * (kept track of in "list1" and "list2"), while A' and B' refer + * to the original domains of the pieces. It is safe to use these + * original domains because the difference between, say, A' and A is + * the domains of pw2-pieces that have been removed before and + * those domains are disjoint from B. A' is used instead of A + * because the continued updating of A may result in this domain + * getting broken up into more disjuncts. + * + * After the updated domains have been computed, the result is constructed + * from "pw1", "pw2", "list1" and "list2". If there are any pieces + * in "pw1" and "pw2" with the same function value expression, then + * they are combined into a single piece in the result. + * In order to be able to do this efficiently, the pieces of "pw1" and + * "pw2" are first sorted according to their function value expressions. + */ +static __isl_give PW *FN(PW,union_opt_cmp)( + __isl_take PW *pw1, __isl_take PW *pw2, + __isl_give isl_set *(*cmp)(__isl_take EL *el1, __isl_take EL *el2)) +{ + int i, j; + PW *res = NULL; + isl_ctx *ctx; + isl_set *set = NULL; + isl_set_list *list1 = NULL, *list2 = NULL; + + if (!pw1 || !pw2) + goto error; + + ctx = isl_space_get_ctx(pw1->dim); + if (!isl_space_is_equal(pw1->dim, pw2->dim)) + isl_die(ctx, isl_error_invalid, + "arguments should live in the same space", goto error); + + if (FN(PW,is_empty)(pw1)) { + FN(PW,free)(pw1); + return pw2; + } + + if (FN(PW,is_empty)(pw2)) { + FN(PW,free)(pw2); + return pw1; + } + + pw1 = FN(PW,sort)(pw1); + pw2 = FN(PW,sort)(pw2); + if (!pw1 || !pw2) + goto error; + + list1 = FN(PW,extract_domains)(pw1); + list2 = FN(PW,extract_domains)(pw2); + + for (i = 0; i < pw1->n; ++i) { + for (j = 0; j < pw2->n; ++j) { + isl_bool disjoint; + isl_set *better, *set_i, *set_j; + + disjoint = isl_set_is_disjoint(pw1->p[i].set, + pw2->p[j].set); + if (disjoint < 0) + goto error; + if (disjoint) + continue; + better = FN(PW,better)(pw2->p[j].FIELD, + pw1->p[i].FIELD, cmp); + set_i = isl_set_list_get_set(list1, i); + set_j = isl_set_copy(pw2->p[j].set); + set_i = FN(PW,worse_or_out)(set_i, + isl_set_copy(better), set_j); + list1 = isl_set_list_set_set(list1, i, set_i); + set_i = isl_set_copy(pw1->p[i].set); + set_j = isl_set_list_get_set(list2, j); + set_j = FN(PW,better_or_out)(set_j, better, set_i); + list2 = isl_set_list_set_set(list2, j, set_j); + } + } + + res = FN(PW,merge)(pw1, pw2, list1, list2); + + return res; +error: + isl_set_list_free(list1); + isl_set_list_free(list2); + FN(PW,free)(pw1); + FN(PW,free)(pw2); + isl_set_free(set); + return FN(PW,free)(res); +} Index: contrib/isl/isl_range.h =================================================================== --- /dev/null +++ contrib/isl/isl_range.h @@ -0,0 +1,6 @@ +#include + +isl_stat isl_qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, struct isl_bound *bound); +__isl_give isl_qpolynomial *isl_qpolynomial_terms_of_sign( + __isl_keep isl_qpolynomial *poly, int *signs, int sign); Index: contrib/isl/isl_range.c =================================================================== --- /dev/null +++ contrib/isl/isl_range.c @@ -0,0 +1,541 @@ +#include +#include +#include +#include +#include +#include +#include + +struct range_data { + struct isl_bound *bound; + int *signs; + int sign; + int test_monotonicity; + int monotonicity; + int tight; + isl_qpolynomial *poly; + isl_pw_qpolynomial_fold *pwf; + isl_pw_qpolynomial_fold *pwf_tight; +}; + +static isl_stat propagate_on_domain(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, struct range_data *data); + +/* Check whether the polynomial "poly" has sign "sign" over "bset", + * i.e., if sign == 1, check that the lower bound on the polynomial + * is non-negative and if sign == -1, check that the upper bound on + * the polynomial is non-positive. + */ +static int has_sign(__isl_keep isl_basic_set *bset, + __isl_keep isl_qpolynomial *poly, int sign, int *signs) +{ + struct range_data data_m; + unsigned nparam; + isl_space *dim; + isl_val *opt; + int r; + enum isl_fold type; + + nparam = isl_basic_set_dim(bset, isl_dim_param); + + bset = isl_basic_set_copy(bset); + poly = isl_qpolynomial_copy(poly); + + bset = isl_basic_set_move_dims(bset, isl_dim_set, 0, + isl_dim_param, 0, nparam); + poly = isl_qpolynomial_move_dims(poly, isl_dim_in, 0, + isl_dim_param, 0, nparam); + + dim = isl_qpolynomial_get_space(poly); + dim = isl_space_params(dim); + dim = isl_space_from_domain(dim); + dim = isl_space_add_dims(dim, isl_dim_out, 1); + + data_m.test_monotonicity = 0; + data_m.signs = signs; + data_m.sign = -sign; + type = data_m.sign < 0 ? isl_fold_min : isl_fold_max; + data_m.pwf = isl_pw_qpolynomial_fold_zero(dim, type); + data_m.tight = 0; + data_m.pwf_tight = NULL; + + if (propagate_on_domain(bset, poly, &data_m) < 0) + goto error; + + if (sign > 0) + opt = isl_pw_qpolynomial_fold_min(data_m.pwf); + else + opt = isl_pw_qpolynomial_fold_max(data_m.pwf); + + if (!opt) + r = -1; + else if (isl_val_is_nan(opt) || + isl_val_is_infty(opt) || + isl_val_is_neginfty(opt)) + r = 0; + else + r = sign * isl_val_sgn(opt) >= 0; + + isl_val_free(opt); + + return r; +error: + isl_pw_qpolynomial_fold_free(data_m.pwf); + return -1; +} + +/* Return 1 if poly is monotonically increasing in the last set variable, + * -1 if poly is monotonically decreasing in the last set variable, + * 0 if no conclusion, + * -2 on error. + * + * We simply check the sign of p(x+1)-p(x) + */ +static int monotonicity(__isl_keep isl_basic_set *bset, + __isl_keep isl_qpolynomial *poly, struct range_data *data) +{ + isl_ctx *ctx; + isl_space *dim; + isl_qpolynomial *sub = NULL; + isl_qpolynomial *diff = NULL; + int result = 0; + int s; + unsigned nvar; + + ctx = isl_qpolynomial_get_ctx(poly); + dim = isl_qpolynomial_get_domain_space(poly); + + nvar = isl_basic_set_dim(bset, isl_dim_set); + + sub = isl_qpolynomial_var_on_domain(isl_space_copy(dim), isl_dim_set, nvar - 1); + sub = isl_qpolynomial_add(sub, + isl_qpolynomial_rat_cst_on_domain(dim, ctx->one, ctx->one)); + + diff = isl_qpolynomial_substitute(isl_qpolynomial_copy(poly), + isl_dim_in, nvar - 1, 1, &sub); + diff = isl_qpolynomial_sub(diff, isl_qpolynomial_copy(poly)); + + s = has_sign(bset, diff, 1, data->signs); + if (s < 0) + goto error; + if (s) + result = 1; + else { + s = has_sign(bset, diff, -1, data->signs); + if (s < 0) + goto error; + if (s) + result = -1; + } + + isl_qpolynomial_free(diff); + isl_qpolynomial_free(sub); + + return result; +error: + isl_qpolynomial_free(diff); + isl_qpolynomial_free(sub); + return -2; +} + +/* Return a positive ("sign" > 0) or negative ("sign" < 0) infinite polynomial + * with domain space "space". + */ +static __isl_give isl_qpolynomial *signed_infty(__isl_take isl_space *space, + int sign) +{ + if (sign > 0) + return isl_qpolynomial_infty_on_domain(space); + else + return isl_qpolynomial_neginfty_on_domain(space); +} + +static __isl_give isl_qpolynomial *bound2poly(__isl_take isl_constraint *bound, + __isl_take isl_space *space, unsigned pos, int sign) +{ + if (!bound) + return signed_infty(space, sign); + isl_space_free(space); + return isl_qpolynomial_from_constraint(bound, isl_dim_set, pos); +} + +static int bound_is_integer(__isl_take isl_constraint *bound, unsigned pos) +{ + isl_int c; + int is_int; + + if (!bound) + return 1; + + isl_int_init(c); + isl_constraint_get_coefficient(bound, isl_dim_set, pos, &c); + is_int = isl_int_is_one(c) || isl_int_is_negone(c); + isl_int_clear(c); + + return is_int; +} + +struct isl_fixed_sign_data { + int *signs; + int sign; + isl_qpolynomial *poly; +}; + +/* Add term "term" to data->poly if it has sign data->sign. + * The sign is determined based on the signs of the parameters + * and variables in data->signs. The integer divisions, if + * any, are assumed to be non-negative. + */ +static isl_stat collect_fixed_sign_terms(__isl_take isl_term *term, void *user) +{ + struct isl_fixed_sign_data *data = (struct isl_fixed_sign_data *)user; + isl_int n; + int i; + int sign; + unsigned nparam; + unsigned nvar; + + if (!term) + return isl_stat_error; + + nparam = isl_term_dim(term, isl_dim_param); + nvar = isl_term_dim(term, isl_dim_set); + + isl_int_init(n); + + isl_term_get_num(term, &n); + + sign = isl_int_sgn(n); + for (i = 0; i < nparam; ++i) { + if (data->signs[i] > 0) + continue; + if (isl_term_get_exp(term, isl_dim_param, i) % 2) + sign = -sign; + } + for (i = 0; i < nvar; ++i) { + if (data->signs[nparam + i] > 0) + continue; + if (isl_term_get_exp(term, isl_dim_set, i) % 2) + sign = -sign; + } + + if (sign == data->sign) { + isl_qpolynomial *t = isl_qpolynomial_from_term(term); + + data->poly = isl_qpolynomial_add(data->poly, t); + } else + isl_term_free(term); + + isl_int_clear(n); + + return isl_stat_ok; +} + +/* Construct and return a polynomial that consists of the terms + * in "poly" that have sign "sign". The integer divisions, if + * any, are assumed to be non-negative. + */ +__isl_give isl_qpolynomial *isl_qpolynomial_terms_of_sign( + __isl_keep isl_qpolynomial *poly, int *signs, int sign) +{ + isl_space *space; + struct isl_fixed_sign_data data = { signs, sign }; + + space = isl_qpolynomial_get_domain_space(poly); + data.poly = isl_qpolynomial_zero_on_domain(space); + + if (isl_qpolynomial_foreach_term(poly, collect_fixed_sign_terms, &data) < 0) + goto error; + + return data.poly; +error: + isl_qpolynomial_free(data.poly); + return NULL; +} + +/* Helper function to add a guarded polynomial to either pwf_tight or pwf, + * depending on whether the result has been determined to be tight. + */ +static isl_stat add_guarded_poly(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, struct range_data *data) +{ + enum isl_fold type = data->sign < 0 ? isl_fold_min : isl_fold_max; + isl_set *set; + isl_qpolynomial_fold *fold; + isl_pw_qpolynomial_fold *pwf; + + bset = isl_basic_set_params(bset); + poly = isl_qpolynomial_project_domain_on_params(poly); + + fold = isl_qpolynomial_fold_alloc(type, poly); + set = isl_set_from_basic_set(bset); + pwf = isl_pw_qpolynomial_fold_alloc(type, set, fold); + if (data->tight) + data->pwf_tight = isl_pw_qpolynomial_fold_fold( + data->pwf_tight, pwf); + else + data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, pwf); + + return isl_stat_ok; +} + +/* Plug in "sub" for the variable at position "pos" in "poly". + * + * If "sub" is an infinite polynomial and if the variable actually + * appears in "poly", then calling isl_qpolynomial_substitute + * to perform the substitution may result in a NaN result. + * In such cases, return positive or negative infinity instead, + * depending on whether an upper bound or a lower bound is being computed, + * and mark the result as not being tight. + */ +static __isl_give isl_qpolynomial *plug_in_at_pos( + __isl_take isl_qpolynomial *poly, int pos, + __isl_take isl_qpolynomial *sub, struct range_data *data) +{ + isl_bool involves, infty; + + involves = isl_qpolynomial_involves_dims(poly, isl_dim_in, pos, 1); + if (involves < 0) + goto error; + if (!involves) { + isl_qpolynomial_free(sub); + return poly; + } + + infty = isl_qpolynomial_is_infty(sub); + if (infty >= 0 && !infty) + infty = isl_qpolynomial_is_neginfty(sub); + if (infty < 0) + goto error; + if (infty) { + isl_space *space = isl_qpolynomial_get_domain_space(poly); + data->tight = 0; + isl_qpolynomial_free(poly); + isl_qpolynomial_free(sub); + return signed_infty(space, data->sign); + } + + poly = isl_qpolynomial_substitute(poly, isl_dim_in, pos, 1, &sub); + isl_qpolynomial_free(sub); + + return poly; +error: + isl_qpolynomial_free(poly); + isl_qpolynomial_free(sub); + return NULL; +} + +/* Given a lower and upper bound on the final variable and constraints + * on the remaining variables where these bounds are active, + * eliminate the variable from data->poly based on these bounds. + * If the polynomial has been determined to be monotonic + * in the variable, then simply plug in the appropriate bound. + * If the current polynomial is tight and if this bound is integer, + * then the result is still tight. In all other cases, the results + * may not be tight. + * Otherwise, plug in the largest bound (in absolute value) in + * the positive terms (if an upper bound is wanted) or the negative terms + * (if a lower bounded is wanted) and the other bound in the other terms. + * + * If all variables have been eliminated, then record the result. + * Ohterwise, recurse on the next variable. + */ +static isl_stat propagate_on_bound_pair(__isl_take isl_constraint *lower, + __isl_take isl_constraint *upper, __isl_take isl_basic_set *bset, + void *user) +{ + struct range_data *data = (struct range_data *)user; + int save_tight = data->tight; + isl_qpolynomial *poly; + isl_stat r; + unsigned nvar; + + nvar = isl_basic_set_dim(bset, isl_dim_set); + + if (data->monotonicity) { + isl_qpolynomial *sub; + isl_space *dim = isl_qpolynomial_get_domain_space(data->poly); + if (data->monotonicity * data->sign > 0) { + if (data->tight) + data->tight = bound_is_integer(upper, nvar); + sub = bound2poly(upper, dim, nvar, 1); + isl_constraint_free(lower); + } else { + if (data->tight) + data->tight = bound_is_integer(lower, nvar); + sub = bound2poly(lower, dim, nvar, -1); + isl_constraint_free(upper); + } + poly = isl_qpolynomial_copy(data->poly); + poly = plug_in_at_pos(poly, nvar, sub, data); + poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, nvar, 1); + } else { + isl_qpolynomial *l, *u; + isl_qpolynomial *pos, *neg; + isl_space *dim = isl_qpolynomial_get_domain_space(data->poly); + unsigned nparam = isl_basic_set_dim(bset, isl_dim_param); + int sign = data->sign * data->signs[nparam + nvar]; + + data->tight = 0; + + u = bound2poly(upper, isl_space_copy(dim), nvar, 1); + l = bound2poly(lower, dim, nvar, -1); + + pos = isl_qpolynomial_terms_of_sign(data->poly, data->signs, sign); + neg = isl_qpolynomial_terms_of_sign(data->poly, data->signs, -sign); + + pos = plug_in_at_pos(pos, nvar, u, data); + neg = plug_in_at_pos(neg, nvar, l, data); + + poly = isl_qpolynomial_add(pos, neg); + poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, nvar, 1); + } + + if (isl_basic_set_dim(bset, isl_dim_set) == 0) + r = add_guarded_poly(bset, poly, data); + else + r = propagate_on_domain(bset, poly, data); + + data->tight = save_tight; + + return r; +} + +/* Recursively perform range propagation on the polynomial "poly" + * defined over the basic set "bset" and collect the results in "data". + */ +static isl_stat propagate_on_domain(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, struct range_data *data) +{ + isl_ctx *ctx; + isl_qpolynomial *save_poly = data->poly; + int save_monotonicity = data->monotonicity; + unsigned d; + + if (!bset || !poly) + goto error; + + ctx = isl_basic_set_get_ctx(bset); + d = isl_basic_set_dim(bset, isl_dim_set); + isl_assert(ctx, d >= 1, goto error); + + if (isl_qpolynomial_is_cst(poly, NULL, NULL)) { + bset = isl_basic_set_project_out(bset, isl_dim_set, 0, d); + poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, 0, d); + return add_guarded_poly(bset, poly, data); + } + + if (data->test_monotonicity) + data->monotonicity = monotonicity(bset, poly, data); + else + data->monotonicity = 0; + if (data->monotonicity < -1) + goto error; + + data->poly = poly; + if (isl_basic_set_foreach_bound_pair(bset, isl_dim_set, d - 1, + &propagate_on_bound_pair, data) < 0) + goto error; + + isl_basic_set_free(bset); + isl_qpolynomial_free(poly); + data->monotonicity = save_monotonicity; + data->poly = save_poly; + + return isl_stat_ok; +error: + isl_basic_set_free(bset); + isl_qpolynomial_free(poly); + data->monotonicity = save_monotonicity; + data->poly = save_poly; + return isl_stat_error; +} + +static isl_stat basic_guarded_poly_bound(__isl_take isl_basic_set *bset, + void *user) +{ + struct range_data *data = (struct range_data *)user; + isl_ctx *ctx; + unsigned nparam = isl_basic_set_dim(bset, isl_dim_param); + unsigned dim = isl_basic_set_dim(bset, isl_dim_set); + isl_stat r; + + data->signs = NULL; + + ctx = isl_basic_set_get_ctx(bset); + data->signs = isl_alloc_array(ctx, int, + isl_basic_set_dim(bset, isl_dim_all)); + + if (isl_basic_set_dims_get_sign(bset, isl_dim_set, 0, dim, + data->signs + nparam) < 0) + goto error; + if (isl_basic_set_dims_get_sign(bset, isl_dim_param, 0, nparam, + data->signs) < 0) + goto error; + + r = propagate_on_domain(bset, isl_qpolynomial_copy(data->poly), data); + + free(data->signs); + + return r; +error: + free(data->signs); + isl_basic_set_free(bset); + return isl_stat_error; +} + +static isl_stat qpolynomial_bound_on_domain_range( + __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly, + struct range_data *data) +{ + unsigned nparam = isl_basic_set_dim(bset, isl_dim_param); + unsigned nvar = isl_basic_set_dim(bset, isl_dim_set); + isl_set *set = NULL; + + if (!bset) + goto error; + + if (nvar == 0) + return add_guarded_poly(bset, poly, data); + + set = isl_set_from_basic_set(bset); + set = isl_set_split_dims(set, isl_dim_param, 0, nparam); + set = isl_set_split_dims(set, isl_dim_set, 0, nvar); + + data->poly = poly; + + data->test_monotonicity = 1; + if (isl_set_foreach_basic_set(set, &basic_guarded_poly_bound, data) < 0) + goto error; + + isl_set_free(set); + isl_qpolynomial_free(poly); + + return isl_stat_ok; +error: + isl_set_free(set); + isl_qpolynomial_free(poly); + return isl_stat_error; +} + +isl_stat isl_qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *poly, struct isl_bound *bound) +{ + struct range_data data; + isl_stat r; + + data.pwf = bound->pwf; + data.pwf_tight = bound->pwf_tight; + data.tight = bound->check_tight; + if (bound->type == isl_fold_min) + data.sign = -1; + else + data.sign = 1; + + r = qpolynomial_bound_on_domain_range(bset, poly, &data); + + bound->pwf = data.pwf; + bound->pwf_tight = data.pwf_tight; + + return r; +} Index: contrib/isl/isl_reordering.h =================================================================== --- /dev/null +++ contrib/isl/isl_reordering.h @@ -0,0 +1,31 @@ +#ifndef ISL_REORDERING_H +#define ISL_REORDERING_H + +#include + +/* pos maps original dimensions to new dimensions. + * The final dimension is given by dim. + * The number of dimensions (i.e., the range of values) in the result + * may be larger than the number of dimensions in the input. + * In particular, the possible values of the entries in pos ranges from 0 to + * the total dimension of dim - 1, unless isl_reordering_extend + * has been called. + */ +struct isl_reordering { + int ref; + isl_space *dim; + unsigned len; + int pos[1]; +}; +typedef struct isl_reordering isl_reordering; + +__isl_give isl_reordering *isl_parameter_alignment_reordering( + __isl_keep isl_space *alignee, __isl_keep isl_space *aligner); +__isl_give isl_reordering *isl_reordering_copy(__isl_keep isl_reordering *exp); +void *isl_reordering_free(__isl_take isl_reordering *exp); +__isl_give isl_reordering *isl_reordering_extend_space( + __isl_take isl_reordering *exp, __isl_take isl_space *dim); +__isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp, + unsigned extra); + +#endif Index: contrib/isl/isl_reordering.c =================================================================== --- /dev/null +++ contrib/isl/isl_reordering.c @@ -0,0 +1,205 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#include +#include +#include + +__isl_give isl_reordering *isl_reordering_alloc(isl_ctx *ctx, int len) +{ + isl_reordering *exp; + + exp = isl_alloc(ctx, struct isl_reordering, + sizeof(struct isl_reordering) + (len - 1) * sizeof(int)); + if (!exp) + return NULL; + + exp->ref = 1; + exp->len = len; + exp->dim = NULL; + + return exp; +} + +__isl_give isl_reordering *isl_reordering_copy(__isl_keep isl_reordering *exp) +{ + if (!exp) + return NULL; + + exp->ref++; + return exp; +} + +__isl_give isl_reordering *isl_reordering_dup(__isl_keep isl_reordering *r) +{ + int i; + isl_reordering *dup; + + if (!r) + return NULL; + + dup = isl_reordering_alloc(r->dim->ctx, r->len); + if (!dup) + return NULL; + + dup->dim = isl_space_copy(r->dim); + if (!dup->dim) + return isl_reordering_free(dup); + for (i = 0; i < dup->len; ++i) + dup->pos[i] = r->pos[i]; + + return dup; +} + +__isl_give isl_reordering *isl_reordering_cow(__isl_take isl_reordering *r) +{ + if (!r) + return NULL; + + if (r->ref == 1) + return r; + r->ref--; + return isl_reordering_dup(r); +} + +void *isl_reordering_free(__isl_take isl_reordering *exp) +{ + if (!exp) + return NULL; + + if (--exp->ref > 0) + return NULL; + + isl_space_free(exp->dim); + free(exp); + return NULL; +} + +/* Construct a reordering that maps the parameters of "alignee" + * to the corresponding parameters in a new dimension specification + * that has the parameters of "aligner" first, followed by + * any remaining parameters of "alignee" that do not occur in "aligner". + */ +__isl_give isl_reordering *isl_parameter_alignment_reordering( + __isl_keep isl_space *alignee, __isl_keep isl_space *aligner) +{ + int i, j; + isl_reordering *exp; + + if (!alignee || !aligner) + return NULL; + + exp = isl_reordering_alloc(alignee->ctx, alignee->nparam); + if (!exp) + return NULL; + + exp->dim = isl_space_copy(aligner); + + for (i = 0; i < alignee->nparam; ++i) { + isl_id *id_i; + id_i = isl_space_get_dim_id(alignee, isl_dim_param, i); + if (!id_i) + isl_die(alignee->ctx, isl_error_invalid, + "cannot align unnamed parameters", goto error); + for (j = 0; j < aligner->nparam; ++j) { + isl_id *id_j; + id_j = isl_space_get_dim_id(aligner, isl_dim_param, j); + isl_id_free(id_j); + if (id_i == id_j) + break; + } + if (j < aligner->nparam) { + exp->pos[i] = j; + isl_id_free(id_i); + } else { + int pos; + pos = isl_space_dim(exp->dim, isl_dim_param); + exp->dim = isl_space_add_dims(exp->dim, isl_dim_param, 1); + exp->dim = isl_space_set_dim_id(exp->dim, + isl_dim_param, pos, id_i); + exp->pos[i] = pos; + } + } + + if (!exp->dim) + return isl_reordering_free(exp); + return exp; +error: + isl_reordering_free(exp); + return NULL; +} + +__isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp, + unsigned extra) +{ + int i; + isl_reordering *res; + int offset; + + if (!exp) + return NULL; + if (extra == 0) + return exp; + + offset = isl_space_dim(exp->dim, isl_dim_all) - exp->len; + res = isl_reordering_alloc(exp->dim->ctx, exp->len + extra); + if (!res) + goto error; + res->dim = isl_space_copy(exp->dim); + for (i = 0; i < exp->len; ++i) + res->pos[i] = exp->pos[i]; + for (i = exp->len; i < res->len; ++i) + res->pos[i] = offset + i; + + isl_reordering_free(exp); + + return res; +error: + isl_reordering_free(exp); + return NULL; +} + +__isl_give isl_reordering *isl_reordering_extend_space( + __isl_take isl_reordering *exp, __isl_take isl_space *dim) +{ + isl_reordering *res; + + if (!exp || !dim) + goto error; + + res = isl_reordering_extend(isl_reordering_copy(exp), + isl_space_dim(dim, isl_dim_all) - exp->len); + res = isl_reordering_cow(res); + if (!res) + goto error; + isl_space_free(res->dim); + res->dim = isl_space_replace(dim, isl_dim_param, exp->dim); + + isl_reordering_free(exp); + + if (!res->dim) + return isl_reordering_free(res); + + return res; +error: + isl_reordering_free(exp); + isl_space_free(dim); + return NULL; +} + +void isl_reordering_dump(__isl_keep isl_reordering *exp) +{ + int i; + + isl_space_dump(exp->dim); + for (i = 0; i < exp->len; ++i) + fprintf(stderr, "%d -> %d; ", i, exp->pos[i]); + fprintf(stderr, "\n"); +} Index: contrib/isl/isl_sample.h =================================================================== --- /dev/null +++ contrib/isl/isl_sample.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_SAMPLE_H +#define ISL_SAMPLE_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_vec *isl_basic_set_sample_vec(__isl_take isl_basic_set *bset); +__isl_give isl_vec *isl_basic_set_sample_bounded( + __isl_take isl_basic_set *bset); +__isl_give isl_vec *isl_basic_set_sample_with_cone( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone); + +__isl_give isl_basic_set *isl_basic_set_from_vec(__isl_take isl_vec *vec); + +int isl_tab_set_initial_basis_with_cone(struct isl_tab *tab, + struct isl_tab *tab_cone); +struct isl_vec *isl_tab_sample(struct isl_tab *tab); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/isl_sample.c =================================================================== --- /dev/null +++ contrib/isl/isl_sample.c @@ -0,0 +1,1308 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include "isl_sample.h" +#include +#include +#include +#include "isl_equalities.h" +#include "isl_tab.h" +#include "isl_basis_reduction.h" +#include +#include +#include +#include + +#include +#include + +static __isl_give isl_vec *empty_sample(__isl_take isl_basic_set *bset) +{ + struct isl_vec *vec; + + vec = isl_vec_alloc(bset->ctx, 0); + isl_basic_set_free(bset); + return vec; +} + +/* Construct a zero sample of the same dimension as bset. + * As a special case, if bset is zero-dimensional, this + * function creates a zero-dimensional sample point. + */ +static __isl_give isl_vec *zero_sample(__isl_take isl_basic_set *bset) +{ + unsigned dim; + struct isl_vec *sample; + + dim = isl_basic_set_total_dim(bset); + sample = isl_vec_alloc(bset->ctx, 1 + dim); + if (sample) { + isl_int_set_si(sample->el[0], 1); + isl_seq_clr(sample->el + 1, dim); + } + isl_basic_set_free(bset); + return sample; +} + +static __isl_give isl_vec *interval_sample(__isl_take isl_basic_set *bset) +{ + int i; + isl_int t; + struct isl_vec *sample; + + bset = isl_basic_set_simplify(bset); + if (!bset) + return NULL; + 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); + + sample = isl_vec_alloc(bset->ctx, 2); + if (!sample) + goto error; + if (!bset) + return NULL; + isl_int_set_si(sample->block.data[0], 1); + + if (bset->n_eq > 0) { + isl_assert(bset->ctx, bset->n_eq == 1, goto error); + isl_assert(bset->ctx, bset->n_ineq == 0, goto error); + if (isl_int_is_one(bset->eq[0][1])) + isl_int_neg(sample->el[1], bset->eq[0][0]); + else { + isl_assert(bset->ctx, isl_int_is_negone(bset->eq[0][1]), + goto error); + isl_int_set(sample->el[1], bset->eq[0][0]); + } + isl_basic_set_free(bset); + return sample; + } + + isl_int_init(t); + if (isl_int_is_one(bset->ineq[0][1])) + isl_int_neg(sample->block.data[1], bset->ineq[0][0]); + else + isl_int_set(sample->block.data[1], bset->ineq[0][0]); + for (i = 1; i < bset->n_ineq; ++i) { + isl_seq_inner_product(sample->block.data, + bset->ineq[i], 2, &t); + if (isl_int_is_neg(t)) + break; + } + isl_int_clear(t); + if (i < bset->n_ineq) { + isl_vec_free(sample); + return empty_sample(bset); + } + + isl_basic_set_free(bset); + return sample; +error: + isl_basic_set_free(bset); + isl_vec_free(sample); + return NULL; +} + +/* Find a sample integer point, if any, in bset, which is known + * to have equalities. If bset contains no integer points, then + * return a zero-length vector. + * We simply remove the known equalities, compute a sample + * in the resulting bset, using the specified recurse function, + * and then transform the sample back to the original space. + */ +static __isl_give isl_vec *sample_eq(__isl_take isl_basic_set *bset, + __isl_give isl_vec *(*recurse)(__isl_take isl_basic_set *)) +{ + struct isl_mat *T; + struct isl_vec *sample; + + if (!bset) + return NULL; + + bset = isl_basic_set_remove_equalities(bset, &T, NULL); + sample = recurse(bset); + if (!sample || sample->size == 0) + isl_mat_free(T); + else + sample = isl_mat_vec_product(T, sample); + return sample; +} + +/* Return a matrix containing the equalities of the tableau + * in constraint form. The tableau is assumed to have + * an associated bset that has been kept up-to-date. + */ +static struct isl_mat *tab_equalities(struct isl_tab *tab) +{ + int i, j; + int n_eq; + struct isl_mat *eq; + struct isl_basic_set *bset; + + if (!tab) + return NULL; + + bset = isl_tab_peek_bset(tab); + isl_assert(tab->mat->ctx, bset, return NULL); + + n_eq = tab->n_var - tab->n_col + tab->n_dead; + if (tab->empty || n_eq == 0) + return isl_mat_alloc(tab->mat->ctx, 0, tab->n_var); + if (n_eq == tab->n_var) + return isl_mat_identity(tab->mat->ctx, tab->n_var); + + eq = isl_mat_alloc(tab->mat->ctx, n_eq, tab->n_var); + if (!eq) + return NULL; + for (i = 0, j = 0; i < tab->n_con; ++i) { + if (tab->con[i].is_row) + continue; + if (tab->con[i].index >= 0 && tab->con[i].index >= tab->n_dead) + continue; + if (i < bset->n_eq) + isl_seq_cpy(eq->row[j], bset->eq[i] + 1, tab->n_var); + else + isl_seq_cpy(eq->row[j], + bset->ineq[i - bset->n_eq] + 1, tab->n_var); + ++j; + } + isl_assert(bset->ctx, j == n_eq, goto error); + return eq; +error: + isl_mat_free(eq); + return NULL; +} + +/* Compute and return an initial basis for the bounded tableau "tab". + * + * If the tableau is either full-dimensional or zero-dimensional, + * the we simply return an identity matrix. + * Otherwise, we construct a basis whose first directions correspond + * to equalities. + */ +static struct isl_mat *initial_basis(struct isl_tab *tab) +{ + int n_eq; + struct isl_mat *eq; + struct isl_mat *Q; + + tab->n_unbounded = 0; + tab->n_zero = n_eq = tab->n_var - tab->n_col + tab->n_dead; + if (tab->empty || n_eq == 0 || n_eq == tab->n_var) + return isl_mat_identity(tab->mat->ctx, 1 + tab->n_var); + + eq = tab_equalities(tab); + eq = isl_mat_left_hermite(eq, 0, NULL, &Q); + if (!eq) + return NULL; + isl_mat_free(eq); + + Q = isl_mat_lin_to_aff(Q); + return Q; +} + +/* Compute the minimum of the current ("level") basis row over "tab" + * and store the result in position "level" of "min". + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +static enum isl_lp_result compute_min(isl_ctx *ctx, struct isl_tab *tab, + __isl_keep isl_vec *min, int level) +{ + return isl_tab_min(tab, tab->basis->row[1 + level], + ctx->one, &min->el[level], NULL, 0); +} + +/* Compute the maximum of the current ("level") basis row over "tab" + * and store the result in position "level" of "max". + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +static enum isl_lp_result compute_max(isl_ctx *ctx, struct isl_tab *tab, + __isl_keep isl_vec *max, int level) +{ + enum isl_lp_result res; + unsigned dim = tab->n_var; + + isl_seq_neg(tab->basis->row[1 + level] + 1, + tab->basis->row[1 + level] + 1, dim); + res = isl_tab_min(tab, tab->basis->row[1 + level], + ctx->one, &max->el[level], NULL, 0); + isl_seq_neg(tab->basis->row[1 + level] + 1, + tab->basis->row[1 + level] + 1, dim); + isl_int_neg(max->el[level], max->el[level]); + + return res; +} + +/* Perform a greedy search for an integer point in the set represented + * by "tab", given that the minimal rational value (rounded up to the + * nearest integer) at "level" is smaller than the maximal rational + * value (rounded down to the nearest integer). + * + * Return 1 if we have found an integer point (if tab->n_unbounded > 0 + * then we may have only found integer values for the bounded dimensions + * and it is the responsibility of the caller to extend this solution + * to the unbounded dimensions). + * Return 0 if greedy search did not result in a solution. + * Return -1 if some error occurred. + * + * We assign a value half-way between the minimum and the maximum + * to the current dimension and check if the minimal value of the + * next dimension is still smaller than (or equal) to the maximal value. + * We continue this process until either + * - the minimal value (rounded up) is greater than the maximal value + * (rounded down). In this case, greedy search has failed. + * - we have exhausted all bounded dimensions, meaning that we have + * found a solution. + * - the sample value of the tableau is integral. + * - some error has occurred. + */ +static int greedy_search(isl_ctx *ctx, struct isl_tab *tab, + __isl_keep isl_vec *min, __isl_keep isl_vec *max, int level) +{ + struct isl_tab_undo *snap; + enum isl_lp_result res; + + snap = isl_tab_snap(tab); + + do { + isl_int_add(tab->basis->row[1 + level][0], + min->el[level], max->el[level]); + isl_int_fdiv_q_ui(tab->basis->row[1 + level][0], + tab->basis->row[1 + level][0], 2); + isl_int_neg(tab->basis->row[1 + level][0], + tab->basis->row[1 + level][0]); + if (isl_tab_add_valid_eq(tab, tab->basis->row[1 + level]) < 0) + return -1; + isl_int_set_si(tab->basis->row[1 + level][0], 0); + + if (++level >= tab->n_var - tab->n_unbounded) + return 1; + if (isl_tab_sample_is_integer(tab)) + return 1; + + res = compute_min(ctx, tab, min, level); + if (res == isl_lp_error) + return -1; + if (res != isl_lp_ok) + isl_die(ctx, isl_error_internal, + "expecting bounded rational solution", + return -1); + res = compute_max(ctx, tab, max, level); + if (res == isl_lp_error) + return -1; + if (res != isl_lp_ok) + isl_die(ctx, isl_error_internal, + "expecting bounded rational solution", + return -1); + } while (isl_int_le(min->el[level], max->el[level])); + + if (isl_tab_rollback(tab, snap) < 0) + return -1; + + return 0; +} + +/* Given a tableau representing a set, find and return + * an integer point in the set, if there is any. + * + * We perform a depth first search + * for an integer point, by scanning all possible values in the range + * attained by a basis vector, where an initial basis may have been set + * by the calling function. Otherwise an initial basis that exploits + * the equalities in the tableau is created. + * tab->n_zero is currently ignored and is clobbered by this function. + * + * The tableau is allowed to have unbounded direction, but then + * the calling function needs to set an initial basis, with the + * unbounded directions last and with tab->n_unbounded set + * to the number of unbounded directions. + * Furthermore, the calling functions needs to add shifted copies + * of all constraints involving unbounded directions to ensure + * that any feasible rational value in these directions can be rounded + * up to yield a feasible integer value. + * In particular, let B define the given basis x' = B x + * and let T be the inverse of B, i.e., X = T x'. + * Let a x + c >= 0 be a constraint of the set represented by the tableau, + * or a T x' + c >= 0 in terms of the given basis. Assume that + * the bounded directions have an integer value, then we can safely + * round up the values for the unbounded directions if we make sure + * that x' not only satisfies the original constraint, but also + * the constraint "a T x' + c + s >= 0" with s the sum of all + * negative values in the last n_unbounded entries of "a T". + * The calling function therefore needs to add the constraint + * a x + c + s >= 0. The current function then scans the first + * directions for an integer value and once those have been found, + * it can compute "T ceil(B x)" to yield an integer point in the set. + * Note that during the search, the first rows of B may be changed + * by a basis reduction, but the last n_unbounded rows of B remain + * unaltered and are also not mixed into the first rows. + * + * The search is implemented iteratively. "level" identifies the current + * basis vector. "init" is true if we want the first value at the current + * level and false if we want the next value. + * + * At the start of each level, we first check if we can find a solution + * using greedy search. If not, we continue with the exhaustive search. + * + * The initial basis is the identity matrix. If the range in some direction + * contains more than one integer value, we perform basis reduction based + * on the value of ctx->opt->gbr + * - ISL_GBR_NEVER: never perform basis reduction + * - ISL_GBR_ONCE: only perform basis reduction the first + * time such a range is encountered + * - ISL_GBR_ALWAYS: always perform basis reduction when + * such a range is encountered + * + * When ctx->opt->gbr is set to ISL_GBR_ALWAYS, then we allow the basis + * reduction computation to return early. That is, as soon as it + * finds a reasonable first direction. + */ +struct isl_vec *isl_tab_sample(struct isl_tab *tab) +{ + unsigned dim; + unsigned gbr; + struct isl_ctx *ctx; + struct isl_vec *sample; + struct isl_vec *min; + struct isl_vec *max; + enum isl_lp_result res; + int level; + int init; + int reduced; + struct isl_tab_undo **snap; + + if (!tab) + return NULL; + if (tab->empty) + return isl_vec_alloc(tab->mat->ctx, 0); + + if (!tab->basis) + tab->basis = initial_basis(tab); + if (!tab->basis) + return NULL; + isl_assert(tab->mat->ctx, tab->basis->n_row == tab->n_var + 1, + return NULL); + isl_assert(tab->mat->ctx, tab->basis->n_col == tab->n_var + 1, + return NULL); + + ctx = tab->mat->ctx; + dim = tab->n_var; + gbr = ctx->opt->gbr; + + if (tab->n_unbounded == tab->n_var) { + sample = isl_tab_get_sample_value(tab); + sample = isl_mat_vec_product(isl_mat_copy(tab->basis), sample); + sample = isl_vec_ceil(sample); + sample = isl_mat_vec_inverse_product(isl_mat_copy(tab->basis), + sample); + return sample; + } + + if (isl_tab_extend_cons(tab, dim + 1) < 0) + return NULL; + + min = isl_vec_alloc(ctx, dim); + max = isl_vec_alloc(ctx, dim); + snap = isl_alloc_array(ctx, struct isl_tab_undo *, dim); + + if (!min || !max || !snap) + goto error; + + level = 0; + init = 1; + reduced = 0; + + while (level >= 0) { + if (init) { + int choice; + + res = compute_min(ctx, tab, min, level); + if (res == isl_lp_error) + goto error; + if (res != isl_lp_ok) + isl_die(ctx, isl_error_internal, + "expecting bounded rational solution", + goto error); + if (isl_tab_sample_is_integer(tab)) + break; + res = compute_max(ctx, tab, max, level); + if (res == isl_lp_error) + goto error; + if (res != isl_lp_ok) + isl_die(ctx, isl_error_internal, + "expecting bounded rational solution", + goto error); + if (isl_tab_sample_is_integer(tab)) + break; + choice = isl_int_lt(min->el[level], max->el[level]); + if (choice) { + int g; + g = greedy_search(ctx, tab, min, max, level); + if (g < 0) + goto error; + if (g) + break; + } + if (!reduced && choice && + ctx->opt->gbr != ISL_GBR_NEVER) { + unsigned gbr_only_first; + if (ctx->opt->gbr == ISL_GBR_ONCE) + ctx->opt->gbr = ISL_GBR_NEVER; + tab->n_zero = level; + gbr_only_first = ctx->opt->gbr_only_first; + ctx->opt->gbr_only_first = + ctx->opt->gbr == ISL_GBR_ALWAYS; + tab = isl_tab_compute_reduced_basis(tab); + ctx->opt->gbr_only_first = gbr_only_first; + if (!tab || !tab->basis) + goto error; + reduced = 1; + continue; + } + reduced = 0; + snap[level] = isl_tab_snap(tab); + } else + isl_int_add_ui(min->el[level], min->el[level], 1); + + if (isl_int_gt(min->el[level], max->el[level])) { + level--; + init = 0; + if (level >= 0) + if (isl_tab_rollback(tab, snap[level]) < 0) + goto error; + continue; + } + isl_int_neg(tab->basis->row[1 + level][0], min->el[level]); + if (isl_tab_add_valid_eq(tab, tab->basis->row[1 + level]) < 0) + goto error; + isl_int_set_si(tab->basis->row[1 + level][0], 0); + if (level + tab->n_unbounded < dim - 1) { + ++level; + init = 1; + continue; + } + break; + } + + if (level >= 0) { + sample = isl_tab_get_sample_value(tab); + if (!sample) + goto error; + if (tab->n_unbounded && !isl_int_is_one(sample->el[0])) { + sample = isl_mat_vec_product(isl_mat_copy(tab->basis), + sample); + sample = isl_vec_ceil(sample); + sample = isl_mat_vec_inverse_product( + isl_mat_copy(tab->basis), sample); + } + } else + sample = isl_vec_alloc(ctx, 0); + + ctx->opt->gbr = gbr; + isl_vec_free(min); + isl_vec_free(max); + free(snap); + return sample; +error: + ctx->opt->gbr = gbr; + isl_vec_free(min); + isl_vec_free(max); + free(snap); + return NULL; +} + +static __isl_give isl_vec *sample_bounded(__isl_take isl_basic_set *bset); + +/* Compute a sample point of the given basic set, based on the given, + * non-trivial factorization. + */ +static __isl_give isl_vec *factored_sample(__isl_take isl_basic_set *bset, + __isl_take isl_factorizer *f) +{ + int i, n; + isl_vec *sample = NULL; + isl_ctx *ctx; + unsigned nparam; + unsigned nvar; + + ctx = isl_basic_set_get_ctx(bset); + if (!ctx) + goto error; + + nparam = isl_basic_set_dim(bset, isl_dim_param); + nvar = isl_basic_set_dim(bset, isl_dim_set); + + sample = isl_vec_alloc(ctx, 1 + isl_basic_set_total_dim(bset)); + if (!sample) + goto error; + isl_int_set_si(sample->el[0], 1); + + bset = isl_morph_basic_set(isl_morph_copy(f->morph), bset); + + for (i = 0, n = 0; i < f->n_group; ++i) { + isl_basic_set *bset_i; + isl_vec *sample_i; + + bset_i = isl_basic_set_copy(bset); + bset_i = isl_basic_set_drop_constraints_involving(bset_i, + nparam + n + f->len[i], nvar - n - f->len[i]); + bset_i = isl_basic_set_drop_constraints_involving(bset_i, + nparam, n); + bset_i = isl_basic_set_drop(bset_i, isl_dim_set, + n + f->len[i], nvar - n - f->len[i]); + bset_i = isl_basic_set_drop(bset_i, isl_dim_set, 0, n); + + sample_i = sample_bounded(bset_i); + if (!sample_i) + goto error; + if (sample_i->size == 0) { + isl_basic_set_free(bset); + isl_factorizer_free(f); + isl_vec_free(sample); + return sample_i; + } + isl_seq_cpy(sample->el + 1 + nparam + n, + sample_i->el + 1, f->len[i]); + isl_vec_free(sample_i); + + n += f->len[i]; + } + + f->morph = isl_morph_inverse(f->morph); + sample = isl_morph_vec(isl_morph_copy(f->morph), sample); + + isl_basic_set_free(bset); + isl_factorizer_free(f); + return sample; +error: + isl_basic_set_free(bset); + isl_factorizer_free(f); + isl_vec_free(sample); + return NULL; +} + +/* Given a basic set that is known to be bounded, find and return + * an integer point in the basic set, if there is any. + * + * After handling some trivial cases, we construct a tableau + * and then use isl_tab_sample to find a sample, passing it + * the identity matrix as initial basis. + */ +static __isl_give isl_vec *sample_bounded(__isl_take isl_basic_set *bset) +{ + unsigned dim; + struct isl_vec *sample; + struct isl_tab *tab = NULL; + isl_factorizer *f; + + if (!bset) + return NULL; + + if (isl_basic_set_plain_is_empty(bset)) + return empty_sample(bset); + + dim = isl_basic_set_total_dim(bset); + if (dim == 0) + return zero_sample(bset); + if (dim == 1) + return interval_sample(bset); + if (bset->n_eq > 0) + return sample_eq(bset, sample_bounded); + + f = isl_basic_set_factorizer(bset); + if (!f) + goto error; + if (f->n_group != 0) + return factored_sample(bset, f); + isl_factorizer_free(f); + + tab = isl_tab_from_basic_set(bset, 1); + if (tab && tab->empty) { + isl_tab_free(tab); + ISL_F_SET(bset, ISL_BASIC_SET_EMPTY); + sample = isl_vec_alloc(isl_basic_set_get_ctx(bset), 0); + isl_basic_set_free(bset); + return sample; + } + + if (!ISL_F_ISSET(bset, ISL_BASIC_SET_NO_IMPLICIT)) + if (isl_tab_detect_implicit_equalities(tab) < 0) + goto error; + + sample = isl_tab_sample(tab); + if (!sample) + goto error; + + if (sample->size > 0) { + isl_vec_free(bset->sample); + bset->sample = isl_vec_copy(sample); + } + + isl_basic_set_free(bset); + isl_tab_free(tab); + return sample; +error: + isl_basic_set_free(bset); + isl_tab_free(tab); + return NULL; +} + +/* Given a basic set "bset" and a value "sample" for the first coordinates + * of bset, plug in these values and drop the corresponding coordinates. + * + * We do this by computing the preimage of the transformation + * + * [ 1 0 ] + * x = [ s 0 ] x' + * [ 0 I ] + * + * where [1 s] is the sample value and I is the identity matrix of the + * appropriate dimension. + */ +static __isl_give isl_basic_set *plug_in(__isl_take isl_basic_set *bset, + __isl_take isl_vec *sample) +{ + int i; + unsigned total; + struct isl_mat *T; + + if (!bset || !sample) + goto error; + + total = isl_basic_set_total_dim(bset); + T = isl_mat_alloc(bset->ctx, 1 + total, 1 + total - (sample->size - 1)); + if (!T) + goto error; + + for (i = 0; i < sample->size; ++i) { + isl_int_set(T->row[i][0], sample->el[i]); + isl_seq_clr(T->row[i] + 1, T->n_col - 1); + } + for (i = 0; i < T->n_col - 1; ++i) { + isl_seq_clr(T->row[sample->size + i], T->n_col); + isl_int_set_si(T->row[sample->size + i][1 + i], 1); + } + isl_vec_free(sample); + + bset = isl_basic_set_preimage(bset, T); + return bset; +error: + isl_basic_set_free(bset); + isl_vec_free(sample); + return NULL; +} + +/* Given a basic set "bset", return any (possibly non-integer) point + * in the basic set. + */ +static __isl_give isl_vec *rational_sample(__isl_take isl_basic_set *bset) +{ + struct isl_tab *tab; + struct isl_vec *sample; + + if (!bset) + return NULL; + + tab = isl_tab_from_basic_set(bset, 0); + sample = isl_tab_get_sample_value(tab); + isl_tab_free(tab); + + isl_basic_set_free(bset); + + return sample; +} + +/* Given a linear cone "cone" and a rational point "vec", + * construct a polyhedron with shifted copies of the constraints in "cone", + * i.e., a polyhedron with "cone" as its recession cone, such that each + * point x in this polyhedron is such that the unit box positioned at x + * lies entirely inside the affine cone 'vec + cone'. + * Any rational point in this polyhedron may therefore be rounded up + * to yield an integer point that lies inside said affine cone. + * + * Denote the constraints of cone by " >= 0" and the rational + * point "vec" by v/d. + * Let b_i = . Then the affine cone 'vec + cone' is given + * by - b/d >= 0. + * The polyhedron - ceil{b/d} >= 0 is a subset of this affine cone. + * We prefer this polyhedron over the actual affine cone because it doesn't + * require a scaling of the constraints. + * If each of the vertices of the unit cube positioned at x lies inside + * this polyhedron, then the whole unit cube at x lies inside the affine cone. + * We therefore impose that x' = x + \sum e_i, for any selection of unit + * vectors lies inside the polyhedron, i.e., + * + * - ceil{b/d} = + sum a_i - ceil{b/d} >= 0 + * + * The most stringent of these constraints is the one that selects + * all negative a_i, so the polyhedron we are looking for has constraints + * + * + sum_{a_i < 0} a_i - ceil{b/d} >= 0 + * + * Note that if cone were known to have only non-negative rays + * (which can be accomplished by a unimodular transformation), + * then we would only have to check the points x' = x + e_i + * and we only have to add the smallest negative a_i (if any) + * instead of the sum of all negative a_i. + */ +static __isl_give isl_basic_set *shift_cone(__isl_take isl_basic_set *cone, + __isl_take isl_vec *vec) +{ + int i, j, k; + unsigned total; + + struct isl_basic_set *shift = NULL; + + if (!cone || !vec) + goto error; + + isl_assert(cone->ctx, cone->n_eq == 0, goto error); + + total = isl_basic_set_total_dim(cone); + + shift = isl_basic_set_alloc_space(isl_basic_set_get_space(cone), + 0, 0, cone->n_ineq); + + for (i = 0; i < cone->n_ineq; ++i) { + k = isl_basic_set_alloc_inequality(shift); + if (k < 0) + goto error; + isl_seq_cpy(shift->ineq[k] + 1, cone->ineq[i] + 1, total); + isl_seq_inner_product(shift->ineq[k] + 1, vec->el + 1, total, + &shift->ineq[k][0]); + isl_int_cdiv_q(shift->ineq[k][0], + shift->ineq[k][0], vec->el[0]); + isl_int_neg(shift->ineq[k][0], shift->ineq[k][0]); + for (j = 0; j < total; ++j) { + if (isl_int_is_nonneg(shift->ineq[k][1 + j])) + continue; + isl_int_add(shift->ineq[k][0], + shift->ineq[k][0], shift->ineq[k][1 + j]); + } + } + + isl_basic_set_free(cone); + isl_vec_free(vec); + + return isl_basic_set_finalize(shift); +error: + isl_basic_set_free(shift); + isl_basic_set_free(cone); + isl_vec_free(vec); + return NULL; +} + +/* Given a rational point vec in a (transformed) basic set, + * such that cone is the recession cone of the original basic set, + * "round up" the rational point to an integer point. + * + * We first check if the rational point just happens to be integer. + * If not, we transform the cone in the same way as the basic set, + * pick a point x in this cone shifted to the rational point such that + * the whole unit cube at x is also inside this affine cone. + * Then we simply round up the coordinates of x and return the + * resulting integer point. + */ +static __isl_give isl_vec *round_up_in_cone(__isl_take isl_vec *vec, + __isl_take isl_basic_set *cone, __isl_take isl_mat *U) +{ + unsigned total; + + if (!vec || !cone || !U) + goto error; + + isl_assert(vec->ctx, vec->size != 0, goto error); + if (isl_int_is_one(vec->el[0])) { + isl_mat_free(U); + isl_basic_set_free(cone); + return vec; + } + + total = isl_basic_set_total_dim(cone); + cone = isl_basic_set_preimage(cone, U); + cone = isl_basic_set_remove_dims(cone, isl_dim_set, + 0, total - (vec->size - 1)); + + cone = shift_cone(cone, vec); + + vec = rational_sample(cone); + vec = isl_vec_ceil(vec); + return vec; +error: + isl_mat_free(U); + isl_vec_free(vec); + isl_basic_set_free(cone); + return NULL; +} + +/* Concatenate two integer vectors, i.e., two vectors with denominator + * (stored in element 0) equal to 1. + */ +static __isl_give isl_vec *vec_concat(__isl_take isl_vec *vec1, + __isl_take isl_vec *vec2) +{ + struct isl_vec *vec; + + if (!vec1 || !vec2) + goto error; + isl_assert(vec1->ctx, vec1->size > 0, goto error); + isl_assert(vec2->ctx, vec2->size > 0, goto error); + isl_assert(vec1->ctx, isl_int_is_one(vec1->el[0]), goto error); + isl_assert(vec2->ctx, isl_int_is_one(vec2->el[0]), goto error); + + vec = isl_vec_alloc(vec1->ctx, vec1->size + vec2->size - 1); + if (!vec) + goto error; + + isl_seq_cpy(vec->el, vec1->el, vec1->size); + isl_seq_cpy(vec->el + vec1->size, vec2->el + 1, vec2->size - 1); + + isl_vec_free(vec1); + isl_vec_free(vec2); + + return vec; +error: + isl_vec_free(vec1); + isl_vec_free(vec2); + return NULL; +} + +/* Give a basic set "bset" with recession cone "cone", compute and + * return an integer point in bset, if any. + * + * If the recession cone is full-dimensional, then we know that + * bset contains an infinite number of integer points and it is + * fairly easy to pick one of them. + * If the recession cone is not full-dimensional, then we first + * transform bset such that the bounded directions appear as + * the first dimensions of the transformed basic set. + * We do this by using a unimodular transformation that transforms + * the equalities in the recession cone to equalities on the first + * dimensions. + * + * The transformed set is then projected onto its bounded dimensions. + * Note that to compute this projection, we can simply drop all constraints + * involving any of the unbounded dimensions since these constraints + * cannot be combined to produce a constraint on the bounded dimensions. + * To see this, assume that there is such a combination of constraints + * that produces a constraint on the bounded dimensions. This means + * that some combination of the unbounded dimensions has both an upper + * bound and a lower bound in terms of the bounded dimensions, but then + * this combination would be a bounded direction too and would have been + * transformed into a bounded dimensions. + * + * We then compute a sample value in the bounded dimensions. + * If no such value can be found, then the original set did not contain + * any integer points and we are done. + * Otherwise, we plug in the value we found in the bounded dimensions, + * project out these bounded dimensions and end up with a set with + * a full-dimensional recession cone. + * A sample point in this set is computed by "rounding up" any + * rational point in the set. + * + * The sample points in the bounded and unbounded dimensions are + * then combined into a single sample point and transformed back + * to the original space. + */ +__isl_give isl_vec *isl_basic_set_sample_with_cone( + __isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone) +{ + unsigned total; + unsigned cone_dim; + struct isl_mat *M, *U; + struct isl_vec *sample; + struct isl_vec *cone_sample; + struct isl_ctx *ctx; + struct isl_basic_set *bounded; + + if (!bset || !cone) + goto error; + + ctx = isl_basic_set_get_ctx(bset); + total = isl_basic_set_total_dim(cone); + cone_dim = total - cone->n_eq; + + M = isl_mat_sub_alloc6(ctx, cone->eq, 0, cone->n_eq, 1, total); + M = isl_mat_left_hermite(M, 0, &U, NULL); + if (!M) + goto error; + isl_mat_free(M); + + U = isl_mat_lin_to_aff(U); + bset = isl_basic_set_preimage(bset, isl_mat_copy(U)); + + bounded = isl_basic_set_copy(bset); + bounded = isl_basic_set_drop_constraints_involving(bounded, + total - cone_dim, cone_dim); + bounded = isl_basic_set_drop_dims(bounded, total - cone_dim, cone_dim); + sample = sample_bounded(bounded); + if (!sample || sample->size == 0) { + isl_basic_set_free(bset); + isl_basic_set_free(cone); + isl_mat_free(U); + return sample; + } + bset = plug_in(bset, isl_vec_copy(sample)); + cone_sample = rational_sample(bset); + cone_sample = round_up_in_cone(cone_sample, cone, isl_mat_copy(U)); + sample = vec_concat(sample, cone_sample); + sample = isl_mat_vec_product(U, sample); + return sample; +error: + isl_basic_set_free(cone); + isl_basic_set_free(bset); + return NULL; +} + +static void vec_sum_of_neg(struct isl_vec *v, isl_int *s) +{ + int i; + + isl_int_set_si(*s, 0); + + for (i = 0; i < v->size; ++i) + if (isl_int_is_neg(v->el[i])) + isl_int_add(*s, *s, v->el[i]); +} + +/* Given a tableau "tab", a tableau "tab_cone" that corresponds + * to the recession cone and the inverse of a new basis U = inv(B), + * with the unbounded directions in B last, + * add constraints to "tab" that ensure any rational value + * in the unbounded directions can be rounded up to an integer value. + * + * The new basis is given by x' = B x, i.e., x = U x'. + * For any rational value of the last tab->n_unbounded coordinates + * in the update tableau, the value that is obtained by rounding + * up this value should be contained in the original tableau. + * For any constraint "a x + c >= 0", we therefore need to add + * a constraint "a x + c + s >= 0", with s the sum of all negative + * entries in the last elements of "a U". + * + * Since we are not interested in the first entries of any of the "a U", + * we first drop the columns of U that correpond to bounded directions. + */ +static int tab_shift_cone(struct isl_tab *tab, + struct isl_tab *tab_cone, struct isl_mat *U) +{ + int i; + isl_int v; + struct isl_basic_set *bset = NULL; + + if (tab && tab->n_unbounded == 0) { + isl_mat_free(U); + return 0; + } + isl_int_init(v); + if (!tab || !tab_cone || !U) + goto error; + bset = isl_tab_peek_bset(tab_cone); + U = isl_mat_drop_cols(U, 0, tab->n_var - tab->n_unbounded); + for (i = 0; i < bset->n_ineq; ++i) { + int ok; + struct isl_vec *row = NULL; + if (isl_tab_is_equality(tab_cone, tab_cone->n_eq + i)) + continue; + row = isl_vec_alloc(bset->ctx, tab_cone->n_var); + if (!row) + goto error; + isl_seq_cpy(row->el, bset->ineq[i] + 1, tab_cone->n_var); + row = isl_vec_mat_product(row, isl_mat_copy(U)); + if (!row) + goto error; + vec_sum_of_neg(row, &v); + isl_vec_free(row); + if (isl_int_is_zero(v)) + continue; + if (isl_tab_extend_cons(tab, 1) < 0) + goto error; + isl_int_add(bset->ineq[i][0], bset->ineq[i][0], v); + ok = isl_tab_add_ineq(tab, bset->ineq[i]) >= 0; + isl_int_sub(bset->ineq[i][0], bset->ineq[i][0], v); + if (!ok) + goto error; + } + + isl_mat_free(U); + isl_int_clear(v); + return 0; +error: + isl_mat_free(U); + isl_int_clear(v); + return -1; +} + +/* Compute and return an initial basis for the possibly + * unbounded tableau "tab". "tab_cone" is a tableau + * for the corresponding recession cone. + * Additionally, add constraints to "tab" that ensure + * that any rational value for the unbounded directions + * can be rounded up to an integer value. + * + * If the tableau is bounded, i.e., if the recession cone + * is zero-dimensional, then we just use inital_basis. + * Otherwise, we construct a basis whose first directions + * correspond to equalities, followed by bounded directions, + * i.e., equalities in the recession cone. + * The remaining directions are then unbounded. + */ +int isl_tab_set_initial_basis_with_cone(struct isl_tab *tab, + struct isl_tab *tab_cone) +{ + struct isl_mat *eq; + struct isl_mat *cone_eq; + struct isl_mat *U, *Q; + + if (!tab || !tab_cone) + return -1; + + if (tab_cone->n_col == tab_cone->n_dead) { + tab->basis = initial_basis(tab); + return tab->basis ? 0 : -1; + } + + eq = tab_equalities(tab); + if (!eq) + return -1; + tab->n_zero = eq->n_row; + cone_eq = tab_equalities(tab_cone); + eq = isl_mat_concat(eq, cone_eq); + if (!eq) + return -1; + tab->n_unbounded = tab->n_var - (eq->n_row - tab->n_zero); + eq = isl_mat_left_hermite(eq, 0, &U, &Q); + if (!eq) + return -1; + isl_mat_free(eq); + tab->basis = isl_mat_lin_to_aff(Q); + if (tab_shift_cone(tab, tab_cone, U) < 0) + return -1; + if (!tab->basis) + return -1; + return 0; +} + +/* Compute and return a sample point in bset using generalized basis + * reduction. We first check if the input set has a non-trivial + * recession cone. If so, we perform some extra preprocessing in + * sample_with_cone. Otherwise, we directly perform generalized basis + * reduction. + */ +static __isl_give isl_vec *gbr_sample(__isl_take isl_basic_set *bset) +{ + unsigned dim; + struct isl_basic_set *cone; + + dim = isl_basic_set_total_dim(bset); + + cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset)); + if (!cone) + goto error; + + if (cone->n_eq < dim) + return isl_basic_set_sample_with_cone(bset, cone); + + isl_basic_set_free(cone); + return sample_bounded(bset); +error: + isl_basic_set_free(bset); + return NULL; +} + +static __isl_give isl_vec *basic_set_sample(__isl_take isl_basic_set *bset, + int bounded) +{ + struct isl_ctx *ctx; + unsigned dim; + if (!bset) + return NULL; + + ctx = bset->ctx; + if (isl_basic_set_plain_is_empty(bset)) + return empty_sample(bset); + + dim = isl_basic_set_n_dim(bset); + isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error); + isl_assert(ctx, bset->n_div == 0, goto error); + + if (bset->sample && bset->sample->size == 1 + dim) { + int contains = isl_basic_set_contains(bset, bset->sample); + if (contains < 0) + goto error; + if (contains) { + struct isl_vec *sample = isl_vec_copy(bset->sample); + isl_basic_set_free(bset); + return sample; + } + } + isl_vec_free(bset->sample); + bset->sample = NULL; + + if (bset->n_eq > 0) + return sample_eq(bset, bounded ? isl_basic_set_sample_bounded + : isl_basic_set_sample_vec); + if (dim == 0) + return zero_sample(bset); + if (dim == 1) + return interval_sample(bset); + + return bounded ? sample_bounded(bset) : gbr_sample(bset); +error: + isl_basic_set_free(bset); + return NULL; +} + +__isl_give isl_vec *isl_basic_set_sample_vec(__isl_take isl_basic_set *bset) +{ + return basic_set_sample(bset, 0); +} + +/* Compute an integer sample in "bset", where the caller guarantees + * that "bset" is bounded. + */ +__isl_give isl_vec *isl_basic_set_sample_bounded(__isl_take isl_basic_set *bset) +{ + return basic_set_sample(bset, 1); +} + +__isl_give isl_basic_set *isl_basic_set_from_vec(__isl_take isl_vec *vec) +{ + int i; + int k; + struct isl_basic_set *bset = NULL; + struct isl_ctx *ctx; + unsigned dim; + + if (!vec) + return NULL; + ctx = vec->ctx; + isl_assert(ctx, vec->size != 0, goto error); + + bset = isl_basic_set_alloc(ctx, 0, vec->size - 1, 0, vec->size - 1, 0); + if (!bset) + goto error; + dim = isl_basic_set_n_dim(bset); + for (i = dim - 1; i >= 0; --i) { + k = isl_basic_set_alloc_equality(bset); + if (k < 0) + goto error; + isl_seq_clr(bset->eq[k], 1 + dim); + isl_int_neg(bset->eq[k][0], vec->el[1 + i]); + isl_int_set(bset->eq[k][1 + i], vec->el[0]); + } + bset->sample = vec; + + return bset; +error: + isl_basic_set_free(bset); + isl_vec_free(vec); + return NULL; +} + +__isl_give isl_basic_map *isl_basic_map_sample(__isl_take isl_basic_map *bmap) +{ + struct isl_basic_set *bset; + struct isl_vec *sample_vec; + + bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap)); + sample_vec = isl_basic_set_sample_vec(bset); + if (!sample_vec) + goto error; + if (sample_vec->size == 0) { + isl_vec_free(sample_vec); + return isl_basic_map_set_to_empty(bmap); + } + isl_vec_free(bmap->sample); + bmap->sample = isl_vec_copy(sample_vec); + bset = isl_basic_set_from_vec(sample_vec); + return isl_basic_map_overlying_set(bset, bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +__isl_give isl_basic_set *isl_basic_set_sample(__isl_take isl_basic_set *bset) +{ + return isl_basic_map_sample(bset); +} + +__isl_give isl_basic_map *isl_map_sample(__isl_take isl_map *map) +{ + int i; + isl_basic_map *sample = NULL; + + if (!map) + goto error; + + for (i = 0; i < map->n; ++i) { + sample = isl_basic_map_sample(isl_basic_map_copy(map->p[i])); + if (!sample) + goto error; + if (!ISL_F_ISSET(sample, ISL_BASIC_MAP_EMPTY)) + break; + isl_basic_map_free(sample); + } + if (i == map->n) + sample = isl_basic_map_empty(isl_map_get_space(map)); + isl_map_free(map); + return sample; +error: + isl_map_free(map); + return NULL; +} + +__isl_give isl_basic_set *isl_set_sample(__isl_take isl_set *set) +{ + return bset_from_bmap(isl_map_sample(set_to_map(set))); +} + +__isl_give isl_point *isl_basic_set_sample_point(__isl_take isl_basic_set *bset) +{ + isl_vec *vec; + isl_space *dim; + + dim = isl_basic_set_get_space(bset); + bset = isl_basic_set_underlying_set(bset); + vec = isl_basic_set_sample_vec(bset); + + return isl_point_alloc(dim, vec); +} + +__isl_give isl_point *isl_set_sample_point(__isl_take isl_set *set) +{ + int i; + isl_point *pnt; + + if (!set) + return NULL; + + for (i = 0; i < set->n; ++i) { + pnt = isl_basic_set_sample_point(isl_basic_set_copy(set->p[i])); + if (!pnt) + goto error; + if (!isl_point_is_void(pnt)) + break; + isl_point_free(pnt); + } + if (i == set->n) + pnt = isl_point_void(isl_set_get_space(set)); + + isl_set_free(set); + return pnt; +error: + isl_set_free(set); + return NULL; +} Index: contrib/isl/isl_scan.h =================================================================== --- /dev/null +++ contrib/isl/isl_scan.h @@ -0,0 +1,26 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_SCAN_H +#define ISL_SCAN_H + +#include +#include + +struct isl_scan_callback { + isl_stat (*add)(struct isl_scan_callback *cb, + __isl_take isl_vec *sample); +}; + +isl_stat isl_basic_set_scan(__isl_take isl_basic_set *bset, + struct isl_scan_callback *callback); +isl_stat isl_set_scan(__isl_take isl_set *set, + struct isl_scan_callback *callback); + +#endif Index: contrib/isl/isl_scan.c =================================================================== --- /dev/null +++ contrib/isl/isl_scan.c @@ -0,0 +1,325 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include "isl_basis_reduction.h" +#include "isl_scan.h" +#include +#include "isl_tab.h" +#include +#include + +struct isl_counter { + struct isl_scan_callback callback; + isl_int count; + isl_int max; +}; + +static isl_stat increment_counter(struct isl_scan_callback *cb, + __isl_take isl_vec *sample) +{ + struct isl_counter *cnt = (struct isl_counter *)cb; + + isl_int_add_ui(cnt->count, cnt->count, 1); + + isl_vec_free(sample); + + if (isl_int_is_zero(cnt->max) || isl_int_lt(cnt->count, cnt->max)) + return isl_stat_ok; + return isl_stat_error; +} + +static int increment_range(struct isl_scan_callback *cb, isl_int min, isl_int max) +{ + struct isl_counter *cnt = (struct isl_counter *)cb; + + isl_int_add(cnt->count, cnt->count, max); + isl_int_sub(cnt->count, cnt->count, min); + isl_int_add_ui(cnt->count, cnt->count, 1); + + if (isl_int_is_zero(cnt->max) || isl_int_lt(cnt->count, cnt->max)) + return 0; + isl_int_set(cnt->count, cnt->max); + return -1; +} + +/* Call callback->add with the current sample value of the tableau "tab". + */ +static int add_solution(struct isl_tab *tab, struct isl_scan_callback *callback) +{ + struct isl_vec *sample; + + if (!tab) + return -1; + sample = isl_tab_get_sample_value(tab); + if (!sample) + return -1; + + return callback->add(callback, sample); +} + +static isl_stat scan_0D(__isl_take isl_basic_set *bset, + struct isl_scan_callback *callback) +{ + struct isl_vec *sample; + + sample = isl_vec_alloc(bset->ctx, 1); + isl_basic_set_free(bset); + + if (!sample) + return isl_stat_error; + + isl_int_set_si(sample->el[0], 1); + + return callback->add(callback, sample); +} + +/* Look for all integer points in "bset", which is assumed to be bounded, + * and call callback->add on each of them. + * + * We first compute a reduced basis for the set and then scan + * the set in the directions of this basis. + * We basically perform a depth first search, where in each level i + * we compute the range in the i-th basis vector direction, given + * fixed values in the directions of the previous basis vector. + * We then add an equality to the tableau fixing the value in the + * direction of the current basis vector to each value in the range + * in turn and then continue to the next level. + * + * The search is implemented iteratively. "level" identifies the current + * basis vector. "init" is true if we want the first value at the current + * level and false if we want the next value. + * Solutions are added in the leaves of the search tree, i.e., after + * we have fixed a value in each direction of the basis. + */ +isl_stat isl_basic_set_scan(__isl_take isl_basic_set *bset, + struct isl_scan_callback *callback) +{ + unsigned dim; + struct isl_mat *B = NULL; + struct isl_tab *tab = NULL; + struct isl_vec *min; + struct isl_vec *max; + struct isl_tab_undo **snap; + int level; + int init; + enum isl_lp_result res; + + if (!bset) + return isl_stat_error; + + dim = isl_basic_set_total_dim(bset); + if (dim == 0) + return scan_0D(bset, callback); + + min = isl_vec_alloc(bset->ctx, dim); + max = isl_vec_alloc(bset->ctx, dim); + snap = isl_alloc_array(bset->ctx, struct isl_tab_undo *, dim); + + if (!min || !max || !snap) + goto error; + + tab = isl_tab_from_basic_set(bset, 0); + if (!tab) + goto error; + if (isl_tab_extend_cons(tab, dim + 1) < 0) + goto error; + + tab->basis = isl_mat_identity(bset->ctx, 1 + dim); + if (1) + tab = isl_tab_compute_reduced_basis(tab); + if (!tab) + goto error; + B = isl_mat_copy(tab->basis); + if (!B) + goto error; + + level = 0; + init = 1; + + while (level >= 0) { + int empty = 0; + if (init) { + res = isl_tab_min(tab, B->row[1 + level], + bset->ctx->one, &min->el[level], NULL, 0); + if (res == isl_lp_empty) + empty = 1; + if (res == isl_lp_error || res == isl_lp_unbounded) + goto error; + isl_seq_neg(B->row[1 + level] + 1, + B->row[1 + level] + 1, dim); + res = isl_tab_min(tab, B->row[1 + level], + bset->ctx->one, &max->el[level], NULL, 0); + isl_seq_neg(B->row[1 + level] + 1, + B->row[1 + level] + 1, dim); + isl_int_neg(max->el[level], max->el[level]); + if (res == isl_lp_empty) + empty = 1; + if (res == isl_lp_error || res == isl_lp_unbounded) + goto error; + snap[level] = isl_tab_snap(tab); + } else + isl_int_add_ui(min->el[level], min->el[level], 1); + + if (empty || isl_int_gt(min->el[level], max->el[level])) { + level--; + init = 0; + if (level >= 0) + if (isl_tab_rollback(tab, snap[level]) < 0) + goto error; + continue; + } + if (level == dim - 1 && callback->add == increment_counter) { + if (increment_range(callback, + min->el[level], max->el[level])) + goto error; + level--; + init = 0; + if (level >= 0) + if (isl_tab_rollback(tab, snap[level]) < 0) + goto error; + continue; + } + isl_int_neg(B->row[1 + level][0], min->el[level]); + if (isl_tab_add_valid_eq(tab, B->row[1 + level]) < 0) + goto error; + isl_int_set_si(B->row[1 + level][0], 0); + if (level < dim - 1) { + ++level; + init = 1; + continue; + } + if (add_solution(tab, callback) < 0) + goto error; + init = 0; + if (isl_tab_rollback(tab, snap[level]) < 0) + goto error; + } + + isl_tab_free(tab); + free(snap); + isl_vec_free(min); + isl_vec_free(max); + isl_basic_set_free(bset); + isl_mat_free(B); + return isl_stat_ok; +error: + isl_tab_free(tab); + free(snap); + isl_vec_free(min); + isl_vec_free(max); + isl_basic_set_free(bset); + isl_mat_free(B); + return isl_stat_error; +} + +isl_stat isl_set_scan(__isl_take isl_set *set, + struct isl_scan_callback *callback) +{ + int i; + + if (!set || !callback) + goto error; + + set = isl_set_cow(set); + set = isl_set_make_disjoint(set); + set = isl_set_compute_divs(set); + if (!set) + goto error; + + for (i = 0; i < set->n; ++i) + if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]), + callback) < 0) + goto error; + + isl_set_free(set); + return isl_stat_ok; +error: + isl_set_free(set); + return isl_stat_error; +} + +int isl_basic_set_count_upto(__isl_keep isl_basic_set *bset, + isl_int max, isl_int *count) +{ + struct isl_counter cnt = { { &increment_counter } }; + + if (!bset) + return -1; + + isl_int_init(cnt.count); + isl_int_init(cnt.max); + + isl_int_set_si(cnt.count, 0); + isl_int_set(cnt.max, max); + if (isl_basic_set_scan(isl_basic_set_copy(bset), &cnt.callback) < 0 && + isl_int_lt(cnt.count, cnt.max)) + goto error; + + isl_int_set(*count, cnt.count); + isl_int_clear(cnt.max); + isl_int_clear(cnt.count); + + return 0; +error: + isl_int_clear(cnt.count); + return -1; +} + +int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count) +{ + struct isl_counter cnt = { { &increment_counter } }; + + if (!set) + return -1; + + isl_int_init(cnt.count); + isl_int_init(cnt.max); + + isl_int_set_si(cnt.count, 0); + isl_int_set(cnt.max, max); + if (isl_set_scan(isl_set_copy(set), &cnt.callback) < 0 && + isl_int_lt(cnt.count, cnt.max)) + goto error; + + isl_int_set(*count, cnt.count); + isl_int_clear(cnt.max); + isl_int_clear(cnt.count); + + return 0; +error: + isl_int_clear(cnt.count); + return -1; +} + +int isl_set_count(__isl_keep isl_set *set, isl_int *count) +{ + if (!set) + return -1; + return isl_set_count_upto(set, set->ctx->zero, count); +} + +/* Count the total number of elements in "set" (in an inefficient way) and + * return the result. + */ +__isl_give isl_val *isl_set_count_val(__isl_keep isl_set *set) +{ + isl_val *v; + + if (!set) + return NULL; + v = isl_val_zero(isl_set_get_ctx(set)); + v = isl_val_cow(v); + if (!v) + return NULL; + if (isl_set_count(set, &v->n) < 0) + v = isl_val_free(v); + return v; +} Index: contrib/isl/isl_schedule.c =================================================================== --- /dev/null +++ contrib/isl/isl_schedule.c @@ -0,0 +1,684 @@ +/* + * Copyright 2011 INRIA Saclay + * Copyright 2012-2014 Ecole Normale Superieure + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Return a schedule encapsulating the given schedule tree. + * + * We currently only allow schedule trees with a domain or extension as root. + * + * The leaf field is initialized as a leaf node so that it can be + * used to represent leaves in the constructed schedule. + * The reference count is set to -1 since the isl_schedule_tree + * should never be freed. It is up to the (internal) users of + * these leaves to ensure that they are only used while the schedule + * is still alive. + */ +__isl_give isl_schedule *isl_schedule_from_schedule_tree(isl_ctx *ctx, + __isl_take isl_schedule_tree *tree) +{ + enum isl_schedule_node_type type; + isl_schedule *schedule; + + if (!tree) + return NULL; + type = isl_schedule_tree_get_type(tree); + if (type != isl_schedule_node_domain && + type != isl_schedule_node_extension) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported, + "root of schedule tree should be a domain or extension", + goto error); + + schedule = isl_calloc_type(ctx, isl_schedule); + if (!schedule) + goto error; + + schedule->ref = 1; + schedule->root = tree; + schedule->leaf = isl_schedule_tree_leaf(ctx); + + if (!schedule->leaf) + return isl_schedule_free(schedule); + return schedule; +error: + isl_schedule_tree_free(tree); + return NULL; +} + +/* Return a pointer to a schedule with as single node + * a domain node with the given domain. + */ +__isl_give isl_schedule *isl_schedule_from_domain( + __isl_take isl_union_set *domain) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + ctx = isl_union_set_get_ctx(domain); + tree = isl_schedule_tree_from_domain(domain); + return isl_schedule_from_schedule_tree(ctx, tree); +} + +/* Return a pointer to a schedule with as single node + * a domain node with an empty domain. + */ +__isl_give isl_schedule *isl_schedule_empty(__isl_take isl_space *space) +{ + return isl_schedule_from_domain(isl_union_set_empty(space)); +} + +/* Return a new reference to "sched". + */ +__isl_give isl_schedule *isl_schedule_copy(__isl_keep isl_schedule *sched) +{ + if (!sched) + return NULL; + + sched->ref++; + return sched; +} + +/* Return an isl_schedule that is equal to "schedule" and that has only + * a single reference. + */ +__isl_give isl_schedule *isl_schedule_cow(__isl_take isl_schedule *schedule) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!schedule) + return NULL; + if (schedule->ref == 1) + return schedule; + + ctx = isl_schedule_get_ctx(schedule); + schedule->ref--; + tree = isl_schedule_tree_copy(schedule->root); + return isl_schedule_from_schedule_tree(ctx, tree); +} + +__isl_null isl_schedule *isl_schedule_free(__isl_take isl_schedule *sched) +{ + if (!sched) + return NULL; + + if (--sched->ref > 0) + return NULL; + + isl_schedule_tree_free(sched->root); + isl_schedule_tree_free(sched->leaf); + free(sched); + return NULL; +} + +/* Replace the root of "schedule" by "tree". + */ +__isl_give isl_schedule *isl_schedule_set_root( + __isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree) +{ + if (!schedule || !tree) + goto error; + if (schedule->root == tree) { + isl_schedule_tree_free(tree); + return schedule; + } + + schedule = isl_schedule_cow(schedule); + if (!schedule) + goto error; + isl_schedule_tree_free(schedule->root); + schedule->root = tree; + + return schedule; +error: + isl_schedule_free(schedule); + isl_schedule_tree_free(tree); + return NULL; +} + +isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *schedule) +{ + return schedule ? isl_schedule_tree_get_ctx(schedule->leaf) : NULL; +} + +/* Return a pointer to the leaf of "schedule". + */ +__isl_keep isl_schedule_tree *isl_schedule_peek_leaf( + __isl_keep isl_schedule *schedule) +{ + return schedule ? schedule->leaf : NULL; +} + +/* Are "schedule1" and "schedule2" obviously equal to each other? + */ +isl_bool isl_schedule_plain_is_equal(__isl_keep isl_schedule *schedule1, + __isl_keep isl_schedule *schedule2) +{ + if (!schedule1 || !schedule2) + return isl_bool_error; + if (schedule1 == schedule2) + return isl_bool_true; + return isl_schedule_tree_plain_is_equal(schedule1->root, + schedule2->root); +} + +/* Return the (parameter) space of the schedule, i.e., the space + * of the root domain. + */ +__isl_give isl_space *isl_schedule_get_space( + __isl_keep isl_schedule *schedule) +{ + enum isl_schedule_node_type type; + isl_space *space; + isl_union_set *domain; + + if (!schedule) + return NULL; + type = isl_schedule_tree_get_type(schedule->root); + if (type != isl_schedule_node_domain) + isl_die(isl_schedule_get_ctx(schedule), isl_error_internal, + "root node not a domain node", return NULL); + + domain = isl_schedule_tree_domain_get_domain(schedule->root); + space = isl_union_set_get_space(domain); + isl_union_set_free(domain); + + return space; +} + +/* Return a pointer to the root of "schedule". + */ +__isl_give isl_schedule_node *isl_schedule_get_root( + __isl_keep isl_schedule *schedule) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + isl_schedule_tree_list *ancestors; + + if (!schedule) + return NULL; + + ctx = isl_schedule_get_ctx(schedule); + tree = isl_schedule_tree_copy(schedule->root); + schedule = isl_schedule_copy(schedule); + ancestors = isl_schedule_tree_list_alloc(ctx, 0); + return isl_schedule_node_alloc(schedule, tree, ancestors, NULL); +} + +/* Return the domain of the root domain node of "schedule". + */ +__isl_give isl_union_set *isl_schedule_get_domain( + __isl_keep isl_schedule *schedule) +{ + if (!schedule) + return NULL; + return isl_schedule_tree_domain_get_domain(schedule->root); +} + +/* Traverse all nodes of "sched" in depth first preorder. + * + * If "fn" returns -1 on any of the nodes, then the traversal is aborted. + * If "fn" returns 0 on any of the nodes, then the subtree rooted + * at that node is skipped. + * + * Return 0 on success and -1 on failure. + */ +isl_stat isl_schedule_foreach_schedule_node_top_down( + __isl_keep isl_schedule *sched, + isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user), + void *user) +{ + isl_schedule_node *node; + isl_stat r; + + if (!sched) + return isl_stat_error; + + node = isl_schedule_get_root(sched); + r = isl_schedule_node_foreach_descendant_top_down(node, fn, user); + isl_schedule_node_free(node); + + return r; +} + +/* Traverse the node of "sched" in depth first postorder, + * allowing the user to modify the visited node. + * The traversal continues from the node returned by the callback function. + * It is the responsibility of the user to ensure that this does not + * lead to an infinite loop. It is safest to always return a pointer + * to the same position (same ancestors and child positions) as the input node. + */ +__isl_give isl_schedule *isl_schedule_map_schedule_node_bottom_up( + __isl_take isl_schedule *schedule, + __isl_give isl_schedule_node *(*fn)( + __isl_take isl_schedule_node *node, void *user), void *user) +{ + isl_schedule_node *node; + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + + node = isl_schedule_node_map_descendant_bottom_up(node, fn, user); + schedule = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + return schedule; +} + +/* Wrapper around isl_schedule_node_reset_user for use as + * an isl_schedule_map_schedule_node_bottom_up callback. + */ +static __isl_give isl_schedule_node *reset_user( + __isl_take isl_schedule_node *node, void *user) +{ + return isl_schedule_node_reset_user(node); +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * in the schedule "schedule". + */ +__isl_give isl_schedule *isl_schedule_reset_user( + __isl_take isl_schedule *schedule) +{ + return isl_schedule_map_schedule_node_bottom_up(schedule, &reset_user, + NULL); +} + +/* Wrapper around isl_schedule_node_align_params for use as + * an isl_schedule_map_schedule_node_bottom_up callback. + */ +static __isl_give isl_schedule_node *align_params( + __isl_take isl_schedule_node *node, void *user) +{ + isl_space *space = user; + + return isl_schedule_node_align_params(node, isl_space_copy(space)); +} + +/* Align the parameters of all nodes in schedule "schedule" + * to those of "space". + */ +__isl_give isl_schedule *isl_schedule_align_params( + __isl_take isl_schedule *schedule, __isl_take isl_space *space) +{ + schedule = isl_schedule_map_schedule_node_bottom_up(schedule, + &align_params, space); + isl_space_free(space); + return schedule; +} + +/* Wrapper around isl_schedule_node_pullback_union_pw_multi_aff for use as + * an isl_schedule_map_schedule_node_bottom_up callback. + */ +static __isl_give isl_schedule_node *pullback_upma( + __isl_take isl_schedule_node *node, void *user) +{ + isl_union_pw_multi_aff *upma = user; + + return isl_schedule_node_pullback_union_pw_multi_aff(node, + isl_union_pw_multi_aff_copy(upma)); +} + +/* Compute the pullback of "schedule" by the function represented by "upma". + * In other words, plug in "upma" in the iteration domains of "schedule". + * + * The schedule tree is not allowed to contain any expansion nodes. + */ +__isl_give isl_schedule *isl_schedule_pullback_union_pw_multi_aff( + __isl_take isl_schedule *schedule, + __isl_take isl_union_pw_multi_aff *upma) +{ + schedule = isl_schedule_map_schedule_node_bottom_up(schedule, + &pullback_upma, upma); + isl_union_pw_multi_aff_free(upma); + return schedule; +} + +/* Expand the schedule "schedule" by extending all leaves + * with an expansion node with as subtree the tree of "expansion". + * The expansion of the expansion node is determined by "contraction" + * and the domain of "expansion". That is, the domain of "expansion" + * is contracted according to "contraction". + * + * Call isl_schedule_node_expand after extracting the required + * information from "expansion". + */ +__isl_give isl_schedule *isl_schedule_expand(__isl_take isl_schedule *schedule, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_schedule *expansion) +{ + isl_union_set *domain; + isl_schedule_node *node; + isl_schedule_tree *tree; + + domain = isl_schedule_get_domain(expansion); + + node = isl_schedule_get_root(expansion); + node = isl_schedule_node_child(node, 0); + tree = isl_schedule_node_get_tree(node); + isl_schedule_node_free(node); + isl_schedule_free(expansion); + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + node = isl_schedule_node_expand(node, contraction, domain, tree); + schedule = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + return schedule; +} + +/* Intersect the domain of the schedule "schedule" with "domain". + * The root of "schedule" is required to be a domain node. + */ +__isl_give isl_schedule *isl_schedule_intersect_domain( + __isl_take isl_schedule *schedule, __isl_take isl_union_set *domain) +{ + enum isl_schedule_node_type root_type; + isl_schedule_node *node; + + if (!schedule || !domain) + goto error; + + root_type = isl_schedule_tree_get_type(schedule->root); + if (root_type != isl_schedule_node_domain) + isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid, + "root node must be a domain node", goto error); + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + node = isl_schedule_node_domain_intersect_domain(node, domain); + schedule = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + return schedule; +error: + isl_schedule_free(schedule); + isl_union_set_free(domain); + return NULL; +} + +/* Replace the domain of the schedule "schedule" with the gist + * of the original domain with respect to the parameter domain "context". + */ +__isl_give isl_schedule *isl_schedule_gist_domain_params( + __isl_take isl_schedule *schedule, __isl_take isl_set *context) +{ + enum isl_schedule_node_type root_type; + isl_schedule_node *node; + + if (!schedule || !context) + goto error; + + root_type = isl_schedule_tree_get_type(schedule->root); + if (root_type != isl_schedule_node_domain) + isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid, + "root node must be a domain node", goto error); + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + node = isl_schedule_node_domain_gist_params(node, context); + schedule = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + return schedule; +error: + isl_schedule_free(schedule); + isl_set_free(context); + return NULL; +} + +/* Return an isl_union_map representation of the schedule. In particular, + * return an isl_union_map corresponding to the subtree schedule of the child + * of the root domain node. That is, we do not intersect the domain + * of the returned isl_union_map with the domain constraints. + */ +__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched) +{ + enum isl_schedule_node_type type; + isl_schedule_node *node; + isl_union_map *umap; + + if (!sched) + return NULL; + type = isl_schedule_tree_get_type(sched->root); + if (type != isl_schedule_node_domain) + isl_die(isl_schedule_get_ctx(sched), isl_error_internal, + "root node not a domain node", return NULL); + + node = isl_schedule_get_root(sched); + node = isl_schedule_node_child(node, 0); + umap = isl_schedule_node_get_subtree_schedule_union_map(node); + isl_schedule_node_free(node); + + return umap; +} + +/* Insert a band node with partial schedule "partial" between the domain + * root node of "schedule" and its single child. + * Return a pointer to the updated schedule. + * + * If any of the nodes in the tree depend on the set of outer band nodes + * then we refuse to insert the band node. + */ +__isl_give isl_schedule *isl_schedule_insert_partial_schedule( + __isl_take isl_schedule *schedule, + __isl_take isl_multi_union_pw_aff *partial) +{ + isl_schedule_node *node; + int anchored; + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + if (!node) + goto error; + if (isl_schedule_node_get_type(node) != isl_schedule_node_domain) + isl_die(isl_schedule_node_get_ctx(node), isl_error_internal, + "root node not a domain node", goto error); + + node = isl_schedule_node_child(node, 0); + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + goto error; + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot insert band node in anchored subtree", + goto error); + node = isl_schedule_node_insert_partial_schedule(node, partial); + + schedule = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + return schedule; +error: + isl_schedule_node_free(node); + isl_multi_union_pw_aff_free(partial); + return NULL; +} + +/* Insert a context node with constraints "context" between the domain + * root node of "schedule" and its single child. + * Return a pointer to the updated schedule. + */ +__isl_give isl_schedule *isl_schedule_insert_context( + __isl_take isl_schedule *schedule, __isl_take isl_set *context) +{ + isl_schedule_node *node; + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_insert_context(node, context); + schedule = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + return schedule; +} + +/* Insert a guard node with constraints "guard" between the domain + * root node of "schedule" and its single child. + * Return a pointer to the updated schedule. + */ +__isl_give isl_schedule *isl_schedule_insert_guard( + __isl_take isl_schedule *schedule, __isl_take isl_set *guard) +{ + isl_schedule_node *node; + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_insert_guard(node, guard); + schedule = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + return schedule; +} + +/* Return a tree with as top-level node a filter corresponding to "filter" and + * as child, the (single) child of "tree". + * However, if this single child is of type "type", then the filter is inserted + * in the children of this single child instead. + */ +static __isl_give isl_schedule_tree *insert_filter_in_child_of_type( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter, + enum isl_schedule_node_type type) +{ + if (!isl_schedule_tree_has_children(tree)) { + isl_schedule_tree_free(tree); + return isl_schedule_tree_from_filter(filter); + } else { + tree = isl_schedule_tree_child(tree, 0); + } + + if (isl_schedule_tree_get_type(tree) == type) + tree = isl_schedule_tree_children_insert_filter(tree, filter); + else + tree = isl_schedule_tree_insert_filter(tree, filter); + + return tree; +} + +/* Construct a schedule that combines the schedules "schedule1" and "schedule2" + * with a top-level node (underneath the domain node) of type "type", + * either isl_schedule_node_sequence or isl_schedule_node_set. + * The domains of the two schedules are assumed to be disjoint. + * + * The new schedule has as domain the union of the domains of the two + * schedules. The child of the domain node is a node of type "type" + * with two filters corresponding to the domains of the input schedules. + * If one (or both) of the top-level nodes of the two schedules is itself + * of type "type", then the filter is pushed into the children of that + * node and the sequence of set is flattened. + */ +__isl_give isl_schedule *isl_schedule_pair(enum isl_schedule_node_type type, + __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2) +{ + int disjoint; + isl_ctx *ctx; + enum isl_schedule_node_type root_type; + isl_schedule_tree *tree1, *tree2; + isl_union_set *filter1, *filter2, *domain; + + if (!schedule1 || !schedule2) + goto error; + + root_type = isl_schedule_tree_get_type(schedule1->root); + if (root_type != isl_schedule_node_domain) + isl_die(isl_schedule_get_ctx(schedule1), isl_error_internal, + "root node not a domain node", goto error); + root_type = isl_schedule_tree_get_type(schedule2->root); + if (root_type != isl_schedule_node_domain) + isl_die(isl_schedule_get_ctx(schedule1), isl_error_internal, + "root node not a domain node", goto error); + + ctx = isl_schedule_get_ctx(schedule1); + tree1 = isl_schedule_tree_copy(schedule1->root); + filter1 = isl_schedule_tree_domain_get_domain(tree1); + tree2 = isl_schedule_tree_copy(schedule2->root); + filter2 = isl_schedule_tree_domain_get_domain(tree2); + + isl_schedule_free(schedule1); + isl_schedule_free(schedule2); + + disjoint = isl_union_set_is_disjoint(filter1, filter2); + if (disjoint < 0) + filter1 = isl_union_set_free(filter1); + if (!disjoint) + isl_die(ctx, isl_error_invalid, + "schedule domains not disjoint", + filter1 = isl_union_set_free(filter1)); + + domain = isl_union_set_union(isl_union_set_copy(filter1), + isl_union_set_copy(filter2)); + filter1 = isl_union_set_gist(filter1, isl_union_set_copy(domain)); + filter2 = isl_union_set_gist(filter2, isl_union_set_copy(domain)); + + tree1 = insert_filter_in_child_of_type(tree1, filter1, type); + tree2 = insert_filter_in_child_of_type(tree2, filter2, type); + + tree1 = isl_schedule_tree_from_pair(type, tree1, tree2); + tree1 = isl_schedule_tree_insert_domain(tree1, domain); + + return isl_schedule_from_schedule_tree(ctx, tree1); +error: + isl_schedule_free(schedule1); + isl_schedule_free(schedule2); + return NULL; +} + +/* Construct a schedule that combines the schedules "schedule1" and "schedule2" + * through a sequence node. + * The domains of the input schedules are assumed to be disjoint. + */ +__isl_give isl_schedule *isl_schedule_sequence( + __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2) +{ + return isl_schedule_pair(isl_schedule_node_sequence, + schedule1, schedule2); +} + +/* Construct a schedule that combines the schedules "schedule1" and "schedule2" + * through a set node. + * The domains of the input schedules are assumed to be disjoint. + */ +__isl_give isl_schedule *isl_schedule_set( + __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2) +{ + return isl_schedule_pair(isl_schedule_node_set, schedule1, schedule2); +} + +/* Print "schedule" to "p". + */ +__isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p, + __isl_keep isl_schedule *schedule) +{ + if (!schedule) + return isl_printer_free(p); + + return isl_printer_print_schedule_tree(p, schedule->root); +} + +#undef BASE +#define BASE schedule +#include Index: contrib/isl/isl_schedule_band.h =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_band.h @@ -0,0 +1,125 @@ +#ifndef ISL_SCHEDULE_BAND_H +#define ISL_SCHEDULE_BAND_H + +#include +#include +#include + +/* Information about a band within a schedule. + * + * n is the number of scheduling dimensions within the band. + * coincident is an array of length n, indicating whether a scheduling dimension + * satisfies the coincidence constraints in the sense that + * the corresponding dependence distances are zero. + * permutable is set if the band is permutable. + * mupa is the partial schedule corresponding to this band. The dimension + * of mupa is equal to n. + * loop_type contains the loop AST generation types for the members + * in the band. It may be NULL, if all members are + * of type isl_ast_loop_default. + * isolate_loop_type contains the loop AST generation types for the members + * in the band for the isolated part. It may be NULL, if all members are + * of type isl_ast_loop_default. + * ast_build_options are the remaining AST build options associated + * to the band. + * anchored is set if the node depends on its position in the schedule tree. + * In particular, it is set if the AST build options include + * an isolate option. + */ +struct isl_schedule_band { + int ref; + + int n; + int *coincident; + int permutable; + + isl_multi_union_pw_aff *mupa; + + int anchored; + isl_union_set *ast_build_options; + enum isl_ast_loop_type *loop_type; + enum isl_ast_loop_type *isolate_loop_type; +}; +typedef struct isl_schedule_band isl_schedule_band; + +__isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); +__isl_give isl_schedule_band *isl_schedule_band_copy( + __isl_keep isl_schedule_band *band); +__isl_null isl_schedule_band *isl_schedule_band_free( + __isl_take isl_schedule_band *band); + +isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band); + +isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1, + __isl_keep isl_schedule_band *band2); + +int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band); + +__isl_give isl_space *isl_schedule_band_get_space( + __isl_keep isl_schedule_band *band); +__isl_give isl_schedule_band *isl_schedule_band_intersect_domain( + __isl_take isl_schedule_band *band, __isl_take isl_union_set *domain); +__isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule( + __isl_keep isl_schedule_band *band); +__isl_give isl_schedule_band *isl_schedule_band_set_partial_schedule( + __isl_take isl_schedule_band *band, + __isl_take isl_multi_union_pw_aff *schedule); +enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type( + __isl_keep isl_schedule_band *band, int pos); +__isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type( + __isl_take isl_schedule_band *band, int pos, + enum isl_ast_loop_type type); +enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type( + __isl_keep isl_schedule_band *band, int pos); +__isl_give isl_schedule_band * +isl_schedule_band_member_set_isolate_ast_loop_type( + __isl_take isl_schedule_band *band, int pos, + enum isl_ast_loop_type type); +__isl_give isl_union_set *isl_schedule_band_get_ast_build_options( + __isl_keep isl_schedule_band *band); +__isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options( + __isl_take isl_schedule_band *band, __isl_take isl_union_set *options); +__isl_give isl_set *isl_schedule_band_get_ast_isolate_option( + __isl_keep isl_schedule_band *band, int depth); +__isl_give isl_schedule_band *isl_schedule_band_replace_ast_build_option( + __isl_take isl_schedule_band *band, __isl_take isl_set *drop, + __isl_take isl_set *add); + +int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band); +isl_bool isl_schedule_band_member_get_coincident( + __isl_keep isl_schedule_band *band, int pos); +__isl_give isl_schedule_band *isl_schedule_band_member_set_coincident( + __isl_take isl_schedule_band *band, int pos, int coincident); +isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band); +__isl_give isl_schedule_band *isl_schedule_band_set_permutable( + __isl_take isl_schedule_band *band, int permutable); + +__isl_give isl_schedule_band *isl_schedule_band_scale( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_band *isl_schedule_band_scale_down( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_band *isl_schedule_band_mod( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_band *isl_schedule_band_tile( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes); +__isl_give isl_schedule_band *isl_schedule_band_point( + __isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile, + __isl_take isl_multi_val *sizes); +__isl_give isl_schedule_band *isl_schedule_band_shift( + __isl_take isl_schedule_band *band, + __isl_take isl_multi_union_pw_aff *shift); +__isl_give isl_schedule_band *isl_schedule_band_drop( + __isl_take isl_schedule_band *band, int pos, int n); +__isl_give isl_schedule_band *isl_schedule_band_gist( + __isl_take isl_schedule_band *band, __isl_take isl_union_set *context); + +__isl_give isl_schedule_band *isl_schedule_band_reset_user( + __isl_take isl_schedule_band *band); +__isl_give isl_schedule_band *isl_schedule_band_align_params( + __isl_take isl_schedule_band *band, __isl_take isl_space *space); +__isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff( + __isl_take isl_schedule_band *band, + __isl_take isl_union_pw_multi_aff *upma); + +#endif Index: contrib/isl/isl_schedule_band.c =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_band.c @@ -0,0 +1,1301 @@ +/* + * Copyright 2013-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include +#include +#include + +isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band) +{ + return band ? isl_multi_union_pw_aff_get_ctx(band->mupa) : NULL; +} + +/* Return a new uninitialized isl_schedule_band. + */ +static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx) +{ + isl_schedule_band *band; + + band = isl_calloc_type(ctx, isl_schedule_band); + if (!band) + return NULL; + + band->ref = 1; + + return band; +} + +/* Return a new isl_schedule_band with partial schedule "mupa". + * First replace "mupa" by its greatest integer part to ensure + * that the schedule is always integral. + * The band is not marked permutable, the dimensions are not + * marked coincident and the AST build options are empty. + * Since there are no build options, the node is not anchored. + */ +__isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa) +{ + isl_ctx *ctx; + isl_schedule_band *band; + isl_space *space; + + mupa = isl_multi_union_pw_aff_floor(mupa); + if (!mupa) + return NULL; + ctx = isl_multi_union_pw_aff_get_ctx(mupa); + band = isl_schedule_band_alloc(ctx); + if (!band) + goto error; + + band->n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + band->coincident = isl_calloc_array(ctx, int, band->n); + band->mupa = mupa; + space = isl_space_params_alloc(ctx, 0); + band->ast_build_options = isl_union_set_empty(space); + band->anchored = 0; + + if ((band->n && !band->coincident) || !band->ast_build_options) + return isl_schedule_band_free(band); + + return band; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Create a duplicate of the given isl_schedule_band. + */ +__isl_give isl_schedule_band *isl_schedule_band_dup( + __isl_keep isl_schedule_band *band) +{ + int i; + isl_ctx *ctx; + isl_schedule_band *dup; + + if (!band) + return NULL; + + ctx = isl_schedule_band_get_ctx(band); + dup = isl_schedule_band_alloc(ctx); + if (!dup) + return NULL; + + dup->n = band->n; + dup->coincident = isl_alloc_array(ctx, int, band->n); + if (band->n && !dup->coincident) + return isl_schedule_band_free(dup); + + for (i = 0; i < band->n; ++i) + dup->coincident[i] = band->coincident[i]; + dup->permutable = band->permutable; + + dup->mupa = isl_multi_union_pw_aff_copy(band->mupa); + dup->ast_build_options = isl_union_set_copy(band->ast_build_options); + if (!dup->mupa || !dup->ast_build_options) + return isl_schedule_band_free(dup); + + if (band->loop_type) { + dup->loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !dup->loop_type) + return isl_schedule_band_free(dup); + for (i = 0; i < band->n; ++i) + dup->loop_type[i] = band->loop_type[i]; + } + if (band->isolate_loop_type) { + dup->isolate_loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !dup->isolate_loop_type) + return isl_schedule_band_free(dup); + for (i = 0; i < band->n; ++i) + dup->isolate_loop_type[i] = band->isolate_loop_type[i]; + } + + return dup; +} + +/* Return an isl_schedule_band that is equal to "band" and that has only + * a single reference. + */ +__isl_give isl_schedule_band *isl_schedule_band_cow( + __isl_take isl_schedule_band *band) +{ + if (!band) + return NULL; + + if (band->ref == 1) + return band; + band->ref--; + return isl_schedule_band_dup(band); +} + +/* Return a new reference to "band". + */ +__isl_give isl_schedule_band *isl_schedule_band_copy( + __isl_keep isl_schedule_band *band) +{ + if (!band) + return NULL; + + band->ref++; + return band; +} + +/* Free a reference to "band" and return NULL. + */ +__isl_null isl_schedule_band *isl_schedule_band_free( + __isl_take isl_schedule_band *band) +{ + if (!band) + return NULL; + + if (--band->ref > 0) + return NULL; + + isl_multi_union_pw_aff_free(band->mupa); + isl_union_set_free(band->ast_build_options); + free(band->loop_type); + free(band->isolate_loop_type); + free(band->coincident); + free(band); + + return NULL; +} + +/* Are "band1" and "band2" obviously equal? + */ +isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1, + __isl_keep isl_schedule_band *band2) +{ + int i; + isl_bool equal; + + if (!band1 || !band2) + return isl_bool_error; + if (band1 == band2) + return isl_bool_true; + + if (band1->n != band2->n) + return isl_bool_false; + for (i = 0; i < band1->n; ++i) + if (band1->coincident[i] != band2->coincident[i]) + return isl_bool_false; + if (band1->permutable != band2->permutable) + return isl_bool_false; + + equal = isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa); + if (equal < 0 || !equal) + return equal; + + if (!band1->loop_type != !band2->loop_type) + return isl_bool_false; + if (band1->loop_type) + for (i = 0; i < band1->n; ++i) + if (band1->loop_type[i] != band2->loop_type[i]) + return isl_bool_false; + + if (!band1->isolate_loop_type != !band2->isolate_loop_type) + return isl_bool_false; + if (band1->isolate_loop_type) + for (i = 0; i < band1->n; ++i) + if (band1->isolate_loop_type[i] != + band2->isolate_loop_type[i]) + return isl_bool_false; + + return isl_union_set_is_equal(band1->ast_build_options, + band2->ast_build_options); +} + +/* Return the number of scheduling dimensions in the band. + */ +int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band) +{ + return band ? band->n : 0; +} + +/* Is the given scheduling dimension coincident within the band and + * with respect to the coincidence constraints? + */ +isl_bool isl_schedule_band_member_get_coincident( + __isl_keep isl_schedule_band *band, int pos) +{ + if (!band) + return isl_bool_error; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", return isl_bool_error); + + return band->coincident[pos]; +} + +/* Mark the given scheduling dimension as being coincident or not + * according to "coincident". + */ +__isl_give isl_schedule_band *isl_schedule_band_member_set_coincident( + __isl_take isl_schedule_band *band, int pos, int coincident) +{ + if (!band) + return NULL; + if (isl_schedule_band_member_get_coincident(band, pos) == coincident) + return band; + band = isl_schedule_band_cow(band); + if (!band) + return NULL; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", + return isl_schedule_band_free(band)); + + band->coincident[pos] = coincident; + + return band; +} + +/* Is the schedule band mark permutable? + */ +isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band) +{ + if (!band) + return isl_bool_error; + return band->permutable; +} + +/* Mark the schedule band permutable or not according to "permutable"? + */ +__isl_give isl_schedule_band *isl_schedule_band_set_permutable( + __isl_take isl_schedule_band *band, int permutable) +{ + if (!band) + return NULL; + if (band->permutable == permutable) + return band; + band = isl_schedule_band_cow(band); + if (!band) + return NULL; + + band->permutable = permutable; + + return band; +} + +/* Is the band node "node" anchored? That is, does it reference + * the outer band nodes? + */ +int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band) +{ + return band ? band->anchored : -1; +} + +/* Return the schedule space of the band. + */ +__isl_give isl_space *isl_schedule_band_get_space( + __isl_keep isl_schedule_band *band) +{ + if (!band) + return NULL; + return isl_multi_union_pw_aff_get_space(band->mupa); +} + +/* Intersect the domain of the band schedule of "band" with "domain". + */ +__isl_give isl_schedule_band *isl_schedule_band_intersect_domain( + __isl_take isl_schedule_band *band, __isl_take isl_union_set *domain) +{ + band = isl_schedule_band_cow(band); + if (!band || !domain) + goto error; + + band->mupa = isl_multi_union_pw_aff_intersect_domain(band->mupa, + domain); + if (!band->mupa) + return isl_schedule_band_free(band); + + return band; +error: + isl_schedule_band_free(band); + isl_union_set_free(domain); + return NULL; +} + +/* Return the schedule of the band in isolation. + */ +__isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule( + __isl_keep isl_schedule_band *band) +{ + return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL; +} + +/* Replace the schedule of "band" by "schedule". + */ +__isl_give isl_schedule_band *isl_schedule_band_set_partial_schedule( + __isl_take isl_schedule_band *band, + __isl_take isl_multi_union_pw_aff *schedule) +{ + band = isl_schedule_band_cow(band); + if (!band || !schedule) + goto error; + + isl_multi_union_pw_aff_free(band->mupa); + band->mupa = schedule; + + return band; +error: + isl_schedule_band_free(band); + isl_multi_union_pw_aff_free(schedule); + return NULL; +} + +/* Return the loop AST generation type for the band member of "band" + * at position "pos". + */ +enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type( + __isl_keep isl_schedule_band *band, int pos) +{ + if (!band) + return isl_ast_loop_error; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", return -1); + + if (!band->loop_type) + return isl_ast_loop_default; + + return band->loop_type[pos]; +} + +/* Set the loop AST generation type for the band member of "band" + * at position "pos" to "type". + */ +__isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type( + __isl_take isl_schedule_band *band, int pos, + enum isl_ast_loop_type type) +{ + if (!band) + return NULL; + if (isl_schedule_band_member_get_ast_loop_type(band, pos) == type) + return band; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", + return isl_schedule_band_free(band)); + + band = isl_schedule_band_cow(band); + if (!band) + return isl_schedule_band_free(band); + + if (!band->loop_type) { + isl_ctx *ctx; + + ctx = isl_schedule_band_get_ctx(band); + band->loop_type = isl_calloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !band->loop_type) + return isl_schedule_band_free(band); + } + + band->loop_type[pos] = type; + + return band; +} + +/* Return the loop AST generation type for the band member of "band" + * at position "pos" for the part that has been isolated by the isolate option. + */ +enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type( + __isl_keep isl_schedule_band *band, int pos) +{ + if (!band) + return isl_ast_loop_error; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", return -1); + + if (!band->isolate_loop_type) + return isl_ast_loop_default; + + return band->isolate_loop_type[pos]; +} + +/* Set the loop AST generation type for the band member of "band" + * at position "pos" to "type" for the part that has been isolated + * by the isolate option. + */ +__isl_give isl_schedule_band * +isl_schedule_band_member_set_isolate_ast_loop_type( + __isl_take isl_schedule_band *band, int pos, + enum isl_ast_loop_type type) +{ + if (!band) + return NULL; + if (isl_schedule_band_member_get_isolate_ast_loop_type(band, pos) == + type) + return band; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", + return isl_schedule_band_free(band)); + + band = isl_schedule_band_cow(band); + if (!band) + return isl_schedule_band_free(band); + + if (!band->isolate_loop_type) { + isl_ctx *ctx; + + ctx = isl_schedule_band_get_ctx(band); + band->isolate_loop_type = isl_calloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !band->isolate_loop_type) + return isl_schedule_band_free(band); + } + + band->isolate_loop_type[pos] = type; + + return band; +} + +static const char *option_str[] = { + [isl_ast_loop_atomic] = "atomic", + [isl_ast_loop_unroll] = "unroll", + [isl_ast_loop_separate] = "separate" +}; + +/* Given a parameter space "space", extend it to a set space + * + * { type[x] } + * + * or + * + * { [isolate[] -> type[x]] } + * + * depending on whether "isolate" is set. + * These can be used to encode loop AST generation options of the given type. + */ +static __isl_give isl_space *loop_type_space(__isl_take isl_space *space, + enum isl_ast_loop_type type, int isolate) +{ + const char *name; + + name = option_str[type]; + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, 1); + space = isl_space_set_tuple_name(space, isl_dim_set, name); + if (!isolate) + return space; + space = isl_space_from_range(space); + space = isl_space_set_tuple_name(space, isl_dim_in, "isolate"); + space = isl_space_wrap(space); + + return space; +} + +/* Add encodings of the "n" loop AST generation options "type" to "options". + * If "isolate" is set, then these options refer to the isolated part. + * + * In particular, for each sequence of consecutive identical types "t", + * different from the default, add an option + * + * { t[x] : first <= x <= last } + * + * or + * + * { [isolate[] -> t[x]] : first <= x <= last } + */ +static __isl_give isl_union_set *add_loop_types( + __isl_take isl_union_set *options, int n, enum isl_ast_loop_type *type, + int isolate) +{ + int i; + + if (!type) + return options; + if (!options) + return NULL; + + for (i = 0; i < n; ++i) { + int first; + isl_space *space; + isl_set *option; + + if (type[i] == isl_ast_loop_default) + continue; + + first = i; + while (i + 1 < n && type[i + 1] == type[i]) + ++i; + + space = isl_union_set_get_space(options); + space = loop_type_space(space, type[i], isolate); + option = isl_set_universe(space); + option = isl_set_lower_bound_si(option, isl_dim_set, 0, first); + option = isl_set_upper_bound_si(option, isl_dim_set, 0, i); + options = isl_union_set_add_set(options, option); + } + + return options; +} + +/* Return the AST build options associated to "band". + */ +__isl_give isl_union_set *isl_schedule_band_get_ast_build_options( + __isl_keep isl_schedule_band *band) +{ + isl_union_set *options; + + if (!band) + return NULL; + + options = isl_union_set_copy(band->ast_build_options); + options = add_loop_types(options, band->n, band->loop_type, 0); + options = add_loop_types(options, band->n, band->isolate_loop_type, 1); + + return options; +} + +/* Does "uset" contain any set that satisfies "is"? + * "is" is assumed to set its integer argument to 1 if it is satisfied. + */ +static int has_any(__isl_keep isl_union_set *uset, + isl_stat (*is)(__isl_take isl_set *set, void *user)) +{ + int found = 0; + + if (isl_union_set_foreach_set(uset, is, &found) < 0 && !found) + return -1; + + return found; +} + +/* Does "set" live in a space of the form + * + * isolate[[...] -> [...]] + * + * ? + * + * If so, set *found and abort the search. + */ +static isl_stat is_isolate(__isl_take isl_set *set, void *user) +{ + int *found = user; + + if (isl_set_has_tuple_name(set)) { + const char *name; + name = isl_set_get_tuple_name(set); + if (isl_set_is_wrapping(set) && !strcmp(name, "isolate")) + *found = 1; + } + isl_set_free(set); + + return *found ? isl_stat_error : isl_stat_ok; +} + +/* Does "options" include an option of the ofrm + * + * isolate[[...] -> [...]] + * + * ? + */ +static int has_isolate_option(__isl_keep isl_union_set *options) +{ + return has_any(options, &is_isolate); +} + +/* Does "set" encode a loop AST generation option? + */ +static isl_stat is_loop_type_option(__isl_take isl_set *set, void *user) +{ + int *found = user; + + if (isl_set_dim(set, isl_dim_set) == 1 && + isl_set_has_tuple_name(set)) { + const char *name; + enum isl_ast_loop_type type; + name = isl_set_get_tuple_name(set); + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + if (strcmp(name, option_str[type])) + continue; + *found = 1; + break; + } + } + isl_set_free(set); + + return *found ? isl_stat_error : isl_stat_ok; +} + +/* Does "set" encode a loop AST generation option for the isolated part? + * That is, is of the form + * + * { [isolate[] -> t[x]] } + * + * with t equal to "atomic", "unroll" or "separate"? + */ +static isl_stat is_isolate_loop_type_option(__isl_take isl_set *set, void *user) +{ + int *found = user; + const char *name; + enum isl_ast_loop_type type; + isl_map *map; + + if (!isl_set_is_wrapping(set)) { + isl_set_free(set); + return isl_stat_ok; + } + map = isl_set_unwrap(set); + if (!isl_map_has_tuple_name(map, isl_dim_in) || + !isl_map_has_tuple_name(map, isl_dim_out)) { + isl_map_free(map); + return isl_stat_ok; + } + name = isl_map_get_tuple_name(map, isl_dim_in); + if (!strcmp(name, "isolate")) { + name = isl_map_get_tuple_name(map, isl_dim_out); + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + if (strcmp(name, option_str[type])) + continue; + *found = 1; + break; + } + } + isl_map_free(map); + + return *found ? isl_stat_error : isl_stat_ok; +} + +/* Does "options" encode any loop AST generation options + * for the isolated part? + */ +static int has_isolate_loop_type_options(__isl_keep isl_union_set *options) +{ + return has_any(options, &is_isolate_loop_type_option); +} + +/* Does "options" encode any loop AST generation options? + */ +static int has_loop_type_options(__isl_keep isl_union_set *options) +{ + return has_any(options, &is_loop_type_option); +} + +/* Extract the loop AST generation type for the band member + * at position "pos" from "options". + * If "isolate" is set, then extract the loop types for the isolated part. + */ +static enum isl_ast_loop_type extract_loop_type( + __isl_keep isl_union_set *options, int pos, int isolate) +{ + isl_ctx *ctx; + enum isl_ast_loop_type type, res = isl_ast_loop_default; + + ctx = isl_union_set_get_ctx(options); + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + isl_space *space; + isl_set *option; + int empty; + + space = isl_union_set_get_space(options); + space = loop_type_space(space, type, isolate); + option = isl_union_set_extract_set(options, space); + option = isl_set_fix_si(option, isl_dim_set, 0, pos); + empty = isl_set_is_empty(option); + isl_set_free(option); + + if (empty < 0) + return isl_ast_loop_error; + if (empty) + continue; + if (res != isl_ast_loop_default) + isl_die(ctx, isl_error_invalid, + "conflicting loop type options", + return isl_ast_loop_error); + res = type; + } + + return res; +} + +/* Extract the loop AST generation types for the members of "band" + * from "options" and store them in band->loop_type. + * Return -1 on error. + */ +static int extract_loop_types(__isl_keep isl_schedule_band *band, + __isl_keep isl_union_set *options) +{ + int i; + + if (!band->loop_type) { + isl_ctx *ctx = isl_schedule_band_get_ctx(band); + band->loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !band->loop_type) + return -1; + } + for (i = 0; i < band->n; ++i) { + band->loop_type[i] = extract_loop_type(options, i, 0); + if (band->loop_type[i] == isl_ast_loop_error) + return -1; + } + + return 0; +} + +/* Extract the loop AST generation types for the members of "band" + * from "options" for the isolated part and + * store them in band->isolate_loop_type. + * Return -1 on error. + */ +static int extract_isolate_loop_types(__isl_keep isl_schedule_band *band, + __isl_keep isl_union_set *options) +{ + int i; + + if (!band->isolate_loop_type) { + isl_ctx *ctx = isl_schedule_band_get_ctx(band); + band->isolate_loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !band->isolate_loop_type) + return -1; + } + for (i = 0; i < band->n; ++i) { + band->isolate_loop_type[i] = extract_loop_type(options, i, 1); + if (band->isolate_loop_type[i] == isl_ast_loop_error) + return -1; + } + + return 0; +} + +/* Construct universe sets of the spaces that encode loop AST generation + * types (for the isolated part if "isolate" is set). That is, construct + * + * { atomic[x]; separate[x]; unroll[x] } + * + * or + * + * { [isolate[] -> atomic[x]]; [isolate[] -> separate[x]]; + * [isolate[] -> unroll[x]] } + */ +static __isl_give isl_union_set *loop_types(__isl_take isl_space *space, + int isolate) +{ + enum isl_ast_loop_type type; + isl_union_set *types; + + types = isl_union_set_empty(space); + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + isl_set *set; + + space = isl_union_set_get_space(types); + space = loop_type_space(space, type, isolate); + set = isl_set_universe(space); + types = isl_union_set_add_set(types, set); + } + + return types; +} + +/* Remove all elements from spaces that encode loop AST generation types + * from "options". + */ +static __isl_give isl_union_set *clear_loop_types( + __isl_take isl_union_set *options) +{ + isl_union_set *types; + + types = loop_types(isl_union_set_get_space(options), 0); + options = isl_union_set_subtract(options, types); + + return options; +} + +/* Remove all elements from spaces that encode loop AST generation types + * for the isolated part from "options". + */ +static __isl_give isl_union_set *clear_isolate_loop_types( + __isl_take isl_union_set *options) +{ + isl_union_set *types; + + types = loop_types(isl_union_set_get_space(options), 1); + options = isl_union_set_subtract(options, types); + + return options; +} + +/* Replace the AST build options associated to "band" by "options". + * If there are any loop AST generation type options, then they + * are extracted and stored in band->loop_type. Otherwise, + * band->loop_type is removed to indicate that the default applies + * to all members. Similarly for the loop AST generation type options + * for the isolated part, which are stored in band->isolate_loop_type. + * The remaining options are stored in band->ast_build_options. + * + * Set anchored if the options include an isolate option since the + * domain of the wrapped map references the outer band node schedules. + */ +__isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options( + __isl_take isl_schedule_band *band, __isl_take isl_union_set *options) +{ + int has_isolate, has_loop_type, has_isolate_loop_type; + + band = isl_schedule_band_cow(band); + if (!band || !options) + goto error; + has_isolate = has_isolate_option(options); + if (has_isolate < 0) + goto error; + has_loop_type = has_loop_type_options(options); + if (has_loop_type < 0) + goto error; + has_isolate_loop_type = has_isolate_loop_type_options(options); + if (has_isolate_loop_type < 0) + goto error; + + if (!has_loop_type) { + free(band->loop_type); + band->loop_type = NULL; + } else { + if (extract_loop_types(band, options) < 0) + goto error; + options = clear_loop_types(options); + if (!options) + goto error; + } + + if (!has_isolate_loop_type) { + free(band->isolate_loop_type); + band->isolate_loop_type = NULL; + } else { + if (extract_isolate_loop_types(band, options) < 0) + goto error; + options = clear_isolate_loop_types(options); + if (!options) + goto error; + } + + isl_union_set_free(band->ast_build_options); + band->ast_build_options = options; + band->anchored = has_isolate; + + return band; +error: + isl_schedule_band_free(band); + isl_union_set_free(options); + return NULL; +} + +/* Return the "isolate" option associated to "band", assuming + * it at appears at schedule depth "depth". + * + * The isolate option is of the form + * + * isolate[[flattened outer bands] -> band] + */ +__isl_give isl_set *isl_schedule_band_get_ast_isolate_option( + __isl_keep isl_schedule_band *band, int depth) +{ + isl_space *space; + isl_set *isolate; + + if (!band) + return NULL; + + space = isl_schedule_band_get_space(band); + space = isl_space_from_range(space); + space = isl_space_add_dims(space, isl_dim_in, depth); + space = isl_space_wrap(space); + space = isl_space_set_tuple_name(space, isl_dim_set, "isolate"); + + isolate = isl_union_set_extract_set(band->ast_build_options, space); + + return isolate; +} + +/* Replace the option "drop" in the AST build options by "add". + * That is, remove "drop" and add "add". + */ +__isl_give isl_schedule_band *isl_schedule_band_replace_ast_build_option( + __isl_take isl_schedule_band *band, __isl_take isl_set *drop, + __isl_take isl_set *add) +{ + isl_union_set *options; + + band = isl_schedule_band_cow(band); + if (!band) + goto error; + + options = band->ast_build_options; + options = isl_union_set_subtract(options, isl_union_set_from_set(drop)); + options = isl_union_set_union(options, isl_union_set_from_set(add)); + band->ast_build_options = options; + + if (!band->ast_build_options) + return isl_schedule_band_free(band); + + return band; +error: + isl_schedule_band_free(band); + isl_set_free(drop); + isl_set_free(add); + return NULL; +} + +/* Multiply the partial schedule of "band" with the factors in "mv". + * Replace the result by its greatest integer part to ensure + * that the schedule is always integral. + */ +__isl_give isl_schedule_band *isl_schedule_band_scale( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) +{ + band = isl_schedule_band_cow(band); + if (!band || !mv) + goto error; + band->mupa = isl_multi_union_pw_aff_scale_multi_val(band->mupa, mv); + band->mupa = isl_multi_union_pw_aff_floor(band->mupa); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(mv); + return NULL; +} + +/* Divide the partial schedule of "band" by the factors in "mv". + * Replace the result by its greatest integer part to ensure + * that the schedule is always integral. + */ +__isl_give isl_schedule_band *isl_schedule_band_scale_down( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) +{ + band = isl_schedule_band_cow(band); + if (!band || !mv) + goto error; + band->mupa = isl_multi_union_pw_aff_scale_down_multi_val(band->mupa, + mv); + band->mupa = isl_multi_union_pw_aff_floor(band->mupa); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(mv); + return NULL; +} + +/* Reduce the partial schedule of "band" modulo the factors in "mv". + */ +__isl_give isl_schedule_band *isl_schedule_band_mod( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) +{ + band = isl_schedule_band_cow(band); + if (!band || !mv) + goto error; + band->mupa = isl_multi_union_pw_aff_mod_multi_val(band->mupa, mv); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(mv); + return NULL; +} + +/* Shift the partial schedule of "band" by "shift" after checking + * that the domain of the partial schedule would not be affected + * by this shift. + */ +__isl_give isl_schedule_band *isl_schedule_band_shift( + __isl_take isl_schedule_band *band, + __isl_take isl_multi_union_pw_aff *shift) +{ + isl_union_set *dom1, *dom2; + isl_bool subset; + + band = isl_schedule_band_cow(band); + if (!band || !shift) + goto error; + dom1 = isl_multi_union_pw_aff_domain( + isl_multi_union_pw_aff_copy(band->mupa)); + dom2 = isl_multi_union_pw_aff_domain( + isl_multi_union_pw_aff_copy(shift)); + subset = isl_union_set_is_subset(dom1, dom2); + isl_union_set_free(dom1); + isl_union_set_free(dom2); + if (subset < 0) + goto error; + if (!subset) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "domain of shift needs to include domain of " + "partial schedule", goto error); + band->mupa = isl_multi_union_pw_aff_add(band->mupa, shift); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_union_pw_aff_free(shift); + return NULL; +} + +/* Given the schedule of a band, construct the corresponding + * schedule for the tile loops based on the given tile sizes + * and return the result. + * + * If the scale tile loops options is set, then the tile loops + * are scaled by the tile sizes. + * + * That is replace each schedule dimension "i" by either + * "floor(i/s)" or "s * floor(i/s)". + */ +static isl_multi_union_pw_aff *isl_multi_union_pw_aff_tile( + __isl_take isl_multi_union_pw_aff *sched, + __isl_take isl_multi_val *sizes) +{ + isl_ctx *ctx; + int i, n; + isl_val *v; + int scale; + + ctx = isl_multi_val_get_ctx(sizes); + scale = isl_options_get_tile_scale_tile_loops(ctx); + + n = isl_multi_union_pw_aff_dim(sched, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_union_pw_aff *upa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(sched, i); + v = isl_multi_val_get_val(sizes, i); + + upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(v)); + upa = isl_union_pw_aff_floor(upa); + if (scale) + upa = isl_union_pw_aff_scale_val(upa, isl_val_copy(v)); + isl_val_free(v); + + sched = isl_multi_union_pw_aff_set_union_pw_aff(sched, i, upa); + } + + isl_multi_val_free(sizes); + return sched; +} + +/* Replace "band" by a band corresponding to the tile loops of a tiling + * with the given tile sizes. + */ +__isl_give isl_schedule_band *isl_schedule_band_tile( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes) +{ + band = isl_schedule_band_cow(band); + if (!band || !sizes) + goto error; + band->mupa = isl_multi_union_pw_aff_tile(band->mupa, sizes); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(sizes); + return NULL; +} + +/* Replace "band" by a band corresponding to the point loops of a tiling + * with the given tile sizes. + * "tile" is the corresponding tile loop band. + * + * If the shift point loops option is set, then the point loops + * are shifted to start at zero. That is, each schedule dimension "i" + * is replaced by "i - s * floor(i/s)". + * The expression "floor(i/s)" (or "s * floor(i/s)") is extracted from + * the tile band. + * + * Otherwise, the band is left untouched. + */ +__isl_give isl_schedule_band *isl_schedule_band_point( + __isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile, + __isl_take isl_multi_val *sizes) +{ + isl_ctx *ctx; + isl_multi_union_pw_aff *scaled; + + if (!band || !sizes) + goto error; + + ctx = isl_schedule_band_get_ctx(band); + if (!isl_options_get_tile_shift_point_loops(ctx)) { + isl_multi_val_free(sizes); + return band; + } + band = isl_schedule_band_cow(band); + if (!band) + goto error; + + scaled = isl_schedule_band_get_partial_schedule(tile); + if (!isl_options_get_tile_scale_tile_loops(ctx)) + scaled = isl_multi_union_pw_aff_scale_multi_val(scaled, sizes); + else + isl_multi_val_free(sizes); + band->mupa = isl_multi_union_pw_aff_sub(band->mupa, scaled); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(sizes); + return NULL; +} + +/* Drop the "n" dimensions starting at "pos" from "band". + * + * We apply the transformation even if "n" is zero to ensure consistent + * behavior with respect to changes in the schedule space. + * + * The caller is responsible for updating the isolate option. + */ +__isl_give isl_schedule_band *isl_schedule_band_drop( + __isl_take isl_schedule_band *band, int pos, int n) +{ + int i; + + if (pos < 0 || n < 0 || pos + n > band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_internal, + "range out of bounds", + return isl_schedule_band_free(band)); + + band = isl_schedule_band_cow(band); + if (!band) + return NULL; + + band->mupa = isl_multi_union_pw_aff_drop_dims(band->mupa, + isl_dim_set, pos, n); + if (!band->mupa) + return isl_schedule_band_free(band); + + for (i = pos + n; i < band->n; ++i) + band->coincident[i - n] = band->coincident[i]; + if (band->loop_type) + for (i = pos + n; i < band->n; ++i) + band->loop_type[i - n] = band->loop_type[i]; + if (band->isolate_loop_type) + for (i = pos + n; i < band->n; ++i) + band->isolate_loop_type[i - n] = + band->isolate_loop_type[i]; + + band->n -= n; + + return band; +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * in "band". + */ +__isl_give isl_schedule_band *isl_schedule_band_reset_user( + __isl_take isl_schedule_band *band) +{ + band = isl_schedule_band_cow(band); + if (!band) + return NULL; + + band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa); + band->ast_build_options = + isl_union_set_reset_user(band->ast_build_options); + if (!band->mupa || !band->ast_build_options) + return isl_schedule_band_free(band); + + return band; +} + +/* Align the parameters of "band" to those of "space". + */ +__isl_give isl_schedule_band *isl_schedule_band_align_params( + __isl_take isl_schedule_band *band, __isl_take isl_space *space) +{ + band = isl_schedule_band_cow(band); + if (!band || !space) + goto error; + + band->mupa = isl_multi_union_pw_aff_align_params(band->mupa, + isl_space_copy(space)); + band->ast_build_options = + isl_union_set_align_params(band->ast_build_options, space); + if (!band->mupa || !band->ast_build_options) + return isl_schedule_band_free(band); + + return band; +error: + isl_space_free(space); + isl_schedule_band_free(band); + return NULL; +} + +/* Compute the pullback of "band" by the function represented by "upma". + * In other words, plug in "upma" in the iteration domains of "band". + */ +__isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff( + __isl_take isl_schedule_band *band, + __isl_take isl_union_pw_multi_aff *upma) +{ + band = isl_schedule_band_cow(band); + if (!band || !upma) + goto error; + + band->mupa = + isl_multi_union_pw_aff_pullback_union_pw_multi_aff(band->mupa, + upma); + if (!band->mupa) + return isl_schedule_band_free(band); + + return band; +error: + isl_union_pw_multi_aff_free(upma); + isl_schedule_band_free(band); + return NULL; +} + +/* Compute the gist of "band" with respect to "context". + * In particular, compute the gist of the associated partial schedule. + */ +__isl_give isl_schedule_band *isl_schedule_band_gist( + __isl_take isl_schedule_band *band, __isl_take isl_union_set *context) +{ + if (!band || !context) + goto error; + if (band->n == 0) { + isl_union_set_free(context); + return band; + } + band = isl_schedule_band_cow(band); + if (!band) + goto error; + band->mupa = isl_multi_union_pw_aff_gist(band->mupa, context); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_union_set_free(context); + isl_schedule_band_free(band); + return NULL; +} Index: contrib/isl/isl_schedule_constraints.h =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_constraints.h @@ -0,0 +1,30 @@ +#ifndef ISL_SCHEDULE_CONSTRAINTS_H +#define ISL_SCHEDULE_CONSTRAINTS_H + +#include + +enum isl_edge_type { + isl_edge_validity = 0, + isl_edge_first = isl_edge_validity, + isl_edge_coincidence, + isl_edge_condition, + isl_edge_conditional_validity, + isl_edge_proximity, + isl_edge_last = isl_edge_proximity, + isl_edge_local +}; + +__isl_give isl_schedule_constraints * +isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc); + +__isl_give isl_union_map *isl_schedule_constraints_get( + __isl_keep isl_schedule_constraints *sc, enum isl_edge_type type); +__isl_give isl_schedule_constraints *isl_schedule_constraints_add( + __isl_take isl_schedule_constraints *sc, enum isl_edge_type type, + __isl_take isl_union_map *c); + +int isl_schedule_constraints_n_basic_map( + __isl_keep isl_schedule_constraints *sc); +int isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints *sc); + +#endif Index: contrib/isl/isl_schedule_constraints.c =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_constraints.c @@ -0,0 +1,750 @@ +/* + * Copyright 2012 Ecole Normale Superieure + * Copyright 2015-2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* The constraints that need to be satisfied by a schedule on "domain". + * + * "context" specifies extra constraints on the parameters. + * + * "validity" constraints map domain elements i to domain elements + * that should be scheduled after i. (Hard constraint) + * "proximity" constraints map domain elements i to domains elements + * that should be scheduled as early as possible after i (or before i). + * (Soft constraint) + * + * "condition" and "conditional_validity" constraints map possibly "tagged" + * domain elements i -> s to "tagged" domain elements j -> t. + * The elements of the "conditional_validity" constraints, but without the + * tags (i.e., the elements i -> j) are treated as validity constraints, + * except that during the construction of a tilable band, + * the elements of the "conditional_validity" constraints may be violated + * provided that all adjacent elements of the "condition" constraints + * are local within the band. + * A dependence is local within a band if domain and range are mapped + * to the same schedule point by the band. + */ +struct isl_schedule_constraints { + isl_union_set *domain; + isl_set *context; + + isl_union_map *constraint[isl_edge_last + 1]; +}; + +__isl_give isl_schedule_constraints *isl_schedule_constraints_copy( + __isl_keep isl_schedule_constraints *sc) +{ + isl_ctx *ctx; + isl_schedule_constraints *sc_copy; + enum isl_edge_type i; + + ctx = isl_union_set_get_ctx(sc->domain); + sc_copy = isl_calloc_type(ctx, struct isl_schedule_constraints); + if (!sc_copy) + return NULL; + + sc_copy->domain = isl_union_set_copy(sc->domain); + sc_copy->context = isl_set_copy(sc->context); + if (!sc_copy->domain || !sc_copy->context) + return isl_schedule_constraints_free(sc_copy); + + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + sc_copy->constraint[i] = isl_union_map_copy(sc->constraint[i]); + if (!sc_copy->constraint[i]) + return isl_schedule_constraints_free(sc_copy); + } + + return sc_copy; +} + +/* Construct an empty (invalid) isl_schedule_constraints object. + * The caller is responsible for setting the domain and initializing + * all the other fields, e.g., by calling isl_schedule_constraints_init. + */ +static __isl_give isl_schedule_constraints *isl_schedule_constraints_alloc( + isl_ctx *ctx) +{ + return isl_calloc_type(ctx, struct isl_schedule_constraints); +} + +/* Initialize all the fields of "sc", except domain, which is assumed + * to have been set by the caller. + */ +static __isl_give isl_schedule_constraints *isl_schedule_constraints_init( + __isl_take isl_schedule_constraints *sc) +{ + isl_space *space; + isl_union_map *empty; + enum isl_edge_type i; + + if (!sc) + return NULL; + if (!sc->domain) + return isl_schedule_constraints_free(sc); + space = isl_union_set_get_space(sc->domain); + if (!sc->context) + sc->context = isl_set_universe(isl_space_copy(space)); + empty = isl_union_map_empty(space); + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + if (sc->constraint[i]) + continue; + sc->constraint[i] = isl_union_map_copy(empty); + if (!sc->constraint[i]) + sc->domain = isl_union_set_free(sc->domain); + } + isl_union_map_free(empty); + + if (!sc->domain || !sc->context) + return isl_schedule_constraints_free(sc); + + return sc; +} + +/* Construct an isl_schedule_constraints object for computing a schedule + * on "domain". The initial object does not impose any constraints. + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain( + __isl_take isl_union_set *domain) +{ + isl_ctx *ctx; + isl_schedule_constraints *sc; + + if (!domain) + return NULL; + + ctx = isl_union_set_get_ctx(domain); + sc = isl_schedule_constraints_alloc(ctx); + if (!sc) + goto error; + + sc->domain = domain; + return isl_schedule_constraints_init(sc); +error: + isl_union_set_free(domain); + return NULL; +} + +/* Replace the domain of "sc" by "domain". + */ +static __isl_give isl_schedule_constraints *isl_schedule_constraints_set_domain( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_set *domain) +{ + if (!sc || !domain) + goto error; + + isl_union_set_free(sc->domain); + sc->domain = domain; + + return sc; +error: + isl_schedule_constraints_free(sc); + isl_union_set_free(domain); + return NULL; +} + +/* Replace the context of "sc" by "context". + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_context( + __isl_take isl_schedule_constraints *sc, __isl_take isl_set *context) +{ + if (!sc || !context) + goto error; + + isl_set_free(sc->context); + sc->context = context; + + return sc; +error: + isl_schedule_constraints_free(sc); + isl_set_free(context); + return NULL; +} + +/* Replace the constraints of type "type" in "sc" by "c". + */ +static __isl_give isl_schedule_constraints *isl_schedule_constraints_set( + __isl_take isl_schedule_constraints *sc, enum isl_edge_type type, + __isl_take isl_union_map *c) +{ + if (!sc || !c) + goto error; + + isl_union_map_free(sc->constraint[type]); + sc->constraint[type] = c; + + return sc; +error: + isl_schedule_constraints_free(sc); + isl_union_map_free(c); + return NULL; +} + +/* Replace the validity constraints of "sc" by "validity". + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *validity) +{ + return isl_schedule_constraints_set(sc, isl_edge_validity, validity); +} + +/* Replace the coincidence constraints of "sc" by "coincidence". + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_coincidence( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *coincidence) +{ + return isl_schedule_constraints_set(sc, isl_edge_coincidence, + coincidence); +} + +/* Replace the proximity constraints of "sc" by "proximity". + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_proximity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *proximity) +{ + return isl_schedule_constraints_set(sc, isl_edge_proximity, proximity); +} + +/* Replace the conditional validity constraints of "sc" by "condition" + * and "validity". + */ +__isl_give isl_schedule_constraints * +isl_schedule_constraints_set_conditional_validity( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *condition, + __isl_take isl_union_map *validity) +{ + sc = isl_schedule_constraints_set(sc, isl_edge_condition, condition); + sc = isl_schedule_constraints_set(sc, isl_edge_conditional_validity, + validity); + return sc; +} + +__isl_null isl_schedule_constraints *isl_schedule_constraints_free( + __isl_take isl_schedule_constraints *sc) +{ + enum isl_edge_type i; + + if (!sc) + return NULL; + + isl_union_set_free(sc->domain); + isl_set_free(sc->context); + for (i = isl_edge_first; i <= isl_edge_last; ++i) + isl_union_map_free(sc->constraint[i]); + + free(sc); + + return NULL; +} + +isl_ctx *isl_schedule_constraints_get_ctx( + __isl_keep isl_schedule_constraints *sc) +{ + return sc ? isl_union_set_get_ctx(sc->domain) : NULL; +} + +/* Return the domain of "sc". + */ +__isl_give isl_union_set *isl_schedule_constraints_get_domain( + __isl_keep isl_schedule_constraints *sc) +{ + if (!sc) + return NULL; + + return isl_union_set_copy(sc->domain); +} + +/* Return the context of "sc". + */ +__isl_give isl_set *isl_schedule_constraints_get_context( + __isl_keep isl_schedule_constraints *sc) +{ + if (!sc) + return NULL; + + return isl_set_copy(sc->context); +} + +/* Return the constraints of type "type" in "sc". + */ +__isl_give isl_union_map *isl_schedule_constraints_get( + __isl_keep isl_schedule_constraints *sc, enum isl_edge_type type) +{ + if (!sc) + return NULL; + + return isl_union_map_copy(sc->constraint[type]); +} + +/* Return the validity constraints of "sc". + */ +__isl_give isl_union_map *isl_schedule_constraints_get_validity( + __isl_keep isl_schedule_constraints *sc) +{ + return isl_schedule_constraints_get(sc, isl_edge_validity); +} + +/* Return the coincidence constraints of "sc". + */ +__isl_give isl_union_map *isl_schedule_constraints_get_coincidence( + __isl_keep isl_schedule_constraints *sc) +{ + return isl_schedule_constraints_get(sc, isl_edge_coincidence); +} + +/* Return the proximity constraints of "sc". + */ +__isl_give isl_union_map *isl_schedule_constraints_get_proximity( + __isl_keep isl_schedule_constraints *sc) +{ + return isl_schedule_constraints_get(sc, isl_edge_proximity); +} + +/* Return the conditional validity constraints of "sc". + */ +__isl_give isl_union_map *isl_schedule_constraints_get_conditional_validity( + __isl_keep isl_schedule_constraints *sc) +{ + return isl_schedule_constraints_get(sc, isl_edge_conditional_validity); +} + +/* Return the conditions for the conditional validity constraints of "sc". + */ +__isl_give isl_union_map * +isl_schedule_constraints_get_conditional_validity_condition( + __isl_keep isl_schedule_constraints *sc) +{ + return isl_schedule_constraints_get(sc, isl_edge_condition); +} + +/* Add "c" to the constraints of type "type" in "sc". + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_add( + __isl_take isl_schedule_constraints *sc, enum isl_edge_type type, + __isl_take isl_union_map *c) +{ + if (!sc || !c) + goto error; + + c = isl_union_map_union(sc->constraint[type], c); + sc->constraint[type] = c; + if (!c) + return isl_schedule_constraints_free(sc); + + return sc; +error: + isl_schedule_constraints_free(sc); + isl_union_map_free(c); + return NULL; +} + +/* Can a schedule constraint of type "type" be tagged? + */ +static int may_be_tagged(enum isl_edge_type type) +{ + if (type == isl_edge_condition || type == isl_edge_conditional_validity) + return 1; + return 0; +} + +/* Apply "umap" to the domains of the wrapped relations + * inside the domain and range of "c". + * + * That is, for each map of the form + * + * [D -> S] -> [E -> T] + * + * in "c", apply "umap" to D and E. + * + * D is exposed by currying the relation to + * + * D -> [S -> [E -> T]] + * + * E is exposed by doing the same to the inverse of "c". + */ +static __isl_give isl_union_map *apply_factor_domain( + __isl_take isl_union_map *c, __isl_keep isl_union_map *umap) +{ + c = isl_union_map_curry(c); + c = isl_union_map_apply_domain(c, isl_union_map_copy(umap)); + c = isl_union_map_uncurry(c); + + c = isl_union_map_reverse(c); + c = isl_union_map_curry(c); + c = isl_union_map_apply_domain(c, isl_union_map_copy(umap)); + c = isl_union_map_uncurry(c); + c = isl_union_map_reverse(c); + + return c; +} + +/* Apply "umap" to domain and range of "c". + * If "tag" is set, then "c" may contain tags and then "umap" + * needs to be applied to the domains of the wrapped relations + * inside the domain and range of "c". + */ +static __isl_give isl_union_map *apply(__isl_take isl_union_map *c, + __isl_keep isl_union_map *umap, int tag) +{ + isl_union_map *t; + + if (tag) + t = isl_union_map_copy(c); + c = isl_union_map_apply_domain(c, isl_union_map_copy(umap)); + c = isl_union_map_apply_range(c, isl_union_map_copy(umap)); + if (!tag) + return c; + t = apply_factor_domain(t, umap); + c = isl_union_map_union(c, t); + return c; +} + +/* Apply "umap" to the domain of the schedule constraints "sc". + * + * The two sides of the various schedule constraints are adjusted + * accordingly. + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_apply( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_union_map *umap) +{ + enum isl_edge_type i; + + if (!sc || !umap) + goto error; + + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + int tag = may_be_tagged(i); + + sc->constraint[i] = apply(sc->constraint[i], umap, tag); + if (!sc->constraint[i]) + goto error; + } + sc->domain = isl_union_set_apply(sc->domain, umap); + if (!sc->domain) + return isl_schedule_constraints_free(sc); + + return sc; +error: + isl_schedule_constraints_free(sc); + isl_union_map_free(umap); + return NULL; +} + +/* An enumeration of the various keys that may appear in a YAML mapping + * of an isl_schedule_constraints object. + * The keys for the edge types are assumed to have the same values + * as the edge types in isl_edge_type. + */ +enum isl_sc_key { + isl_sc_key_error = -1, + isl_sc_key_validity = isl_edge_validity, + isl_sc_key_coincidence = isl_edge_coincidence, + isl_sc_key_condition = isl_edge_condition, + isl_sc_key_conditional_validity = isl_edge_conditional_validity, + isl_sc_key_proximity = isl_edge_proximity, + isl_sc_key_domain, + isl_sc_key_context, + isl_sc_key_end +}; + +/* Textual representations of the YAML keys for an isl_schedule_constraints + * object. + */ +static char *key_str[] = { + [isl_sc_key_validity] = "validity", + [isl_sc_key_coincidence] = "coincidence", + [isl_sc_key_condition] = "condition", + [isl_sc_key_conditional_validity] = "conditional_validity", + [isl_sc_key_proximity] = "proximity", + [isl_sc_key_domain] = "domain", + [isl_sc_key_context] = "context", +}; + +/* Print a key, value pair for the edge of type "type" in "sc" to "p". + * + * If the edge relation is empty, then it is not printed since + * an empty relation is the default value. + */ +static __isl_give isl_printer *print_constraint(__isl_take isl_printer *p, + __isl_keep isl_schedule_constraints *sc, enum isl_edge_type type) +{ + isl_bool empty; + + empty = isl_union_map_plain_is_empty(sc->constraint[type]); + if (empty < 0) + return isl_printer_free(p); + if (empty) + return p; + + p = isl_printer_print_str(p, key_str[type]); + p = isl_printer_yaml_next(p); + p = isl_printer_print_union_map(p, sc->constraint[type]); + p = isl_printer_yaml_next(p); + + return p; +} + +/* Print "sc" to "p" + * + * In particular, print the isl_schedule_constraints object as a YAML document. + * Fields with values that are (obviously) equal to their default values + * are not printed. + */ +__isl_give isl_printer *isl_printer_print_schedule_constraints( + __isl_take isl_printer *p, __isl_keep isl_schedule_constraints *sc) +{ + isl_bool universe; + + if (!sc) + return isl_printer_free(p); + + p = isl_printer_yaml_start_mapping(p); + p = isl_printer_print_str(p, key_str[isl_sc_key_domain]); + p = isl_printer_yaml_next(p); + p = isl_printer_print_union_set(p, sc->domain); + p = isl_printer_yaml_next(p); + universe = isl_set_plain_is_universe(sc->context); + if (universe < 0) + return isl_printer_free(p); + if (!universe) { + p = isl_printer_print_str(p, key_str[isl_sc_key_context]); + p = isl_printer_yaml_next(p); + p = isl_printer_print_set(p, sc->context); + p = isl_printer_yaml_next(p); + } + p = print_constraint(p, sc, isl_edge_validity); + p = print_constraint(p, sc, isl_edge_proximity); + p = print_constraint(p, sc, isl_edge_coincidence); + p = print_constraint(p, sc, isl_edge_condition); + p = print_constraint(p, sc, isl_edge_conditional_validity); + p = isl_printer_yaml_end_mapping(p); + + return p; +} + +#undef BASE +#define BASE schedule_constraints +#include + +#undef KEY +#define KEY enum isl_sc_key +#undef KEY_ERROR +#define KEY_ERROR isl_sc_key_error +#undef KEY_END +#define KEY_END isl_sc_key_end +#include "extract_key.c" + +#undef BASE +#define BASE set +#include "read_in_string_templ.c" + +#undef BASE +#define BASE union_set +#include "read_in_string_templ.c" + +#undef BASE +#define BASE union_map +#include "read_in_string_templ.c" + +/* Read an isl_schedule_constraints object from "s". + * + * Start off with an empty (invalid) isl_schedule_constraints object and + * then fill up the fields based on the input. + * The input needs to contain at least a description of the domain. + * The other fields are set to defaults by isl_schedule_constraints_init + * if they are not specified in the input. + */ +__isl_give isl_schedule_constraints *isl_stream_read_schedule_constraints( + isl_stream *s) +{ + isl_ctx *ctx; + isl_schedule_constraints *sc; + int more; + int domain_set = 0; + + if (isl_stream_yaml_read_start_mapping(s)) + return NULL; + + ctx = isl_stream_get_ctx(s); + sc = isl_schedule_constraints_alloc(ctx); + while ((more = isl_stream_yaml_next(s)) > 0) { + enum isl_sc_key key; + isl_set *context; + isl_union_set *domain; + isl_union_map *constraints; + + key = get_key(s); + if (isl_stream_yaml_next(s) < 0) + return isl_schedule_constraints_free(sc); + switch (key) { + case isl_sc_key_end: + case isl_sc_key_error: + return isl_schedule_constraints_free(sc); + case isl_sc_key_domain: + domain_set = 1; + domain = read_union_set(s); + sc = isl_schedule_constraints_set_domain(sc, domain); + if (!sc) + return NULL; + break; + case isl_sc_key_context: + context = read_set(s); + sc = isl_schedule_constraints_set_context(sc, context); + if (!sc) + return NULL; + break; + case isl_sc_key_validity: + case isl_sc_key_coincidence: + case isl_sc_key_condition: + case isl_sc_key_conditional_validity: + case isl_sc_key_proximity: + constraints = read_union_map(s); + sc = isl_schedule_constraints_set(sc, key, constraints); + if (!sc) + return NULL; + break; + } + } + if (more < 0) + return isl_schedule_constraints_free(sc); + + if (isl_stream_yaml_read_end_mapping(s) < 0) { + isl_stream_error(s, NULL, "unexpected extra elements"); + return isl_schedule_constraints_free(sc); + } + + if (!domain_set) { + isl_stream_error(s, NULL, "no domain specified"); + return isl_schedule_constraints_free(sc); + } + + return isl_schedule_constraints_init(sc); +} + +/* Read an isl_schedule_constraints object from the file "input". + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_file( + isl_ctx *ctx, FILE *input) +{ + struct isl_stream *s; + isl_schedule_constraints *sc; + + s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + sc = isl_stream_read_schedule_constraints(s); + isl_stream_free(s); + + return sc; +} + +/* Read an isl_schedule_constraints object from the string "str". + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_str( + isl_ctx *ctx, const char *str) +{ + struct isl_stream *s; + isl_schedule_constraints *sc; + + s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + sc = isl_stream_read_schedule_constraints(s); + isl_stream_free(s); + + return sc; +} + +/* Align the parameters of the fields of "sc". + */ +__isl_give isl_schedule_constraints * +isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc) +{ + isl_space *space; + enum isl_edge_type i; + + if (!sc) + return NULL; + + space = isl_union_set_get_space(sc->domain); + space = isl_space_align_params(space, isl_set_get_space(sc->context)); + for (i = isl_edge_first; i <= isl_edge_last; ++i) + space = isl_space_align_params(space, + isl_union_map_get_space(sc->constraint[i])); + + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + sc->constraint[i] = isl_union_map_align_params( + sc->constraint[i], isl_space_copy(space)); + if (!sc->constraint[i]) + space = isl_space_free(space); + } + sc->context = isl_set_align_params(sc->context, isl_space_copy(space)); + sc->domain = isl_union_set_align_params(sc->domain, space); + if (!sc->context || !sc->domain) + return isl_schedule_constraints_free(sc); + + return sc; +} + +/* Add the number of basic maps in "map" to *n. + */ +static isl_stat add_n_basic_map(__isl_take isl_map *map, void *user) +{ + int *n = user; + + *n += isl_map_n_basic_map(map); + isl_map_free(map); + + return isl_stat_ok; +} + +/* Return the total number of isl_basic_maps in the constraints of "sc". + * Return -1 on error. + */ +int isl_schedule_constraints_n_basic_map( + __isl_keep isl_schedule_constraints *sc) +{ + enum isl_edge_type i; + int n = 0; + + if (!sc) + return -1; + for (i = isl_edge_first; i <= isl_edge_last; ++i) + if (isl_union_map_foreach_map(sc->constraint[i], + &add_n_basic_map, &n) < 0) + return -1; + + return n; +} + +/* Return the total number of isl_maps in the constraints of "sc". + */ +int isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints *sc) +{ + enum isl_edge_type i; + int n = 0; + + for (i = isl_edge_first; i <= isl_edge_last; ++i) + n += isl_union_map_n_map(sc->constraint[i]); + + return n; +} Index: contrib/isl/isl_schedule_node.c =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_node.c @@ -0,0 +1,4766 @@ +/* + * Copyright 2013-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include +#include + +/* Create a new schedule node in the given schedule, point at the given + * tree with given ancestors and child positions. + * "child_pos" may be NULL if there are no ancestors. + */ +__isl_give isl_schedule_node *isl_schedule_node_alloc( + __isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree, + __isl_take isl_schedule_tree_list *ancestors, int *child_pos) +{ + isl_ctx *ctx; + isl_schedule_node *node; + int i, n; + + if (!schedule || !tree || !ancestors) + goto error; + n = isl_schedule_tree_list_n_schedule_tree(ancestors); + if (n > 0 && !child_pos) + goto error; + ctx = isl_schedule_get_ctx(schedule); + node = isl_calloc_type(ctx, isl_schedule_node); + if (!node) + goto error; + node->ref = 1; + node->schedule = schedule; + node->tree = tree; + node->ancestors = ancestors; + node->child_pos = isl_alloc_array(ctx, int, n); + if (n && !node->child_pos) + return isl_schedule_node_free(node); + for (i = 0; i < n; ++i) + node->child_pos[i] = child_pos[i]; + + return node; +error: + isl_schedule_free(schedule); + isl_schedule_tree_free(tree); + isl_schedule_tree_list_free(ancestors); + return NULL; +} + +/* Return a pointer to the root of a schedule tree with as single + * node a domain node with the given domain. + */ +__isl_give isl_schedule_node *isl_schedule_node_from_domain( + __isl_take isl_union_set *domain) +{ + isl_schedule *schedule; + isl_schedule_node *node; + + schedule = isl_schedule_from_domain(domain); + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + + return node; +} + +/* Return a pointer to the root of a schedule tree with as single + * node a extension node with the given extension. + */ +__isl_give isl_schedule_node *isl_schedule_node_from_extension( + __isl_take isl_union_map *extension) +{ + isl_ctx *ctx; + isl_schedule *schedule; + isl_schedule_tree *tree; + isl_schedule_node *node; + + if (!extension) + return NULL; + + ctx = isl_union_map_get_ctx(extension); + tree = isl_schedule_tree_from_extension(extension); + schedule = isl_schedule_from_schedule_tree(ctx, tree); + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + + return node; +} + +/* Return the isl_ctx to which "node" belongs. + */ +isl_ctx *isl_schedule_node_get_ctx(__isl_keep isl_schedule_node *node) +{ + return node ? isl_schedule_get_ctx(node->schedule) : NULL; +} + +/* Return a pointer to the leaf of the schedule into which "node" points. + */ +__isl_keep isl_schedule_tree *isl_schedule_node_peek_leaf( + __isl_keep isl_schedule_node *node) +{ + return node ? isl_schedule_peek_leaf(node->schedule) : NULL; +} + +/* Return a copy of the leaf of the schedule into which "node" points. + */ +__isl_give isl_schedule_tree *isl_schedule_node_get_leaf( + __isl_keep isl_schedule_node *node) +{ + return isl_schedule_tree_copy(isl_schedule_node_peek_leaf(node)); +} + +/* Return the type of the node or isl_schedule_node_error on error. + */ +enum isl_schedule_node_type isl_schedule_node_get_type( + __isl_keep isl_schedule_node *node) +{ + return node ? isl_schedule_tree_get_type(node->tree) + : isl_schedule_node_error; +} + +/* Return the type of the parent of "node" or isl_schedule_node_error on error. + */ +enum isl_schedule_node_type isl_schedule_node_get_parent_type( + __isl_keep isl_schedule_node *node) +{ + int pos; + int has_parent; + isl_schedule_tree *parent; + enum isl_schedule_node_type type; + + if (!node) + return isl_schedule_node_error; + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0) + return isl_schedule_node_error; + if (!has_parent) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no parent", return isl_schedule_node_error); + + pos = isl_schedule_tree_list_n_schedule_tree(node->ancestors) - 1; + parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors, pos); + type = isl_schedule_tree_get_type(parent); + isl_schedule_tree_free(parent); + + return type; +} + +/* Return a copy of the subtree that this node points to. + */ +__isl_give isl_schedule_tree *isl_schedule_node_get_tree( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_copy(node->tree); +} + +/* Return a copy of the schedule into which "node" points. + */ +__isl_give isl_schedule *isl_schedule_node_get_schedule( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + return isl_schedule_copy(node->schedule); +} + +/* Return a fresh copy of "node". + */ +__isl_take isl_schedule_node *isl_schedule_node_dup( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_node_alloc(isl_schedule_copy(node->schedule), + isl_schedule_tree_copy(node->tree), + isl_schedule_tree_list_copy(node->ancestors), + node->child_pos); +} + +/* Return an isl_schedule_node that is equal to "node" and that has only + * a single reference. + */ +__isl_give isl_schedule_node *isl_schedule_node_cow( + __isl_take isl_schedule_node *node) +{ + if (!node) + return NULL; + + if (node->ref == 1) + return node; + node->ref--; + return isl_schedule_node_dup(node); +} + +/* Return a new reference to "node". + */ +__isl_give isl_schedule_node *isl_schedule_node_copy( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + node->ref++; + return node; +} + +/* Free "node" and return NULL. + */ +__isl_null isl_schedule_node *isl_schedule_node_free( + __isl_take isl_schedule_node *node) +{ + if (!node) + return NULL; + if (--node->ref > 0) + return NULL; + + isl_schedule_tree_list_free(node->ancestors); + free(node->child_pos); + isl_schedule_tree_free(node->tree); + isl_schedule_free(node->schedule); + free(node); + + return NULL; +} + +/* Do "node1" and "node2" point to the same position in the same + * schedule? + */ +isl_bool isl_schedule_node_is_equal(__isl_keep isl_schedule_node *node1, + __isl_keep isl_schedule_node *node2) +{ + int i, n1, n2; + + if (!node1 || !node2) + return isl_bool_error; + if (node1 == node2) + return isl_bool_true; + if (node1->schedule != node2->schedule) + return isl_bool_false; + + n1 = isl_schedule_node_get_tree_depth(node1); + n2 = isl_schedule_node_get_tree_depth(node2); + if (n1 != n2) + return isl_bool_false; + for (i = 0; i < n1; ++i) + if (node1->child_pos[i] != node2->child_pos[i]) + return isl_bool_false; + + return isl_bool_true; +} + +/* Return the number of outer schedule dimensions of "node" + * in its schedule tree. + * + * Return -1 on error. + */ +int isl_schedule_node_get_schedule_depth(__isl_keep isl_schedule_node *node) +{ + int i, n; + int depth = 0; + + if (!node) + return -1; + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + for (i = n - 1; i >= 0; --i) { + isl_schedule_tree *tree; + + tree = isl_schedule_tree_list_get_schedule_tree( + node->ancestors, i); + if (!tree) + return -1; + if (tree->type == isl_schedule_node_band) + depth += isl_schedule_tree_band_n_member(tree); + isl_schedule_tree_free(tree); + } + + return depth; +} + +/* Internal data structure for + * isl_schedule_node_get_prefix_schedule_union_pw_multi_aff + * + * "initialized" is set if the filter field has been initialized. + * If "universe_domain" is not set, then the collected filter is intersected + * with the domain of the root domain node. + * "universe_filter" is set if we are only collecting the universes of filters + * "collect_prefix" is set if we are collecting prefixes. + * "filter" collects all outer filters and is NULL until "initialized" is set. + * "prefix" collects all outer band partial schedules (if "collect_prefix" + * is set). If it is used, then it is initialized by the caller + * of collect_filter_prefix to a zero-dimensional function. + */ +struct isl_schedule_node_get_filter_prefix_data { + int initialized; + int universe_domain; + int universe_filter; + int collect_prefix; + isl_union_set *filter; + isl_multi_union_pw_aff *prefix; +}; + +static int collect_filter_prefix(__isl_keep isl_schedule_tree_list *list, + int n, struct isl_schedule_node_get_filter_prefix_data *data); + +/* Update the filter and prefix information in "data" based on the first "n" + * elements in "list" and the expansion tree root "tree". + * + * We first collect the information from the elements in "list", + * initializing the filter based on the domain of the expansion. + * Then we map the results to the expanded space and combined them + * with the results already in "data". + */ +static int collect_filter_prefix_expansion(__isl_take isl_schedule_tree *tree, + __isl_keep isl_schedule_tree_list *list, int n, + struct isl_schedule_node_get_filter_prefix_data *data) +{ + struct isl_schedule_node_get_filter_prefix_data contracted; + isl_union_pw_multi_aff *c; + isl_union_map *exp, *universe; + isl_union_set *filter; + + c = isl_schedule_tree_expansion_get_contraction(tree); + exp = isl_schedule_tree_expansion_get_expansion(tree); + + contracted.initialized = 1; + contracted.universe_domain = data->universe_domain; + contracted.universe_filter = data->universe_filter; + contracted.collect_prefix = data->collect_prefix; + universe = isl_union_map_universe(isl_union_map_copy(exp)); + filter = isl_union_map_domain(universe); + if (data->collect_prefix) { + isl_space *space = isl_union_set_get_space(filter); + space = isl_space_set_from_params(space); + contracted.prefix = isl_multi_union_pw_aff_zero(space); + } + contracted.filter = filter; + + if (collect_filter_prefix(list, n, &contracted) < 0) + contracted.filter = isl_union_set_free(contracted.filter); + if (data->collect_prefix) { + isl_multi_union_pw_aff *prefix; + + prefix = contracted.prefix; + prefix = + isl_multi_union_pw_aff_pullback_union_pw_multi_aff(prefix, + isl_union_pw_multi_aff_copy(c)); + data->prefix = isl_multi_union_pw_aff_flat_range_product( + prefix, data->prefix); + } + filter = contracted.filter; + if (data->universe_domain) + filter = isl_union_set_preimage_union_pw_multi_aff(filter, + isl_union_pw_multi_aff_copy(c)); + else + filter = isl_union_set_apply(filter, isl_union_map_copy(exp)); + if (!data->initialized) + data->filter = filter; + else + data->filter = isl_union_set_intersect(filter, data->filter); + data->initialized = 1; + + isl_union_pw_multi_aff_free(c); + isl_union_map_free(exp); + isl_schedule_tree_free(tree); + + return 0; +} + +/* Update the filter information in "data" based on the first "n" + * elements in "list" and the extension tree root "tree", in case + * data->universe_domain is set and data->collect_prefix is not. + * + * We collect the universe domain of the elements in "list" and + * add it to the universe range of the extension (intersected + * with the already collected filter, if any). + */ +static int collect_universe_domain_extension(__isl_take isl_schedule_tree *tree, + __isl_keep isl_schedule_tree_list *list, int n, + struct isl_schedule_node_get_filter_prefix_data *data) +{ + struct isl_schedule_node_get_filter_prefix_data data_outer; + isl_union_map *extension; + isl_union_set *filter; + + data_outer.initialized = 0; + data_outer.universe_domain = 1; + data_outer.universe_filter = data->universe_filter; + data_outer.collect_prefix = 0; + data_outer.filter = NULL; + data_outer.prefix = NULL; + + if (collect_filter_prefix(list, n, &data_outer) < 0) + data_outer.filter = isl_union_set_free(data_outer.filter); + + extension = isl_schedule_tree_extension_get_extension(tree); + extension = isl_union_map_universe(extension); + filter = isl_union_map_range(extension); + if (data_outer.initialized) + filter = isl_union_set_union(filter, data_outer.filter); + if (data->initialized) + filter = isl_union_set_intersect(filter, data->filter); + + data->filter = filter; + + isl_schedule_tree_free(tree); + + return 0; +} + +/* Update "data" based on the tree node "tree" in case "data" has + * not been initialized yet. + * + * Return 0 on success and -1 on error. + * + * If "tree" is a filter, then we set data->filter to this filter + * (or its universe). + * If "tree" is a domain, then this means we have reached the root + * of the schedule tree without being able to extract any information. + * We therefore initialize data->filter to the universe of the domain, + * or the domain itself if data->universe_domain is not set. + * If "tree" is a band with at least one member, then we set data->filter + * to the universe of the schedule domain and replace the zero-dimensional + * data->prefix by the band schedule (if data->collect_prefix is set). + */ +static int collect_filter_prefix_init(__isl_keep isl_schedule_tree *tree, + struct isl_schedule_node_get_filter_prefix_data *data) +{ + enum isl_schedule_node_type type; + isl_multi_union_pw_aff *mupa; + isl_union_set *filter; + + type = isl_schedule_tree_get_type(tree); + switch (type) { + case isl_schedule_node_error: + return -1; + case isl_schedule_node_expansion: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "should be handled by caller", return -1); + case isl_schedule_node_extension: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "cannot handle extension nodes", return -1); + case isl_schedule_node_context: + case isl_schedule_node_leaf: + case isl_schedule_node_guard: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + return 0; + case isl_schedule_node_domain: + filter = isl_schedule_tree_domain_get_domain(tree); + if (data->universe_domain) + filter = isl_union_set_universe(filter); + data->filter = filter; + break; + case isl_schedule_node_band: + if (isl_schedule_tree_band_n_member(tree) == 0) + return 0; + mupa = isl_schedule_tree_band_get_partial_schedule(tree); + if (data->collect_prefix) { + isl_multi_union_pw_aff_free(data->prefix); + mupa = isl_multi_union_pw_aff_reset_tuple_id(mupa, + isl_dim_set); + data->prefix = isl_multi_union_pw_aff_copy(mupa); + } + filter = isl_multi_union_pw_aff_domain(mupa); + filter = isl_union_set_universe(filter); + data->filter = filter; + break; + case isl_schedule_node_filter: + filter = isl_schedule_tree_filter_get_filter(tree); + if (data->universe_filter) + filter = isl_union_set_universe(filter); + data->filter = filter; + break; + } + + if ((data->collect_prefix && !data->prefix) || !data->filter) + return -1; + + data->initialized = 1; + + return 0; +} + +/* Update "data" based on the tree node "tree" in case "data" has + * already been initialized. + * + * Return 0 on success and -1 on error. + * + * If "tree" is a domain and data->universe_domain is not set, then + * intersect data->filter with the domain. + * If "tree" is a filter, then we intersect data->filter with this filter + * (or its universe). + * If "tree" is a band with at least one member and data->collect_prefix + * is set, then we extend data->prefix with the band schedule. + * If "tree" is an extension, then we make sure that we are not collecting + * information on any extended domain elements. + */ +static int collect_filter_prefix_update(__isl_keep isl_schedule_tree *tree, + struct isl_schedule_node_get_filter_prefix_data *data) +{ + enum isl_schedule_node_type type; + isl_multi_union_pw_aff *mupa; + isl_union_set *filter; + isl_union_map *extension; + int empty; + + type = isl_schedule_tree_get_type(tree); + switch (type) { + case isl_schedule_node_error: + return -1; + case isl_schedule_node_expansion: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "should be handled by caller", return -1); + case isl_schedule_node_extension: + extension = isl_schedule_tree_extension_get_extension(tree); + extension = isl_union_map_intersect_range(extension, + isl_union_set_copy(data->filter)); + empty = isl_union_map_is_empty(extension); + isl_union_map_free(extension); + if (empty < 0) + return -1; + if (empty) + break; + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "cannot handle extension nodes", return -1); + case isl_schedule_node_context: + case isl_schedule_node_leaf: + case isl_schedule_node_guard: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + case isl_schedule_node_domain: + if (data->universe_domain) + break; + filter = isl_schedule_tree_domain_get_domain(tree); + data->filter = isl_union_set_intersect(data->filter, filter); + break; + case isl_schedule_node_band: + if (isl_schedule_tree_band_n_member(tree) == 0) + break; + if (!data->collect_prefix) + break; + mupa = isl_schedule_tree_band_get_partial_schedule(tree); + data->prefix = isl_multi_union_pw_aff_flat_range_product(mupa, + data->prefix); + if (!data->prefix) + return -1; + break; + case isl_schedule_node_filter: + filter = isl_schedule_tree_filter_get_filter(tree); + if (data->universe_filter) + filter = isl_union_set_universe(filter); + data->filter = isl_union_set_intersect(data->filter, filter); + if (!data->filter) + return -1; + break; + } + + return 0; +} + +/* Collect filter and/or prefix information from the first "n" + * elements in "list" (which represent the ancestors of a node). + * Store the results in "data". + * + * Extension nodes are only supported if they do not affect the outcome, + * i.e., if we are collecting information on non-extended domain elements, + * or if we are collecting the universe domain (without prefix). + * + * Return 0 on success and -1 on error. + * + * We traverse the list from innermost ancestor (last element) + * to outermost ancestor (first element), calling collect_filter_prefix_init + * on each node as long as we have not been able to extract any information + * yet and collect_filter_prefix_update afterwards. + * If we come across an expansion node, then we interrupt the traversal + * and call collect_filter_prefix_expansion to restart the traversal + * over the remaining ancestors and to combine the results with those + * that have already been collected. + * If we come across an extension node and we are only computing + * the universe domain, then we interrupt the traversal and call + * collect_universe_domain_extension to restart the traversal + * over the remaining ancestors and to combine the results with those + * that have already been collected. + * On successful return, data->initialized will be set since the outermost + * ancestor is a domain node, which always results in an initialization. + */ +static int collect_filter_prefix(__isl_keep isl_schedule_tree_list *list, + int n, struct isl_schedule_node_get_filter_prefix_data *data) +{ + int i; + + if (!list) + return -1; + + for (i = n - 1; i >= 0; --i) { + isl_schedule_tree *tree; + enum isl_schedule_node_type type; + int r; + + tree = isl_schedule_tree_list_get_schedule_tree(list, i); + if (!tree) + return -1; + type = isl_schedule_tree_get_type(tree); + if (type == isl_schedule_node_expansion) + return collect_filter_prefix_expansion(tree, list, i, + data); + if (type == isl_schedule_node_extension && + data->universe_domain && !data->collect_prefix) + return collect_universe_domain_extension(tree, list, i, + data); + if (!data->initialized) + r = collect_filter_prefix_init(tree, data); + else + r = collect_filter_prefix_update(tree, data); + isl_schedule_tree_free(tree); + if (r < 0) + return -1; + } + + return 0; +} + +/* Return the concatenation of the partial schedules of all outer band + * nodes of "node" interesected with all outer filters + * as an isl_multi_union_pw_aff. + * None of the ancestors of "node" may be an extension node, unless + * there is also a filter ancestor that filters out all the extended + * domain elements. + * + * If "node" is pointing at the root of the schedule tree, then + * there are no domain elements reaching the current node, so + * we return an empty result. + * + * We collect all the filters and partial schedules in collect_filter_prefix + * and intersect the domain of the combined schedule with the combined filter. + */ +__isl_give isl_multi_union_pw_aff * +isl_schedule_node_get_prefix_schedule_multi_union_pw_aff( + __isl_keep isl_schedule_node *node) +{ + int n; + isl_space *space; + struct isl_schedule_node_get_filter_prefix_data data; + + if (!node) + return NULL; + + space = isl_schedule_get_space(node->schedule); + space = isl_space_set_from_params(space); + if (node->tree == node->schedule->root) + return isl_multi_union_pw_aff_zero(space); + + data.initialized = 0; + data.universe_domain = 1; + data.universe_filter = 0; + data.collect_prefix = 1; + data.filter = NULL; + data.prefix = isl_multi_union_pw_aff_zero(space); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + if (collect_filter_prefix(node->ancestors, n, &data) < 0) + data.prefix = isl_multi_union_pw_aff_free(data.prefix); + + data.prefix = isl_multi_union_pw_aff_intersect_domain(data.prefix, + data.filter); + + return data.prefix; +} + +/* Return the concatenation of the partial schedules of all outer band + * nodes of "node" interesected with all outer filters + * as an isl_union_pw_multi_aff. + * None of the ancestors of "node" may be an extension node, unless + * there is also a filter ancestor that filters out all the extended + * domain elements. + * + * If "node" is pointing at the root of the schedule tree, then + * there are no domain elements reaching the current node, so + * we return an empty result. + * + * We collect all the filters and partial schedules in collect_filter_prefix. + * The partial schedules are collected as an isl_multi_union_pw_aff. + * If this isl_multi_union_pw_aff is zero-dimensional, then it does not + * contain any domain information, so we construct the isl_union_pw_multi_aff + * result as a zero-dimensional function on the collected filter. + * Otherwise, we convert the isl_multi_union_pw_aff to + * an isl_multi_union_pw_aff and intersect the domain with the filter. + */ +__isl_give isl_union_pw_multi_aff * +isl_schedule_node_get_prefix_schedule_union_pw_multi_aff( + __isl_keep isl_schedule_node *node) +{ + int n; + isl_space *space; + isl_union_pw_multi_aff *prefix; + struct isl_schedule_node_get_filter_prefix_data data; + + if (!node) + return NULL; + + space = isl_schedule_get_space(node->schedule); + if (node->tree == node->schedule->root) + return isl_union_pw_multi_aff_empty(space); + + space = isl_space_set_from_params(space); + data.initialized = 0; + data.universe_domain = 1; + data.universe_filter = 0; + data.collect_prefix = 1; + data.filter = NULL; + data.prefix = isl_multi_union_pw_aff_zero(space); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + if (collect_filter_prefix(node->ancestors, n, &data) < 0) + data.prefix = isl_multi_union_pw_aff_free(data.prefix); + + if (data.prefix && + isl_multi_union_pw_aff_dim(data.prefix, isl_dim_set) == 0) { + isl_multi_union_pw_aff_free(data.prefix); + prefix = isl_union_pw_multi_aff_from_domain(data.filter); + } else { + prefix = + isl_union_pw_multi_aff_from_multi_union_pw_aff(data.prefix); + prefix = isl_union_pw_multi_aff_intersect_domain(prefix, + data.filter); + } + + return prefix; +} + +/* Return the concatenation of the partial schedules of all outer band + * nodes of "node" interesected with all outer filters + * as an isl_union_map. + */ +__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_union_map( + __isl_keep isl_schedule_node *node) +{ + isl_union_pw_multi_aff *upma; + + upma = isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(node); + return isl_union_map_from_union_pw_multi_aff(upma); +} + +/* Return the concatenation of the partial schedules of all outer band + * nodes of "node" intersected with all outer domain constraints. + * None of the ancestors of "node" may be an extension node, unless + * there is also a filter ancestor that filters out all the extended + * domain elements. + * + * Essentially, this function intersects the domain of the output + * of isl_schedule_node_get_prefix_schedule_union_map with the output + * of isl_schedule_node_get_domain, except that it only traverses + * the ancestors of "node" once. + */ +__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_relation( + __isl_keep isl_schedule_node *node) +{ + int n; + isl_space *space; + isl_union_map *prefix; + struct isl_schedule_node_get_filter_prefix_data data; + + if (!node) + return NULL; + + space = isl_schedule_get_space(node->schedule); + if (node->tree == node->schedule->root) + return isl_union_map_empty(space); + + space = isl_space_set_from_params(space); + data.initialized = 0; + data.universe_domain = 0; + data.universe_filter = 0; + data.collect_prefix = 1; + data.filter = NULL; + data.prefix = isl_multi_union_pw_aff_zero(space); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + if (collect_filter_prefix(node->ancestors, n, &data) < 0) + data.prefix = isl_multi_union_pw_aff_free(data.prefix); + + if (data.prefix && + isl_multi_union_pw_aff_dim(data.prefix, isl_dim_set) == 0) { + isl_multi_union_pw_aff_free(data.prefix); + prefix = isl_union_map_from_domain(data.filter); + } else { + prefix = isl_union_map_from_multi_union_pw_aff(data.prefix); + prefix = isl_union_map_intersect_domain(prefix, data.filter); + } + + return prefix; +} + +/* Return the domain elements that reach "node". + * + * If "node" is pointing at the root of the schedule tree, then + * there are no domain elements reaching the current node, so + * we return an empty result. + * None of the ancestors of "node" may be an extension node, unless + * there is also a filter ancestor that filters out all the extended + * domain elements. + * + * Otherwise, we collect all filters reaching the node, + * intersected with the root domain in collect_filter_prefix. + */ +__isl_give isl_union_set *isl_schedule_node_get_domain( + __isl_keep isl_schedule_node *node) +{ + int n; + struct isl_schedule_node_get_filter_prefix_data data; + + if (!node) + return NULL; + + if (node->tree == node->schedule->root) { + isl_space *space; + + space = isl_schedule_get_space(node->schedule); + return isl_union_set_empty(space); + } + + data.initialized = 0; + data.universe_domain = 0; + data.universe_filter = 0; + data.collect_prefix = 0; + data.filter = NULL; + data.prefix = NULL; + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + if (collect_filter_prefix(node->ancestors, n, &data) < 0) + data.filter = isl_union_set_free(data.filter); + + return data.filter; +} + +/* Return the union of universe sets of the domain elements that reach "node". + * + * If "node" is pointing at the root of the schedule tree, then + * there are no domain elements reaching the current node, so + * we return an empty result. + * + * Otherwise, we collect the universes of all filters reaching the node + * in collect_filter_prefix. + */ +__isl_give isl_union_set *isl_schedule_node_get_universe_domain( + __isl_keep isl_schedule_node *node) +{ + int n; + struct isl_schedule_node_get_filter_prefix_data data; + + if (!node) + return NULL; + + if (node->tree == node->schedule->root) { + isl_space *space; + + space = isl_schedule_get_space(node->schedule); + return isl_union_set_empty(space); + } + + data.initialized = 0; + data.universe_domain = 1; + data.universe_filter = 1; + data.collect_prefix = 0; + data.filter = NULL; + data.prefix = NULL; + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + if (collect_filter_prefix(node->ancestors, n, &data) < 0) + data.filter = isl_union_set_free(data.filter); + + return data.filter; +} + +/* Return the subtree schedule of "node". + * + * Since isl_schedule_tree_get_subtree_schedule_union_map does not handle + * trees that do not contain any schedule information, we first + * move down to the first relevant descendant and handle leaves ourselves. + * + * If the subtree rooted at "node" contains any expansion nodes, then + * the returned subtree schedule is formulated in terms of the expanded + * domains. + * The subtree is not allowed to contain any extension nodes. + */ +__isl_give isl_union_map *isl_schedule_node_get_subtree_schedule_union_map( + __isl_keep isl_schedule_node *node) +{ + isl_schedule_tree *tree, *leaf; + isl_union_map *umap; + + tree = isl_schedule_node_get_tree(node); + leaf = isl_schedule_node_peek_leaf(node); + tree = isl_schedule_tree_first_schedule_descendant(tree, leaf); + if (!tree) + return NULL; + if (tree == leaf) { + isl_union_set *domain; + domain = isl_schedule_node_get_universe_domain(node); + isl_schedule_tree_free(tree); + return isl_union_map_from_domain(domain); + } + + umap = isl_schedule_tree_get_subtree_schedule_union_map(tree); + isl_schedule_tree_free(tree); + return umap; +} + +/* Return the number of ancestors of "node" in its schedule tree. + */ +int isl_schedule_node_get_tree_depth(__isl_keep isl_schedule_node *node) +{ + if (!node) + return -1; + return isl_schedule_tree_list_n_schedule_tree(node->ancestors); +} + +/* Does "node" have a parent? + * + * That is, does it point to any node of the schedule other than the root? + */ +isl_bool isl_schedule_node_has_parent(__isl_keep isl_schedule_node *node) +{ + if (!node) + return isl_bool_error; + if (!node->ancestors) + return isl_bool_error; + + return isl_schedule_tree_list_n_schedule_tree(node->ancestors) != 0; +} + +/* Return the position of "node" among the children of its parent. + */ +int isl_schedule_node_get_child_position(__isl_keep isl_schedule_node *node) +{ + int n; + int has_parent; + + if (!node) + return -1; + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0) + return -1; + if (!has_parent) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no parent", return -1); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + return node->child_pos[n - 1]; +} + +/* Does the parent (if any) of "node" have any children with a smaller child + * position than this one? + */ +isl_bool isl_schedule_node_has_previous_sibling( + __isl_keep isl_schedule_node *node) +{ + int n; + isl_bool has_parent; + + if (!node) + return isl_bool_error; + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0 || !has_parent) + return has_parent; + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + + return node->child_pos[n - 1] > 0; +} + +/* Does the parent (if any) of "node" have any children with a greater child + * position than this one? + */ +isl_bool isl_schedule_node_has_next_sibling(__isl_keep isl_schedule_node *node) +{ + int n, n_child; + isl_bool has_parent; + isl_schedule_tree *tree; + + if (!node) + return isl_bool_error; + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0 || !has_parent) + return has_parent; + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, n - 1); + if (!tree) + return isl_bool_error; + n_child = isl_schedule_tree_list_n_schedule_tree(tree->children); + isl_schedule_tree_free(tree); + + return node->child_pos[n - 1] + 1 < n_child; +} + +/* Does "node" have any children? + * + * Any node other than the leaf nodes is considered to have at least + * one child, even if the corresponding isl_schedule_tree does not + * have any children. + */ +isl_bool isl_schedule_node_has_children(__isl_keep isl_schedule_node *node) +{ + if (!node) + return isl_bool_error; + return !isl_schedule_tree_is_leaf(node->tree); +} + +/* Return the number of children of "node"? + * + * Any node other than the leaf nodes is considered to have at least + * one child, even if the corresponding isl_schedule_tree does not + * have any children. That is, the number of children of "node" is + * only zero if its tree is the explicit empty tree. Otherwise, + * if the isl_schedule_tree has any children, then it is equal + * to the number of children of "node". If it has zero children, + * then "node" still has a leaf node as child. + */ +int isl_schedule_node_n_children(__isl_keep isl_schedule_node *node) +{ + int n; + + if (!node) + return -1; + + if (isl_schedule_tree_is_leaf(node->tree)) + return 0; + + n = isl_schedule_tree_n_children(node->tree); + if (n == 0) + return 1; + + return n; +} + +/* Move the "node" pointer to the ancestor of the given generation + * of the node it currently points to, where generation 0 is the node + * itself and generation 1 is its parent. + */ +__isl_give isl_schedule_node *isl_schedule_node_ancestor( + __isl_take isl_schedule_node *node, int generation) +{ + int n; + isl_schedule_tree *tree; + + if (!node) + return NULL; + if (generation == 0) + return node; + n = isl_schedule_node_get_tree_depth(node); + if (n < 0) + return isl_schedule_node_free(node); + if (generation < 0 || generation > n) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "generation out of bounds", + return isl_schedule_node_free(node)); + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + + tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, + n - generation); + isl_schedule_tree_free(node->tree); + node->tree = tree; + node->ancestors = isl_schedule_tree_list_drop(node->ancestors, + n - generation, generation); + if (!node->ancestors || !node->tree) + return isl_schedule_node_free(node); + + return node; +} + +/* Move the "node" pointer to the parent of the node it currently points to. + */ +__isl_give isl_schedule_node *isl_schedule_node_parent( + __isl_take isl_schedule_node *node) +{ + if (!node) + return NULL; + if (!isl_schedule_node_has_parent(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no parent", + return isl_schedule_node_free(node)); + return isl_schedule_node_ancestor(node, 1); +} + +/* Move the "node" pointer to the root of its schedule tree. + */ +__isl_give isl_schedule_node *isl_schedule_node_root( + __isl_take isl_schedule_node *node) +{ + int n; + + if (!node) + return NULL; + n = isl_schedule_node_get_tree_depth(node); + if (n < 0) + return isl_schedule_node_free(node); + return isl_schedule_node_ancestor(node, n); +} + +/* Move the "node" pointer to the child at position "pos" of the node + * it currently points to. + */ +__isl_give isl_schedule_node *isl_schedule_node_child( + __isl_take isl_schedule_node *node, int pos) +{ + int n; + isl_ctx *ctx; + isl_schedule_tree *tree; + int *child_pos; + + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + if (!isl_schedule_node_has_children(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no children", + return isl_schedule_node_free(node)); + + ctx = isl_schedule_node_get_ctx(node); + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + child_pos = isl_realloc_array(ctx, node->child_pos, int, n + 1); + if (!child_pos) + return isl_schedule_node_free(node); + node->child_pos = child_pos; + node->child_pos[n] = pos; + + node->ancestors = isl_schedule_tree_list_add(node->ancestors, + isl_schedule_tree_copy(node->tree)); + tree = node->tree; + if (isl_schedule_tree_has_children(tree)) + tree = isl_schedule_tree_get_child(tree, pos); + else + tree = isl_schedule_node_get_leaf(node); + isl_schedule_tree_free(node->tree); + node->tree = tree; + + if (!node->tree || !node->ancestors) + return isl_schedule_node_free(node); + + return node; +} + +/* Move the "node" pointer to the first child of the node + * it currently points to. + */ +__isl_give isl_schedule_node *isl_schedule_node_first_child( + __isl_take isl_schedule_node *node) +{ + return isl_schedule_node_child(node, 0); +} + +/* Move the "node" pointer to the child of this node's parent in + * the previous child position. + */ +__isl_give isl_schedule_node *isl_schedule_node_previous_sibling( + __isl_take isl_schedule_node *node) +{ + int n; + isl_schedule_tree *parent, *tree; + + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + if (!isl_schedule_node_has_previous_sibling(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no previous sibling", + return isl_schedule_node_free(node)); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors, + n - 1); + if (!parent) + return isl_schedule_node_free(node); + node->child_pos[n - 1]--; + tree = isl_schedule_tree_list_get_schedule_tree(parent->children, + node->child_pos[n - 1]); + isl_schedule_tree_free(parent); + if (!tree) + return isl_schedule_node_free(node); + isl_schedule_tree_free(node->tree); + node->tree = tree; + + return node; +} + +/* Move the "node" pointer to the child of this node's parent in + * the next child position. + */ +__isl_give isl_schedule_node *isl_schedule_node_next_sibling( + __isl_take isl_schedule_node *node) +{ + int n; + isl_schedule_tree *parent, *tree; + + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + if (!isl_schedule_node_has_next_sibling(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no next sibling", + return isl_schedule_node_free(node)); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors, + n - 1); + if (!parent) + return isl_schedule_node_free(node); + node->child_pos[n - 1]++; + tree = isl_schedule_tree_list_get_schedule_tree(parent->children, + node->child_pos[n - 1]); + isl_schedule_tree_free(parent); + if (!tree) + return isl_schedule_node_free(node); + isl_schedule_tree_free(node->tree); + node->tree = tree; + + return node; +} + +/* Return a copy to the child at position "pos" of "node". + */ +__isl_give isl_schedule_node *isl_schedule_node_get_child( + __isl_keep isl_schedule_node *node, int pos) +{ + return isl_schedule_node_child(isl_schedule_node_copy(node), pos); +} + +/* Traverse the descendant of "node" in depth-first order, including + * "node" itself. Call "enter" whenever a node is entered and "leave" + * whenever a node is left. The callback "enter" is responsible + * for moving to the deepest initial subtree of its argument that + * should be traversed. + */ +static __isl_give isl_schedule_node *traverse( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_node *(*enter)( + __isl_take isl_schedule_node *node, void *user), + __isl_give isl_schedule_node *(*leave)( + __isl_take isl_schedule_node *node, void *user), + void *user) +{ + int depth; + + if (!node) + return NULL; + + depth = isl_schedule_node_get_tree_depth(node); + do { + node = enter(node, user); + node = leave(node, user); + while (node && isl_schedule_node_get_tree_depth(node) > depth && + !isl_schedule_node_has_next_sibling(node)) { + node = isl_schedule_node_parent(node); + node = leave(node, user); + } + if (node && isl_schedule_node_get_tree_depth(node) > depth) + node = isl_schedule_node_next_sibling(node); + } while (node && isl_schedule_node_get_tree_depth(node) > depth); + + return node; +} + +/* Internal data structure for isl_schedule_node_foreach_descendant_top_down. + * + * "fn" is the user-specified callback function. + * "user" is the user-specified argument for the callback. + */ +struct isl_schedule_node_preorder_data { + isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user); + void *user; +}; + +/* Callback for "traverse" to enter a node and to move + * to the deepest initial subtree that should be traversed + * for use in a preorder visit. + * + * If the user callback returns a negative value, then we abort + * the traversal. If this callback returns zero, then we skip + * the subtree rooted at the current node. Otherwise, we move + * down to the first child and repeat the process until a leaf + * is reached. + */ +static __isl_give isl_schedule_node *preorder_enter( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_schedule_node_preorder_data *data = user; + + if (!node) + return NULL; + + do { + isl_bool r; + + r = data->fn(node, data->user); + if (r < 0) + return isl_schedule_node_free(node); + if (r == isl_bool_false) + return node; + } while (isl_schedule_node_has_children(node) && + (node = isl_schedule_node_first_child(node)) != NULL); + + return node; +} + +/* Callback for "traverse" to leave a node + * for use in a preorder visit. + * Since we already visited the node when we entered it, + * we do not need to do anything here. + */ +static __isl_give isl_schedule_node *preorder_leave( + __isl_take isl_schedule_node *node, void *user) +{ + return node; +} + +/* Traverse the descendants of "node" (including the node itself) + * in depth first preorder. + * + * If "fn" returns isl_bool_error on any of the nodes, + * then the traversal is aborted. + * If "fn" returns isl_bool_false on any of the nodes, then the subtree rooted + * at that node is skipped. + * + * Return isl_stat_ok on success and isl_stat_error on failure. + */ +isl_stat isl_schedule_node_foreach_descendant_top_down( + __isl_keep isl_schedule_node *node, + isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user), + void *user) +{ + struct isl_schedule_node_preorder_data data = { fn, user }; + + node = isl_schedule_node_copy(node); + node = traverse(node, &preorder_enter, &preorder_leave, &data); + isl_schedule_node_free(node); + + return node ? isl_stat_ok : isl_stat_error; +} + +/* Internal data structure for isl_schedule_node_every_descendant. + * + * "test" is the user-specified callback function. + * "user" is the user-specified callback function argument. + * + * "failed" is initialized to 0 and set to 1 if "test" fails + * on any node. + */ +struct isl_union_map_every_data { + isl_bool (*test)(__isl_keep isl_schedule_node *node, void *user); + void *user; + int failed; +}; + +/* isl_schedule_node_foreach_descendant_top_down callback + * that sets data->failed if data->test returns false and + * subsequently aborts the traversal. + */ +static isl_bool call_every(__isl_keep isl_schedule_node *node, void *user) +{ + struct isl_union_map_every_data *data = user; + isl_bool r; + + r = data->test(node, data->user); + if (r < 0) + return isl_bool_error; + if (r) + return isl_bool_true; + data->failed = 1; + return isl_bool_error; +} + +/* Does "test" succeed on every descendant of "node" (including "node" itself)? + */ +isl_bool isl_schedule_node_every_descendant(__isl_keep isl_schedule_node *node, + isl_bool (*test)(__isl_keep isl_schedule_node *node, void *user), + void *user) +{ + struct isl_union_map_every_data data = { test, user, 0 }; + isl_stat r; + + r = isl_schedule_node_foreach_descendant_top_down(node, &call_every, + &data); + if (r >= 0) + return isl_bool_true; + if (data.failed) + return isl_bool_false; + return isl_bool_error; +} + +/* Internal data structure for isl_schedule_node_map_descendant_bottom_up. + * + * "fn" is the user-specified callback function. + * "user" is the user-specified argument for the callback. + */ +struct isl_schedule_node_postorder_data { + __isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node, + void *user); + void *user; +}; + +/* Callback for "traverse" to enter a node and to move + * to the deepest initial subtree that should be traversed + * for use in a postorder visit. + * + * Since we are performing a postorder visit, we only need + * to move to the deepest initial leaf here. + */ +static __isl_give isl_schedule_node *postorder_enter( + __isl_take isl_schedule_node *node, void *user) +{ + while (node && isl_schedule_node_has_children(node)) + node = isl_schedule_node_first_child(node); + + return node; +} + +/* Callback for "traverse" to leave a node + * for use in a postorder visit. + * + * Since we are performing a postorder visit, we need + * to call the user callback here. + */ +static __isl_give isl_schedule_node *postorder_leave( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_schedule_node_postorder_data *data = user; + + return data->fn(node, data->user); +} + +/* Traverse the descendants of "node" (including the node itself) + * in depth first postorder, allowing the user to modify the visited node. + * The traversal continues from the node returned by the callback function. + * It is the responsibility of the user to ensure that this does not + * lead to an infinite loop. It is safest to always return a pointer + * to the same position (same ancestors and child positions) as the input node. + */ +__isl_give isl_schedule_node *isl_schedule_node_map_descendant_bottom_up( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node, + void *user), void *user) +{ + struct isl_schedule_node_postorder_data data = { fn, user }; + + return traverse(node, &postorder_enter, &postorder_leave, &data); +} + +/* Traverse the ancestors of "node" from the root down to and including + * the parent of "node", calling "fn" on each of them. + * + * If "fn" returns -1 on any of the nodes, then the traversal is aborted. + * + * Return 0 on success and -1 on failure. + */ +isl_stat isl_schedule_node_foreach_ancestor_top_down( + __isl_keep isl_schedule_node *node, + isl_stat (*fn)(__isl_keep isl_schedule_node *node, void *user), + void *user) +{ + int i, n; + + if (!node) + return isl_stat_error; + + n = isl_schedule_node_get_tree_depth(node); + for (i = 0; i < n; ++i) { + isl_schedule_node *ancestor; + isl_stat r; + + ancestor = isl_schedule_node_copy(node); + ancestor = isl_schedule_node_ancestor(ancestor, n - i); + r = fn(ancestor, user); + isl_schedule_node_free(ancestor); + if (r < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Is any node in the subtree rooted at "node" anchored? + * That is, do any of these nodes reference the outer band nodes? + */ +isl_bool isl_schedule_node_is_subtree_anchored( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return isl_bool_error; + return isl_schedule_tree_is_subtree_anchored(node->tree); +} + +/* Return the number of members in the given band node. + */ +unsigned isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node) +{ + return node ? isl_schedule_tree_band_n_member(node->tree) : 0; +} + +/* Is the band member at position "pos" of the band node "node" + * marked coincident? + */ +isl_bool isl_schedule_node_band_member_get_coincident( + __isl_keep isl_schedule_node *node, int pos) +{ + if (!node) + return isl_bool_error; + return isl_schedule_tree_band_member_get_coincident(node->tree, pos); +} + +/* Mark the band member at position "pos" the band node "node" + * as being coincident or not according to "coincident". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_member_set_coincident( + __isl_take isl_schedule_node *node, int pos, int coincident) +{ + int c; + isl_schedule_tree *tree; + + if (!node) + return NULL; + c = isl_schedule_node_band_member_get_coincident(node, pos); + if (c == coincident) + return node; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_member_set_coincident(tree, pos, + coincident); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Is the band node "node" marked permutable? + */ +isl_bool isl_schedule_node_band_get_permutable( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return isl_bool_error; + + return isl_schedule_tree_band_get_permutable(node->tree); +} + +/* Mark the band node "node" permutable or not according to "permutable"? + */ +__isl_give isl_schedule_node *isl_schedule_node_band_set_permutable( + __isl_take isl_schedule_node *node, int permutable) +{ + isl_schedule_tree *tree; + + if (!node) + return NULL; + if (isl_schedule_node_band_get_permutable(node) == permutable) + return node; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_set_permutable(tree, permutable); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Return the schedule space of the band node. + */ +__isl_give isl_space *isl_schedule_node_band_get_space( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_band_get_space(node->tree); +} + +/* Return the schedule of the band node in isolation. + */ +__isl_give isl_multi_union_pw_aff *isl_schedule_node_band_get_partial_schedule( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_band_get_partial_schedule(node->tree); +} + +/* Return the schedule of the band node in isolation in the form of + * an isl_union_map. + * + * If the band does not have any members, then we construct a universe map + * with the universe of the domain elements reaching the node as domain. + * Otherwise, we extract an isl_multi_union_pw_aff representation and + * convert that to an isl_union_map. + */ +__isl_give isl_union_map *isl_schedule_node_band_get_partial_schedule_union_map( + __isl_keep isl_schedule_node *node) +{ + isl_multi_union_pw_aff *mupa; + + if (!node) + return NULL; + + if (isl_schedule_node_get_type(node) != isl_schedule_node_band) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a band node", return NULL); + if (isl_schedule_node_band_n_member(node) == 0) { + isl_union_set *domain; + + domain = isl_schedule_node_get_universe_domain(node); + return isl_union_map_from_domain(domain); + } + + mupa = isl_schedule_node_band_get_partial_schedule(node); + return isl_union_map_from_multi_union_pw_aff(mupa); +} + +/* Return the loop AST generation type for the band member of band node "node" + * at position "pos". + */ +enum isl_ast_loop_type isl_schedule_node_band_member_get_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos) +{ + if (!node) + return isl_ast_loop_error; + + return isl_schedule_tree_band_member_get_ast_loop_type(node->tree, pos); +} + +/* Set the loop AST generation type for the band member of band node "node" + * at position "pos" to "type". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_member_set_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type) +{ + isl_schedule_tree *tree; + + if (!node) + return NULL; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_member_set_ast_loop_type(tree, pos, type); + return isl_schedule_node_graft_tree(node, tree); +} + +/* Return the loop AST generation type for the band member of band node "node" + * at position "pos" for the isolated part. + */ +enum isl_ast_loop_type isl_schedule_node_band_member_get_isolate_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos) +{ + if (!node) + return isl_ast_loop_error; + + return isl_schedule_tree_band_member_get_isolate_ast_loop_type( + node->tree, pos); +} + +/* Set the loop AST generation type for the band member of band node "node" + * at position "pos" for the isolated part to "type". + */ +__isl_give isl_schedule_node * +isl_schedule_node_band_member_set_isolate_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type) +{ + isl_schedule_tree *tree; + + if (!node) + return NULL; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_member_set_isolate_ast_loop_type(tree, + pos, type); + return isl_schedule_node_graft_tree(node, tree); +} + +/* Return the AST build options associated to band node "node". + */ +__isl_give isl_union_set *isl_schedule_node_band_get_ast_build_options( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_band_get_ast_build_options(node->tree); +} + +/* Replace the AST build options associated to band node "node" by "options". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_set_ast_build_options( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *options) +{ + isl_schedule_tree *tree; + + if (!node || !options) + goto error; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_set_ast_build_options(tree, options); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_schedule_node_free(node); + isl_union_set_free(options); + return NULL; +} + +/* Return the "isolate" option associated to band node "node". + */ +__isl_give isl_set *isl_schedule_node_band_get_ast_isolate_option( + __isl_keep isl_schedule_node *node) +{ + int depth; + + if (!node) + return NULL; + + depth = isl_schedule_node_get_schedule_depth(node); + return isl_schedule_tree_band_get_ast_isolate_option(node->tree, depth); +} + +/* Make sure that that spaces of "node" and "mv" are the same. + * Return -1 on error, reporting the error to the user. + */ +static int check_space_multi_val(__isl_keep isl_schedule_node *node, + __isl_keep isl_multi_val *mv) +{ + isl_space *node_space, *mv_space; + int equal; + + node_space = isl_schedule_node_band_get_space(node); + mv_space = isl_multi_val_get_space(mv); + equal = isl_space_tuple_is_equal(node_space, isl_dim_set, + mv_space, isl_dim_set); + isl_space_free(mv_space); + isl_space_free(node_space); + if (equal < 0) + return -1; + if (!equal) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "spaces don't match", return -1); + + return 0; +} + +/* Multiply the partial schedule of the band node "node" + * with the factors in "mv". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_scale( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv) +{ + isl_schedule_tree *tree; + int anchored; + + if (!node || !mv) + goto error; + if (check_space_multi_val(node, mv) < 0) + goto error; + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + goto error; + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot scale band node with anchored subtree", + goto error); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_scale(tree, mv); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_multi_val_free(mv); + isl_schedule_node_free(node); + return NULL; +} + +/* Divide the partial schedule of the band node "node" + * by the factors in "mv". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_scale_down( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv) +{ + isl_schedule_tree *tree; + int anchored; + + if (!node || !mv) + goto error; + if (check_space_multi_val(node, mv) < 0) + goto error; + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + goto error; + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot scale down band node with anchored subtree", + goto error); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_scale_down(tree, mv); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_multi_val_free(mv); + isl_schedule_node_free(node); + return NULL; +} + +/* Reduce the partial schedule of the band node "node" + * modulo the factors in "mv". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_mod( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv) +{ + isl_schedule_tree *tree; + isl_bool anchored; + + if (!node || !mv) + goto error; + if (check_space_multi_val(node, mv) < 0) + goto error; + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + goto error; + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot perform mod on band node with anchored subtree", + goto error); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_mod(tree, mv); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_multi_val_free(mv); + isl_schedule_node_free(node); + return NULL; +} + +/* Make sure that that spaces of "node" and "mupa" are the same. + * Return isl_stat_error on error, reporting the error to the user. + */ +static isl_stat check_space_multi_union_pw_aff( + __isl_keep isl_schedule_node *node, + __isl_keep isl_multi_union_pw_aff *mupa) +{ + isl_space *node_space, *mupa_space; + isl_bool equal; + + node_space = isl_schedule_node_band_get_space(node); + mupa_space = isl_multi_union_pw_aff_get_space(mupa); + equal = isl_space_tuple_is_equal(node_space, isl_dim_set, + mupa_space, isl_dim_set); + isl_space_free(mupa_space); + isl_space_free(node_space); + if (equal < 0) + return isl_stat_error; + if (!equal) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "spaces don't match", return isl_stat_error); + + return isl_stat_ok; +} + +/* Shift the partial schedule of the band node "node" by "shift". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_shift( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *shift) +{ + isl_schedule_tree *tree; + int anchored; + + if (!node || !shift) + goto error; + if (check_space_multi_union_pw_aff(node, shift) < 0) + goto error; + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + goto error; + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot shift band node with anchored subtree", + goto error); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_shift(tree, shift); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_multi_union_pw_aff_free(shift); + isl_schedule_node_free(node); + return NULL; +} + +/* Tile "node" with tile sizes "sizes". + * + * The current node is replaced by two nested nodes corresponding + * to the tile dimensions and the point dimensions. + * + * Return a pointer to the outer (tile) node. + * + * If any of the descendants of "node" depend on the set of outer band nodes, + * then we refuse to tile the node. + * + * If the scale tile loops option is set, then the tile loops + * are scaled by the tile sizes. If the shift point loops option is set, + * then the point loops are shifted to start at zero. + * In particular, these options affect the tile and point loop schedules + * as follows + * + * scale shift original tile point + * + * 0 0 i floor(i/s) i + * 1 0 i s * floor(i/s) i + * 0 1 i floor(i/s) i - s * floor(i/s) + * 1 1 i s * floor(i/s) i - s * floor(i/s) + */ +__isl_give isl_schedule_node *isl_schedule_node_band_tile( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes) +{ + isl_schedule_tree *tree; + int anchored; + + if (!node || !sizes) + goto error; + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + goto error; + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot tile band node with anchored subtree", + goto error); + + if (check_space_multi_val(node, sizes) < 0) + goto error; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_tile(tree, sizes); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_multi_val_free(sizes); + isl_schedule_node_free(node); + return NULL; +} + +/* Move the band node "node" down to all the leaves in the subtree + * rooted at "node". + * Return a pointer to the node in the resulting tree that is in the same + * position as the node pointed to by "node" in the original tree. + * + * If the node only has a leaf child, then nothing needs to be done. + * Otherwise, the child of the node is removed and the result is + * appended to all the leaves in the subtree rooted at the original child. + * Since the node is moved to the leaves, it needs to be expanded + * according to the expansion, if any, defined by that subtree. + * In the end, the original node is replaced by the result of + * attaching copies of the expanded node to the leaves. + * + * If any of the nodes in the subtree rooted at "node" depend on + * the set of outer band nodes then we refuse to sink the band node. + */ +__isl_give isl_schedule_node *isl_schedule_node_band_sink( + __isl_take isl_schedule_node *node) +{ + enum isl_schedule_node_type type; + isl_schedule_tree *tree, *child; + isl_union_pw_multi_aff *contraction; + int anchored; + + if (!node) + return NULL; + + type = isl_schedule_node_get_type(node); + if (type != isl_schedule_node_band) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a band node", return isl_schedule_node_free(node)); + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + return isl_schedule_node_free(node); + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot sink band node in anchored subtree", + return isl_schedule_node_free(node)); + if (isl_schedule_tree_n_children(node->tree) == 0) + return node; + + contraction = isl_schedule_node_get_subtree_contraction(node); + + tree = isl_schedule_node_get_tree(node); + child = isl_schedule_tree_get_child(tree, 0); + tree = isl_schedule_tree_reset_children(tree); + tree = isl_schedule_tree_pullback_union_pw_multi_aff(tree, contraction); + tree = isl_schedule_tree_append_to_leaves(child, tree); + + return isl_schedule_node_graft_tree(node, tree); +} + +/* Split "node" into two nested band nodes, one with the first "pos" + * dimensions and one with the remaining dimensions. + * The schedules of the two band nodes live in anonymous spaces. + * The loop AST generation type options and the isolate option + * are split over the two band nodes. + */ +__isl_give isl_schedule_node *isl_schedule_node_band_split( + __isl_take isl_schedule_node *node, int pos) +{ + int depth; + isl_schedule_tree *tree; + + depth = isl_schedule_node_get_schedule_depth(node); + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_split(tree, pos, depth); + return isl_schedule_node_graft_tree(node, tree); +} + +/* Return the context of the context node "node". + */ +__isl_give isl_set *isl_schedule_node_context_get_context( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_context_get_context(node->tree); +} + +/* Return the domain of the domain node "node". + */ +__isl_give isl_union_set *isl_schedule_node_domain_get_domain( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_domain_get_domain(node->tree); +} + +/* Return the expansion map of expansion node "node". + */ +__isl_give isl_union_map *isl_schedule_node_expansion_get_expansion( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_expansion_get_expansion(node->tree); +} + +/* Return the contraction of expansion node "node". + */ +__isl_give isl_union_pw_multi_aff *isl_schedule_node_expansion_get_contraction( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_expansion_get_contraction(node->tree); +} + +/* Replace the contraction and the expansion of the expansion node "node" + * by "contraction" and "expansion". + */ +__isl_give isl_schedule_node * +isl_schedule_node_expansion_set_contraction_and_expansion( + __isl_take isl_schedule_node *node, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion) +{ + isl_schedule_tree *tree; + + if (!node || !contraction || !expansion) + goto error; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_expansion_set_contraction_and_expansion(tree, + contraction, expansion); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_schedule_node_free(node); + isl_union_pw_multi_aff_free(contraction); + isl_union_map_free(expansion); + return NULL; +} + +/* Return the extension of the extension node "node". + */ +__isl_give isl_union_map *isl_schedule_node_extension_get_extension( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_extension_get_extension(node->tree); +} + +/* Replace the extension of extension node "node" by "extension". + */ +__isl_give isl_schedule_node *isl_schedule_node_extension_set_extension( + __isl_take isl_schedule_node *node, __isl_take isl_union_map *extension) +{ + isl_schedule_tree *tree; + + if (!node || !extension) + goto error; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_extension_set_extension(tree, extension); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_schedule_node_free(node); + isl_union_map_free(extension); + return NULL; +} + +/* Return the filter of the filter node "node". + */ +__isl_give isl_union_set *isl_schedule_node_filter_get_filter( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_filter_get_filter(node->tree); +} + +/* Replace the filter of filter node "node" by "filter". + */ +__isl_give isl_schedule_node *isl_schedule_node_filter_set_filter( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter) +{ + isl_schedule_tree *tree; + + if (!node || !filter) + goto error; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_filter_set_filter(tree, filter); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_schedule_node_free(node); + isl_union_set_free(filter); + return NULL; +} + +/* Intersect the filter of filter node "node" with "filter". + * + * If the filter of the node is already a subset of "filter", + * then leave the node unchanged. + */ +__isl_give isl_schedule_node *isl_schedule_node_filter_intersect_filter( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter) +{ + isl_union_set *node_filter = NULL; + isl_bool subset; + + if (!node || !filter) + goto error; + + node_filter = isl_schedule_node_filter_get_filter(node); + subset = isl_union_set_is_subset(node_filter, filter); + if (subset < 0) + goto error; + if (subset) { + isl_union_set_free(node_filter); + isl_union_set_free(filter); + return node; + } + node_filter = isl_union_set_intersect(node_filter, filter); + node = isl_schedule_node_filter_set_filter(node, node_filter); + return node; +error: + isl_schedule_node_free(node); + isl_union_set_free(node_filter); + isl_union_set_free(filter); + return NULL; +} + +/* Return the guard of the guard node "node". + */ +__isl_give isl_set *isl_schedule_node_guard_get_guard( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_guard_get_guard(node->tree); +} + +/* Return the mark identifier of the mark node "node". + */ +__isl_give isl_id *isl_schedule_node_mark_get_id( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_mark_get_id(node->tree); +} + +/* Replace the child at position "pos" of the sequence node "node" + * by the children of sequence root node of "tree". + */ +__isl_give isl_schedule_node *isl_schedule_node_sequence_splice( + __isl_take isl_schedule_node *node, int pos, + __isl_take isl_schedule_tree *tree) +{ + isl_schedule_tree *node_tree; + + if (!node || !tree) + goto error; + if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a sequence node", goto error); + if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a sequence node", goto error); + node_tree = isl_schedule_node_get_tree(node); + node_tree = isl_schedule_tree_sequence_splice(node_tree, pos, tree); + node = isl_schedule_node_graft_tree(node, node_tree); + + return node; +error: + isl_schedule_node_free(node); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Given a sequence node "node", with a child at position "pos" that + * is also a sequence node, attach the children of that node directly + * as children of "node" at that position, replacing the original child. + * + * The filters of these children are intersected with the filter + * of the child at position "pos". + */ +__isl_give isl_schedule_node *isl_schedule_node_sequence_splice_child( + __isl_take isl_schedule_node *node, int pos) +{ + int i, n; + isl_union_set *filter; + isl_schedule_node *child; + isl_schedule_tree *tree; + + if (!node) + return NULL; + if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a sequence node", + return isl_schedule_node_free(node)); + node = isl_schedule_node_child(node, pos); + node = isl_schedule_node_child(node, 0); + if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a sequence node", + return isl_schedule_node_free(node)); + child = isl_schedule_node_copy(node); + node = isl_schedule_node_parent(node); + filter = isl_schedule_node_filter_get_filter(node); + n = isl_schedule_node_n_children(child); + for (i = 0; i < n; ++i) { + child = isl_schedule_node_child(child, i); + child = isl_schedule_node_filter_intersect_filter(child, + isl_union_set_copy(filter)); + child = isl_schedule_node_parent(child); + } + isl_union_set_free(filter); + tree = isl_schedule_node_get_tree(child); + isl_schedule_node_free(child); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_sequence_splice(node, pos, tree); + + return node; +} + +/* Update the ancestors of "node" to point to the tree that "node" + * now points to. + * That is, replace the child in the original parent that corresponds + * to the current tree position by node->tree and continue updating + * the ancestors in the same way until the root is reached. + * + * If "fn" is not NULL, then it is called on each ancestor as we move up + * the tree so that it can modify the ancestor before it is added + * to the list of ancestors of the modified node. + * The additional "pos" argument records the position + * of the "tree" argument in the original schedule tree. + * + * If "node" originally points to a leaf of the schedule tree, then make sure + * that in the end it points to a leaf in the updated schedule tree. + */ +static __isl_give isl_schedule_node *update_ancestors( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_tree *(*fn)(__isl_take isl_schedule_tree *tree, + __isl_keep isl_schedule_node *pos, void *user), void *user) +{ + int i, n; + int is_leaf; + isl_schedule_tree *tree; + isl_schedule_node *pos = NULL; + + if (fn) + pos = isl_schedule_node_copy(node); + + node = isl_schedule_node_cow(node); + if (!node) + return isl_schedule_node_free(pos); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + tree = isl_schedule_tree_copy(node->tree); + + for (i = n - 1; i >= 0; --i) { + isl_schedule_tree *parent; + + parent = isl_schedule_tree_list_get_schedule_tree( + node->ancestors, i); + parent = isl_schedule_tree_replace_child(parent, + node->child_pos[i], tree); + if (fn) { + pos = isl_schedule_node_parent(pos); + parent = fn(parent, pos, user); + } + node->ancestors = isl_schedule_tree_list_set_schedule_tree( + node->ancestors, i, isl_schedule_tree_copy(parent)); + + tree = parent; + } + + if (fn) + isl_schedule_node_free(pos); + + is_leaf = isl_schedule_tree_is_leaf(node->tree); + node->schedule = isl_schedule_set_root(node->schedule, tree); + if (is_leaf) { + isl_schedule_tree_free(node->tree); + node->tree = isl_schedule_node_get_leaf(node); + } + + if (!node->schedule || !node->ancestors) + return isl_schedule_node_free(node); + + return node; +} + +/* Replace the subtree that "pos" points to by "tree", updating + * the ancestors to maintain a consistent state. + */ +__isl_give isl_schedule_node *isl_schedule_node_graft_tree( + __isl_take isl_schedule_node *pos, __isl_take isl_schedule_tree *tree) +{ + if (!tree || !pos) + goto error; + if (pos->tree == tree) { + isl_schedule_tree_free(tree); + return pos; + } + + pos = isl_schedule_node_cow(pos); + if (!pos) + goto error; + + isl_schedule_tree_free(pos->tree); + pos->tree = tree; + + return update_ancestors(pos, NULL, NULL); +error: + isl_schedule_node_free(pos); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Make sure we can insert a node between "node" and its parent. + * Return -1 on error, reporting the reason why we cannot insert a node. + */ +static int check_insert(__isl_keep isl_schedule_node *node) +{ + int has_parent; + enum isl_schedule_node_type type; + + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0) + return -1; + if (!has_parent) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot insert node outside of root", return -1); + + type = isl_schedule_node_get_parent_type(node); + if (type == isl_schedule_node_error) + return -1; + if (type == isl_schedule_node_set || type == isl_schedule_node_sequence) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot insert node between set or sequence node " + "and its filter children", return -1); + + return 0; +} + +/* Insert a band node with partial schedule "mupa" between "node" and + * its parent. + * Return a pointer to the new band node. + * + * If any of the nodes in the subtree rooted at "node" depend on + * the set of outer band nodes then we refuse to insert the band node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_partial_schedule( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *mupa) +{ + int anchored; + isl_schedule_band *band; + isl_schedule_tree *tree; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + goto error; + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot insert band node in anchored subtree", + goto error); + + tree = isl_schedule_node_get_tree(node); + band = isl_schedule_band_from_multi_union_pw_aff(mupa); + tree = isl_schedule_tree_insert_band(tree, band); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +error: + isl_schedule_node_free(node); + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Insert a context node with context "context" between "node" and its parent. + * Return a pointer to the new context node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_context( + __isl_take isl_schedule_node *node, __isl_take isl_set *context) +{ + isl_schedule_tree *tree; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_insert_context(tree, context); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Insert an expansion node with the given "contraction" and "expansion" + * between "node" and its parent. + * Return a pointer to the new expansion node. + * + * Typically the domain and range spaces of the expansion are different. + * This means that only one of them can refer to the current domain space + * in a consistent tree. It is up to the caller to ensure that the tree + * returns to a consistent state. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_expansion( + __isl_take isl_schedule_node *node, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion) +{ + isl_schedule_tree *tree; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_insert_expansion(tree, contraction, expansion); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Insert an extension node with extension "extension" between "node" and + * its parent. + * Return a pointer to the new extension node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_extension( + __isl_take isl_schedule_node *node, + __isl_take isl_union_map *extension) +{ + isl_schedule_tree *tree; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_insert_extension(tree, extension); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Insert a filter node with filter "filter" between "node" and its parent. + * Return a pointer to the new filter node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_filter( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter) +{ + isl_schedule_tree *tree; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_insert_filter(tree, filter); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Insert a guard node with guard "guard" between "node" and its parent. + * Return a pointer to the new guard node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_guard( + __isl_take isl_schedule_node *node, __isl_take isl_set *guard) +{ + isl_schedule_tree *tree; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_insert_guard(tree, guard); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Insert a mark node with mark identifier "mark" between "node" and + * its parent. + * Return a pointer to the new mark node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_mark( + __isl_take isl_schedule_node *node, __isl_take isl_id *mark) +{ + isl_schedule_tree *tree; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_insert_mark(tree, mark); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Attach the current subtree of "node" to a sequence of filter tree nodes + * with filters described by "filters", attach this sequence + * of filter tree nodes as children to a new tree of type "type" and + * replace the original subtree of "node" by this new tree. + * Each copy of the original subtree is simplified with respect + * to the corresponding filter. + */ +static __isl_give isl_schedule_node *isl_schedule_node_insert_children( + __isl_take isl_schedule_node *node, + enum isl_schedule_node_type type, + __isl_take isl_union_set_list *filters) +{ + int i, n; + isl_ctx *ctx; + isl_schedule_tree *tree; + isl_schedule_tree_list *list; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + if (!node || !filters) + goto error; + + ctx = isl_schedule_node_get_ctx(node); + n = isl_union_set_list_n_union_set(filters); + list = isl_schedule_tree_list_alloc(ctx, n); + for (i = 0; i < n; ++i) { + isl_schedule_node *node_i; + isl_schedule_tree *tree; + isl_union_set *filter; + + filter = isl_union_set_list_get_union_set(filters, i); + node_i = isl_schedule_node_copy(node); + node_i = isl_schedule_node_gist(node_i, + isl_union_set_copy(filter)); + tree = isl_schedule_node_get_tree(node_i); + isl_schedule_node_free(node_i); + tree = isl_schedule_tree_insert_filter(tree, filter); + list = isl_schedule_tree_list_add(list, tree); + } + tree = isl_schedule_tree_from_children(type, list); + node = isl_schedule_node_graft_tree(node, tree); + + isl_union_set_list_free(filters); + return node; +error: + isl_union_set_list_free(filters); + isl_schedule_node_free(node); + return NULL; +} + +/* Insert a sequence node with child filters "filters" between "node" and + * its parent. That is, the tree that "node" points to is attached + * to each of the child nodes of the filter nodes. + * Return a pointer to the new sequence node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_sequence( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters) +{ + return isl_schedule_node_insert_children(node, + isl_schedule_node_sequence, filters); +} + +/* Insert a set node with child filters "filters" between "node" and + * its parent. That is, the tree that "node" points to is attached + * to each of the child nodes of the filter nodes. + * Return a pointer to the new set node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_set( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters) +{ + return isl_schedule_node_insert_children(node, + isl_schedule_node_set, filters); +} + +/* Remove "node" from its schedule tree and return a pointer + * to the leaf at the same position in the updated schedule tree. + * + * It is not allowed to remove the root of a schedule tree or + * a child of a set or sequence node. + */ +__isl_give isl_schedule_node *isl_schedule_node_cut( + __isl_take isl_schedule_node *node) +{ + isl_schedule_tree *leaf; + enum isl_schedule_node_type parent_type; + + if (!node) + return NULL; + if (!isl_schedule_node_has_parent(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot cut root", return isl_schedule_node_free(node)); + + parent_type = isl_schedule_node_get_parent_type(node); + if (parent_type == isl_schedule_node_set || + parent_type == isl_schedule_node_sequence) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot cut child of set or sequence", + return isl_schedule_node_free(node)); + + leaf = isl_schedule_node_get_leaf(node); + return isl_schedule_node_graft_tree(node, leaf); +} + +/* Remove a single node from the schedule tree, attaching the child + * of "node" directly to its parent. + * Return a pointer to this former child or to the leaf the position + * of the original node if there was no child. + * It is not allowed to remove the root of a schedule tree, + * a set or sequence node, a child of a set or sequence node or + * a band node with an anchored subtree. + */ +__isl_give isl_schedule_node *isl_schedule_node_delete( + __isl_take isl_schedule_node *node) +{ + int n; + isl_schedule_tree *tree; + enum isl_schedule_node_type type; + + if (!node) + return NULL; + + if (isl_schedule_node_get_tree_depth(node) == 0) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot delete root node", + return isl_schedule_node_free(node)); + n = isl_schedule_node_n_children(node); + if (n != 1) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "can only delete node with a single child", + return isl_schedule_node_free(node)); + type = isl_schedule_node_get_parent_type(node); + if (type == isl_schedule_node_sequence || type == isl_schedule_node_set) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot delete child of set or sequence", + return isl_schedule_node_free(node)); + if (isl_schedule_node_get_type(node) == isl_schedule_node_band) { + int anchored; + + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + return isl_schedule_node_free(node); + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), + isl_error_invalid, + "cannot delete band node with anchored subtree", + return isl_schedule_node_free(node)); + } + + tree = isl_schedule_node_get_tree(node); + if (!tree || isl_schedule_tree_has_children(tree)) { + tree = isl_schedule_tree_child(tree, 0); + } else { + isl_schedule_tree_free(tree); + tree = isl_schedule_node_get_leaf(node); + } + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Internal data structure for the group_ancestor callback. + * + * If "finished" is set, then we no longer need to modify + * any further ancestors. + * + * "contraction" and "expansion" represent the expansion + * that reflects the grouping. + * + * "domain" contains the domain elements that reach the position + * where the grouping is performed. That is, it is the range + * of the resulting expansion. + * "domain_universe" is the universe of "domain". + * "group" is the set of group elements, i.e., the domain + * of the resulting expansion. + * "group_universe" is the universe of "group". + * + * "sched" is the schedule for the group elements, in pratice + * an identity mapping on "group_universe". + * "dim" is the dimension of "sched". + */ +struct isl_schedule_group_data { + int finished; + + isl_union_map *expansion; + isl_union_pw_multi_aff *contraction; + + isl_union_set *domain; + isl_union_set *domain_universe; + isl_union_set *group; + isl_union_set *group_universe; + + int dim; + isl_multi_aff *sched; +}; + +/* Is domain covered by data->domain within data->domain_universe? + */ +static int locally_covered_by_domain(__isl_keep isl_union_set *domain, + struct isl_schedule_group_data *data) +{ + int is_subset; + isl_union_set *test; + + test = isl_union_set_copy(domain); + test = isl_union_set_intersect(test, + isl_union_set_copy(data->domain_universe)); + is_subset = isl_union_set_is_subset(test, data->domain); + isl_union_set_free(test); + + return is_subset; +} + +/* Update the band tree root "tree" to refer to the group instances + * in data->group rather than the original domain elements in data->domain. + * "pos" is the position in the original schedule tree where the modified + * "tree" will be attached. + * + * Add the part of the identity schedule on the group instances data->sched + * that corresponds to this band node to the band schedule. + * If the domain elements that reach the node and that are part + * of data->domain_universe are all elements of data->domain (and therefore + * replaced by the group instances) then this data->domain_universe + * is removed from the domain of the band schedule. + */ +static __isl_give isl_schedule_tree *group_band( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos, + struct isl_schedule_group_data *data) +{ + isl_union_set *domain; + isl_multi_aff *ma; + isl_multi_union_pw_aff *mupa, *partial; + int is_covered; + int depth, n, has_id; + + domain = isl_schedule_node_get_domain(pos); + is_covered = locally_covered_by_domain(domain, data); + if (is_covered >= 0 && is_covered) { + domain = isl_union_set_universe(domain); + domain = isl_union_set_subtract(domain, + isl_union_set_copy(data->domain_universe)); + tree = isl_schedule_tree_band_intersect_domain(tree, domain); + } else + isl_union_set_free(domain); + if (is_covered < 0) + return isl_schedule_tree_free(tree); + depth = isl_schedule_node_get_schedule_depth(pos); + n = isl_schedule_tree_band_n_member(tree); + ma = isl_multi_aff_copy(data->sched); + ma = isl_multi_aff_drop_dims(ma, isl_dim_out, 0, depth); + ma = isl_multi_aff_drop_dims(ma, isl_dim_out, n, data->dim - depth - n); + mupa = isl_multi_union_pw_aff_from_multi_aff(ma); + partial = isl_schedule_tree_band_get_partial_schedule(tree); + has_id = isl_multi_union_pw_aff_has_tuple_id(partial, isl_dim_set); + if (has_id < 0) { + partial = isl_multi_union_pw_aff_free(partial); + } else if (has_id) { + isl_id *id; + id = isl_multi_union_pw_aff_get_tuple_id(partial, isl_dim_set); + mupa = isl_multi_union_pw_aff_set_tuple_id(mupa, + isl_dim_set, id); + } + partial = isl_multi_union_pw_aff_union_add(partial, mupa); + tree = isl_schedule_tree_band_set_partial_schedule(tree, partial); + + return tree; +} + +/* Drop the parameters in "uset" that are not also in "space". + * "n" is the number of parameters in "space". + */ +static __isl_give isl_union_set *union_set_drop_extra_params( + __isl_take isl_union_set *uset, __isl_keep isl_space *space, int n) +{ + int n2; + + uset = isl_union_set_align_params(uset, isl_space_copy(space)); + n2 = isl_union_set_dim(uset, isl_dim_param); + uset = isl_union_set_project_out(uset, isl_dim_param, n, n2 - n); + + return uset; +} + +/* Update the context tree root "tree" to refer to the group instances + * in data->group rather than the original domain elements in data->domain. + * "pos" is the position in the original schedule tree where the modified + * "tree" will be attached. + * + * We do not actually need to update "tree" since a context node only + * refers to the schedule space. However, we may need to update "data" + * to not refer to any parameters introduced by the context node. + */ +static __isl_give isl_schedule_tree *group_context( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos, + struct isl_schedule_group_data *data) +{ + isl_space *space; + isl_union_set *domain; + int n1, n2; + int involves; + + if (isl_schedule_node_get_tree_depth(pos) == 1) + return tree; + + domain = isl_schedule_node_get_universe_domain(pos); + space = isl_union_set_get_space(domain); + isl_union_set_free(domain); + + n1 = isl_space_dim(space, isl_dim_param); + data->expansion = isl_union_map_align_params(data->expansion, space); + n2 = isl_union_map_dim(data->expansion, isl_dim_param); + + if (!data->expansion) + return isl_schedule_tree_free(tree); + if (n1 == n2) + return tree; + + involves = isl_union_map_involves_dims(data->expansion, + isl_dim_param, n1, n2 - n1); + if (involves < 0) + return isl_schedule_tree_free(tree); + if (involves) + isl_die(isl_schedule_node_get_ctx(pos), isl_error_invalid, + "grouping cannot only refer to global parameters", + return isl_schedule_tree_free(tree)); + + data->expansion = isl_union_map_project_out(data->expansion, + isl_dim_param, n1, n2 - n1); + space = isl_union_map_get_space(data->expansion); + + data->contraction = isl_union_pw_multi_aff_align_params( + data->contraction, isl_space_copy(space)); + n2 = isl_union_pw_multi_aff_dim(data->contraction, isl_dim_param); + data->contraction = isl_union_pw_multi_aff_drop_dims(data->contraction, + isl_dim_param, n1, n2 - n1); + + data->domain = union_set_drop_extra_params(data->domain, space, n1); + data->domain_universe = + union_set_drop_extra_params(data->domain_universe, space, n1); + data->group = union_set_drop_extra_params(data->group, space, n1); + data->group_universe = + union_set_drop_extra_params(data->group_universe, space, n1); + + data->sched = isl_multi_aff_align_params(data->sched, + isl_space_copy(space)); + n2 = isl_multi_aff_dim(data->sched, isl_dim_param); + data->sched = isl_multi_aff_drop_dims(data->sched, + isl_dim_param, n1, n2 - n1); + + isl_space_free(space); + + return tree; +} + +/* Update the domain tree root "tree" to refer to the group instances + * in data->group rather than the original domain elements in data->domain. + * "pos" is the position in the original schedule tree where the modified + * "tree" will be attached. + * + * We first double-check that all grouped domain elements are actually + * part of the root domain and then replace those elements by the group + * instances. + */ +static __isl_give isl_schedule_tree *group_domain( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos, + struct isl_schedule_group_data *data) +{ + isl_union_set *domain; + int is_subset; + + domain = isl_schedule_tree_domain_get_domain(tree); + is_subset = isl_union_set_is_subset(data->domain, domain); + isl_union_set_free(domain); + if (is_subset < 0) + return isl_schedule_tree_free(tree); + if (!is_subset) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "grouped domain should be part of outer domain", + return isl_schedule_tree_free(tree)); + domain = isl_schedule_tree_domain_get_domain(tree); + domain = isl_union_set_subtract(domain, + isl_union_set_copy(data->domain)); + domain = isl_union_set_union(domain, isl_union_set_copy(data->group)); + tree = isl_schedule_tree_domain_set_domain(tree, domain); + + return tree; +} + +/* Update the expansion tree root "tree" to refer to the group instances + * in data->group rather than the original domain elements in data->domain. + * "pos" is the position in the original schedule tree where the modified + * "tree" will be attached. + * + * Let G_1 -> D_1 be the expansion of "tree" and G_2 -> D_2 the newly + * introduced expansion in a descendant of "tree". + * We first double-check that D_2 is a subset of D_1. + * Then we remove D_2 from the range of G_1 -> D_1 and add the mapping + * G_1 -> D_1 . D_2 -> G_2. + * Simmilarly, we restrict the domain of the contraction to the universe + * of the range of the updated expansion and add G_2 -> D_2 . D_1 -> G_1, + * attempting to remove the domain constraints of this additional part. + */ +static __isl_give isl_schedule_tree *group_expansion( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos, + struct isl_schedule_group_data *data) +{ + isl_union_set *domain; + isl_union_map *expansion, *umap; + isl_union_pw_multi_aff *contraction, *upma; + int is_subset; + + expansion = isl_schedule_tree_expansion_get_expansion(tree); + domain = isl_union_map_range(expansion); + is_subset = isl_union_set_is_subset(data->domain, domain); + isl_union_set_free(domain); + if (is_subset < 0) + return isl_schedule_tree_free(tree); + if (!is_subset) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "grouped domain should be part " + "of outer expansion domain", + return isl_schedule_tree_free(tree)); + expansion = isl_schedule_tree_expansion_get_expansion(tree); + umap = isl_union_map_from_union_pw_multi_aff( + isl_union_pw_multi_aff_copy(data->contraction)); + umap = isl_union_map_apply_range(expansion, umap); + expansion = isl_schedule_tree_expansion_get_expansion(tree); + expansion = isl_union_map_subtract_range(expansion, + isl_union_set_copy(data->domain)); + expansion = isl_union_map_union(expansion, umap); + umap = isl_union_map_universe(isl_union_map_copy(expansion)); + domain = isl_union_map_range(umap); + contraction = isl_schedule_tree_expansion_get_contraction(tree); + umap = isl_union_map_from_union_pw_multi_aff(contraction); + umap = isl_union_map_apply_range(isl_union_map_copy(data->expansion), + umap); + upma = isl_union_pw_multi_aff_from_union_map(umap); + contraction = isl_schedule_tree_expansion_get_contraction(tree); + contraction = isl_union_pw_multi_aff_intersect_domain(contraction, + domain); + domain = isl_union_pw_multi_aff_domain( + isl_union_pw_multi_aff_copy(upma)); + upma = isl_union_pw_multi_aff_gist(upma, domain); + contraction = isl_union_pw_multi_aff_union_add(contraction, upma); + tree = isl_schedule_tree_expansion_set_contraction_and_expansion(tree, + contraction, expansion); + + return tree; +} + +/* Update the tree root "tree" to refer to the group instances + * in data->group rather than the original domain elements in data->domain. + * "pos" is the position in the original schedule tree where the modified + * "tree" will be attached. + * + * If we have come across a domain or expansion node before (data->finished + * is set), then we no longer need perform any modifications. + * + * If "tree" is a filter, then we add data->group_universe to the filter. + * We also remove data->domain_universe from the filter if all the domain + * elements in this universe that reach the filter node are part of + * the elements that are being grouped by data->expansion. + * If "tree" is a band, domain or expansion, then it is handled + * in a separate function. + */ +static __isl_give isl_schedule_tree *group_ancestor( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos, + void *user) +{ + struct isl_schedule_group_data *data = user; + isl_union_set *domain; + int is_covered; + + if (!tree || !pos) + return isl_schedule_tree_free(tree); + + if (data->finished) + return tree; + + switch (isl_schedule_tree_get_type(tree)) { + case isl_schedule_node_error: + return isl_schedule_tree_free(tree); + case isl_schedule_node_extension: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported, + "grouping not allowed in extended tree", + return isl_schedule_tree_free(tree)); + case isl_schedule_node_band: + tree = group_band(tree, pos, data); + break; + case isl_schedule_node_context: + tree = group_context(tree, pos, data); + break; + case isl_schedule_node_domain: + tree = group_domain(tree, pos, data); + data->finished = 1; + break; + case isl_schedule_node_filter: + domain = isl_schedule_node_get_domain(pos); + is_covered = locally_covered_by_domain(domain, data); + isl_union_set_free(domain); + if (is_covered < 0) + return isl_schedule_tree_free(tree); + domain = isl_schedule_tree_filter_get_filter(tree); + if (is_covered) + domain = isl_union_set_subtract(domain, + isl_union_set_copy(data->domain_universe)); + domain = isl_union_set_union(domain, + isl_union_set_copy(data->group_universe)); + tree = isl_schedule_tree_filter_set_filter(tree, domain); + break; + case isl_schedule_node_expansion: + tree = group_expansion(tree, pos, data); + data->finished = 1; + break; + case isl_schedule_node_leaf: + case isl_schedule_node_guard: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + } + + return tree; +} + +/* Group the domain elements that reach "node" into instances + * of a single statement with identifier "group_id". + * In particular, group the domain elements according to their + * prefix schedule. + * + * That is, introduce an expansion node with as contraction + * the prefix schedule (with the target space replaced by "group_id") + * and as expansion the inverse of this contraction (with its range + * intersected with the domain elements that reach "node"). + * The outer nodes are then modified to refer to the group instances + * instead of the original domain elements. + * + * No instance of "group_id" is allowed to reach "node" prior + * to the grouping. + * No ancestor of "node" is allowed to be an extension node. + * + * Return a pointer to original node in tree, i.e., the child + * of the newly introduced expansion node. + */ +__isl_give isl_schedule_node *isl_schedule_node_group( + __isl_take isl_schedule_node *node, __isl_take isl_id *group_id) +{ + struct isl_schedule_group_data data = { 0 }; + isl_space *space; + isl_union_set *domain; + isl_union_pw_multi_aff *contraction; + isl_union_map *expansion; + int disjoint; + + if (!node || !group_id) + goto error; + if (check_insert(node) < 0) + goto error; + + domain = isl_schedule_node_get_domain(node); + data.domain = isl_union_set_copy(domain); + data.domain_universe = isl_union_set_copy(domain); + data.domain_universe = isl_union_set_universe(data.domain_universe); + + data.dim = isl_schedule_node_get_schedule_depth(node); + if (data.dim == 0) { + isl_ctx *ctx; + isl_set *set; + isl_union_set *group; + isl_union_map *univ; + + ctx = isl_schedule_node_get_ctx(node); + space = isl_space_set_alloc(ctx, 0, 0); + space = isl_space_set_tuple_id(space, isl_dim_set, group_id); + set = isl_set_universe(isl_space_copy(space)); + group = isl_union_set_from_set(set); + expansion = isl_union_map_from_domain_and_range(domain, group); + univ = isl_union_map_universe(isl_union_map_copy(expansion)); + contraction = isl_union_pw_multi_aff_from_union_map(univ); + expansion = isl_union_map_reverse(expansion); + } else { + isl_multi_union_pw_aff *prefix; + isl_union_set *univ; + + prefix = + isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(node); + prefix = isl_multi_union_pw_aff_set_tuple_id(prefix, + isl_dim_set, group_id); + space = isl_multi_union_pw_aff_get_space(prefix); + contraction = isl_union_pw_multi_aff_from_multi_union_pw_aff( + prefix); + univ = isl_union_set_universe(isl_union_set_copy(domain)); + contraction = + isl_union_pw_multi_aff_intersect_domain(contraction, univ); + expansion = isl_union_map_from_union_pw_multi_aff( + isl_union_pw_multi_aff_copy(contraction)); + expansion = isl_union_map_reverse(expansion); + expansion = isl_union_map_intersect_range(expansion, domain); + } + space = isl_space_map_from_set(space); + data.sched = isl_multi_aff_identity(space); + data.group = isl_union_map_domain(isl_union_map_copy(expansion)); + data.group = isl_union_set_coalesce(data.group); + data.group_universe = isl_union_set_copy(data.group); + data.group_universe = isl_union_set_universe(data.group_universe); + data.expansion = isl_union_map_copy(expansion); + data.contraction = isl_union_pw_multi_aff_copy(contraction); + node = isl_schedule_node_insert_expansion(node, contraction, expansion); + + disjoint = isl_union_set_is_disjoint(data.domain_universe, + data.group_universe); + + node = update_ancestors(node, &group_ancestor, &data); + + isl_union_set_free(data.domain); + isl_union_set_free(data.domain_universe); + isl_union_set_free(data.group); + isl_union_set_free(data.group_universe); + isl_multi_aff_free(data.sched); + isl_union_map_free(data.expansion); + isl_union_pw_multi_aff_free(data.contraction); + + node = isl_schedule_node_child(node, 0); + + if (!node || disjoint < 0) + return isl_schedule_node_free(node); + if (!disjoint) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "group instances already reach node", + return isl_schedule_node_free(node)); + + return node; +error: + isl_schedule_node_free(node); + isl_id_free(group_id); + return NULL; +} + +/* Compute the gist of the given band node with respect to "context". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_gist( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *context) +{ + isl_schedule_tree *tree; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_gist(tree, context); + return isl_schedule_node_graft_tree(node, tree); +} + +/* Internal data structure for isl_schedule_node_gist. + * "n_expansion" is the number of outer expansion nodes + * with respect to the current position + * "filters" contains an element for each outer filter, expansion or + * extension node with respect to the current position, each representing + * the intersection of the previous element and the filter on the filter node + * or the expansion/extension of the previous element. + * The first element in the original context passed to isl_schedule_node_gist. + */ +struct isl_node_gist_data { + int n_expansion; + isl_union_set_list *filters; +}; + +/* Enter the expansion node "node" during a isl_schedule_node_gist traversal. + * + * In particular, add an extra element to data->filters containing + * the expansion of the previous element and replace the expansion + * and contraction on "node" by the gist with respect to these filters. + * Also keep track of the fact that we have entered another expansion. + */ +static __isl_give isl_schedule_node *gist_enter_expansion( + __isl_take isl_schedule_node *node, struct isl_node_gist_data *data) +{ + int n; + isl_union_set *inner; + isl_union_map *expansion; + isl_union_pw_multi_aff *contraction; + + data->n_expansion++; + + n = isl_union_set_list_n_union_set(data->filters); + inner = isl_union_set_list_get_union_set(data->filters, n - 1); + expansion = isl_schedule_node_expansion_get_expansion(node); + inner = isl_union_set_apply(inner, expansion); + + contraction = isl_schedule_node_expansion_get_contraction(node); + contraction = isl_union_pw_multi_aff_gist(contraction, + isl_union_set_copy(inner)); + + data->filters = isl_union_set_list_add(data->filters, inner); + + inner = isl_union_set_list_get_union_set(data->filters, n - 1); + expansion = isl_schedule_node_expansion_get_expansion(node); + expansion = isl_union_map_gist_domain(expansion, inner); + node = isl_schedule_node_expansion_set_contraction_and_expansion(node, + contraction, expansion); + + return node; +} + +/* Leave the expansion node "node" during a isl_schedule_node_gist traversal. + * + * In particular, remove the element in data->filters that was added by + * gist_enter_expansion and decrement the number of outer expansions. + * + * The expansion has already been simplified in gist_enter_expansion. + * If this simplification results in an identity expansion, then + * it is removed here. + */ +static __isl_give isl_schedule_node *gist_leave_expansion( + __isl_take isl_schedule_node *node, struct isl_node_gist_data *data) +{ + int n; + isl_bool identity; + isl_union_map *expansion; + + expansion = isl_schedule_node_expansion_get_expansion(node); + identity = isl_union_map_is_identity(expansion); + isl_union_map_free(expansion); + + if (identity < 0) + node = isl_schedule_node_free(node); + else if (identity) + node = isl_schedule_node_delete(node); + + n = isl_union_set_list_n_union_set(data->filters); + data->filters = isl_union_set_list_drop(data->filters, n - 1, 1); + + data->n_expansion--; + + return node; +} + +/* Enter the extension node "node" during a isl_schedule_node_gist traversal. + * + * In particular, add an extra element to data->filters containing + * the union of the previous element with the additional domain elements + * introduced by the extension. + */ +static __isl_give isl_schedule_node *gist_enter_extension( + __isl_take isl_schedule_node *node, struct isl_node_gist_data *data) +{ + int n; + isl_union_set *inner, *extra; + isl_union_map *extension; + + n = isl_union_set_list_n_union_set(data->filters); + inner = isl_union_set_list_get_union_set(data->filters, n - 1); + extension = isl_schedule_node_extension_get_extension(node); + extra = isl_union_map_range(extension); + inner = isl_union_set_union(inner, extra); + + data->filters = isl_union_set_list_add(data->filters, inner); + + return node; +} + +/* Can we finish gisting at this node? + * That is, is the filter on the current filter node a subset of + * the original context passed to isl_schedule_node_gist? + * If we have gone through any expansions, then we cannot perform + * this test since the current domain elements are incomparable + * to the domain elements in the original context. + */ +static int gist_done(__isl_keep isl_schedule_node *node, + struct isl_node_gist_data *data) +{ + isl_union_set *filter, *outer; + int subset; + + if (data->n_expansion != 0) + return 0; + + filter = isl_schedule_node_filter_get_filter(node); + outer = isl_union_set_list_get_union_set(data->filters, 0); + subset = isl_union_set_is_subset(filter, outer); + isl_union_set_free(outer); + isl_union_set_free(filter); + + return subset; +} + +/* Callback for "traverse" to enter a node and to move + * to the deepest initial subtree that should be traversed + * by isl_schedule_node_gist. + * + * The "filters" list is extended by one element each time + * we come across a filter node by the result of intersecting + * the last element in the list with the filter on the filter node. + * + * If the filter on the current filter node is a subset of + * the original context passed to isl_schedule_node_gist, + * then there is no need to go into its subtree since it cannot + * be further simplified by the context. The "filters" list is + * still extended for consistency, but the actual value of the + * added element is immaterial since it will not be used. + * + * Otherwise, the filter on the current filter node is replaced by + * the gist of the original filter with respect to the intersection + * of the original context with the intermediate filters. + * + * If the new element in the "filters" list is empty, then no elements + * can reach the descendants of the current filter node. The subtree + * underneath the filter node is therefore removed. + * + * Each expansion node we come across is handled by + * gist_enter_expansion. + * + * Each extension node we come across is handled by + * gist_enter_extension. + */ +static __isl_give isl_schedule_node *gist_enter( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_node_gist_data *data = user; + + do { + isl_union_set *filter, *inner; + int done, empty; + int n; + + switch (isl_schedule_node_get_type(node)) { + case isl_schedule_node_error: + return isl_schedule_node_free(node); + case isl_schedule_node_expansion: + node = gist_enter_expansion(node, data); + continue; + case isl_schedule_node_extension: + node = gist_enter_extension(node, data); + continue; + case isl_schedule_node_band: + case isl_schedule_node_context: + case isl_schedule_node_domain: + case isl_schedule_node_guard: + case isl_schedule_node_leaf: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + continue; + case isl_schedule_node_filter: + break; + } + done = gist_done(node, data); + filter = isl_schedule_node_filter_get_filter(node); + if (done < 0 || done) { + data->filters = isl_union_set_list_add(data->filters, + filter); + if (done < 0) + return isl_schedule_node_free(node); + return node; + } + n = isl_union_set_list_n_union_set(data->filters); + inner = isl_union_set_list_get_union_set(data->filters, n - 1); + filter = isl_union_set_gist(filter, isl_union_set_copy(inner)); + node = isl_schedule_node_filter_set_filter(node, + isl_union_set_copy(filter)); + filter = isl_union_set_intersect(filter, inner); + empty = isl_union_set_is_empty(filter); + data->filters = isl_union_set_list_add(data->filters, filter); + if (empty < 0) + return isl_schedule_node_free(node); + if (!empty) + continue; + node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_cut(node); + node = isl_schedule_node_parent(node); + return node; + } while (isl_schedule_node_has_children(node) && + (node = isl_schedule_node_first_child(node)) != NULL); + + return node; +} + +/* Callback for "traverse" to leave a node for isl_schedule_node_gist. + * + * In particular, if the current node is a filter node, then we remove + * the element on the "filters" list that was added when we entered + * the node. There is no need to compute any gist here, since we + * already did that when we entered the node. + * + * Expansion nodes are handled by gist_leave_expansion. + * + * If the current node is an extension, then remove the element + * in data->filters that was added by gist_enter_extension. + * + * If the current node is a band node, then we compute the gist of + * the band node with respect to the intersection of the original context + * and the intermediate filters. + * + * If the current node is a sequence or set node, then some of + * the filter children may have become empty and so they are removed. + * If only one child is left, then the set or sequence node along with + * the single remaining child filter is removed. The filter can be + * removed because the filters on a sequence or set node are supposed + * to partition the incoming domain instances. + * In principle, it should then be impossible for there to be zero + * remaining children, but should this happen, we replace the entire + * subtree with an empty filter. + */ +static __isl_give isl_schedule_node *gist_leave( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_node_gist_data *data = user; + isl_schedule_tree *tree; + int i, n; + isl_union_set *filter; + + switch (isl_schedule_node_get_type(node)) { + case isl_schedule_node_error: + return isl_schedule_node_free(node); + case isl_schedule_node_expansion: + node = gist_leave_expansion(node, data); + break; + case isl_schedule_node_extension: + case isl_schedule_node_filter: + n = isl_union_set_list_n_union_set(data->filters); + data->filters = isl_union_set_list_drop(data->filters, + n - 1, 1); + break; + case isl_schedule_node_band: + n = isl_union_set_list_n_union_set(data->filters); + filter = isl_union_set_list_get_union_set(data->filters, n - 1); + node = isl_schedule_node_band_gist(node, filter); + break; + case isl_schedule_node_set: + case isl_schedule_node_sequence: + tree = isl_schedule_node_get_tree(node); + n = isl_schedule_tree_n_children(tree); + for (i = n - 1; i >= 0; --i) { + isl_schedule_tree *child; + isl_union_set *filter; + int empty; + + child = isl_schedule_tree_get_child(tree, i); + filter = isl_schedule_tree_filter_get_filter(child); + empty = isl_union_set_is_empty(filter); + isl_union_set_free(filter); + isl_schedule_tree_free(child); + if (empty < 0) + tree = isl_schedule_tree_free(tree); + else if (empty) + tree = isl_schedule_tree_drop_child(tree, i); + } + n = isl_schedule_tree_n_children(tree); + node = isl_schedule_node_graft_tree(node, tree); + if (n == 1) { + node = isl_schedule_node_delete(node); + node = isl_schedule_node_delete(node); + } else if (n == 0) { + isl_space *space; + + filter = + isl_union_set_list_get_union_set(data->filters, 0); + space = isl_union_set_get_space(filter); + isl_union_set_free(filter); + filter = isl_union_set_empty(space); + node = isl_schedule_node_cut(node); + node = isl_schedule_node_insert_filter(node, filter); + } + break; + case isl_schedule_node_context: + case isl_schedule_node_domain: + case isl_schedule_node_guard: + case isl_schedule_node_leaf: + case isl_schedule_node_mark: + break; + } + + return node; +} + +/* Compute the gist of the subtree at "node" with respect to + * the reaching domain elements in "context". + * In particular, compute the gist of all band and filter nodes + * in the subtree with respect to "context". Children of set or sequence + * nodes that end up with an empty filter are removed completely. + * + * We keep track of the intersection of "context" with all outer filters + * of the current node within the subtree in the final element of "filters". + * Initially, this list contains the single element "context" and it is + * extended or shortened each time we enter or leave a filter node. + */ +__isl_give isl_schedule_node *isl_schedule_node_gist( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *context) +{ + struct isl_node_gist_data data; + + data.n_expansion = 0; + data.filters = isl_union_set_list_from_union_set(context); + node = traverse(node, &gist_enter, &gist_leave, &data); + isl_union_set_list_free(data.filters); + return node; +} + +/* Intersect the domain of domain node "node" with "domain". + * + * If the domain of "node" is already a subset of "domain", + * then nothing needs to be changed. + * + * Otherwise, we replace the domain of the domain node by the intersection + * and simplify the subtree rooted at "node" with respect to this intersection. + */ +__isl_give isl_schedule_node *isl_schedule_node_domain_intersect_domain( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *domain) +{ + isl_schedule_tree *tree; + isl_union_set *uset; + int is_subset; + + if (!node || !domain) + goto error; + + uset = isl_schedule_tree_domain_get_domain(node->tree); + is_subset = isl_union_set_is_subset(uset, domain); + isl_union_set_free(uset); + if (is_subset < 0) + goto error; + if (is_subset) { + isl_union_set_free(domain); + return node; + } + + tree = isl_schedule_tree_copy(node->tree); + uset = isl_schedule_tree_domain_get_domain(tree); + uset = isl_union_set_intersect(uset, domain); + tree = isl_schedule_tree_domain_set_domain(tree, + isl_union_set_copy(uset)); + node = isl_schedule_node_graft_tree(node, tree); + + node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_gist(node, uset); + node = isl_schedule_node_parent(node); + + return node; +error: + isl_schedule_node_free(node); + isl_union_set_free(domain); + return NULL; +} + +/* Replace the domain of domain node "node" with the gist + * of the original domain with respect to the parameter domain "context". + */ +__isl_give isl_schedule_node *isl_schedule_node_domain_gist_params( + __isl_take isl_schedule_node *node, __isl_take isl_set *context) +{ + isl_union_set *domain; + isl_schedule_tree *tree; + + if (!node || !context) + goto error; + + tree = isl_schedule_tree_copy(node->tree); + domain = isl_schedule_tree_domain_get_domain(node->tree); + domain = isl_union_set_gist_params(domain, context); + tree = isl_schedule_tree_domain_set_domain(tree, domain); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +error: + isl_schedule_node_free(node); + isl_set_free(context); + return NULL; +} + +/* Internal data structure for isl_schedule_node_get_subtree_expansion. + * "expansions" contains a list of accumulated expansions + * for each outer expansion, set or sequence node. The first element + * in the list is an identity mapping on the reaching domain elements. + * "res" collects the results. + */ +struct isl_subtree_expansion_data { + isl_union_map_list *expansions; + isl_union_map *res; +}; + +/* Callback for "traverse" to enter a node and to move + * to the deepest initial subtree that should be traversed + * by isl_schedule_node_get_subtree_expansion. + * + * Whenever we come across an expansion node, the last element + * of data->expansions is combined with the expansion + * on the expansion node. + * + * Whenever we come across a filter node that is the child + * of a set or sequence node, data->expansions is extended + * with a new element that restricts the previous element + * to the elements selected by the filter. + * The previous element can then be reused while backtracking. + */ +static __isl_give isl_schedule_node *subtree_expansion_enter( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_subtree_expansion_data *data = user; + + do { + enum isl_schedule_node_type type; + isl_union_set *filter; + isl_union_map *inner, *expansion; + int n; + + switch (isl_schedule_node_get_type(node)) { + case isl_schedule_node_error: + return isl_schedule_node_free(node); + case isl_schedule_node_filter: + type = isl_schedule_node_get_parent_type(node); + if (type != isl_schedule_node_set && + type != isl_schedule_node_sequence) + break; + filter = isl_schedule_node_filter_get_filter(node); + n = isl_union_map_list_n_union_map(data->expansions); + inner = + isl_union_map_list_get_union_map(data->expansions, + n - 1); + inner = isl_union_map_intersect_range(inner, filter); + data->expansions = + isl_union_map_list_add(data->expansions, inner); + break; + case isl_schedule_node_expansion: + n = isl_union_map_list_n_union_map(data->expansions); + expansion = + isl_schedule_node_expansion_get_expansion(node); + inner = + isl_union_map_list_get_union_map(data->expansions, + n - 1); + inner = isl_union_map_apply_range(inner, expansion); + data->expansions = + isl_union_map_list_set_union_map(data->expansions, + n - 1, inner); + break; + case isl_schedule_node_band: + case isl_schedule_node_context: + case isl_schedule_node_domain: + case isl_schedule_node_extension: + case isl_schedule_node_guard: + case isl_schedule_node_leaf: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + } + } while (isl_schedule_node_has_children(node) && + (node = isl_schedule_node_first_child(node)) != NULL); + + return node; +} + +/* Callback for "traverse" to leave a node for + * isl_schedule_node_get_subtree_expansion. + * + * If we come across a filter node that is the child + * of a set or sequence node, then we remove the element + * of data->expansions that was added in subtree_expansion_enter. + * + * If we reach a leaf node, then the accumulated expansion is + * added to data->res. + */ +static __isl_give isl_schedule_node *subtree_expansion_leave( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_subtree_expansion_data *data = user; + int n; + isl_union_map *inner; + enum isl_schedule_node_type type; + + switch (isl_schedule_node_get_type(node)) { + case isl_schedule_node_error: + return isl_schedule_node_free(node); + case isl_schedule_node_filter: + type = isl_schedule_node_get_parent_type(node); + if (type != isl_schedule_node_set && + type != isl_schedule_node_sequence) + break; + n = isl_union_map_list_n_union_map(data->expansions); + data->expansions = isl_union_map_list_drop(data->expansions, + n - 1, 1); + break; + case isl_schedule_node_leaf: + n = isl_union_map_list_n_union_map(data->expansions); + inner = isl_union_map_list_get_union_map(data->expansions, + n - 1); + data->res = isl_union_map_union(data->res, inner); + break; + case isl_schedule_node_band: + case isl_schedule_node_context: + case isl_schedule_node_domain: + case isl_schedule_node_expansion: + case isl_schedule_node_extension: + case isl_schedule_node_guard: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + } + + return node; +} + +/* Return a mapping from the domain elements that reach "node" + * to the corresponding domain elements in the leaves of the subtree + * rooted at "node" obtained by composing the intermediate expansions. + * + * We start out with an identity mapping between the domain elements + * that reach "node" and compose it with all the expansions + * on a path from "node" to a leaf while traversing the subtree. + * Within the children of an a sequence or set node, the + * accumulated expansion is restricted to the elements selected + * by the filter child. + */ +__isl_give isl_union_map *isl_schedule_node_get_subtree_expansion( + __isl_keep isl_schedule_node *node) +{ + struct isl_subtree_expansion_data data; + isl_space *space; + isl_union_set *domain; + isl_union_map *expansion; + + if (!node) + return NULL; + + domain = isl_schedule_node_get_universe_domain(node); + space = isl_union_set_get_space(domain); + expansion = isl_union_set_identity(domain); + data.res = isl_union_map_empty(space); + data.expansions = isl_union_map_list_from_union_map(expansion); + + node = isl_schedule_node_copy(node); + node = traverse(node, &subtree_expansion_enter, + &subtree_expansion_leave, &data); + if (!node) + data.res = isl_union_map_free(data.res); + isl_schedule_node_free(node); + + isl_union_map_list_free(data.expansions); + + return data.res; +} + +/* Internal data structure for isl_schedule_node_get_subtree_contraction. + * "contractions" contains a list of accumulated contractions + * for each outer expansion, set or sequence node. The first element + * in the list is an identity mapping on the reaching domain elements. + * "res" collects the results. + */ +struct isl_subtree_contraction_data { + isl_union_pw_multi_aff_list *contractions; + isl_union_pw_multi_aff *res; +}; + +/* Callback for "traverse" to enter a node and to move + * to the deepest initial subtree that should be traversed + * by isl_schedule_node_get_subtree_contraction. + * + * Whenever we come across an expansion node, the last element + * of data->contractions is combined with the contraction + * on the expansion node. + * + * Whenever we come across a filter node that is the child + * of a set or sequence node, data->contractions is extended + * with a new element that restricts the previous element + * to the elements selected by the filter. + * The previous element can then be reused while backtracking. + */ +static __isl_give isl_schedule_node *subtree_contraction_enter( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_subtree_contraction_data *data = user; + + do { + enum isl_schedule_node_type type; + isl_union_set *filter; + isl_union_pw_multi_aff *inner, *contraction; + int n; + + switch (isl_schedule_node_get_type(node)) { + case isl_schedule_node_error: + return isl_schedule_node_free(node); + case isl_schedule_node_filter: + type = isl_schedule_node_get_parent_type(node); + if (type != isl_schedule_node_set && + type != isl_schedule_node_sequence) + break; + filter = isl_schedule_node_filter_get_filter(node); + n = isl_union_pw_multi_aff_list_n_union_pw_multi_aff( + data->contractions); + inner = + isl_union_pw_multi_aff_list_get_union_pw_multi_aff( + data->contractions, n - 1); + inner = isl_union_pw_multi_aff_intersect_domain(inner, + filter); + data->contractions = + isl_union_pw_multi_aff_list_add(data->contractions, + inner); + break; + case isl_schedule_node_expansion: + n = isl_union_pw_multi_aff_list_n_union_pw_multi_aff( + data->contractions); + contraction = + isl_schedule_node_expansion_get_contraction(node); + inner = + isl_union_pw_multi_aff_list_get_union_pw_multi_aff( + data->contractions, n - 1); + inner = + isl_union_pw_multi_aff_pullback_union_pw_multi_aff( + inner, contraction); + data->contractions = + isl_union_pw_multi_aff_list_set_union_pw_multi_aff( + data->contractions, n - 1, inner); + break; + case isl_schedule_node_band: + case isl_schedule_node_context: + case isl_schedule_node_domain: + case isl_schedule_node_extension: + case isl_schedule_node_guard: + case isl_schedule_node_leaf: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + } + } while (isl_schedule_node_has_children(node) && + (node = isl_schedule_node_first_child(node)) != NULL); + + return node; +} + +/* Callback for "traverse" to leave a node for + * isl_schedule_node_get_subtree_contraction. + * + * If we come across a filter node that is the child + * of a set or sequence node, then we remove the element + * of data->contractions that was added in subtree_contraction_enter. + * + * If we reach a leaf node, then the accumulated contraction is + * added to data->res. + */ +static __isl_give isl_schedule_node *subtree_contraction_leave( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_subtree_contraction_data *data = user; + int n; + isl_union_pw_multi_aff *inner; + enum isl_schedule_node_type type; + + switch (isl_schedule_node_get_type(node)) { + case isl_schedule_node_error: + return isl_schedule_node_free(node); + case isl_schedule_node_filter: + type = isl_schedule_node_get_parent_type(node); + if (type != isl_schedule_node_set && + type != isl_schedule_node_sequence) + break; + n = isl_union_pw_multi_aff_list_n_union_pw_multi_aff( + data->contractions); + data->contractions = + isl_union_pw_multi_aff_list_drop(data->contractions, + n - 1, 1); + break; + case isl_schedule_node_leaf: + n = isl_union_pw_multi_aff_list_n_union_pw_multi_aff( + data->contractions); + inner = isl_union_pw_multi_aff_list_get_union_pw_multi_aff( + data->contractions, n - 1); + data->res = isl_union_pw_multi_aff_union_add(data->res, inner); + break; + case isl_schedule_node_band: + case isl_schedule_node_context: + case isl_schedule_node_domain: + case isl_schedule_node_expansion: + case isl_schedule_node_extension: + case isl_schedule_node_guard: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + } + + return node; +} + +/* Return a mapping from the domain elements in the leaves of the subtree + * rooted at "node" to the corresponding domain elements that reach "node" + * obtained by composing the intermediate contractions. + * + * We start out with an identity mapping between the domain elements + * that reach "node" and compose it with all the contractions + * on a path from "node" to a leaf while traversing the subtree. + * Within the children of an a sequence or set node, the + * accumulated contraction is restricted to the elements selected + * by the filter child. + */ +__isl_give isl_union_pw_multi_aff *isl_schedule_node_get_subtree_contraction( + __isl_keep isl_schedule_node *node) +{ + struct isl_subtree_contraction_data data; + isl_space *space; + isl_union_set *domain; + isl_union_pw_multi_aff *contraction; + + if (!node) + return NULL; + + domain = isl_schedule_node_get_universe_domain(node); + space = isl_union_set_get_space(domain); + contraction = isl_union_set_identity_union_pw_multi_aff(domain); + data.res = isl_union_pw_multi_aff_empty(space); + data.contractions = + isl_union_pw_multi_aff_list_from_union_pw_multi_aff(contraction); + + node = isl_schedule_node_copy(node); + node = traverse(node, &subtree_contraction_enter, + &subtree_contraction_leave, &data); + if (!node) + data.res = isl_union_pw_multi_aff_free(data.res); + isl_schedule_node_free(node); + + isl_union_pw_multi_aff_list_free(data.contractions); + + return data.res; +} + +/* Do the nearest "n" ancestors of "node" have the types given in "types" + * (starting at the parent of "node")? + */ +static int has_ancestors(__isl_keep isl_schedule_node *node, + int n, enum isl_schedule_node_type *types) +{ + int i, n_ancestor; + + if (!node) + return -1; + + n_ancestor = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + if (n_ancestor < n) + return 0; + + for (i = 0; i < n; ++i) { + isl_schedule_tree *tree; + int correct_type; + + tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, + n_ancestor - 1 - i); + if (!tree) + return -1; + correct_type = isl_schedule_tree_get_type(tree) == types[i]; + isl_schedule_tree_free(tree); + if (!correct_type) + return 0; + } + + return 1; +} + +/* Given a node "node" that appears in an extension (i.e., it is the child + * of a filter in a sequence inside an extension node), are the spaces + * of the extension specified by "extension" disjoint from those + * of both the original extension and the domain elements that reach + * that original extension? + */ +static int is_disjoint_extension(__isl_keep isl_schedule_node *node, + __isl_keep isl_union_map *extension) +{ + isl_union_map *old; + isl_union_set *domain; + int empty; + + node = isl_schedule_node_copy(node); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); + old = isl_schedule_node_extension_get_extension(node); + domain = isl_schedule_node_get_universe_domain(node); + isl_schedule_node_free(node); + old = isl_union_map_universe(old); + domain = isl_union_set_union(domain, isl_union_map_range(old)); + extension = isl_union_map_copy(extension); + extension = isl_union_map_intersect_range(extension, domain); + empty = isl_union_map_is_empty(extension); + isl_union_map_free(extension); + + return empty; +} + +/* Given a node "node" that is governed by an extension node, extend + * that extension node with "extension". + * + * In particular, "node" is the child of a filter in a sequence that + * is in turn a child of an extension node. Extend that extension node + * with "extension". + * + * Return a pointer to the parent of the original node (i.e., a filter). + */ +static __isl_give isl_schedule_node *extend_extension( + __isl_take isl_schedule_node *node, __isl_take isl_union_map *extension) +{ + int pos; + int disjoint; + isl_union_map *node_extension; + + node = isl_schedule_node_parent(node); + pos = isl_schedule_node_get_child_position(node); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); + node_extension = isl_schedule_node_extension_get_extension(node); + disjoint = isl_union_map_is_disjoint(extension, node_extension); + extension = isl_union_map_union(extension, node_extension); + node = isl_schedule_node_extension_set_extension(node, extension); + node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_child(node, pos); + + if (disjoint < 0) + return isl_schedule_node_free(node); + if (!node) + return NULL; + if (!disjoint) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "extension domain should be disjoint from earlier " + "extensions", return isl_schedule_node_free(node)); + + return node; +} + +/* Return the universe of "uset" if this universe is disjoint from "ref". + * Otherwise, return "uset". + * + * Also check if "uset" itself is disjoint from "ref", reporting + * an error if it is not. + */ +static __isl_give isl_union_set *replace_by_universe_if_disjoint( + __isl_take isl_union_set *uset, __isl_keep isl_union_set *ref) +{ + int disjoint; + isl_union_set *universe; + + disjoint = isl_union_set_is_disjoint(uset, ref); + if (disjoint < 0) + return isl_union_set_free(uset); + if (!disjoint) + isl_die(isl_union_set_get_ctx(uset), isl_error_invalid, + "extension domain should be disjoint from " + "current domain", return isl_union_set_free(uset)); + + universe = isl_union_set_universe(isl_union_set_copy(uset)); + disjoint = isl_union_set_is_disjoint(universe, ref); + if (disjoint >= 0 && disjoint) { + isl_union_set_free(uset); + return universe; + } + isl_union_set_free(universe); + + if (disjoint < 0) + return isl_union_set_free(uset); + return uset; +} + +/* Insert an extension node on top of "node" with extension "extension". + * In addition, insert a filter that separates node from the extension + * between the extension node and "node". + * Return a pointer to the inserted filter node. + * + * If "node" already appears in an extension (i.e., if it is the child + * of a filter in a sequence inside an extension node), then extend that + * extension with "extension" instead. + * In this case, a pointer to the original filter node is returned. + * Note that if some of the elements in the new extension live in the + * same space as those of the original extension or the domain elements + * reaching the original extension, then we insert a new extension anyway. + * Otherwise, we would have to adjust the filters in the sequence child + * of the extension to ensure that the elements in the new extension + * are filtered out. + */ +static __isl_give isl_schedule_node *insert_extension( + __isl_take isl_schedule_node *node, __isl_take isl_union_map *extension) +{ + enum isl_schedule_node_type ancestors[] = + { isl_schedule_node_filter, isl_schedule_node_sequence, + isl_schedule_node_extension }; + isl_union_set *domain; + isl_union_set *filter; + int in_ext; + + in_ext = has_ancestors(node, 3, ancestors); + if (in_ext < 0) + goto error; + if (in_ext) { + int disjoint; + + disjoint = is_disjoint_extension(node, extension); + if (disjoint < 0) + goto error; + if (disjoint) + return extend_extension(node, extension); + } + + filter = isl_schedule_node_get_domain(node); + domain = isl_union_map_range(isl_union_map_copy(extension)); + filter = replace_by_universe_if_disjoint(filter, domain); + isl_union_set_free(domain); + + node = isl_schedule_node_insert_filter(node, filter); + node = isl_schedule_node_insert_extension(node, extension); + node = isl_schedule_node_child(node, 0); + return node; +error: + isl_schedule_node_free(node); + isl_union_map_free(extension); + return NULL; +} + +/* Replace the subtree that "node" points to by "tree" (which has + * a sequence root with two children), except if the parent of "node" + * is a sequence as well, in which case "tree" is spliced at the position + * of "node" in its parent. + * Return a pointer to the child of the "tree_pos" (filter) child of "tree" + * in the updated schedule tree. + */ +static __isl_give isl_schedule_node *graft_or_splice( + __isl_take isl_schedule_node *node, __isl_take isl_schedule_tree *tree, + int tree_pos) +{ + int pos; + + if (isl_schedule_node_get_parent_type(node) == + isl_schedule_node_sequence) { + pos = isl_schedule_node_get_child_position(node); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_sequence_splice(node, pos, tree); + } else { + pos = 0; + node = isl_schedule_node_graft_tree(node, tree); + } + node = isl_schedule_node_child(node, pos + tree_pos); + node = isl_schedule_node_child(node, 0); + + return node; +} + +/* Insert a node "graft" into the schedule tree of "node" such that it + * is executed before (if "before" is set) or after (if "before" is not set) + * the node that "node" points to. + * The root of "graft" is an extension node. + * Return a pointer to the node that "node" pointed to. + * + * We first insert an extension node on top of "node" (or extend + * the extension node if there already is one), with a filter on "node" + * separating it from the extension. + * We then insert a filter in the graft to separate it from the original + * domain elements and combine the original and new tree in a sequence. + * If we have extended an extension node, then the children of this + * sequence are spliced in the sequence of the extended extension + * at the position where "node" appears in the original extension. + * Otherwise, the sequence pair is attached to the new extension node. + */ +static __isl_give isl_schedule_node *graft_extension( + __isl_take isl_schedule_node *node, __isl_take isl_schedule_node *graft, + int before) +{ + isl_union_map *extension; + isl_union_set *graft_domain; + isl_union_set *node_domain; + isl_schedule_tree *tree, *tree_graft; + + extension = isl_schedule_node_extension_get_extension(graft); + graft_domain = isl_union_map_range(isl_union_map_copy(extension)); + node_domain = isl_schedule_node_get_universe_domain(node); + node = insert_extension(node, extension); + + graft_domain = replace_by_universe_if_disjoint(graft_domain, + node_domain); + isl_union_set_free(node_domain); + + tree = isl_schedule_node_get_tree(node); + if (!isl_schedule_node_has_children(graft)) { + tree_graft = isl_schedule_tree_from_filter(graft_domain); + } else { + graft = isl_schedule_node_child(graft, 0); + tree_graft = isl_schedule_node_get_tree(graft); + tree_graft = isl_schedule_tree_insert_filter(tree_graft, + graft_domain); + } + if (before) + tree = isl_schedule_tree_sequence_pair(tree_graft, tree); + else + tree = isl_schedule_tree_sequence_pair(tree, tree_graft); + node = graft_or_splice(node, tree, before); + + isl_schedule_node_free(graft); + + return node; +} + +/* Replace the root domain node of "node" by an extension node suitable + * for insertion at "pos". + * That is, create an extension node that maps the outer band nodes + * at "pos" to the domain of the root node of "node" and attach + * the child of this root node to the extension node. + */ +static __isl_give isl_schedule_node *extension_from_domain( + __isl_take isl_schedule_node *node, __isl_keep isl_schedule_node *pos) +{ + isl_union_set *universe; + isl_union_set *domain; + isl_union_map *ext; + int depth; + int anchored; + isl_space *space; + isl_schedule_node *res; + isl_schedule_tree *tree; + + anchored = isl_schedule_node_is_subtree_anchored(node); + if (anchored < 0) + return isl_schedule_node_free(node); + if (anchored) + isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported, + "cannot graft anchored tree with domain root", + return isl_schedule_node_free(node)); + + depth = isl_schedule_node_get_schedule_depth(pos); + domain = isl_schedule_node_domain_get_domain(node); + space = isl_union_set_get_space(domain); + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, depth); + universe = isl_union_set_from_set(isl_set_universe(space)); + ext = isl_union_map_from_domain_and_range(universe, domain); + res = isl_schedule_node_from_extension(ext); + node = isl_schedule_node_child(node, 0); + if (!node) + return isl_schedule_node_free(res); + if (!isl_schedule_tree_is_leaf(node->tree)) { + tree = isl_schedule_node_get_tree(node); + res = isl_schedule_node_child(res, 0); + res = isl_schedule_node_graft_tree(res, tree); + res = isl_schedule_node_parent(res); + } + isl_schedule_node_free(node); + + return res; +} + +/* Insert a node "graft" into the schedule tree of "node" such that it + * is executed before (if "before" is set) or after (if "before" is not set) + * the node that "node" points to. + * The root of "graft" may be either a domain or an extension node. + * In the latter case, the domain of the extension needs to correspond + * to the outer band nodes of "node". + * The elements of the domain or the range of the extension may not + * intersect with the domain elements that reach "node". + * The schedule tree of "graft" may not be anchored. + * + * The schedule tree of "node" is modified to include an extension node + * corresponding to the root node of "graft" as a child of the original + * parent of "node". The original node that "node" points to and the + * child of the root node of "graft" are attached to this extension node + * through a sequence, with appropriate filters and with the child + * of "graft" appearing before or after the original "node". + * + * If "node" already appears inside a sequence that is the child of + * an extension node and if the spaces of the new domain elements + * do not overlap with those of the original domain elements, + * then that extension node is extended with the new extension + * rather than introducing a new segment of extension and sequence nodes. + * + * Return a pointer to the same node in the modified tree that + * "node" pointed to in the original tree. + */ +static __isl_give isl_schedule_node *isl_schedule_node_graft_before_or_after( + __isl_take isl_schedule_node *node, __isl_take isl_schedule_node *graft, + int before) +{ + if (!node || !graft) + goto error; + if (check_insert(node) < 0) + goto error; + + if (isl_schedule_node_get_type(graft) == isl_schedule_node_domain) + graft = extension_from_domain(graft, node); + + if (isl_schedule_node_get_type(graft) != isl_schedule_node_extension) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "expecting domain or extension as root of graft", + goto error); + + return graft_extension(node, graft, before); +error: + isl_schedule_node_free(node); + isl_schedule_node_free(graft); + return NULL; +} + +/* Insert a node "graft" into the schedule tree of "node" such that it + * is executed before the node that "node" points to. + * The root of "graft" may be either a domain or an extension node. + * In the latter case, the domain of the extension needs to correspond + * to the outer band nodes of "node". + * The elements of the domain or the range of the extension may not + * intersect with the domain elements that reach "node". + * The schedule tree of "graft" may not be anchored. + * + * Return a pointer to the same node in the modified tree that + * "node" pointed to in the original tree. + */ +__isl_give isl_schedule_node *isl_schedule_node_graft_before( + __isl_take isl_schedule_node *node, __isl_take isl_schedule_node *graft) +{ + return isl_schedule_node_graft_before_or_after(node, graft, 1); +} + +/* Insert a node "graft" into the schedule tree of "node" such that it + * is executed after the node that "node" points to. + * The root of "graft" may be either a domain or an extension node. + * In the latter case, the domain of the extension needs to correspond + * to the outer band nodes of "node". + * The elements of the domain or the range of the extension may not + * intersect with the domain elements that reach "node". + * The schedule tree of "graft" may not be anchored. + * + * Return a pointer to the same node in the modified tree that + * "node" pointed to in the original tree. + */ +__isl_give isl_schedule_node *isl_schedule_node_graft_after( + __isl_take isl_schedule_node *node, + __isl_take isl_schedule_node *graft) +{ + return isl_schedule_node_graft_before_or_after(node, graft, 0); +} + +/* Split the domain elements that reach "node" into those that satisfy + * "filter" and those that do not. Arrange for the first subset to be + * executed before or after the second subset, depending on the value + * of "before". + * Return a pointer to the tree corresponding to the second subset, + * except when this subset is empty in which case the original pointer + * is returned. + * If both subsets are non-empty, then a sequence node is introduced + * to impose the order. If the grandparent of the original node was + * itself a sequence, then the original child is replaced by two children + * in this sequence instead. + * The children in the sequence are copies of the original subtree, + * simplified with respect to their filters. + */ +static __isl_give isl_schedule_node *isl_schedule_node_order_before_or_after( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter, + int before) +{ + enum isl_schedule_node_type ancestors[] = + { isl_schedule_node_filter, isl_schedule_node_sequence }; + isl_union_set *node_domain, *node_filter = NULL, *parent_filter; + isl_schedule_node *node2; + isl_schedule_tree *tree1, *tree2; + int empty1, empty2; + int in_seq; + + if (!node || !filter) + goto error; + if (check_insert(node) < 0) + goto error; + + in_seq = has_ancestors(node, 2, ancestors); + if (in_seq < 0) + goto error; + node_domain = isl_schedule_node_get_domain(node); + filter = isl_union_set_gist(filter, isl_union_set_copy(node_domain)); + node_filter = isl_union_set_copy(node_domain); + node_filter = isl_union_set_subtract(node_filter, + isl_union_set_copy(filter)); + node_filter = isl_union_set_gist(node_filter, node_domain); + empty1 = isl_union_set_is_empty(filter); + empty2 = isl_union_set_is_empty(node_filter); + if (empty1 < 0 || empty2 < 0) + goto error; + if (empty1 || empty2) { + isl_union_set_free(filter); + isl_union_set_free(node_filter); + return node; + } + + if (in_seq) { + node = isl_schedule_node_parent(node); + parent_filter = isl_schedule_node_filter_get_filter(node); + node_filter = isl_union_set_intersect(node_filter, + isl_union_set_copy(parent_filter)); + filter = isl_union_set_intersect(filter, parent_filter); + } + + node2 = isl_schedule_node_copy(node); + node = isl_schedule_node_gist(node, isl_union_set_copy(node_filter)); + node2 = isl_schedule_node_gist(node2, isl_union_set_copy(filter)); + tree1 = isl_schedule_node_get_tree(node); + tree2 = isl_schedule_node_get_tree(node2); + tree1 = isl_schedule_tree_insert_filter(tree1, node_filter); + tree2 = isl_schedule_tree_insert_filter(tree2, filter); + isl_schedule_node_free(node2); + + if (before) { + tree1 = isl_schedule_tree_sequence_pair(tree2, tree1); + node = graft_or_splice(node, tree1, 1); + } else { + tree1 = isl_schedule_tree_sequence_pair(tree1, tree2); + node = graft_or_splice(node, tree1, 0); + } + + return node; +error: + isl_schedule_node_free(node); + isl_union_set_free(filter); + isl_union_set_free(node_filter); + return NULL; +} + +/* Split the domain elements that reach "node" into those that satisfy + * "filter" and those that do not. Arrange for the first subset to be + * executed before the second subset. + * Return a pointer to the tree corresponding to the second subset, + * except when this subset is empty in which case the original pointer + * is returned. + */ +__isl_give isl_schedule_node *isl_schedule_node_order_before( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter) +{ + return isl_schedule_node_order_before_or_after(node, filter, 1); +} + +/* Split the domain elements that reach "node" into those that satisfy + * "filter" and those that do not. Arrange for the first subset to be + * executed after the second subset. + * Return a pointer to the tree corresponding to the second subset, + * except when this subset is empty in which case the original pointer + * is returned. + */ +__isl_give isl_schedule_node *isl_schedule_node_order_after( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter) +{ + return isl_schedule_node_order_before_or_after(node, filter, 0); +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * in the schedule node "node". + */ +__isl_give isl_schedule_node *isl_schedule_node_reset_user( + __isl_take isl_schedule_node *node) +{ + isl_schedule_tree *tree; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_reset_user(tree); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Align the parameters of the schedule node "node" to those of "space". + */ +__isl_give isl_schedule_node *isl_schedule_node_align_params( + __isl_take isl_schedule_node *node, __isl_take isl_space *space) +{ + isl_schedule_tree *tree; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_align_params(tree, space); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Compute the pullback of schedule node "node" + * by the function represented by "upma". + * In other words, plug in "upma" in the iteration domains + * of schedule node "node". + * We currently do not handle expansion nodes. + * + * Note that this is only a helper function for + * isl_schedule_pullback_union_pw_multi_aff. In order to maintain consistency, + * this function should not be called on a single node without also + * calling it on all the other nodes. + */ +__isl_give isl_schedule_node *isl_schedule_node_pullback_union_pw_multi_aff( + __isl_take isl_schedule_node *node, + __isl_take isl_union_pw_multi_aff *upma) +{ + isl_schedule_tree *tree; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_pullback_union_pw_multi_aff(tree, upma); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Internal data structure for isl_schedule_node_expand. + * "tree" is the tree that needs to be plugged in in all the leaves. + * "domain" is the set of domain elements in the original leaves + * to which the tree applies. + */ +struct isl_schedule_expand_data { + isl_schedule_tree *tree; + isl_union_set *domain; +}; + +/* If "node" is a leaf, then plug in data->tree, simplifying it + * within its new context. + * + * If there are any domain elements at the leaf where the tree + * should not be plugged in (i.e., there are elements not in data->domain) + * then first extend the tree to only apply to the elements in data->domain + * by constructing a set node that selects data->tree for elements + * in data->domain and a leaf for the other elements. + */ +static __isl_give isl_schedule_node *expand(__isl_take isl_schedule_node *node, + void *user) +{ + struct isl_schedule_expand_data *data = user; + isl_schedule_tree *tree, *leaf; + isl_union_set *domain, *left; + isl_bool empty; + + if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf) + return node; + + domain = isl_schedule_node_get_domain(node); + tree = isl_schedule_tree_copy(data->tree); + + left = isl_union_set_copy(domain); + left = isl_union_set_subtract(left, isl_union_set_copy(data->domain)); + empty = isl_union_set_is_empty(left); + if (empty >= 0 && !empty) { + leaf = isl_schedule_node_get_leaf(node); + leaf = isl_schedule_tree_insert_filter(leaf, left); + left = isl_union_set_copy(data->domain); + tree = isl_schedule_tree_insert_filter(tree, left); + tree = isl_schedule_tree_set_pair(tree, leaf); + } else { + if (empty < 0) + node = isl_schedule_node_free(node); + isl_union_set_free(left); + } + + node = isl_schedule_node_graft_tree(node, tree); + node = isl_schedule_node_gist(node, domain); + + return node; +} + +/* Expand the tree rooted at "node" by extending all leaves + * with an expansion node with as child "tree". + * The expansion is determined by "contraction" and "domain". + * That is, the elements of "domain" are contracted according + * to "contraction". The expansion relation is then the inverse + * of "contraction" with its range intersected with "domain". + * + * Insert the appropriate expansion node on top of "tree" and + * then plug in the result in all leaves of "node". + */ +__isl_give isl_schedule_node *isl_schedule_node_expand( + __isl_take isl_schedule_node *node, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_set *domain, + __isl_take isl_schedule_tree *tree) +{ + struct isl_schedule_expand_data data; + isl_union_map *expansion; + isl_union_pw_multi_aff *copy; + + if (!node || !contraction || !tree) + node = isl_schedule_node_free(node); + + copy = isl_union_pw_multi_aff_copy(contraction); + expansion = isl_union_map_from_union_pw_multi_aff(copy); + expansion = isl_union_map_reverse(expansion); + expansion = isl_union_map_intersect_range(expansion, domain); + data.domain = isl_union_map_domain(isl_union_map_copy(expansion)); + + tree = isl_schedule_tree_insert_expansion(tree, contraction, expansion); + data.tree = tree; + + node = isl_schedule_node_map_descendant_bottom_up(node, &expand, &data); + isl_union_set_free(data.domain); + isl_schedule_tree_free(data.tree); + return node; +} + +/* Return the position of the subtree containing "node" among the children + * of "ancestor". "node" is assumed to be a descendant of "ancestor". + * In particular, both nodes should point to the same schedule tree. + * + * Return -1 on error. + */ +int isl_schedule_node_get_ancestor_child_position( + __isl_keep isl_schedule_node *node, + __isl_keep isl_schedule_node *ancestor) +{ + int n1, n2; + isl_schedule_tree *tree; + + if (!node || !ancestor) + return -1; + + if (node->schedule != ancestor->schedule) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a descendant", return -1); + + n1 = isl_schedule_node_get_tree_depth(ancestor); + n2 = isl_schedule_node_get_tree_depth(node); + + if (n1 >= n2) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a descendant", return -1); + tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, n1); + isl_schedule_tree_free(tree); + if (tree != ancestor->tree) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a descendant", return -1); + + return node->child_pos[n1]; +} + +/* Given two nodes that point to the same schedule tree, return their + * closest shared ancestor. + * + * Since the two nodes point to the same schedule, they share at least + * one ancestor, the root of the schedule. We move down from the root + * to the first ancestor where the respective children have a different + * child position. This is the requested ancestor. + * If there is no ancestor where the children have a different position, + * then one node is an ancestor of the other and then this node is + * the requested ancestor. + */ +__isl_give isl_schedule_node *isl_schedule_node_get_shared_ancestor( + __isl_keep isl_schedule_node *node1, + __isl_keep isl_schedule_node *node2) +{ + int i, n1, n2; + + if (!node1 || !node2) + return NULL; + if (node1->schedule != node2->schedule) + isl_die(isl_schedule_node_get_ctx(node1), isl_error_invalid, + "not part of same schedule", return NULL); + n1 = isl_schedule_node_get_tree_depth(node1); + n2 = isl_schedule_node_get_tree_depth(node2); + if (n2 < n1) + return isl_schedule_node_get_shared_ancestor(node2, node1); + if (n1 == 0) + return isl_schedule_node_copy(node1); + if (isl_schedule_node_is_equal(node1, node2)) + return isl_schedule_node_copy(node1); + + for (i = 0; i < n1; ++i) + if (node1->child_pos[i] != node2->child_pos[i]) + break; + + node1 = isl_schedule_node_copy(node1); + return isl_schedule_node_ancestor(node1, n1 - i); +} + +/* Print "node" to "p". + */ +__isl_give isl_printer *isl_printer_print_schedule_node( + __isl_take isl_printer *p, __isl_keep isl_schedule_node *node) +{ + if (!node) + return isl_printer_free(p); + return isl_printer_print_schedule_tree_mark(p, node->schedule->root, + isl_schedule_tree_list_n_schedule_tree(node->ancestors), + node->child_pos); +} + +void isl_schedule_node_dump(__isl_keep isl_schedule_node *node) +{ + isl_ctx *ctx; + isl_printer *printer; + + if (!node) + return; + + ctx = isl_schedule_node_get_ctx(node); + printer = isl_printer_to_file(ctx, stderr); + printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK); + printer = isl_printer_print_schedule_node(printer, node); + + isl_printer_free(printer); +} + +/* Return a string representation of "node". + * Print the schedule node in block format as it would otherwise + * look identical to the entire schedule. + */ +__isl_give char *isl_schedule_node_to_str(__isl_keep isl_schedule_node *node) +{ + isl_printer *printer; + char *s; + + if (!node) + return NULL; + + printer = isl_printer_to_str(isl_schedule_node_get_ctx(node)); + printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK); + printer = isl_printer_print_schedule_node(printer, node); + s = isl_printer_get_str(printer); + isl_printer_free(printer); + + return s; +} Index: contrib/isl/isl_schedule_node_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_node_private.h @@ -0,0 +1,68 @@ +#ifndef ISL_SCHEDLUE_NODE_PRIVATE_H +#define ISL_SCHEDLUE_NODE_PRIVATE_H + +#include +#include +#include + +/* An isl_schedule_node points to a particular location in a schedule tree. + * + * "schedule" is the schedule that the node is pointing to. + * "ancestors" is a list of the n ancestors of the node + * that is being pointed to. + * The first ancestor is the root of "schedule", while the last ancestor + * is the parent of the specified location. + * "child_pos" is an array of child positions of the same length as "ancestors", + * where ancestor i (i > 0) appears in child_pos[i - 1] of ancestor i - 1 and + * "tree" appears in child_pos[n - 1] of ancestor n - 1. + * "tree" is the subtree at the specified location. + * + * Note that the same isl_schedule_tree object may appear several times + * in a schedule tree and therefore does not uniquely identify a position + * in the schedule tree. + */ +struct isl_schedule_node { + int ref; + + isl_schedule *schedule; + isl_schedule_tree_list *ancestors; + int *child_pos; + isl_schedule_tree *tree; +}; + +__isl_give isl_schedule_node *isl_schedule_node_alloc( + __isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree, + __isl_take isl_schedule_tree_list *ancestors, int *child_pos); +__isl_give isl_schedule_node *isl_schedule_node_graft_tree( + __isl_take isl_schedule_node *pos, __isl_take isl_schedule_tree *tree); + +__isl_give isl_schedule_tree *isl_schedule_node_get_tree( + __isl_keep isl_schedule_node *node); + +__isl_give isl_schedule_node *isl_schedule_node_pullback_union_pw_multi_aff( + __isl_take isl_schedule_node *node, + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_schedule_node *isl_schedule_node_expand( + __isl_take isl_schedule_node *node, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_set *domain, + __isl_take isl_schedule_tree *tree); + +__isl_give isl_schedule_node *isl_schedule_node_gist( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *context); + +__isl_give isl_schedule_node *isl_schedule_node_domain_intersect_domain( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *domain); +__isl_give isl_schedule_node *isl_schedule_node_domain_gist_params( + __isl_take isl_schedule_node *node, __isl_take isl_set *context); + +__isl_give isl_schedule_node *isl_schedule_node_insert_expansion( + __isl_take isl_schedule_node *node, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion); +__isl_give isl_schedule_node *isl_schedule_node_insert_extension( + __isl_take isl_schedule_node *node, + __isl_take isl_union_map *extension); + +#endif Index: contrib/isl/isl_schedule_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_private.h @@ -0,0 +1,36 @@ +#ifndef ISL_SCHEDLUE_PRIVATE_H +#define ISL_SCHEDLUE_PRIVATE_H + +#include +#include +#include + +/* A complete schedule tree. + * + * "root" is the root of the schedule tree. + * + * "leaf" may be used to represent a leaf of the schedule. + * It should not appear as a child to any other isl_schedule_tree objects, + * but an isl_schedule_node may have "leaf" as its tree if it refers to + * a leaf of this schedule tree. + */ +struct isl_schedule { + int ref; + + isl_schedule_tree *root; + + struct isl_schedule_tree *leaf; +}; + +__isl_give isl_schedule *isl_schedule_from_schedule_tree(isl_ctx *ctx, + __isl_take isl_schedule_tree *tree); +__isl_give isl_schedule *isl_schedule_set_root( + __isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree); +__isl_give isl_space *isl_schedule_get_space( + __isl_keep isl_schedule *schedule); +__isl_give isl_union_set *isl_schedule_get_domain( + __isl_keep isl_schedule *schedule); +__isl_keep isl_schedule_tree *isl_schedule_peek_leaf( + __isl_keep isl_schedule *schedule); + +#endif Index: contrib/isl/isl_schedule_read.c =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_read.c @@ -0,0 +1,776 @@ +#include +#include +#include +#include +#include + +/* An enumeration of the various keys that may appear in a YAML mapping + * of a schedule. + */ +enum isl_schedule_key { + isl_schedule_key_error = -1, + isl_schedule_key_child, + isl_schedule_key_coincident, + isl_schedule_key_context, + isl_schedule_key_contraction, + isl_schedule_key_domain, + isl_schedule_key_expansion, + isl_schedule_key_extension, + isl_schedule_key_filter, + isl_schedule_key_guard, + isl_schedule_key_leaf, + isl_schedule_key_mark, + isl_schedule_key_options, + isl_schedule_key_permutable, + isl_schedule_key_schedule, + isl_schedule_key_sequence, + isl_schedule_key_set, + isl_schedule_key_end +}; + +/* Textual representations of the YAML keys for an isl_schedule object. + */ +static char *key_str[] = { + [isl_schedule_key_child] = "child", + [isl_schedule_key_coincident] = "coincident", + [isl_schedule_key_context] = "context", + [isl_schedule_key_contraction] = "contraction", + [isl_schedule_key_domain] = "domain", + [isl_schedule_key_expansion] = "expansion", + [isl_schedule_key_extension] = "extension", + [isl_schedule_key_filter] = "filter", + [isl_schedule_key_guard] = "guard", + [isl_schedule_key_leaf] = "leaf", + [isl_schedule_key_mark] = "mark", + [isl_schedule_key_options] = "options", + [isl_schedule_key_permutable] = "permutable", + [isl_schedule_key_schedule] = "schedule", + [isl_schedule_key_sequence] = "sequence", + [isl_schedule_key_set] = "set", +}; + +#undef KEY +#define KEY enum isl_schedule_key +#undef KEY_ERROR +#define KEY_ERROR isl_schedule_key_error +#undef KEY_END +#define KEY_END isl_schedule_key_end +#include "extract_key.c" + +static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( + __isl_keep isl_stream *s); + +/* Read a subtree with context root node from "s". + */ +static __isl_give isl_schedule_tree *read_context(__isl_keep isl_stream *s) +{ + isl_set *context = NULL; + isl_schedule_tree *tree; + isl_ctx *ctx; + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + int more; + + ctx = isl_stream_get_ctx(s); + + key = get_key(s); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + str = isl_token_get_str(ctx, tok); + context = isl_set_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + + more = isl_stream_yaml_next(s); + if (more < 0) + goto error; + if (!more) { + tree = isl_schedule_tree_from_context(context); + } else { + key = get_key(s); + if (key != isl_schedule_key_child) + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + if (isl_stream_yaml_next(s) < 0) + goto error; + tree = isl_stream_read_schedule_tree(s); + tree = isl_schedule_tree_insert_context(tree, context); + } + + return tree; +error: + isl_set_free(context); + return NULL; +} + +/* Read a subtree with domain root node from "s". + */ +static __isl_give isl_schedule_tree *read_domain(__isl_keep isl_stream *s) +{ + isl_union_set *domain = NULL; + isl_schedule_tree *tree; + isl_ctx *ctx; + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + int more; + + ctx = isl_stream_get_ctx(s); + + key = get_key(s); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + str = isl_token_get_str(ctx, tok); + domain = isl_union_set_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + + more = isl_stream_yaml_next(s); + if (more < 0) + goto error; + if (!more) { + tree = isl_schedule_tree_from_domain(domain); + } else { + key = get_key(s); + if (key != isl_schedule_key_child) + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + if (isl_stream_yaml_next(s) < 0) + goto error; + tree = isl_stream_read_schedule_tree(s); + tree = isl_schedule_tree_insert_domain(tree, domain); + } + + return tree; +error: + isl_union_set_free(domain); + return NULL; +} + +/* Read a subtree with expansion root node from "s". + */ +static __isl_give isl_schedule_tree *read_expansion(isl_stream *s) +{ + isl_ctx *ctx; + isl_union_pw_multi_aff *contraction = NULL; + isl_union_map *expansion = NULL; + isl_schedule_tree *tree = NULL; + int more; + + ctx = isl_stream_get_ctx(s); + + do { + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + + key = get_key(s); + if (isl_stream_yaml_next(s) < 0) + goto error; + + switch (key) { + case isl_schedule_key_contraction: + isl_union_pw_multi_aff_free(contraction); + tok = isl_stream_next_token(s); + str = isl_token_get_str(ctx, tok); + contraction = isl_union_pw_multi_aff_read_from_str(ctx, + str); + free(str); + isl_token_free(tok); + if (!contraction) + goto error; + break; + case isl_schedule_key_expansion: + isl_union_map_free(expansion); + tok = isl_stream_next_token(s); + str = isl_token_get_str(ctx, tok); + expansion = isl_union_map_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + if (!expansion) + goto error; + break; + case isl_schedule_key_child: + isl_schedule_tree_free(tree); + tree = isl_stream_read_schedule_tree(s); + if (!tree) + goto error; + break; + default: + isl_die(ctx, isl_error_invalid, "unexpected key", + goto error); + } + } while ((more = isl_stream_yaml_next(s)) > 0); + + if (more < 0) + goto error; + + if (!contraction) + isl_die(ctx, isl_error_invalid, "missing contraction", + goto error); + if (!expansion) + isl_die(ctx, isl_error_invalid, "missing expansion", + goto error); + + if (!tree) + return isl_schedule_tree_from_expansion(contraction, expansion); + return isl_schedule_tree_insert_expansion(tree, contraction, expansion); +error: + isl_schedule_tree_free(tree); + isl_union_pw_multi_aff_free(contraction); + isl_union_map_free(expansion); + return NULL; +} + +/* Read a subtree with extension root node from "s". + */ +static __isl_give isl_schedule_tree *read_extension(isl_stream *s) +{ + isl_union_map *extension = NULL; + isl_schedule_tree *tree; + isl_ctx *ctx; + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + int more; + + ctx = isl_stream_get_ctx(s); + + key = get_key(s); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + str = isl_token_get_str(ctx, tok); + extension = isl_union_map_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + + more = isl_stream_yaml_next(s); + if (more < 0) + goto error; + if (!more) { + tree = isl_schedule_tree_from_extension(extension); + } else { + key = get_key(s); + if (key != isl_schedule_key_child) + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + if (isl_stream_yaml_next(s) < 0) + goto error; + tree = isl_stream_read_schedule_tree(s); + tree = isl_schedule_tree_insert_extension(tree, extension); + } + + return tree; +error: + isl_union_map_free(extension); + return NULL; +} + +/* Read a subtree with filter root node from "s". + */ +static __isl_give isl_schedule_tree *read_filter(__isl_keep isl_stream *s) +{ + isl_union_set *filter = NULL; + isl_schedule_tree *tree; + isl_ctx *ctx; + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + int more; + + ctx = isl_stream_get_ctx(s); + + key = get_key(s); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + str = isl_token_get_str(ctx, tok); + filter = isl_union_set_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + + more = isl_stream_yaml_next(s); + if (more < 0) + goto error; + if (!more) { + tree = isl_schedule_tree_from_filter(filter); + } else { + key = get_key(s); + if (key != isl_schedule_key_child) + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + if (isl_stream_yaml_next(s) < 0) + goto error; + tree = isl_stream_read_schedule_tree(s); + tree = isl_schedule_tree_insert_filter(tree, filter); + } + + return tree; +error: + isl_union_set_free(filter); + return NULL; +} + +/* Read a subtree with guard root node from "s". + */ +static __isl_give isl_schedule_tree *read_guard(isl_stream *s) +{ + isl_set *guard = NULL; + isl_schedule_tree *tree; + isl_ctx *ctx; + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + int more; + + ctx = isl_stream_get_ctx(s); + + key = get_key(s); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + str = isl_token_get_str(ctx, tok); + guard = isl_set_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + + more = isl_stream_yaml_next(s); + if (more < 0) + goto error; + if (!more) { + tree = isl_schedule_tree_from_guard(guard); + } else { + key = get_key(s); + if (key != isl_schedule_key_child) + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + if (isl_stream_yaml_next(s) < 0) + goto error; + tree = isl_stream_read_schedule_tree(s); + tree = isl_schedule_tree_insert_guard(tree, guard); + } + + return tree; +error: + isl_set_free(guard); + return NULL; +} + +/* Read a subtree with mark root node from "s". + */ +static __isl_give isl_schedule_tree *read_mark(isl_stream *s) +{ + isl_id *mark; + isl_schedule_tree *tree; + isl_ctx *ctx; + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + int more; + + ctx = isl_stream_get_ctx(s); + + key = get_key(s); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + str = isl_token_get_str(ctx, tok); + mark = isl_id_alloc(ctx, str, NULL); + free(str); + isl_token_free(tok); + + more = isl_stream_yaml_next(s); + if (more < 0) + goto error; + if (!more) { + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + } else { + key = get_key(s); + if (key != isl_schedule_key_child) + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + if (isl_stream_yaml_next(s) < 0) + goto error; + tree = isl_stream_read_schedule_tree(s); + tree = isl_schedule_tree_insert_mark(tree, mark); + } + + return tree; +error: + isl_id_free(mark); + return NULL; +} + +/* Read a sequence of integers from "s" (representing the coincident + * property of a band node). + */ +static __isl_give isl_val_list *read_coincident(__isl_keep isl_stream *s) +{ + isl_ctx *ctx; + isl_val_list *list; + int more; + + ctx = isl_stream_get_ctx(s); + + if (isl_stream_yaml_read_start_sequence(s) < 0) + return NULL; + + list = isl_val_list_alloc(ctx, 0); + while ((more = isl_stream_yaml_next(s)) > 0) { + isl_val *val; + + val = isl_stream_read_val(s); + list = isl_val_list_add(list, val); + } + + if (more < 0 || isl_stream_yaml_read_end_sequence(s)) + list = isl_val_list_free(list); + + return list; +} + +/* Set the (initial) coincident properties of "band" according to + * the (initial) elements of "coincident". + */ +static __isl_give isl_schedule_band *set_coincident( + __isl_take isl_schedule_band *band, __isl_take isl_val_list *coincident) +{ + int i; + int n, m; + + n = isl_schedule_band_n_member(band); + m = isl_val_list_n_val(coincident); + + for (i = 0; i < n && i < m; ++i) { + isl_val *v; + + v = isl_val_list_get_val(coincident, i); + if (!v) + band = isl_schedule_band_free(band); + band = isl_schedule_band_member_set_coincident(band, i, + !isl_val_is_zero(v)); + isl_val_free(v); + } + isl_val_list_free(coincident); + return band; +} + +/* Read a subtree with band root node from "s". + */ +static __isl_give isl_schedule_tree *read_band(isl_stream *s) +{ + isl_multi_union_pw_aff *schedule = NULL; + isl_schedule_tree *tree = NULL; + isl_val_list *coincident = NULL; + isl_union_set *options = NULL; + isl_ctx *ctx; + isl_schedule_band *band; + int permutable = 0; + int more; + + ctx = isl_stream_get_ctx(s); + + do { + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + isl_val *v; + + key = get_key(s); + if (isl_stream_yaml_next(s) < 0) + goto error; + + switch (key) { + case isl_schedule_key_schedule: + schedule = isl_multi_union_pw_aff_free(schedule); + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + str = isl_token_get_str(ctx, tok); + schedule = isl_multi_union_pw_aff_read_from_str(ctx, + str); + free(str); + isl_token_free(tok); + if (!schedule) + goto error; + break; + case isl_schedule_key_coincident: + coincident = read_coincident(s); + if (!coincident) + goto error; + break; + case isl_schedule_key_permutable: + v = isl_stream_read_val(s); + permutable = !isl_val_is_zero(v); + isl_val_free(v); + break; + case isl_schedule_key_options: + isl_union_set_free(options); + tok = isl_stream_next_token(s); + str = isl_token_get_str(ctx, tok); + options = isl_union_set_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + if (!options) + goto error; + break; + case isl_schedule_key_child: + isl_schedule_tree_free(tree); + tree = isl_stream_read_schedule_tree(s); + if (!tree) + goto error; + break; + default: + isl_die(ctx, isl_error_invalid, "unexpected key", + goto error); + } + } while ((more = isl_stream_yaml_next(s)) > 0); + + if (more < 0) + goto error; + + if (!schedule) + isl_die(ctx, isl_error_invalid, "missing schedule", goto error); + + band = isl_schedule_band_from_multi_union_pw_aff(schedule); + band = isl_schedule_band_set_permutable(band, permutable); + if (coincident) + band = set_coincident(band, coincident); + if (options) + band = isl_schedule_band_set_ast_build_options(band, options); + if (tree) + tree = isl_schedule_tree_insert_band(tree, band); + else + tree = isl_schedule_tree_from_band(band); + + return tree; +error: + isl_val_list_free(coincident); + isl_union_set_free(options); + isl_schedule_tree_free(tree); + isl_multi_union_pw_aff_free(schedule); + return NULL; +} + +/* Read a subtree with root node of type "type" from "s". + * The node is represented by a sequence of children. + */ +static __isl_give isl_schedule_tree *read_children(isl_stream *s, + enum isl_schedule_node_type type) +{ + isl_ctx *ctx; + isl_schedule_tree_list *list; + int more; + + ctx = isl_stream_get_ctx(s); + + isl_token_free(isl_stream_next_token(s)); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + if (isl_stream_yaml_read_start_sequence(s)) + return NULL; + + list = isl_schedule_tree_list_alloc(ctx, 0); + while ((more = isl_stream_yaml_next(s)) > 0) { + isl_schedule_tree *tree; + + tree = isl_stream_read_schedule_tree(s); + list = isl_schedule_tree_list_add(list, tree); + } + + if (more < 0 || isl_stream_yaml_read_end_sequence(s)) + list = isl_schedule_tree_list_free(list); + + return isl_schedule_tree_from_children(type, list); +} + +/* Read a subtree with sequence root node from "s". + */ +static __isl_give isl_schedule_tree *read_sequence(isl_stream *s) +{ + return read_children(s, isl_schedule_node_sequence); +} + +/* Read a subtree with set root node from "s". + */ +static __isl_give isl_schedule_tree *read_set(isl_stream *s) +{ + return read_children(s, isl_schedule_node_set); +} + +/* Read a schedule (sub)tree from "s". + * + * We first determine the type of the root node based on the first + * mapping key and then hand over to a function tailored to reading + * nodes of this type. + */ +static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( + struct isl_stream *s) +{ + enum isl_schedule_key key; + struct isl_token *tok; + isl_schedule_tree *tree = NULL; + int more; + + if (isl_stream_yaml_read_start_mapping(s)) + return NULL; + more = isl_stream_yaml_next(s); + if (more < 0) + return NULL; + if (!more) { + isl_stream_error(s, NULL, "missing key"); + return NULL; + } + + tok = isl_stream_next_token(s); + key = extract_key(s, tok); + isl_stream_push_token(s, tok); + if (key < 0) + return NULL; + switch (key) { + case isl_schedule_key_context: + tree = read_context(s); + break; + case isl_schedule_key_domain: + tree = read_domain(s); + break; + case isl_schedule_key_contraction: + case isl_schedule_key_expansion: + tree = read_expansion(s); + break; + case isl_schedule_key_extension: + tree = read_extension(s); + break; + case isl_schedule_key_filter: + tree = read_filter(s); + break; + case isl_schedule_key_guard: + tree = read_guard(s); + break; + case isl_schedule_key_leaf: + isl_token_free(isl_stream_next_token(s)); + tree = isl_schedule_tree_leaf(isl_stream_get_ctx(s)); + break; + case isl_schedule_key_mark: + tree = read_mark(s); + break; + case isl_schedule_key_sequence: + tree = read_sequence(s); + break; + case isl_schedule_key_set: + tree = read_set(s); + break; + case isl_schedule_key_schedule: + case isl_schedule_key_coincident: + case isl_schedule_key_options: + case isl_schedule_key_permutable: + tree = read_band(s); + break; + case isl_schedule_key_child: + isl_die(isl_stream_get_ctx(s), isl_error_unsupported, + "cannot identity node type", return NULL); + case isl_schedule_key_end: + case isl_schedule_key_error: + return NULL; + } + + if (isl_stream_yaml_read_end_mapping(s) < 0) { + isl_stream_error(s, NULL, "unexpected extra elements"); + return isl_schedule_tree_free(tree); + } + + return tree; +} + +/* Read an isl_schedule from "s". + */ +__isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!s) + return NULL; + + ctx = isl_stream_get_ctx(s); + tree = isl_stream_read_schedule_tree(s); + return isl_schedule_from_schedule_tree(ctx, tree); +} + +/* Read an isl_schedule from "input". + */ +__isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input) +{ + struct isl_stream *s; + isl_schedule *schedule; + + s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + schedule = isl_stream_read_schedule(s); + isl_stream_free(s); + + return schedule; +} + +/* Read an isl_schedule from "str". + */ +__isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx, + const char *str) +{ + struct isl_stream *s; + isl_schedule *schedule; + + s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + schedule = isl_stream_read_schedule(s); + isl_stream_free(s); + + return schedule; +} Index: contrib/isl/isl_schedule_tree.h =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_tree.h @@ -0,0 +1,266 @@ +#ifndef ISL_SCHEDLUE_TREE_H +#define ISL_SCHEDLUE_TREE_H + +#include +#include +#include +#include + +struct isl_schedule_tree; +typedef struct isl_schedule_tree isl_schedule_tree; + +ISL_DECLARE_LIST(schedule_tree) + +/* A schedule (sub)tree. + * + * The leaves of a tree are not explicitly represented inside + * the isl_schedule_tree, except when the tree consists of only a leaf. + * + * The "band" field is valid when type is isl_schedule_node_band. + * The "context" field is valid when type is isl_schedule_node_context + * and represents constraints on the flat product of the outer band nodes, + * possibly introducing additional parameters. + * The "domain" field is valid when type is isl_schedule_node_domain + * and introduces the statement instances scheduled by the tree. + * + * The "contraction" and "expansion" fields are valid when type + * is isl_schedule_node_expansion. + * "expansion" expands the reaching domain elements to one or more + * domain elements for the subtree. + * "contraction" maps these elements back to the corresponding + * reaching domain element. It does not involve any domain constraints. + * + * The "extension" field is valid when the is isl_schedule_node_extension + * maps outer schedule dimenions (the flat product of the outer band nodes) + * to additional iteration domains. + * + * The "filter" field is valid when type is isl_schedule_node_filter + * and represents the statement instances selected by the node. + * + * The "guard" field is valid when type is isl_schedule_node_guard + * and represents constraints on the flat product of the outer band nodes + * that need to be enforced by the outer nodes in the generated AST. + * + * The "mark" field is valid when type is isl_schedule_node_mark and + * identifies the mark. + * + * The "children" field is valid for all types except + * isl_schedule_node_leaf. This field is NULL if there are + * no children (except for the implicit leaves). + * + * anchored is set if the node or any of its descendants depends + * on its position in the schedule tree. + */ +struct isl_schedule_tree { + int ref; + isl_ctx *ctx; + int anchored; + enum isl_schedule_node_type type; + union { + isl_schedule_band *band; + isl_set *context; + isl_union_set *domain; + struct { + isl_union_pw_multi_aff *contraction; + isl_union_map *expansion; + }; + isl_union_map *extension; + isl_union_set *filter; + isl_set *guard; + isl_id *mark; + }; + isl_schedule_tree_list *children; +}; + +isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree); +enum isl_schedule_node_type isl_schedule_tree_get_type( + __isl_keep isl_schedule_tree *tree); + +__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx); +int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree); + +isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1, + __isl_keep isl_schedule_tree *tree2); + +__isl_give isl_schedule_tree *isl_schedule_tree_copy( + __isl_keep isl_schedule_tree *tree); +__isl_null isl_schedule_tree *isl_schedule_tree_free( + __isl_take isl_schedule_tree *tree); + +__isl_give isl_schedule_tree *isl_schedule_tree_from_band( + __isl_take isl_schedule_band *band); +__isl_give isl_schedule_tree *isl_schedule_tree_from_context( + __isl_take isl_set *context); +__isl_give isl_schedule_tree *isl_schedule_tree_from_domain( + __isl_take isl_union_set *domain); +__isl_give isl_schedule_tree *isl_schedule_tree_from_expansion( + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion); +__isl_give isl_schedule_tree *isl_schedule_tree_from_extension( + __isl_take isl_union_map *extension); +__isl_give isl_schedule_tree *isl_schedule_tree_from_filter( + __isl_take isl_union_set *filter); +__isl_give isl_schedule_tree *isl_schedule_tree_from_guard( + __isl_take isl_set *guard); +__isl_give isl_schedule_tree *isl_schedule_tree_from_children( + enum isl_schedule_node_type type, + __isl_take isl_schedule_tree_list *list); +__isl_give isl_schedule_tree *isl_schedule_tree_from_pair( + enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2); +__isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair( + __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2); +__isl_give isl_schedule_tree *isl_schedule_tree_set_pair( + __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2); + +isl_bool isl_schedule_tree_is_subtree_anchored( + __isl_keep isl_schedule_tree *tree); + +__isl_give isl_space *isl_schedule_tree_band_get_space( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain); +__isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule( + __isl_take isl_schedule_tree *tree, + __isl_take isl_multi_union_pw_aff *schedule); +enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type( + __isl_keep isl_schedule_tree *tree, int pos); +__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type( + __isl_take isl_schedule_tree *tree, int pos, + enum isl_ast_loop_type type); +enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type( + __isl_keep isl_schedule_tree *tree, int pos); +__isl_give isl_schedule_tree * +isl_schedule_tree_band_member_set_isolate_ast_loop_type( + __isl_take isl_schedule_tree *tree, int pos, + enum isl_ast_loop_type type); +__isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options); +__isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option( + __isl_keep isl_schedule_tree *tree, int depth); +__isl_give isl_set *isl_schedule_tree_context_get_context( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_union_set *isl_schedule_tree_domain_get_domain( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain); +__isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree * +isl_schedule_tree_expansion_set_contraction_and_expansion( + __isl_take isl_schedule_tree *tree, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion); +__isl_give isl_union_map *isl_schedule_tree_extension_get_extension( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension( + __isl_take isl_schedule_tree *tree, + __isl_take isl_union_map *extension); +__isl_give isl_union_set *isl_schedule_tree_filter_get_filter( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter); +__isl_give isl_set *isl_schedule_tree_guard_get_guard( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_id *isl_schedule_tree_mark_get_id( + __isl_keep isl_schedule_tree *tree); + +__isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf); +__isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map( + __isl_keep isl_schedule_tree *tree); + +unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree); + +isl_bool isl_schedule_tree_band_member_get_coincident( + __isl_keep isl_schedule_tree *tree, int pos); +__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident( + __isl_take isl_schedule_tree *tree, int pos, int coincident); +isl_bool isl_schedule_tree_band_get_permutable( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable( + __isl_take isl_schedule_tree *tree, int permutable); + +int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree); +int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_get_child( + __isl_keep isl_schedule_tree *tree, int pos); + +__isl_give isl_schedule_tree *isl_schedule_tree_insert_band( + __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_context( + __isl_take isl_schedule_tree *tree, __isl_take isl_set *context); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion( + __isl_take isl_schedule_tree *tree, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_extension( + __isl_take isl_schedule_tree *tree, + __isl_take isl_union_map *extension); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter); +__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_guard( + __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_mark( + __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark); + +__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves( + __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2); + +__isl_give isl_schedule_tree *isl_schedule_tree_band_scale( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_tree *isl_schedule_tree_band_mod( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_tree *isl_schedule_tree_band_tile( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes); +__isl_give isl_schedule_tree *isl_schedule_tree_band_shift( + __isl_take isl_schedule_tree *tree, + __isl_take isl_multi_union_pw_aff *shift); +__isl_give isl_schedule_tree *isl_schedule_tree_band_split( + __isl_take isl_schedule_tree *tree, int pos, int depth); +__isl_give isl_schedule_tree *isl_schedule_tree_band_gist( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context); + +__isl_give isl_schedule_tree *isl_schedule_tree_child( + __isl_take isl_schedule_tree *tree, int pos); +__isl_give isl_schedule_tree *isl_schedule_tree_reset_children( + __isl_take isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_drop_child( + __isl_take isl_schedule_tree *tree, int pos); +__isl_give isl_schedule_tree *isl_schedule_tree_replace_child( + __isl_take isl_schedule_tree *tree, int pos, + __isl_take isl_schedule_tree *new_child); +__isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice( + __isl_take isl_schedule_tree *tree, int pos, + __isl_take isl_schedule_tree *child); + +__isl_give isl_schedule_tree *isl_schedule_tree_reset_user( + __isl_take isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_align_params( + __isl_take isl_schedule_tree *tree, __isl_take isl_space *space); +__isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff( + __isl_take isl_schedule_tree *tree, + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_printer *isl_printer_print_schedule_tree( + __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree); +__isl_give isl_printer *isl_printer_print_schedule_tree_mark( + __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree, + int n_ancestor, int *child_pos); + +#endif Index: contrib/isl/isl_schedule_tree.c =================================================================== --- /dev/null +++ contrib/isl/isl_schedule_tree.c @@ -0,0 +1,2858 @@ +/* + * Copyright 2013-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * Copyright 2016 INRIA Paris + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12, + * CS 42112, 75589 Paris Cedex 12, France + */ + +#include +#include +#include +#include +#include + +#undef EL +#define EL isl_schedule_tree + +#include + +#undef BASE +#define BASE schedule_tree + +#include + +/* Is "tree" the leaf of a schedule tree? + */ +int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree) +{ + return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf; +} + +/* Create a new schedule tree of type "type". + * The caller is responsible for filling in the type specific fields and + * the children. + * + * By default, the single node tree does not have any anchored nodes. + * The caller is responsible for updating the anchored field if needed. + */ +static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx, + enum isl_schedule_node_type type) +{ + isl_schedule_tree *tree; + + if (type == isl_schedule_node_error) + return NULL; + + tree = isl_calloc_type(ctx, isl_schedule_tree); + if (!tree) + return NULL; + + tree->ref = 1; + tree->ctx = ctx; + isl_ctx_ref(ctx); + tree->type = type; + tree->anchored = 0; + + return tree; +} + +/* Return a fresh copy of "tree". + */ +__isl_take isl_schedule_tree *isl_schedule_tree_dup( + __isl_keep isl_schedule_tree *tree) +{ + isl_ctx *ctx; + isl_schedule_tree *dup; + + if (!tree) + return NULL; + + ctx = isl_schedule_tree_get_ctx(tree); + dup = isl_schedule_tree_alloc(ctx, tree->type); + if (!dup) + return NULL; + + switch (tree->type) { + case isl_schedule_node_error: + isl_die(ctx, isl_error_internal, + "allocation should have failed", + return isl_schedule_tree_free(dup)); + case isl_schedule_node_band: + dup->band = isl_schedule_band_copy(tree->band); + if (!dup->band) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_context: + dup->context = isl_set_copy(tree->context); + if (!dup->context) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_domain: + dup->domain = isl_union_set_copy(tree->domain); + if (!dup->domain) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_expansion: + dup->contraction = + isl_union_pw_multi_aff_copy(tree->contraction); + dup->expansion = isl_union_map_copy(tree->expansion); + if (!dup->contraction || !dup->expansion) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_extension: + dup->extension = isl_union_map_copy(tree->extension); + if (!dup->extension) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_filter: + dup->filter = isl_union_set_copy(tree->filter); + if (!dup->filter) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_guard: + dup->guard = isl_set_copy(tree->guard); + if (!dup->guard) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_mark: + dup->mark = isl_id_copy(tree->mark); + if (!dup->mark) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_leaf: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + } + + if (tree->children) { + dup->children = isl_schedule_tree_list_copy(tree->children); + if (!dup->children) + return isl_schedule_tree_free(dup); + } + dup->anchored = tree->anchored; + + return dup; +} + +/* Return an isl_schedule_tree that is equal to "tree" and that has only + * a single reference. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_cow( + __isl_take isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->ref == 1) + return tree; + tree->ref--; + return isl_schedule_tree_dup(tree); +} + +/* Return a new reference to "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_copy( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + tree->ref++; + return tree; +} + +/* Free "tree" and return NULL. + */ +__isl_null isl_schedule_tree *isl_schedule_tree_free( + __isl_take isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + if (--tree->ref > 0) + return NULL; + + switch (tree->type) { + case isl_schedule_node_band: + isl_schedule_band_free(tree->band); + break; + case isl_schedule_node_context: + isl_set_free(tree->context); + break; + case isl_schedule_node_domain: + isl_union_set_free(tree->domain); + break; + case isl_schedule_node_expansion: + isl_union_pw_multi_aff_free(tree->contraction); + isl_union_map_free(tree->expansion); + break; + case isl_schedule_node_extension: + isl_union_map_free(tree->extension); + break; + case isl_schedule_node_filter: + isl_union_set_free(tree->filter); + break; + case isl_schedule_node_guard: + isl_set_free(tree->guard); + break; + case isl_schedule_node_mark: + isl_id_free(tree->mark); + break; + case isl_schedule_node_sequence: + case isl_schedule_node_set: + case isl_schedule_node_error: + case isl_schedule_node_leaf: + break; + } + isl_schedule_tree_list_free(tree->children); + isl_ctx_deref(tree->ctx); + free(tree); + + return NULL; +} + +/* Create and return a new leaf schedule tree. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx) +{ + return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf); +} + +/* Create a new band schedule tree referring to "band" + * with no children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_band( + __isl_take isl_schedule_band *band) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!band) + return NULL; + + ctx = isl_schedule_band_get_ctx(band); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band); + if (!tree) + goto error; + + tree->band = band; + tree->anchored = isl_schedule_band_is_anchored(band); + + return tree; +error: + isl_schedule_band_free(band); + return NULL; +} + +/* Create a new context schedule tree with the given context and no children. + * Since the context references the outer schedule dimension, + * the tree is anchored. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_context( + __isl_take isl_set *context) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!context) + return NULL; + + ctx = isl_set_get_ctx(context); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context); + if (!tree) + goto error; + + tree->context = context; + tree->anchored = 1; + + return tree; +error: + isl_set_free(context); + return NULL; +} + +/* Create a new domain schedule tree with the given domain and no children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_domain( + __isl_take isl_union_set *domain) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!domain) + return NULL; + + ctx = isl_union_set_get_ctx(domain); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain); + if (!tree) + goto error; + + tree->domain = domain; + + return tree; +error: + isl_union_set_free(domain); + return NULL; +} + +/* Create a new expansion schedule tree with the given contraction and + * expansion and no children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_expansion( + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!contraction || !expansion) + goto error; + + ctx = isl_union_map_get_ctx(expansion); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion); + if (!tree) + goto error; + + tree->contraction = contraction; + tree->expansion = expansion; + + return tree; +error: + isl_union_pw_multi_aff_free(contraction); + isl_union_map_free(expansion); + return NULL; +} + +/* Create a new extension schedule tree with the given extension and + * no children. + * Since the domain of the extension refers to the outer schedule dimension, + * the tree is anchored. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_extension( + __isl_take isl_union_map *extension) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!extension) + return NULL; + + ctx = isl_union_map_get_ctx(extension); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension); + if (!tree) + goto error; + + tree->extension = extension; + tree->anchored = 1; + + return tree; +error: + isl_union_map_free(extension); + return NULL; +} + +/* Create a new filter schedule tree with the given filter and no children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_filter( + __isl_take isl_union_set *filter) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!filter) + return NULL; + + ctx = isl_union_set_get_ctx(filter); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter); + if (!tree) + goto error; + + tree->filter = filter; + + return tree; +error: + isl_union_set_free(filter); + return NULL; +} + +/* Create a new guard schedule tree with the given guard and no children. + * Since the guard references the outer schedule dimension, + * the tree is anchored. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_guard( + __isl_take isl_set *guard) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!guard) + return NULL; + + ctx = isl_set_get_ctx(guard); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard); + if (!tree) + goto error; + + tree->guard = guard; + tree->anchored = 1; + + return tree; +error: + isl_set_free(guard); + return NULL; +} + +/* Create a new mark schedule tree with the given mark identifier and + * no children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_mark( + __isl_take isl_id *mark) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!mark) + return NULL; + + ctx = isl_id_get_ctx(mark); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark); + if (!tree) + goto error; + + tree->mark = mark; + + return tree; +error: + isl_id_free(mark); + return NULL; +} + +/* Does "tree" have any node that depends on its position + * in the complete schedule tree? + */ +isl_bool isl_schedule_tree_is_subtree_anchored( + __isl_keep isl_schedule_tree *tree) +{ + return tree ? tree->anchored : isl_bool_error; +} + +/* Does the root node of "tree" depend on its position in the complete + * schedule tree? + * Band nodes may be anchored depending on the associated AST build options. + * Context, extension and guard nodes are always anchored. + */ +int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return -1; + + switch (isl_schedule_tree_get_type(tree)) { + case isl_schedule_node_error: + return -1; + case isl_schedule_node_band: + return isl_schedule_band_is_anchored(tree->band); + case isl_schedule_node_context: + case isl_schedule_node_extension: + case isl_schedule_node_guard: + return 1; + case isl_schedule_node_domain: + case isl_schedule_node_expansion: + case isl_schedule_node_filter: + case isl_schedule_node_leaf: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + return 0; + } + + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "unhandled case", return -1); +} + +/* Update the anchored field of "tree" based on whether the root node + * itself in anchored and the anchored fields of the children. + * + * This function should be called whenever the children of a tree node + * are changed or the anchoredness of the tree root itself changes. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_update_anchored( + __isl_take isl_schedule_tree *tree) +{ + int i, n; + int anchored; + + if (!tree) + return NULL; + + anchored = isl_schedule_tree_is_anchored(tree); + if (anchored < 0) + return isl_schedule_tree_free(tree); + + n = isl_schedule_tree_list_n_schedule_tree(tree->children); + for (i = 0; !anchored && i < n; ++i) { + isl_schedule_tree *child; + + child = isl_schedule_tree_get_child(tree, i); + if (!child) + return isl_schedule_tree_free(tree); + anchored = child->anchored; + isl_schedule_tree_free(child); + } + + if (anchored == tree->anchored) + return tree; + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + tree->anchored = anchored; + return tree; +} + +/* Create a new tree of the given type (isl_schedule_node_sequence or + * isl_schedule_node_set) with the given children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_children( + enum isl_schedule_node_type type, + __isl_take isl_schedule_tree_list *list) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!list) + return NULL; + + ctx = isl_schedule_tree_list_get_ctx(list); + tree = isl_schedule_tree_alloc(ctx, type); + if (!tree) + goto error; + + tree->children = list; + tree = isl_schedule_tree_update_anchored(tree); + + return tree; +error: + isl_schedule_tree_list_free(list); + return NULL; +} + +/* Construct a tree with a root node of type "type" and as children + * "tree1" and "tree2". + * If the root of one (or both) of the input trees is itself of type "type", + * then the tree is replaced by its children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_pair( + enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2) +{ + isl_ctx *ctx; + isl_schedule_tree_list *list; + + if (!tree1 || !tree2) + goto error; + + ctx = isl_schedule_tree_get_ctx(tree1); + if (isl_schedule_tree_get_type(tree1) == type) { + list = isl_schedule_tree_list_copy(tree1->children); + isl_schedule_tree_free(tree1); + } else { + list = isl_schedule_tree_list_alloc(ctx, 2); + list = isl_schedule_tree_list_add(list, tree1); + } + if (isl_schedule_tree_get_type(tree2) == type) { + isl_schedule_tree_list *children; + + children = isl_schedule_tree_list_copy(tree2->children); + list = isl_schedule_tree_list_concat(list, children); + isl_schedule_tree_free(tree2); + } else { + list = isl_schedule_tree_list_add(list, tree2); + } + + return isl_schedule_tree_from_children(type, list); +error: + isl_schedule_tree_free(tree1); + isl_schedule_tree_free(tree2); + return NULL; +} + +/* Construct a tree with a sequence root node and as children + * "tree1" and "tree2". + * If the root of one (or both) of the input trees is itself a sequence, + * then the tree is replaced by its children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair( + __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2) +{ + return isl_schedule_tree_from_pair(isl_schedule_node_sequence, + tree1, tree2); +} + +/* Construct a tree with a set root node and as children + * "tree1" and "tree2". + * If the root of one (or both) of the input trees is itself a set, + * then the tree is replaced by its children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_set_pair( + __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2) +{ + return isl_schedule_tree_from_pair(isl_schedule_node_set, tree1, tree2); +} + +/* Return the isl_ctx to which "tree" belongs. + */ +isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree) +{ + return tree ? tree->ctx : NULL; +} + +/* Return the type of the root of the tree or isl_schedule_node_error + * on error. + */ +enum isl_schedule_node_type isl_schedule_tree_get_type( + __isl_keep isl_schedule_tree *tree) +{ + return tree ? tree->type : isl_schedule_node_error; +} + +/* Are "tree1" and "tree2" obviously equal to each other? + */ +isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1, + __isl_keep isl_schedule_tree *tree2) +{ + isl_bool equal; + int i, n; + + if (!tree1 || !tree2) + return isl_bool_error; + if (tree1 == tree2) + return isl_bool_true; + if (tree1->type != tree2->type) + return isl_bool_false; + + switch (tree1->type) { + case isl_schedule_node_band: + equal = isl_schedule_band_plain_is_equal(tree1->band, + tree2->band); + break; + case isl_schedule_node_context: + equal = isl_set_is_equal(tree1->context, tree2->context); + break; + case isl_schedule_node_domain: + equal = isl_union_set_is_equal(tree1->domain, tree2->domain); + break; + case isl_schedule_node_expansion: + equal = isl_union_map_is_equal(tree1->expansion, + tree2->expansion); + if (equal >= 0 && equal) + equal = isl_union_pw_multi_aff_plain_is_equal( + tree1->contraction, tree2->contraction); + break; + case isl_schedule_node_extension: + equal = isl_union_map_is_equal(tree1->extension, + tree2->extension); + break; + case isl_schedule_node_filter: + equal = isl_union_set_is_equal(tree1->filter, tree2->filter); + break; + case isl_schedule_node_guard: + equal = isl_set_is_equal(tree1->guard, tree2->guard); + break; + case isl_schedule_node_mark: + equal = tree1->mark == tree2->mark; + break; + case isl_schedule_node_leaf: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + equal = isl_bool_true; + break; + case isl_schedule_node_error: + equal = isl_bool_error; + break; + } + + if (equal < 0 || !equal) + return equal; + + n = isl_schedule_tree_n_children(tree1); + if (n != isl_schedule_tree_n_children(tree2)) + return isl_bool_false; + for (i = 0; i < n; ++i) { + isl_schedule_tree *child1, *child2; + + child1 = isl_schedule_tree_get_child(tree1, i); + child2 = isl_schedule_tree_get_child(tree2, i); + equal = isl_schedule_tree_plain_is_equal(child1, child2); + isl_schedule_tree_free(child1); + isl_schedule_tree_free(child2); + + if (equal < 0 || !equal) + return equal; + } + + return isl_bool_true; +} + +/* Does "tree" have any children, other than an implicit leaf. + */ +int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return -1; + + return tree->children != NULL; +} + +/* Return the number of children of "tree", excluding implicit leaves. + */ +int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return -1; + + return isl_schedule_tree_list_n_schedule_tree(tree->children); +} + +/* Return a copy of the (explicit) child at position "pos" of "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_get_child( + __isl_keep isl_schedule_tree *tree, int pos) +{ + if (!tree) + return NULL; + if (!tree->children) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "schedule tree has no explicit children", return NULL); + return isl_schedule_tree_list_get_schedule_tree(tree->children, pos); +} + +/* Return a copy of the (explicit) child at position "pos" of "tree" and + * free "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_child( + __isl_take isl_schedule_tree *tree, int pos) +{ + isl_schedule_tree *child; + + child = isl_schedule_tree_get_child(tree, pos); + isl_schedule_tree_free(tree); + return child; +} + +/* Remove all (explicit) children from "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_reset_children( + __isl_take isl_schedule_tree *tree) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + tree->children = isl_schedule_tree_list_free(tree->children); + return tree; +} + +/* Remove the child at position "pos" from the children of "tree". + * If there was only one child to begin with, then remove all children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_drop_child( + __isl_take isl_schedule_tree *tree, int pos) +{ + int n; + + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + + if (!isl_schedule_tree_has_children(tree)) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "tree does not have any explicit children", + return isl_schedule_tree_free(tree)); + n = isl_schedule_tree_list_n_schedule_tree(tree->children); + if (pos < 0 || pos >= n) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "position out of bounds", + return isl_schedule_tree_free(tree)); + if (n == 1) + return isl_schedule_tree_reset_children(tree); + + tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1); + if (!tree->children) + return isl_schedule_tree_free(tree); + + return tree; +} + +/* Replace the child at position "pos" of "tree" by "child". + * + * If the new child is a leaf, then it is not explicitly + * recorded in the list of children. Instead, the list of children + * (which is assumed to have only one element) is removed. + * Note that the children of set and sequence nodes are always + * filters, so they cannot be replaced by empty trees. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_replace_child( + __isl_take isl_schedule_tree *tree, int pos, + __isl_take isl_schedule_tree *child) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !child) + goto error; + + if (isl_schedule_tree_is_leaf(child)) { + isl_schedule_tree_free(child); + if (!tree->children && pos == 0) + return tree; + if (isl_schedule_tree_n_children(tree) != 1) + isl_die(isl_schedule_tree_get_ctx(tree), + isl_error_internal, + "can only replace single child by leaf", + goto error); + return isl_schedule_tree_reset_children(tree); + } + + if (!tree->children && pos == 0) + tree->children = + isl_schedule_tree_list_from_schedule_tree(child); + else + tree->children = isl_schedule_tree_list_set_schedule_tree( + tree->children, pos, child); + + if (!tree->children) + return isl_schedule_tree_free(tree); + tree = isl_schedule_tree_update_anchored(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_schedule_tree_free(child); + return NULL; +} + +/* Replace the (explicit) children of "tree" by "children"? + */ +__isl_give isl_schedule_tree *isl_schedule_tree_set_children( + __isl_take isl_schedule_tree *tree, + __isl_take isl_schedule_tree_list *children) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !children) + goto error; + isl_schedule_tree_list_free(tree->children); + tree->children = children; + return tree; +error: + isl_schedule_tree_free(tree); + isl_schedule_tree_list_free(children); + return NULL; +} + +/* Create a new band schedule tree referring to "band" + * with "tree" as single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_band( + __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_band(band); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Create a new context schedule tree with the given context and + * with "tree" as single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_context( + __isl_take isl_schedule_tree *tree, __isl_take isl_set *context) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_context(context); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Create a new domain schedule tree with the given domain and + * with "tree" as single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_domain(domain); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Create a new expansion schedule tree with the given contraction and + * expansion and with "tree" as single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion( + __isl_take isl_schedule_tree *tree, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_expansion(contraction, expansion); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Create a new extension schedule tree with the given extension and + * with "tree" as single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_extension( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_extension(extension); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Create a new filter schedule tree with the given filter and single child. + * + * If the root of "tree" is itself a filter node, then the two + * filter nodes are merged into one node. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter) +{ + isl_schedule_tree *res; + + if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) { + isl_union_set *tree_filter; + + tree_filter = isl_schedule_tree_filter_get_filter(tree); + tree_filter = isl_union_set_intersect(tree_filter, filter); + tree = isl_schedule_tree_filter_set_filter(tree, tree_filter); + return tree; + } + + res = isl_schedule_tree_from_filter(filter); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Insert a filter node with filter set "filter" + * in each of the children of "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter) +{ + int i, n; + + if (!tree || !filter) + goto error; + + n = isl_schedule_tree_n_children(tree); + for (i = 0; i < n; ++i) { + isl_schedule_tree *child; + + child = isl_schedule_tree_get_child(tree, i); + child = isl_schedule_tree_insert_filter(child, + isl_union_set_copy(filter)); + tree = isl_schedule_tree_replace_child(tree, i, child); + } + + isl_union_set_free(filter); + return tree; +error: + isl_union_set_free(filter); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Create a new guard schedule tree with the given guard and + * with "tree" as single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_guard( + __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_guard(guard); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Create a new mark schedule tree with the given mark identifier and + * single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_mark( + __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_mark(mark); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Return the number of members in the band tree root. + */ +unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return 0; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return 0); + + return isl_schedule_band_n_member(tree->band); +} + +/* Is the band member at position "pos" of the band tree root + * marked coincident? + */ +isl_bool isl_schedule_tree_band_member_get_coincident( + __isl_keep isl_schedule_tree *tree, int pos) +{ + if (!tree) + return isl_bool_error; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_bool_error); + + return isl_schedule_band_member_get_coincident(tree->band, pos); +} + +/* Mark the given band member as being coincident or not + * according to "coincident". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident( + __isl_take isl_schedule_tree *tree, int pos, int coincident) +{ + if (!tree) + return NULL; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_schedule_tree_free(tree)); + if (isl_schedule_tree_band_member_get_coincident(tree, pos) == + coincident) + return tree; + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + + tree->band = isl_schedule_band_member_set_coincident(tree->band, pos, + coincident); + if (!tree->band) + return isl_schedule_tree_free(tree); + return tree; +} + +/* Is the band tree root marked permutable? + */ +isl_bool isl_schedule_tree_band_get_permutable( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return isl_bool_error; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_bool_error); + + return isl_schedule_band_get_permutable(tree->band); +} + +/* Mark the band tree root permutable or not according to "permutable"? + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable( + __isl_take isl_schedule_tree *tree, int permutable) +{ + if (!tree) + return NULL; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_schedule_tree_free(tree)); + if (isl_schedule_tree_band_get_permutable(tree) == permutable) + return tree; + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + + tree->band = isl_schedule_band_set_permutable(tree->band, permutable); + if (!tree->band) + return isl_schedule_tree_free(tree); + return tree; +} + +/* Return the schedule space of the band tree root. + */ +__isl_give isl_space *isl_schedule_tree_band_get_space( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return NULL); + + return isl_schedule_band_get_space(tree->band); +} + +/* Intersect the domain of the band schedule of the band tree root + * with "domain". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain) +{ + if (!tree || !domain) + goto error; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + tree->band = isl_schedule_band_intersect_domain(tree->band, domain); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_set_free(domain); + return NULL; +} + +/* Return the schedule of the band tree root in isolation. + */ +__isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return NULL); + + return isl_schedule_band_get_partial_schedule(tree->band); +} + +/* Replace the schedule of the band tree root by "schedule". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule( + __isl_take isl_schedule_tree *tree, + __isl_take isl_multi_union_pw_aff *schedule) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !schedule) + goto error; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return NULL); + tree->band = isl_schedule_band_set_partial_schedule(tree->band, + schedule); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_multi_union_pw_aff_free(schedule); + return NULL; +} + +/* Return the loop AST generation type for the band member + * of the band tree root at position "pos". + */ +enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type( + __isl_keep isl_schedule_tree *tree, int pos) +{ + if (!tree) + return isl_ast_loop_error; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_ast_loop_error); + + return isl_schedule_band_member_get_ast_loop_type(tree->band, pos); +} + +/* Set the loop AST generation type for the band member of the band tree root + * at position "pos" to "type". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type( + __isl_take isl_schedule_tree *tree, int pos, + enum isl_ast_loop_type type) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_schedule_tree_free(tree)); + + tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band, + pos, type); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +} + +/* Return the loop AST generation type for the band member + * of the band tree root at position "pos" for the isolated part. + */ +enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type( + __isl_keep isl_schedule_tree *tree, int pos) +{ + if (!tree) + return isl_ast_loop_error; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_ast_loop_error); + + return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band, + pos); +} + +/* Set the loop AST generation type for the band member of the band tree root + * at position "pos" for the isolated part to "type". + */ +__isl_give isl_schedule_tree * +isl_schedule_tree_band_member_set_isolate_ast_loop_type( + __isl_take isl_schedule_tree *tree, int pos, + enum isl_ast_loop_type type) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_schedule_tree_free(tree)); + + tree->band = isl_schedule_band_member_set_isolate_ast_loop_type( + tree->band, pos, type); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +} + +/* Return the AST build options associated to the band tree root. + */ +__isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return NULL); + + return isl_schedule_band_get_ast_build_options(tree->band); +} + +/* Replace the AST build options associated to band tree root by "options". + * Updated the anchored field if the anchoredness of the root node itself + * changes. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options) +{ + int was_anchored; + + tree = isl_schedule_tree_cow(tree); + if (!tree || !options) + goto error; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + was_anchored = isl_schedule_tree_is_anchored(tree); + tree->band = isl_schedule_band_set_ast_build_options(tree->band, + options); + if (!tree->band) + return isl_schedule_tree_free(tree); + if (isl_schedule_tree_is_anchored(tree) != was_anchored) + tree = isl_schedule_tree_update_anchored(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_set_free(options); + return NULL; +} + +/* Return the "isolate" option associated to the band tree root of "tree", + * which is assumed to appear at schedule depth "depth". + */ +__isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option( + __isl_keep isl_schedule_tree *tree, int depth) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return NULL); + + return isl_schedule_band_get_ast_isolate_option(tree->band, depth); +} + +/* Return the context of the context tree root. + */ +__isl_give isl_set *isl_schedule_tree_context_get_context( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_context) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a context node", return NULL); + + return isl_set_copy(tree->context); +} + +/* Return the domain of the domain tree root. + */ +__isl_give isl_union_set *isl_schedule_tree_domain_get_domain( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_domain) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a domain node", return NULL); + + return isl_union_set_copy(tree->domain); +} + +/* Replace the domain of domain tree root "tree" by "domain". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !domain) + goto error; + + if (tree->type != isl_schedule_node_domain) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a domain node", goto error); + + isl_union_set_free(tree->domain); + tree->domain = domain; + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_set_free(domain); + return NULL; +} + +/* Return the contraction of the expansion tree root. + */ +__isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_expansion) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not an expansion node", return NULL); + + return isl_union_pw_multi_aff_copy(tree->contraction); +} + +/* Return the expansion of the expansion tree root. + */ +__isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_expansion) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not an expansion node", return NULL); + + return isl_union_map_copy(tree->expansion); +} + +/* Replace the contraction and the expansion of the expansion tree root "tree" + * by "contraction" and "expansion". + */ +__isl_give isl_schedule_tree * +isl_schedule_tree_expansion_set_contraction_and_expansion( + __isl_take isl_schedule_tree *tree, + __isl_take isl_union_pw_multi_aff *contraction, + __isl_take isl_union_map *expansion) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !contraction || !expansion) + goto error; + + if (tree->type != isl_schedule_node_expansion) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not an expansion node", return NULL); + + isl_union_pw_multi_aff_free(tree->contraction); + tree->contraction = contraction; + isl_union_map_free(tree->expansion); + tree->expansion = expansion; + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_pw_multi_aff_free(contraction); + isl_union_map_free(expansion); + return NULL; +} + +/* Return the extension of the extension tree root. + */ +__isl_give isl_union_map *isl_schedule_tree_extension_get_extension( + __isl_take isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_extension) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not an extension node", return NULL); + + return isl_union_map_copy(tree->extension); +} + +/* Replace the extension of extension tree root "tree" by "extension". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !extension) + goto error; + + if (tree->type != isl_schedule_node_extension) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not an extension node", return NULL); + isl_union_map_free(tree->extension); + tree->extension = extension; + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_map_free(extension); + return NULL; +} + +/* Return the filter of the filter tree root. + */ +__isl_give isl_union_set *isl_schedule_tree_filter_get_filter( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_filter) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a filter node", return NULL); + + return isl_union_set_copy(tree->filter); +} + +/* Replace the filter of the filter tree root by "filter". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !filter) + goto error; + + if (tree->type != isl_schedule_node_filter) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a filter node", return NULL); + + isl_union_set_free(tree->filter); + tree->filter = filter; + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_set_free(filter); + return NULL; +} + +/* Return the guard of the guard tree root. + */ +__isl_give isl_set *isl_schedule_tree_guard_get_guard( + __isl_take isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_guard) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a guard node", return NULL); + + return isl_set_copy(tree->guard); +} + +/* Return the mark identifier of the mark tree root "tree". + */ +__isl_give isl_id *isl_schedule_tree_mark_get_id( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_mark) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a mark node", return NULL); + + return isl_id_copy(tree->mark); +} + +/* Set dim to the range dimension of "map" and abort the search. + */ +static isl_stat set_range_dim(__isl_take isl_map *map, void *user) +{ + int *dim = user; + + *dim = isl_map_dim(map, isl_dim_out); + isl_map_free(map); + + return isl_stat_error; +} + +/* Return the dimension of the range of "umap". + * "umap" is assumed not to be empty and + * all maps inside "umap" are assumed to have the same range. + * + * We extract the range dimension from the first map in "umap". + */ +static int range_dim(__isl_keep isl_union_map *umap) +{ + int dim = -1; + + if (!umap) + return -1; + if (isl_union_map_n_map(umap) == 0) + isl_die(isl_union_map_get_ctx(umap), isl_error_internal, + "unexpected empty input", return -1); + + isl_union_map_foreach_map(umap, &set_range_dim, &dim); + + return dim; +} + +/* Append an "extra" number of zeros to the range of "umap" and + * return the result. + */ +static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap, + int extra) +{ + isl_union_set *dom; + isl_space *space; + isl_multi_val *mv; + isl_union_pw_multi_aff *suffix; + isl_union_map *universe; + isl_union_map *suffix_umap; + + universe = isl_union_map_universe(isl_union_map_copy(umap)); + dom = isl_union_map_domain(universe); + space = isl_union_set_get_space(dom); + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, extra); + mv = isl_multi_val_zero(space); + + suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv); + suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix); + umap = isl_union_map_flat_range_product(umap, suffix_umap); + + return umap; +} + +/* Should we skip the root of "tree" while looking for the first + * descendant with schedule information? + * That is, is it impossible to derive any information about + * the iteration domain from this node? + * + * We do not want to skip leaf or error nodes because there is + * no point in looking any deeper from these nodes. + * We can only extract partial iteration domain information + * from an extension node, but extension nodes are not supported + * by the caller and it will error out on them. + */ +static int domain_less(__isl_keep isl_schedule_tree *tree) +{ + enum isl_schedule_node_type type; + + type = isl_schedule_tree_get_type(tree); + switch (type) { + case isl_schedule_node_band: + return isl_schedule_tree_band_n_member(tree) == 0; + case isl_schedule_node_context: + case isl_schedule_node_guard: + case isl_schedule_node_mark: + return 1; + case isl_schedule_node_leaf: + case isl_schedule_node_error: + case isl_schedule_node_domain: + case isl_schedule_node_expansion: + case isl_schedule_node_extension: + case isl_schedule_node_filter: + case isl_schedule_node_set: + case isl_schedule_node_sequence: + return 0; + } + + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "unhandled case", return 0); +} + +/* Move down to the first descendant of "tree" that contains any schedule + * information or return "leaf" if there is no such descendant. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf) +{ + while (domain_less(tree)) { + if (!isl_schedule_tree_has_children(tree)) { + isl_schedule_tree_free(tree); + return isl_schedule_tree_copy(leaf); + } + tree = isl_schedule_tree_child(tree, 0); + } + + return tree; +} + +static __isl_give isl_union_map *subtree_schedule_extend( + __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer); + +/* Extend the schedule map "outer" with the subtree schedule + * of the (single) child of "tree", if any. + * + * If "tree" does not have any descendants (apart from those that + * do not carry any schedule information), then we simply return "outer". + * Otherwise, we extend the schedule map "outer" with the subtree schedule + * of the single child. + */ +static __isl_give isl_union_map *subtree_schedule_extend_child( + __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) +{ + isl_schedule_tree *child; + isl_union_map *res; + + if (!tree) + return isl_union_map_free(outer); + if (!isl_schedule_tree_has_children(tree)) + return outer; + child = isl_schedule_tree_get_child(tree, 0); + if (!child) + return isl_union_map_free(outer); + res = subtree_schedule_extend(child, outer); + isl_schedule_tree_free(child); + return res; +} + +/* Extract the parameter space from one of the children of "tree", + * which are assumed to be filters. + */ +static __isl_give isl_space *extract_space_from_filter_child( + __isl_keep isl_schedule_tree *tree) +{ + isl_space *space; + isl_union_set *dom; + isl_schedule_tree *child; + + child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0); + dom = isl_schedule_tree_filter_get_filter(child); + space = isl_union_set_get_space(dom); + isl_union_set_free(dom); + isl_schedule_tree_free(child); + + return space; +} + +/* Extend the schedule map "outer" with the subtree schedule + * of a set or sequence node. + * + * The schedule for the set or sequence node itself is composed of + * pieces of the form + * + * filter -> [] + * + * or + * + * filter -> [index] + * + * The first form is used if there is only a single child or + * if the current node is a set node and the schedule_separate_components + * option is not set. + * + * Each of the pieces above is extended with the subtree schedule of + * the child of the corresponding filter, if any, padded with zeros + * to ensure that all pieces have the same range dimension. + */ +static __isl_give isl_union_map *subtree_schedule_extend_from_children( + __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) +{ + int i, n; + int dim; + int separate; + isl_ctx *ctx; + isl_val *v = NULL; + isl_multi_val *mv; + isl_space *space; + isl_union_map *umap; + + if (!tree) + return NULL; + + ctx = isl_schedule_tree_get_ctx(tree); + if (!tree->children) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "missing children", return NULL); + n = isl_schedule_tree_list_n_schedule_tree(tree->children); + if (n == 0) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "missing children", return NULL); + + separate = n > 1 && (tree->type == isl_schedule_node_sequence || + isl_options_get_schedule_separate_components(ctx)); + + space = extract_space_from_filter_child(tree); + + umap = isl_union_map_empty(isl_space_copy(space)); + space = isl_space_set_from_params(space); + if (separate) { + space = isl_space_add_dims(space, isl_dim_set, 1); + v = isl_val_zero(ctx); + } + mv = isl_multi_val_zero(space); + + dim = isl_multi_val_dim(mv, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_union_pw_multi_aff *upma; + isl_union_map *umap_i; + isl_union_set *dom; + isl_schedule_tree *child; + int dim_i; + int empty; + + child = isl_schedule_tree_list_get_schedule_tree( + tree->children, i); + dom = isl_schedule_tree_filter_get_filter(child); + + if (separate) { + mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v)); + v = isl_val_add_ui(v, 1); + } + upma = isl_union_pw_multi_aff_multi_val_on_domain(dom, + isl_multi_val_copy(mv)); + umap_i = isl_union_map_from_union_pw_multi_aff(upma); + umap_i = isl_union_map_flat_range_product( + isl_union_map_copy(outer), umap_i); + umap_i = subtree_schedule_extend_child(child, umap_i); + isl_schedule_tree_free(child); + + empty = isl_union_map_is_empty(umap_i); + if (empty < 0) + umap_i = isl_union_map_free(umap_i); + else if (empty) { + isl_union_map_free(umap_i); + continue; + } + + dim_i = range_dim(umap_i); + if (dim_i < 0) { + umap = isl_union_map_free(umap); + } else if (dim < dim_i) { + umap = append_range(umap, dim_i - dim); + dim = dim_i; + } else if (dim_i < dim) { + umap_i = append_range(umap_i, dim - dim_i); + } + umap = isl_union_map_union(umap, umap_i); + } + + isl_val_free(v); + isl_multi_val_free(mv); + isl_union_map_free(outer); + + return umap; +} + +/* Extend the schedule map "outer" with the subtree schedule of "tree". + * + * If the root of the tree is a set or a sequence, then we extend + * the schedule map in subtree_schedule_extend_from_children. + * Otherwise, we extend the schedule map with the partial schedule + * corresponding to the root of the tree and then continue with + * the single child of this root. + * In the special case of an expansion, the schedule map is "extended" + * by applying the expansion to the domain of the schedule map. + */ +static __isl_give isl_union_map *subtree_schedule_extend( + __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) +{ + isl_multi_union_pw_aff *mupa; + isl_union_map *umap; + isl_union_set *domain; + + if (!tree) + return NULL; + + switch (tree->type) { + case isl_schedule_node_error: + return isl_union_map_free(outer); + case isl_schedule_node_extension: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "cannot construct subtree schedule of tree " + "with extension nodes", + return isl_union_map_free(outer)); + case isl_schedule_node_context: + case isl_schedule_node_guard: + case isl_schedule_node_mark: + return subtree_schedule_extend_child(tree, outer); + case isl_schedule_node_band: + if (isl_schedule_tree_band_n_member(tree) == 0) + return subtree_schedule_extend_child(tree, outer); + mupa = isl_schedule_band_get_partial_schedule(tree->band); + umap = isl_union_map_from_multi_union_pw_aff(mupa); + outer = isl_union_map_flat_range_product(outer, umap); + umap = subtree_schedule_extend_child(tree, outer); + break; + case isl_schedule_node_domain: + domain = isl_schedule_tree_domain_get_domain(tree); + umap = isl_union_map_from_domain(domain); + outer = isl_union_map_flat_range_product(outer, umap); + umap = subtree_schedule_extend_child(tree, outer); + break; + case isl_schedule_node_expansion: + umap = isl_schedule_tree_expansion_get_expansion(tree); + outer = isl_union_map_apply_domain(outer, umap); + umap = subtree_schedule_extend_child(tree, outer); + break; + case isl_schedule_node_filter: + domain = isl_schedule_tree_filter_get_filter(tree); + umap = isl_union_map_from_domain(domain); + outer = isl_union_map_flat_range_product(outer, umap); + umap = subtree_schedule_extend_child(tree, outer); + break; + case isl_schedule_node_leaf: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "leaf node should be handled by caller", return NULL); + case isl_schedule_node_set: + case isl_schedule_node_sequence: + umap = subtree_schedule_extend_from_children(tree, outer); + break; + } + + return umap; +} + +static __isl_give isl_union_set *initial_domain( + __isl_keep isl_schedule_tree *tree); + +/* Extract a universe domain from the children of the tree root "tree", + * which is a set or sequence, meaning that its children are filters. + * In particular, return the union of the universes of the filters. + */ +static __isl_give isl_union_set *initial_domain_from_children( + __isl_keep isl_schedule_tree *tree) +{ + int i, n; + isl_space *space; + isl_union_set *domain; + + if (!tree->children) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "missing children", return NULL); + n = isl_schedule_tree_list_n_schedule_tree(tree->children); + if (n == 0) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "missing children", return NULL); + + space = extract_space_from_filter_child(tree); + domain = isl_union_set_empty(space); + + for (i = 0; i < n; ++i) { + isl_schedule_tree *child; + isl_union_set *domain_i; + + child = isl_schedule_tree_get_child(tree, i); + domain_i = initial_domain(child); + domain = isl_union_set_union(domain, domain_i); + isl_schedule_tree_free(child); + } + + return domain; +} + +/* Extract a universe domain from the tree root "tree". + * The caller is responsible for making sure that this node + * would not be skipped by isl_schedule_tree_first_schedule_descendant + * and that it is not a leaf node. + */ +static __isl_give isl_union_set *initial_domain( + __isl_keep isl_schedule_tree *tree) +{ + isl_multi_union_pw_aff *mupa; + isl_union_set *domain; + isl_union_map *exp; + + if (!tree) + return NULL; + + switch (tree->type) { + case isl_schedule_node_error: + return NULL; + case isl_schedule_node_context: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "context node should be handled by caller", + return NULL); + case isl_schedule_node_guard: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "guard node should be handled by caller", + return NULL); + case isl_schedule_node_mark: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "mark node should be handled by caller", + return NULL); + case isl_schedule_node_extension: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "cannot construct subtree schedule of tree " + "with extension nodes", return NULL); + case isl_schedule_node_band: + if (isl_schedule_tree_band_n_member(tree) == 0) + isl_die(isl_schedule_tree_get_ctx(tree), + isl_error_internal, + "0D band should be handled by caller", + return NULL); + mupa = isl_schedule_band_get_partial_schedule(tree->band); + domain = isl_multi_union_pw_aff_domain(mupa); + domain = isl_union_set_universe(domain); + break; + case isl_schedule_node_domain: + domain = isl_schedule_tree_domain_get_domain(tree); + domain = isl_union_set_universe(domain); + break; + case isl_schedule_node_expansion: + exp = isl_schedule_tree_expansion_get_expansion(tree); + exp = isl_union_map_universe(exp); + domain = isl_union_map_domain(exp); + break; + case isl_schedule_node_filter: + domain = isl_schedule_tree_filter_get_filter(tree); + domain = isl_union_set_universe(domain); + break; + case isl_schedule_node_leaf: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "leaf node should be handled by caller", return NULL); + case isl_schedule_node_set: + case isl_schedule_node_sequence: + domain = initial_domain_from_children(tree); + break; + } + + return domain; +} + +/* Return the subtree schedule of a node that contains some schedule + * information, i.e., a node that would not be skipped by + * isl_schedule_tree_first_schedule_descendant and that is not a leaf. + * + * If the tree contains any expansions, then the returned subtree + * schedule is formulated in terms of the expanded domains. + * The tree is not allowed to contain any extension nodes. + * + * We start with an initial zero-dimensional subtree schedule based + * on the domain information in the root node and then extend it + * based on the schedule information in the root node and its descendants. + */ +__isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map( + __isl_keep isl_schedule_tree *tree) +{ + isl_union_set *domain; + isl_union_map *umap; + + domain = initial_domain(tree); + umap = isl_union_map_from_domain(domain); + return subtree_schedule_extend(tree, umap); +} + +/* Multiply the partial schedule of the band root node of "tree" + * with the factors in "mv". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_scale( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv) +{ + if (!tree || !mv) + goto error; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + tree->band = isl_schedule_band_scale(tree->band, mv); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_multi_val_free(mv); + return NULL; +} + +/* Divide the partial schedule of the band root node of "tree" + * by the factors in "mv". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv) +{ + if (!tree || !mv) + goto error; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + tree->band = isl_schedule_band_scale_down(tree->band, mv); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_multi_val_free(mv); + return NULL; +} + +/* Reduce the partial schedule of the band root node of "tree" + * modulo the factors in "mv". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_mod( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv) +{ + if (!tree || !mv) + goto error; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + tree->band = isl_schedule_band_mod(tree->band, mv); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_multi_val_free(mv); + return NULL; +} + +/* Shift the partial schedule of the band root node of "tree" by "shift". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_shift( + __isl_take isl_schedule_tree *tree, + __isl_take isl_multi_union_pw_aff *shift) +{ + if (!tree || !shift) + goto error; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + tree->band = isl_schedule_band_shift(tree->band, shift); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_multi_union_pw_aff_free(shift); + return NULL; +} + +/* Given two trees with sequence roots, replace the child at position + * "pos" of "tree" with the children of "child". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice( + __isl_take isl_schedule_tree *tree, int pos, + __isl_take isl_schedule_tree *child) +{ + int n; + isl_schedule_tree_list *list1, *list2; + + tree = isl_schedule_tree_cow(tree); + if (!tree || !child) + goto error; + if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a sequence node", goto error); + n = isl_schedule_tree_n_children(tree); + if (pos < 0 || pos >= n) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "position out of bounds", goto error); + if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a sequence node", goto error); + + list1 = isl_schedule_tree_list_copy(tree->children); + list1 = isl_schedule_tree_list_drop(list1, pos, n - pos); + list2 = isl_schedule_tree_list_copy(tree->children); + list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1); + list1 = isl_schedule_tree_list_concat(list1, + isl_schedule_tree_list_copy(child->children)); + list1 = isl_schedule_tree_list_concat(list1, list2); + + isl_schedule_tree_free(tree); + isl_schedule_tree_free(child); + return isl_schedule_tree_from_children(isl_schedule_node_sequence, + list1); +error: + isl_schedule_tree_free(tree); + isl_schedule_tree_free(child); + return NULL; +} + +/* Tile the band root node of "tree" with tile sizes "sizes". + * + * We duplicate the band node, change the schedule of one of them + * to the tile schedule and the other to the point schedule and then + * attach the point band as a child to the tile band. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_tile( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes) +{ + isl_schedule_tree *child = NULL; + + if (!tree || !sizes) + goto error; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + child = isl_schedule_tree_copy(tree); + tree = isl_schedule_tree_cow(tree); + child = isl_schedule_tree_cow(child); + if (!tree || !child) + goto error; + + tree->band = isl_schedule_band_tile(tree->band, + isl_multi_val_copy(sizes)); + if (!tree->band) + goto error; + child->band = isl_schedule_band_point(child->band, tree->band, sizes); + if (!child->band) + child = isl_schedule_tree_free(child); + + tree = isl_schedule_tree_replace_child(tree, 0, child); + + return tree; +error: + isl_schedule_tree_free(child); + isl_schedule_tree_free(tree); + isl_multi_val_free(sizes); + return NULL; +} + +/* Given an isolate AST generation option "isolate" for a band of size pos + n, + * return the corresponding option for a band covering the first "pos" + * members. + * + * The input isolate option is of the form + * + * isolate[[flattened outer bands] -> [pos; n]] + * + * The output isolate option is of the form + * + * isolate[[flattened outer bands] -> [pos]] + */ +static __isl_give isl_set *isolate_initial(__isl_keep isl_set *isolate, + int pos, int n) +{ + isl_id *id; + isl_map *map; + + isolate = isl_set_copy(isolate); + id = isl_set_get_tuple_id(isolate); + map = isl_set_unwrap(isolate); + map = isl_map_project_out(map, isl_dim_out, pos, n); + isolate = isl_map_wrap(map); + isolate = isl_set_set_tuple_id(isolate, id); + + return isolate; +} + +/* Given an isolate AST generation option "isolate" for a band of size pos + n, + * return the corresponding option for a band covering the final "n" + * members within a band covering the first "pos" members. + * + * The input isolate option is of the form + * + * isolate[[flattened outer bands] -> [pos; n]] + * + * The output isolate option is of the form + * + * isolate[[flattened outer bands; pos] -> [n]] + * + * + * The range is first split into + * + * isolate[[flattened outer bands] -> [[pos] -> [n]]] + * + * and then the first pos members are moved to the domain + * + * isolate[[[flattened outer bands] -> [pos]] -> [n]] + * + * after which the domain is flattened to obtain the desired output. + */ +static __isl_give isl_set *isolate_final(__isl_keep isl_set *isolate, + int pos, int n) +{ + isl_id *id; + isl_space *space; + isl_multi_aff *ma1, *ma2; + isl_map *map; + + isolate = isl_set_copy(isolate); + id = isl_set_get_tuple_id(isolate); + map = isl_set_unwrap(isolate); + space = isl_space_range(isl_map_get_space(map)); + ma1 = isl_multi_aff_project_out_map(isl_space_copy(space), + isl_dim_set, pos, n); + ma2 = isl_multi_aff_project_out_map(space, isl_dim_set, 0, pos); + ma1 = isl_multi_aff_range_product(ma1, ma2); + map = isl_map_apply_range(map, isl_map_from_multi_aff(ma1)); + map = isl_map_uncurry(map); + map = isl_map_flatten_domain(map); + isolate = isl_map_wrap(map); + isolate = isl_set_set_tuple_id(isolate, id); + + return isolate; +} + +/* Split the band root node of "tree" into two nested band nodes, + * one with the first "pos" dimensions and + * one with the remaining dimensions. + * The tree is itself positioned at schedule depth "depth". + * + * The loop AST generation type options and the isolate option + * are split over the two band nodes. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_split( + __isl_take isl_schedule_tree *tree, int pos, int depth) +{ + int n; + isl_set *isolate, *tree_isolate, *child_isolate; + isl_schedule_tree *child; + + if (!tree) + return NULL; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_schedule_tree_free(tree)); + + n = isl_schedule_tree_band_n_member(tree); + if (pos < 0 || pos > n) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "position out of bounds", + return isl_schedule_tree_free(tree)); + + child = isl_schedule_tree_copy(tree); + tree = isl_schedule_tree_cow(tree); + child = isl_schedule_tree_cow(child); + if (!tree || !child) + goto error; + + isolate = isl_schedule_tree_band_get_ast_isolate_option(tree, depth); + tree_isolate = isolate_initial(isolate, pos, n - pos); + child_isolate = isolate_final(isolate, pos, n - pos); + child->band = isl_schedule_band_drop(child->band, 0, pos); + child->band = isl_schedule_band_replace_ast_build_option(child->band, + isl_set_copy(isolate), child_isolate); + tree->band = isl_schedule_band_drop(tree->band, pos, n - pos); + tree->band = isl_schedule_band_replace_ast_build_option(tree->band, + isl_set_copy(isolate), tree_isolate); + isl_set_free(isolate); + if (!child->band || !tree->band) + goto error; + + tree = isl_schedule_tree_replace_child(tree, 0, child); + + return tree; +error: + isl_schedule_tree_free(child); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Attach "tree2" at each of the leaves of "tree1". + * + * If "tree1" does not have any explicit children, then make "tree2" + * its single child. Otherwise, attach "tree2" to the leaves of + * each of the children of "tree1". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves( + __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2) +{ + int i, n; + + if (!tree1 || !tree2) + goto error; + n = isl_schedule_tree_n_children(tree1); + if (n == 0) { + isl_schedule_tree_list *list; + list = isl_schedule_tree_list_from_schedule_tree(tree2); + tree1 = isl_schedule_tree_set_children(tree1, list); + return tree1; + } + for (i = 0; i < n; ++i) { + isl_schedule_tree *child; + + child = isl_schedule_tree_get_child(tree1, i); + child = isl_schedule_tree_append_to_leaves(child, + isl_schedule_tree_copy(tree2)); + tree1 = isl_schedule_tree_replace_child(tree1, i, child); + } + + isl_schedule_tree_free(tree2); + return tree1; +error: + isl_schedule_tree_free(tree1); + isl_schedule_tree_free(tree2); + return NULL; +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * in the root of "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_reset_user( + __isl_take isl_schedule_tree *tree) +{ + if (isl_schedule_tree_is_leaf(tree)) + return tree; + + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + + switch (tree->type) { + case isl_schedule_node_error: + return isl_schedule_tree_free(tree); + case isl_schedule_node_band: + tree->band = isl_schedule_band_reset_user(tree->band); + if (!tree->band) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_context: + tree->context = isl_set_reset_user(tree->context); + if (!tree->context) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_domain: + tree->domain = isl_union_set_reset_user(tree->domain); + if (!tree->domain) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_expansion: + tree->contraction = + isl_union_pw_multi_aff_reset_user(tree->contraction); + tree->expansion = isl_union_map_reset_user(tree->expansion); + if (!tree->contraction || !tree->expansion) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_extension: + tree->extension = isl_union_map_reset_user(tree->extension); + if (!tree->extension) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_filter: + tree->filter = isl_union_set_reset_user(tree->filter); + if (!tree->filter) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_guard: + tree->guard = isl_set_reset_user(tree->guard); + if (!tree->guard) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_leaf: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + } + + return tree; +} + +/* Align the parameters of the root of "tree" to those of "space". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_align_params( + __isl_take isl_schedule_tree *tree, __isl_take isl_space *space) +{ + if (!space) + goto error; + + if (isl_schedule_tree_is_leaf(tree)) { + isl_space_free(space); + return tree; + } + + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + switch (tree->type) { + case isl_schedule_node_error: + goto error; + case isl_schedule_node_band: + tree->band = isl_schedule_band_align_params(tree->band, space); + if (!tree->band) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_context: + tree->context = isl_set_align_params(tree->context, space); + if (!tree->context) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_domain: + tree->domain = isl_union_set_align_params(tree->domain, space); + if (!tree->domain) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_expansion: + tree->contraction = + isl_union_pw_multi_aff_align_params(tree->contraction, + isl_space_copy(space)); + tree->expansion = isl_union_map_align_params(tree->expansion, + space); + if (!tree->contraction || !tree->expansion) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_extension: + tree->extension = isl_union_map_align_params(tree->extension, + space); + if (!tree->extension) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_filter: + tree->filter = isl_union_set_align_params(tree->filter, space); + if (!tree->filter) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_guard: + tree->guard = isl_set_align_params(tree->guard, space); + if (!tree->guard) + return isl_schedule_tree_free(tree); + break; + case isl_schedule_node_leaf: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + isl_space_free(space); + break; + } + + return tree; +error: + isl_space_free(space); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Does "tree" involve the iteration domain? + * That is, does it need to be modified + * by isl_schedule_tree_pullback_union_pw_multi_aff? + */ +static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return -1; + + switch (tree->type) { + case isl_schedule_node_error: + return -1; + case isl_schedule_node_band: + case isl_schedule_node_domain: + case isl_schedule_node_expansion: + case isl_schedule_node_extension: + case isl_schedule_node_filter: + return 1; + case isl_schedule_node_context: + case isl_schedule_node_leaf: + case isl_schedule_node_guard: + case isl_schedule_node_mark: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + return 0; + } + + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "unhandled case", return -1); +} + +/* Compute the pullback of the root node of "tree" by the function + * represented by "upma". + * In other words, plug in "upma" in the iteration domains of + * the root node of "tree". + * We currently do not handle expansion nodes. + * + * We first check if the root node involves any iteration domains. + * If so, we handle the specific cases. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff( + __isl_take isl_schedule_tree *tree, + __isl_take isl_union_pw_multi_aff *upma) +{ + int involves; + + if (!tree || !upma) + goto error; + + involves = involves_iteration_domain(tree); + if (involves < 0) + goto error; + if (!involves) { + isl_union_pw_multi_aff_free(upma); + return tree; + } + + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + if (tree->type == isl_schedule_node_band) { + tree->band = isl_schedule_band_pullback_union_pw_multi_aff( + tree->band, upma); + if (!tree->band) + return isl_schedule_tree_free(tree); + } else if (tree->type == isl_schedule_node_domain) { + tree->domain = + isl_union_set_preimage_union_pw_multi_aff(tree->domain, + upma); + if (!tree->domain) + return isl_schedule_tree_free(tree); + } else if (tree->type == isl_schedule_node_expansion) { + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported, + "cannot pullback expansion node", goto error); + } else if (tree->type == isl_schedule_node_extension) { + tree->extension = + isl_union_map_preimage_range_union_pw_multi_aff( + tree->extension, upma); + if (!tree->extension) + return isl_schedule_tree_free(tree); + } else if (tree->type == isl_schedule_node_filter) { + tree->filter = + isl_union_set_preimage_union_pw_multi_aff(tree->filter, + upma); + if (!tree->filter) + return isl_schedule_tree_free(tree); + } + + return tree; +error: + isl_union_pw_multi_aff_free(upma); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Compute the gist of the band tree root with respect to "context". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_gist( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context) +{ + if (!tree) + return NULL; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + tree->band = isl_schedule_band_gist(tree->band, context); + if (!tree->band) + return isl_schedule_tree_free(tree); + return tree; +error: + isl_union_set_free(context); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Are any members in "band" marked coincident? + */ +static int any_coincident(__isl_keep isl_schedule_band *band) +{ + int i, n; + + n = isl_schedule_band_n_member(band); + for (i = 0; i < n; ++i) + if (isl_schedule_band_member_get_coincident(band, i)) + return 1; + + return 0; +} + +/* Print the band node "band" to "p". + * + * The permutable and coincident properties are only printed if they + * are different from the defaults. + * The coincident property is always printed in YAML flow style. + */ +static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p, + __isl_keep isl_schedule_band *band) +{ + isl_union_set *options; + int empty; + + p = isl_printer_print_str(p, "schedule"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_multi_union_pw_aff(p, band->mupa); + p = isl_printer_print_str(p, "\""); + if (isl_schedule_band_get_permutable(band)) { + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "permutable"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_int(p, 1); + } + if (any_coincident(band)) { + int i, n; + int style; + + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "coincident"); + p = isl_printer_yaml_next(p); + style = isl_printer_get_yaml_style(p); + p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW); + p = isl_printer_yaml_start_sequence(p); + n = isl_schedule_band_n_member(band); + for (i = 0; i < n; ++i) { + p = isl_printer_print_int(p, + isl_schedule_band_member_get_coincident(band, i)); + p = isl_printer_yaml_next(p); + } + p = isl_printer_yaml_end_sequence(p); + p = isl_printer_set_yaml_style(p, style); + } + options = isl_schedule_band_get_ast_build_options(band); + empty = isl_union_set_is_empty(options); + if (empty < 0) + p = isl_printer_free(p); + if (!empty) { + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "options"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_set(p, options); + p = isl_printer_print_str(p, "\""); + } + isl_union_set_free(options); + + return p; +} + +/* Print "tree" to "p". + * + * If "n_ancestor" is non-negative, then "child_pos" contains the child + * positions of a descendant of the current node that should be marked + * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor" + * is zero, then the current node should be marked. + * The marking is only printed in YAML block format. + * + * Implicit leaf nodes are not printed, except if they correspond + * to the node that should be marked. + */ +__isl_give isl_printer *isl_printer_print_schedule_tree_mark( + __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree, + int n_ancestor, int *child_pos) +{ + int i, n; + int sequence = 0; + int block; + + block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK; + + p = isl_printer_yaml_start_mapping(p); + if (n_ancestor == 0 && block) { + p = isl_printer_print_str(p, "# YOU ARE HERE"); + p = isl_printer_end_line(p); + p = isl_printer_start_line(p); + } + switch (tree->type) { + case isl_schedule_node_error: + p = isl_printer_print_str(p, "ERROR"); + break; + case isl_schedule_node_leaf: + p = isl_printer_print_str(p, "leaf"); + break; + case isl_schedule_node_sequence: + p = isl_printer_print_str(p, "sequence"); + sequence = 1; + break; + case isl_schedule_node_set: + p = isl_printer_print_str(p, "set"); + sequence = 1; + break; + case isl_schedule_node_context: + p = isl_printer_print_str(p, "context"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_set(p, tree->context); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_domain: + p = isl_printer_print_str(p, "domain"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_set(p, tree->domain); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_expansion: + p = isl_printer_print_str(p, "contraction"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_pw_multi_aff(p, tree->contraction); + p = isl_printer_print_str(p, "\""); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "expansion"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_map(p, tree->expansion); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_extension: + p = isl_printer_print_str(p, "extension"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_map(p, tree->extension); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_filter: + p = isl_printer_print_str(p, "filter"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_set(p, tree->filter); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_guard: + p = isl_printer_print_str(p, "guard"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_set(p, tree->guard); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_mark: + p = isl_printer_print_str(p, "mark"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_str(p, isl_id_get_name(tree->mark)); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_band: + p = print_tree_band(p, tree->band); + break; + } + p = isl_printer_yaml_next(p); + + if (!tree->children) { + if (n_ancestor > 0 && block) { + isl_schedule_tree *leaf; + + p = isl_printer_print_str(p, "child"); + p = isl_printer_yaml_next(p); + leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p)); + p = isl_printer_print_schedule_tree_mark(p, + leaf, 0, NULL); + isl_schedule_tree_free(leaf); + p = isl_printer_yaml_next(p); + } + return isl_printer_yaml_end_mapping(p); + } + + if (sequence) { + p = isl_printer_yaml_start_sequence(p); + } else { + p = isl_printer_print_str(p, "child"); + p = isl_printer_yaml_next(p); + } + + n = isl_schedule_tree_list_n_schedule_tree(tree->children); + for (i = 0; i < n; ++i) { + isl_schedule_tree *t; + + t = isl_schedule_tree_get_child(tree, i); + if (n_ancestor > 0 && child_pos[0] == i) + p = isl_printer_print_schedule_tree_mark(p, t, + n_ancestor - 1, child_pos + 1); + else + p = isl_printer_print_schedule_tree_mark(p, t, + -1, NULL); + isl_schedule_tree_free(t); + + p = isl_printer_yaml_next(p); + } + + if (sequence) + p = isl_printer_yaml_end_sequence(p); + p = isl_printer_yaml_end_mapping(p); + + return p; +} + +/* Print "tree" to "p". + */ +__isl_give isl_printer *isl_printer_print_schedule_tree( + __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree) +{ + return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL); +} + +void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree) +{ + isl_ctx *ctx; + isl_printer *printer; + + if (!tree) + return; + + ctx = isl_schedule_tree_get_ctx(tree); + printer = isl_printer_to_file(ctx, stderr); + printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK); + printer = isl_printer_print_schedule_tree(printer, tree); + + isl_printer_free(printer); +} Index: contrib/isl/isl_scheduler.c =================================================================== --- /dev/null +++ contrib/isl/isl_scheduler.c @@ -0,0 +1,7424 @@ +/* + * Copyright 2011 INRIA Saclay + * Copyright 2012-2014 Ecole Normale Superieure + * Copyright 2015-2016 Sven Verdoolaege + * Copyright 2016 INRIA Paris + * Copyright 2017 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12, + * CS 42112, 75589 Paris Cedex 12, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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". + * + * For a detailed description of the variant implemented in isl, + * see Verdoolaege and Janssens, "Scheduling for PPCG" (2017). + */ + + +/* Internal information about a node that is used during the construction + * of a schedule. + * space represents the original space in which the domain lives; + * that is, the space is not affected by compression + * sched is a matrix representation of the schedule being constructed + * for this node; if compressed is set, then this schedule is + * defined over the compressed domain space + * sched_map is an isl_map representation of the same (partial) schedule + * sched_map may be NULL; if compressed is set, then this map + * is defined over the uncompressed domain space + * rank is the number of linearly independent rows in the linear part + * of sched + * the rows of "vmap" represent a change of basis for the node + * variables; the first rank rows span the linear part of + * the schedule rows; the remaining rows are linearly independent + * the rows of "indep" represent linear combinations of the schedule + * coefficients that are non-zero when the schedule coefficients are + * linearly independent of previously computed 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 (compressed) domain + * nparam is the number of parameters or 0 if we are not constructing + * a parametric schedule + * + * If compressed is set, then hull represents the constraints + * that were used to derive the compression, while compress and + * decompress map the original space to the compressed space and + * vice versa. + * + * scc is the index of SCC (or WCC) this node belongs to + * + * "cluster" is only used inside extract_clusters and identifies + * the cluster of SCCs that the node belongs to. + * + * coincident contains a boolean for each of the rows of the schedule, + * indicating whether the corresponding scheduling dimension satisfies + * the coincidence constraints in the sense that the corresponding + * dependence distances are zero. + * + * If the schedule_treat_coalescing option is set, then + * "sizes" contains the sizes of the (compressed) instance set + * in each direction. If there is no fixed size in a given direction, + * then the corresponding size value is set to infinity. + * If the schedule_treat_coalescing option or the schedule_max_coefficient + * option is set, then "max" contains the maximal values for + * schedule coefficients of the (compressed) variables. If no bound + * needs to be imposed on a particular variable, then the corresponding + * value is negative. + * If not NULL, then "bounds" contains a non-parametric set + * in the compressed space that is bounded by the size in each direction. + */ +struct isl_sched_node { + isl_space *space; + int compressed; + isl_set *hull; + isl_multi_aff *compress; + isl_multi_aff *decompress; + isl_mat *sched; + isl_map *sched_map; + int rank; + isl_mat *indep; + isl_mat *vmap; + int start; + int nvar; + int nparam; + + int scc; + int cluster; + + int *coincident; + + isl_multi_val *sizes; + isl_basic_set *bounds; + isl_vec *max; +}; + +static int node_has_tuples(const void *entry, const void *val) +{ + struct isl_sched_node *node = (struct isl_sched_node *)entry; + isl_space *space = (isl_space *) val; + + return isl_space_has_equal_tuples(node->space, space); +} + +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; +} + +/* 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, with i -> j in the map if j depends on i + * tagged_condition and tagged_validity contain the union of all tagged + * condition or conditional validity dependence relations that + * specialize the dependence relation "map"; that is, + * if (i -> a) -> (j -> b) is an element of "tagged_condition" + * or "tagged_validity", then i -> j is an element of "map". + * If these fields are NULL, then they represent the empty relation. + * src is the source node + * dst is the sink node + * + * types is a bit vector containing the types of this edge. + * validity is set if the edge is used to ensure correctness + * coincidence is used to enforce zero dependence distances + * proximity is set if the edge is used to minimize dependence distances + * condition is set if the edge represents a condition + * for a conditional validity schedule constraint + * local can only be set for condition edges and indicates that + * the dependence distance over the edge should be zero + * conditional_validity is set if the edge is used to conditionally + * ensure correctness + * + * 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. + * + * During clustering, an edge may be marked "no_merge" if it should + * not be used to merge clusters. + * The weight is also only used during clustering and it is + * an indication of how many schedule dimensions on either side + * of the schedule constraints can be aligned. + * If the weight is negative, then this means that this edge was postponed + * by has_bounded_distances or any_no_merge. The original weight can + * be retrieved by adding 1 + graph->max_weight, with "graph" + * the graph containing this edge. + */ +struct isl_sched_edge { + isl_map *map; + isl_union_map *tagged_condition; + isl_union_map *tagged_validity; + + struct isl_sched_node *src; + struct isl_sched_node *dst; + + unsigned types; + + int start; + int end; + + int no_merge; + int weight; +}; + +/* Is "edge" marked as being of type "type"? + */ +static int is_type(struct isl_sched_edge *edge, enum isl_edge_type type) +{ + return ISL_FL_ISSET(edge->types, 1 << type); +} + +/* Mark "edge" as being of type "type". + */ +static void set_type(struct isl_sched_edge *edge, enum isl_edge_type type) +{ + ISL_FL_SET(edge->types, 1 << type); +} + +/* No longer mark "edge" as being of type "type"? + */ +static void clear_type(struct isl_sched_edge *edge, enum isl_edge_type type) +{ + ISL_FL_CLR(edge->types, 1 << type); +} + +/* Is "edge" marked as a validity edge? + */ +static int is_validity(struct isl_sched_edge *edge) +{ + return is_type(edge, isl_edge_validity); +} + +/* Mark "edge" as a validity edge. + */ +static void set_validity(struct isl_sched_edge *edge) +{ + set_type(edge, isl_edge_validity); +} + +/* Is "edge" marked as a proximity edge? + */ +static int is_proximity(struct isl_sched_edge *edge) +{ + return is_type(edge, isl_edge_proximity); +} + +/* Is "edge" marked as a local edge? + */ +static int is_local(struct isl_sched_edge *edge) +{ + return is_type(edge, isl_edge_local); +} + +/* Mark "edge" as a local edge. + */ +static void set_local(struct isl_sched_edge *edge) +{ + set_type(edge, isl_edge_local); +} + +/* No longer mark "edge" as a local edge. + */ +static void clear_local(struct isl_sched_edge *edge) +{ + clear_type(edge, isl_edge_local); +} + +/* Is "edge" marked as a coincidence edge? + */ +static int is_coincidence(struct isl_sched_edge *edge) +{ + return is_type(edge, isl_edge_coincidence); +} + +/* Is "edge" marked as a condition edge? + */ +static int is_condition(struct isl_sched_edge *edge) +{ + return is_type(edge, isl_edge_condition); +} + +/* Is "edge" marked as a conditional validity edge? + */ +static int is_conditional_validity(struct isl_sched_edge *edge) +{ + return is_type(edge, isl_edge_conditional_validity); +} + +/* Is "edge" of a type that can appear multiple times between + * the same pair of nodes? + * + * Condition edges and conditional validity edges may have tagged + * dependence relations, in which case an edge is added for each + * pair of tags. + */ +static int is_multi_edge_type(struct isl_sched_edge *edge) +{ + return is_condition(edge) || is_conditional_validity(edge); +} + +/* 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, possibly without + * coefficients for the parameters + * intra_hmap_param is a cache, mapping dependence relations to their dual, + * for dependences from a node to itself, including coefficients + * for the parameters + * inter_hmap is a cache, mapping dependence relations to their dual, + * for dependences between distinct nodes + * if compression is involved then the key for these maps + * is the original, uncompressed dependence relation, while + * the value is the dual of the compressed dependence relation. + * + * n is the number of nodes + * node is the list of nodes + * maxvar is the maximal number of variables over all nodes + * max_row is the allocated number of rows in the schedule + * 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 + * band_start is the starting row in the node schedules of the current band + * root is set to the original dependence graph from which this graph + * is derived through splitting. If this graph is not the result of + * splitting, then the root field points to the graph itself. + * + * 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 + * max_edge contains the maximal number of edges of each type; + * in particular, it contains the number of edges in the inital graph. + * edge_table contains pointers into the edge array, hashed on the source + * and sink spaces; there is one such table for each type; + * a given edge may be referenced from more than one table + * if the corresponding relation appears in more than one of the + * sets of dependences; however, for each type there is only + * a single edge between a given pair of source and sink space + * in the entire graph + * + * node_table contains pointers into the node array, hashed on the space tuples + * + * 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 represents the number of components + * weak is set if the components are weakly connected + * + * max_weight is used during clustering and represents the maximal + * weight of the relevant proximity edges. + */ +struct isl_sched_graph { + isl_map_to_basic_set *intra_hmap; + isl_map_to_basic_set *intra_hmap_param; + isl_map_to_basic_set *inter_hmap; + + struct isl_sched_node *node; + int n; + int maxvar; + int max_row; + int n_row; + + int *sorted; + + int n_total_row; + int band_start; + + struct isl_sched_graph *root; + + struct isl_sched_edge *edge; + int n_edge; + int max_edge[isl_edge_last + 1]; + struct isl_hash_table *edge_table[isl_edge_last + 1]; + + struct isl_hash_table *node_table; + struct isl_trivial_region *region; + + isl_basic_set *lp; + + int src_scc; + int dst_scc; + + int scc; + int weak; + + int max_weight; +}; + +/* 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_space_get_tuple_hash(graph->node[i].space); + entry = isl_hash_table_find(ctx, graph->node_table, hash, + &node_has_tuples, + graph->node[i].space, 1); + if (!entry) + return -1; + entry->data = &graph->node[i]; + } + + return 0; +} + +/* Return a pointer to the node that lives within the given space, + * an invalid node if there is no such node, or NULL in case of error. + */ +static struct isl_sched_node *graph_find_node(isl_ctx *ctx, + struct isl_sched_graph *graph, __isl_keep isl_space *space) +{ + struct isl_hash_table_entry *entry; + uint32_t hash; + + if (!space) + return NULL; + + hash = isl_space_get_tuple_hash(space); + entry = isl_hash_table_find(ctx, graph->node_table, hash, + &node_has_tuples, space, 0); + + return entry ? entry->data : graph->node + graph->n; +} + +/* Is "node" a node in "graph"? + */ +static int is_node(struct isl_sched_graph *graph, + struct isl_sched_node *node) +{ + return node && node >= &graph->node[0] && node < &graph->node[graph->n]; +} + +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; +} + +/* Add the given edge to graph->edge_table[type]. + */ +static isl_stat graph_edge_table_add(isl_ctx *ctx, + struct isl_sched_graph *graph, enum isl_edge_type type, + struct isl_sched_edge *edge) +{ + struct isl_hash_table_entry *entry; + uint32_t hash; + + hash = isl_hash_init(); + hash = isl_hash_builtin(hash, edge->src); + hash = isl_hash_builtin(hash, edge->dst); + entry = isl_hash_table_find(ctx, graph->edge_table[type], hash, + &edge_has_src_and_dst, edge, 1); + if (!entry) + return isl_stat_error; + entry->data = edge; + + return isl_stat_ok; +} + +/* Add "edge" to all relevant edge tables. + * That is, for every type of the edge, add it to the corresponding table. + */ +static isl_stat graph_edge_tables_add(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_sched_edge *edge) +{ + enum isl_edge_type t; + + for (t = isl_edge_first; t <= isl_edge_last; ++t) { + if (!is_type(edge, t)) + continue; + if (graph_edge_table_add(ctx, graph, t, edge) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Allocate the edge_tables based on the maximal number of edges of + * each type. + */ +static int graph_init_edge_tables(isl_ctx *ctx, struct isl_sched_graph *graph) +{ + int i; + + for (i = 0; i <= isl_edge_last; ++i) { + graph->edge_table[i] = isl_hash_table_alloc(ctx, + graph->max_edge[i]); + if (!graph->edge_table[i]) + return -1; + } + + return 0; +} + +/* If graph->edge_table[type] contains an edge from the given source + * to the given destination, then return the hash table entry of this edge. + * Otherwise, return NULL. + */ +static struct isl_hash_table_entry *graph_find_edge_entry( + struct isl_sched_graph *graph, + enum isl_edge_type type, + struct isl_sched_node *src, struct isl_sched_node *dst) +{ + isl_ctx *ctx = isl_space_get_ctx(src->space); + uint32_t hash; + struct isl_sched_edge temp = { .src = src, .dst = dst }; + + hash = isl_hash_init(); + hash = isl_hash_builtin(hash, temp.src); + hash = isl_hash_builtin(hash, temp.dst); + return isl_hash_table_find(ctx, graph->edge_table[type], hash, + &edge_has_src_and_dst, &temp, 0); +} + + +/* If graph->edge_table[type] contains an edge from the given source + * to the given destination, then return this edge. + * Otherwise, return NULL. + */ +static struct isl_sched_edge *graph_find_edge(struct isl_sched_graph *graph, + enum isl_edge_type type, + struct isl_sched_node *src, struct isl_sched_node *dst) +{ + struct isl_hash_table_entry *entry; + + entry = graph_find_edge_entry(graph, type, src, dst); + if (!entry) + return NULL; + + return entry->data; +} + +/* Check whether the dependence graph has an edge of the given type + * between the given two nodes. + */ +static isl_bool graph_has_edge(struct isl_sched_graph *graph, + enum isl_edge_type type, + struct isl_sched_node *src, struct isl_sched_node *dst) +{ + struct isl_sched_edge *edge; + isl_bool empty; + + edge = graph_find_edge(graph, type, src, dst); + if (!edge) + return 0; + + empty = isl_map_plain_is_empty(edge->map); + if (empty < 0) + return isl_bool_error; + + return !empty; +} + +/* Look for any edge with the same src, dst and map fields as "model". + * + * Return the matching edge if one can be found. + * Return "model" if no matching edge is found. + * Return NULL on error. + */ +static struct isl_sched_edge *graph_find_matching_edge( + struct isl_sched_graph *graph, struct isl_sched_edge *model) +{ + enum isl_edge_type i; + struct isl_sched_edge *edge; + + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + int is_equal; + + edge = graph_find_edge(graph, i, model->src, model->dst); + if (!edge) + continue; + is_equal = isl_map_plain_is_equal(model->map, edge->map); + if (is_equal < 0) + return NULL; + if (is_equal) + return edge; + } + + return model; +} + +/* Remove the given edge from all the edge_tables that refer to it. + */ +static void graph_remove_edge(struct isl_sched_graph *graph, + struct isl_sched_edge *edge) +{ + isl_ctx *ctx = isl_map_get_ctx(edge->map); + enum isl_edge_type i; + + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + struct isl_hash_table_entry *entry; + + entry = graph_find_edge_entry(graph, i, edge->src, edge->dst); + if (!entry) + continue; + if (entry->data != edge) + continue; + isl_hash_table_remove(ctx, graph->edge_table[i], entry); + } +} + +/* Check whether the dependence graph has any edge + * between the given two nodes. + */ +static isl_bool graph_has_any_edge(struct isl_sched_graph *graph, + struct isl_sched_node *src, struct isl_sched_node *dst) +{ + enum isl_edge_type i; + isl_bool r; + + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + r = graph_has_edge(graph, i, src, dst); + if (r < 0 || r) + return r; + } + + return r; +} + +/* Check whether the dependence graph has a validity edge + * between the given two nodes. + * + * Conditional validity edges are essentially validity edges that + * can be ignored if the corresponding condition edges are iteration private. + * Here, we are only checking for the presence of validity + * edges, so we need to consider the conditional validity edges too. + * In particular, this function is used during the detection + * of strongly connected components and we cannot ignore + * conditional validity edges during this detection. + */ +static isl_bool graph_has_validity_edge(struct isl_sched_graph *graph, + struct isl_sched_node *src, struct isl_sched_node *dst) +{ + isl_bool r; + + r = graph_has_edge(graph, isl_edge_validity, src, dst); + if (r < 0 || r) + return r; + + return graph_has_edge(graph, isl_edge_conditional_validity, src, dst); +} + +/* Perform all the required memory allocations for a schedule graph "graph" + * with "n_node" nodes and "n_edge" edge and initialize the corresponding + * fields. + */ +static isl_stat 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_trivial_region, graph->n); + graph->edge = isl_calloc_array(ctx, + struct isl_sched_edge, graph->n_edge); + + graph->intra_hmap = isl_map_to_basic_set_alloc(ctx, 2 * n_edge); + graph->intra_hmap_param = isl_map_to_basic_set_alloc(ctx, 2 * n_edge); + graph->inter_hmap = isl_map_to_basic_set_alloc(ctx, 2 * n_edge); + + if (!graph->node || !graph->region || (graph->n_edge && !graph->edge) || + !graph->sorted) + return isl_stat_error; + + for(i = 0; i < graph->n; ++i) + graph->sorted[i] = i; + + return isl_stat_ok; +} + +/* Free the memory associated to node "node" in "graph". + * The "coincident" field is shared by nodes in a graph and its subgraph. + * It therefore only needs to be freed for the original dependence graph, + * i.e., one that is not the result of splitting. + */ +static void clear_node(struct isl_sched_graph *graph, + struct isl_sched_node *node) +{ + isl_space_free(node->space); + isl_set_free(node->hull); + isl_multi_aff_free(node->compress); + isl_multi_aff_free(node->decompress); + isl_mat_free(node->sched); + isl_map_free(node->sched_map); + isl_mat_free(node->indep); + isl_mat_free(node->vmap); + if (graph->root == graph) + free(node->coincident); + isl_multi_val_free(node->sizes); + isl_basic_set_free(node->bounds); + isl_vec_free(node->max); +} + +static void graph_free(isl_ctx *ctx, struct isl_sched_graph *graph) +{ + int i; + + isl_map_to_basic_set_free(graph->intra_hmap); + isl_map_to_basic_set_free(graph->intra_hmap_param); + isl_map_to_basic_set_free(graph->inter_hmap); + + if (graph->node) + for (i = 0; i < graph->n; ++i) + clear_node(graph, &graph->node[i]); + free(graph->node); + free(graph->sorted); + if (graph->edge) + for (i = 0; i < graph->n_edge; ++i) { + isl_map_free(graph->edge[i].map); + isl_union_map_free(graph->edge[i].tagged_condition); + isl_union_map_free(graph->edge[i].tagged_validity); + } + free(graph->edge); + free(graph->region); + for (i = 0; i <= isl_edge_last; ++i) + isl_hash_table_free(ctx, graph->edge_table[i]); + isl_hash_table_free(ctx, graph->node_table); + isl_basic_set_free(graph->lp); +} + +/* For each "set" on which this function is called, increment + * graph->n by one and update graph->maxvar. + */ +static isl_stat init_n_maxvar(__isl_take isl_set *set, void *user) +{ + struct isl_sched_graph *graph = user; + int nvar = isl_set_dim(set, isl_dim_set); + + graph->n++; + if (nvar > graph->maxvar) + graph->maxvar = nvar; + + isl_set_free(set); + + return isl_stat_ok; +} + +/* Compute the number of rows that should be allocated for the schedule. + * In particular, we need one row for each variable or one row + * for each basic map in the dependences. + * Note that it is practically impossible to exhaust both + * the number of dependences and the number of variables. + */ +static isl_stat compute_max_row(struct isl_sched_graph *graph, + __isl_keep isl_schedule_constraints *sc) +{ + int n_edge; + isl_stat r; + isl_union_set *domain; + + graph->n = 0; + graph->maxvar = 0; + domain = isl_schedule_constraints_get_domain(sc); + r = isl_union_set_foreach_set(domain, &init_n_maxvar, graph); + isl_union_set_free(domain); + if (r < 0) + return isl_stat_error; + n_edge = isl_schedule_constraints_n_basic_map(sc); + if (n_edge < 0) + return isl_stat_error; + graph->max_row = n_edge + graph->maxvar; + + return isl_stat_ok; +} + +/* Does "bset" have any defining equalities for its set variables? + */ +static isl_bool has_any_defining_equality(__isl_keep isl_basic_set *bset) +{ + int i, n; + + if (!bset) + return isl_bool_error; + + n = isl_basic_set_dim(bset, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_bool has; + + has = isl_basic_set_has_defining_equality(bset, isl_dim_set, i, + NULL); + if (has < 0 || has) + return has; + } + + return isl_bool_false; +} + +/* Set the entries of node->max to the value of the schedule_max_coefficient + * option, if set. + */ +static isl_stat set_max_coefficient(isl_ctx *ctx, struct isl_sched_node *node) +{ + int max; + + max = isl_options_get_schedule_max_coefficient(ctx); + if (max == -1) + return isl_stat_ok; + + node->max = isl_vec_alloc(ctx, node->nvar); + node->max = isl_vec_set_si(node->max, max); + if (!node->max) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Set the entries of node->max to the minimum of the schedule_max_coefficient + * option (if set) and half of the minimum of the sizes in the other + * dimensions. Round up when computing the half such that + * if the minimum of the sizes is one, half of the size is taken to be one + * rather than zero. + * If the global minimum is unbounded (i.e., if both + * the schedule_max_coefficient is not set and the sizes in the other + * dimensions are unbounded), then store a negative value. + * If the schedule coefficient is close to the size of the instance set + * in another dimension, then the schedule may represent a loop + * coalescing transformation (especially if the coefficient + * in that other dimension is one). Forcing the coefficient to be + * smaller than or equal to half the minimal size should avoid this + * situation. + */ +static isl_stat compute_max_coefficient(isl_ctx *ctx, + struct isl_sched_node *node) +{ + int max; + int i, j; + isl_vec *v; + + max = isl_options_get_schedule_max_coefficient(ctx); + v = isl_vec_alloc(ctx, node->nvar); + if (!v) + return isl_stat_error; + + for (i = 0; i < node->nvar; ++i) { + isl_int_set_si(v->el[i], max); + isl_int_mul_si(v->el[i], v->el[i], 2); + } + + for (i = 0; i < node->nvar; ++i) { + isl_val *size; + + size = isl_multi_val_get_val(node->sizes, i); + if (!size) + goto error; + if (!isl_val_is_int(size)) { + isl_val_free(size); + continue; + } + for (j = 0; j < node->nvar; ++j) { + if (j == i) + continue; + if (isl_int_is_neg(v->el[j]) || + isl_int_gt(v->el[j], size->n)) + isl_int_set(v->el[j], size->n); + } + isl_val_free(size); + } + + for (i = 0; i < node->nvar; ++i) + isl_int_cdiv_q_ui(v->el[i], v->el[i], 2); + + node->max = v; + return isl_stat_ok; +error: + isl_vec_free(v); + return isl_stat_error; +} + +/* Compute and return the size of "set" in dimension "dim". + * The size is taken to be the difference in values for that variable + * for fixed values of the other variables. + * This assumes that "set" is convex. + * In particular, the variable is first isolated from the other variables + * in the range of a map + * + * [i_0, ..., i_dim-1, i_dim+1, ...] -> [i_dim] + * + * and then duplicated + * + * [i_0, ..., i_dim-1, i_dim+1, ...] -> [[i_dim] -> [i_dim']] + * + * The shared variables are then projected out and the maximal value + * of i_dim' - i_dim is computed. + */ +static __isl_give isl_val *compute_size(__isl_take isl_set *set, int dim) +{ + isl_map *map; + isl_local_space *ls; + isl_aff *obj; + isl_val *v; + + map = isl_set_project_onto_map(set, isl_dim_set, dim, 1); + map = isl_map_project_out(map, isl_dim_in, dim, 1); + map = isl_map_range_product(map, isl_map_copy(map)); + map = isl_set_unwrap(isl_map_range(map)); + set = isl_map_deltas(map); + ls = isl_local_space_from_space(isl_set_get_space(set)); + obj = isl_aff_var_on_domain(ls, isl_dim_set, 0); + v = isl_set_max_val(set, obj); + isl_aff_free(obj); + isl_set_free(set); + + return v; +} + +/* Compute the size of the instance set "set" of "node", after compression, + * as well as bounds on the corresponding coefficients, if needed. + * + * The sizes are needed when the schedule_treat_coalescing option is set. + * The bounds are needed when the schedule_treat_coalescing option or + * the schedule_max_coefficient option is set. + * + * If the schedule_treat_coalescing option is not set, then at most + * the bounds need to be set and this is done in set_max_coefficient. + * Otherwise, compress the domain if needed, compute the size + * in each direction and store the results in node->size. + * If the domain is not convex, then the sizes are computed + * on a convex superset in order to avoid picking up sizes + * that are valid for the individual disjuncts, but not for + * the domain as a whole. + * Finally, set the bounds on the coefficients based on the sizes + * and the schedule_max_coefficient option in compute_max_coefficient. + */ +static isl_stat compute_sizes_and_max(isl_ctx *ctx, struct isl_sched_node *node, + __isl_take isl_set *set) +{ + int j, n; + isl_multi_val *mv; + + if (!isl_options_get_schedule_treat_coalescing(ctx)) { + isl_set_free(set); + return set_max_coefficient(ctx, node); + } + + if (node->compressed) + set = isl_set_preimage_multi_aff(set, + isl_multi_aff_copy(node->decompress)); + set = isl_set_from_basic_set(isl_set_simple_hull(set)); + mv = isl_multi_val_zero(isl_set_get_space(set)); + n = isl_set_dim(set, isl_dim_set); + for (j = 0; j < n; ++j) { + isl_val *v; + + v = compute_size(isl_set_copy(set), j); + mv = isl_multi_val_set_val(mv, j, v); + } + node->sizes = mv; + isl_set_free(set); + if (!node->sizes) + return isl_stat_error; + return compute_max_coefficient(ctx, node); +} + +/* Add a new node to the graph representing the given instance set. + * "nvar" is the (possibly compressed) number of variables and + * may be smaller than then number of set variables in "set" + * if "compressed" is set. + * If "compressed" is set, then "hull" represents the constraints + * that were used to derive the compression, while "compress" and + * "decompress" map the original space to the compressed space and + * vice versa. + * If "compressed" is not set, then "hull", "compress" and "decompress" + * should be NULL. + * + * Compute the size of the instance set and bounds on the coefficients, + * if needed. + */ +static isl_stat add_node(struct isl_sched_graph *graph, + __isl_take isl_set *set, int nvar, int compressed, + __isl_take isl_set *hull, __isl_take isl_multi_aff *compress, + __isl_take isl_multi_aff *decompress) +{ + int nparam; + isl_ctx *ctx; + isl_mat *sched; + isl_space *space; + int *coincident; + struct isl_sched_node *node; + + if (!set) + return isl_stat_error; + + ctx = isl_set_get_ctx(set); + nparam = isl_set_dim(set, isl_dim_param); + if (!ctx->opt->schedule_parametric) + nparam = 0; + sched = isl_mat_alloc(ctx, 0, 1 + nparam + nvar); + node = &graph->node[graph->n]; + graph->n++; + space = isl_set_get_space(set); + node->space = space; + node->nvar = nvar; + node->nparam = nparam; + node->sched = sched; + node->sched_map = NULL; + coincident = isl_calloc_array(ctx, int, graph->max_row); + node->coincident = coincident; + node->compressed = compressed; + node->hull = hull; + node->compress = compress; + node->decompress = decompress; + if (compute_sizes_and_max(ctx, node, set) < 0) + return isl_stat_error; + + if (!space || !sched || (graph->max_row && !coincident)) + return isl_stat_error; + if (compressed && (!hull || !compress || !decompress)) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Construct an identifier for node "node", which will represent "set". + * The name of the identifier is either "compressed" or + * "compressed_", with the name of the space of "set". + * The user pointer of the identifier points to "node". + */ +static __isl_give isl_id *construct_compressed_id(__isl_keep isl_set *set, + struct isl_sched_node *node) +{ + isl_bool has_name; + isl_ctx *ctx; + isl_id *id; + isl_printer *p; + const char *name; + char *id_name; + + has_name = isl_set_has_tuple_name(set); + if (has_name < 0) + return NULL; + + ctx = isl_set_get_ctx(set); + if (!has_name) + return isl_id_alloc(ctx, "compressed", node); + + p = isl_printer_to_str(ctx); + name = isl_set_get_tuple_name(set); + p = isl_printer_print_str(p, "compressed_"); + p = isl_printer_print_str(p, name); + id_name = isl_printer_get_str(p); + isl_printer_free(p); + + id = isl_id_alloc(ctx, id_name, node); + free(id_name); + + return id; +} + +/* Add a new node to the graph representing the given set. + * + * If any of the set variables is defined by an equality, then + * we perform variable compression such that we can perform + * the scheduling on the compressed domain. + * In this case, an identifier is used that references the new node + * such that each compressed space is unique and + * such that the node can be recovered from the compressed space. + */ +static isl_stat extract_node(__isl_take isl_set *set, void *user) +{ + int nvar; + isl_bool has_equality; + isl_id *id; + isl_basic_set *hull; + isl_set *hull_set; + isl_morph *morph; + isl_multi_aff *compress, *decompress; + struct isl_sched_graph *graph = user; + + hull = isl_set_affine_hull(isl_set_copy(set)); + hull = isl_basic_set_remove_divs(hull); + nvar = isl_set_dim(set, isl_dim_set); + has_equality = has_any_defining_equality(hull); + + if (has_equality < 0) + goto error; + if (!has_equality) { + isl_basic_set_free(hull); + return add_node(graph, set, nvar, 0, NULL, NULL, NULL); + } + + id = construct_compressed_id(set, &graph->node[graph->n]); + morph = isl_basic_set_variable_compression_with_id(hull, + isl_dim_set, id); + isl_id_free(id); + nvar = isl_morph_ran_dim(morph, isl_dim_set); + compress = isl_morph_get_var_multi_aff(morph); + morph = isl_morph_inverse(morph); + decompress = isl_morph_get_var_multi_aff(morph); + isl_morph_free(morph); + + hull_set = isl_set_from_basic_set(hull); + return add_node(graph, set, nvar, 1, hull_set, compress, decompress); +error: + isl_basic_set_free(hull); + isl_set_free(set); + return isl_stat_error; +} + +struct isl_extract_edge_data { + enum isl_edge_type type; + struct isl_sched_graph *graph; +}; + +/* Merge edge2 into edge1, freeing the contents of edge2. + * Return 0 on success and -1 on failure. + * + * edge1 and edge2 are assumed to have the same value for the map field. + */ +static int merge_edge(struct isl_sched_edge *edge1, + struct isl_sched_edge *edge2) +{ + edge1->types |= edge2->types; + isl_map_free(edge2->map); + + if (is_condition(edge2)) { + if (!edge1->tagged_condition) + edge1->tagged_condition = edge2->tagged_condition; + else + edge1->tagged_condition = + isl_union_map_union(edge1->tagged_condition, + edge2->tagged_condition); + } + + if (is_conditional_validity(edge2)) { + if (!edge1->tagged_validity) + edge1->tagged_validity = edge2->tagged_validity; + else + edge1->tagged_validity = + isl_union_map_union(edge1->tagged_validity, + edge2->tagged_validity); + } + + if (is_condition(edge2) && !edge1->tagged_condition) + return -1; + if (is_conditional_validity(edge2) && !edge1->tagged_validity) + return -1; + + return 0; +} + +/* Insert dummy tags in domain and range of "map". + * + * In particular, if "map" is of the form + * + * A -> B + * + * then return + * + * [A -> dummy_tag] -> [B -> dummy_tag] + * + * where the dummy_tags are identical and equal to any dummy tags + * introduced by any other call to this function. + */ +static __isl_give isl_map *insert_dummy_tags(__isl_take isl_map *map) +{ + static char dummy; + isl_ctx *ctx; + isl_id *id; + isl_space *space; + isl_set *domain, *range; + + ctx = isl_map_get_ctx(map); + + id = isl_id_alloc(ctx, NULL, &dummy); + space = isl_space_params(isl_map_get_space(map)); + space = isl_space_set_from_params(space); + space = isl_space_set_tuple_id(space, isl_dim_set, id); + space = isl_space_map_from_set(space); + + domain = isl_map_wrap(map); + range = isl_map_wrap(isl_map_universe(space)); + map = isl_map_from_domain_and_range(domain, range); + map = isl_map_zip(map); + + return map; +} + +/* Given that at least one of "src" or "dst" is compressed, return + * a map between the spaces of these nodes restricted to the affine + * hull that was used in the compression. + */ +static __isl_give isl_map *extract_hull(struct isl_sched_node *src, + struct isl_sched_node *dst) +{ + isl_set *dom, *ran; + + if (src->compressed) + dom = isl_set_copy(src->hull); + else + dom = isl_set_universe(isl_space_copy(src->space)); + if (dst->compressed) + ran = isl_set_copy(dst->hull); + else + ran = isl_set_universe(isl_space_copy(dst->space)); + + return isl_map_from_domain_and_range(dom, ran); +} + +/* Intersect the domains of the nested relations in domain and range + * of "tagged" with "map". + */ +static __isl_give isl_map *map_intersect_domains(__isl_take isl_map *tagged, + __isl_keep isl_map *map) +{ + isl_set *set; + + tagged = isl_map_zip(tagged); + set = isl_map_wrap(isl_map_copy(map)); + tagged = isl_map_intersect_domain(tagged, set); + tagged = isl_map_zip(tagged); + return tagged; +} + +/* Return a pointer to the node that lives in the domain space of "map", + * an invalid node if there is no such node, or NULL in case of error. + */ +static struct isl_sched_node *find_domain_node(isl_ctx *ctx, + struct isl_sched_graph *graph, __isl_keep isl_map *map) +{ + struct isl_sched_node *node; + isl_space *space; + + space = isl_space_domain(isl_map_get_space(map)); + node = graph_find_node(ctx, graph, space); + isl_space_free(space); + + return node; +} + +/* Return a pointer to the node that lives in the range space of "map", + * an invalid node if there is no such node, or NULL in case of error. + */ +static struct isl_sched_node *find_range_node(isl_ctx *ctx, + struct isl_sched_graph *graph, __isl_keep isl_map *map) +{ + struct isl_sched_node *node; + isl_space *space; + + space = isl_space_range(isl_map_get_space(map)); + node = graph_find_node(ctx, graph, space); + isl_space_free(space); + + return node; +} + +/* Refrain from adding a new edge based on "map". + * Instead, just free the map. + * "tagged" is either a copy of "map" with additional tags or NULL. + */ +static isl_stat skip_edge(__isl_take isl_map *map, __isl_take isl_map *tagged) +{ + isl_map_free(map); + isl_map_free(tagged); + + return isl_stat_ok; +} + +/* Add a new edge to the graph based on the given map + * and add it to data->graph->edge_table[data->type]. + * If a dependence relation of a given type happens to be identical + * to one of the dependence relations of a type that was added before, + * then we don't create a new edge, but instead mark the original edge + * as also representing a dependence of the current type. + * + * Edges of type isl_edge_condition or isl_edge_conditional_validity + * may be specified as "tagged" dependence relations. That is, "map" + * may contain elements (i -> a) -> (j -> b), where i -> j denotes + * the dependence on iterations and a and b are tags. + * edge->map is set to the relation containing the elements i -> j, + * while edge->tagged_condition and edge->tagged_validity contain + * the union of all the "map" relations + * for which extract_edge is called that result in the same edge->map. + * + * If the source or the destination node is compressed, then + * intersect both "map" and "tagged" with the constraints that + * were used to construct the compression. + * This ensures that there are no schedule constraints defined + * outside of these domains, while the scheduler no longer has + * any control over those outside parts. + */ +static isl_stat extract_edge(__isl_take isl_map *map, void *user) +{ + isl_bool empty; + isl_ctx *ctx = isl_map_get_ctx(map); + struct isl_extract_edge_data *data = user; + struct isl_sched_graph *graph = data->graph; + struct isl_sched_node *src, *dst; + struct isl_sched_edge *edge; + isl_map *tagged = NULL; + + if (data->type == isl_edge_condition || + data->type == isl_edge_conditional_validity) { + if (isl_map_can_zip(map)) { + tagged = isl_map_copy(map); + map = isl_set_unwrap(isl_map_domain(isl_map_zip(map))); + } else { + tagged = insert_dummy_tags(isl_map_copy(map)); + } + } + + src = find_domain_node(ctx, graph, map); + dst = find_range_node(ctx, graph, map); + + if (!src || !dst) + goto error; + if (!is_node(graph, src) || !is_node(graph, dst)) + return skip_edge(map, tagged); + + if (src->compressed || dst->compressed) { + isl_map *hull; + hull = extract_hull(src, dst); + if (tagged) + tagged = map_intersect_domains(tagged, hull); + map = isl_map_intersect(map, hull); + } + + empty = isl_map_plain_is_empty(map); + if (empty < 0) + goto error; + if (empty) + return skip_edge(map, tagged); + + 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].types = 0; + graph->edge[graph->n_edge].tagged_condition = NULL; + graph->edge[graph->n_edge].tagged_validity = NULL; + set_type(&graph->edge[graph->n_edge], data->type); + if (data->type == isl_edge_condition) + graph->edge[graph->n_edge].tagged_condition = + isl_union_map_from_map(tagged); + if (data->type == isl_edge_conditional_validity) + graph->edge[graph->n_edge].tagged_validity = + isl_union_map_from_map(tagged); + + edge = graph_find_matching_edge(graph, &graph->edge[graph->n_edge]); + if (!edge) { + graph->n_edge++; + return isl_stat_error; + } + if (edge == &graph->edge[graph->n_edge]) + return graph_edge_table_add(ctx, graph, data->type, + &graph->edge[graph->n_edge++]); + + if (merge_edge(edge, &graph->edge[graph->n_edge]) < 0) + return isl_stat_error; + + return graph_edge_table_add(ctx, graph, data->type, edge); +error: + isl_map_free(map); + isl_map_free(tagged); + return isl_stat_error; +} + +/* Initialize the schedule graph "graph" from the schedule constraints "sc". + * + * The context is included in the domain before the nodes of + * the graphs are extracted in order to be able to exploit + * any possible additional equalities. + * Note that this intersection is only performed locally here. + */ +static isl_stat graph_init(struct isl_sched_graph *graph, + __isl_keep isl_schedule_constraints *sc) +{ + isl_ctx *ctx; + isl_union_set *domain; + isl_union_map *c; + struct isl_extract_edge_data data; + enum isl_edge_type i; + isl_stat r; + + if (!sc) + return isl_stat_error; + + ctx = isl_schedule_constraints_get_ctx(sc); + + domain = isl_schedule_constraints_get_domain(sc); + graph->n = isl_union_set_n_set(domain); + isl_union_set_free(domain); + + if (graph_alloc(ctx, graph, graph->n, + isl_schedule_constraints_n_map(sc)) < 0) + return isl_stat_error; + + if (compute_max_row(graph, sc) < 0) + return isl_stat_error; + graph->root = graph; + graph->n = 0; + domain = isl_schedule_constraints_get_domain(sc); + domain = isl_union_set_intersect_params(domain, + isl_schedule_constraints_get_context(sc)); + r = isl_union_set_foreach_set(domain, &extract_node, graph); + isl_union_set_free(domain); + if (r < 0) + return isl_stat_error; + if (graph_init_table(ctx, graph) < 0) + return isl_stat_error; + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + c = isl_schedule_constraints_get(sc, i); + graph->max_edge[i] = isl_union_map_n_map(c); + isl_union_map_free(c); + if (!c) + return isl_stat_error; + } + if (graph_init_edge_tables(ctx, graph) < 0) + return isl_stat_error; + graph->n_edge = 0; + data.graph = graph; + for (i = isl_edge_first; i <= isl_edge_last; ++i) { + isl_stat r; + + data.type = i; + c = isl_schedule_constraints_get(sc, i); + r = isl_union_map_foreach_map(c, &extract_edge, &data); + isl_union_map_free(c); + if (r < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Check whether there is any dependence from node[j] to node[i] + * or from node[i] to node[j]. + */ +static isl_bool node_follows_weak(int i, int j, void *user) +{ + isl_bool f; + struct isl_sched_graph *graph = user; + + f = graph_has_any_edge(graph, &graph->node[j], &graph->node[i]); + if (f < 0 || f) + return f; + return graph_has_any_edge(graph, &graph->node[i], &graph->node[j]); +} + +/* Check whether there is a (conditional) validity dependence from node[j] + * to node[i], forcing node[i] to follow node[j]. + */ +static isl_bool node_follows_strong(int i, int j, void *user) +{ + struct isl_sched_graph *graph = user; + + return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]); +} + +/* Use Tarjan's algorithm for computing the strongly connected components + * in the dependence graph only considering those edges defined by "follows". + */ +static isl_stat detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph, + isl_bool (*follows)(int i, int j, void *user)) +{ + int i, n; + struct isl_tarjan_graph *g = NULL; + + g = isl_tarjan_graph_init(ctx, graph->n, follows, graph); + if (!g) + return isl_stat_error; + + graph->scc = 0; + i = 0; + n = graph->n; + while (n) { + while (g->order[i] != -1) { + graph->node[g->order[i]].scc = graph->scc; + --n; + ++i; + } + ++i; + graph->scc++; + } + + isl_tarjan_graph_free(g); + + return isl_stat_ok; +} + +/* Apply Tarjan's algorithm to detect the strongly connected components + * in the dependence graph. + * Only consider the (conditional) validity dependences and clear "weak". + */ +static isl_stat detect_sccs(isl_ctx *ctx, struct isl_sched_graph *graph) +{ + graph->weak = 0; + return detect_ccs(ctx, graph, &node_follows_strong); +} + +/* Apply Tarjan's algorithm to detect the (weakly) connected components + * in the dependence graph. + * Consider all dependences and set "weak". + */ +static isl_stat detect_wccs(isl_ctx *ctx, struct isl_sched_graph *graph) +{ + graph->weak = 1; + return detect_ccs(ctx, graph, &node_follows_weak); +} + +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 int sort_sccs(struct isl_sched_graph *graph) +{ + return isl_sort(graph->sorted, graph->n, sizeof(int), &cmp_scc, graph); +} + +/* Return a non-parametric set in the compressed space of "node" that is + * bounded by the size in each direction + * + * { [x] : -S_i <= x_i <= S_i } + * + * If S_i is infinity in direction i, then there are no constraints + * in that direction. + * + * Cache the result in node->bounds. + */ +static __isl_give isl_basic_set *get_size_bounds(struct isl_sched_node *node) +{ + isl_space *space; + isl_basic_set *bounds; + int i; + unsigned nparam; + + if (node->bounds) + return isl_basic_set_copy(node->bounds); + + if (node->compressed) + space = isl_multi_aff_get_domain_space(node->decompress); + else + space = isl_space_copy(node->space); + nparam = isl_space_dim(space, isl_dim_param); + space = isl_space_drop_dims(space, isl_dim_param, 0, nparam); + bounds = isl_basic_set_universe(space); + + for (i = 0; i < node->nvar; ++i) { + isl_val *size; + + size = isl_multi_val_get_val(node->sizes, i); + if (!size) + return isl_basic_set_free(bounds); + if (!isl_val_is_int(size)) { + isl_val_free(size); + continue; + } + bounds = isl_basic_set_upper_bound_val(bounds, isl_dim_set, i, + isl_val_copy(size)); + bounds = isl_basic_set_lower_bound_val(bounds, isl_dim_set, i, + isl_val_neg(size)); + } + + node->bounds = isl_basic_set_copy(bounds); + return bounds; +} + +/* Drop some constraints from "delta" that could be exploited + * to construct loop coalescing schedules. + * In particular, drop those constraint that bound the difference + * to the size of the domain. + * First project out the parameters to improve the effectiveness. + */ +static __isl_give isl_set *drop_coalescing_constraints( + __isl_take isl_set *delta, struct isl_sched_node *node) +{ + unsigned nparam; + isl_basic_set *bounds; + + bounds = get_size_bounds(node); + + nparam = isl_set_dim(delta, isl_dim_param); + delta = isl_set_project_out(delta, isl_dim_param, 0, nparam); + delta = isl_set_remove_divs(delta); + delta = isl_set_plain_gist_basic_set(delta, bounds); + return delta; +} + +/* Given a dependence relation R from "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). + * + * If "need_param" is set, then the resulting coefficients effectively + * include coefficients for the parameters c_n. Otherwise, they may + * have been projected out already. + * Since the constraints may be different for these two cases, + * they are stored in separate caches. + * In particular, if no parameter coefficients are required and + * the schedule_treat_coalescing option is set, then the parameters + * are projected out and some constraints that could be exploited + * to construct coalescing schedules are removed before the dual + * is computed. + * + * If "node" has been compressed, then the dependence relation + * is also compressed before the set of coefficients is computed. + */ +static __isl_give isl_basic_set *intra_coefficients( + struct isl_sched_graph *graph, struct isl_sched_node *node, + __isl_take isl_map *map, int need_param) +{ + isl_ctx *ctx; + isl_set *delta; + isl_map *key; + isl_basic_set *coef; + isl_maybe_isl_basic_set m; + isl_map_to_basic_set **hmap = &graph->intra_hmap; + int treat; + + if (!map) + return NULL; + + ctx = isl_map_get_ctx(map); + treat = !need_param && isl_options_get_schedule_treat_coalescing(ctx); + if (!treat) + hmap = &graph->intra_hmap_param; + m = isl_map_to_basic_set_try_get(*hmap, map); + if (m.valid < 0 || m.valid) { + isl_map_free(map); + return m.value; + } + + key = isl_map_copy(map); + if (node->compressed) { + map = isl_map_preimage_domain_multi_aff(map, + isl_multi_aff_copy(node->decompress)); + map = isl_map_preimage_range_multi_aff(map, + isl_multi_aff_copy(node->decompress)); + } + delta = isl_map_deltas(map); + if (treat) + delta = drop_coalescing_constraints(delta, node); + delta = isl_set_remove_divs(delta); + coef = isl_set_coefficients(delta); + *hmap = isl_map_to_basic_set_set(*hmap, key, 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 + * + * If the source or destination nodes of "edge" have been compressed, + * then the dependence relation is also compressed before + * the set of coefficients is computed. + */ +static __isl_give isl_basic_set *inter_coefficients( + struct isl_sched_graph *graph, struct isl_sched_edge *edge, + __isl_take isl_map *map) +{ + isl_set *set; + isl_map *key; + isl_basic_set *coef; + isl_maybe_isl_basic_set m; + + m = isl_map_to_basic_set_try_get(graph->inter_hmap, map); + if (m.valid < 0 || m.valid) { + isl_map_free(map); + return m.value; + } + + key = isl_map_copy(map); + if (edge->src->compressed) + map = isl_map_preimage_domain_multi_aff(map, + isl_multi_aff_copy(edge->src->decompress)); + if (edge->dst->compressed) + map = isl_map_preimage_range_multi_aff(map, + isl_multi_aff_copy(edge->dst->decompress)); + set = isl_map_wrap(isl_map_remove_divs(map)); + coef = isl_set_coefficients(set); + graph->inter_hmap = isl_map_to_basic_set_set(graph->inter_hmap, key, + isl_basic_set_copy(coef)); + + return coef; +} + +/* Return the position of the coefficients of the variables in + * the coefficients constraints "coef". + * + * The space of "coef" is of the form + * + * { coefficients[[cst, params] -> S] } + * + * Return the position of S. + */ +static int coef_var_offset(__isl_keep isl_basic_set *coef) +{ + int offset; + isl_space *space; + + space = isl_space_unwrap(isl_basic_set_get_space(coef)); + offset = isl_space_dim(space, isl_dim_in); + isl_space_free(space); + + return offset; +} + +/* Return the offset of the coefficient of the constant term of "node" + * within the (I)LP. + * + * Within each node, the coefficients have the following order: + * - positive and negative parts of c_i_x + * - c_i_n (if parametric) + * - c_i_0 + */ +static int node_cst_coef_offset(struct isl_sched_node *node) +{ + return node->start + 2 * node->nvar + node->nparam; +} + +/* Return the offset of the coefficients of the parameters of "node" + * within the (I)LP. + * + * Within each node, the coefficients have the following order: + * - positive and negative parts of c_i_x + * - c_i_n (if parametric) + * - c_i_0 + */ +static int node_par_coef_offset(struct isl_sched_node *node) +{ + return node->start + 2 * node->nvar; +} + +/* Return the offset of the coefficients of the variables of "node" + * within the (I)LP. + * + * Within each node, the coefficients have the following order: + * - positive and negative parts of c_i_x + * - c_i_n (if parametric) + * - c_i_0 + */ +static int node_var_coef_offset(struct isl_sched_node *node) +{ + return node->start; +} + +/* Return the position of the pair of variables encoding + * coefficient "i" of "node". + * + * The order of these variable pairs is the opposite of + * that of the coefficients, with 2 variables per coefficient. + */ +static int node_var_coef_pos(struct isl_sched_node *node, int i) +{ + return node_var_coef_offset(node) + 2 * (node->nvar - 1 - i); +} + +/* Construct an isl_dim_map for mapping constraints on coefficients + * for "node" to the corresponding positions in graph->lp. + * "offset" is the offset of the coefficients for the variables + * in the input constraints. + * "s" is the sign of the mapping. + * + * The input constraints are given in terms of the coefficients + * (c_0, c_x) or (c_0, c_n, c_x). + * The mapping produced by this function essentially plugs in + * (0, c_i_x^+ - c_i_x^-) if s = 1 and + * (0, -c_i_x^+ + c_i_x^-) if s = -1 or + * (0, 0, c_i_x^+ - c_i_x^-) if s = 1 and + * (0, 0, -c_i_x^+ + c_i_x^-) if s = -1. + * In graph->lp, the c_i_x^- appear before their c_i_x^+ counterpart. + * Furthermore, the order of these pairs is the opposite of that + * of the corresponding coefficients. + * + * The caller can extend the mapping to also map the other coefficients + * (and therefore not plug in 0). + */ +static __isl_give isl_dim_map *intra_dim_map(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_sched_node *node, + int offset, int s) +{ + int pos; + unsigned total; + isl_dim_map *dim_map; + + if (!node || !graph->lp) + return NULL; + + total = isl_basic_set_total_dim(graph->lp); + pos = node_var_coef_pos(node, 0); + dim_map = isl_dim_map_alloc(ctx, total); + isl_dim_map_range(dim_map, pos, -2, offset, 1, node->nvar, -s); + isl_dim_map_range(dim_map, pos + 1, -2, offset, 1, node->nvar, s); + + return dim_map; +} + +/* Construct an isl_dim_map for mapping constraints on coefficients + * for "src" (node i) and "dst" (node j) to the corresponding positions + * in graph->lp. + * "offset" is the offset of the coefficients for the variables of "src" + * in the input constraints. + * "s" is the sign of the mapping. + * + * The input constraints are given in terms of the coefficients + * (c_0, c_n, c_x, c_y). + * The mapping produced by this function essentially plugs in + * (c_j_0 - c_i_0, c_j_n - c_i_n, + * -(c_i_x^+ - c_i_x^-), c_j_x^+ - c_j_x^-) if s = 1 and + * (-c_j_0 + c_i_0, -c_j_n + c_i_n, + * c_i_x^+ - c_i_x^-, -(c_j_x^+ - c_j_x^-)) if s = -1. + * In graph->lp, the c_*^- appear before their c_*^+ counterpart. + * Furthermore, the order of these pairs is the opposite of that + * of the corresponding coefficients. + * + * The caller can further extend the mapping. + */ +static __isl_give isl_dim_map *inter_dim_map(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_sched_node *src, + struct isl_sched_node *dst, int offset, int s) +{ + int pos; + unsigned total; + isl_dim_map *dim_map; + + if (!src || !dst || !graph->lp) + return NULL; + + total = isl_basic_set_total_dim(graph->lp); + dim_map = isl_dim_map_alloc(ctx, total); + + pos = node_cst_coef_offset(dst); + isl_dim_map_range(dim_map, pos, 0, 0, 0, 1, s); + pos = node_par_coef_offset(dst); + isl_dim_map_range(dim_map, pos, 1, 1, 1, dst->nparam, s); + pos = node_var_coef_pos(dst, 0); + isl_dim_map_range(dim_map, pos, -2, offset + src->nvar, 1, + dst->nvar, -s); + isl_dim_map_range(dim_map, pos + 1, -2, offset + src->nvar, 1, + dst->nvar, s); + + pos = node_cst_coef_offset(src); + isl_dim_map_range(dim_map, pos, 0, 0, 0, 1, -s); + pos = node_par_coef_offset(src); + isl_dim_map_range(dim_map, pos, 1, 1, 1, src->nparam, -s); + pos = node_var_coef_pos(src, 0); + isl_dim_map_range(dim_map, pos, -2, offset, 1, src->nvar, s); + isl_dim_map_range(dim_map, pos + 1, -2, offset, 1, src->nvar, -s); + + return dim_map; +} + +/* Add the constraints from "src" to "dst" using "dim_map", + * after making sure there is enough room in "dst" for the extra constraints. + */ +static __isl_give 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) +{ + int n_eq, n_ineq; + + n_eq = isl_basic_set_n_equality(src); + n_ineq = isl_basic_set_n_inequality(src); + dst = isl_basic_set_extend_constraints(dst, n_eq, n_ineq); + dst = isl_basic_set_add_constraints_dim_map(dst, src, dim_map); + return dst; +} + +/* 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_x) + * of valid constraints for (y - x) and then plug in (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. + * Note that the result of intra_coefficients may also contain + * parameter coefficients c_n, in which case 0 is plugged in for them as well. + */ +static isl_stat add_intra_validity_constraints(struct isl_sched_graph *graph, + struct isl_sched_edge *edge) +{ + int offset; + isl_map *map = isl_map_copy(edge->map); + isl_ctx *ctx = isl_map_get_ctx(map); + isl_dim_map *dim_map; + isl_basic_set *coef; + struct isl_sched_node *node = edge->src; + + coef = intra_coefficients(graph, node, map, 0); + + offset = coef_var_offset(coef); + + if (!coef) + return isl_stat_error; + + dim_map = intra_dim_map(ctx, graph, node, offset, 1); + graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map); + + return isl_stat_ok; +} + +/* 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_i_n, -(c_i_x^+ - c_i_x^-), c_j_x^+ - c_j_x^-), + * where c_* = c_*^+ - c_*^-, with c_*^+ and c_*^- non-negative. + * In graph->lp, the c_*^- appear before their c_*^+ counterpart. + */ +static isl_stat add_inter_validity_constraints(struct isl_sched_graph *graph, + struct isl_sched_edge *edge) +{ + int offset; + isl_map *map; + isl_ctx *ctx; + isl_dim_map *dim_map; + isl_basic_set *coef; + struct isl_sched_node *src = edge->src; + struct isl_sched_node *dst = edge->dst; + + if (!graph->lp) + return isl_stat_error; + + map = isl_map_copy(edge->map); + ctx = isl_map_get_ctx(map); + coef = inter_coefficients(graph, edge, map); + + offset = coef_var_offset(coef); + + if (!coef) + return isl_stat_error; + + dim_map = inter_dim_map(ctx, graph, src, dst, offset, 1); + + edge->start = graph->lp->n_ineq; + graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map); + if (!graph->lp) + return isl_stat_error; + edge->end = graph->lp->n_ineq; + + return isl_stat_ok; +} + +/* 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. + * + * + * If "local" is set, then we add constraints + * + * c_i_x (y - x) <= 0 + * + * or + * + * -c_i_x (y - x) <= 0 + * + * instead, forcing the dependence distance to be (less than or) equal to 0. + * That is, we plug in (0, 0, -s * c_i_x), + * intra_coefficients is not required to have c_n in its result when + * "local" is set. If they are missing, then (0, -s * c_i_x) is plugged in. + * Note that dependences marked local are treated as validity constraints + * by add_all_validity_constraints and therefore also have + * their distances bounded by 0 from below. + */ +static isl_stat add_intra_proximity_constraints(struct isl_sched_graph *graph, + struct isl_sched_edge *edge, int s, int local) +{ + int offset; + unsigned nparam; + isl_map *map = isl_map_copy(edge->map); + isl_ctx *ctx = isl_map_get_ctx(map); + isl_dim_map *dim_map; + isl_basic_set *coef; + struct isl_sched_node *node = edge->src; + + coef = intra_coefficients(graph, node, map, !local); + + offset = coef_var_offset(coef); + + if (!coef) + return isl_stat_error; + + nparam = isl_space_dim(node->space, isl_dim_param); + dim_map = intra_dim_map(ctx, graph, node, offset, -s); + + if (!local) { + 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); + } + graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map); + + return isl_stat_ok; +} + +/* 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_i_x, -s*c_j_x) + * with each coefficient (except m_0, c_*_0 and c_*_n) + * represented as a pair of non-negative coefficients. + * + * + * If "local" is set (and s = 1), then we add constraints + * + * (c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) <= 0 + * + * or + * + * -((c_j_0 + c_j_n n + c_j_x y) + (c_i_0 + c_i_n n + c_i_x x)) >= 0 + * + * instead, forcing the dependence distance to be (less than or) equal to 0. + * That is, we plug in + * (-s*c_j_0 + s*c_i_0, -s*c_j_n + s*c_i_n, s*c_i_x, -s*c_j_x). + * Note that dependences marked local are treated as validity constraints + * by add_all_validity_constraints and therefore also have + * their distances bounded by 0 from below. + */ +static isl_stat add_inter_proximity_constraints(struct isl_sched_graph *graph, + struct isl_sched_edge *edge, int s, int local) +{ + int offset; + unsigned nparam; + isl_map *map = isl_map_copy(edge->map); + isl_ctx *ctx = isl_map_get_ctx(map); + 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, edge, map); + + offset = coef_var_offset(coef); + + if (!coef) + return isl_stat_error; + + nparam = isl_space_dim(src->space, isl_dim_param); + dim_map = inter_dim_map(ctx, graph, src, dst, offset, -s); + + if (!local) { + 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); + } + + graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map); + + return isl_stat_ok; +} + +/* Should the distance over "edge" be forced to zero? + * That is, is it marked as a local edge? + * If "use_coincidence" is set, then coincidence edges are treated + * as local edges. + */ +static int force_zero(struct isl_sched_edge *edge, int use_coincidence) +{ + return is_local(edge) || (use_coincidence && is_coincidence(edge)); +} + +/* Add all validity constraints to graph->lp. + * + * An edge that is forced to be local needs to have its dependence + * distances equal to zero. We take care of bounding them by 0 from below + * here. add_all_proximity_constraints takes care of bounding them by 0 + * from above. + * + * If "use_coincidence" is set, then we treat coincidence edges as local edges. + * Otherwise, we ignore them. + */ +static int add_all_validity_constraints(struct isl_sched_graph *graph, + int use_coincidence) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + int zero; + + zero = force_zero(edge, use_coincidence); + if (!is_validity(edge) && !zero) + 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]; + int zero; + + zero = force_zero(edge, use_coincidence); + if (!is_validity(edge) && !zero) + 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. (This includes the case of "local" dependences + * which are treated as validity dependence by add_all_validity_constraints.) + * Otherwise, we need to bound the distance both from above and from below. + * + * If "use_coincidence" is set, then we treat coincidence edges as local edges. + * Otherwise, we ignore them. + */ +static int add_all_proximity_constraints(struct isl_sched_graph *graph, + int use_coincidence) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + int zero; + + zero = force_zero(edge, use_coincidence); + if (!is_proximity(edge) && !zero) + continue; + if (edge->src == edge->dst && + add_intra_proximity_constraints(graph, edge, 1, zero) < 0) + return -1; + if (edge->src != edge->dst && + add_inter_proximity_constraints(graph, edge, 1, zero) < 0) + return -1; + if (is_validity(edge) || zero) + continue; + if (edge->src == edge->dst && + add_intra_proximity_constraints(graph, edge, -1, 0) < 0) + return -1; + if (edge->src != edge->dst && + add_inter_proximity_constraints(graph, edge, -1, 0) < 0) + return -1; + } + + return 0; +} + +/* Normalize the rows of "indep" such that all rows are lexicographically + * positive and such that each row contains as many final zeros as possible, + * given the choice for the previous rows. + * Do this by performing elementary row operations. + */ +static __isl_give isl_mat *normalize_independent(__isl_take isl_mat *indep) +{ + indep = isl_mat_reverse_gauss(indep); + indep = isl_mat_lexnonneg_rows(indep); + return indep; +} + +/* 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 + * S U = H + * + * with H the Hermite normal form of S. That is, all but the + * first rank columns of H are zero and so each row in S is + * a linear combination of the first rank rows of Q. + * The matrix Q can be used as a variable transformation + * that isolates the directions of S in the first rank rows. + * Transposing S U = H yields + * + * U^T S^T = H^T + * + * with all but the first rank rows of H^T zero. + * The last rows of U^T are therefore linear combinations + * of schedule coefficients that are all zero on schedule + * coefficients that are linearly dependent on the rows of S. + * At least one of these combinations is non-zero on + * linearly independent schedule coefficients. + * The rows are normalized to involve as few of the last + * coefficients as possible and to have a positive initial value. + */ +static int node_update_vmap(struct isl_sched_node *node) +{ + isl_mat *H, *U, *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, &U, &Q); + isl_mat_free(node->indep); + isl_mat_free(node->vmap); + node->vmap = Q; + node->indep = isl_mat_transpose(U); + node->rank = isl_mat_initial_non_zero_cols(H); + node->indep = isl_mat_drop_rows(node->indep, 0, node->rank); + node->indep = normalize_independent(node->indep); + isl_mat_free(H); + + if (!node->indep || !node->vmap || node->rank < 0) + return -1; + return 0; +} + +/* Is "edge" marked as a validity or a conditional validity edge? + */ +static int is_any_validity(struct isl_sched_edge *edge) +{ + return is_validity(edge) || is_conditional_validity(edge); +} + +/* How many times should we count the constraints in "edge"? + * + * We count as follows + * validity -> 1 (>= 0) + * validity+proximity -> 2 (>= 0 and upper bound) + * proximity -> 2 (lower and upper bound) + * local(+any) -> 2 (>= 0 and <= 0) + * + * If an edge is only marked conditional_validity then it counts + * as zero since it is only checked afterwards. + * + * If "use_coincidence" is set, then we treat coincidence edges as local edges. + * Otherwise, we ignore them. + */ +static int edge_multiplicity(struct isl_sched_edge *edge, int use_coincidence) +{ + if (is_proximity(edge) || force_zero(edge, use_coincidence)) + return 2; + if (is_validity(edge)) + return 1; + return 0; +} + +/* How many times should the constraints in "edge" be counted + * as a parametric intra-node constraint? + * + * Only proximity edges that are not forced zero need + * coefficient constraints that include coefficients for parameters. + * If the edge is also a validity edge, then only + * an upper bound is introduced. Otherwise, both lower and upper bounds + * are introduced. + */ +static int parametric_intra_edge_multiplicity(struct isl_sched_edge *edge, + int use_coincidence) +{ + if (edge->src != edge->dst) + return 0; + if (!is_proximity(edge)) + return 0; + if (force_zero(edge, use_coincidence)) + return 0; + if (is_validity(edge)) + return 1; + else + return 2; +} + +/* Add "f" times the number of equality and inequality constraints of "bset" + * to "n_eq" and "n_ineq" and free "bset". + */ +static isl_stat update_count(__isl_take isl_basic_set *bset, + int f, int *n_eq, int *n_ineq) +{ + if (!bset) + return isl_stat_error; + + *n_eq += isl_basic_set_n_equality(bset); + *n_ineq += isl_basic_set_n_inequality(bset); + isl_basic_set_free(bset); + + return isl_stat_ok; +} + +/* Count the number of equality and inequality constraints + * that will be added for the given map. + * + * The edges that require parameter coefficients are counted separately. + * + * "use_coincidence" is set if we should take into account coincidence edges. + */ +static isl_stat count_map_constraints(struct isl_sched_graph *graph, + struct isl_sched_edge *edge, __isl_take isl_map *map, + int *n_eq, int *n_ineq, int use_coincidence) +{ + isl_map *copy; + isl_basic_set *coef; + int f = edge_multiplicity(edge, use_coincidence); + int fp = parametric_intra_edge_multiplicity(edge, use_coincidence); + + if (f == 0) { + isl_map_free(map); + return isl_stat_ok; + } + + if (edge->src != edge->dst) { + coef = inter_coefficients(graph, edge, map); + return update_count(coef, f, n_eq, n_ineq); + } + + if (fp > 0) { + copy = isl_map_copy(map); + coef = intra_coefficients(graph, edge->src, copy, 1); + if (update_count(coef, fp, n_eq, n_ineq) < 0) + goto error; + } + + if (f > fp) { + copy = isl_map_copy(map); + coef = intra_coefficients(graph, edge->src, copy, 0); + if (update_count(coef, f - fp, n_eq, n_ineq) < 0) + goto error; + } + + isl_map_free(map); + return isl_stat_ok; +error: + isl_map_free(map); + return isl_stat_error; +} + +/* Count the number of equality and inequality constraints + * that will be added to the main lp problem. + * We count as follows + * validity -> 1 (>= 0) + * validity+proximity -> 2 (>= 0 and upper bound) + * proximity -> 2 (lower and upper bound) + * local(+any) -> 2 (>= 0 and <= 0) + * + * If "use_coincidence" is set, then we treat coincidence edges as local edges. + * Otherwise, we ignore them. + */ +static int count_constraints(struct isl_sched_graph *graph, + int *n_eq, int *n_ineq, int use_coincidence) +{ + int i; + + *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); + + if (count_map_constraints(graph, edge, map, n_eq, n_ineq, + use_coincidence) < 0) + return -1; + } + + return 0; +} + +/* Count the number of constraints that will be added by + * add_bound_constant_constraints to bound the values of the constant terms + * and increment *n_eq and *n_ineq accordingly. + * + * In practice, add_bound_constant_constraints only adds inequalities. + */ +static isl_stat count_bound_constant_constraints(isl_ctx *ctx, + struct isl_sched_graph *graph, int *n_eq, int *n_ineq) +{ + if (isl_options_get_schedule_max_constant_term(ctx) == -1) + return isl_stat_ok; + + *n_ineq += graph->n; + + return isl_stat_ok; +} + +/* Add constraints to bound the values of the constant terms in the schedule, + * if requested by the user. + * + * The maximal value of the constant terms is defined by the option + * "schedule_max_constant_term". + */ +static isl_stat add_bound_constant_constraints(isl_ctx *ctx, + struct isl_sched_graph *graph) +{ + int i, k; + int max; + int total; + + max = isl_options_get_schedule_max_constant_term(ctx); + if (max == -1) + return isl_stat_ok; + + total = isl_basic_set_dim(graph->lp, isl_dim_set); + + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + int pos; + + k = isl_basic_set_alloc_inequality(graph->lp); + if (k < 0) + return isl_stat_error; + isl_seq_clr(graph->lp->ineq[k], 1 + total); + pos = node_cst_coef_offset(node); + isl_int_set_si(graph->lp->ineq[k][1 + pos], -1); + isl_int_set_si(graph->lp->ineq[k][0], max); + } + + return isl_stat_ok; +} + +/* Count the number of constraints that will be added by + * add_bound_coefficient_constraints and increment *n_eq and *n_ineq + * accordingly. + * + * In practice, add_bound_coefficient_constraints only adds inequalities. + */ +static int count_bound_coefficient_constraints(isl_ctx *ctx, + struct isl_sched_graph *graph, int *n_eq, int *n_ineq) +{ + int i; + + if (isl_options_get_schedule_max_coefficient(ctx) == -1 && + !isl_options_get_schedule_treat_coalescing(ctx)) + return 0; + + for (i = 0; i < graph->n; ++i) + *n_ineq += graph->node[i].nparam + 2 * graph->node[i].nvar; + + return 0; +} + +/* Add constraints to graph->lp that bound the values of + * the parameter schedule coefficients of "node" to "max" and + * the variable schedule coefficients to the corresponding entry + * in node->max. + * In either case, a negative value means that no bound needs to be imposed. + * + * For parameter coefficients, this amounts to adding a constraint + * + * c_n <= max + * + * i.e., + * + * -c_n + max >= 0 + * + * The variables coefficients are, however, not represented directly. + * Instead, the variable coefficients c_x are written as differences + * c_x = c_x^+ - c_x^-. + * That is, + * + * -max_i <= c_x_i <= max_i + * + * is encoded as + * + * -max_i <= c_x_i^+ - c_x_i^- <= max_i + * + * or + * + * -(c_x_i^+ - c_x_i^-) + max_i >= 0 + * c_x_i^+ - c_x_i^- + max_i >= 0 + */ +static isl_stat node_add_coefficient_constraints(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_sched_node *node, int max) +{ + int i, j, k; + int total; + isl_vec *ineq; + + total = isl_basic_set_dim(graph->lp, isl_dim_set); + + for (j = 0; j < node->nparam; ++j) { + int dim; + + if (max < 0) + continue; + + k = isl_basic_set_alloc_inequality(graph->lp); + if (k < 0) + return isl_stat_error; + dim = 1 + node_par_coef_offset(node) + j; + isl_seq_clr(graph->lp->ineq[k], 1 + total); + isl_int_set_si(graph->lp->ineq[k][dim], -1); + isl_int_set_si(graph->lp->ineq[k][0], max); + } + + ineq = isl_vec_alloc(ctx, 1 + total); + ineq = isl_vec_clr(ineq); + if (!ineq) + return isl_stat_error; + for (i = 0; i < node->nvar; ++i) { + int pos = 1 + node_var_coef_pos(node, i); + + if (isl_int_is_neg(node->max->el[i])) + continue; + + isl_int_set_si(ineq->el[pos], 1); + isl_int_set_si(ineq->el[pos + 1], -1); + isl_int_set(ineq->el[0], node->max->el[i]); + + k = isl_basic_set_alloc_inequality(graph->lp); + if (k < 0) + goto error; + isl_seq_cpy(graph->lp->ineq[k], ineq->el, 1 + total); + + isl_seq_neg(ineq->el + pos, ineq->el + pos, 2); + k = isl_basic_set_alloc_inequality(graph->lp); + if (k < 0) + goto error; + isl_seq_cpy(graph->lp->ineq[k], ineq->el, 1 + total); + + isl_seq_clr(ineq->el + pos, 2); + } + isl_vec_free(ineq); + + return isl_stat_ok; +error: + isl_vec_free(ineq); + return isl_stat_error; +} + +/* Add constraints that bound the values of the variable and parameter + * coefficients of the schedule. + * + * The maximal value of the coefficients is defined by the option + * 'schedule_max_coefficient' and the entries in node->max. + * These latter entries are only set if either the schedule_max_coefficient + * option or the schedule_treat_coalescing option is set. + */ +static isl_stat add_bound_coefficient_constraints(isl_ctx *ctx, + struct isl_sched_graph *graph) +{ + int i; + int max; + + max = isl_options_get_schedule_max_coefficient(ctx); + + if (max == -1 && !isl_options_get_schedule_treat_coalescing(ctx)) + return isl_stat_ok; + + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + + if (node_add_coefficient_constraints(ctx, graph, node, max) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Add a constraint to graph->lp that equates the value at position + * "sum_pos" to the sum of the "n" values starting at "first". + */ +static isl_stat add_sum_constraint(struct isl_sched_graph *graph, + int sum_pos, int first, int n) +{ + int i, k; + int total; + + total = isl_basic_set_dim(graph->lp, isl_dim_set); + + k = isl_basic_set_alloc_equality(graph->lp); + if (k < 0) + return isl_stat_error; + isl_seq_clr(graph->lp->eq[k], 1 + total); + isl_int_set_si(graph->lp->eq[k][1 + sum_pos], -1); + for (i = 0; i < n; ++i) + isl_int_set_si(graph->lp->eq[k][1 + first + i], 1); + + return isl_stat_ok; +} + +/* Add a constraint to graph->lp that equates the value at position + * "sum_pos" to the sum of the parameter coefficients of all nodes. + */ +static isl_stat add_param_sum_constraint(struct isl_sched_graph *graph, + int sum_pos) +{ + int i, j, k; + int total; + + total = isl_basic_set_dim(graph->lp, isl_dim_set); + + k = isl_basic_set_alloc_equality(graph->lp); + if (k < 0) + return isl_stat_error; + isl_seq_clr(graph->lp->eq[k], 1 + total); + isl_int_set_si(graph->lp->eq[k][1 + sum_pos], -1); + for (i = 0; i < graph->n; ++i) { + int pos = 1 + node_par_coef_offset(&graph->node[i]); + + for (j = 0; j < graph->node[i].nparam; ++j) + isl_int_set_si(graph->lp->eq[k][pos + j], 1); + } + + return isl_stat_ok; +} + +/* Add a constraint to graph->lp that equates the value at position + * "sum_pos" to the sum of the variable coefficients of all nodes. + */ +static isl_stat add_var_sum_constraint(struct isl_sched_graph *graph, + int sum_pos) +{ + int i, j, k; + int total; + + total = isl_basic_set_dim(graph->lp, isl_dim_set); + + k = isl_basic_set_alloc_equality(graph->lp); + if (k < 0) + return isl_stat_error; + isl_seq_clr(graph->lp->eq[k], 1 + total); + isl_int_set_si(graph->lp->eq[k][1 + sum_pos], -1); + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + int pos = 1 + node_var_coef_offset(node); + + for (j = 0; j < 2 * node->nvar; ++j) + isl_int_set_si(graph->lp->eq[k][pos + j], 1); + } + + return isl_stat_ok; +} + +/* 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 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 + * - positive and negative parts of c_i_x, in opposite order + * - c_i_n (if parametric) + * - c_i_0 + * + * The constraints are those from the edges plus two or three equalities + * to express the sums. + * + * If "use_coincidence" is set, then we treat coincidence edges as local edges. + * Otherwise, we ignore them. + */ +static isl_stat setup_lp(isl_ctx *ctx, struct isl_sched_graph *graph, + int use_coincidence) +{ + int i; + unsigned nparam; + unsigned total; + isl_space *space; + int parametric; + int param_pos; + int n_eq, n_ineq; + + parametric = ctx->opt->schedule_parametric; + nparam = isl_space_dim(graph->node[0].space, 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_vmap(node) < 0) + return isl_stat_error; + node->start = total; + total += 1 + node->nparam + 2 * node->nvar; + } + + if (count_constraints(graph, &n_eq, &n_ineq, use_coincidence) < 0) + return isl_stat_error; + if (count_bound_constant_constraints(ctx, graph, &n_eq, &n_ineq) < 0) + return isl_stat_error; + if (count_bound_coefficient_constraints(ctx, graph, &n_eq, &n_ineq) < 0) + return isl_stat_error; + + space = isl_space_set_alloc(ctx, 0, total); + isl_basic_set_free(graph->lp); + n_eq += 2 + parametric; + + graph->lp = isl_basic_set_alloc_space(space, 0, n_eq, n_ineq); + + if (add_sum_constraint(graph, 0, param_pos, 2 * nparam) < 0) + return isl_stat_error; + if (parametric && add_param_sum_constraint(graph, 2) < 0) + return isl_stat_error; + if (add_var_sum_constraint(graph, 3) < 0) + return isl_stat_error; + if (add_bound_constant_constraints(ctx, graph) < 0) + return isl_stat_error; + if (add_bound_coefficient_constraints(ctx, graph) < 0) + return isl_stat_error; + if (add_all_validity_constraints(graph, use_coincidence) < 0) + return isl_stat_error; + if (add_all_proximity_constraints(graph, use_coincidence) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* 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 (!is_validity(&graph->edge[i])) + 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; +} + +/* Construct a non-triviality region with triviality directions + * corresponding to the rows of "indep". + * The rows of "indep" are expressed in terms of the schedule coefficients c_i, + * while the triviality directions are expressed in terms of + * pairs of non-negative variables c^+_i - c^-_i, with c^-_i appearing + * before c^+_i. Furthermore, + * the pairs of non-negative variables representing the coefficients + * are stored in the opposite order. + */ +static __isl_give isl_mat *construct_trivial(__isl_keep isl_mat *indep) +{ + isl_ctx *ctx; + isl_mat *mat; + int i, j, n, n_var; + + if (!indep) + return NULL; + + ctx = isl_mat_get_ctx(indep); + n = isl_mat_rows(indep); + n_var = isl_mat_cols(indep); + mat = isl_mat_alloc(ctx, n, 2 * n_var); + if (!mat) + return NULL; + for (i = 0; i < n; ++i) { + for (j = 0; j < n_var; ++j) { + int nj = n_var - 1 - j; + isl_int_neg(mat->row[i][2 * nj], indep->row[i][j]); + isl_int_set(mat->row[i][2 * nj + 1], indep->row[i][j]); + } + } + + return mat; +} + +/* 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 non-triviality region enforces that at least + * one of the linear combinations in the rows of node->indep is non-zero. + */ +static __isl_give isl_vec *solve_lp(isl_ctx *ctx, 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]; + isl_mat *trivial; + + graph->region[i].pos = node_var_coef_offset(node); + if (needs_row(graph, node)) + trivial = construct_trivial(node->indep); + else + trivial = isl_mat_zero(ctx, 0, 0); + graph->region[i].trivial = trivial; + } + lp = isl_basic_set_copy(graph->lp); + sol = isl_tab_basic_set_non_trivial_lexmin(lp, 2, graph->n, + graph->region, &check_conflict, graph); + for (i = 0; i < graph->n; ++i) + isl_mat_free(graph->region[i].trivial); + return sol; +} + +/* Extract the coefficients for the variables of "node" from "sol". + * + * Each schedule coefficient c_i_x is represented as the difference + * between two non-negative variables c_i_x^+ - c_i_x^-. + * The c_i_x^- appear before their c_i_x^+ counterpart. + * Furthermore, the order of these pairs is the opposite of that + * of the corresponding coefficients. + * + * Return c_i_x = c_i_x^+ - c_i_x^- + */ +static __isl_give isl_vec *extract_var_coef(struct isl_sched_node *node, + __isl_keep isl_vec *sol) +{ + int i; + int pos; + isl_vec *csol; + + if (!sol) + return NULL; + csol = isl_vec_alloc(isl_vec_get_ctx(sol), node->nvar); + if (!csol) + return NULL; + + pos = 1 + node_var_coef_offset(node); + for (i = 0; i < node->nvar; ++i) + isl_int_sub(csol->el[node->nvar - 1 - i], + sol->el[pos + 2 * i + 1], sol->el[pos + 2 * i]); + + return csol; +} + +/* 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. + * + * If coincident is set, then the caller guarantees that the new + * row satisfies the coincidence constraints. + */ +static int update_schedule(struct isl_sched_graph *graph, + __isl_take isl_vec *sol, int coincident) +{ + 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); + if (graph->n_total_row >= graph->max_row) + isl_die(sol->ctx, isl_error_internal, + "too many schedule rows", goto error); + + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + int pos; + int row = isl_mat_rows(node->sched); + + isl_vec_free(csol); + csol = extract_var_coef(node, sol); + 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; + pos = node_cst_coef_offset(node); + node->sched = isl_mat_set_element(node->sched, + row, 0, sol->el[1 + pos]); + pos = node_par_coef_offset(node); + for (j = 0; j < node->nparam; ++j) + node->sched = isl_mat_set_element(node->sched, + row, 1 + j, sol->el[1 + pos + j]); + for (j = 0; j < node->nvar; ++j) + node->sched = isl_mat_set_element(node->sched, + row, 1 + node->nparam + j, csol->el[j]); + node->coincident[graph->n_total_row] = coincident; + } + 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 row "row" of node->sched into an isl_aff living in "ls" + * and return this isl_aff. + */ +static __isl_give isl_aff *extract_schedule_row(__isl_take isl_local_space *ls, + struct isl_sched_node *node, int row) +{ + int j; + isl_int v; + isl_aff *aff; + + isl_int_init(v); + + aff = isl_aff_zero_on_domain(ls); + if (isl_mat_get_element(node->sched, row, 0, &v) < 0) + goto error; + aff = isl_aff_set_constant(aff, v); + for (j = 0; j < node->nparam; ++j) { + if (isl_mat_get_element(node->sched, row, 1 + j, &v) < 0) + goto error; + aff = isl_aff_set_coefficient(aff, isl_dim_param, j, v); + } + for (j = 0; j < node->nvar; ++j) { + if (isl_mat_get_element(node->sched, row, + 1 + node->nparam + j, &v) < 0) + goto error; + aff = isl_aff_set_coefficient(aff, isl_dim_in, j, v); + } + + isl_int_clear(v); + + return aff; +error: + isl_int_clear(v); + isl_aff_free(aff); + return NULL; +} + +/* Convert the "n" rows starting at "first" of node->sched into a multi_aff + * and return this multi_aff. + * + * The result is defined over the uncompressed node domain. + */ +static __isl_give isl_multi_aff *node_extract_partial_schedule_multi_aff( + struct isl_sched_node *node, int first, int n) +{ + int i; + isl_space *space; + isl_local_space *ls; + isl_aff *aff; + isl_multi_aff *ma; + int nrow; + + if (!node) + return NULL; + nrow = isl_mat_rows(node->sched); + if (node->compressed) + space = isl_multi_aff_get_domain_space(node->decompress); + else + space = isl_space_copy(node->space); + ls = isl_local_space_from_space(isl_space_copy(space)); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, n); + ma = isl_multi_aff_zero(space); + + for (i = first; i < first + n; ++i) { + aff = extract_schedule_row(isl_local_space_copy(ls), node, i); + ma = isl_multi_aff_set_aff(ma, i - first, aff); + } + + isl_local_space_free(ls); + + if (node->compressed) + ma = isl_multi_aff_pullback_multi_aff(ma, + isl_multi_aff_copy(node->compress)); + + return ma; +} + +/* Convert node->sched into a multi_aff and return this multi_aff. + * + * The result is defined over the uncompressed node domain. + */ +static __isl_give isl_multi_aff *node_extract_schedule_multi_aff( + struct isl_sched_node *node) +{ + int nrow; + + nrow = isl_mat_rows(node->sched); + return node_extract_partial_schedule_multi_aff(node, 0, nrow); +} + +/* Convert node->sched into a map and return this map. + * + * The result is cached in node->sched_map, which needs to be released + * whenever node->sched is updated. + * It is defined over the uncompressed node domain. + */ +static __isl_give isl_map *node_extract_schedule(struct isl_sched_node *node) +{ + if (!node->sched_map) { + isl_multi_aff *ma; + + ma = node_extract_schedule_multi_aff(node); + node->sched_map = isl_map_from_multi_aff(ma); + } + + return isl_map_copy(node->sched_map); +} + +/* Construct a map that can be used to update a dependence relation + * based on the current schedule. + * That is, construct a map expressing that source and sink + * are executed within the same iteration of the current schedule. + * This map can then be intersected with the dependence relation. + * This is not the most efficient way, but this shouldn't be a critical + * operation. + */ +static __isl_give isl_map *specializer(struct isl_sched_node *src, + struct isl_sched_node *dst) +{ + isl_map *src_sched, *dst_sched; + + src_sched = node_extract_schedule(src); + dst_sched = node_extract_schedule(dst); + return isl_map_apply_range(src_sched, isl_map_reverse(dst_sched)); +} + +/* Intersect the domains of the nested relations in domain and range + * of "umap" with "map". + */ +static __isl_give isl_union_map *intersect_domains( + __isl_take isl_union_map *umap, __isl_keep isl_map *map) +{ + isl_union_set *uset; + + umap = isl_union_map_zip(umap); + uset = isl_union_set_from_set(isl_map_wrap(isl_map_copy(map))); + umap = isl_union_map_intersect_domain(umap, uset); + umap = isl_union_map_zip(umap); + return umap; +} + +/* Update the dependence relation of the given edge based + * on the current schedule. + * If the dependence is carried completely by the current schedule, then + * it is removed from the edge_tables. It is kept in the list of edges + * as otherwise all edge_tables would have to be recomputed. + * + * If the edge is of a type that can appear multiple times + * between the same pair of nodes, then it is added to + * the edge table (again). This prevents the situation + * where none of these edges is referenced from the edge table + * because the one that was referenced turned out to be empty and + * was therefore removed from the table. + */ +static isl_stat update_edge(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_sched_edge *edge) +{ + int empty; + isl_map *id; + + id = specializer(edge->src, edge->dst); + edge->map = isl_map_intersect(edge->map, isl_map_copy(id)); + if (!edge->map) + goto error; + + if (edge->tagged_condition) { + edge->tagged_condition = + intersect_domains(edge->tagged_condition, id); + if (!edge->tagged_condition) + goto error; + } + if (edge->tagged_validity) { + edge->tagged_validity = + intersect_domains(edge->tagged_validity, id); + if (!edge->tagged_validity) + goto error; + } + + empty = isl_map_plain_is_empty(edge->map); + if (empty < 0) + goto error; + if (empty) { + graph_remove_edge(graph, edge); + } else if (is_multi_edge_type(edge)) { + if (graph_edge_tables_add(ctx, graph, edge) < 0) + goto error; + } + + isl_map_free(id); + return isl_stat_ok; +error: + isl_map_free(id); + return isl_stat_error; +} + +/* Does the domain of "umap" intersect "uset"? + */ +static int domain_intersects(__isl_keep isl_union_map *umap, + __isl_keep isl_union_set *uset) +{ + int empty; + + umap = isl_union_map_copy(umap); + umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(uset)); + empty = isl_union_map_is_empty(umap); + isl_union_map_free(umap); + + return empty < 0 ? -1 : !empty; +} + +/* Does the range of "umap" intersect "uset"? + */ +static int range_intersects(__isl_keep isl_union_map *umap, + __isl_keep isl_union_set *uset) +{ + int empty; + + umap = isl_union_map_copy(umap); + umap = isl_union_map_intersect_range(umap, isl_union_set_copy(uset)); + empty = isl_union_map_is_empty(umap); + isl_union_map_free(umap); + + return empty < 0 ? -1 : !empty; +} + +/* Are the condition dependences of "edge" local with respect to + * the current schedule? + * + * That is, are domain and range of the condition dependences mapped + * to the same point? + * + * In other words, is the condition false? + */ +static int is_condition_false(struct isl_sched_edge *edge) +{ + isl_union_map *umap; + isl_map *map, *sched, *test; + int empty, local; + + empty = isl_union_map_is_empty(edge->tagged_condition); + if (empty < 0 || empty) + return empty; + + umap = isl_union_map_copy(edge->tagged_condition); + umap = isl_union_map_zip(umap); + umap = isl_union_set_unwrap(isl_union_map_domain(umap)); + map = isl_map_from_union_map(umap); + + sched = node_extract_schedule(edge->src); + map = isl_map_apply_domain(map, sched); + sched = node_extract_schedule(edge->dst); + map = isl_map_apply_range(map, sched); + + test = isl_map_identity(isl_map_get_space(map)); + local = isl_map_is_subset(map, test); + isl_map_free(map); + isl_map_free(test); + + return local; +} + +/* For each conditional validity constraint that is adjacent + * to a condition with domain in condition_source or range in condition_sink, + * turn it into an unconditional validity constraint. + */ +static int unconditionalize_adjacent_validity(struct isl_sched_graph *graph, + __isl_take isl_union_set *condition_source, + __isl_take isl_union_set *condition_sink) +{ + int i; + + condition_source = isl_union_set_coalesce(condition_source); + condition_sink = isl_union_set_coalesce(condition_sink); + + for (i = 0; i < graph->n_edge; ++i) { + int adjacent; + isl_union_map *validity; + + if (!is_conditional_validity(&graph->edge[i])) + continue; + if (is_validity(&graph->edge[i])) + continue; + + validity = graph->edge[i].tagged_validity; + adjacent = domain_intersects(validity, condition_sink); + if (adjacent >= 0 && !adjacent) + adjacent = range_intersects(validity, condition_source); + if (adjacent < 0) + goto error; + if (!adjacent) + continue; + + set_validity(&graph->edge[i]); + } + + isl_union_set_free(condition_source); + isl_union_set_free(condition_sink); + return 0; +error: + isl_union_set_free(condition_source); + isl_union_set_free(condition_sink); + return -1; +} + +/* Update the dependence relations of all edges based on the current schedule + * and enforce conditional validity constraints that are adjacent + * to satisfied condition constraints. + * + * First check if any of the condition constraints are satisfied + * (i.e., not local to the outer schedule) and keep track of + * their domain and range. + * Then update all dependence relations (which removes the non-local + * constraints). + * Finally, if any condition constraints turned out to be satisfied, + * then turn all adjacent conditional validity constraints into + * unconditional validity constraints. + */ +static int update_edges(isl_ctx *ctx, struct isl_sched_graph *graph) +{ + int i; + int any = 0; + isl_union_set *source, *sink; + + source = isl_union_set_empty(isl_space_params_alloc(ctx, 0)); + sink = isl_union_set_empty(isl_space_params_alloc(ctx, 0)); + for (i = 0; i < graph->n_edge; ++i) { + int local; + isl_union_set *uset; + isl_union_map *umap; + + if (!is_condition(&graph->edge[i])) + continue; + if (is_local(&graph->edge[i])) + continue; + local = is_condition_false(&graph->edge[i]); + if (local < 0) + goto error; + if (local) + continue; + + any = 1; + + umap = isl_union_map_copy(graph->edge[i].tagged_condition); + uset = isl_union_map_domain(umap); + source = isl_union_set_union(source, uset); + + umap = isl_union_map_copy(graph->edge[i].tagged_condition); + uset = isl_union_map_range(umap); + sink = isl_union_set_union(sink, uset); + } + + for (i = 0; i < graph->n_edge; ++i) { + if (update_edge(ctx, graph, &graph->edge[i]) < 0) + goto error; + } + + if (any) + return unconditionalize_adjacent_validity(graph, source, sink); + + isl_union_set_free(source); + isl_union_set_free(sink); + return 0; +error: + isl_union_set_free(source); + isl_union_set_free(sink); + return -1; +} + +static void next_band(struct isl_sched_graph *graph) +{ + graph->band_start = graph->n_total_row; +} + +/* Return the union of the universe domains of the nodes in "graph" + * that satisfy "pred". + */ +static __isl_give isl_union_set *isl_sched_graph_domain(isl_ctx *ctx, + struct isl_sched_graph *graph, + int (*pred)(struct isl_sched_node *node, int data), int data) +{ + int i; + isl_set *set; + isl_union_set *dom; + + for (i = 0; i < graph->n; ++i) + if (pred(&graph->node[i], data)) + break; + + if (i >= graph->n) + isl_die(ctx, isl_error_internal, + "empty component", return NULL); + + set = isl_set_universe(isl_space_copy(graph->node[i].space)); + dom = isl_union_set_from_set(set); + + for (i = i + 1; i < graph->n; ++i) { + if (!pred(&graph->node[i], data)) + continue; + set = isl_set_universe(isl_space_copy(graph->node[i].space)); + dom = isl_union_set_union(dom, isl_union_set_from_set(set)); + } + + return dom; +} + +/* Return a list of unions of universe domains, where each element + * in the list corresponds to an SCC (or WCC) indexed by node->scc. + */ +static __isl_give isl_union_set_list *extract_sccs(isl_ctx *ctx, + struct isl_sched_graph *graph) +{ + int i; + isl_union_set_list *filters; + + filters = isl_union_set_list_alloc(ctx, graph->scc); + for (i = 0; i < graph->scc; ++i) { + isl_union_set *dom; + + dom = isl_sched_graph_domain(ctx, graph, &node_scc_exactly, i); + filters = isl_union_set_list_add(filters, dom); + } + + return filters; +} + +/* Return a list of two unions of universe domains, one for the SCCs up + * to and including graph->src_scc and another for the other SCCs. + */ +static __isl_give isl_union_set_list *extract_split(isl_ctx *ctx, + struct isl_sched_graph *graph) +{ + isl_union_set *dom; + isl_union_set_list *filters; + + filters = isl_union_set_list_alloc(ctx, 2); + dom = isl_sched_graph_domain(ctx, graph, + &node_scc_at_most, graph->src_scc); + filters = isl_union_set_list_add(filters, dom); + dom = isl_sched_graph_domain(ctx, graph, + &node_scc_at_least, graph->src_scc + 1); + filters = isl_union_set_list_add(filters, dom); + + return filters; +} + +/* Copy nodes that satisfy node_pred from the src dependence graph + * to the dst dependence graph. + */ +static isl_stat 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) { + int j; + + if (!node_pred(&src->node[i], data)) + continue; + + j = dst->n; + dst->node[j].space = isl_space_copy(src->node[i].space); + dst->node[j].compressed = src->node[i].compressed; + dst->node[j].hull = isl_set_copy(src->node[i].hull); + dst->node[j].compress = + isl_multi_aff_copy(src->node[i].compress); + dst->node[j].decompress = + isl_multi_aff_copy(src->node[i].decompress); + dst->node[j].nvar = src->node[i].nvar; + dst->node[j].nparam = src->node[i].nparam; + dst->node[j].sched = isl_mat_copy(src->node[i].sched); + dst->node[j].sched_map = isl_map_copy(src->node[i].sched_map); + dst->node[j].coincident = src->node[i].coincident; + dst->node[j].sizes = isl_multi_val_copy(src->node[i].sizes); + dst->node[j].bounds = isl_basic_set_copy(src->node[i].bounds); + dst->node[j].max = isl_vec_copy(src->node[i].max); + dst->n++; + + if (!dst->node[j].space || !dst->node[j].sched) + return isl_stat_error; + if (dst->node[j].compressed && + (!dst->node[j].hull || !dst->node[j].compress || + !dst->node[j].decompress)) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Copy non-empty edges that satisfy edge_pred from the src dependence graph + * to the dst dependence graph. + * If the source or destination node of the edge is not in the destination + * graph, then it must be a backward proximity edge and it should simply + * be ignored. + */ +static isl_stat 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; + isl_union_map *tagged_condition; + isl_union_map *tagged_validity; + struct isl_sched_node *dst_src, *dst_dst; + + if (!edge_pred(edge, data)) + continue; + + if (isl_map_plain_is_empty(edge->map)) + continue; + + dst_src = graph_find_node(ctx, dst, edge->src->space); + dst_dst = graph_find_node(ctx, dst, edge->dst->space); + if (!dst_src || !dst_dst) + return isl_stat_error; + if (!is_node(dst, dst_src) || !is_node(dst, dst_dst)) { + if (is_validity(edge) || is_conditional_validity(edge)) + isl_die(ctx, isl_error_internal, + "backward (conditional) validity edge", + return isl_stat_error); + continue; + } + + map = isl_map_copy(edge->map); + tagged_condition = isl_union_map_copy(edge->tagged_condition); + tagged_validity = isl_union_map_copy(edge->tagged_validity); + + dst->edge[dst->n_edge].src = dst_src; + dst->edge[dst->n_edge].dst = dst_dst; + dst->edge[dst->n_edge].map = map; + dst->edge[dst->n_edge].tagged_condition = tagged_condition; + dst->edge[dst->n_edge].tagged_validity = tagged_validity; + dst->edge[dst->n_edge].types = edge->types; + dst->n_edge++; + + if (edge->tagged_condition && !tagged_condition) + return isl_stat_error; + if (edge->tagged_validity && !tagged_validity) + return isl_stat_error; + + if (graph_edge_tables_add(ctx, dst, + &dst->edge[dst->n_edge - 1]) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* 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_vmap(node) < 0) + return -1; + nvar = node->nvar + graph->n_row - node->rank; + if (nvar > graph->maxvar) + graph->maxvar = nvar; + } + + return 0; +} + +/* Extract the subgraph of "graph" that consists of the nodes satisfying + * "node_pred" and the edges satisfying "edge_pred" and store + * the result in "sub". + */ +static isl_stat extract_sub_graph(isl_ctx *ctx, struct isl_sched_graph *graph, + int (*node_pred)(struct isl_sched_node *node, int data), + int (*edge_pred)(struct isl_sched_edge *edge, int data), + int data, struct isl_sched_graph *sub) +{ + int i, n = 0, n_edge = 0; + int t; + + for (i = 0; i < graph->n; ++i) + if (node_pred(&graph->node[i], data)) + ++n; + for (i = 0; i < graph->n_edge; ++i) + if (edge_pred(&graph->edge[i], data)) + ++n_edge; + if (graph_alloc(ctx, sub, n, n_edge) < 0) + return isl_stat_error; + sub->root = graph->root; + if (copy_nodes(sub, graph, node_pred, data) < 0) + return isl_stat_error; + if (graph_init_table(ctx, sub) < 0) + return isl_stat_error; + for (t = 0; t <= isl_edge_last; ++t) + sub->max_edge[t] = graph->max_edge[t]; + if (graph_init_edge_tables(ctx, sub) < 0) + return isl_stat_error; + if (copy_edges(ctx, sub, graph, edge_pred, data) < 0) + return isl_stat_error; + sub->n_row = graph->n_row; + sub->max_row = graph->max_row; + sub->n_total_row = graph->n_total_row; + sub->band_start = graph->band_start; + + return isl_stat_ok; +} + +static __isl_give isl_schedule_node *compute_schedule(isl_schedule_node *node, + struct isl_sched_graph *graph); +static __isl_give isl_schedule_node *compute_schedule_wcc( + isl_schedule_node *node, 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. + * 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. + * + * The schedule is inserted at "node" and the updated schedule node + * is returned. + */ +static __isl_give isl_schedule_node *compute_sub_schedule( + __isl_take isl_schedule_node *node, isl_ctx *ctx, + struct isl_sched_graph *graph, + 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 (extract_sub_graph(ctx, graph, node_pred, edge_pred, data, + &split) < 0) + goto error; + + if (wcc) + node = compute_schedule_wcc(node, &split); + else + node = compute_schedule(node, &split); + + graph_free(ctx, &split); + return node; +error: + graph_free(ctx, &split); + return isl_schedule_node_free(node); +} + +static int edge_scc_exactly(struct isl_sched_edge *edge, int scc) +{ + return edge->src->scc == scc && edge->dst->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; +} + +/* Reset the current band by dropping all its schedule rows. + */ +static isl_stat reset_band(struct isl_sched_graph *graph) +{ + int i; + int drop; + + drop = graph->n_total_row - graph->band_start; + graph->n_total_row -= drop; + graph->n_row -= drop; + + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + + isl_map_free(node->sched_map); + node->sched_map = NULL; + + node->sched = isl_mat_drop_rows(node->sched, + graph->band_start, drop); + + if (!node->sched) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* 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 by a sequence node inserted at position "node" + * in the schedule tree. Return the updated schedule node. + * If either of these two parts consists of a sequence, then it is spliced + * into the sequence containing the two parts. + * + * The current band is reset. It would be possible to reuse + * the previously computed rows 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 __isl_give isl_schedule_node *compute_split_schedule( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + int is_seq; + isl_ctx *ctx; + isl_union_set_list *filters; + + if (!node) + return NULL; + + if (reset_band(graph) < 0) + return isl_schedule_node_free(node); + + next_band(graph); + + ctx = isl_schedule_node_get_ctx(node); + filters = extract_split(ctx, graph); + node = isl_schedule_node_insert_sequence(node, filters); + node = isl_schedule_node_child(node, 1); + node = isl_schedule_node_child(node, 0); + + node = compute_sub_schedule(node, ctx, graph, + &node_scc_at_least, &edge_src_scc_at_least, + graph->src_scc + 1, 0); + is_seq = isl_schedule_node_get_type(node) == isl_schedule_node_sequence; + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); + if (is_seq) + node = isl_schedule_node_sequence_splice_child(node, 1); + node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_child(node, 0); + node = compute_sub_schedule(node, ctx, graph, + &node_scc_at_most, &edge_dst_scc_at_most, + graph->src_scc, 0); + is_seq = isl_schedule_node_get_type(node) == isl_schedule_node_sequence; + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); + if (is_seq) + node = isl_schedule_node_sequence_splice_child(node, 0); + + return node; +} + +/* Insert a band node at position "node" in the schedule tree corresponding + * to the current band in "graph". Mark the band node permutable + * if "permutable" is set. + * The partial schedules and the coincidence property are extracted + * from the graph nodes. + * Return the updated schedule node. + */ +static __isl_give isl_schedule_node *insert_current_band( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int permutable) +{ + int i; + int start, end, n; + isl_multi_aff *ma; + isl_multi_pw_aff *mpa; + isl_multi_union_pw_aff *mupa; + + if (!node) + return NULL; + + if (graph->n < 1) + isl_die(isl_schedule_node_get_ctx(node), isl_error_internal, + "graph should have at least one node", + return isl_schedule_node_free(node)); + + start = graph->band_start; + end = graph->n_total_row; + n = end - start; + + ma = node_extract_partial_schedule_multi_aff(&graph->node[0], start, n); + mpa = isl_multi_pw_aff_from_multi_aff(ma); + mupa = isl_multi_union_pw_aff_from_multi_pw_aff(mpa); + + for (i = 1; i < graph->n; ++i) { + isl_multi_union_pw_aff *mupa_i; + + ma = node_extract_partial_schedule_multi_aff(&graph->node[i], + start, n); + mpa = isl_multi_pw_aff_from_multi_aff(ma); + mupa_i = isl_multi_union_pw_aff_from_multi_pw_aff(mpa); + mupa = isl_multi_union_pw_aff_union_add(mupa, mupa_i); + } + node = isl_schedule_node_insert_partial_schedule(node, mupa); + + for (i = 0; i < n; ++i) + node = isl_schedule_node_band_member_set_coincident(node, i, + graph->node[0].coincident[start + i]); + node = isl_schedule_node_band_set_permutable(node, permutable); + + return node; +} + +/* Update the dependence relations based on the current schedule, + * add the current band to "node" and then continue with the computation + * of the next band. + * Return the updated schedule node. + */ +static __isl_give isl_schedule_node *compute_next_band( + __isl_take isl_schedule_node *node, + struct isl_sched_graph *graph, int permutable) +{ + isl_ctx *ctx; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); + if (update_edges(ctx, graph) < 0) + return isl_schedule_node_free(node); + node = insert_current_band(node, graph, permutable); + next_band(graph); + + node = isl_schedule_node_child(node, 0); + node = compute_schedule(node, graph); + node = isl_schedule_node_parent(node); + + return node; +} + +/* Add the constraints "coef" derived from an edge from "node" to itself + * to graph->lp in order to respect the dependences and to try and carry them. + * "pos" is the sequence number of the edge that needs to be carried. + * "coef" represents general constraints on coefficients (c_0, c_x) + * of valid constraints for (y - x) with x and y instances of the node. + * + * The constraints added to graph->lp need to enforce + * + * (c_j_0 + c_j_x y) - (c_j_0 + c_j_x x) + * = c_j_x (y - x) >= e_i + * + * for each (x,y) in the dependence relation of the edge. + * That is, (-e_i, c_j_x) needs to be plugged in for (c_0, c_x), + * taking into account that each coefficient in c_j_x is represented + * as a pair of non-negative coefficients. + */ +static isl_stat add_intra_constraints(struct isl_sched_graph *graph, + struct isl_sched_node *node, __isl_take isl_basic_set *coef, int pos) +{ + int offset; + isl_ctx *ctx; + isl_dim_map *dim_map; + + if (!coef) + return isl_stat_error; + + ctx = isl_basic_set_get_ctx(coef); + offset = coef_var_offset(coef); + dim_map = intra_dim_map(ctx, graph, node, offset, 1); + isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1); + graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map); + + return isl_stat_ok; +} + +/* Add the constraints "coef" derived from an edge from "src" to "dst" + * to graph->lp in order to respect the dependences and to try and carry them. + * "pos" is the sequence number of the edge that needs to be carried or + * -1 if no attempt should be made to carry the dependences. + * "coef" represents general constraints on coefficients (c_0, c_n, c_x, c_y) + * of valid constraints for (x, y) with x and y instances of "src" and "dst". + * + * The constraints added to graph->lp need to 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 the dependence relation of the edge or + * + * (c_k_0 + c_k_n n + c_k_x y) - (c_j_0 + c_j_n n + c_j_x x) >= 0 + * + * if pos is -1. + * That is, + * (-e_i + c_k_0 - c_j_0, c_k_n - c_j_n, -c_j_x, c_k_x) + * or + * (c_k_0 - c_j_0, c_k_n - c_j_n, -c_j_x, c_k_x) + * needs to be plugged in for (c_0, c_n, c_x, c_y), + * taking into account that each coefficient in c_j_x and c_k_x is represented + * as a pair of non-negative coefficients. + */ +static isl_stat add_inter_constraints(struct isl_sched_graph *graph, + struct isl_sched_node *src, struct isl_sched_node *dst, + __isl_take isl_basic_set *coef, int pos) +{ + int offset; + isl_ctx *ctx; + isl_dim_map *dim_map; + + if (!coef) + return isl_stat_error; + + ctx = isl_basic_set_get_ctx(coef); + offset = coef_var_offset(coef); + dim_map = inter_dim_map(ctx, graph, src, dst, offset, 1); + if (pos >= 0) + isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1); + graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map); + + return isl_stat_ok; +} + +/* Data structure for keeping track of the data needed + * to exploit non-trivial lineality spaces. + * + * "any_non_trivial" is true if there are any non-trivial lineality spaces. + * If "any_non_trivial" is not true, then "equivalent" and "mask" may be NULL. + * "equivalent" connects instances to other instances on the same line(s). + * "mask" contains the domain spaces of "equivalent". + * Any instance set not in "mask" does not have a non-trivial lineality space. + */ +struct isl_exploit_lineality_data { + isl_bool any_non_trivial; + isl_union_map *equivalent; + isl_union_set *mask; +}; + +/* Data structure collecting information used during the construction + * of an LP for carrying dependences. + * + * "intra" is a sequence of coefficient constraints for intra-node edges. + * "inter" is a sequence of coefficient constraints for inter-node edges. + * "lineality" contains data used to exploit non-trivial lineality spaces. + */ +struct isl_carry { + isl_basic_set_list *intra; + isl_basic_set_list *inter; + struct isl_exploit_lineality_data lineality; +}; + +/* Free all the data stored in "carry". + */ +static void isl_carry_clear(struct isl_carry *carry) +{ + isl_basic_set_list_free(carry->intra); + isl_basic_set_list_free(carry->inter); + isl_union_map_free(carry->lineality.equivalent); + isl_union_set_free(carry->lineality.mask); +} + +/* Return a pointer to the node in "graph" that lives in "space". + * If the requested node has been compressed, then "space" + * corresponds to the compressed space. + * The graph is assumed to have such a node. + * Return NULL in case of error. + * + * First try and see if "space" is the space of an uncompressed node. + * If so, return that node. + * Otherwise, "space" was constructed by construct_compressed_id and + * contains a user pointer pointing to the node in the tuple id. + * However, this node belongs to the original dependence graph. + * If "graph" is a subgraph of this original dependence graph, + * then the node with the same space still needs to be looked up + * in the current graph. + */ +static struct isl_sched_node *graph_find_compressed_node(isl_ctx *ctx, + struct isl_sched_graph *graph, __isl_keep isl_space *space) +{ + isl_id *id; + struct isl_sched_node *node; + + if (!space) + return NULL; + + node = graph_find_node(ctx, graph, space); + if (!node) + return NULL; + if (is_node(graph, node)) + return node; + + id = isl_space_get_tuple_id(space, isl_dim_set); + node = isl_id_get_user(id); + isl_id_free(id); + + if (!node) + return NULL; + + if (!is_node(graph->root, node)) + isl_die(ctx, isl_error_internal, + "space points to invalid node", return NULL); + if (graph != graph->root) + node = graph_find_node(ctx, graph, node->space); + if (!is_node(graph, node)) + isl_die(ctx, isl_error_internal, + "unable to find node", return NULL); + + return node; +} + +/* Internal data structure for add_all_constraints. + * + * "graph" is the schedule constraint graph for which an LP problem + * is being constructed. + * "carry_inter" indicates whether inter-node edges should be carried. + * "pos" is the position of the next edge that needs to be carried. + */ +struct isl_add_all_constraints_data { + isl_ctx *ctx; + struct isl_sched_graph *graph; + int carry_inter; + int pos; +}; + +/* Add the constraints "coef" derived from an edge from a node to itself + * to data->graph->lp in order to respect the dependences and + * to try and carry them. + * + * The space of "coef" is of the form + * + * coefficients[[c_cst] -> S[c_x]] + * + * with S[c_x] the (compressed) space of the node. + * Extract the node from the space and call add_intra_constraints. + */ +static isl_stat lp_add_intra(__isl_take isl_basic_set *coef, void *user) +{ + struct isl_add_all_constraints_data *data = user; + isl_space *space; + struct isl_sched_node *node; + + space = isl_basic_set_get_space(coef); + space = isl_space_range(isl_space_unwrap(space)); + node = graph_find_compressed_node(data->ctx, data->graph, space); + isl_space_free(space); + return add_intra_constraints(data->graph, node, coef, data->pos++); +} + +/* Add the constraints "coef" derived from an edge from a node j + * to a node k to data->graph->lp in order to respect the dependences and + * to try and carry them (provided data->carry_inter is set). + * + * The space of "coef" is of the form + * + * coefficients[[c_cst, c_n] -> [S_j[c_x] -> S_k[c_y]]] + * + * with S_j[c_x] and S_k[c_y] the (compressed) spaces of the nodes. + * Extract the nodes from the space and call add_inter_constraints. + */ +static isl_stat lp_add_inter(__isl_take isl_basic_set *coef, void *user) +{ + struct isl_add_all_constraints_data *data = user; + isl_space *space, *dom; + struct isl_sched_node *src, *dst; + int pos; + + space = isl_basic_set_get_space(coef); + space = isl_space_unwrap(isl_space_range(isl_space_unwrap(space))); + dom = isl_space_domain(isl_space_copy(space)); + src = graph_find_compressed_node(data->ctx, data->graph, dom); + isl_space_free(dom); + space = isl_space_range(space); + dst = graph_find_compressed_node(data->ctx, data->graph, space); + isl_space_free(space); + + pos = data->carry_inter ? data->pos++ : -1; + return add_inter_constraints(data->graph, src, dst, coef, pos); +} + +/* Add constraints to graph->lp that force all (conditional) validity + * dependences to be respected and attempt to carry them. + * "intra" is the sequence of coefficient constraints for intra-node edges. + * "inter" is the sequence of coefficient constraints for inter-node edges. + * "carry_inter" indicates whether inter-node edges should be carried or + * only respected. + */ +static isl_stat add_all_constraints(isl_ctx *ctx, struct isl_sched_graph *graph, + __isl_keep isl_basic_set_list *intra, + __isl_keep isl_basic_set_list *inter, int carry_inter) +{ + struct isl_add_all_constraints_data data = { ctx, graph, carry_inter }; + + data.pos = 0; + if (isl_basic_set_list_foreach(intra, &lp_add_intra, &data) < 0) + return isl_stat_error; + if (isl_basic_set_list_foreach(inter, &lp_add_inter, &data) < 0) + return isl_stat_error; + return isl_stat_ok; +} + +/* Internal data structure for count_all_constraints + * for keeping track of the number of equality and inequality constraints. + */ +struct isl_sched_count { + int n_eq; + int n_ineq; +}; + +/* Add the number of equality and inequality constraints of "bset" + * to data->n_eq and data->n_ineq. + */ +static isl_stat bset_update_count(__isl_take isl_basic_set *bset, void *user) +{ + struct isl_sched_count *data = user; + + return update_count(bset, 1, &data->n_eq, &data->n_ineq); +} + +/* Count the number of equality and inequality constraints + * that will be added to the carry_lp problem. + * We count each edge exactly once. + * "intra" is the sequence of coefficient constraints for intra-node edges. + * "inter" is the sequence of coefficient constraints for inter-node edges. + */ +static isl_stat count_all_constraints(__isl_keep isl_basic_set_list *intra, + __isl_keep isl_basic_set_list *inter, int *n_eq, int *n_ineq) +{ + struct isl_sched_count data; + + data.n_eq = data.n_ineq = 0; + if (isl_basic_set_list_foreach(inter, &bset_update_count, &data) < 0) + return isl_stat_error; + if (isl_basic_set_list_foreach(intra, &bset_update_count, &data) < 0) + return isl_stat_error; + + *n_eq = data.n_eq; + *n_ineq = data.n_ineq; + + return isl_stat_ok; +} + +/* Construct an LP problem for finding schedule coefficients + * such that the schedule carries as many validity 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. Dependences with e_i = 0 in the solution are simply + * respected, while those with e_i > 0 (in practice e_i = 1) are carried. + * "intra" is the sequence of coefficient constraints for intra-node edges. + * "inter" is the sequence of coefficient constraints for inter-node edges. + * "n_edge" is the total number of edges. + * "carry_inter" indicates whether inter-node edges should be carried or + * only respected. That is, if "carry_inter" is not set, then + * no e_i variables are introduced for the inter-node edges. + * + * 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 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 + * - positive and negative parts of c_i_x, in opposite order + * - c_i_n (if parametric) + * - c_i_0 + * + * The constraints are those from the (validity) edges plus three equalities + * to express the sums and n_edge inequalities to express e_i <= 1. + */ +static isl_stat setup_carry_lp(isl_ctx *ctx, struct isl_sched_graph *graph, + int n_edge, __isl_keep isl_basic_set_list *intra, + __isl_keep isl_basic_set_list *inter, int carry_inter) +{ + int i; + int k; + isl_space *dim; + unsigned total; + int n_eq, n_ineq; + + total = 3 + n_edge; + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[graph->sorted[i]]; + node->start = total; + total += 1 + node->nparam + 2 * node->nvar; + } + + if (count_all_constraints(intra, inter, &n_eq, &n_ineq) < 0) + return isl_stat_error; + + dim = isl_space_set_alloc(ctx, 0, total); + isl_basic_set_free(graph->lp); + n_eq += 3; + n_ineq += n_edge; + graph->lp = isl_basic_set_alloc_space(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 isl_stat_error; + isl_seq_clr(graph->lp->eq[k], 1 + total); + isl_int_set_si(graph->lp->eq[k][0], -n_edge); + isl_int_set_si(graph->lp->eq[k][1], 1); + for (i = 0; i < n_edge; ++i) + isl_int_set_si(graph->lp->eq[k][4 + i], 1); + + if (add_param_sum_constraint(graph, 1) < 0) + return isl_stat_error; + if (add_var_sum_constraint(graph, 2) < 0) + return isl_stat_error; + + for (i = 0; i < n_edge; ++i) { + k = isl_basic_set_alloc_inequality(graph->lp); + if (k < 0) + return isl_stat_error; + 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(ctx, graph, intra, inter, carry_inter) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +static __isl_give isl_schedule_node *compute_component_schedule( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int wcc); + +/* If the schedule_split_scaled option is set and if the linear + * parts of the scheduling rows for all nodes in the graphs have + * a non-trivial common divisor, then remove this + * common divisor from the linear part. + * Otherwise, insert a band node directly and continue with + * the construction of the schedule. + * + * If a non-trivial common divisor is found, then + * the linear part is reduced and the remainder is ignored. + * The pieces of the graph that are assigned different remainders + * form (groups of) strongly connected components within + * the scaled down band. If needed, they can therefore + * be ordered along this remainder in a sequence node. + * However, this ordering is not enforced here in order to allow + * the scheduler to combine some of the strongly connected components. + */ +static __isl_give isl_schedule_node *split_scaled( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + int i; + int row; + isl_ctx *ctx; + isl_int gcd, gcd_i; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); + if (!ctx->opt->schedule_split_scaled) + return compute_next_band(node, graph, 0); + if (graph->n <= 1) + return compute_next_band(node, graph, 0); + + isl_int_init(gcd); + isl_int_init(gcd_i); + + isl_int_set_si(gcd, 0); + + row = isl_mat_rows(graph->node[0].sched) - 1; + + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + int cols = isl_mat_cols(node->sched); + + isl_seq_gcd(node->sched->row[row] + 1, cols - 1, &gcd_i); + isl_int_gcd(gcd, gcd, gcd_i); + } + + isl_int_clear(gcd_i); + + if (isl_int_cmp_si(gcd, 1) <= 0) { + isl_int_clear(gcd); + return compute_next_band(node, graph, 0); + } + + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + + isl_int_fdiv_q(node->sched->row[row][0], + node->sched->row[row][0], gcd); + isl_int_mul(node->sched->row[row][0], + node->sched->row[row][0], gcd); + node->sched = isl_mat_scale_down_row(node->sched, row, gcd); + if (!node->sched) + goto error; + } + + isl_int_clear(gcd); + + return compute_next_band(node, graph, 0); +error: + isl_int_clear(gcd); + return isl_schedule_node_free(node); +} + +/* Is the schedule row "sol" trivial on node "node"? + * That is, is the solution zero on the dimensions linearly independent of + * the previously found solutions? + * Return 1 if the solution is trivial, 0 if it is not and -1 on error. + * + * Each coefficient is represented as the difference between + * two non-negative values in "sol". + * We construct the schedule row s and check if it is linearly + * independent of previously computed schedule rows + * by computing T s, with T the linear combinations that are zero + * on linearly dependent schedule rows. + * If the result consists of all zeros, then the solution is trivial. + */ +static int is_trivial(struct isl_sched_node *node, __isl_keep isl_vec *sol) +{ + int trivial; + isl_vec *node_sol; + + if (!sol) + return -1; + if (node->nvar == node->rank) + return 0; + + node_sol = extract_var_coef(node, sol); + node_sol = isl_mat_vec_product(isl_mat_copy(node->indep), node_sol); + if (!node_sol) + return -1; + + trivial = isl_seq_first_non_zero(node_sol->el, + node->nvar - node->rank) == -1; + + isl_vec_free(node_sol); + + return trivial; +} + +/* Is the schedule row "sol" trivial on any node where it should + * not be trivial? + * Return 1 if any solution is trivial, 0 if they are not and -1 on error. + */ +static int is_any_trivial(struct isl_sched_graph *graph, + __isl_keep isl_vec *sol) +{ + int i; + + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + int trivial; + + if (!needs_row(graph, node)) + continue; + trivial = is_trivial(node, sol); + if (trivial < 0 || trivial) + return trivial; + } + + return 0; +} + +/* Does the schedule represented by "sol" perform loop coalescing on "node"? + * If so, return the position of the coalesced dimension. + * Otherwise, return node->nvar or -1 on error. + * + * In particular, look for pairs of coefficients c_i and c_j such that + * |c_j/c_i| > ceil(size_i/2), i.e., |c_j| > |c_i * ceil(size_i/2)|. + * If any such pair is found, then return i. + * If size_i is infinity, then no check on c_i needs to be performed. + */ +static int find_node_coalescing(struct isl_sched_node *node, + __isl_keep isl_vec *sol) +{ + int i, j; + isl_int max; + isl_vec *csol; + + if (node->nvar <= 1) + return node->nvar; + + csol = extract_var_coef(node, sol); + if (!csol) + return -1; + isl_int_init(max); + for (i = 0; i < node->nvar; ++i) { + isl_val *v; + + if (isl_int_is_zero(csol->el[i])) + continue; + v = isl_multi_val_get_val(node->sizes, i); + if (!v) + goto error; + if (!isl_val_is_int(v)) { + isl_val_free(v); + continue; + } + v = isl_val_div_ui(v, 2); + v = isl_val_ceil(v); + if (!v) + goto error; + isl_int_mul(max, v->n, csol->el[i]); + isl_val_free(v); + + for (j = 0; j < node->nvar; ++j) { + if (j == i) + continue; + if (isl_int_abs_gt(csol->el[j], max)) + break; + } + if (j < node->nvar) + break; + } + + isl_int_clear(max); + isl_vec_free(csol); + return i; +error: + isl_int_clear(max); + isl_vec_free(csol); + return -1; +} + +/* Force the schedule coefficient at position "pos" of "node" to be zero + * in "tl". + * The coefficient is encoded as the difference between two non-negative + * variables. Force these two variables to have the same value. + */ +static __isl_give isl_tab_lexmin *zero_out_node_coef( + __isl_take isl_tab_lexmin *tl, struct isl_sched_node *node, int pos) +{ + int dim; + isl_ctx *ctx; + isl_vec *eq; + + ctx = isl_space_get_ctx(node->space); + dim = isl_tab_lexmin_dim(tl); + if (dim < 0) + return isl_tab_lexmin_free(tl); + eq = isl_vec_alloc(ctx, 1 + dim); + eq = isl_vec_clr(eq); + if (!eq) + return isl_tab_lexmin_free(tl); + + pos = 1 + node_var_coef_pos(node, pos); + isl_int_set_si(eq->el[pos], 1); + isl_int_set_si(eq->el[pos + 1], -1); + tl = isl_tab_lexmin_add_eq(tl, eq->el); + isl_vec_free(eq); + + return tl; +} + +/* Return the lexicographically smallest rational point in the basic set + * from which "tl" was constructed, double checking that this input set + * was not empty. + */ +static __isl_give isl_vec *non_empty_solution(__isl_keep isl_tab_lexmin *tl) +{ + isl_vec *sol; + + sol = isl_tab_lexmin_get_solution(tl); + if (!sol) + return NULL; + if (sol->size == 0) + isl_die(isl_vec_get_ctx(sol), isl_error_internal, + "error in schedule construction", + return isl_vec_free(sol)); + return sol; +} + +/* Does the solution "sol" of the LP problem constructed by setup_carry_lp + * carry any of the "n_edge" groups of dependences? + * The value in the first position is the sum of (1 - e_i) over all "n_edge" + * edges, with 0 <= e_i <= 1 equal to 1 when the dependences represented + * by the edge are carried by the solution. + * If the sum of the (1 - e_i) is smaller than "n_edge" then at least + * one of those is carried. + * + * Note that despite the fact that the problem is solved using a rational + * solver, the solution is guaranteed to be integral. + * Specifically, the dependence distance lower bounds e_i (and therefore + * also their sum) are integers. See Lemma 5 of [1]. + * + * Any potential denominator of the sum is cleared by this function. + * The denominator is not relevant for any of the other elements + * in the solution. + * + * [1] P. Feautrier, Some Efficient Solutions to the Affine Scheduling + * Problem, Part II: Multi-Dimensional Time. + * In Intl. Journal of Parallel Programming, 1992. + */ +static int carries_dependences(__isl_keep isl_vec *sol, int n_edge) +{ + isl_int_divexact(sol->el[1], sol->el[1], sol->el[0]); + isl_int_set_si(sol->el[0], 1); + return isl_int_cmp_si(sol->el[1], n_edge) < 0; +} + +/* Return the lexicographically smallest rational point in "lp", + * assuming that all variables are non-negative and performing some + * additional sanity checks. + * If "want_integral" is set, then compute the lexicographically smallest + * integer point instead. + * In particular, "lp" should not be empty by construction. + * Double check that this is the case. + * If dependences are not carried for any of the "n_edge" edges, + * then return an empty vector. + * + * If the schedule_treat_coalescing option is set and + * if the computed schedule performs loop coalescing on a given node, + * i.e., if it is of the form + * + * c_i i + c_j j + ... + * + * with |c_j/c_i| >= size_i, then force the coefficient c_i to be zero + * to cut out this solution. Repeat this process until no more loop + * coalescing occurs or until no more dependences can be carried. + * In the latter case, revert to the previously computed solution. + * + * If the caller requests an integral solution and if coalescing should + * be treated, then perform the coalescing treatment first as + * an integral solution computed before coalescing treatment + * would carry the same number of edges and would therefore probably + * also be coalescing. + * + * To allow the coalescing treatment to be performed first, + * the initial solution is allowed to be rational and it is only + * cut out (if needed) in the next iteration, if no coalescing measures + * were taken. + */ +static __isl_give isl_vec *non_neg_lexmin(struct isl_sched_graph *graph, + __isl_take isl_basic_set *lp, int n_edge, int want_integral) +{ + int i, pos, cut; + isl_ctx *ctx; + isl_tab_lexmin *tl; + isl_vec *sol = NULL, *prev; + int treat_coalescing; + int try_again; + + if (!lp) + return NULL; + ctx = isl_basic_set_get_ctx(lp); + treat_coalescing = isl_options_get_schedule_treat_coalescing(ctx); + tl = isl_tab_lexmin_from_basic_set(lp); + + cut = 0; + do { + int integral; + + try_again = 0; + if (cut) + tl = isl_tab_lexmin_cut_to_integer(tl); + prev = sol; + sol = non_empty_solution(tl); + if (!sol) + goto error; + + integral = isl_int_is_one(sol->el[0]); + if (!carries_dependences(sol, n_edge)) { + if (!prev) + prev = isl_vec_alloc(ctx, 0); + isl_vec_free(sol); + sol = prev; + break; + } + prev = isl_vec_free(prev); + cut = want_integral && !integral; + if (cut) + try_again = 1; + if (!treat_coalescing) + continue; + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + + pos = find_node_coalescing(node, sol); + if (pos < 0) + goto error; + if (pos < node->nvar) + break; + } + if (i < graph->n) { + try_again = 1; + tl = zero_out_node_coef(tl, &graph->node[i], pos); + cut = 0; + } + } while (try_again); + + isl_tab_lexmin_free(tl); + + return sol; +error: + isl_tab_lexmin_free(tl); + isl_vec_free(prev); + isl_vec_free(sol); + return NULL; +} + +/* If "edge" is an edge from a node to itself, then add the corresponding + * dependence relation to "umap". + * If "node" has been compressed, then the dependence relation + * is also compressed first. + */ +static __isl_give isl_union_map *add_intra(__isl_take isl_union_map *umap, + struct isl_sched_edge *edge) +{ + isl_map *map; + struct isl_sched_node *node = edge->src; + + if (edge->src != edge->dst) + return umap; + + map = isl_map_copy(edge->map); + if (node->compressed) { + map = isl_map_preimage_domain_multi_aff(map, + isl_multi_aff_copy(node->decompress)); + map = isl_map_preimage_range_multi_aff(map, + isl_multi_aff_copy(node->decompress)); + } + umap = isl_union_map_add_map(umap, map); + return umap; +} + +/* If "edge" is an edge from a node to another node, then add the corresponding + * dependence relation to "umap". + * If the source or destination nodes of "edge" have been compressed, + * then the dependence relation is also compressed first. + */ +static __isl_give isl_union_map *add_inter(__isl_take isl_union_map *umap, + struct isl_sched_edge *edge) +{ + isl_map *map; + + if (edge->src == edge->dst) + return umap; + + map = isl_map_copy(edge->map); + if (edge->src->compressed) + map = isl_map_preimage_domain_multi_aff(map, + isl_multi_aff_copy(edge->src->decompress)); + if (edge->dst->compressed) + map = isl_map_preimage_range_multi_aff(map, + isl_multi_aff_copy(edge->dst->decompress)); + umap = isl_union_map_add_map(umap, map); + return umap; +} + +/* Internal data structure used by union_drop_coalescing_constraints + * to collect bounds on all relevant statements. + * + * "graph" is the schedule constraint graph for which an LP problem + * is being constructed. + * "bounds" collects the bounds. + */ +struct isl_collect_bounds_data { + isl_ctx *ctx; + struct isl_sched_graph *graph; + isl_union_set *bounds; +}; + +/* Add the size bounds for the node with instance deltas in "set" + * to data->bounds. + */ +static isl_stat collect_bounds(__isl_take isl_set *set, void *user) +{ + struct isl_collect_bounds_data *data = user; + struct isl_sched_node *node; + isl_space *space; + isl_set *bounds; + + space = isl_set_get_space(set); + isl_set_free(set); + + node = graph_find_compressed_node(data->ctx, data->graph, space); + isl_space_free(space); + + bounds = isl_set_from_basic_set(get_size_bounds(node)); + data->bounds = isl_union_set_add_set(data->bounds, bounds); + + return isl_stat_ok; +} + +/* Drop some constraints from "delta" that could be exploited + * to construct loop coalescing schedules. + * In particular, drop those constraint that bound the difference + * to the size of the domain. + * Do this for each set/node in "delta" separately. + * The parameters are assumed to have been projected out by the caller. + */ +static __isl_give isl_union_set *union_drop_coalescing_constraints(isl_ctx *ctx, + struct isl_sched_graph *graph, __isl_take isl_union_set *delta) +{ + struct isl_collect_bounds_data data = { ctx, graph }; + + data.bounds = isl_union_set_empty(isl_space_params_alloc(ctx, 0)); + if (isl_union_set_foreach_set(delta, &collect_bounds, &data) < 0) + data.bounds = isl_union_set_free(data.bounds); + delta = isl_union_set_plain_gist(delta, data.bounds); + + return delta; +} + +/* Given a non-trivial lineality space "lineality", add the corresponding + * universe set to data->mask and add a map from elements to + * other elements along the lines in "lineality" to data->equivalent. + * If this is the first time this function gets called + * (data->any_non_trivial is still false), then set data->any_non_trivial and + * initialize data->mask and data->equivalent. + * + * In particular, if the lineality space is defined by equality constraints + * + * E x = 0 + * + * then construct an affine mapping + * + * f : x -> E x + * + * and compute the equivalence relation of having the same image under f: + * + * { x -> x' : E x = E x' } + */ +static isl_stat add_non_trivial_lineality(__isl_take isl_basic_set *lineality, + struct isl_exploit_lineality_data *data) +{ + isl_mat *eq; + isl_space *space; + isl_set *univ; + isl_multi_aff *ma; + isl_multi_pw_aff *mpa; + isl_map *map; + int n; + + if (!lineality) + return isl_stat_error; + if (isl_basic_set_dim(lineality, isl_dim_div) != 0) + isl_die(isl_basic_set_get_ctx(lineality), isl_error_internal, + "local variables not allowed", goto error); + + space = isl_basic_set_get_space(lineality); + if (!data->any_non_trivial) { + data->equivalent = isl_union_map_empty(isl_space_copy(space)); + data->mask = isl_union_set_empty(isl_space_copy(space)); + } + data->any_non_trivial = isl_bool_true; + + univ = isl_set_universe(isl_space_copy(space)); + data->mask = isl_union_set_add_set(data->mask, univ); + + eq = isl_basic_set_extract_equalities(lineality); + n = isl_mat_rows(eq); + eq = isl_mat_insert_zero_rows(eq, 0, 1); + eq = isl_mat_set_element_si(eq, 0, 0, 1); + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, n); + ma = isl_multi_aff_from_aff_mat(space, eq); + mpa = isl_multi_pw_aff_from_multi_aff(ma); + map = isl_multi_pw_aff_eq_map(mpa, isl_multi_pw_aff_copy(mpa)); + data->equivalent = isl_union_map_add_map(data->equivalent, map); + + isl_basic_set_free(lineality); + return isl_stat_ok; +error: + isl_basic_set_free(lineality); + return isl_stat_error; +} + +/* Check if the lineality space "set" is non-trivial (i.e., is not just + * the origin or, in other words, satisfies a number of equality constraints + * that is smaller than the dimension of the set). + * If so, extend data->mask and data->equivalent accordingly. + * + * The input should not have any local variables already, but + * isl_set_remove_divs is called to make sure it does not. + */ +static isl_stat add_lineality(__isl_take isl_set *set, void *user) +{ + struct isl_exploit_lineality_data *data = user; + isl_basic_set *hull; + int dim, n_eq; + + set = isl_set_remove_divs(set); + hull = isl_set_unshifted_simple_hull(set); + dim = isl_basic_set_dim(hull, isl_dim_set); + n_eq = isl_basic_set_n_equality(hull); + if (!hull) + return isl_stat_error; + if (dim != n_eq) + return add_non_trivial_lineality(hull, data); + isl_basic_set_free(hull); + return isl_stat_ok; +} + +/* Check if the difference set on intra-node schedule constraints "intra" + * has any non-trivial lineality space. + * If so, then extend the difference set to a difference set + * on equivalent elements. That is, if "intra" is + * + * { y - x : (x,y) \in V } + * + * and elements are equivalent if they have the same image under f, + * then return + * + * { y' - x' : (x,y) \in V and f(x) = f(x') and f(y) = f(y') } + * + * or, since f is linear, + * + * { y' - x' : (x,y) \in V and f(y - x) = f(y' - x') } + * + * The results of the search for non-trivial lineality spaces is stored + * in "data". + */ +static __isl_give isl_union_set *exploit_intra_lineality( + __isl_take isl_union_set *intra, + struct isl_exploit_lineality_data *data) +{ + isl_union_set *lineality; + isl_union_set *uset; + + data->any_non_trivial = isl_bool_false; + lineality = isl_union_set_copy(intra); + lineality = isl_union_set_combined_lineality_space(lineality); + if (isl_union_set_foreach_set(lineality, &add_lineality, data) < 0) + data->any_non_trivial = isl_bool_error; + isl_union_set_free(lineality); + + if (data->any_non_trivial < 0) + return isl_union_set_free(intra); + if (!data->any_non_trivial) + return intra; + + uset = isl_union_set_copy(intra); + intra = isl_union_set_subtract(intra, isl_union_set_copy(data->mask)); + uset = isl_union_set_apply(uset, isl_union_map_copy(data->equivalent)); + intra = isl_union_set_union(intra, uset); + + intra = isl_union_set_remove_divs(intra); + + return intra; +} + +/* If the difference set on intra-node schedule constraints was found to have + * any non-trivial lineality space by exploit_intra_lineality, + * as recorded in "data", then extend the inter-node + * schedule constraints "inter" to schedule constraints on equivalent elements. + * That is, if "inter" is V and + * elements are equivalent if they have the same image under f, then return + * + * { (x', y') : (x,y) \in V and f(x) = f(x') and f(y) = f(y') } + */ +static __isl_give isl_union_map *exploit_inter_lineality( + __isl_take isl_union_map *inter, + struct isl_exploit_lineality_data *data) +{ + isl_union_map *umap; + + if (data->any_non_trivial < 0) + return isl_union_map_free(inter); + if (!data->any_non_trivial) + return inter; + + umap = isl_union_map_copy(inter); + inter = isl_union_map_subtract_range(inter, + isl_union_set_copy(data->mask)); + umap = isl_union_map_apply_range(umap, + isl_union_map_copy(data->equivalent)); + inter = isl_union_map_union(inter, umap); + umap = isl_union_map_copy(inter); + inter = isl_union_map_subtract_domain(inter, + isl_union_set_copy(data->mask)); + umap = isl_union_map_apply_range(isl_union_map_copy(data->equivalent), + umap); + inter = isl_union_map_union(inter, umap); + + inter = isl_union_map_remove_divs(inter); + + return inter; +} + +/* For each (conditional) validity edge in "graph", + * add the corresponding dependence relation using "add" + * to a collection of dependence relations and return the result. + * If "coincidence" is set, then coincidence edges are considered as well. + */ +static __isl_give isl_union_map *collect_validity(struct isl_sched_graph *graph, + __isl_give isl_union_map *(*add)(__isl_take isl_union_map *umap, + struct isl_sched_edge *edge), int coincidence) +{ + int i; + isl_space *space; + isl_union_map *umap; + + space = isl_space_copy(graph->node[0].space); + umap = isl_union_map_empty(space); + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + + if (!is_any_validity(edge) && + (!coincidence || !is_coincidence(edge))) + continue; + + umap = add(umap, edge); + } + + return umap; +} + +/* Project out all parameters from "uset" and return the result. + */ +static __isl_give isl_union_set *union_set_drop_parameters( + __isl_take isl_union_set *uset) +{ + unsigned nparam; + + nparam = isl_union_set_dim(uset, isl_dim_param); + return isl_union_set_project_out(uset, isl_dim_param, 0, nparam); +} + +/* For each dependence relation on a (conditional) validity edge + * from a node to itself, + * construct the set of coefficients of valid constraints for elements + * in that dependence relation and collect the results. + * If "coincidence" is set, then coincidence edges are considered as well. + * + * In particular, for each dependence relation R, constraints + * on coefficients (c_0, c_x) are constructed such that + * + * c_0 + c_x d >= 0 for each d in delta R = { y - x | (x,y) in R } + * + * If the schedule_treat_coalescing option is set, then some constraints + * that could be exploited to construct coalescing schedules + * are removed before the dual is computed, but after the parameters + * have been projected out. + * The entire computation is essentially the same as that performed + * by intra_coefficients, except that it operates on multiple + * edges together and that the parameters are always projected out. + * + * Additionally, exploit any non-trivial lineality space + * in the difference set after removing coalescing constraints and + * store the results of the non-trivial lineality space detection in "data". + * The procedure is currently run unconditionally, but it is unlikely + * to find any non-trivial lineality spaces if no coalescing constraints + * have been removed. + * + * Note that if a dependence relation is a union of basic maps, + * then each basic map needs to be treated individually as it may only + * be possible to carry the dependences expressed by some of those + * basic maps and not all of them. + * The collected validity constraints are therefore not coalesced and + * it is assumed that they are not coalesced automatically. + * Duplicate basic maps can be removed, however. + * In particular, if the same basic map appears as a disjunct + * in multiple edges, then it only needs to be carried once. + */ +static __isl_give isl_basic_set_list *collect_intra_validity(isl_ctx *ctx, + struct isl_sched_graph *graph, int coincidence, + struct isl_exploit_lineality_data *data) +{ + isl_union_map *intra; + isl_union_set *delta; + isl_basic_set_list *list; + + intra = collect_validity(graph, &add_intra, coincidence); + delta = isl_union_map_deltas(intra); + delta = union_set_drop_parameters(delta); + delta = isl_union_set_remove_divs(delta); + if (isl_options_get_schedule_treat_coalescing(ctx)) + delta = union_drop_coalescing_constraints(ctx, graph, delta); + delta = exploit_intra_lineality(delta, data); + list = isl_union_set_get_basic_set_list(delta); + isl_union_set_free(delta); + + return isl_basic_set_list_coefficients(list); +} + +/* For each dependence relation on a (conditional) validity edge + * from a node to some other node, + * construct the set of coefficients of valid constraints for elements + * in that dependence relation and collect the results. + * If "coincidence" is set, then coincidence edges are considered as well. + * + * In particular, for each dependence relation R, constraints + * on coefficients (c_0, c_n, c_x, c_y) are constructed such that + * + * c_0 + c_n n + c_x x + c_y y >= 0 for each (x,y) in R + * + * This computation is essentially the same as that performed + * by inter_coefficients, except that it operates on multiple + * edges together. + * + * Additionally, exploit any non-trivial lineality space + * that may have been discovered by collect_intra_validity + * (as stored in "data"). + * + * Note that if a dependence relation is a union of basic maps, + * then each basic map needs to be treated individually as it may only + * be possible to carry the dependences expressed by some of those + * basic maps and not all of them. + * The collected validity constraints are therefore not coalesced and + * it is assumed that they are not coalesced automatically. + * Duplicate basic maps can be removed, however. + * In particular, if the same basic map appears as a disjunct + * in multiple edges, then it only needs to be carried once. + */ +static __isl_give isl_basic_set_list *collect_inter_validity( + struct isl_sched_graph *graph, int coincidence, + struct isl_exploit_lineality_data *data) +{ + isl_union_map *inter; + isl_union_set *wrap; + isl_basic_set_list *list; + + inter = collect_validity(graph, &add_inter, coincidence); + inter = exploit_inter_lineality(inter, data); + inter = isl_union_map_remove_divs(inter); + wrap = isl_union_map_wrap(inter); + list = isl_union_set_get_basic_set_list(wrap); + isl_union_set_free(wrap); + return isl_basic_set_list_coefficients(list); +} + +/* Construct an LP problem for finding schedule coefficients + * such that the schedule carries as many of the "n_edge" groups of + * dependences as possible based on the corresponding coefficient + * constraints and return the lexicographically smallest non-trivial solution. + * "intra" is the sequence of coefficient constraints for intra-node edges. + * "inter" is the sequence of coefficient constraints for inter-node edges. + * If "want_integral" is set, then compute an integral solution + * for the coefficients rather than using the numerators + * of a rational solution. + * "carry_inter" indicates whether inter-node edges should be carried or + * only respected. + * + * If none of the "n_edge" groups can be carried + * then return an empty vector. + */ +static __isl_give isl_vec *compute_carrying_sol_coef(isl_ctx *ctx, + struct isl_sched_graph *graph, int n_edge, + __isl_keep isl_basic_set_list *intra, + __isl_keep isl_basic_set_list *inter, int want_integral, + int carry_inter) +{ + isl_basic_set *lp; + + if (setup_carry_lp(ctx, graph, n_edge, intra, inter, carry_inter) < 0) + return NULL; + + lp = isl_basic_set_copy(graph->lp); + return non_neg_lexmin(graph, lp, n_edge, want_integral); +} + +/* Construct an LP problem for finding schedule coefficients + * such that the schedule carries as many of the validity dependences + * as possible and + * return the lexicographically smallest non-trivial solution. + * If "fallback" is set, then the carrying is performed as a fallback + * for the Pluto-like scheduler. + * If "coincidence" is set, then try and carry coincidence edges as well. + * + * The variable "n_edge" stores the number of groups that should be carried. + * If none of the "n_edge" groups can be carried + * then return an empty vector. + * If, moreover, "n_edge" is zero, then the LP problem does not even + * need to be constructed. + * + * If a fallback solution is being computed, then compute an integral solution + * for the coefficients rather than using the numerators + * of a rational solution. + * + * If a fallback solution is being computed, if there are any intra-node + * dependences, and if requested by the user, then first try + * to only carry those intra-node dependences. + * If this fails to carry any dependences, then try again + * with the inter-node dependences included. + */ +static __isl_give isl_vec *compute_carrying_sol(isl_ctx *ctx, + struct isl_sched_graph *graph, int fallback, int coincidence) +{ + int n_intra, n_inter; + int n_edge; + struct isl_carry carry = { 0 }; + isl_vec *sol; + + carry.intra = collect_intra_validity(ctx, graph, coincidence, + &carry.lineality); + carry.inter = collect_inter_validity(graph, coincidence, + &carry.lineality); + if (!carry.intra || !carry.inter) + goto error; + n_intra = isl_basic_set_list_n_basic_set(carry.intra); + n_inter = isl_basic_set_list_n_basic_set(carry.inter); + + if (fallback && n_intra > 0 && + isl_options_get_schedule_carry_self_first(ctx)) { + sol = compute_carrying_sol_coef(ctx, graph, n_intra, + carry.intra, carry.inter, fallback, 0); + if (!sol || sol->size != 0 || n_inter == 0) { + isl_carry_clear(&carry); + return sol; + } + isl_vec_free(sol); + } + + n_edge = n_intra + n_inter; + if (n_edge == 0) { + isl_carry_clear(&carry); + return isl_vec_alloc(ctx, 0); + } + + sol = compute_carrying_sol_coef(ctx, graph, n_edge, + carry.intra, carry.inter, fallback, 1); + isl_carry_clear(&carry); + return sol; +error: + isl_carry_clear(&carry); + return NULL; +} + +/* Construct a schedule row for each node such that as many validity dependences + * as possible are carried and then continue with the next band. + * If "fallback" is set, then the carrying is performed as a fallback + * for the Pluto-like scheduler. + * If "coincidence" is set, then try and carry coincidence edges as well. + * + * If there are no validity dependences, then no dependence can be carried and + * the procedure is guaranteed to fail. If there is more than one component, + * then try computing a schedule on each component separately + * to prevent or at least postpone this failure. + * + * If a schedule row is computed, then check that dependences are carried + * for at least one of the edges. + * + * If the computed schedule row turns out to be trivial on one or + * more nodes where it should not be trivial, then we throw it away + * and try again on each component separately. + * + * If there is only one component, then we accept the schedule row anyway, + * but we do not consider it as a complete row and therefore do not + * increment graph->n_row. Note that the ranks of the nodes that + * do get a non-trivial schedule part will get updated regardless and + * graph->maxvar is computed based on these ranks. The test for + * whether more schedule rows are required in compute_schedule_wcc + * is therefore not affected. + * + * Insert a band corresponding to the schedule row at position "node" + * of the schedule tree and continue with the construction of the schedule. + * This insertion and the continued construction is performed by split_scaled + * after optionally checking for non-trivial common divisors. + */ +static __isl_give isl_schedule_node *carry(__isl_take isl_schedule_node *node, + struct isl_sched_graph *graph, int fallback, int coincidence) +{ + int trivial; + isl_ctx *ctx; + isl_vec *sol; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); + sol = compute_carrying_sol(ctx, graph, fallback, coincidence); + if (!sol) + return isl_schedule_node_free(node); + if (sol->size == 0) { + isl_vec_free(sol); + if (graph->scc > 1) + return compute_component_schedule(node, graph, 1); + isl_die(ctx, isl_error_unknown, "unable to carry dependences", + return isl_schedule_node_free(node)); + } + + trivial = is_any_trivial(graph, sol); + if (trivial < 0) { + sol = isl_vec_free(sol); + } else if (trivial && graph->scc > 1) { + isl_vec_free(sol); + return compute_component_schedule(node, graph, 1); + } + + if (update_schedule(graph, sol, 0) < 0) + return isl_schedule_node_free(node); + if (trivial) + graph->n_row--; + + return split_scaled(node, graph); +} + +/* Construct a schedule row for each node such that as many validity dependences + * as possible are carried and then continue with the next band. + * Do so as a fallback for the Pluto-like scheduler. + * If "coincidence" is set, then try and carry coincidence edges as well. + */ +static __isl_give isl_schedule_node *carry_fallback( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int coincidence) +{ + return carry(node, graph, 1, coincidence); +} + +/* Construct a schedule row for each node such that as many validity dependences + * as possible are carried and then continue with the next band. + * Do so for the case where the Feautrier scheduler was selected + * by the user. + */ +static __isl_give isl_schedule_node *carry_feautrier( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + return carry(node, graph, 0, 0); +} + +/* Construct a schedule row for each node such that as many validity dependences + * as possible are carried and then continue with the next band. + * Do so as a fallback for the Pluto-like scheduler. + */ +static __isl_give isl_schedule_node *carry_dependences( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + return carry_fallback(node, graph, 0); +} + +/* Construct a schedule row for each node such that as many validity or + * coincidence dependences as possible are carried and + * then continue with the next band. + * Do so as a fallback for the Pluto-like scheduler. + */ +static __isl_give isl_schedule_node *carry_coincidence( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + return carry_fallback(node, graph, 1); +} + +/* Topologically sort statements mapped to the same schedule iteration + * and add insert a sequence node in front of "node" + * corresponding to this order. + * If "initialized" is set, then it may be assumed that compute_maxvar + * has been called on the current band. Otherwise, call + * compute_maxvar if and before carry_dependences gets called. + * + * If it turns out to be impossible to sort the statements apart, + * because different dependences impose different orderings + * on the statements, then we extend the schedule such that + * it carries at least one more dependence. + */ +static __isl_give isl_schedule_node *sort_statements( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int initialized) +{ + isl_ctx *ctx; + isl_union_set_list *filters; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); + if (graph->n < 1) + isl_die(ctx, isl_error_internal, + "graph should have at least one node", + return isl_schedule_node_free(node)); + + if (graph->n == 1) + return node; + + if (update_edges(ctx, graph) < 0) + return isl_schedule_node_free(node); + + if (graph->n_edge == 0) + return node; + + if (detect_sccs(ctx, graph) < 0) + return isl_schedule_node_free(node); + + next_band(graph); + if (graph->scc < graph->n) { + if (!initialized && compute_maxvar(graph) < 0) + return isl_schedule_node_free(node); + return carry_dependences(node, graph); + } + + filters = extract_sccs(ctx, graph); + node = isl_schedule_node_insert_sequence(node, filters); + + return node; +} + +/* Are there any (non-empty) (conditional) validity edges in the graph? + */ +static int has_validity_edges(struct isl_sched_graph *graph) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + int empty; + + empty = isl_map_plain_is_empty(graph->edge[i].map); + if (empty < 0) + return -1; + if (empty) + continue; + if (is_any_validity(&graph->edge[i])) + return 1; + } + + return 0; +} + +/* Should we apply a Feautrier step? + * That is, did the user request the Feautrier algorithm and are + * there any validity dependences (left)? + */ +static int need_feautrier_step(isl_ctx *ctx, struct isl_sched_graph *graph) +{ + if (ctx->opt->schedule_algorithm != ISL_SCHEDULE_ALGORITHM_FEAUTRIER) + return 0; + + return has_validity_edges(graph); +} + +/* Compute a schedule for a connected dependence graph using Feautrier's + * multi-dimensional scheduling algorithm and return the updated schedule node. + * + * The original algorithm is described in [1]. + * The main idea is to minimize the number of scheduling dimensions, by + * trying to satisfy as many dependences as possible per scheduling dimension. + * + * [1] P. Feautrier, Some Efficient Solutions to the Affine Scheduling + * Problem, Part II: Multi-Dimensional Time. + * In Intl. Journal of Parallel Programming, 1992. + */ +static __isl_give isl_schedule_node *compute_schedule_wcc_feautrier( + isl_schedule_node *node, struct isl_sched_graph *graph) +{ + return carry_feautrier(node, graph); +} + +/* Turn off the "local" bit on all (condition) edges. + */ +static void clear_local_edges(struct isl_sched_graph *graph) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) + if (is_condition(&graph->edge[i])) + clear_local(&graph->edge[i]); +} + +/* Does "graph" have both condition and conditional validity edges? + */ +static int need_condition_check(struct isl_sched_graph *graph) +{ + int i; + int any_condition = 0; + int any_conditional_validity = 0; + + for (i = 0; i < graph->n_edge; ++i) { + if (is_condition(&graph->edge[i])) + any_condition = 1; + if (is_conditional_validity(&graph->edge[i])) + any_conditional_validity = 1; + } + + return any_condition && any_conditional_validity; +} + +/* Does "graph" contain any coincidence edge? + */ +static int has_any_coincidence(struct isl_sched_graph *graph) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) + if (is_coincidence(&graph->edge[i])) + return 1; + + return 0; +} + +/* Extract the final schedule row as a map with the iteration domain + * of "node" as domain. + */ +static __isl_give isl_map *final_row(struct isl_sched_node *node) +{ + isl_multi_aff *ma; + int row; + + row = isl_mat_rows(node->sched) - 1; + ma = node_extract_partial_schedule_multi_aff(node, row, 1); + return isl_map_from_multi_aff(ma); +} + +/* Is the conditional validity dependence in the edge with index "edge_index" + * violated by the latest (i.e., final) row of the schedule? + * That is, is i scheduled after j + * for any conditional validity dependence i -> j? + */ +static int is_violated(struct isl_sched_graph *graph, int edge_index) +{ + isl_map *src_sched, *dst_sched, *map; + struct isl_sched_edge *edge = &graph->edge[edge_index]; + int empty; + + src_sched = final_row(edge->src); + dst_sched = final_row(edge->dst); + map = isl_map_copy(edge->map); + map = isl_map_apply_domain(map, src_sched); + map = isl_map_apply_range(map, dst_sched); + map = isl_map_order_gt(map, isl_dim_in, 0, isl_dim_out, 0); + empty = isl_map_is_empty(map); + isl_map_free(map); + + if (empty < 0) + return -1; + + return !empty; +} + +/* Does "graph" have any satisfied condition edges that + * are adjacent to the conditional validity constraint with + * domain "conditional_source" and range "conditional_sink"? + * + * A satisfied condition is one that is not local. + * If a condition was forced to be local already (i.e., marked as local) + * then there is no need to check if it is in fact local. + * + * Additionally, mark all adjacent condition edges found as local. + */ +static int has_adjacent_true_conditions(struct isl_sched_graph *graph, + __isl_keep isl_union_set *conditional_source, + __isl_keep isl_union_set *conditional_sink) +{ + int i; + int any = 0; + + for (i = 0; i < graph->n_edge; ++i) { + int adjacent, local; + isl_union_map *condition; + + if (!is_condition(&graph->edge[i])) + continue; + if (is_local(&graph->edge[i])) + continue; + + condition = graph->edge[i].tagged_condition; + adjacent = domain_intersects(condition, conditional_sink); + if (adjacent >= 0 && !adjacent) + adjacent = range_intersects(condition, + conditional_source); + if (adjacent < 0) + return -1; + if (!adjacent) + continue; + + set_local(&graph->edge[i]); + + local = is_condition_false(&graph->edge[i]); + if (local < 0) + return -1; + if (!local) + any = 1; + } + + return any; +} + +/* Are there any violated conditional validity dependences with + * adjacent condition dependences that are not local with respect + * to the current schedule? + * That is, is the conditional validity constraint violated? + * + * Additionally, mark all those adjacent condition dependences as local. + * We also mark those adjacent condition dependences that were not marked + * as local before, but just happened to be local already. This ensures + * that they remain local if the schedule is recomputed. + * + * We first collect domain and range of all violated conditional validity + * dependences and then check if there are any adjacent non-local + * condition dependences. + */ +static int has_violated_conditional_constraint(isl_ctx *ctx, + struct isl_sched_graph *graph) +{ + int i; + int any = 0; + isl_union_set *source, *sink; + + source = isl_union_set_empty(isl_space_params_alloc(ctx, 0)); + sink = isl_union_set_empty(isl_space_params_alloc(ctx, 0)); + for (i = 0; i < graph->n_edge; ++i) { + isl_union_set *uset; + isl_union_map *umap; + int violated; + + if (!is_conditional_validity(&graph->edge[i])) + continue; + + violated = is_violated(graph, i); + if (violated < 0) + goto error; + if (!violated) + continue; + + any = 1; + + umap = isl_union_map_copy(graph->edge[i].tagged_validity); + uset = isl_union_map_domain(umap); + source = isl_union_set_union(source, uset); + source = isl_union_set_coalesce(source); + + umap = isl_union_map_copy(graph->edge[i].tagged_validity); + uset = isl_union_map_range(umap); + sink = isl_union_set_union(sink, uset); + sink = isl_union_set_coalesce(sink); + } + + if (any) + any = has_adjacent_true_conditions(graph, source, sink); + + isl_union_set_free(source); + isl_union_set_free(sink); + return any; +error: + isl_union_set_free(source); + isl_union_set_free(sink); + return -1; +} + +/* Examine the current band (the rows between graph->band_start and + * graph->n_total_row), deciding whether to drop it or add it to "node" + * and then continue with the computation of the next band, if any. + * If "initialized" is set, then it may be assumed that compute_maxvar + * has been called on the current band. Otherwise, call + * compute_maxvar if and before carry_dependences gets called. + * + * The caller keeps looking for a new row as long as + * graph->n_row < graph->maxvar. If the latest attempt to find + * such a row failed (i.e., we still have graph->n_row < graph->maxvar), + * then 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) + * - if there is more than one SCC left, then split along all SCCs + * - if outer coincidence needs to be enforced, then try to carry as many + * validity or coincidence dependences as possible and + * continue with the next band + * - try to carry as many validity dependences as possible and + * continue with the next band + * In each case, we first insert a band node in the schedule tree + * if any rows have been computed. + * + * If the caller managed to complete the schedule and the current band + * is empty, then finish off by topologically + * sorting the statements based on the remaining dependences. + * If, on the other hand, the current band has at least one row, + * then continue with the next band. Note that this next band + * will necessarily be empty, but the graph may still be split up + * into weakly connected components before arriving back here. + */ +static __isl_give isl_schedule_node *compute_schedule_finish_band( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int initialized) +{ + int empty; + + if (!node) + return NULL; + + empty = graph->n_total_row == graph->band_start; + if (graph->n_row < graph->maxvar) { + isl_ctx *ctx; + + ctx = isl_schedule_node_get_ctx(node); + if (!ctx->opt->schedule_maximize_band_depth && !empty) + return compute_next_band(node, graph, 1); + if (graph->src_scc >= 0) + return compute_split_schedule(node, graph); + if (!empty) + return compute_next_band(node, graph, 1); + if (graph->scc > 1) + return compute_component_schedule(node, graph, 1); + if (!initialized && compute_maxvar(graph) < 0) + return isl_schedule_node_free(node); + if (isl_options_get_schedule_outer_coincidence(ctx)) + return carry_coincidence(node, graph); + return carry_dependences(node, graph); + } + + if (!empty) + return compute_next_band(node, graph, 1); + return sort_statements(node, graph, initialized); +} + +/* Construct a band of schedule rows for a connected dependence graph. + * The caller is responsible for determining the strongly connected + * components and calling compute_maxvar first. + * + * 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), with as + * many of the initial rows as possible satisfying the coincidence constraints. + * The computation stops if we can't find any more rows or if we have found + * all the rows we wanted to find. + * + * If ctx->opt->schedule_outer_coincidence is set, then we force the + * outermost dimension to satisfy the coincidence constraints. If this + * turns out to be impossible, we fall back on the general scheme above + * and try to carry as many dependences as possible. + * + * If "graph" contains both condition and conditional validity dependences, + * then we need to check that that the conditional schedule constraint + * is satisfied, i.e., there are no violated conditional validity dependences + * that are adjacent to any non-local condition dependences. + * If there are, then we mark all those adjacent condition dependences + * as local and recompute the current band. Those dependences that + * are marked local will then be forced to be local. + * The initial computation is performed with no dependences marked as local. + * If we are lucky, then there will be no violated conditional validity + * dependences adjacent to any non-local condition dependences. + * Otherwise, we mark some additional condition dependences as local and + * recompute. We continue this process until there are no violations left or + * until we are no longer able to compute a schedule. + * Since there are only a finite number of dependences, + * there will only be a finite number of iterations. + */ +static isl_stat compute_schedule_wcc_band(isl_ctx *ctx, + struct isl_sched_graph *graph) +{ + int has_coincidence; + int use_coincidence; + int force_coincidence = 0; + int check_conditional; + + if (sort_sccs(graph) < 0) + return isl_stat_error; + + clear_local_edges(graph); + check_conditional = need_condition_check(graph); + has_coincidence = has_any_coincidence(graph); + + if (ctx->opt->schedule_outer_coincidence) + force_coincidence = 1; + + use_coincidence = has_coincidence; + while (graph->n_row < graph->maxvar) { + isl_vec *sol; + int violated; + int coincident; + + graph->src_scc = -1; + graph->dst_scc = -1; + + if (setup_lp(ctx, graph, use_coincidence) < 0) + return isl_stat_error; + sol = solve_lp(ctx, graph); + if (!sol) + return isl_stat_error; + if (sol->size == 0) { + int empty = graph->n_total_row == graph->band_start; + + isl_vec_free(sol); + if (use_coincidence && (!force_coincidence || !empty)) { + use_coincidence = 0; + continue; + } + return isl_stat_ok; + } + coincident = !has_coincidence || use_coincidence; + if (update_schedule(graph, sol, coincident) < 0) + return isl_stat_error; + + if (!check_conditional) + continue; + violated = has_violated_conditional_constraint(ctx, graph); + if (violated < 0) + return isl_stat_error; + if (!violated) + continue; + if (reset_band(graph) < 0) + return isl_stat_error; + use_coincidence = has_coincidence; + } + + return isl_stat_ok; +} + +/* Compute a schedule for a connected dependence graph by considering + * the graph as a whole and return the updated schedule node. + * + * The actual schedule rows of the current band are computed by + * compute_schedule_wcc_band. compute_schedule_finish_band takes + * care of integrating the band into "node" and continuing + * the computation. + */ +static __isl_give isl_schedule_node *compute_schedule_wcc_whole( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + isl_ctx *ctx; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); + if (compute_schedule_wcc_band(ctx, graph) < 0) + return isl_schedule_node_free(node); + + return compute_schedule_finish_band(node, graph, 1); +} + +/* Clustering information used by compute_schedule_wcc_clustering. + * + * "n" is the number of SCCs in the original dependence graph + * "scc" is an array of "n" elements, each representing an SCC + * of the original dependence graph. All entries in the same cluster + * have the same number of schedule rows. + * "scc_cluster" maps each SCC index to the cluster to which it belongs, + * where each cluster is represented by the index of the first SCC + * in the cluster. Initially, each SCC belongs to a cluster containing + * only that SCC. + * + * "scc_in_merge" is used by merge_clusters_along_edge to keep + * track of which SCCs need to be merged. + * + * "cluster" contains the merged clusters of SCCs after the clustering + * has completed. + * + * "scc_node" is a temporary data structure used inside copy_partial. + * For each SCC, it keeps track of the number of nodes in the SCC + * that have already been copied. + */ +struct isl_clustering { + int n; + struct isl_sched_graph *scc; + struct isl_sched_graph *cluster; + int *scc_cluster; + int *scc_node; + int *scc_in_merge; +}; + +/* Initialize the clustering data structure "c" from "graph". + * + * In particular, allocate memory, extract the SCCs from "graph" + * into c->scc, initialize scc_cluster and construct + * a band of schedule rows for each SCC. + * Within each SCC, there is only one SCC by definition. + * Each SCC initially belongs to a cluster containing only that SCC. + */ +static isl_stat clustering_init(isl_ctx *ctx, struct isl_clustering *c, + struct isl_sched_graph *graph) +{ + int i; + + c->n = graph->scc; + c->scc = isl_calloc_array(ctx, struct isl_sched_graph, c->n); + c->cluster = isl_calloc_array(ctx, struct isl_sched_graph, c->n); + c->scc_cluster = isl_calloc_array(ctx, int, c->n); + c->scc_node = isl_calloc_array(ctx, int, c->n); + c->scc_in_merge = isl_calloc_array(ctx, int, c->n); + if (!c->scc || !c->cluster || + !c->scc_cluster || !c->scc_node || !c->scc_in_merge) + return isl_stat_error; + + for (i = 0; i < c->n; ++i) { + if (extract_sub_graph(ctx, graph, &node_scc_exactly, + &edge_scc_exactly, i, &c->scc[i]) < 0) + return isl_stat_error; + c->scc[i].scc = 1; + if (compute_maxvar(&c->scc[i]) < 0) + return isl_stat_error; + if (compute_schedule_wcc_band(ctx, &c->scc[i]) < 0) + return isl_stat_error; + c->scc_cluster[i] = i; + } + + return isl_stat_ok; +} + +/* Free all memory allocated for "c". + */ +static void clustering_free(isl_ctx *ctx, struct isl_clustering *c) +{ + int i; + + if (c->scc) + for (i = 0; i < c->n; ++i) + graph_free(ctx, &c->scc[i]); + free(c->scc); + if (c->cluster) + for (i = 0; i < c->n; ++i) + graph_free(ctx, &c->cluster[i]); + free(c->cluster); + free(c->scc_cluster); + free(c->scc_node); + free(c->scc_in_merge); +} + +/* Should we refrain from merging the cluster in "graph" with + * any other cluster? + * In particular, is its current schedule band empty and incomplete. + */ +static int bad_cluster(struct isl_sched_graph *graph) +{ + return graph->n_row < graph->maxvar && + graph->n_total_row == graph->band_start; +} + +/* Is "edge" a proximity edge with a non-empty dependence relation? + */ +static isl_bool is_non_empty_proximity(struct isl_sched_edge *edge) +{ + if (!is_proximity(edge)) + return isl_bool_false; + return isl_bool_not(isl_map_plain_is_empty(edge->map)); +} + +/* Return the index of an edge in "graph" that can be used to merge + * two clusters in "c". + * Return graph->n_edge if no such edge can be found. + * Return -1 on error. + * + * In particular, return a proximity edge between two clusters + * that is not marked "no_merge" and such that neither of the + * two clusters has an incomplete, empty band. + * + * If there are multiple such edges, then try and find the most + * appropriate edge to use for merging. In particular, pick the edge + * with the greatest weight. If there are multiple of those, + * then pick one with the shortest distance between + * the two cluster representatives. + */ +static int find_proximity(struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + int i, best = graph->n_edge, best_dist, best_weight; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + int dist, weight; + isl_bool prox; + + prox = is_non_empty_proximity(edge); + if (prox < 0) + return -1; + if (!prox) + continue; + if (edge->no_merge) + continue; + if (bad_cluster(&c->scc[edge->src->scc]) || + bad_cluster(&c->scc[edge->dst->scc])) + continue; + dist = c->scc_cluster[edge->dst->scc] - + c->scc_cluster[edge->src->scc]; + if (dist == 0) + continue; + weight = edge->weight; + if (best < graph->n_edge) { + if (best_weight > weight) + continue; + if (best_weight == weight && best_dist <= dist) + continue; + } + best = i; + best_dist = dist; + best_weight = weight; + } + + return best; +} + +/* Internal data structure used in mark_merge_sccs. + * + * "graph" is the dependence graph in which a strongly connected + * component is constructed. + * "scc_cluster" maps each SCC index to the cluster to which it belongs. + * "src" and "dst" are the indices of the nodes that are being merged. + */ +struct isl_mark_merge_sccs_data { + struct isl_sched_graph *graph; + int *scc_cluster; + int src; + int dst; +}; + +/* Check whether the cluster containing node "i" depends on the cluster + * containing node "j". If "i" and "j" belong to the same cluster, + * then they are taken to depend on each other to ensure that + * the resulting strongly connected component consists of complete + * clusters. Furthermore, if "i" and "j" are the two nodes that + * are being merged, then they are taken to depend on each other as well. + * Otherwise, check if there is a (conditional) validity dependence + * from node[j] to node[i], forcing node[i] to follow node[j]. + */ +static isl_bool cluster_follows(int i, int j, void *user) +{ + struct isl_mark_merge_sccs_data *data = user; + struct isl_sched_graph *graph = data->graph; + int *scc_cluster = data->scc_cluster; + + if (data->src == i && data->dst == j) + return isl_bool_true; + if (data->src == j && data->dst == i) + return isl_bool_true; + if (scc_cluster[graph->node[i].scc] == scc_cluster[graph->node[j].scc]) + return isl_bool_true; + + return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]); +} + +/* Mark all SCCs that belong to either of the two clusters in "c" + * connected by the edge in "graph" with index "edge", or to any + * of the intermediate clusters. + * The marking is recorded in c->scc_in_merge. + * + * The given edge has been selected for merging two clusters, + * meaning that there is at least a proximity edge between the two nodes. + * However, there may also be (indirect) validity dependences + * between the two nodes. When merging the two clusters, all clusters + * containing one or more of the intermediate nodes along the + * indirect validity dependences need to be merged in as well. + * + * First collect all such nodes by computing the strongly connected + * component (SCC) containing the two nodes connected by the edge, where + * the two nodes are considered to depend on each other to make + * sure they end up in the same SCC. Similarly, each node is considered + * to depend on every other node in the same cluster to ensure + * that the SCC consists of complete clusters. + * + * Then the original SCCs that contain any of these nodes are marked + * in c->scc_in_merge. + */ +static isl_stat mark_merge_sccs(isl_ctx *ctx, struct isl_sched_graph *graph, + int edge, struct isl_clustering *c) +{ + struct isl_mark_merge_sccs_data data; + struct isl_tarjan_graph *g; + int i; + + for (i = 0; i < c->n; ++i) + c->scc_in_merge[i] = 0; + + data.graph = graph; + data.scc_cluster = c->scc_cluster; + data.src = graph->edge[edge].src - graph->node; + data.dst = graph->edge[edge].dst - graph->node; + + g = isl_tarjan_graph_component(ctx, graph->n, data.dst, + &cluster_follows, &data); + if (!g) + goto error; + + i = g->op; + if (i < 3) + isl_die(ctx, isl_error_internal, + "expecting at least two nodes in component", + goto error); + if (g->order[--i] != -1) + isl_die(ctx, isl_error_internal, + "expecting end of component marker", goto error); + + for (--i; i >= 0 && g->order[i] != -1; --i) { + int scc = graph->node[g->order[i]].scc; + c->scc_in_merge[scc] = 1; + } + + isl_tarjan_graph_free(g); + return isl_stat_ok; +error: + isl_tarjan_graph_free(g); + return isl_stat_error; +} + +/* Construct the identifier "cluster_i". + */ +static __isl_give isl_id *cluster_id(isl_ctx *ctx, int i) +{ + char name[40]; + + snprintf(name, sizeof(name), "cluster_%d", i); + return isl_id_alloc(ctx, name, NULL); +} + +/* Construct the space of the cluster with index "i" containing + * the strongly connected component "scc". + * + * In particular, construct a space called cluster_i with dimension equal + * to the number of schedule rows in the current band of "scc". + */ +static __isl_give isl_space *cluster_space(struct isl_sched_graph *scc, int i) +{ + int nvar; + isl_space *space; + isl_id *id; + + nvar = scc->n_total_row - scc->band_start; + space = isl_space_copy(scc->node[0].space); + space = isl_space_params(space); + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, nvar); + id = cluster_id(isl_space_get_ctx(space), i); + space = isl_space_set_tuple_id(space, isl_dim_set, id); + + return space; +} + +/* Collect the domain of the graph for merging clusters. + * + * In particular, for each cluster with first SCC "i", construct + * a set in the space called cluster_i with dimension equal + * to the number of schedule rows in the current band of the cluster. + */ +static __isl_give isl_union_set *collect_domain(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_clustering *c) +{ + int i; + isl_space *space; + isl_union_set *domain; + + space = isl_space_params_alloc(ctx, 0); + domain = isl_union_set_empty(space); + + for (i = 0; i < graph->scc; ++i) { + isl_space *space; + + if (!c->scc_in_merge[i]) + continue; + if (c->scc_cluster[i] != i) + continue; + space = cluster_space(&c->scc[i], i); + domain = isl_union_set_add_set(domain, isl_set_universe(space)); + } + + return domain; +} + +/* Construct a map from the original instances to the corresponding + * cluster instance in the current bands of the clusters in "c". + */ +static __isl_give isl_union_map *collect_cluster_map(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_clustering *c) +{ + int i, j; + isl_space *space; + isl_union_map *cluster_map; + + space = isl_space_params_alloc(ctx, 0); + cluster_map = isl_union_map_empty(space); + for (i = 0; i < graph->scc; ++i) { + int start, n; + isl_id *id; + + if (!c->scc_in_merge[i]) + continue; + + id = cluster_id(ctx, c->scc_cluster[i]); + start = c->scc[i].band_start; + n = c->scc[i].n_total_row - start; + for (j = 0; j < c->scc[i].n; ++j) { + isl_multi_aff *ma; + isl_map *map; + struct isl_sched_node *node = &c->scc[i].node[j]; + + ma = node_extract_partial_schedule_multi_aff(node, + start, n); + ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out, + isl_id_copy(id)); + map = isl_map_from_multi_aff(ma); + cluster_map = isl_union_map_add_map(cluster_map, map); + } + isl_id_free(id); + } + + return cluster_map; +} + +/* Add "umap" to the schedule constraints "sc" of all types of "edge" + * that are not isl_edge_condition or isl_edge_conditional_validity. + */ +static __isl_give isl_schedule_constraints *add_non_conditional_constraints( + struct isl_sched_edge *edge, __isl_keep isl_union_map *umap, + __isl_take isl_schedule_constraints *sc) +{ + enum isl_edge_type t; + + if (!sc) + return NULL; + + for (t = isl_edge_first; t <= isl_edge_last; ++t) { + if (t == isl_edge_condition || + t == isl_edge_conditional_validity) + continue; + if (!is_type(edge, t)) + continue; + sc = isl_schedule_constraints_add(sc, t, + isl_union_map_copy(umap)); + } + + return sc; +} + +/* Add schedule constraints of types isl_edge_condition and + * isl_edge_conditional_validity to "sc" by applying "umap" to + * the domains of the wrapped relations in domain and range + * of the corresponding tagged constraints of "edge". + */ +static __isl_give isl_schedule_constraints *add_conditional_constraints( + struct isl_sched_edge *edge, __isl_keep isl_union_map *umap, + __isl_take isl_schedule_constraints *sc) +{ + enum isl_edge_type t; + isl_union_map *tagged; + + for (t = isl_edge_condition; t <= isl_edge_conditional_validity; ++t) { + if (!is_type(edge, t)) + continue; + if (t == isl_edge_condition) + tagged = isl_union_map_copy(edge->tagged_condition); + else + tagged = isl_union_map_copy(edge->tagged_validity); + tagged = isl_union_map_zip(tagged); + tagged = isl_union_map_apply_domain(tagged, + isl_union_map_copy(umap)); + tagged = isl_union_map_zip(tagged); + sc = isl_schedule_constraints_add(sc, t, tagged); + if (!sc) + return NULL; + } + + return sc; +} + +/* Given a mapping "cluster_map" from the original instances to + * the cluster instances, add schedule constraints on the clusters + * to "sc" corresponding to the original constraints represented by "edge". + * + * For non-tagged dependence constraints, the cluster constraints + * are obtained by applying "cluster_map" to the edge->map. + * + * For tagged dependence constraints, "cluster_map" needs to be applied + * to the domains of the wrapped relations in domain and range + * of the tagged dependence constraints. Pick out the mappings + * from these domains from "cluster_map" and construct their product. + * This mapping can then be applied to the pair of domains. + */ +static __isl_give isl_schedule_constraints *collect_edge_constraints( + struct isl_sched_edge *edge, __isl_keep isl_union_map *cluster_map, + __isl_take isl_schedule_constraints *sc) +{ + isl_union_map *umap; + isl_space *space; + isl_union_set *uset; + isl_union_map *umap1, *umap2; + + if (!sc) + return NULL; + + umap = isl_union_map_from_map(isl_map_copy(edge->map)); + umap = isl_union_map_apply_domain(umap, + isl_union_map_copy(cluster_map)); + umap = isl_union_map_apply_range(umap, + isl_union_map_copy(cluster_map)); + sc = add_non_conditional_constraints(edge, umap, sc); + isl_union_map_free(umap); + + if (!sc || (!is_condition(edge) && !is_conditional_validity(edge))) + return sc; + + space = isl_space_domain(isl_map_get_space(edge->map)); + uset = isl_union_set_from_set(isl_set_universe(space)); + umap1 = isl_union_map_copy(cluster_map); + umap1 = isl_union_map_intersect_domain(umap1, uset); + space = isl_space_range(isl_map_get_space(edge->map)); + uset = isl_union_set_from_set(isl_set_universe(space)); + umap2 = isl_union_map_copy(cluster_map); + umap2 = isl_union_map_intersect_domain(umap2, uset); + umap = isl_union_map_product(umap1, umap2); + + sc = add_conditional_constraints(edge, umap, sc); + + isl_union_map_free(umap); + return sc; +} + +/* Given a mapping "cluster_map" from the original instances to + * the cluster instances, add schedule constraints on the clusters + * to "sc" corresponding to all edges in "graph" between nodes that + * belong to SCCs that are marked for merging in "scc_in_merge". + */ +static __isl_give isl_schedule_constraints *collect_constraints( + struct isl_sched_graph *graph, int *scc_in_merge, + __isl_keep isl_union_map *cluster_map, + __isl_take isl_schedule_constraints *sc) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + + if (!scc_in_merge[edge->src->scc]) + continue; + if (!scc_in_merge[edge->dst->scc]) + continue; + sc = collect_edge_constraints(edge, cluster_map, sc); + } + + return sc; +} + +/* Construct a dependence graph for scheduling clusters with respect + * to each other and store the result in "merge_graph". + * In particular, the nodes of the graph correspond to the schedule + * dimensions of the current bands of those clusters that have been + * marked for merging in "c". + * + * First construct an isl_schedule_constraints object for this domain + * by transforming the edges in "graph" to the domain. + * Then initialize a dependence graph for scheduling from these + * constraints. + */ +static isl_stat init_merge_graph(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_clustering *c, struct isl_sched_graph *merge_graph) +{ + isl_union_set *domain; + isl_union_map *cluster_map; + isl_schedule_constraints *sc; + isl_stat r; + + domain = collect_domain(ctx, graph, c); + sc = isl_schedule_constraints_on_domain(domain); + if (!sc) + return isl_stat_error; + cluster_map = collect_cluster_map(ctx, graph, c); + sc = collect_constraints(graph, c->scc_in_merge, cluster_map, sc); + isl_union_map_free(cluster_map); + + r = graph_init(merge_graph, sc); + + isl_schedule_constraints_free(sc); + + return r; +} + +/* Compute the maximal number of remaining schedule rows that still need + * to be computed for the nodes that belong to clusters with the maximal + * dimension for the current band (i.e., the band that is to be merged). + * Only clusters that are about to be merged are considered. + * "maxvar" is the maximal dimension for the current band. + * "c" contains information about the clusters. + * + * Return the maximal number of remaining schedule rows or -1 on error. + */ +static int compute_maxvar_max_slack(int maxvar, struct isl_clustering *c) +{ + int i, j; + int max_slack; + + max_slack = 0; + for (i = 0; i < c->n; ++i) { + int nvar; + struct isl_sched_graph *scc; + + if (!c->scc_in_merge[i]) + continue; + scc = &c->scc[i]; + nvar = scc->n_total_row - scc->band_start; + if (nvar != maxvar) + continue; + for (j = 0; j < scc->n; ++j) { + struct isl_sched_node *node = &scc->node[j]; + int slack; + + if (node_update_vmap(node) < 0) + return -1; + slack = node->nvar - node->rank; + if (slack > max_slack) + max_slack = slack; + } + } + + return max_slack; +} + +/* If there are any clusters where the dimension of the current band + * (i.e., the band that is to be merged) is smaller than "maxvar" and + * if there are any nodes in such a cluster where the number + * of remaining schedule rows that still need to be computed + * is greater than "max_slack", then return the smallest current band + * dimension of all these clusters. Otherwise return the original value + * of "maxvar". Return -1 in case of any error. + * Only clusters that are about to be merged are considered. + * "c" contains information about the clusters. + */ +static int limit_maxvar_to_slack(int maxvar, int max_slack, + struct isl_clustering *c) +{ + int i, j; + + for (i = 0; i < c->n; ++i) { + int nvar; + struct isl_sched_graph *scc; + + if (!c->scc_in_merge[i]) + continue; + scc = &c->scc[i]; + nvar = scc->n_total_row - scc->band_start; + if (nvar >= maxvar) + continue; + for (j = 0; j < scc->n; ++j) { + struct isl_sched_node *node = &scc->node[j]; + int slack; + + if (node_update_vmap(node) < 0) + return -1; + slack = node->nvar - node->rank; + if (slack > max_slack) { + maxvar = nvar; + break; + } + } + } + + return maxvar; +} + +/* Adjust merge_graph->maxvar based on the number of remaining schedule rows + * that still need to be computed. In particular, if there is a node + * in a cluster where the dimension of the current band is smaller + * than merge_graph->maxvar, but the number of remaining schedule rows + * is greater than that of any node in a cluster with the maximal + * dimension for the current band (i.e., merge_graph->maxvar), + * then adjust merge_graph->maxvar to the (smallest) current band dimension + * of those clusters. Without this adjustment, the total number of + * schedule dimensions would be increased, resulting in a skewed view + * of the number of coincident dimensions. + * "c" contains information about the clusters. + * + * If the maximize_band_depth option is set and merge_graph->maxvar is reduced, + * then there is no point in attempting any merge since it will be rejected + * anyway. Set merge_graph->maxvar to zero in such cases. + */ +static isl_stat adjust_maxvar_to_slack(isl_ctx *ctx, + struct isl_sched_graph *merge_graph, struct isl_clustering *c) +{ + int max_slack, maxvar; + + max_slack = compute_maxvar_max_slack(merge_graph->maxvar, c); + if (max_slack < 0) + return isl_stat_error; + maxvar = limit_maxvar_to_slack(merge_graph->maxvar, max_slack, c); + if (maxvar < 0) + return isl_stat_error; + + if (maxvar < merge_graph->maxvar) { + if (isl_options_get_schedule_maximize_band_depth(ctx)) + merge_graph->maxvar = 0; + else + merge_graph->maxvar = maxvar; + } + + return isl_stat_ok; +} + +/* Return the number of coincident dimensions in the current band of "graph", + * where the nodes of "graph" are assumed to be scheduled by a single band. + */ +static int get_n_coincident(struct isl_sched_graph *graph) +{ + int i; + + for (i = graph->band_start; i < graph->n_total_row; ++i) + if (!graph->node[0].coincident[i]) + break; + + return i - graph->band_start; +} + +/* Should the clusters be merged based on the cluster schedule + * in the current (and only) band of "merge_graph", given that + * coincidence should be maximized? + * + * If the number of coincident schedule dimensions in the merged band + * would be less than the maximal number of coincident schedule dimensions + * in any of the merged clusters, then the clusters should not be merged. + */ +static isl_bool ok_to_merge_coincident(struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + int i; + int n_coincident; + int max_coincident; + + max_coincident = 0; + for (i = 0; i < c->n; ++i) { + if (!c->scc_in_merge[i]) + continue; + n_coincident = get_n_coincident(&c->scc[i]); + if (n_coincident > max_coincident) + max_coincident = n_coincident; + } + + n_coincident = get_n_coincident(merge_graph); + + return n_coincident >= max_coincident; +} + +/* Return the transformation on "node" expressed by the current (and only) + * band of "merge_graph" applied to the clusters in "c". + * + * First find the representation of "node" in its SCC in "c" and + * extract the transformation expressed by the current band. + * Then extract the transformation applied by "merge_graph" + * to the cluster to which this SCC belongs. + * Combine the two to obtain the complete transformation on the node. + * + * Note that the range of the first transformation is an anonymous space, + * while the domain of the second is named "cluster_X". The range + * of the former therefore needs to be adjusted before the two + * can be combined. + */ +static __isl_give isl_map *extract_node_transformation(isl_ctx *ctx, + struct isl_sched_node *node, struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + struct isl_sched_node *scc_node, *cluster_node; + int start, n; + isl_id *id; + isl_space *space; + isl_multi_aff *ma, *ma2; + + scc_node = graph_find_node(ctx, &c->scc[node->scc], node->space); + if (scc_node && !is_node(&c->scc[node->scc], scc_node)) + isl_die(ctx, isl_error_internal, "unable to find node", + return NULL); + start = c->scc[node->scc].band_start; + n = c->scc[node->scc].n_total_row - start; + ma = node_extract_partial_schedule_multi_aff(scc_node, start, n); + space = cluster_space(&c->scc[node->scc], c->scc_cluster[node->scc]); + cluster_node = graph_find_node(ctx, merge_graph, space); + if (cluster_node && !is_node(merge_graph, cluster_node)) + isl_die(ctx, isl_error_internal, "unable to find cluster", + space = isl_space_free(space)); + id = isl_space_get_tuple_id(space, isl_dim_set); + ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out, id); + isl_space_free(space); + n = merge_graph->n_total_row; + ma2 = node_extract_partial_schedule_multi_aff(cluster_node, 0, n); + ma = isl_multi_aff_pullback_multi_aff(ma2, ma); + + return isl_map_from_multi_aff(ma); +} + +/* Give a set of distances "set", are they bounded by a small constant + * in direction "pos"? + * In practice, check if they are bounded by 2 by checking that there + * are no elements with a value greater than or equal to 3 or + * smaller than or equal to -3. + */ +static isl_bool distance_is_bounded(__isl_keep isl_set *set, int pos) +{ + isl_bool bounded; + isl_set *test; + + if (!set) + return isl_bool_error; + + test = isl_set_copy(set); + test = isl_set_lower_bound_si(test, isl_dim_set, pos, 3); + bounded = isl_set_is_empty(test); + isl_set_free(test); + + if (bounded < 0 || !bounded) + return bounded; + + test = isl_set_copy(set); + test = isl_set_upper_bound_si(test, isl_dim_set, pos, -3); + bounded = isl_set_is_empty(test); + isl_set_free(test); + + return bounded; +} + +/* Does the set "set" have a fixed (but possible parametric) value + * at dimension "pos"? + */ +static isl_bool has_single_value(__isl_keep isl_set *set, int pos) +{ + int n; + isl_bool single; + + if (!set) + return isl_bool_error; + set = isl_set_copy(set); + n = isl_set_dim(set, isl_dim_set); + set = isl_set_project_out(set, isl_dim_set, pos + 1, n - (pos + 1)); + set = isl_set_project_out(set, isl_dim_set, 0, pos); + single = isl_set_is_singleton(set); + isl_set_free(set); + + return single; +} + +/* Does "map" have a fixed (but possible parametric) value + * at dimension "pos" of either its domain or its range? + */ +static isl_bool has_singular_src_or_dst(__isl_keep isl_map *map, int pos) +{ + isl_set *set; + isl_bool single; + + set = isl_map_domain(isl_map_copy(map)); + single = has_single_value(set, pos); + isl_set_free(set); + + if (single < 0 || single) + return single; + + set = isl_map_range(isl_map_copy(map)); + single = has_single_value(set, pos); + isl_set_free(set); + + return single; +} + +/* Does the edge "edge" from "graph" have bounded dependence distances + * in the merged graph "merge_graph" of a selection of clusters in "c"? + * + * Extract the complete transformations of the source and destination + * nodes of the edge, apply them to the edge constraints and + * compute the differences. Finally, check if these differences are bounded + * in each direction. + * + * If the dimension of the band is greater than the number of + * dimensions that can be expected to be optimized by the edge + * (based on its weight), then also allow the differences to be unbounded + * in the remaining dimensions, but only if either the source or + * the destination has a fixed value in that direction. + * This allows a statement that produces values that are used by + * several instances of another statement to be merged with that + * other statement. + * However, merging such clusters will introduce an inherently + * large proximity distance inside the merged cluster, meaning + * that proximity distances will no longer be optimized in + * subsequent merges. These merges are therefore only allowed + * after all other possible merges have been tried. + * The first time such a merge is encountered, the weight of the edge + * is replaced by a negative weight. The second time (i.e., after + * all merges over edges with a non-negative weight have been tried), + * the merge is allowed. + */ +static isl_bool has_bounded_distances(isl_ctx *ctx, struct isl_sched_edge *edge, + struct isl_sched_graph *graph, struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + int i, n, n_slack; + isl_bool bounded; + isl_map *map, *t; + isl_set *dist; + + map = isl_map_copy(edge->map); + t = extract_node_transformation(ctx, edge->src, c, merge_graph); + map = isl_map_apply_domain(map, t); + t = extract_node_transformation(ctx, edge->dst, c, merge_graph); + map = isl_map_apply_range(map, t); + dist = isl_map_deltas(isl_map_copy(map)); + + bounded = isl_bool_true; + n = isl_set_dim(dist, isl_dim_set); + n_slack = n - edge->weight; + if (edge->weight < 0) + n_slack -= graph->max_weight + 1; + for (i = 0; i < n; ++i) { + isl_bool bounded_i, singular_i; + + bounded_i = distance_is_bounded(dist, i); + if (bounded_i < 0) + goto error; + if (bounded_i) + continue; + if (edge->weight >= 0) + bounded = isl_bool_false; + n_slack--; + if (n_slack < 0) + break; + singular_i = has_singular_src_or_dst(map, i); + if (singular_i < 0) + goto error; + if (singular_i) + continue; + bounded = isl_bool_false; + break; + } + if (!bounded && i >= n && edge->weight >= 0) + edge->weight -= graph->max_weight + 1; + isl_map_free(map); + isl_set_free(dist); + + return bounded; +error: + isl_map_free(map); + isl_set_free(dist); + return isl_bool_error; +} + +/* Should the clusters be merged based on the cluster schedule + * in the current (and only) band of "merge_graph"? + * "graph" is the original dependence graph, while "c" records + * which SCCs are involved in the latest merge. + * + * In particular, is there at least one proximity constraint + * that is optimized by the merge? + * + * A proximity constraint is considered to be optimized + * if the dependence distances are small. + */ +static isl_bool ok_to_merge_proximity(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + isl_bool bounded; + + if (!is_proximity(edge)) + continue; + if (!c->scc_in_merge[edge->src->scc]) + continue; + if (!c->scc_in_merge[edge->dst->scc]) + continue; + if (c->scc_cluster[edge->dst->scc] == + c->scc_cluster[edge->src->scc]) + continue; + bounded = has_bounded_distances(ctx, edge, graph, c, + merge_graph); + if (bounded < 0 || bounded) + return bounded; + } + + return isl_bool_false; +} + +/* Should the clusters be merged based on the cluster schedule + * in the current (and only) band of "merge_graph"? + * "graph" is the original dependence graph, while "c" records + * which SCCs are involved in the latest merge. + * + * If the current band is empty, then the clusters should not be merged. + * + * If the band depth should be maximized and the merge schedule + * is incomplete (meaning that the dimension of some of the schedule + * bands in the original schedule will be reduced), then the clusters + * should not be merged. + * + * If the schedule_maximize_coincidence option is set, then check that + * the number of coincident schedule dimensions is not reduced. + * + * Finally, only allow the merge if at least one proximity + * constraint is optimized. + */ +static isl_bool ok_to_merge(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_clustering *c, struct isl_sched_graph *merge_graph) +{ + if (merge_graph->n_total_row == merge_graph->band_start) + return isl_bool_false; + + if (isl_options_get_schedule_maximize_band_depth(ctx) && + merge_graph->n_total_row < merge_graph->maxvar) + return isl_bool_false; + + if (isl_options_get_schedule_maximize_coincidence(ctx)) { + isl_bool ok; + + ok = ok_to_merge_coincident(c, merge_graph); + if (ok < 0 || !ok) + return ok; + } + + return ok_to_merge_proximity(ctx, graph, c, merge_graph); +} + +/* Apply the schedule in "t_node" to the "n" rows starting at "first" + * of the schedule in "node" and return the result. + * + * That is, essentially compute + * + * T * N(first:first+n-1) + * + * taking into account the constant term and the parameter coefficients + * in "t_node". + */ +static __isl_give isl_mat *node_transformation(isl_ctx *ctx, + struct isl_sched_node *t_node, struct isl_sched_node *node, + int first, int n) +{ + int i, j; + isl_mat *t; + int n_row, n_col, n_param, n_var; + + n_param = node->nparam; + n_var = node->nvar; + n_row = isl_mat_rows(t_node->sched); + n_col = isl_mat_cols(node->sched); + t = isl_mat_alloc(ctx, n_row, n_col); + if (!t) + return NULL; + for (i = 0; i < n_row; ++i) { + isl_seq_cpy(t->row[i], t_node->sched->row[i], 1 + n_param); + isl_seq_clr(t->row[i] + 1 + n_param, n_var); + for (j = 0; j < n; ++j) + isl_seq_addmul(t->row[i], + t_node->sched->row[i][1 + n_param + j], + node->sched->row[first + j], + 1 + n_param + n_var); + } + return t; +} + +/* Apply the cluster schedule in "t_node" to the current band + * schedule of the nodes in "graph". + * + * In particular, replace the rows starting at band_start + * by the result of applying the cluster schedule in "t_node" + * to the original rows. + * + * The coincidence of the schedule is determined by the coincidence + * of the cluster schedule. + */ +static isl_stat transform(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_sched_node *t_node) +{ + int i, j; + int n_new; + int start, n; + + start = graph->band_start; + n = graph->n_total_row - start; + + n_new = isl_mat_rows(t_node->sched); + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + isl_mat *t; + + t = node_transformation(ctx, t_node, node, start, n); + node->sched = isl_mat_drop_rows(node->sched, start, n); + node->sched = isl_mat_concat(node->sched, t); + node->sched_map = isl_map_free(node->sched_map); + if (!node->sched) + return isl_stat_error; + for (j = 0; j < n_new; ++j) + node->coincident[start + j] = t_node->coincident[j]; + } + graph->n_total_row -= n; + graph->n_row -= n; + graph->n_total_row += n_new; + graph->n_row += n_new; + + return isl_stat_ok; +} + +/* Merge the clusters marked for merging in "c" into a single + * cluster using the cluster schedule in the current band of "merge_graph". + * The representative SCC for the new cluster is the SCC with + * the smallest index. + * + * The current band schedule of each SCC in the new cluster is obtained + * by applying the schedule of the corresponding original cluster + * to the original band schedule. + * All SCCs in the new cluster have the same number of schedule rows. + */ +static isl_stat merge(isl_ctx *ctx, struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + int i; + int cluster = -1; + isl_space *space; + + for (i = 0; i < c->n; ++i) { + struct isl_sched_node *node; + + if (!c->scc_in_merge[i]) + continue; + if (cluster < 0) + cluster = i; + space = cluster_space(&c->scc[i], c->scc_cluster[i]); + node = graph_find_node(ctx, merge_graph, space); + isl_space_free(space); + if (!node) + return isl_stat_error; + if (!is_node(merge_graph, node)) + isl_die(ctx, isl_error_internal, + "unable to find cluster", + return isl_stat_error); + if (transform(ctx, &c->scc[i], node) < 0) + return isl_stat_error; + c->scc_cluster[i] = cluster; + } + + return isl_stat_ok; +} + +/* Try and merge the clusters of SCCs marked in c->scc_in_merge + * by scheduling the current cluster bands with respect to each other. + * + * Construct a dependence graph with a space for each cluster and + * with the coordinates of each space corresponding to the schedule + * dimensions of the current band of that cluster. + * Construct a cluster schedule in this cluster dependence graph and + * apply it to the current cluster bands if it is applicable + * according to ok_to_merge. + * + * If the number of remaining schedule dimensions in a cluster + * with a non-maximal current schedule dimension is greater than + * the number of remaining schedule dimensions in clusters + * with a maximal current schedule dimension, then restrict + * the number of rows to be computed in the cluster schedule + * to the minimal such non-maximal current schedule dimension. + * Do this by adjusting merge_graph.maxvar. + * + * Return isl_bool_true if the clusters have effectively been merged + * into a single cluster. + * + * Note that since the standard scheduling algorithm minimizes the maximal + * distance over proximity constraints, the proximity constraints between + * the merged clusters may not be optimized any further than what is + * sufficient to bring the distances within the limits of the internal + * proximity constraints inside the individual clusters. + * It may therefore make sense to perform an additional translation step + * to bring the clusters closer to each other, while maintaining + * the linear part of the merging schedule found using the standard + * scheduling algorithm. + */ +static isl_bool try_merge(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + struct isl_sched_graph merge_graph = { 0 }; + isl_bool merged; + + if (init_merge_graph(ctx, graph, c, &merge_graph) < 0) + goto error; + + if (compute_maxvar(&merge_graph) < 0) + goto error; + if (adjust_maxvar_to_slack(ctx, &merge_graph,c) < 0) + goto error; + if (compute_schedule_wcc_band(ctx, &merge_graph) < 0) + goto error; + merged = ok_to_merge(ctx, graph, c, &merge_graph); + if (merged && merge(ctx, c, &merge_graph) < 0) + goto error; + + graph_free(ctx, &merge_graph); + return merged; +error: + graph_free(ctx, &merge_graph); + return isl_bool_error; +} + +/* Is there any edge marked "no_merge" between two SCCs that are + * about to be merged (i.e., that are set in "scc_in_merge")? + * "merge_edge" is the proximity edge along which the clusters of SCCs + * are going to be merged. + * + * If there is any edge between two SCCs with a negative weight, + * while the weight of "merge_edge" is non-negative, then this + * means that the edge was postponed. "merge_edge" should then + * also be postponed since merging along the edge with negative weight should + * be postponed until all edges with non-negative weight have been tried. + * Replace the weight of "merge_edge" by a negative weight as well and + * tell the caller not to attempt a merge. + */ +static int any_no_merge(struct isl_sched_graph *graph, int *scc_in_merge, + struct isl_sched_edge *merge_edge) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + + if (!scc_in_merge[edge->src->scc]) + continue; + if (!scc_in_merge[edge->dst->scc]) + continue; + if (edge->no_merge) + return 1; + if (merge_edge->weight >= 0 && edge->weight < 0) { + merge_edge->weight -= graph->max_weight + 1; + return 1; + } + } + + return 0; +} + +/* Merge the two clusters in "c" connected by the edge in "graph" + * with index "edge" into a single cluster. + * If it turns out to be impossible to merge these two clusters, + * then mark the edge as "no_merge" such that it will not be + * considered again. + * + * First mark all SCCs that need to be merged. This includes the SCCs + * in the two clusters, but it may also include the SCCs + * of intermediate clusters. + * If there is already a no_merge edge between any pair of such SCCs, + * then simply mark the current edge as no_merge as well. + * Likewise, if any of those edges was postponed by has_bounded_distances, + * then postpone the current edge as well. + * Otherwise, try and merge the clusters and mark "edge" as "no_merge" + * if the clusters did not end up getting merged, unless the non-merge + * is due to the fact that the edge was postponed. This postponement + * can be recognized by a change in weight (from non-negative to negative). + */ +static isl_stat merge_clusters_along_edge(isl_ctx *ctx, + struct isl_sched_graph *graph, int edge, struct isl_clustering *c) +{ + isl_bool merged; + int edge_weight = graph->edge[edge].weight; + + if (mark_merge_sccs(ctx, graph, edge, c) < 0) + return isl_stat_error; + + if (any_no_merge(graph, c->scc_in_merge, &graph->edge[edge])) + merged = isl_bool_false; + else + merged = try_merge(ctx, graph, c); + if (merged < 0) + return isl_stat_error; + if (!merged && edge_weight == graph->edge[edge].weight) + graph->edge[edge].no_merge = 1; + + return isl_stat_ok; +} + +/* Does "node" belong to the cluster identified by "cluster"? + */ +static int node_cluster_exactly(struct isl_sched_node *node, int cluster) +{ + return node->cluster == cluster; +} + +/* Does "edge" connect two nodes belonging to the cluster + * identified by "cluster"? + */ +static int edge_cluster_exactly(struct isl_sched_edge *edge, int cluster) +{ + return edge->src->cluster == cluster && edge->dst->cluster == cluster; +} + +/* Swap the schedule of "node1" and "node2". + * Both nodes have been derived from the same node in a common parent graph. + * Since the "coincident" field is shared with that node + * in the parent graph, there is no need to also swap this field. + */ +static void swap_sched(struct isl_sched_node *node1, + struct isl_sched_node *node2) +{ + isl_mat *sched; + isl_map *sched_map; + + sched = node1->sched; + node1->sched = node2->sched; + node2->sched = sched; + + sched_map = node1->sched_map; + node1->sched_map = node2->sched_map; + node2->sched_map = sched_map; +} + +/* Copy the current band schedule from the SCCs that form the cluster + * with index "pos" to the actual cluster at position "pos". + * By construction, the index of the first SCC that belongs to the cluster + * is also "pos". + * + * The order of the nodes inside both the SCCs and the cluster + * is assumed to be same as the order in the original "graph". + * + * Since the SCC graphs will no longer be used after this function, + * the schedules are actually swapped rather than copied. + */ +static isl_stat copy_partial(struct isl_sched_graph *graph, + struct isl_clustering *c, int pos) +{ + int i, j; + + c->cluster[pos].n_total_row = c->scc[pos].n_total_row; + c->cluster[pos].n_row = c->scc[pos].n_row; + c->cluster[pos].maxvar = c->scc[pos].maxvar; + j = 0; + for (i = 0; i < graph->n; ++i) { + int k; + int s; + + if (graph->node[i].cluster != pos) + continue; + s = graph->node[i].scc; + k = c->scc_node[s]++; + swap_sched(&c->cluster[pos].node[j], &c->scc[s].node[k]); + if (c->scc[s].maxvar > c->cluster[pos].maxvar) + c->cluster[pos].maxvar = c->scc[s].maxvar; + ++j; + } + + return isl_stat_ok; +} + +/* Is there a (conditional) validity dependence from node[j] to node[i], + * forcing node[i] to follow node[j] or do the nodes belong to the same + * cluster? + */ +static isl_bool node_follows_strong_or_same_cluster(int i, int j, void *user) +{ + struct isl_sched_graph *graph = user; + + if (graph->node[i].cluster == graph->node[j].cluster) + return isl_bool_true; + return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]); +} + +/* Extract the merged clusters of SCCs in "graph", sort them, and + * store them in c->clusters. Update c->scc_cluster accordingly. + * + * First keep track of the cluster containing the SCC to which a node + * belongs in the node itself. + * Then extract the clusters into c->clusters, copying the current + * band schedule from the SCCs that belong to the cluster. + * Do this only once per cluster. + * + * Finally, topologically sort the clusters and update c->scc_cluster + * to match the new scc numbering. While the SCCs were originally + * sorted already, some SCCs that depend on some other SCCs may + * have been merged with SCCs that appear before these other SCCs. + * A reordering may therefore be required. + */ +static isl_stat extract_clusters(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + int i; + + for (i = 0; i < graph->n; ++i) + graph->node[i].cluster = c->scc_cluster[graph->node[i].scc]; + + for (i = 0; i < graph->scc; ++i) { + if (c->scc_cluster[i] != i) + continue; + if (extract_sub_graph(ctx, graph, &node_cluster_exactly, + &edge_cluster_exactly, i, &c->cluster[i]) < 0) + return isl_stat_error; + c->cluster[i].src_scc = -1; + c->cluster[i].dst_scc = -1; + if (copy_partial(graph, c, i) < 0) + return isl_stat_error; + } + + if (detect_ccs(ctx, graph, &node_follows_strong_or_same_cluster) < 0) + return isl_stat_error; + for (i = 0; i < graph->n; ++i) + c->scc_cluster[graph->node[i].scc] = graph->node[i].cluster; + + return isl_stat_ok; +} + +/* Compute weights on the proximity edges of "graph" that can + * be used by find_proximity to find the most appropriate + * proximity edge to use to merge two clusters in "c". + * The weights are also used by has_bounded_distances to determine + * whether the merge should be allowed. + * Store the maximum of the computed weights in graph->max_weight. + * + * The computed weight is a measure for the number of remaining schedule + * dimensions that can still be completely aligned. + * In particular, compute the number of equalities between + * input dimensions and output dimensions in the proximity constraints. + * The directions that are already handled by outer schedule bands + * are projected out prior to determining this number. + * + * Edges that will never be considered by find_proximity are ignored. + */ +static isl_stat compute_weights(struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + int i; + + graph->max_weight = 0; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + struct isl_sched_node *src = edge->src; + struct isl_sched_node *dst = edge->dst; + isl_basic_map *hull; + isl_bool prox; + int n_in, n_out; + + prox = is_non_empty_proximity(edge); + if (prox < 0) + return isl_stat_error; + if (!prox) + continue; + if (bad_cluster(&c->scc[edge->src->scc]) || + bad_cluster(&c->scc[edge->dst->scc])) + continue; + if (c->scc_cluster[edge->dst->scc] == + c->scc_cluster[edge->src->scc]) + continue; + + hull = isl_map_affine_hull(isl_map_copy(edge->map)); + hull = isl_basic_map_transform_dims(hull, isl_dim_in, 0, + isl_mat_copy(src->vmap)); + hull = isl_basic_map_transform_dims(hull, isl_dim_out, 0, + isl_mat_copy(dst->vmap)); + hull = isl_basic_map_project_out(hull, + isl_dim_in, 0, src->rank); + hull = isl_basic_map_project_out(hull, + isl_dim_out, 0, dst->rank); + hull = isl_basic_map_remove_divs(hull); + n_in = isl_basic_map_dim(hull, isl_dim_in); + n_out = isl_basic_map_dim(hull, isl_dim_out); + hull = isl_basic_map_drop_constraints_not_involving_dims(hull, + isl_dim_in, 0, n_in); + hull = isl_basic_map_drop_constraints_not_involving_dims(hull, + isl_dim_out, 0, n_out); + if (!hull) + return isl_stat_error; + edge->weight = isl_basic_map_n_equality(hull); + isl_basic_map_free(hull); + + if (edge->weight > graph->max_weight) + graph->max_weight = edge->weight; + } + + return isl_stat_ok; +} + +/* Call compute_schedule_finish_band on each of the clusters in "c" + * in their topological order. This order is determined by the scc + * fields of the nodes in "graph". + * Combine the results in a sequence expressing the topological order. + * + * If there is only one cluster left, then there is no need to introduce + * a sequence node. Also, in this case, the cluster necessarily contains + * the SCC at position 0 in the original graph and is therefore also + * stored in the first cluster of "c". + */ +static __isl_give isl_schedule_node *finish_bands_clustering( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + int i; + isl_ctx *ctx; + isl_union_set_list *filters; + + if (graph->scc == 1) + return compute_schedule_finish_band(node, &c->cluster[0], 0); + + ctx = isl_schedule_node_get_ctx(node); + + filters = extract_sccs(ctx, graph); + node = isl_schedule_node_insert_sequence(node, filters); + + for (i = 0; i < graph->scc; ++i) { + int j = c->scc_cluster[i]; + node = isl_schedule_node_child(node, i); + node = isl_schedule_node_child(node, 0); + node = compute_schedule_finish_band(node, &c->cluster[j], 0); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); + } + + return node; +} + +/* Compute a schedule for a connected dependence graph by first considering + * each strongly connected component (SCC) in the graph separately and then + * incrementally combining them into clusters. + * Return the updated schedule node. + * + * Initially, each cluster consists of a single SCC, each with its + * own band schedule. The algorithm then tries to merge pairs + * of clusters along a proximity edge until no more suitable + * proximity edges can be found. During this merging, the schedule + * is maintained in the individual SCCs. + * After the merging is completed, the full resulting clusters + * are extracted and in finish_bands_clustering, + * compute_schedule_finish_band is called on each of them to integrate + * the band into "node" and to continue the computation. + * + * compute_weights initializes the weights that are used by find_proximity. + */ +static __isl_give isl_schedule_node *compute_schedule_wcc_clustering( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + isl_ctx *ctx; + struct isl_clustering c; + int i; + + ctx = isl_schedule_node_get_ctx(node); + + if (clustering_init(ctx, &c, graph) < 0) + goto error; + + if (compute_weights(graph, &c) < 0) + goto error; + + for (;;) { + i = find_proximity(graph, &c); + if (i < 0) + goto error; + if (i >= graph->n_edge) + break; + if (merge_clusters_along_edge(ctx, graph, i, &c) < 0) + goto error; + } + + if (extract_clusters(ctx, graph, &c) < 0) + goto error; + + node = finish_bands_clustering(node, graph, &c); + + clustering_free(ctx, &c); + return node; +error: + clustering_free(ctx, &c); + return isl_schedule_node_free(node); +} + +/* Compute a schedule for a connected dependence graph and return + * the updated schedule node. + * + * If Feautrier's algorithm is selected, we first recursively try to satisfy + * as many validity dependences as possible. When all validity dependences + * are satisfied we extend the schedule to a full-dimensional schedule. + * + * Call compute_schedule_wcc_whole or compute_schedule_wcc_clustering + * depending on whether the user has selected the option to try and + * compute a schedule for the entire (weakly connected) component first. + * If there is only a single strongly connected component (SCC), then + * there is no point in trying to combine SCCs + * in compute_schedule_wcc_clustering, so compute_schedule_wcc_whole + * is called instead. + */ +static __isl_give isl_schedule_node *compute_schedule_wcc( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + isl_ctx *ctx; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); + if (detect_sccs(ctx, graph) < 0) + return isl_schedule_node_free(node); + + if (compute_maxvar(graph) < 0) + return isl_schedule_node_free(node); + + if (need_feautrier_step(ctx, graph)) + return compute_schedule_wcc_feautrier(node, graph); + + if (graph->scc <= 1 || isl_options_get_schedule_whole_component(ctx)) + return compute_schedule_wcc_whole(node, graph); + else + return compute_schedule_wcc_clustering(node, graph); +} + +/* Compute a schedule for each group of nodes identified by node->scc + * separately and then combine them in a sequence node (or as set node + * if graph->weak is set) inserted at position "node" of the schedule tree. + * Return the updated schedule node. + * + * If "wcc" is set then each of the groups belongs to a single + * weakly connected component in the dependence graph so that + * there is no need for compute_sub_schedule to look for weakly + * connected components. + * + * If a set node would be introduced and if the number of components + * is equal to the number of nodes, then check if the schedule + * is already complete. If so, a redundant set node would be introduced + * (without any further descendants) stating that the statements + * can be executed in arbitrary order, which is also expressed + * by the absence of any node. Refrain from inserting any nodes + * in this case and simply return. + */ +static __isl_give isl_schedule_node *compute_component_schedule( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int wcc) +{ + int component; + isl_ctx *ctx; + isl_union_set_list *filters; + + if (!node) + return NULL; + + if (graph->weak && graph->scc == graph->n) { + if (compute_maxvar(graph) < 0) + return isl_schedule_node_free(node); + if (graph->n_row >= graph->maxvar) + return node; + } + + ctx = isl_schedule_node_get_ctx(node); + filters = extract_sccs(ctx, graph); + if (graph->weak) + node = isl_schedule_node_insert_set(node, filters); + else + node = isl_schedule_node_insert_sequence(node, filters); + + for (component = 0; component < graph->scc; ++component) { + node = isl_schedule_node_child(node, component); + node = isl_schedule_node_child(node, 0); + node = compute_sub_schedule(node, ctx, graph, + &node_scc_exactly, + &edge_scc_exactly, component, wcc); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); + } + + return node; +} + +/* Compute a schedule for the given dependence graph and insert it at "node". + * Return the updated schedule node. + * + * We first check if the graph is connected (through validity and conditional + * validity dependences) and, if not, compute a schedule + * for each component separately. + * If the schedule_serialize_sccs option is set, then we check for strongly + * connected components instead and compute a separate schedule for + * each such strongly connected component. + */ +static __isl_give isl_schedule_node *compute_schedule(isl_schedule_node *node, + struct isl_sched_graph *graph) +{ + isl_ctx *ctx; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); + if (isl_options_get_schedule_serialize_sccs(ctx)) { + if (detect_sccs(ctx, graph) < 0) + return isl_schedule_node_free(node); + } else { + if (detect_wccs(ctx, graph) < 0) + return isl_schedule_node_free(node); + } + + if (graph->scc > 1) + return compute_component_schedule(node, graph, 1); + + return compute_schedule_wcc(node, graph); +} + +/* Compute a schedule on sc->domain that respects the given schedule + * constraints. + * + * In particular, the schedule respects all the validity dependences. + * If the default isl scheduling algorithm is used, it tries to minimize + * the dependence distances over the proximity dependences. + * If Feautrier's scheduling algorithm is used, the proximity dependence + * distances are only minimized during the extension to a full-dimensional + * schedule. + * + * If there are any condition and conditional validity dependences, + * then the conditional validity dependences may be violated inside + * a tilable band, provided they have no adjacent non-local + * condition dependences. + */ +__isl_give isl_schedule *isl_schedule_constraints_compute_schedule( + __isl_take isl_schedule_constraints *sc) +{ + isl_ctx *ctx = isl_schedule_constraints_get_ctx(sc); + struct isl_sched_graph graph = { 0 }; + isl_schedule *sched; + isl_schedule_node *node; + isl_union_set *domain; + + sc = isl_schedule_constraints_align_params(sc); + + domain = isl_schedule_constraints_get_domain(sc); + if (isl_union_set_n_set(domain) == 0) { + isl_schedule_constraints_free(sc); + return isl_schedule_from_domain(domain); + } + + if (graph_init(&graph, sc) < 0) + domain = isl_union_set_free(domain); + + node = isl_schedule_node_from_domain(domain); + node = isl_schedule_node_child(node, 0); + if (graph.n > 0) + node = compute_schedule(node, &graph); + sched = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + graph_free(ctx, &graph); + isl_schedule_constraints_free(sc); + + return sched; +} + +/* Compute a schedule for the given union of domains that respects + * all the validity dependences and minimizes + * the dependence distances over the proximity dependences. + * + * This function is kept for backward compatibility. + */ +__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_schedule_constraints *sc; + + sc = isl_schedule_constraints_on_domain(domain); + sc = isl_schedule_constraints_set_validity(sc, validity); + sc = isl_schedule_constraints_set_proximity(sc, proximity); + + return isl_schedule_constraints_compute_schedule(sc); +} Index: contrib/isl/isl_seq.h =================================================================== --- /dev/null +++ contrib/isl/isl_seq.h @@ -0,0 +1,63 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_SEQ_H +#define ISL_SEQ_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Some common operations on sequences of isl_int's */ + +void isl_seq_clr(isl_int *p, unsigned len); +void isl_seq_set(isl_int *p, isl_int v, unsigned len); +void isl_seq_set_si(isl_int *p, int v, unsigned len); +void isl_seq_neg(isl_int *dst, isl_int *src, unsigned len); +void isl_seq_cpy(isl_int *dst, isl_int *src, unsigned len); +void isl_seq_addmul(isl_int *dst, isl_int f, isl_int *src, unsigned len); +void isl_seq_submul(isl_int *dst, isl_int f, isl_int *src, unsigned len); +void isl_seq_swp_or_cpy(isl_int *dst, isl_int *src, unsigned len); +void isl_seq_scale(isl_int *dst, isl_int *src, isl_int f, unsigned len); +void isl_seq_scale_down(isl_int *dst, isl_int *src, isl_int f, unsigned len); +void isl_seq_cdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len); +void isl_seq_fdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len); +void isl_seq_fdiv_r(isl_int *dst, isl_int *src, isl_int m, unsigned len); +void isl_seq_combine(isl_int *dst, isl_int m1, isl_int *src1, + isl_int m2, isl_int *src2, unsigned len); +void isl_seq_elim(isl_int *dst, isl_int *src, unsigned pos, unsigned len, + isl_int *m); +void isl_seq_abs_max(isl_int *p, unsigned len, isl_int *max); +void isl_seq_gcd(isl_int *p, unsigned len, isl_int *gcd); +void isl_seq_lcm(isl_int *p, unsigned len, isl_int *lcm); +void isl_seq_normalize(struct isl_ctx *ctx, isl_int *p, unsigned len); +void isl_seq_inner_product(isl_int *p1, isl_int *p2, unsigned len, + isl_int *prod); +int isl_seq_first_non_zero(isl_int *p, unsigned len); +int isl_seq_last_non_zero(isl_int *p, unsigned len); +int isl_seq_abs_min_non_zero(isl_int *p, unsigned len); +int isl_seq_eq(isl_int *p1, isl_int *p2, unsigned len); +int isl_seq_cmp(isl_int *p1, isl_int *p2, unsigned len); +int isl_seq_is_neg(isl_int *p1, isl_int *p2, unsigned len); + +void isl_seq_substitute(isl_int *p, int pos, isl_int *subs, + int p_len, int subs_len, isl_int v); + +uint32_t isl_seq_get_hash(isl_int *p, unsigned len); +uint32_t isl_seq_get_hash_bits(isl_int *p, unsigned len, unsigned bits); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/isl_seq.c =================================================================== --- /dev/null +++ contrib/isl/isl_seq.c @@ -0,0 +1,360 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2011 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include + +void isl_seq_clr(isl_int *p, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_set_si(p[i], 0); +} + +void isl_seq_set_si(isl_int *p, int v, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_set_si(p[i], v); +} + +void isl_seq_set(isl_int *p, isl_int v, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_set(p[i], v); +} + +void isl_seq_neg(isl_int *dst, isl_int *src, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_neg(dst[i], src[i]); +} + +void isl_seq_cpy(isl_int *dst, isl_int *src, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_set(dst[i], src[i]); +} + +void isl_seq_submul(isl_int *dst, isl_int f, isl_int *src, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_submul(dst[i], f, src[i]); +} + +void isl_seq_addmul(isl_int *dst, isl_int f, isl_int *src, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_addmul(dst[i], f, src[i]); +} + +void isl_seq_swp_or_cpy(isl_int *dst, isl_int *src, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_swap_or_set(dst[i], src[i]); +} + +void isl_seq_scale(isl_int *dst, isl_int *src, isl_int m, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_mul(dst[i], src[i], m); +} + +void isl_seq_scale_down(isl_int *dst, isl_int *src, isl_int m, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_divexact(dst[i], src[i], m); +} + +void isl_seq_cdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_cdiv_q(dst[i], src[i], m); +} + +void isl_seq_fdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_fdiv_q(dst[i], src[i], m); +} + +void isl_seq_fdiv_r(isl_int *dst, isl_int *src, isl_int m, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + isl_int_fdiv_r(dst[i], src[i], m); +} + +void isl_seq_combine(isl_int *dst, isl_int m1, isl_int *src1, + isl_int m2, isl_int *src2, unsigned len) +{ + int i; + isl_int tmp; + + if (dst == src1 && isl_int_is_one(m1)) { + if (isl_int_is_zero(m2)) + return; + for (i = 0; i < len; ++i) + isl_int_addmul(src1[i], m2, src2[i]); + return; + } + + isl_int_init(tmp); + for (i = 0; i < len; ++i) { + isl_int_mul(tmp, m1, src1[i]); + isl_int_addmul(tmp, m2, src2[i]); + isl_int_set(dst[i], tmp); + } + isl_int_clear(tmp); +} + +/* + * Let d = dst[pos] and s = src[pos] + * dst is replaced by |s| dst - sgn(s)d src + */ +void isl_seq_elim(isl_int *dst, isl_int *src, unsigned pos, unsigned len, + isl_int *m) +{ + isl_int a; + isl_int b; + + if (isl_int_is_zero(dst[pos])) + return; + + isl_int_init(a); + isl_int_init(b); + + isl_int_gcd(a, src[pos], dst[pos]); + isl_int_divexact(b, dst[pos], a); + if (isl_int_is_pos(src[pos])) + isl_int_neg(b, b); + isl_int_divexact(a, src[pos], a); + isl_int_abs(a, a); + isl_seq_combine(dst, a, dst, b, src, len); + + if (m) + isl_int_mul(*m, *m, a); + + isl_int_clear(a); + isl_int_clear(b); +} + +int isl_seq_eq(isl_int *p1, isl_int *p2, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + if (isl_int_ne(p1[i], p2[i])) + return 0; + return 1; +} + +int isl_seq_cmp(isl_int *p1, isl_int *p2, unsigned len) +{ + int i; + int cmp; + for (i = 0; i < len; ++i) + if ((cmp = isl_int_cmp(p1[i], p2[i])) != 0) + return cmp; + return 0; +} + +int isl_seq_is_neg(isl_int *p1, isl_int *p2, unsigned len) +{ + int i; + + for (i = 0; i < len; ++i) { + if (isl_int_abs_ne(p1[i], p2[i])) + return 0; + if (isl_int_is_zero(p1[i])) + continue; + if (isl_int_eq(p1[i], p2[i])) + return 0; + } + return 1; +} + +int isl_seq_first_non_zero(isl_int *p, unsigned len) +{ + int i; + + for (i = 0; i < len; ++i) + if (!isl_int_is_zero(p[i])) + return i; + return -1; +} + +int isl_seq_last_non_zero(isl_int *p, unsigned len) +{ + int i; + + for (i = len - 1; i >= 0; --i) + if (!isl_int_is_zero(p[i])) + return i; + return -1; +} + +void isl_seq_abs_max(isl_int *p, unsigned len, isl_int *max) +{ + int i; + + isl_int_set_si(*max, 0); + + for (i = 0; i < len; ++i) + if (isl_int_abs_gt(p[i], *max)) + isl_int_abs(*max, p[i]); +} + +int isl_seq_abs_min_non_zero(isl_int *p, unsigned len) +{ + int i, min = isl_seq_first_non_zero(p, len); + if (min < 0) + return -1; + for (i = min + 1; i < len; ++i) { + if (isl_int_is_zero(p[i])) + continue; + if (isl_int_abs_lt(p[i], p[min])) + min = i; + } + return min; +} + +void isl_seq_gcd(isl_int *p, unsigned len, isl_int *gcd) +{ + int i, min = isl_seq_abs_min_non_zero(p, len); + + if (min < 0) { + isl_int_set_si(*gcd, 0); + return; + } + isl_int_abs(*gcd, p[min]); + for (i = 0; isl_int_cmp_si(*gcd, 1) > 0 && i < len; ++i) { + if (i == min) + continue; + if (isl_int_is_zero(p[i])) + continue; + isl_int_gcd(*gcd, *gcd, p[i]); + } +} + +void isl_seq_normalize(struct isl_ctx *ctx, isl_int *p, unsigned len) +{ + if (len == 0) + return; + isl_seq_gcd(p, len, &ctx->normalize_gcd); + if (!isl_int_is_zero(ctx->normalize_gcd) && + !isl_int_is_one(ctx->normalize_gcd)) + isl_seq_scale_down(p, p, ctx->normalize_gcd, len); +} + +void isl_seq_lcm(isl_int *p, unsigned len, isl_int *lcm) +{ + int i; + + if (len == 0) { + isl_int_set_si(*lcm, 1); + return; + } + isl_int_set(*lcm, p[0]); + for (i = 1; i < len; ++i) + isl_int_lcm(*lcm, *lcm, p[i]); +} + +void isl_seq_inner_product(isl_int *p1, isl_int *p2, unsigned len, + isl_int *prod) +{ + int i; + if (len == 0) { + isl_int_set_si(*prod, 0); + return; + } + isl_int_mul(*prod, p1[0], p2[0]); + for (i = 1; i < len; ++i) + isl_int_addmul(*prod, p1[i], p2[i]); +} + +uint32_t isl_seq_hash(isl_int *p, unsigned len, uint32_t hash) +{ + int i; + for (i = 0; i < len; ++i) { + if (isl_int_is_zero(p[i])) + continue; + hash *= 16777619; + hash ^= (i & 0xFF); + hash = isl_int_hash(p[i], hash); + } + return hash; +} + +/* Given two affine expressions "p" of length p_len (including the + * denominator and the constant term) and "subs" of length subs_len, + * plug in "subs" for the variable at position "pos". + * The variables of "subs" and "p" are assumed to match up to subs_len, + * but "p" may have additional variables. + * "v" is an initialized isl_int that can be used internally. + * + * In particular, if "p" represents the expression + * + * (a i + g)/m + * + * with i the variable at position "pos" and "subs" represents the expression + * + * f/d + * + * then the result represents the expression + * + * (a f + d g)/(m d) + * + */ +void isl_seq_substitute(isl_int *p, int pos, isl_int *subs, + int p_len, int subs_len, isl_int v) +{ + isl_int_set(v, p[1 + pos]); + isl_int_set_si(p[1 + pos], 0); + isl_seq_combine(p + 1, subs[0], p + 1, v, subs + 1, subs_len - 1); + isl_seq_scale(p + subs_len, p + subs_len, subs[0], p_len - subs_len); + isl_int_mul(p[0], p[0], subs[0]); +} + +uint32_t isl_seq_get_hash(isl_int *p, unsigned len) +{ + uint32_t hash = isl_hash_init(); + + return isl_seq_hash(p, len, hash); +} + +uint32_t isl_seq_get_hash_bits(isl_int *p, unsigned len, unsigned bits) +{ + uint32_t hash; + + hash = isl_seq_get_hash(p, len); + return isl_hash_bits(hash, bits); +} + +void isl_seq_dump(isl_int *p, unsigned len) +{ + int i; + + for (i = 0; i < len; ++i) { + if (i) + fprintf(stderr, " "); + isl_int_print(stderr, p[i], 0); + } + fprintf(stderr, "\n"); +} Index: contrib/isl/isl_set_list.c =================================================================== --- /dev/null +++ contrib/isl/isl_set_list.c @@ -0,0 +1,32 @@ +#include +#include + +#undef EL +#define EL isl_basic_set + +#include + +#undef EL +#define EL isl_set + +#include + +#undef EL +#define EL isl_union_set + +#include + +#undef BASE +#define BASE basic_set + +#include + +#undef BASE +#define BASE set + +#include + +#undef BASE +#define BASE union_set + +#include Index: contrib/isl/isl_sort.h =================================================================== --- /dev/null +++ contrib/isl/isl_sort.h @@ -0,0 +1,9 @@ +#ifndef ISL_SORT_H +#define ISL_SORT_H + +#include + +int isl_sort(void *const pbase, size_t total_elems, size_t size, + int (*cmp)(const void *, const void *, void *arg), void *arg); + +#endif Index: contrib/isl/isl_sort.c =================================================================== --- /dev/null +++ contrib/isl/isl_sort.c @@ -0,0 +1,157 @@ +/* + * The code of this file was taken from http://jeffreystedfast.blogspot.be, + * where it was posted in 2011 by Jeffrey Stedfast under the MIT license. + * The MIT license text is as follows: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#define MID(lo, hi) (lo + ((hi - lo) >> 1)) + +/* The code here is an optimized merge sort. Starting from a generic merge sort + * the following optimizations were applied: + * + * o Batching of memcpy() calls: Instead of calling memcpy() to copy each and + * every element into a temporary buffer, blocks of elements are copied + * at a time. + * + * o To reduce the number of memcpy() calls further, copying leading + * and trailing elements into our temporary buffer is avoided, in case it is + * not necessary to merge them. + * + * A further optimization could be to specialize memcpy calls based on the + * size of the types we compare. For now, this code does not include the + * relevant optimization, as clang e.g. inlines a very efficient memcpy() + * implementation. It is not clear, that the specialized version as provided in + * the blog post, is really superior to the one that will be inlined by + * default. So we decided to keep the code simple until this optimization was + * proven to be beneficial. + */ + +static void +msort (void *array, void *buf, size_t low, size_t high, size_t size, + int (* compare) (const void *, const void *, void *), void *arg) +{ + char *a1, *al, *am, *ah, *ls, *hs, *lo, *hi, *b; + size_t copied = 0; + size_t mid; + + mid = MID (low, high); + + if (mid + 1 < high) + msort (array, buf, mid + 1, high, size, compare, arg); + + if (mid > low) + msort (array, buf, low, mid, size, compare, arg); + + ah = ((char *) array) + ((high + 1) * size); + am = ((char *) array) + ((mid + 1) * size); + a1 = al = ((char *) array) + (low * size); + + b = (char *) buf; + lo = al; + hi = am; + + do { + ls = lo; + hs = hi; + + if (lo > al || hi > am) { + /* our last loop already compared lo & hi and found lo <= hi */ + lo += size; + } + + while (lo < am && compare (lo, hi, arg) <= 0) + lo += size; + + if (lo < am) { + if (copied == 0) { + /* avoid copying the leading items */ + a1 = lo; + ls = lo; + } + + /* our last compare tells us hi < lo */ + hi += size; + + while (hi < ah && compare (hi, lo, arg) < 0) + hi += size; + + if (lo > ls) { + memcpy (b, ls, lo - ls); + copied += (lo - ls); + b += (lo - ls); + } + + memcpy (b, hs, hi - hs); + copied += (hi - hs); + b += (hi - hs); + } else if (copied) { + memcpy (b, ls, lo - ls); + copied += (lo - ls); + b += (lo - ls); + + /* copy everything we needed to re-order back into array */ + memcpy (a1, buf, copied); + return; + } else { + /* everything already in order */ + return; + } + } while (hi < ah); + + if (lo < am) { + memcpy (b, lo, am - lo); + copied += (am - lo); + } + + memcpy (a1, buf, copied); +} + +static int +MergeSort (void *base, size_t nmemb, size_t size, + int (* compare) (const void *, const void *, void *), void *arg) +{ + void *tmp; + + if (nmemb < 2) + return 0; + + if (!(tmp = malloc (nmemb * size))) { + errno = ENOMEM; + return -1; + } + + msort (base, tmp, 0, nmemb - 1, size, compare, arg); + + free (tmp); + + return 0; +} + +int isl_sort(void *const pbase, size_t total_elems, size_t size, + int (*cmp)(const void *, const void *, void *arg), void *arg) +{ + return MergeSort (pbase, total_elems, size, cmp, arg); +} Index: contrib/isl/isl_space.c =================================================================== --- /dev/null +++ contrib/isl/isl_space.c @@ -0,0 +1,2643 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2013-2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include +#include + +isl_ctx *isl_space_get_ctx(__isl_keep isl_space *dim) +{ + return dim ? dim->ctx : NULL; +} + +__isl_give isl_space *isl_space_alloc(isl_ctx *ctx, + unsigned nparam, unsigned n_in, unsigned n_out) +{ + isl_space *dim; + + dim = isl_alloc_type(ctx, struct isl_space); + if (!dim) + return NULL; + + dim->ctx = ctx; + isl_ctx_ref(ctx); + dim->ref = 1; + dim->nparam = nparam; + dim->n_in = n_in; + dim->n_out = n_out; + + dim->tuple_id[0] = NULL; + dim->tuple_id[1] = NULL; + + dim->nested[0] = NULL; + dim->nested[1] = NULL; + + dim->n_id = 0; + dim->ids = NULL; + + return dim; +} + +/* Mark the space as being that of a set, by setting the domain tuple + * to isl_id_none. + */ +static __isl_give isl_space *mark_as_set(__isl_take isl_space *space) +{ + space = isl_space_cow(space); + if (!space) + return NULL; + space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none); + return space; +} + +/* Is the space that of a set? + */ +isl_bool isl_space_is_set(__isl_keep isl_space *space) +{ + if (!space) + return isl_bool_error; + if (space->n_in != 0 || space->nested[0]) + return isl_bool_false; + if (space->tuple_id[0] != &isl_id_none) + return isl_bool_false; + return isl_bool_true; +} + +/* Is the given space that of a map? + */ +isl_bool isl_space_is_map(__isl_keep isl_space *space) +{ + if (!space) + return isl_bool_error; + return space->tuple_id[0] != &isl_id_none && + space->tuple_id[1] != &isl_id_none; +} + +__isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx, + unsigned nparam, unsigned dim) +{ + isl_space *space; + space = isl_space_alloc(ctx, nparam, 0, dim); + space = mark_as_set(space); + return space; +} + +/* Mark the space as being that of a parameter domain, by setting + * both tuples to isl_id_none. + */ +static __isl_give isl_space *mark_as_params(isl_space *space) +{ + if (!space) + return NULL; + space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none); + space = isl_space_set_tuple_id(space, isl_dim_out, &isl_id_none); + return space; +} + +/* Is the space that of a parameter domain? + */ +isl_bool isl_space_is_params(__isl_keep isl_space *space) +{ + if (!space) + return isl_bool_error; + if (space->n_in != 0 || space->nested[0] || + space->n_out != 0 || space->nested[1]) + return isl_bool_false; + if (space->tuple_id[0] != &isl_id_none) + return isl_bool_false; + if (space->tuple_id[1] != &isl_id_none) + return isl_bool_false; + return isl_bool_true; +} + +/* Create a space for a parameter domain. + */ +__isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam) +{ + isl_space *space; + space = isl_space_alloc(ctx, nparam, 0, 0); + space = mark_as_params(space); + return space; +} + +static unsigned global_pos(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos) +{ + struct isl_ctx *ctx = dim->ctx; + + switch (type) { + case isl_dim_param: + isl_assert(ctx, pos < dim->nparam, + return isl_space_dim(dim, isl_dim_all)); + return pos; + case isl_dim_in: + isl_assert(ctx, pos < dim->n_in, + return isl_space_dim(dim, isl_dim_all)); + return pos + dim->nparam; + case isl_dim_out: + isl_assert(ctx, pos < dim->n_out, + return isl_space_dim(dim, isl_dim_all)); + return pos + dim->nparam + dim->n_in; + default: + isl_assert(ctx, 0, return isl_space_dim(dim, isl_dim_all)); + } + return isl_space_dim(dim, isl_dim_all); +} + +/* Extend length of ids array to the total number of dimensions. + */ +static __isl_give isl_space *extend_ids(__isl_take isl_space *dim) +{ + isl_id **ids; + int i; + + if (isl_space_dim(dim, isl_dim_all) <= dim->n_id) + return dim; + + if (!dim->ids) { + dim->ids = isl_calloc_array(dim->ctx, + isl_id *, isl_space_dim(dim, isl_dim_all)); + if (!dim->ids) + goto error; + } else { + ids = isl_realloc_array(dim->ctx, dim->ids, + isl_id *, isl_space_dim(dim, isl_dim_all)); + if (!ids) + goto error; + dim->ids = ids; + for (i = dim->n_id; i < isl_space_dim(dim, isl_dim_all); ++i) + dim->ids[i] = NULL; + } + + dim->n_id = isl_space_dim(dim, isl_dim_all); + + return dim; +error: + isl_space_free(dim); + return NULL; +} + +static __isl_give isl_space *set_id(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) +{ + dim = isl_space_cow(dim); + + if (!dim) + goto error; + + pos = global_pos(dim, type, pos); + if (pos == isl_space_dim(dim, isl_dim_all)) + goto error; + + if (pos >= dim->n_id) { + if (!id) + return dim; + dim = extend_ids(dim); + if (!dim) + goto error; + } + + dim->ids[pos] = id; + + return dim; +error: + isl_id_free(id); + isl_space_free(dim); + return NULL; +} + +static __isl_keep isl_id *get_id(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos) +{ + if (!dim) + return NULL; + + pos = global_pos(dim, type, pos); + if (pos == isl_space_dim(dim, isl_dim_all)) + return NULL; + if (pos >= dim->n_id) + return NULL; + return dim->ids[pos]; +} + +static unsigned offset(__isl_keep isl_space *dim, enum isl_dim_type type) +{ + switch (type) { + case isl_dim_param: return 0; + case isl_dim_in: return dim->nparam; + case isl_dim_out: return dim->nparam + dim->n_in; + default: return 0; + } +} + +static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type) +{ + switch (type) { + case isl_dim_param: return dim->nparam; + case isl_dim_in: return dim->n_in; + case isl_dim_out: return dim->n_out; + case isl_dim_all: return dim->nparam + dim->n_in + dim->n_out; + default: return 0; + } +} + +unsigned isl_space_dim(__isl_keep isl_space *dim, enum isl_dim_type type) +{ + if (!dim) + return 0; + return n(dim, type); +} + +unsigned isl_space_offset(__isl_keep isl_space *dim, enum isl_dim_type type) +{ + if (!dim) + return 0; + return offset(dim, type); +} + +static __isl_give isl_space *copy_ids(__isl_take isl_space *dst, + enum isl_dim_type dst_type, unsigned offset, __isl_keep isl_space *src, + enum isl_dim_type src_type) +{ + int i; + isl_id *id; + + if (!dst) + return NULL; + + for (i = 0; i < n(src, src_type); ++i) { + id = get_id(src, src_type, i); + if (!id) + continue; + dst = set_id(dst, dst_type, offset + i, isl_id_copy(id)); + if (!dst) + return NULL; + } + return dst; +} + +__isl_take isl_space *isl_space_dup(__isl_keep isl_space *dim) +{ + isl_space *dup; + if (!dim) + return NULL; + dup = isl_space_alloc(dim->ctx, dim->nparam, dim->n_in, dim->n_out); + if (!dup) + return NULL; + if (dim->tuple_id[0] && + !(dup->tuple_id[0] = isl_id_copy(dim->tuple_id[0]))) + goto error; + if (dim->tuple_id[1] && + !(dup->tuple_id[1] = isl_id_copy(dim->tuple_id[1]))) + goto error; + if (dim->nested[0] && !(dup->nested[0] = isl_space_copy(dim->nested[0]))) + goto error; + if (dim->nested[1] && !(dup->nested[1] = isl_space_copy(dim->nested[1]))) + goto error; + if (!dim->ids) + return dup; + dup = copy_ids(dup, isl_dim_param, 0, dim, isl_dim_param); + dup = copy_ids(dup, isl_dim_in, 0, dim, isl_dim_in); + dup = copy_ids(dup, isl_dim_out, 0, dim, isl_dim_out); + return dup; +error: + isl_space_free(dup); + return NULL; +} + +__isl_give isl_space *isl_space_cow(__isl_take isl_space *dim) +{ + if (!dim) + return NULL; + + if (dim->ref == 1) + return dim; + dim->ref--; + return isl_space_dup(dim); +} + +__isl_give isl_space *isl_space_copy(__isl_keep isl_space *dim) +{ + if (!dim) + return NULL; + + dim->ref++; + return dim; +} + +__isl_null isl_space *isl_space_free(__isl_take isl_space *space) +{ + int i; + + if (!space) + return NULL; + + if (--space->ref > 0) + return NULL; + + isl_id_free(space->tuple_id[0]); + isl_id_free(space->tuple_id[1]); + + isl_space_free(space->nested[0]); + isl_space_free(space->nested[1]); + + for (i = 0; i < space->n_id; ++i) + isl_id_free(space->ids[i]); + free(space->ids); + isl_ctx_deref(space->ctx); + + free(space); + + return NULL; +} + +/* Check if "s" is a valid dimension or tuple name. + * We currently only forbid names that look like a number. + * + * s is assumed to be non-NULL. + */ +static int name_ok(isl_ctx *ctx, const char *s) +{ + char *p; + long dummy; + + dummy = strtol(s, &p, 0); + if (p != s) + isl_die(ctx, isl_error_invalid, "name looks like a number", + return 0); + + return 1; +} + +/* Is it possible for the given dimension type to have a tuple id? + */ +static int space_can_have_id(__isl_keep isl_space *space, + enum isl_dim_type type) +{ + if (!space) + return 0; + if (isl_space_is_params(space)) + isl_die(space->ctx, isl_error_invalid, + "parameter spaces don't have tuple ids", return 0); + if (isl_space_is_set(space) && type != isl_dim_set) + isl_die(space->ctx, isl_error_invalid, + "set spaces can only have a set id", return 0); + if (type != isl_dim_in && type != isl_dim_out) + isl_die(space->ctx, isl_error_invalid, + "only input, output and set tuples can have ids", + return 0); + + return 1; +} + +/* Does the tuple have an id? + */ +isl_bool isl_space_has_tuple_id(__isl_keep isl_space *dim, + enum isl_dim_type type) +{ + if (!space_can_have_id(dim, type)) + return isl_bool_error; + return dim->tuple_id[type - isl_dim_in] != NULL; +} + +__isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *dim, + enum isl_dim_type type) +{ + int has_id; + + if (!dim) + return NULL; + has_id = isl_space_has_tuple_id(dim, type); + if (has_id < 0) + return NULL; + if (!has_id) + isl_die(dim->ctx, isl_error_invalid, + "tuple has no id", return NULL); + return isl_id_copy(dim->tuple_id[type - isl_dim_in]); +} + +__isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *dim, + enum isl_dim_type type, __isl_take isl_id *id) +{ + dim = isl_space_cow(dim); + if (!dim || !id) + goto error; + if (type != isl_dim_in && type != isl_dim_out) + isl_die(dim->ctx, isl_error_invalid, + "only input, output and set tuples can have names", + goto error); + + isl_id_free(dim->tuple_id[type - isl_dim_in]); + dim->tuple_id[type - isl_dim_in] = id; + + return dim; +error: + isl_id_free(id); + isl_space_free(dim); + return NULL; +} + +__isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *dim, + enum isl_dim_type type) +{ + dim = isl_space_cow(dim); + if (!dim) + return NULL; + if (type != isl_dim_in && type != isl_dim_out) + isl_die(dim->ctx, isl_error_invalid, + "only input, output and set tuples can have names", + goto error); + + isl_id_free(dim->tuple_id[type - isl_dim_in]); + dim->tuple_id[type - isl_dim_in] = NULL; + + return dim; +error: + isl_space_free(dim); + return NULL; +} + +/* Set the id of the given dimension of "space" to "id". + * If the dimension already has an id, then it is replaced. + * If the dimension is a parameter, then we need to change it + * in the nested spaces (if any) as well. + */ +__isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *space, + enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) +{ + space = isl_space_cow(space); + if (!space || !id) + goto error; + + if (type == isl_dim_param) { + int i; + + for (i = 0; i < 2; ++i) { + if (!space->nested[i]) + continue; + space->nested[i] = + isl_space_set_dim_id(space->nested[i], + type, pos, isl_id_copy(id)); + if (!space->nested[i]) + goto error; + } + } + + isl_id_free(get_id(space, type, pos)); + return set_id(space, type, pos, id); +error: + isl_id_free(id); + isl_space_free(space); + return NULL; +} + +/* Reset the id of the given dimension of "space". + * If the dimension already has an id, then it is removed. + * If the dimension is a parameter, then we need to reset it + * in the nested spaces (if any) as well. + */ +__isl_give isl_space *isl_space_reset_dim_id(__isl_take isl_space *space, + enum isl_dim_type type, unsigned pos) +{ + space = isl_space_cow(space); + if (!space) + goto error; + + if (type == isl_dim_param) { + int i; + + for (i = 0; i < 2; ++i) { + if (!space->nested[i]) + continue; + space->nested[i] = + isl_space_reset_dim_id(space->nested[i], + type, pos); + if (!space->nested[i]) + goto error; + } + } + + isl_id_free(get_id(space, type, pos)); + return set_id(space, type, pos, NULL); +error: + isl_space_free(space); + return NULL; +} + +isl_bool isl_space_has_dim_id(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos) +{ + if (!dim) + return isl_bool_error; + return get_id(dim, type, pos) != NULL; +} + +__isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos) +{ + if (!dim) + return NULL; + if (!get_id(dim, type, pos)) + isl_die(dim->ctx, isl_error_invalid, + "dim has no id", return NULL); + return isl_id_copy(get_id(dim, type, pos)); +} + +__isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *dim, + enum isl_dim_type type, const char *s) +{ + isl_id *id; + + if (!dim) + return NULL; + + if (!s) + return isl_space_reset_tuple_id(dim, type); + + if (!name_ok(dim->ctx, s)) + goto error; + + id = isl_id_alloc(dim->ctx, s, NULL); + return isl_space_set_tuple_id(dim, type, id); +error: + isl_space_free(dim); + return NULL; +} + +/* Does the tuple have a name? + */ +isl_bool isl_space_has_tuple_name(__isl_keep isl_space *space, + enum isl_dim_type type) +{ + isl_id *id; + + if (!space_can_have_id(space, type)) + return isl_bool_error; + id = space->tuple_id[type - isl_dim_in]; + return id && id->name; +} + +__isl_keep const char *isl_space_get_tuple_name(__isl_keep isl_space *dim, + enum isl_dim_type type) +{ + isl_id *id; + if (!dim) + return NULL; + if (type != isl_dim_in && type != isl_dim_out) + return NULL; + id = dim->tuple_id[type - isl_dim_in]; + return id ? id->name : NULL; +} + +__isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned pos, + const char *s) +{ + isl_id *id; + + if (!dim) + return NULL; + if (!s) + return isl_space_reset_dim_id(dim, type, pos); + if (!name_ok(dim->ctx, s)) + goto error; + id = isl_id_alloc(dim->ctx, s, NULL); + return isl_space_set_dim_id(dim, type, pos, id); +error: + isl_space_free(dim); + return NULL; +} + +/* Does the given dimension have a name? + */ +isl_bool isl_space_has_dim_name(__isl_keep isl_space *space, + enum isl_dim_type type, unsigned pos) +{ + isl_id *id; + + if (!space) + return isl_bool_error; + id = get_id(space, type, pos); + return id && id->name; +} + +__isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *dim, + enum isl_dim_type type, unsigned pos) +{ + isl_id *id = get_id(dim, type, pos); + return id ? id->name : NULL; +} + +int isl_space_find_dim_by_id(__isl_keep isl_space *dim, enum isl_dim_type type, + __isl_keep isl_id *id) +{ + int i; + int offset; + int n; + + if (!dim || !id) + return -1; + + offset = isl_space_offset(dim, type); + n = isl_space_dim(dim, type); + for (i = 0; i < n && offset + i < dim->n_id; ++i) + if (dim->ids[offset + i] == id) + return i; + + return -1; +} + +int isl_space_find_dim_by_name(__isl_keep isl_space *space, + enum isl_dim_type type, const char *name) +{ + int i; + int offset; + int n; + + if (!space || !name) + return -1; + + offset = isl_space_offset(space, type); + n = isl_space_dim(space, type); + for (i = 0; i < n && offset + i < space->n_id; ++i) { + isl_id *id = get_id(space, type, i); + if (id && id->name && !strcmp(id->name, name)) + return i; + } + + return -1; +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of "space". + */ +__isl_give isl_space *isl_space_reset_user(__isl_take isl_space *space) +{ + int i; + isl_ctx *ctx; + isl_id *id; + const char *name; + + if (!space) + return NULL; + + ctx = isl_space_get_ctx(space); + + for (i = 0; i < space->nparam && i < space->n_id; ++i) { + if (!isl_id_get_user(space->ids[i])) + continue; + space = isl_space_cow(space); + if (!space) + return NULL; + name = isl_id_get_name(space->ids[i]); + id = isl_id_alloc(ctx, name, NULL); + isl_id_free(space->ids[i]); + space->ids[i] = id; + if (!id) + return isl_space_free(space); + } + + for (i = 0; i < 2; ++i) { + if (!space->tuple_id[i]) + continue; + if (!isl_id_get_user(space->tuple_id[i])) + continue; + space = isl_space_cow(space); + if (!space) + return NULL; + name = isl_id_get_name(space->tuple_id[i]); + id = isl_id_alloc(ctx, name, NULL); + isl_id_free(space->tuple_id[i]); + space->tuple_id[i] = id; + if (!id) + return isl_space_free(space); + } + + for (i = 0; i < 2; ++i) { + if (!space->nested[i]) + continue; + space = isl_space_cow(space); + if (!space) + return NULL; + space->nested[i] = isl_space_reset_user(space->nested[i]); + if (!space->nested[i]) + return isl_space_free(space); + } + + return space; +} + +static __isl_keep isl_id *tuple_id(__isl_keep isl_space *dim, + enum isl_dim_type type) +{ + if (!dim) + return NULL; + if (type == isl_dim_in) + return dim->tuple_id[0]; + if (type == isl_dim_out) + return dim->tuple_id[1]; + return NULL; +} + +static __isl_keep isl_space *nested(__isl_keep isl_space *dim, + enum isl_dim_type type) +{ + if (!dim) + return NULL; + if (type == isl_dim_in) + return dim->nested[0]; + if (type == isl_dim_out) + return dim->nested[1]; + return NULL; +} + +/* Are the two spaces the same, apart from positions and names of parameters? + */ +isl_bool isl_space_has_equal_tuples(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + if (!space1 || !space2) + return isl_bool_error; + if (space1 == space2) + return isl_bool_true; + return isl_space_tuple_is_equal(space1, isl_dim_in, + space2, isl_dim_in) && + isl_space_tuple_is_equal(space1, isl_dim_out, + space2, isl_dim_out); +} + +/* Check if the tuple of type "type1" of "space1" is the same as + * the tuple of type "type2" of "space2". + * + * That is, check if the tuples have the same identifier, the same dimension + * and the same internal structure. + * The identifiers of the dimensions inside the tuples do not affect the result. + * + * Note that this function only checks the tuples themselves. + * If nested tuples are involved, then we need to be careful not + * to have result affected by possibly differing parameters + * in those nested tuples. + */ +isl_bool isl_space_tuple_is_equal(__isl_keep isl_space *space1, + enum isl_dim_type type1, __isl_keep isl_space *space2, + enum isl_dim_type type2) +{ + isl_id *id1, *id2; + isl_space *nested1, *nested2; + + if (!space1 || !space2) + return isl_bool_error; + + if (space1 == space2 && type1 == type2) + return isl_bool_true; + + if (n(space1, type1) != n(space2, type2)) + return isl_bool_false; + id1 = tuple_id(space1, type1); + id2 = tuple_id(space2, type2); + if (!id1 ^ !id2) + return isl_bool_false; + if (id1 && id1 != id2) + return isl_bool_false; + nested1 = nested(space1, type1); + nested2 = nested(space2, type2); + if (!nested1 ^ !nested2) + return isl_bool_false; + if (nested1 && !isl_space_has_equal_tuples(nested1, nested2)) + return isl_bool_false; + return isl_bool_true; +} + +/* This is the old, undocumented, name for isl_space_tuple_is_equal. + * It will be removed at some point. + */ +int isl_space_tuple_match(__isl_keep isl_space *space1, enum isl_dim_type type1, + __isl_keep isl_space *space2, enum isl_dim_type type2) +{ + return isl_space_tuple_is_equal(space1, type1, space2, type2); +} + +static isl_bool match(__isl_keep isl_space *space1, enum isl_dim_type type1, + __isl_keep isl_space *space2, enum isl_dim_type type2) +{ + int i; + + if (space1 == space2 && type1 == type2) + return isl_bool_true; + + if (!isl_space_tuple_is_equal(space1, type1, space2, type2)) + return isl_bool_false; + + if (!space1->ids && !space2->ids) + return isl_bool_true; + + for (i = 0; i < n(space1, type1); ++i) { + if (get_id(space1, type1, i) != get_id(space2, type2, i)) + return isl_bool_false; + } + return isl_bool_true; +} + +/* Do "space1" and "space2" have the same parameters? + */ +isl_bool isl_space_has_equal_params(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + if (!space1 || !space2) + return isl_bool_error; + + return match(space1, isl_dim_param, space2, isl_dim_param); +} + +/* Do "space1" and "space2" have the same identifiers for all + * the tuple variables? + */ +isl_bool isl_space_has_equal_ids(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + isl_bool equal; + + if (!space1 || !space2) + return isl_bool_error; + + equal = match(space1, isl_dim_in, space2, isl_dim_in); + if (equal < 0 || !equal) + return equal; + return match(space1, isl_dim_out, space2, isl_dim_out); +} + +isl_bool isl_space_match(__isl_keep isl_space *space1, enum isl_dim_type type1, + __isl_keep isl_space *space2, enum isl_dim_type type2) +{ + if (!space1 || !space2) + return isl_bool_error; + + return match(space1, type1, space2, type2); +} + +static void get_ids(__isl_keep isl_space *dim, enum isl_dim_type type, + unsigned first, unsigned n, __isl_keep isl_id **ids) +{ + int i; + + for (i = 0; i < n ; ++i) + ids[i] = get_id(dim, type, first + i); +} + +static __isl_give isl_space *space_extend(__isl_take isl_space *space, + unsigned nparam, unsigned n_in, unsigned n_out) +{ + isl_id **ids = NULL; + + if (!space) + return NULL; + if (space->nparam == nparam && + space->n_in == n_in && space->n_out == n_out) + return space; + + isl_assert(space->ctx, space->nparam <= nparam, goto error); + isl_assert(space->ctx, space->n_in <= n_in, goto error); + isl_assert(space->ctx, space->n_out <= n_out, goto error); + + space = isl_space_cow(space); + if (!space) + goto error; + + if (space->ids) { + unsigned n; + n = nparam + n_in + n_out; + if (n < nparam || n < n_in || n < n_out) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "overflow in total number of dimensions", + goto error); + ids = isl_calloc_array(space->ctx, isl_id *, n); + if (!ids) + goto error; + get_ids(space, isl_dim_param, 0, space->nparam, ids); + get_ids(space, isl_dim_in, 0, space->n_in, ids + nparam); + get_ids(space, isl_dim_out, 0, space->n_out, + ids + nparam + n_in); + free(space->ids); + space->ids = ids; + space->n_id = nparam + n_in + n_out; + } + space->nparam = nparam; + space->n_in = n_in; + space->n_out = n_out; + + return space; +error: + free(ids); + isl_space_free(space); + return NULL; +} + +__isl_give isl_space *isl_space_extend(__isl_take isl_space *space, + unsigned nparam, unsigned n_in, unsigned n_out) +{ + return space_extend(space, nparam, n_in, n_out); +} + +__isl_give isl_space *isl_space_add_dims(__isl_take isl_space *space, + enum isl_dim_type type, unsigned n) +{ + space = isl_space_reset(space, type); + if (!space) + return NULL; + switch (type) { + case isl_dim_param: + space = space_extend(space, + space->nparam + n, space->n_in, space->n_out); + if (space && space->nested[0] && + !(space->nested[0] = isl_space_add_dims(space->nested[0], + isl_dim_param, n))) + goto error; + if (space && space->nested[1] && + !(space->nested[1] = isl_space_add_dims(space->nested[1], + isl_dim_param, n))) + goto error; + return space; + case isl_dim_in: + return space_extend(space, + space->nparam, space->n_in + n, space->n_out); + case isl_dim_out: + return space_extend(space, + space->nparam, space->n_in, space->n_out + n); + default: + isl_die(space->ctx, isl_error_invalid, + "cannot add dimensions of specified type", goto error); + } +error: + isl_space_free(space); + return NULL; +} + +static int valid_dim_type(enum isl_dim_type type) +{ + switch (type) { + case isl_dim_param: + case isl_dim_in: + case isl_dim_out: + return 1; + default: + return 0; + } +} + +/* Insert "n" dimensions of type "type" at position "pos". + * If we are inserting parameters, then they are also inserted in + * any nested spaces. + */ +__isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned pos, unsigned n) +{ + isl_id **ids = NULL; + + if (!dim) + return NULL; + if (n == 0) + return isl_space_reset(dim, type); + + if (!valid_dim_type(type)) + isl_die(dim->ctx, isl_error_invalid, + "cannot insert dimensions of specified type", + goto error); + + isl_assert(dim->ctx, pos <= isl_space_dim(dim, type), goto error); + + dim = isl_space_cow(dim); + if (!dim) + return NULL; + + if (dim->ids) { + enum isl_dim_type t, o = isl_dim_param; + int off; + int s[3]; + ids = isl_calloc_array(dim->ctx, isl_id *, + dim->nparam + dim->n_in + dim->n_out + n); + if (!ids) + goto error; + off = 0; + s[isl_dim_param - o] = dim->nparam; + s[isl_dim_in - o] = dim->n_in; + s[isl_dim_out - o] = dim->n_out; + for (t = isl_dim_param; t <= isl_dim_out; ++t) { + if (t != type) { + get_ids(dim, t, 0, s[t - o], ids + off); + off += s[t - o]; + } else { + get_ids(dim, t, 0, pos, ids + off); + off += pos + n; + get_ids(dim, t, pos, s[t - o] - pos, ids + off); + off += s[t - o] - pos; + } + } + free(dim->ids); + dim->ids = ids; + dim->n_id = dim->nparam + dim->n_in + dim->n_out + n; + } + switch (type) { + case isl_dim_param: dim->nparam += n; break; + case isl_dim_in: dim->n_in += n; break; + case isl_dim_out: dim->n_out += n; break; + default: ; + } + dim = isl_space_reset(dim, type); + + if (type == isl_dim_param) { + if (dim && dim->nested[0] && + !(dim->nested[0] = isl_space_insert_dims(dim->nested[0], + isl_dim_param, pos, n))) + goto error; + if (dim && dim->nested[1] && + !(dim->nested[1] = isl_space_insert_dims(dim->nested[1], + isl_dim_param, pos, n))) + goto error; + } + + return dim; +error: + isl_space_free(dim); + return NULL; +} + +__isl_give isl_space *isl_space_move_dims(__isl_take isl_space *space, + enum isl_dim_type dst_type, unsigned dst_pos, + enum isl_dim_type src_type, unsigned src_pos, unsigned n) +{ + int i; + + space = isl_space_reset(space, src_type); + space = isl_space_reset(space, dst_type); + if (!space) + return NULL; + if (n == 0) + return space; + + isl_assert(space->ctx, src_pos + n <= isl_space_dim(space, src_type), + goto error); + + if (dst_type == src_type && dst_pos == src_pos) + return space; + + isl_assert(space->ctx, dst_type != src_type, goto error); + + space = isl_space_cow(space); + if (!space) + return NULL; + + if (space->ids) { + isl_id **ids; + enum isl_dim_type t, o = isl_dim_param; + int off; + int s[3]; + ids = isl_calloc_array(space->ctx, isl_id *, + space->nparam + space->n_in + space->n_out); + if (!ids) + goto error; + off = 0; + s[isl_dim_param - o] = space->nparam; + s[isl_dim_in - o] = space->n_in; + s[isl_dim_out - o] = space->n_out; + for (t = isl_dim_param; t <= isl_dim_out; ++t) { + if (t == dst_type) { + get_ids(space, t, 0, dst_pos, ids + off); + off += dst_pos; + get_ids(space, src_type, src_pos, n, ids + off); + off += n; + get_ids(space, t, dst_pos, s[t - o] - dst_pos, + ids + off); + off += s[t - o] - dst_pos; + } else if (t == src_type) { + get_ids(space, t, 0, src_pos, ids + off); + off += src_pos; + get_ids(space, t, src_pos + n, + s[t - o] - src_pos - n, ids + off); + off += s[t - o] - src_pos - n; + } else { + get_ids(space, t, 0, s[t - o], ids + off); + off += s[t - o]; + } + } + free(space->ids); + space->ids = ids; + space->n_id = space->nparam + space->n_in + space->n_out; + } + + switch (dst_type) { + case isl_dim_param: space->nparam += n; break; + case isl_dim_in: space->n_in += n; break; + case isl_dim_out: space->n_out += n; break; + default: ; + } + + switch (src_type) { + case isl_dim_param: space->nparam -= n; break; + case isl_dim_in: space->n_in -= n; break; + case isl_dim_out: space->n_out -= n; break; + default: ; + } + + if (dst_type != isl_dim_param && src_type != isl_dim_param) + return space; + + for (i = 0; i < 2; ++i) { + if (!space->nested[i]) + continue; + space->nested[i] = isl_space_replace(space->nested[i], + isl_dim_param, space); + if (!space->nested[i]) + goto error; + } + + return space; +error: + isl_space_free(space); + return NULL; +} + +/* Check that "space1" and "space2" have the same parameters, + * reporting an error if they do not. + */ +isl_stat isl_space_check_equal_params(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + isl_bool equal; + + equal = isl_space_has_equal_params(space1, space2); + if (equal < 0) + return isl_stat_error; + if (!equal) + isl_die(isl_space_get_ctx(space1), isl_error_invalid, + "parameters need to match", return isl_stat_error); + return isl_stat_ok; +} + +__isl_give isl_space *isl_space_join(__isl_take isl_space *left, + __isl_take isl_space *right) +{ + isl_space *dim; + + if (isl_space_check_equal_params(left, right) < 0) + goto error; + + isl_assert(left->ctx, + isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_in), + goto error); + + dim = isl_space_alloc(left->ctx, left->nparam, left->n_in, right->n_out); + if (!dim) + goto error; + + dim = copy_ids(dim, isl_dim_param, 0, left, isl_dim_param); + dim = copy_ids(dim, isl_dim_in, 0, left, isl_dim_in); + dim = copy_ids(dim, isl_dim_out, 0, right, isl_dim_out); + + if (dim && left->tuple_id[0] && + !(dim->tuple_id[0] = isl_id_copy(left->tuple_id[0]))) + goto error; + if (dim && right->tuple_id[1] && + !(dim->tuple_id[1] = isl_id_copy(right->tuple_id[1]))) + goto error; + if (dim && left->nested[0] && + !(dim->nested[0] = isl_space_copy(left->nested[0]))) + goto error; + if (dim && right->nested[1] && + !(dim->nested[1] = isl_space_copy(right->nested[1]))) + goto error; + + isl_space_free(left); + isl_space_free(right); + + return dim; +error: + isl_space_free(left); + isl_space_free(right); + return NULL; +} + +/* Given two map spaces { A -> C } and { B -> D }, construct the space + * { [A -> B] -> [C -> D] }. + * Given two set spaces { A } and { B }, construct the space { [A -> B] }. + */ +__isl_give isl_space *isl_space_product(__isl_take isl_space *left, + __isl_take isl_space *right) +{ + isl_space *dom1, *dom2, *nest1, *nest2; + int is_set; + + if (!left || !right) + goto error; + + is_set = isl_space_is_set(left); + if (is_set != isl_space_is_set(right)) + isl_die(isl_space_get_ctx(left), isl_error_invalid, + "expecting either two set spaces or two map spaces", + goto error); + if (is_set) + return isl_space_range_product(left, right); + + if (isl_space_check_equal_params(left, right) < 0) + goto error; + + dom1 = isl_space_domain(isl_space_copy(left)); + dom2 = isl_space_domain(isl_space_copy(right)); + nest1 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2)); + + dom1 = isl_space_range(left); + dom2 = isl_space_range(right); + nest2 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2)); + + return isl_space_join(isl_space_reverse(nest1), nest2); +error: + isl_space_free(left); + isl_space_free(right); + return NULL; +} + +/* Given two spaces { A -> C } and { B -> C }, construct the space + * { [A -> B] -> C } + */ +__isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left, + __isl_take isl_space *right) +{ + isl_space *ran, *dom1, *dom2, *nest; + + if (isl_space_check_equal_params(left, right) < 0) + goto error; + + if (!isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_out)) + isl_die(left->ctx, isl_error_invalid, + "ranges need to match", goto error); + + ran = isl_space_range(isl_space_copy(left)); + + dom1 = isl_space_domain(left); + dom2 = isl_space_domain(right); + nest = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2)); + + return isl_space_join(isl_space_reverse(nest), ran); +error: + isl_space_free(left); + isl_space_free(right); + return NULL; +} + +__isl_give isl_space *isl_space_range_product(__isl_take isl_space *left, + __isl_take isl_space *right) +{ + isl_space *dom, *ran1, *ran2, *nest; + + if (isl_space_check_equal_params(left, right) < 0) + goto error; + + if (!isl_space_tuple_is_equal(left, isl_dim_in, right, isl_dim_in)) + isl_die(left->ctx, isl_error_invalid, + "domains need to match", goto error); + + dom = isl_space_domain(isl_space_copy(left)); + + ran1 = isl_space_range(left); + ran2 = isl_space_range(right); + nest = isl_space_wrap(isl_space_join(isl_space_reverse(ran1), ran2)); + + return isl_space_join(isl_space_reverse(dom), nest); +error: + isl_space_free(left); + isl_space_free(right); + return NULL; +} + +/* Given a space of the form [A -> B] -> C, return the space A -> C. + */ +__isl_give isl_space *isl_space_domain_factor_domain( + __isl_take isl_space *space) +{ + isl_space *nested; + isl_space *domain; + + if (!space) + return NULL; + if (!isl_space_domain_is_wrapping(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "domain not a product", return isl_space_free(space)); + + nested = space->nested[0]; + domain = isl_space_copy(space); + domain = isl_space_drop_dims(domain, isl_dim_in, + nested->n_in, nested->n_out); + if (!domain) + return isl_space_free(space); + if (nested->tuple_id[0]) { + domain->tuple_id[0] = isl_id_copy(nested->tuple_id[0]); + if (!domain->tuple_id[0]) + goto error; + } + if (nested->nested[0]) { + domain->nested[0] = isl_space_copy(nested->nested[0]); + if (!domain->nested[0]) + goto error; + } + + isl_space_free(space); + return domain; +error: + isl_space_free(space); + isl_space_free(domain); + return NULL; +} + +/* Given a space of the form [A -> B] -> C, return the space B -> C. + */ +__isl_give isl_space *isl_space_domain_factor_range( + __isl_take isl_space *space) +{ + isl_space *nested; + isl_space *range; + + if (!space) + return NULL; + if (!isl_space_domain_is_wrapping(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "domain not a product", return isl_space_free(space)); + + nested = space->nested[0]; + range = isl_space_copy(space); + range = isl_space_drop_dims(range, isl_dim_in, 0, nested->n_in); + if (!range) + return isl_space_free(space); + if (nested->tuple_id[1]) { + range->tuple_id[0] = isl_id_copy(nested->tuple_id[1]); + if (!range->tuple_id[0]) + goto error; + } + if (nested->nested[1]) { + range->nested[0] = isl_space_copy(nested->nested[1]); + if (!range->nested[0]) + goto error; + } + + isl_space_free(space); + return range; +error: + isl_space_free(space); + isl_space_free(range); + return NULL; +} + +/* Internal function that selects the domain of the map that is + * embedded in either a set space or the range of a map space. + * In particular, given a space of the form [A -> B], return the space A. + * Given a space of the form A -> [B -> C], return the space A -> B. + */ +static __isl_give isl_space *range_factor_domain(__isl_take isl_space *space) +{ + isl_space *nested; + isl_space *domain; + + if (!space) + return NULL; + + nested = space->nested[1]; + domain = isl_space_copy(space); + domain = isl_space_drop_dims(domain, isl_dim_out, + nested->n_in, nested->n_out); + if (!domain) + return isl_space_free(space); + if (nested->tuple_id[0]) { + domain->tuple_id[1] = isl_id_copy(nested->tuple_id[0]); + if (!domain->tuple_id[1]) + goto error; + } + if (nested->nested[0]) { + domain->nested[1] = isl_space_copy(nested->nested[0]); + if (!domain->nested[1]) + goto error; + } + + isl_space_free(space); + return domain; +error: + isl_space_free(space); + isl_space_free(domain); + return NULL; +} + +/* Given a space of the form A -> [B -> C], return the space A -> B. + */ +__isl_give isl_space *isl_space_range_factor_domain( + __isl_take isl_space *space) +{ + if (!space) + return NULL; + if (!isl_space_range_is_wrapping(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "range not a product", return isl_space_free(space)); + + return range_factor_domain(space); +} + +/* Given a space of the form [A -> B], return the space A. + */ +static __isl_give isl_space *set_factor_domain(__isl_take isl_space *space) +{ + if (!space) + return NULL; + if (!isl_space_is_wrapping(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "not a product", return isl_space_free(space)); + + return range_factor_domain(space); +} + +/* Given a space of the form [A -> B] -> [C -> D], return the space A -> C. + * Given a space of the form [A -> B], return the space A. + */ +__isl_give isl_space *isl_space_factor_domain(__isl_take isl_space *space) +{ + if (!space) + return NULL; + if (isl_space_is_set(space)) + return set_factor_domain(space); + space = isl_space_domain_factor_domain(space); + space = isl_space_range_factor_domain(space); + return space; +} + +/* Internal function that selects the range of the map that is + * embedded in either a set space or the range of a map space. + * In particular, given a space of the form [A -> B], return the space B. + * Given a space of the form A -> [B -> C], return the space A -> C. + */ +static __isl_give isl_space *range_factor_range(__isl_take isl_space *space) +{ + isl_space *nested; + isl_space *range; + + if (!space) + return NULL; + + nested = space->nested[1]; + range = isl_space_copy(space); + range = isl_space_drop_dims(range, isl_dim_out, 0, nested->n_in); + if (!range) + return isl_space_free(space); + if (nested->tuple_id[1]) { + range->tuple_id[1] = isl_id_copy(nested->tuple_id[1]); + if (!range->tuple_id[1]) + goto error; + } + if (nested->nested[1]) { + range->nested[1] = isl_space_copy(nested->nested[1]); + if (!range->nested[1]) + goto error; + } + + isl_space_free(space); + return range; +error: + isl_space_free(space); + isl_space_free(range); + return NULL; +} + +/* Given a space of the form A -> [B -> C], return the space A -> C. + */ +__isl_give isl_space *isl_space_range_factor_range( + __isl_take isl_space *space) +{ + if (!space) + return NULL; + if (!isl_space_range_is_wrapping(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "range not a product", return isl_space_free(space)); + + return range_factor_range(space); +} + +/* Given a space of the form [A -> B], return the space B. + */ +static __isl_give isl_space *set_factor_range(__isl_take isl_space *space) +{ + if (!space) + return NULL; + if (!isl_space_is_wrapping(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "not a product", return isl_space_free(space)); + + return range_factor_range(space); +} + +/* Given a space of the form [A -> B] -> [C -> D], return the space B -> D. + * Given a space of the form [A -> B], return the space B. + */ +__isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space) +{ + if (!space) + return NULL; + if (isl_space_is_set(space)) + return set_factor_range(space); + space = isl_space_domain_factor_range(space); + space = isl_space_range_factor_range(space); + return space; +} + +__isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space) +{ + isl_ctx *ctx; + isl_id **ids = NULL; + int n_id; + + if (!space) + return NULL; + ctx = isl_space_get_ctx(space); + if (!isl_space_is_set(space)) + isl_die(ctx, isl_error_invalid, "not a set space", goto error); + space = isl_space_cow(space); + if (!space) + return NULL; + n_id = space->nparam + space->n_out + space->n_out; + if (n_id > 0 && space->ids) { + ids = isl_calloc_array(space->ctx, isl_id *, n_id); + if (!ids) + goto error; + get_ids(space, isl_dim_param, 0, space->nparam, ids); + get_ids(space, isl_dim_out, 0, space->n_out, + ids + space->nparam); + } + space->n_in = space->n_out; + if (ids) { + free(space->ids); + space->ids = ids; + space->n_id = n_id; + space = copy_ids(space, isl_dim_out, 0, space, isl_dim_in); + } + isl_id_free(space->tuple_id[0]); + space->tuple_id[0] = isl_id_copy(space->tuple_id[1]); + isl_space_free(space->nested[0]); + space->nested[0] = isl_space_copy(space->nested[1]); + return space; +error: + isl_space_free(space); + return NULL; +} + +__isl_give isl_space *isl_space_map_from_domain_and_range( + __isl_take isl_space *domain, __isl_take isl_space *range) +{ + if (!domain || !range) + goto error; + if (!isl_space_is_set(domain)) + isl_die(isl_space_get_ctx(domain), isl_error_invalid, + "domain is not a set space", goto error); + if (!isl_space_is_set(range)) + isl_die(isl_space_get_ctx(range), isl_error_invalid, + "range is not a set space", goto error); + return isl_space_join(isl_space_reverse(domain), range); +error: + isl_space_free(domain); + isl_space_free(range); + return NULL; +} + +static __isl_give isl_space *set_ids(__isl_take isl_space *dim, + enum isl_dim_type type, + unsigned first, unsigned n, __isl_take isl_id **ids) +{ + int i; + + for (i = 0; i < n ; ++i) + dim = set_id(dim, type, first + i, ids[i]); + + return dim; +} + +__isl_give isl_space *isl_space_reverse(__isl_take isl_space *dim) +{ + unsigned t; + isl_space *nested; + isl_id **ids = NULL; + isl_id *id; + + if (!dim) + return NULL; + if (match(dim, isl_dim_in, dim, isl_dim_out)) + return dim; + + dim = isl_space_cow(dim); + if (!dim) + return NULL; + + id = dim->tuple_id[0]; + dim->tuple_id[0] = dim->tuple_id[1]; + dim->tuple_id[1] = id; + + nested = dim->nested[0]; + dim->nested[0] = dim->nested[1]; + dim->nested[1] = nested; + + if (dim->ids) { + int n_id = dim->n_in + dim->n_out; + ids = isl_alloc_array(dim->ctx, isl_id *, n_id); + if (n_id && !ids) + goto error; + get_ids(dim, isl_dim_in, 0, dim->n_in, ids); + get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->n_in); + } + + t = dim->n_in; + dim->n_in = dim->n_out; + dim->n_out = t; + + if (dim->ids) { + dim = set_ids(dim, isl_dim_out, 0, dim->n_out, ids); + dim = set_ids(dim, isl_dim_in, 0, dim->n_in, ids + dim->n_out); + free(ids); + } + + return dim; +error: + free(ids); + isl_space_free(dim); + return NULL; +} + +__isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *dim, + enum isl_dim_type type, unsigned first, unsigned num) +{ + int i; + + if (!dim) + return NULL; + + if (num == 0) + return isl_space_reset(dim, type); + + if (!valid_dim_type(type)) + isl_die(dim->ctx, isl_error_invalid, + "cannot drop dimensions of specified type", goto error); + + if (first + num > n(dim, type) || first + num < first) + isl_die(isl_space_get_ctx(dim), isl_error_invalid, + "index out of bounds", return isl_space_free(dim)); + dim = isl_space_cow(dim); + if (!dim) + goto error; + if (dim->ids) { + dim = extend_ids(dim); + if (!dim) + goto error; + for (i = 0; i < num; ++i) + isl_id_free(get_id(dim, type, first + i)); + for (i = first+num; i < n(dim, type); ++i) + set_id(dim, type, i - num, get_id(dim, type, i)); + switch (type) { + case isl_dim_param: + get_ids(dim, isl_dim_in, 0, dim->n_in, + dim->ids + offset(dim, isl_dim_in) - num); + case isl_dim_in: + get_ids(dim, isl_dim_out, 0, dim->n_out, + dim->ids + offset(dim, isl_dim_out) - num); + default: + ; + } + dim->n_id -= num; + } + switch (type) { + case isl_dim_param: dim->nparam -= num; break; + case isl_dim_in: dim->n_in -= num; break; + case isl_dim_out: dim->n_out -= num; break; + default: ; + } + dim = isl_space_reset(dim, type); + if (type == isl_dim_param) { + if (dim && dim->nested[0] && + !(dim->nested[0] = isl_space_drop_dims(dim->nested[0], + isl_dim_param, first, num))) + goto error; + if (dim && dim->nested[1] && + !(dim->nested[1] = isl_space_drop_dims(dim->nested[1], + isl_dim_param, first, num))) + goto error; + } + return dim; +error: + isl_space_free(dim); + return NULL; +} + +__isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *dim, + unsigned first, unsigned n) +{ + if (!dim) + return NULL; + return isl_space_drop_dims(dim, isl_dim_in, first, n); +} + +__isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *dim, + unsigned first, unsigned n) +{ + if (!dim) + return NULL; + return isl_space_drop_dims(dim, isl_dim_out, first, n); +} + +__isl_give isl_space *isl_space_domain(__isl_take isl_space *space) +{ + if (!space) + return NULL; + space = isl_space_drop_dims(space, isl_dim_out, 0, space->n_out); + space = isl_space_reverse(space); + space = mark_as_set(space); + return space; +} + +__isl_give isl_space *isl_space_from_domain(__isl_take isl_space *dim) +{ + if (!dim) + return NULL; + if (!isl_space_is_set(dim)) + isl_die(isl_space_get_ctx(dim), isl_error_invalid, + "not a set space", goto error); + dim = isl_space_reverse(dim); + dim = isl_space_reset(dim, isl_dim_out); + return dim; +error: + isl_space_free(dim); + return NULL; +} + +__isl_give isl_space *isl_space_range(__isl_take isl_space *space) +{ + if (!space) + return NULL; + space = isl_space_drop_dims(space, isl_dim_in, 0, space->n_in); + space = mark_as_set(space); + return space; +} + +__isl_give isl_space *isl_space_from_range(__isl_take isl_space *dim) +{ + if (!dim) + return NULL; + if (!isl_space_is_set(dim)) + isl_die(isl_space_get_ctx(dim), isl_error_invalid, + "not a set space", goto error); + return isl_space_reset(dim, isl_dim_in); +error: + isl_space_free(dim); + return NULL; +} + +/* Given a map space A -> B, return the map space [A -> B] -> A. + */ +__isl_give isl_space *isl_space_domain_map(__isl_take isl_space *space) +{ + isl_space *domain; + + domain = isl_space_from_range(isl_space_domain(isl_space_copy(space))); + space = isl_space_from_domain(isl_space_wrap(space)); + space = isl_space_join(space, domain); + + return space; +} + +/* Given a map space A -> B, return the map space [A -> B] -> B. + */ +__isl_give isl_space *isl_space_range_map(__isl_take isl_space *space) +{ + isl_space *range; + + range = isl_space_from_range(isl_space_range(isl_space_copy(space))); + space = isl_space_from_domain(isl_space_wrap(space)); + space = isl_space_join(space, range); + + return space; +} + +__isl_give isl_space *isl_space_params(__isl_take isl_space *space) +{ + if (isl_space_is_params(space)) + return space; + space = isl_space_drop_dims(space, + isl_dim_in, 0, isl_space_dim(space, isl_dim_in)); + space = isl_space_drop_dims(space, + isl_dim_out, 0, isl_space_dim(space, isl_dim_out)); + space = mark_as_params(space); + return space; +} + +__isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space) +{ + if (!space) + return NULL; + if (!isl_space_is_params(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "not a parameter space", goto error); + return isl_space_reset(space, isl_dim_set); +error: + isl_space_free(space); + return NULL; +} + +__isl_give isl_space *isl_space_underlying(__isl_take isl_space *dim, + unsigned n_div) +{ + int i; + + if (!dim) + return NULL; + if (n_div == 0 && + dim->nparam == 0 && dim->n_in == 0 && dim->n_id == 0) + return isl_space_reset(isl_space_reset(dim, isl_dim_in), isl_dim_out); + dim = isl_space_cow(dim); + if (!dim) + return NULL; + dim->n_out += dim->nparam + dim->n_in + n_div; + dim->nparam = 0; + dim->n_in = 0; + + for (i = 0; i < dim->n_id; ++i) + isl_id_free(get_id(dim, isl_dim_out, i)); + dim->n_id = 0; + dim = isl_space_reset(dim, isl_dim_in); + dim = isl_space_reset(dim, isl_dim_out); + + return dim; +} + +/* Are the two spaces the same, including positions and names of parameters? + */ +isl_bool isl_space_is_equal(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + isl_bool equal; + + if (!space1 || !space2) + return isl_bool_error; + if (space1 == space2) + return isl_bool_true; + equal = isl_space_has_equal_params(space1, space2); + if (equal < 0 || !equal) + return equal; + return isl_space_has_equal_tuples(space1, space2); +} + +/* Is space1 equal to the domain of space2? + * + * In the internal version we also allow space2 to be the space of a set, + * provided space1 is a parameter space. + */ +isl_bool isl_space_is_domain_internal(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + isl_bool equal_params; + + if (!space1 || !space2) + return isl_bool_error; + if (!isl_space_is_set(space1)) + return isl_bool_false; + equal_params = isl_space_has_equal_params(space1, space2); + if (equal_params < 0 || !equal_params) + return equal_params; + return isl_space_tuple_is_equal(space1, isl_dim_set, + space2, isl_dim_in); +} + +/* Is space1 equal to the domain of space2? + */ +isl_bool isl_space_is_domain(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + if (!space2) + return isl_bool_error; + if (!isl_space_is_map(space2)) + return isl_bool_false; + return isl_space_is_domain_internal(space1, space2); +} + +/* Is space1 equal to the range of space2? + * + * In the internal version, space2 is allowed to be the space of a set, + * in which case it should be equal to space1. + */ +isl_bool isl_space_is_range_internal(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + isl_bool equal_params; + + if (!space1 || !space2) + return isl_bool_error; + if (!isl_space_is_set(space1)) + return isl_bool_false; + equal_params = isl_space_has_equal_params(space1, space2); + if (equal_params < 0 || !equal_params) + return equal_params; + return isl_space_tuple_is_equal(space1, isl_dim_set, + space2, isl_dim_out); +} + +/* Is space1 equal to the range of space2? + */ +isl_bool isl_space_is_range(__isl_keep isl_space *space1, + __isl_keep isl_space *space2) +{ + if (!space2) + return isl_bool_error; + if (!isl_space_is_map(space2)) + return isl_bool_false; + return isl_space_is_range_internal(space1, space2); +} + +/* Update "hash" by hashing in the parameters of "space". + */ +static uint32_t isl_hash_params(uint32_t hash, __isl_keep isl_space *space) +{ + int i; + isl_id *id; + + if (!space) + return hash; + + isl_hash_byte(hash, space->nparam % 256); + + for (i = 0; i < space->nparam; ++i) { + id = get_id(space, isl_dim_param, i); + hash = isl_hash_id(hash, id); + } + + return hash; +} + +/* Update "hash" by hashing in the tuples of "space". + * Changes in this function should be reflected in isl_hash_tuples_domain. + */ +static uint32_t isl_hash_tuples(uint32_t hash, __isl_keep isl_space *space) +{ + isl_id *id; + + if (!space) + return hash; + + isl_hash_byte(hash, space->n_in % 256); + isl_hash_byte(hash, space->n_out % 256); + + id = tuple_id(space, isl_dim_in); + hash = isl_hash_id(hash, id); + id = tuple_id(space, isl_dim_out); + hash = isl_hash_id(hash, id); + + hash = isl_hash_tuples(hash, space->nested[0]); + hash = isl_hash_tuples(hash, space->nested[1]); + + return hash; +} + +/* Update "hash" by hashing in the domain tuple of "space". + * The result of this function is equal to the result of applying + * isl_hash_tuples to the domain of "space". + */ +static uint32_t isl_hash_tuples_domain(uint32_t hash, + __isl_keep isl_space *space) +{ + isl_id *id; + + if (!space) + return hash; + + isl_hash_byte(hash, 0); + isl_hash_byte(hash, space->n_in % 256); + + hash = isl_hash_id(hash, &isl_id_none); + id = tuple_id(space, isl_dim_in); + hash = isl_hash_id(hash, id); + + hash = isl_hash_tuples(hash, space->nested[0]); + + return hash; +} + +/* Return a hash value that digests the tuples of "space", + * i.e., that ignores the parameters. + */ +uint32_t isl_space_get_tuple_hash(__isl_keep isl_space *space) +{ + uint32_t hash; + + if (!space) + return 0; + + hash = isl_hash_init(); + hash = isl_hash_tuples(hash, space); + + return hash; +} + +uint32_t isl_space_get_hash(__isl_keep isl_space *space) +{ + uint32_t hash; + + if (!space) + return 0; + + hash = isl_hash_init(); + hash = isl_hash_params(hash, space); + hash = isl_hash_tuples(hash, space); + + return hash; +} + +/* Return the hash value of the domain of "space". + * That is, isl_space_get_domain_hash(space) is equal to + * isl_space_get_hash(isl_space_domain(space)). + */ +uint32_t isl_space_get_domain_hash(__isl_keep isl_space *space) +{ + uint32_t hash; + + if (!space) + return 0; + + hash = isl_hash_init(); + hash = isl_hash_params(hash, space); + hash = isl_hash_tuples_domain(hash, space); + + return hash; +} + +isl_bool isl_space_is_wrapping(__isl_keep isl_space *dim) +{ + if (!dim) + return isl_bool_error; + + if (!isl_space_is_set(dim)) + return isl_bool_false; + + return dim->nested[1] != NULL; +} + +/* Is "space" the space of a map where the domain is a wrapped map space? + */ +isl_bool isl_space_domain_is_wrapping(__isl_keep isl_space *space) +{ + if (!space) + return isl_bool_error; + + if (isl_space_is_set(space)) + return isl_bool_false; + + return space->nested[0] != NULL; +} + +/* Is "space" the space of a map where the range is a wrapped map space? + */ +isl_bool isl_space_range_is_wrapping(__isl_keep isl_space *space) +{ + if (!space) + return isl_bool_error; + + if (isl_space_is_set(space)) + return isl_bool_false; + + return space->nested[1] != NULL; +} + +/* Is "space" a product of two spaces? + * That is, is it a wrapping set space or a map space + * with wrapping domain and range? + */ +isl_bool isl_space_is_product(__isl_keep isl_space *space) +{ + isl_bool is_set; + isl_bool is_product; + + is_set = isl_space_is_set(space); + if (is_set < 0) + return isl_bool_error; + if (is_set) + return isl_space_is_wrapping(space); + is_product = isl_space_domain_is_wrapping(space); + if (is_product < 0 || !is_product) + return is_product; + return isl_space_range_is_wrapping(space); +} + +__isl_give isl_space *isl_space_wrap(__isl_take isl_space *dim) +{ + isl_space *wrap; + + if (!dim) + return NULL; + + wrap = isl_space_set_alloc(dim->ctx, + dim->nparam, dim->n_in + dim->n_out); + + wrap = copy_ids(wrap, isl_dim_param, 0, dim, isl_dim_param); + wrap = copy_ids(wrap, isl_dim_set, 0, dim, isl_dim_in); + wrap = copy_ids(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out); + + if (!wrap) + goto error; + + wrap->nested[1] = dim; + + return wrap; +error: + isl_space_free(dim); + return NULL; +} + +__isl_give isl_space *isl_space_unwrap(__isl_take isl_space *dim) +{ + isl_space *unwrap; + + if (!dim) + return NULL; + + if (!isl_space_is_wrapping(dim)) + isl_die(dim->ctx, isl_error_invalid, "not a wrapping space", + goto error); + + unwrap = isl_space_copy(dim->nested[1]); + isl_space_free(dim); + + return unwrap; +error: + isl_space_free(dim); + return NULL; +} + +isl_bool isl_space_is_named_or_nested(__isl_keep isl_space *space, + enum isl_dim_type type) +{ + if (type != isl_dim_in && type != isl_dim_out) + return isl_bool_false; + if (!space) + return isl_bool_error; + if (space->tuple_id[type - isl_dim_in]) + return isl_bool_true; + if (space->nested[type - isl_dim_in]) + return isl_bool_true; + return isl_bool_false; +} + +isl_bool isl_space_may_be_set(__isl_keep isl_space *space) +{ + isl_bool nested; + + if (!space) + return isl_bool_error; + if (isl_space_is_set(space)) + return isl_bool_true; + if (isl_space_dim(space, isl_dim_in) != 0) + return isl_bool_false; + nested = isl_space_is_named_or_nested(space, isl_dim_in); + if (nested < 0 || nested) + return isl_bool_not(nested); + return isl_bool_true; +} + +__isl_give isl_space *isl_space_reset(__isl_take isl_space *dim, + enum isl_dim_type type) +{ + if (!isl_space_is_named_or_nested(dim, type)) + return dim; + + dim = isl_space_cow(dim); + if (!dim) + return NULL; + + isl_id_free(dim->tuple_id[type - isl_dim_in]); + dim->tuple_id[type - isl_dim_in] = NULL; + isl_space_free(dim->nested[type - isl_dim_in]); + dim->nested[type - isl_dim_in] = NULL; + + return dim; +} + +__isl_give isl_space *isl_space_flatten(__isl_take isl_space *dim) +{ + if (!dim) + return NULL; + if (!dim->nested[0] && !dim->nested[1]) + return dim; + + if (dim->nested[0]) + dim = isl_space_reset(dim, isl_dim_in); + if (dim && dim->nested[1]) + dim = isl_space_reset(dim, isl_dim_out); + + return dim; +} + +__isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *space) +{ + if (!space) + return NULL; + if (!space->nested[0]) + return space; + + return isl_space_reset(space, isl_dim_in); +} + +__isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *space) +{ + if (!space) + return NULL; + if (!space->nested[1]) + return space; + + return isl_space_reset(space, isl_dim_out); +} + +/* Replace the dimensions of the given type of dst by those of src. + */ +__isl_give isl_space *isl_space_replace(__isl_take isl_space *dst, + enum isl_dim_type type, __isl_keep isl_space *src) +{ + dst = isl_space_cow(dst); + + if (!dst || !src) + goto error; + + dst = isl_space_drop_dims(dst, type, 0, isl_space_dim(dst, type)); + dst = isl_space_add_dims(dst, type, isl_space_dim(src, type)); + dst = copy_ids(dst, type, 0, src, type); + + if (dst && type == isl_dim_param) { + int i; + for (i = 0; i <= 1; ++i) { + if (!dst->nested[i]) + continue; + dst->nested[i] = isl_space_replace(dst->nested[i], + type, src); + if (!dst->nested[i]) + goto error; + } + } + + return dst; +error: + isl_space_free(dst); + return NULL; +} + +/* Given a dimension specification "dim" of a set, create a dimension + * specification for the lift of the set. In particular, the result + * is of the form [dim -> local[..]], with n_local variables in the + * range of the wrapped map. + */ +__isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local) +{ + isl_space *local_dim; + + if (!dim) + return NULL; + + local_dim = isl_space_dup(dim); + local_dim = isl_space_drop_dims(local_dim, isl_dim_set, 0, dim->n_out); + local_dim = isl_space_add_dims(local_dim, isl_dim_set, n_local); + local_dim = isl_space_set_tuple_name(local_dim, isl_dim_set, "local"); + dim = isl_space_join(isl_space_from_domain(dim), + isl_space_from_range(local_dim)); + dim = isl_space_wrap(dim); + dim = isl_space_set_tuple_name(dim, isl_dim_set, "lifted"); + + return dim; +} + +isl_bool isl_space_can_zip(__isl_keep isl_space *space) +{ + isl_bool is_set; + + is_set = isl_space_is_set(space); + if (is_set < 0) + return isl_bool_error; + if (is_set) + return isl_bool_false; + return isl_space_is_product(space); +} + +__isl_give isl_space *isl_space_zip(__isl_take isl_space *dim) +{ + isl_space *dom, *ran; + isl_space *dom_dom, *dom_ran, *ran_dom, *ran_ran; + + if (!isl_space_can_zip(dim)) + isl_die(dim->ctx, isl_error_invalid, "dim cannot be zipped", + goto error); + + if (!dim) + return NULL; + dom = isl_space_unwrap(isl_space_domain(isl_space_copy(dim))); + ran = isl_space_unwrap(isl_space_range(dim)); + dom_dom = isl_space_domain(isl_space_copy(dom)); + dom_ran = isl_space_range(dom); + ran_dom = isl_space_domain(isl_space_copy(ran)); + ran_ran = isl_space_range(ran); + dom = isl_space_join(isl_space_from_domain(dom_dom), + isl_space_from_range(ran_dom)); + ran = isl_space_join(isl_space_from_domain(dom_ran), + isl_space_from_range(ran_ran)); + return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)), + isl_space_from_range(isl_space_wrap(ran))); +error: + isl_space_free(dim); + return NULL; +} + +/* Can we apply isl_space_curry to "space"? + * That is, does it have a nested relation in its domain? + */ +isl_bool isl_space_can_curry(__isl_keep isl_space *space) +{ + if (!space) + return isl_bool_error; + + return !!space->nested[0]; +} + +/* Given a space (A -> B) -> C, return the corresponding space + * A -> (B -> C). + */ +__isl_give isl_space *isl_space_curry(__isl_take isl_space *space) +{ + isl_space *dom, *ran; + isl_space *dom_dom, *dom_ran; + + if (!space) + return NULL; + + if (!isl_space_can_curry(space)) + isl_die(space->ctx, isl_error_invalid, + "space cannot be curried", goto error); + + dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space))); + ran = isl_space_range(space); + dom_dom = isl_space_domain(isl_space_copy(dom)); + dom_ran = isl_space_range(dom); + ran = isl_space_join(isl_space_from_domain(dom_ran), + isl_space_from_range(ran)); + return isl_space_join(isl_space_from_domain(dom_dom), + isl_space_from_range(isl_space_wrap(ran))); +error: + isl_space_free(space); + return NULL; +} + +/* Can isl_space_range_curry be applied to "space"? + * That is, does it have a nested relation in its range, + * the domain of which is itself a nested relation? + */ +isl_bool isl_space_can_range_curry(__isl_keep isl_space *space) +{ + isl_bool can; + + if (!space) + return isl_bool_error; + can = isl_space_range_is_wrapping(space); + if (can < 0 || !can) + return can; + return isl_space_can_curry(space->nested[1]); +} + +/* Given a space A -> ((B -> C) -> D), return the corresponding space + * A -> (B -> (C -> D)). + */ +__isl_give isl_space *isl_space_range_curry(__isl_take isl_space *space) +{ + if (!space) + return NULL; + + if (!isl_space_can_range_curry(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "space range cannot be curried", + return isl_space_free(space)); + + space = isl_space_cow(space); + if (!space) + return NULL; + space->nested[1] = isl_space_curry(space->nested[1]); + if (!space->nested[1]) + return isl_space_free(space); + + return space; +} + +/* Can we apply isl_space_uncurry to "space"? + * That is, does it have a nested relation in its range? + */ +isl_bool isl_space_can_uncurry(__isl_keep isl_space *space) +{ + if (!space) + return isl_bool_error; + + return !!space->nested[1]; +} + +/* Given a space A -> (B -> C), return the corresponding space + * (A -> B) -> C. + */ +__isl_give isl_space *isl_space_uncurry(__isl_take isl_space *space) +{ + isl_space *dom, *ran; + isl_space *ran_dom, *ran_ran; + + if (!space) + return NULL; + + if (!isl_space_can_uncurry(space)) + isl_die(space->ctx, isl_error_invalid, + "space cannot be uncurried", + return isl_space_free(space)); + + dom = isl_space_domain(isl_space_copy(space)); + ran = isl_space_unwrap(isl_space_range(space)); + ran_dom = isl_space_domain(isl_space_copy(ran)); + ran_ran = isl_space_range(ran); + dom = isl_space_join(isl_space_from_domain(dom), + isl_space_from_range(ran_dom)); + return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)), + isl_space_from_range(ran_ran)); +} + +isl_bool isl_space_has_named_params(__isl_keep isl_space *space) +{ + int i; + unsigned off; + + if (!space) + return isl_bool_error; + if (space->nparam == 0) + return isl_bool_true; + off = isl_space_offset(space, isl_dim_param); + if (off + space->nparam > space->n_id) + return isl_bool_false; + for (i = 0; i < space->nparam; ++i) + if (!space->ids[off + i]) + return isl_bool_false; + return isl_bool_true; +} + +/* Check that "space" has only named parameters, reporting an error + * if it does not. + */ +isl_stat isl_space_check_named_params(__isl_keep isl_space *space) +{ + isl_bool named; + + named = isl_space_has_named_params(space); + if (named < 0) + return isl_stat_error; + if (!named) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "unaligned unnamed parameters", return isl_stat_error); + + return isl_stat_ok; +} + +/* Align the initial parameters of dim1 to match the order in dim2. + */ +__isl_give isl_space *isl_space_align_params(__isl_take isl_space *dim1, + __isl_take isl_space *dim2) +{ + isl_reordering *exp; + + if (!isl_space_has_named_params(dim1) || !isl_space_has_named_params(dim2)) + isl_die(isl_space_get_ctx(dim1), isl_error_invalid, + "parameter alignment requires named parameters", + goto error); + + dim2 = isl_space_params(dim2); + exp = isl_parameter_alignment_reordering(dim1, dim2); + exp = isl_reordering_extend_space(exp, dim1); + isl_space_free(dim2); + if (!exp) + return NULL; + dim1 = isl_space_copy(exp->dim); + isl_reordering_free(exp); + return dim1; +error: + isl_space_free(dim1); + isl_space_free(dim2); + return NULL; +} + +/* Given the space of set (domain), construct a space for a map + * with as domain the given space and as range the range of "model". + */ +__isl_give isl_space *isl_space_extend_domain_with_range( + __isl_take isl_space *space, __isl_take isl_space *model) +{ + if (!model) + goto error; + + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, + isl_space_dim(model, isl_dim_out)); + if (isl_space_has_tuple_id(model, isl_dim_out)) + space = isl_space_set_tuple_id(space, isl_dim_out, + isl_space_get_tuple_id(model, isl_dim_out)); + if (!space) + goto error; + if (model->nested[1]) { + isl_space *nested = isl_space_copy(model->nested[1]); + int n_nested, n_space; + nested = isl_space_align_params(nested, isl_space_copy(space)); + n_nested = isl_space_dim(nested, isl_dim_param); + n_space = isl_space_dim(space, isl_dim_param); + if (n_nested > n_space) + nested = isl_space_drop_dims(nested, isl_dim_param, + n_space, n_nested - n_space); + if (!nested) + goto error; + space->nested[1] = nested; + } + isl_space_free(model); + return space; +error: + isl_space_free(model); + isl_space_free(space); + return NULL; +} + +/* Compare the "type" dimensions of two isl_spaces. + * + * The order is fairly arbitrary. + */ +static int isl_space_cmp_type(__isl_keep isl_space *space1, + __isl_keep isl_space *space2, enum isl_dim_type type) +{ + int cmp; + isl_space *nested1, *nested2; + + if (isl_space_dim(space1, type) != isl_space_dim(space2, type)) + return isl_space_dim(space1, type) - + isl_space_dim(space2, type); + + cmp = isl_id_cmp(tuple_id(space1, type), tuple_id(space2, type)); + if (cmp != 0) + return cmp; + + nested1 = nested(space1, type); + nested2 = nested(space2, type); + if (!nested1 != !nested2) + return !nested1 - !nested2; + + if (nested1) + return isl_space_cmp(nested1, nested2); + + return 0; +} + +/* Compare two isl_spaces. + * + * The order is fairly arbitrary. + */ +int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2) +{ + int i; + int cmp; + + if (space1 == space2) + return 0; + if (!space1) + return -1; + if (!space2) + return 1; + + cmp = isl_space_cmp_type(space1, space2, isl_dim_param); + if (cmp != 0) + return cmp; + cmp = isl_space_cmp_type(space1, space2, isl_dim_in); + if (cmp != 0) + return cmp; + cmp = isl_space_cmp_type(space1, space2, isl_dim_out); + if (cmp != 0) + return cmp; + + if (!space1->ids && !space2->ids) + return 0; + + for (i = 0; i < n(space1, isl_dim_param); ++i) { + cmp = isl_id_cmp(get_id(space1, isl_dim_param, i), + get_id(space2, isl_dim_param, i)); + if (cmp != 0) + return cmp; + } + + return 0; +} Index: contrib/isl/isl_space_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_space_private.h @@ -0,0 +1,64 @@ +#ifndef ISL_SPACE_PRIVATE +#define ISL_SPACE_PRIVATE + +#include +#include +#include + +struct isl_name; +struct isl_space { + int ref; + + struct isl_ctx *ctx; + + unsigned nparam; + unsigned n_in; /* zero for sets */ + unsigned n_out; /* dim for sets */ + + isl_id *tuple_id[2]; + isl_space *nested[2]; + + unsigned n_id; + isl_id **ids; +}; + +__isl_give isl_space *isl_space_cow(__isl_take isl_space *dim); + +__isl_give isl_space *isl_space_underlying(__isl_take isl_space *dim, + unsigned n_div); + +uint32_t isl_space_get_tuple_hash(__isl_keep isl_space *space); +uint32_t isl_space_get_hash(__isl_keep isl_space *space); +uint32_t isl_space_get_domain_hash(__isl_keep isl_space *space); + +isl_bool isl_space_is_domain_internal(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); +isl_bool isl_space_is_range_internal(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); + +unsigned isl_space_offset(__isl_keep isl_space *dim, enum isl_dim_type type); + +isl_bool isl_space_may_be_set(__isl_keep isl_space *space); +isl_bool isl_space_is_named_or_nested(__isl_keep isl_space *space, + enum isl_dim_type type); +isl_bool isl_space_has_equal_ids(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); +isl_bool isl_space_has_named_params(__isl_keep isl_space *space); +isl_stat isl_space_check_named_params(__isl_keep isl_space *space); +isl_stat isl_space_check_equal_params(__isl_keep isl_space *space1, + __isl_keep isl_space *space2); +__isl_give isl_space *isl_space_reset(__isl_take isl_space *dim, + enum isl_dim_type type); +__isl_give isl_space *isl_space_flatten(__isl_take isl_space *dim); + +__isl_give isl_space *isl_space_replace(__isl_take isl_space *dst, + enum isl_dim_type type, __isl_keep isl_space *src); + +__isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local); + +__isl_give isl_space *isl_space_extend_domain_with_range( + __isl_take isl_space *domain, __isl_take isl_space *model); + +int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2); + +#endif Index: contrib/isl/isl_srcdir.c.in =================================================================== --- /dev/null +++ contrib/isl/isl_srcdir.c.in @@ -0,0 +1 @@ +static const char *srcdir = "@srcdir@"; Index: contrib/isl/isl_stream.c =================================================================== --- /dev/null +++ contrib/isl/isl_stream.c @@ -0,0 +1,1170 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include +#include +#include +#include + +struct isl_keyword { + char *name; + enum isl_token_type type; +}; + +static int same_name(const void *entry, const void *val) +{ + const struct isl_keyword *keyword = (const struct isl_keyword *)entry; + + return !strcmp(keyword->name, val); +} + +enum isl_token_type isl_stream_register_keyword(__isl_keep isl_stream *s, + const char *name) +{ + struct isl_hash_table_entry *entry; + struct isl_keyword *keyword; + uint32_t name_hash; + + if (!s->keywords) { + s->keywords = isl_hash_table_alloc(s->ctx, 10); + if (!s->keywords) + return ISL_TOKEN_ERROR; + s->next_type = ISL_TOKEN_LAST; + } + + name_hash = isl_hash_string(isl_hash_init(), name); + + entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, + same_name, name, 1); + if (!entry) + return ISL_TOKEN_ERROR; + if (entry->data) { + keyword = entry->data; + return keyword->type; + } + + keyword = isl_calloc_type(s->ctx, struct isl_keyword); + if (!keyword) + return ISL_TOKEN_ERROR; + keyword->type = s->next_type++; + keyword->name = strdup(name); + if (!keyword->name) { + free(keyword); + return ISL_TOKEN_ERROR; + } + entry->data = keyword; + + return keyword->type; +} + +struct isl_token *isl_token_new(isl_ctx *ctx, + int line, int col, unsigned on_new_line) +{ + struct isl_token *tok = isl_alloc_type(ctx, struct isl_token); + if (!tok) + return NULL; + tok->line = line; + tok->col = col; + tok->on_new_line = on_new_line; + tok->is_keyword = 0; + tok->u.s = NULL; + return tok; +} + +/* Return the type of "tok". + */ +int isl_token_get_type(struct isl_token *tok) +{ + return tok ? tok->type : ISL_TOKEN_ERROR; +} + +/* Given a token of type ISL_TOKEN_VALUE, return the value it represents. + */ +__isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok) +{ + if (!tok) + return NULL; + if (tok->type != ISL_TOKEN_VALUE) + isl_die(ctx, isl_error_invalid, "not a value token", + return NULL); + + return isl_val_int_from_isl_int(ctx, tok->u.v); +} + +/* Given a token with a string representation, return a copy of this string. + */ +__isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok) +{ + if (!tok) + return NULL; + if (!tok->u.s) + isl_die(ctx, isl_error_invalid, + "token does not have a string representation", + return NULL); + + return strdup(tok->u.s); +} + +void isl_token_free(struct isl_token *tok) +{ + if (!tok) + return; + if (tok->type == ISL_TOKEN_VALUE) + isl_int_clear(tok->u.v); + else if (tok->type == ISL_TOKEN_MAP) + isl_map_free(tok->u.map); + else if (tok->type == ISL_TOKEN_AFF) + isl_pw_aff_free(tok->u.pwaff); + else + free(tok->u.s); + free(tok); +} + +void isl_stream_error(__isl_keep isl_stream *s, struct isl_token *tok, + char *msg) +{ + int line = tok ? tok->line : s->line; + int col = tok ? tok->col : s->col; + fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg); + if (tok) { + if (tok->type < 256) + fprintf(stderr, "got '%c'\n", tok->type); + else if (tok->type == ISL_TOKEN_IDENT) + fprintf(stderr, "got ident '%s'\n", tok->u.s); + else if (tok->is_keyword) + fprintf(stderr, "got keyword '%s'\n", tok->u.s); + else if (tok->type == ISL_TOKEN_VALUE) { + fprintf(stderr, "got value '"); + isl_int_print(stderr, tok->u.v, 0); + fprintf(stderr, "'\n"); + } else if (tok->type == ISL_TOKEN_MAP) { + isl_printer *p; + fprintf(stderr, "got map '"); + p = isl_printer_to_file(s->ctx, stderr); + p = isl_printer_print_map(p, tok->u.map); + isl_printer_free(p); + fprintf(stderr, "'\n"); + } else if (tok->type == ISL_TOKEN_AFF) { + isl_printer *p; + fprintf(stderr, "got affine expression '"); + p = isl_printer_to_file(s->ctx, stderr); + p = isl_printer_print_pw_aff(p, tok->u.pwaff); + isl_printer_free(p); + fprintf(stderr, "'\n"); + } else if (tok->u.s) + fprintf(stderr, "got token '%s'\n", tok->u.s); + else + fprintf(stderr, "got token type %d\n", tok->type); + } +} + +static __isl_give isl_stream* isl_stream_new(struct isl_ctx *ctx) +{ + int i; + isl_stream *s = isl_calloc_type(ctx, struct isl_stream); + if (!s) + return NULL; + s->ctx = ctx; + isl_ctx_ref(s->ctx); + s->file = NULL; + s->str = NULL; + s->len = 0; + s->line = 1; + s->col = 1; + s->eof = 0; + s->last_line = 0; + s->c = -1; + s->n_un = 0; + for (i = 0; i < 5; ++i) + s->tokens[i] = NULL; + s->n_token = 0; + s->keywords = NULL; + s->size = 256; + s->buffer = isl_alloc_array(ctx, char, s->size); + if (!s->buffer) + goto error; + return s; +error: + isl_stream_free(s); + return NULL; +} + +__isl_give isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file) +{ + isl_stream *s = isl_stream_new(ctx); + if (!s) + return NULL; + s->file = file; + return s; +} + +__isl_give isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str) +{ + isl_stream *s; + if (!str) + return NULL; + s = isl_stream_new(ctx); + if (!s) + return NULL; + s->str = str; + return s; +} + +/* Read a character from the stream and advance s->line and s->col + * to point to the next character. + */ +static int stream_getc(__isl_keep isl_stream *s) +{ + int c; + if (s->eof) + return -1; + if (s->n_un) + return s->c = s->un[--s->n_un]; + if (s->file) + c = fgetc(s->file); + else { + c = *s->str++; + if (c == '\0') + c = -1; + } + if (c == -1) + s->eof = 1; + else if (c == '\n') { + s->line++; + s->col = 1; + } else + s->col++; + s->c = c; + return c; +} + +static void isl_stream_ungetc(__isl_keep isl_stream *s, int c) +{ + isl_assert(s->ctx, s->n_un < 5, return); + s->un[s->n_un++] = c; + s->c = -1; +} + +/* Read a character from the stream, skipping pairs of '\\' and '\n'. + * Set s->start_line and s->start_col to the line and column + * of the returned character. + */ +static int isl_stream_getc(__isl_keep isl_stream *s) +{ + int c; + + do { + s->start_line = s->line; + s->start_col = s->col; + c = stream_getc(s); + if (c != '\\') + return c; + c = stream_getc(s); + } while (c == '\n'); + + isl_stream_ungetc(s, c); + + return '\\'; +} + +static int isl_stream_push_char(__isl_keep isl_stream *s, int c) +{ + if (s->len >= s->size) { + char *buffer; + s->size = (3*s->size)/2; + buffer = isl_realloc_array(s->ctx, s->buffer, char, s->size); + if (!buffer) + return -1; + s->buffer = buffer; + } + s->buffer[s->len++] = c; + return 0; +} + +void isl_stream_push_token(__isl_keep isl_stream *s, struct isl_token *tok) +{ + isl_assert(s->ctx, s->n_token < 5, return); + s->tokens[s->n_token++] = tok; +} + +static enum isl_token_type check_keywords(__isl_keep isl_stream *s) +{ + struct isl_hash_table_entry *entry; + struct isl_keyword *keyword; + uint32_t name_hash; + + if (!strcasecmp(s->buffer, "exists")) + return ISL_TOKEN_EXISTS; + if (!strcasecmp(s->buffer, "and")) + return ISL_TOKEN_AND; + if (!strcasecmp(s->buffer, "or")) + return ISL_TOKEN_OR; + if (!strcasecmp(s->buffer, "implies")) + return ISL_TOKEN_IMPLIES; + if (!strcasecmp(s->buffer, "not")) + return ISL_TOKEN_NOT; + if (!strcasecmp(s->buffer, "infty")) + return ISL_TOKEN_INFTY; + if (!strcasecmp(s->buffer, "infinity")) + return ISL_TOKEN_INFTY; + if (!strcasecmp(s->buffer, "NaN")) + return ISL_TOKEN_NAN; + if (!strcasecmp(s->buffer, "min")) + return ISL_TOKEN_MIN; + if (!strcasecmp(s->buffer, "max")) + return ISL_TOKEN_MAX; + if (!strcasecmp(s->buffer, "rat")) + return ISL_TOKEN_RAT; + if (!strcasecmp(s->buffer, "true")) + return ISL_TOKEN_TRUE; + if (!strcasecmp(s->buffer, "false")) + return ISL_TOKEN_FALSE; + if (!strcasecmp(s->buffer, "ceild")) + return ISL_TOKEN_CEILD; + if (!strcasecmp(s->buffer, "floord")) + return ISL_TOKEN_FLOORD; + if (!strcasecmp(s->buffer, "mod")) + return ISL_TOKEN_MOD; + if (!strcasecmp(s->buffer, "ceil")) + return ISL_TOKEN_CEIL; + if (!strcasecmp(s->buffer, "floor")) + return ISL_TOKEN_FLOOR; + + if (!s->keywords) + return ISL_TOKEN_IDENT; + + name_hash = isl_hash_string(isl_hash_init(), s->buffer); + entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name, + s->buffer, 0); + if (entry) { + keyword = entry->data; + return keyword->type; + } + + return ISL_TOKEN_IDENT; +} + +int isl_stream_skip_line(__isl_keep isl_stream *s) +{ + int c; + + while ((c = isl_stream_getc(s)) != -1 && c != '\n') + /* nothing */ + ; + + return c == -1 ? -1 : 0; +} + +static struct isl_token *next_token(__isl_keep isl_stream *s, int same_line) +{ + int c; + struct isl_token *tok = NULL; + int line, col; + int old_line = s->last_line; + + if (s->n_token) { + if (same_line && s->tokens[s->n_token - 1]->on_new_line) + return NULL; + return s->tokens[--s->n_token]; + } + + if (same_line && s->c == '\n') + return NULL; + + s->len = 0; + + /* skip spaces and comment lines */ + while ((c = isl_stream_getc(s)) != -1) { + if (c == '#') { + if (isl_stream_skip_line(s) < 0) + break; + c = '\n'; + if (same_line) + break; + } else if (!isspace(c) || (same_line && c == '\n')) + break; + } + + line = s->start_line; + col = s->start_col; + + if (c == -1 || (same_line && c == '\n')) + return NULL; + s->last_line = line; + + if (c == '(' || + c == ')' || + c == '+' || + c == '*' || + c == '%' || + c == '?' || + c == '^' || + c == '@' || + c == '$' || + c == ',' || + c == '.' || + c == ';' || + c == '[' || + c == ']' || + c == '{' || + c == '}') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = (enum isl_token_type)c; + return tok; + } + if (c == '-') { + int c; + if ((c = isl_stream_getc(s)) == '>') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->u.s = strdup("->"); + tok->type = ISL_TOKEN_TO; + return tok; + } + if (c != -1) + isl_stream_ungetc(s, c); + if (!isdigit(c)) { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = (enum isl_token_type) '-'; + return tok; + } + } + if (c == '-' || isdigit(c)) { + int minus = c == '-'; + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = ISL_TOKEN_VALUE; + isl_int_init(tok->u.v); + if (isl_stream_push_char(s, c)) + goto error; + while ((c = isl_stream_getc(s)) != -1 && isdigit(c)) + if (isl_stream_push_char(s, c)) + goto error; + if (c != -1) + isl_stream_ungetc(s, c); + isl_stream_push_char(s, '\0'); + isl_int_read(tok->u.v, s->buffer); + if (minus && isl_int_is_zero(tok->u.v)) { + tok->col++; + tok->on_new_line = 0; + isl_stream_push_token(s, tok); + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = (enum isl_token_type) '-'; + } + return tok; + } + if (isalpha(c) || c == '_') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + isl_stream_push_char(s, c); + while ((c = isl_stream_getc(s)) != -1 && + (isalnum(c) || c == '_')) + isl_stream_push_char(s, c); + if (c != -1) + isl_stream_ungetc(s, c); + while ((c = isl_stream_getc(s)) != -1 && c == '\'') + isl_stream_push_char(s, c); + if (c != -1) + isl_stream_ungetc(s, c); + isl_stream_push_char(s, '\0'); + tok->type = check_keywords(s); + if (tok->type != ISL_TOKEN_IDENT) + tok->is_keyword = 1; + tok->u.s = strdup(s->buffer); + if (!tok->u.s) + goto error; + return tok; + } + if (c == '"') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = ISL_TOKEN_STRING; + tok->u.s = NULL; + while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n') + isl_stream_push_char(s, c); + if (c != '"') { + isl_stream_error(s, NULL, "unterminated string"); + goto error; + } + isl_stream_push_char(s, '\0'); + tok->u.s = strdup(s->buffer); + return tok; + } + if (c == '=') { + int c; + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + if ((c = isl_stream_getc(s)) == '=') { + tok->u.s = strdup("=="); + tok->type = ISL_TOKEN_EQ_EQ; + return tok; + } + if (c != -1) + isl_stream_ungetc(s, c); + tok->type = (enum isl_token_type) '='; + return tok; + } + if (c == ':') { + int c; + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + if ((c = isl_stream_getc(s)) == '=') { + tok->u.s = strdup(":="); + tok->type = ISL_TOKEN_DEF; + return tok; + } + if (c != -1) + isl_stream_ungetc(s, c); + tok->type = (enum isl_token_type) ':'; + return tok; + } + if (c == '>') { + int c; + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + if ((c = isl_stream_getc(s)) == '=') { + tok->u.s = strdup(">="); + tok->type = ISL_TOKEN_GE; + return tok; + } else if (c == '>') { + if ((c = isl_stream_getc(s)) == '=') { + tok->u.s = strdup(">>="); + tok->type = ISL_TOKEN_LEX_GE; + return tok; + } + tok->u.s = strdup(">>"); + tok->type = ISL_TOKEN_LEX_GT; + } else { + tok->u.s = strdup(">"); + tok->type = ISL_TOKEN_GT; + } + if (c != -1) + isl_stream_ungetc(s, c); + return tok; + } + if (c == '<') { + int c; + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + if ((c = isl_stream_getc(s)) == '=') { + tok->u.s = strdup("<="); + tok->type = ISL_TOKEN_LE; + return tok; + } else if (c == '<') { + if ((c = isl_stream_getc(s)) == '=') { + tok->u.s = strdup("<<="); + tok->type = ISL_TOKEN_LEX_LE; + return tok; + } + tok->u.s = strdup("<<"); + tok->type = ISL_TOKEN_LEX_LT; + } else { + tok->u.s = strdup("<"); + tok->type = ISL_TOKEN_LT; + } + if (c != -1) + isl_stream_ungetc(s, c); + return tok; + } + if (c == '&') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = ISL_TOKEN_AND; + if ((c = isl_stream_getc(s)) != '&' && c != -1) { + tok->u.s = strdup("&"); + isl_stream_ungetc(s, c); + } else + tok->u.s = strdup("&&"); + return tok; + } + if (c == '|') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = ISL_TOKEN_OR; + if ((c = isl_stream_getc(s)) != '|' && c != -1) { + tok->u.s = strdup("|"); + isl_stream_ungetc(s, c); + } else + tok->u.s = strdup("||"); + return tok; + } + if (c == '/') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + if ((c = isl_stream_getc(s)) != '\\' && c != -1) { + tok->type = (enum isl_token_type) '/'; + isl_stream_ungetc(s, c); + } else { + tok->u.s = strdup("/\\"); + tok->type = ISL_TOKEN_AND; + } + return tok; + } + if (c == '\\') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + if ((c = isl_stream_getc(s)) != '/' && c != -1) { + tok->type = (enum isl_token_type) '\\'; + isl_stream_ungetc(s, c); + } else { + tok->u.s = strdup("\\/"); + tok->type = ISL_TOKEN_OR; + } + return tok; + } + if (c == '!') { + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + if ((c = isl_stream_getc(s)) == '=') { + tok->u.s = strdup("!="); + tok->type = ISL_TOKEN_NE; + return tok; + } else { + tok->type = ISL_TOKEN_NOT; + tok->u.s = strdup("!"); + } + if (c != -1) + isl_stream_ungetc(s, c); + return tok; + } + + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = ISL_TOKEN_UNKNOWN; + return tok; +error: + isl_token_free(tok); + return NULL; +} + +struct isl_token *isl_stream_next_token(__isl_keep isl_stream *s) +{ + return next_token(s, 0); +} + +struct isl_token *isl_stream_next_token_on_same_line(__isl_keep isl_stream *s) +{ + return next_token(s, 1); +} + +int isl_stream_eat_if_available(__isl_keep isl_stream *s, int type) +{ + struct isl_token *tok; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type == type) { + isl_token_free(tok); + return 1; + } + isl_stream_push_token(s, tok); + return 0; +} + +int isl_stream_next_token_is(__isl_keep isl_stream *s, int type) +{ + struct isl_token *tok; + int r; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + r = tok->type == type; + isl_stream_push_token(s, tok); + return r; +} + +char *isl_stream_read_ident_if_available(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + + tok = isl_stream_next_token(s); + if (!tok) + return NULL; + if (tok->type == ISL_TOKEN_IDENT) { + char *ident = strdup(tok->u.s); + isl_token_free(tok); + return ident; + } + isl_stream_push_token(s, tok); + return NULL; +} + +int isl_stream_eat(__isl_keep isl_stream *s, int type) +{ + struct isl_token *tok; + + tok = isl_stream_next_token(s); + if (!tok) + return -1; + if (tok->type == type) { + isl_token_free(tok); + return 0; + } + isl_stream_error(s, tok, "expecting other token"); + isl_stream_push_token(s, tok); + return -1; +} + +int isl_stream_is_empty(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + + tok = isl_stream_next_token(s); + + if (!tok) + return 1; + + isl_stream_push_token(s, tok); + return 0; +} + +static isl_stat free_keyword(void **p, void *user) +{ + struct isl_keyword *keyword = *p; + + free(keyword->name); + free(keyword); + + return isl_stat_ok; +} + +void isl_stream_flush_tokens(__isl_keep isl_stream *s) +{ + int i; + + if (!s) + return; + for (i = 0; i < s->n_token; ++i) + isl_token_free(s->tokens[i]); + s->n_token = 0; +} + +isl_ctx *isl_stream_get_ctx(__isl_keep isl_stream *s) +{ + return s ? s->ctx : NULL; +} + +void isl_stream_free(__isl_take isl_stream *s) +{ + if (!s) + return; + free(s->buffer); + if (s->n_token != 0) { + struct isl_token *tok = isl_stream_next_token(s); + isl_stream_error(s, tok, "unexpected token"); + isl_token_free(tok); + } + if (s->keywords) { + isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL); + isl_hash_table_free(s->ctx, s->keywords); + } + free(s->yaml_state); + free(s->yaml_indent); + isl_ctx_deref(s->ctx); + free(s); +} + +/* Push "state" onto the stack of currently active YAML elements. + * The caller is responsible for setting the corresponding indentation. + * Return 0 on success and -1 on failure. + */ +static int push_state(__isl_keep isl_stream *s, enum isl_yaml_state state) +{ + if (s->yaml_size < s->yaml_depth + 1) { + int *indent; + enum isl_yaml_state *state; + + state = isl_realloc_array(s->ctx, s->yaml_state, + enum isl_yaml_state, s->yaml_depth + 1); + if (!state) + return -1; + s->yaml_state = state; + + indent = isl_realloc_array(s->ctx, s->yaml_indent, + int, s->yaml_depth + 1); + if (!indent) + return -1; + s->yaml_indent = indent; + + s->yaml_size = s->yaml_depth + 1; + } + + s->yaml_state[s->yaml_depth] = state; + s->yaml_depth++; + + return 0; +} + +/* Remove the innermost active YAML element from the stack. + * Return 0 on success and -1 on failure. + */ +static int pop_state(__isl_keep isl_stream *s) +{ + if (!s) + return -1; + if (s->yaml_depth < 1) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "not in YAML construct", return -1); + + s->yaml_depth--; + + return 0; +} + +/* Set the state of the innermost active YAML element to "state". + * Return 0 on success and -1 on failure. + */ +static int update_state(__isl_keep isl_stream *s, enum isl_yaml_state state) +{ + if (!s) + return -1; + if (s->yaml_depth < 1) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "not in YAML construct", return -1); + + s->yaml_state[s->yaml_depth - 1] = state; + + return 0; +} + +/* Return the state of the innermost active YAML element. + * Return isl_yaml_none if we are not inside any YAML element. + */ +static enum isl_yaml_state current_state(__isl_keep isl_stream *s) +{ + if (!s) + return isl_yaml_none; + if (s->yaml_depth < 1) + return isl_yaml_none; + return s->yaml_state[s->yaml_depth - 1]; +} + +/* Set the indentation of the innermost active YAML element to "indent". + * If "indent" is equal to ISL_YAML_INDENT_FLOW, then this means + * that the current elemient is in flow format. + */ +static int set_yaml_indent(__isl_keep isl_stream *s, int indent) +{ + if (s->yaml_depth < 1) + isl_die(s->ctx, isl_error_internal, + "not in YAML element", return -1); + + s->yaml_indent[s->yaml_depth - 1] = indent; + + return 0; +} + +/* Return the indentation of the innermost active YAML element + * of -1 on error. + */ +static int get_yaml_indent(__isl_keep isl_stream *s) +{ + if (s->yaml_depth < 1) + isl_die(s->ctx, isl_error_internal, + "not in YAML element", return -1); + + return s->yaml_indent[s->yaml_depth - 1]; +} + +/* Move to the next state at the innermost level. + * Return 1 if successful. + * Return 0 if we are at the end of the innermost level. + * Return -1 on error. + * + * If we are in state isl_yaml_mapping_key_start, then we have just + * started a mapping and we are expecting a key. If the mapping started + * with a '{', then we check if the next token is a '}'. If so, + * then the mapping is empty and there is no next state at this level. + * Otherwise, we assume that there is at least one key (the one from + * which we derived the indentation in isl_stream_yaml_read_start_mapping. + * + * If we are in state isl_yaml_mapping_key, then the we expect a colon + * followed by a value, so there is always a next state unless + * some error occurs. + * + * If we are in state isl_yaml_mapping_val, then there may or may + * not be a subsequent key in the same mapping. + * In flow format, the next key is preceded by a comma. + * In block format, the next key has the same indentation as the first key. + * If the first token has a smaller indentation, then we have reached + * the end of the current mapping. + * + * If we are in state isl_yaml_sequence_start, then we have just + * started a sequence. If the sequence started with a '[', + * then we check if the next token is a ']'. If so, then the sequence + * is empty and there is no next state at this level. + * Otherwise, we assume that there is at least one element in the sequence + * (the one from which we derived the indentation in + * isl_stream_yaml_read_start_sequence. + * + * If we are in state isl_yaml_sequence, then there may or may + * not be a subsequent element in the same sequence. + * In flow format, the next element is preceded by a comma. + * In block format, the next element is introduced by a dash with + * the same indentation as that of the first element. + * If the first token is not a dash or if it has a smaller indentation, + * then we have reached the end of the current sequence. + */ +int isl_stream_yaml_next(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + enum isl_yaml_state state; + int indent; + + state = current_state(s); + if (state == isl_yaml_none) + isl_die(s->ctx, isl_error_invalid, + "not in YAML element", return -1); + switch (state) { + case isl_yaml_mapping_key_start: + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW && + isl_stream_next_token_is(s, '}')) + return 0; + if (update_state(s, isl_yaml_mapping_key) < 0) + return -1; + return 1; + case isl_yaml_mapping_key: + tok = isl_stream_next_token(s); + if (!tok) { + if (s->eof) + isl_stream_error(s, NULL, "unexpected EOF"); + return -1; + } + if (tok->type == ':') { + isl_token_free(tok); + if (update_state(s, isl_yaml_mapping_val) < 0) + return -1; + return 1; + } + isl_stream_error(s, tok, "expecting ':'"); + isl_stream_push_token(s, tok); + return -1; + case isl_yaml_mapping_val: + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { + if (!isl_stream_eat_if_available(s, ',')) + return 0; + if (update_state(s, isl_yaml_mapping_key) < 0) + return -1; + return 1; + } + tok = isl_stream_next_token(s); + if (!tok) + return 0; + indent = tok->col - 1; + isl_stream_push_token(s, tok); + if (indent < get_yaml_indent(s)) + return 0; + if (update_state(s, isl_yaml_mapping_key) < 0) + return -1; + return 1; + case isl_yaml_sequence_start: + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { + if (isl_stream_next_token_is(s, ']')) + return 0; + if (update_state(s, isl_yaml_sequence) < 0) + return -1; + return 1; + } + tok = isl_stream_next_token(s); + if (!tok) { + if (s->eof) + isl_stream_error(s, NULL, "unexpected EOF"); + return -1; + } + if (tok->type == '-') { + isl_token_free(tok); + if (update_state(s, isl_yaml_sequence) < 0) + return -1; + return 1; + } + isl_stream_error(s, tok, "expecting '-'"); + isl_stream_push_token(s, tok); + return 0; + case isl_yaml_sequence: + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) + return isl_stream_eat_if_available(s, ','); + tok = isl_stream_next_token(s); + if (!tok) + return 0; + indent = tok->col - 1; + if (indent < get_yaml_indent(s) || tok->type != '-') { + isl_stream_push_token(s, tok); + return 0; + } + isl_token_free(tok); + return 1; + default: + isl_die(s->ctx, isl_error_internal, + "unexpected state", return 0); + } +} + +/* Start reading a YAML mapping. + * Return 0 on success and -1 on error. + * + * If the first token on the stream is a '{' then we remove this token + * from the stream and keep track of the fact that the mapping + * is given in flow format. + * Otherwise, we assume the first token is the first key of the mapping and + * keep track of its indentation, but keep the token on the stream. + * In both cases, the next token we expect is the first key of the mapping. + */ +int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int indent; + + if (push_state(s, isl_yaml_mapping_key_start) < 0) + return -1; + + tok = isl_stream_next_token(s); + if (!tok) { + if (s->eof) + isl_stream_error(s, NULL, "unexpected EOF"); + return -1; + } + if (isl_token_get_type(tok) == '{') { + isl_token_free(tok); + return set_yaml_indent(s, ISL_YAML_INDENT_FLOW); + } + indent = tok->col - 1; + isl_stream_push_token(s, tok); + + return set_yaml_indent(s, indent); +} + +/* Finish reading a YAML mapping. + * Return 0 on success and -1 on error. + * + * If the mapping started with a '{', then we expect a '}' to close + * the mapping. + * Otherwise, we double-check that the next token (if any) + * has a smaller indentation than that of the current mapping. + */ +int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int indent; + + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { + if (isl_stream_eat(s, '}') < 0) + return -1; + return pop_state(s); + } + + tok = isl_stream_next_token(s); + if (!tok) + return pop_state(s); + + indent = tok->col - 1; + isl_stream_push_token(s, tok); + + if (indent >= get_yaml_indent(s)) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "mapping not finished", return -1); + + return pop_state(s); +} + +/* Start reading a YAML sequence. + * Return 0 on success and -1 on error. + * + * If the first token on the stream is a '[' then we remove this token + * from the stream and keep track of the fact that the sequence + * is given in flow format. + * Otherwise, we assume the first token is the dash that introduces + * the first element of the sequence and keep track of its indentation, + * but keep the token on the stream. + * In both cases, the next token we expect is the first element + * of the sequence. + */ +int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int indent; + + if (push_state(s, isl_yaml_sequence_start) < 0) + return -1; + + tok = isl_stream_next_token(s); + if (!tok) { + if (s->eof) + isl_stream_error(s, NULL, "unexpected EOF"); + return -1; + } + if (isl_token_get_type(tok) == '[') { + isl_token_free(tok); + return set_yaml_indent(s, ISL_YAML_INDENT_FLOW); + } + indent = tok->col - 1; + isl_stream_push_token(s, tok); + + return set_yaml_indent(s, indent); +} + +/* Finish reading a YAML sequence. + * Return 0 on success and -1 on error. + * + * If the sequence started with a '[', then we expect a ']' to close + * the sequence. + * Otherwise, we double-check that the next token (if any) + * is not a dash or that it has a smaller indentation than + * that of the current sequence. + */ +int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int indent; + int dash; + + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { + if (isl_stream_eat(s, ']') < 0) + return -1; + return pop_state(s); + } + + tok = isl_stream_next_token(s); + if (!tok) + return pop_state(s); + + indent = tok->col - 1; + dash = tok->type == '-'; + isl_stream_push_token(s, tok); + + if (indent >= get_yaml_indent(s) && dash) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "sequence not finished", return -1); + + return pop_state(s); +} Index: contrib/isl/isl_stream_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_stream_private.h @@ -0,0 +1,69 @@ +#include +#include +#include + +struct isl_token { + int type; + + unsigned int on_new_line : 1; + unsigned is_keyword : 1; + int line; + int col; + + union { + isl_int v; + char *s; + isl_map *map; + isl_pw_aff *pwaff; + } u; +}; + +struct isl_token *isl_token_new(isl_ctx *ctx, + int line, int col, unsigned on_new_line); + +/* An input stream that may be either a file or a string. + * + * line and col are the line and column number of the next character (1-based). + * start_line and start_col are set by isl_stream_getc to point + * to the position of the returned character. + * last_line is the line number of the previous token. + * + * yaml_state and yaml_indent keep track of the currently active YAML + * elements. yaml_size is the size of these arrays, while yaml_depth + * is the number of elements currently in use. + * yaml_state and yaml_indent may be NULL if no YAML parsing is being + * performed. + * yaml_state keeps track of what is expected next at each level. + * yaml_indent keeps track of the indentation at each level, with + * ISL_YAML_INDENT_FLOW meaning that the element is in flow format + * (such that the indentation is not relevant). + */ +struct isl_stream { + struct isl_ctx *ctx; + FILE *file; + const char *str; + int line; + int col; + int start_line; + int start_col; + int last_line; + int eof; + + char *buffer; + size_t size; + size_t len; + int c; + int un[5]; + int n_un; + + struct isl_token *tokens[5]; + int n_token; + + struct isl_hash_table *keywords; + enum isl_token_type next_type; + + int yaml_depth; + int yaml_size; + enum isl_yaml_state *yaml_state; + int *yaml_indent; +}; Index: contrib/isl/isl_tab.h =================================================================== --- /dev/null +++ contrib/isl/isl_tab.h @@ -0,0 +1,336 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#ifndef ISL_TAB_H +#define ISL_TAB_H + +#include +#include +#include +#include +#include + +struct isl_tab_var { + int index; + unsigned is_row : 1; + unsigned is_nonneg : 1; + unsigned is_zero : 1; + unsigned is_redundant : 1; + unsigned marked : 1; + unsigned frozen : 1; + unsigned negated : 1; +}; + +enum isl_tab_undo_type { + isl_tab_undo_bottom, + isl_tab_undo_rational, + isl_tab_undo_empty, + isl_tab_undo_nonneg, + isl_tab_undo_redundant, + isl_tab_undo_freeze, + isl_tab_undo_zero, + isl_tab_undo_allocate, + isl_tab_undo_relax, + isl_tab_undo_unrestrict, + isl_tab_undo_bmap_ineq, + isl_tab_undo_bmap_eq, + isl_tab_undo_bmap_div, + isl_tab_undo_saved_basis, + isl_tab_undo_drop_sample, + isl_tab_undo_saved_samples, + isl_tab_undo_callback, +}; + +struct isl_tab_callback { + isl_stat (*run)(struct isl_tab_callback *cb); +}; + +union isl_tab_undo_val { + int var_index; + int *col_var; + int n; + struct isl_tab_callback *callback; +}; + +struct isl_tab_undo { + enum isl_tab_undo_type type; + union isl_tab_undo_val u; + struct isl_tab_undo *next; +}; + +/* The tableau maintains equality relations. + * Each column and each row is associated to a variable or a constraint. + * The "value" of an inequality constraint is the value of the corresponding + * slack variable. + * The "row_var" and "col_var" arrays map column and row indices + * to indices in the "var" and "con" arrays. The elements of these + * arrays maintain extra information about the variables and the constraints. + * Each row expresses the corresponding row variable as an affine expression + * of the column variables. + * The first two columns in the matrix contain the common denominator of + * the row and the numerator of the constant term. + * If "M" is set, then the third column represents the "big parameter". + * The third (M = 0) or fourth (M = 1) column + * in the matrix is called column 0 with respect to the col_var array. + * The sample value of the tableau is the value that assigns zero + * to all the column variables and the constant term of each affine + * expression to the corresponding row variable. + * The operations on the tableau maintain the property that the sample + * value satisfies the non-negativity constraints (usually on the slack + * variables). + * + * The big parameter represents an arbitrarily big (and divisible) + * positive number. If present, then the sign of a row is determined + * lexicographically, with the sign of the big parameter coefficient + * considered first. The big parameter is only used while + * solving PILP problems. + * + * The first n_dead column variables have their values fixed to zero. + * The corresponding tab_vars are flagged "is_zero". + * Some of the rows that have have zero coefficients in all but + * the dead columns are also flagged "is_zero". + * + * The first n_redundant rows correspond to inequality constraints + * that are always satisfied for any value satisfying the non-redundant + * rows. The corresponding tab_vars are flagged "is_redundant". + * A row variable that is flagged "is_zero" is also flagged "is_redundant" + * since the constraint has been reduced to 0 = 0 and is therefore always + * satisfied. + * + * There are "n_var" variables in total. The first "n_param" of these + * are called parameters and the last "n_div" of these are called divs. + * The basic tableau operations makes no distinction between different + * kinds of variables. These special variables are only used while + * solving PILP problems. + * + * Dead columns and redundant rows are detected on the fly. + * However, the basic operations do not ensure that all dead columns + * or all redundant rows are detected. + * isl_tab_detect_implicit_equalities and isl_tab_detect_redundant can be used + * to perform an exhaustive search for dead columns and redundant rows. + * + * The samples matrix contains "n_sample" integer points that have at some + * point been elements satisfying the tableau. The first "n_outside" + * of them no longer satisfy the tableau. They are kept because they + * can be reinstated during rollback when the constraint that cut them + * out is removed. These samples are only maintained for the context + * tableau while solving PILP problems. + * + * If "preserve" is set, then we want to keep all constraints in the + * tableau, even if they turn out to be redundant. + */ +enum isl_tab_row_sign { + isl_tab_row_unknown = 0, + isl_tab_row_pos, + isl_tab_row_neg, + isl_tab_row_any, +}; +struct isl_tab { + struct isl_mat *mat; + + unsigned n_row; + unsigned n_col; + unsigned n_dead; + unsigned n_redundant; + + unsigned n_var; + unsigned n_param; + unsigned n_div; + unsigned max_var; + unsigned n_con; + unsigned n_eq; + unsigned max_con; + struct isl_tab_var *var; + struct isl_tab_var *con; + int *row_var; /* v >= 0 -> var v; v < 0 -> con ~v */ + int *col_var; /* v >= 0 -> var v; v < 0 -> con ~v */ + enum isl_tab_row_sign *row_sign; + + struct isl_tab_undo bottom; + struct isl_tab_undo *top; + + struct isl_vec *dual; + struct isl_basic_map *bmap; + + unsigned n_sample; + unsigned n_outside; + int *sample_index; + struct isl_mat *samples; + + int n_zero; + 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 preserve : 1; + unsigned rational : 1; + unsigned empty : 1; + unsigned in_undo : 1; + unsigned M : 1; + unsigned cone : 1; +}; + +struct isl_tab *isl_tab_alloc(struct isl_ctx *ctx, + unsigned n_row, unsigned n_var, unsigned M); +void isl_tab_free(struct isl_tab *tab); + +isl_ctx *isl_tab_get_ctx(struct isl_tab *tab); + +__isl_give struct isl_tab *isl_tab_from_basic_map( + __isl_keep isl_basic_map *bmap, int track); +__isl_give struct isl_tab *isl_tab_from_basic_set( + __isl_keep isl_basic_set *bset, int track); +struct isl_tab *isl_tab_from_recession_cone(struct isl_basic_set *bset, + int parametric); +isl_bool isl_tab_cone_is_bounded(struct isl_tab *tab); +struct isl_basic_map *isl_basic_map_update_from_tab(struct isl_basic_map *bmap, + struct isl_tab *tab); +struct isl_basic_set *isl_basic_set_update_from_tab(struct isl_basic_set *bset, + struct isl_tab *tab); +int isl_tab_detect_implicit_equalities(struct isl_tab *tab) WARN_UNUSED; +__isl_give isl_basic_map *isl_tab_make_equalities_explicit(struct isl_tab *tab, + __isl_take isl_basic_map *bmap); +int isl_tab_detect_redundant(struct isl_tab *tab) WARN_UNUSED; +isl_stat isl_tab_restore_redundant(struct isl_tab *tab); +#define ISL_TAB_SAVE_DUAL (1 << 0) +enum isl_lp_result isl_tab_min(struct isl_tab *tab, + isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom, + unsigned flags) WARN_UNUSED; + +isl_stat isl_tab_add_ineq(struct isl_tab *tab, isl_int *ineq) WARN_UNUSED; +int isl_tab_add_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED; +int isl_tab_add_valid_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED; + +int isl_tab_freeze_constraint(struct isl_tab *tab, int con) WARN_UNUSED; + +isl_stat isl_tab_track_bmap(struct isl_tab *tab, __isl_take isl_basic_map *bmap) + WARN_UNUSED; +isl_stat isl_tab_track_bset(struct isl_tab *tab, __isl_take isl_basic_set *bset) + WARN_UNUSED; +__isl_keep isl_basic_set *isl_tab_peek_bset(struct isl_tab *tab); + +int isl_tab_is_equality(struct isl_tab *tab, int con); +int isl_tab_is_redundant(struct isl_tab *tab, int con); + +int isl_tab_sample_is_integer(struct isl_tab *tab); +struct isl_vec *isl_tab_get_sample_value(struct isl_tab *tab); + +enum isl_ineq_type { + isl_ineq_error = -1, + isl_ineq_redundant, + isl_ineq_separate, + isl_ineq_cut, + isl_ineq_adj_eq, + isl_ineq_adj_ineq, +}; + +enum isl_ineq_type isl_tab_ineq_type(struct isl_tab *tab, isl_int *ineq); + +struct isl_tab_undo *isl_tab_snap(struct isl_tab *tab); +int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap) WARN_UNUSED; +isl_bool isl_tab_need_undo(struct isl_tab *tab); +void isl_tab_clear_undo(struct isl_tab *tab); + +int isl_tab_relax(struct isl_tab *tab, int con) WARN_UNUSED; +int isl_tab_select_facet(struct isl_tab *tab, int con) WARN_UNUSED; +int isl_tab_unrestrict(struct isl_tab *tab, int con) WARN_UNUSED; + +void isl_tab_dump(__isl_keep struct isl_tab *tab); + +/* Compute maximum instead of minimum. */ +#define ISL_OPT_MAX (1 << 0) +/* Compute full instead of partial optimum; also, domain argument is NULL. */ +#define ISL_OPT_FULL (1 << 1) +/* Result should be free of (unknown) quantified variables. */ +#define ISL_OPT_QE (1 << 2) +__isl_give isl_map *isl_tab_basic_map_partial_lexopt( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, unsigned flags); +__isl_give isl_pw_multi_aff *isl_tab_basic_map_partial_lexopt_pw_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, unsigned flags); + +/* An isl_trivial_region represents a non-triviality region. + * The region is trivial if applying "trivial" to a given sequence + * of variables results in a zero vector. + * pos is the location (starting at 0) of the first variable in the sequence. + */ +struct isl_trivial_region { + int pos; + isl_mat *trivial; +}; + +__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_trivial_region *region, + int (*conflict)(int con, void *user), void *user); + +struct isl_tab_lexmin; +typedef struct isl_tab_lexmin isl_tab_lexmin; + +__isl_give isl_tab_lexmin *isl_tab_lexmin_from_basic_set( + __isl_take isl_basic_set *bset); +int isl_tab_lexmin_dim(__isl_keep isl_tab_lexmin *tl); +__isl_give isl_tab_lexmin *isl_tab_lexmin_add_eq(__isl_take isl_tab_lexmin *tl, + isl_int *eq); +__isl_give isl_tab_lexmin *isl_tab_lexmin_cut_to_integer( + __isl_take isl_tab_lexmin *tl); +__isl_give isl_vec *isl_tab_lexmin_get_solution(__isl_keep isl_tab_lexmin *tl); +__isl_null isl_tab_lexmin *isl_tab_lexmin_free(__isl_take isl_tab_lexmin *tl); + +/* private */ + +struct isl_tab_var *isl_tab_var_from_row(struct isl_tab *tab, int i); +int isl_tab_mark_redundant(struct isl_tab *tab, int row) WARN_UNUSED; +int isl_tab_mark_rational(struct isl_tab *tab) WARN_UNUSED; +isl_stat isl_tab_mark_empty(struct isl_tab *tab) WARN_UNUSED; +struct isl_tab *isl_tab_dup(struct isl_tab *tab); +struct isl_tab *isl_tab_product(struct isl_tab *tab1, struct isl_tab *tab2); +int isl_tab_extend_cons(struct isl_tab *tab, unsigned n_new) WARN_UNUSED; +int isl_tab_allocate_con(struct isl_tab *tab) WARN_UNUSED; +int isl_tab_extend_vars(struct isl_tab *tab, unsigned n_new) WARN_UNUSED; +int isl_tab_allocate_var(struct isl_tab *tab) WARN_UNUSED; +int isl_tab_insert_var(struct isl_tab *tab, int pos) WARN_UNUSED; +int isl_tab_pivot(struct isl_tab *tab, int row, int col) WARN_UNUSED; +int isl_tab_add_row(struct isl_tab *tab, isl_int *line) WARN_UNUSED; +int isl_tab_row_is_redundant(struct isl_tab *tab, int row); +int isl_tab_min_at_most_neg_one(struct isl_tab *tab, struct isl_tab_var *var); +int isl_tab_sign_of_max(struct isl_tab *tab, int con); +int isl_tab_kill_col(struct isl_tab *tab, int col) WARN_UNUSED; + +int isl_tab_push(struct isl_tab *tab, enum isl_tab_undo_type type) WARN_UNUSED; +int isl_tab_push_var(struct isl_tab *tab, + enum isl_tab_undo_type type, struct isl_tab_var *var) WARN_UNUSED; +int isl_tab_push_basis(struct isl_tab *tab) WARN_UNUSED; + +struct isl_tab *isl_tab_init_samples(struct isl_tab *tab) WARN_UNUSED; +int isl_tab_add_sample(struct isl_tab *tab, + __isl_take isl_vec *sample) WARN_UNUSED; +struct isl_tab *isl_tab_drop_sample(struct isl_tab *tab, int s); +int isl_tab_save_samples(struct isl_tab *tab) WARN_UNUSED; + +struct isl_tab *isl_tab_detect_equalities(struct isl_tab *tab, + struct isl_tab *tab_cone) WARN_UNUSED; +isl_bool isl_tab_is_constant(struct isl_tab *tab, int var, isl_int *value); +isl_stat isl_tab_detect_constants(struct isl_tab *tab); + +int isl_tab_push_callback(struct isl_tab *tab, + struct isl_tab_callback *callback) WARN_UNUSED; + +int isl_tab_insert_div(struct isl_tab *tab, int pos, __isl_keep isl_vec *div, + isl_stat (*add_ineq)(void *user, isl_int *), void *user); +int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div); + +int isl_tab_shift_var(struct isl_tab *tab, int pos, isl_int shift) WARN_UNUSED; + +#endif Index: contrib/isl/isl_tab.c =================================================================== --- /dev/null +++ contrib/isl/isl_tab.c @@ -0,0 +1,4130 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2013 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include "isl_map_private.h" +#include "isl_tab.h" +#include +#include + +#include +#include + +/* + * The implementation of tableaus in this file was inspired by Section 8 + * of David Detlefs, Greg Nelson and James B. Saxe, "Simplify: a theorem + * prover for program checking". + */ + +struct isl_tab *isl_tab_alloc(struct isl_ctx *ctx, + unsigned n_row, unsigned n_var, unsigned M) +{ + int i; + struct isl_tab *tab; + unsigned off = 2 + M; + + tab = isl_calloc_type(ctx, struct isl_tab); + if (!tab) + return NULL; + tab->mat = isl_mat_alloc(ctx, n_row, off + n_var); + if (!tab->mat) + goto error; + tab->var = isl_alloc_array(ctx, struct isl_tab_var, n_var); + if (n_var && !tab->var) + goto error; + tab->con = isl_alloc_array(ctx, struct isl_tab_var, n_row); + if (n_row && !tab->con) + goto error; + tab->col_var = isl_alloc_array(ctx, int, n_var); + if (n_var && !tab->col_var) + goto error; + tab->row_var = isl_alloc_array(ctx, int, n_row); + if (n_row && !tab->row_var) + goto error; + for (i = 0; i < n_var; ++i) { + tab->var[i].index = i; + tab->var[i].is_row = 0; + tab->var[i].is_nonneg = 0; + tab->var[i].is_zero = 0; + tab->var[i].is_redundant = 0; + tab->var[i].frozen = 0; + tab->var[i].negated = 0; + tab->col_var[i] = i; + } + tab->n_row = 0; + tab->n_con = 0; + tab->n_eq = 0; + tab->max_con = n_row; + tab->n_col = n_var; + tab->n_var = n_var; + tab->max_var = n_var; + tab->n_param = 0; + tab->n_div = 0; + tab->n_dead = 0; + tab->n_redundant = 0; + tab->strict_redundant = 0; + tab->need_undo = 0; + tab->rational = 0; + tab->empty = 0; + tab->in_undo = 0; + tab->M = M; + tab->cone = 0; + tab->bottom.type = isl_tab_undo_bottom; + tab->bottom.next = NULL; + tab->top = &tab->bottom; + + tab->n_zero = 0; + tab->n_unbounded = 0; + tab->basis = NULL; + + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +isl_ctx *isl_tab_get_ctx(struct isl_tab *tab) +{ + return tab ? isl_mat_get_ctx(tab->mat) : NULL; +} + +int isl_tab_extend_cons(struct isl_tab *tab, unsigned n_new) +{ + unsigned off; + + if (!tab) + return -1; + + off = 2 + tab->M; + + if (tab->max_con < tab->n_con + n_new) { + struct isl_tab_var *con; + + con = isl_realloc_array(tab->mat->ctx, tab->con, + struct isl_tab_var, tab->max_con + n_new); + if (!con) + return -1; + tab->con = con; + tab->max_con += n_new; + } + if (tab->mat->n_row < tab->n_row + n_new) { + int *row_var; + + tab->mat = isl_mat_extend(tab->mat, + tab->n_row + n_new, off + tab->n_col); + if (!tab->mat) + return -1; + row_var = isl_realloc_array(tab->mat->ctx, tab->row_var, + int, tab->mat->n_row); + if (!row_var) + return -1; + tab->row_var = row_var; + if (tab->row_sign) { + enum isl_tab_row_sign *s; + s = isl_realloc_array(tab->mat->ctx, tab->row_sign, + enum isl_tab_row_sign, tab->mat->n_row); + if (!s) + return -1; + tab->row_sign = s; + } + } + return 0; +} + +/* Make room for at least n_new extra variables. + * Return -1 if anything went wrong. + */ +int isl_tab_extend_vars(struct isl_tab *tab, unsigned n_new) +{ + struct isl_tab_var *var; + unsigned off = 2 + tab->M; + + if (tab->max_var < tab->n_var + n_new) { + var = isl_realloc_array(tab->mat->ctx, tab->var, + struct isl_tab_var, tab->n_var + n_new); + if (!var) + return -1; + tab->var = var; + tab->max_var = tab->n_var + n_new; + } + + if (tab->mat->n_col < off + tab->n_col + n_new) { + int *p; + + tab->mat = isl_mat_extend(tab->mat, + tab->mat->n_row, off + tab->n_col + n_new); + if (!tab->mat) + return -1; + p = isl_realloc_array(tab->mat->ctx, tab->col_var, + int, tab->n_col + n_new); + if (!p) + return -1; + tab->col_var = p; + } + + return 0; +} + +static void free_undo_record(struct isl_tab_undo *undo) +{ + switch (undo->type) { + case isl_tab_undo_saved_basis: + free(undo->u.col_var); + break; + default:; + } + free(undo); +} + +static void free_undo(struct isl_tab *tab) +{ + struct isl_tab_undo *undo, *next; + + for (undo = tab->top; undo && undo != &tab->bottom; undo = next) { + next = undo->next; + free_undo_record(undo); + } + tab->top = undo; +} + +void isl_tab_free(struct isl_tab *tab) +{ + if (!tab) + return; + free_undo(tab); + isl_mat_free(tab->mat); + isl_vec_free(tab->dual); + isl_basic_map_free(tab->bmap); + free(tab->var); + free(tab->con); + free(tab->row_var); + free(tab->col_var); + free(tab->row_sign); + isl_mat_free(tab->samples); + free(tab->sample_index); + isl_mat_free(tab->basis); + free(tab); +} + +struct isl_tab *isl_tab_dup(struct isl_tab *tab) +{ + int i; + struct isl_tab *dup; + unsigned off; + + if (!tab) + return NULL; + + off = 2 + tab->M; + dup = isl_calloc_type(tab->mat->ctx, struct isl_tab); + if (!dup) + return NULL; + dup->mat = isl_mat_dup(tab->mat); + if (!dup->mat) + goto error; + dup->var = isl_alloc_array(tab->mat->ctx, struct isl_tab_var, tab->max_var); + if (tab->max_var && !dup->var) + goto error; + for (i = 0; i < tab->n_var; ++i) + dup->var[i] = tab->var[i]; + dup->con = isl_alloc_array(tab->mat->ctx, struct isl_tab_var, tab->max_con); + if (tab->max_con && !dup->con) + goto error; + for (i = 0; i < tab->n_con; ++i) + dup->con[i] = tab->con[i]; + dup->col_var = isl_alloc_array(tab->mat->ctx, int, tab->mat->n_col - off); + if ((tab->mat->n_col - off) && !dup->col_var) + goto error; + for (i = 0; i < tab->n_col; ++i) + dup->col_var[i] = tab->col_var[i]; + dup->row_var = isl_alloc_array(tab->mat->ctx, int, tab->mat->n_row); + if (tab->mat->n_row && !dup->row_var) + goto error; + for (i = 0; i < tab->n_row; ++i) + dup->row_var[i] = tab->row_var[i]; + if (tab->row_sign) { + dup->row_sign = isl_alloc_array(tab->mat->ctx, enum isl_tab_row_sign, + tab->mat->n_row); + if (tab->mat->n_row && !dup->row_sign) + goto error; + for (i = 0; i < tab->n_row; ++i) + dup->row_sign[i] = tab->row_sign[i]; + } + if (tab->samples) { + dup->samples = isl_mat_dup(tab->samples); + if (!dup->samples) + goto error; + dup->sample_index = isl_alloc_array(tab->mat->ctx, int, + tab->samples->n_row); + if (tab->samples->n_row && !dup->sample_index) + goto error; + dup->n_sample = tab->n_sample; + dup->n_outside = tab->n_outside; + } + dup->n_row = tab->n_row; + dup->n_con = tab->n_con; + dup->n_eq = tab->n_eq; + dup->max_con = tab->max_con; + dup->n_col = tab->n_col; + dup->n_var = tab->n_var; + dup->max_var = tab->max_var; + dup->n_param = tab->n_param; + dup->n_div = tab->n_div; + dup->n_dead = tab->n_dead; + dup->n_redundant = tab->n_redundant; + dup->rational = tab->rational; + dup->empty = tab->empty; + dup->strict_redundant = 0; + dup->need_undo = 0; + dup->in_undo = 0; + dup->M = tab->M; + tab->cone = tab->cone; + dup->bottom.type = isl_tab_undo_bottom; + dup->bottom.next = NULL; + dup->top = &dup->bottom; + + dup->n_zero = tab->n_zero; + dup->n_unbounded = tab->n_unbounded; + dup->basis = isl_mat_dup(tab->basis); + + return dup; +error: + isl_tab_free(dup); + return NULL; +} + +/* Construct the coefficient matrix of the product tableau + * of two tableaus. + * mat{1,2} is the coefficient matrix of tableau {1,2} + * row{1,2} is the number of rows in tableau {1,2} + * col{1,2} is the number of columns in tableau {1,2} + * off is the offset to the coefficient column (skipping the + * denominator, the constant term and the big parameter if any) + * r{1,2} is the number of redundant rows in tableau {1,2} + * d{1,2} is the number of dead columns in tableau {1,2} + * + * The order of the rows and columns in the result is as explained + * in isl_tab_product. + */ +static struct isl_mat *tab_mat_product(struct isl_mat *mat1, + struct isl_mat *mat2, unsigned row1, unsigned row2, + unsigned col1, unsigned col2, + unsigned off, unsigned r1, unsigned r2, unsigned d1, unsigned d2) +{ + int i; + struct isl_mat *prod; + unsigned n; + + prod = isl_mat_alloc(mat1->ctx, mat1->n_row + mat2->n_row, + off + col1 + col2); + if (!prod) + return NULL; + + n = 0; + for (i = 0; i < r1; ++i) { + isl_seq_cpy(prod->row[n + i], mat1->row[i], off + d1); + isl_seq_clr(prod->row[n + i] + off + d1, d2); + isl_seq_cpy(prod->row[n + i] + off + d1 + d2, + mat1->row[i] + off + d1, col1 - d1); + isl_seq_clr(prod->row[n + i] + off + col1 + d1, col2 - d2); + } + + n += r1; + for (i = 0; i < r2; ++i) { + isl_seq_cpy(prod->row[n + i], mat2->row[i], off); + isl_seq_clr(prod->row[n + i] + off, d1); + isl_seq_cpy(prod->row[n + i] + off + d1, + mat2->row[i] + off, d2); + isl_seq_clr(prod->row[n + i] + off + d1 + d2, col1 - d1); + isl_seq_cpy(prod->row[n + i] + off + col1 + d1, + mat2->row[i] + off + d2, col2 - d2); + } + + n += r2; + for (i = 0; i < row1 - r1; ++i) { + isl_seq_cpy(prod->row[n + i], mat1->row[r1 + i], off + d1); + isl_seq_clr(prod->row[n + i] + off + d1, d2); + isl_seq_cpy(prod->row[n + i] + off + d1 + d2, + mat1->row[r1 + i] + off + d1, col1 - d1); + isl_seq_clr(prod->row[n + i] + off + col1 + d1, col2 - d2); + } + + n += row1 - r1; + for (i = 0; i < row2 - r2; ++i) { + isl_seq_cpy(prod->row[n + i], mat2->row[r2 + i], off); + isl_seq_clr(prod->row[n + i] + off, d1); + isl_seq_cpy(prod->row[n + i] + off + d1, + mat2->row[r2 + i] + off, d2); + isl_seq_clr(prod->row[n + i] + off + d1 + d2, col1 - d1); + isl_seq_cpy(prod->row[n + i] + off + col1 + d1, + mat2->row[r2 + i] + off + d2, col2 - d2); + } + + return prod; +} + +/* Update the row or column index of a variable that corresponds + * to a variable in the first input tableau. + */ +static void update_index1(struct isl_tab_var *var, + unsigned r1, unsigned r2, unsigned d1, unsigned d2) +{ + if (var->index == -1) + return; + if (var->is_row && var->index >= r1) + var->index += r2; + if (!var->is_row && var->index >= d1) + var->index += d2; +} + +/* Update the row or column index of a variable that corresponds + * to a variable in the second input tableau. + */ +static void update_index2(struct isl_tab_var *var, + unsigned row1, unsigned col1, + unsigned r1, unsigned r2, unsigned d1, unsigned d2) +{ + if (var->index == -1) + return; + if (var->is_row) { + if (var->index < r2) + var->index += r1; + else + var->index += row1; + } else { + if (var->index < d2) + var->index += d1; + else + var->index += col1; + } +} + +/* Create a tableau that represents the Cartesian product of the sets + * represented by tableaus tab1 and tab2. + * The order of the rows in the product is + * - redundant rows of tab1 + * - redundant rows of tab2 + * - non-redundant rows of tab1 + * - non-redundant rows of tab2 + * The order of the columns is + * - denominator + * - constant term + * - coefficient of big parameter, if any + * - dead columns of tab1 + * - dead columns of tab2 + * - live columns of tab1 + * - live columns of tab2 + * The order of the variables and the constraints is a concatenation + * of order in the two input tableaus. + */ +struct isl_tab *isl_tab_product(struct isl_tab *tab1, struct isl_tab *tab2) +{ + int i; + struct isl_tab *prod; + unsigned off; + unsigned r1, r2, d1, d2; + + if (!tab1 || !tab2) + return NULL; + + isl_assert(tab1->mat->ctx, tab1->M == tab2->M, return NULL); + isl_assert(tab1->mat->ctx, tab1->rational == tab2->rational, return NULL); + isl_assert(tab1->mat->ctx, tab1->cone == tab2->cone, return NULL); + isl_assert(tab1->mat->ctx, !tab1->row_sign, return NULL); + isl_assert(tab1->mat->ctx, !tab2->row_sign, return NULL); + isl_assert(tab1->mat->ctx, tab1->n_param == 0, return NULL); + isl_assert(tab1->mat->ctx, tab2->n_param == 0, return NULL); + isl_assert(tab1->mat->ctx, tab1->n_div == 0, return NULL); + isl_assert(tab1->mat->ctx, tab2->n_div == 0, return NULL); + + off = 2 + tab1->M; + r1 = tab1->n_redundant; + r2 = tab2->n_redundant; + d1 = tab1->n_dead; + d2 = tab2->n_dead; + prod = isl_calloc_type(tab1->mat->ctx, struct isl_tab); + if (!prod) + return NULL; + prod->mat = tab_mat_product(tab1->mat, tab2->mat, + tab1->n_row, tab2->n_row, + tab1->n_col, tab2->n_col, off, r1, r2, d1, d2); + if (!prod->mat) + goto error; + prod->var = isl_alloc_array(tab1->mat->ctx, struct isl_tab_var, + tab1->max_var + tab2->max_var); + if ((tab1->max_var + tab2->max_var) && !prod->var) + goto error; + for (i = 0; i < tab1->n_var; ++i) { + prod->var[i] = tab1->var[i]; + update_index1(&prod->var[i], r1, r2, d1, d2); + } + for (i = 0; i < tab2->n_var; ++i) { + prod->var[tab1->n_var + i] = tab2->var[i]; + update_index2(&prod->var[tab1->n_var + i], + tab1->n_row, tab1->n_col, + r1, r2, d1, d2); + } + prod->con = isl_alloc_array(tab1->mat->ctx, struct isl_tab_var, + tab1->max_con + tab2->max_con); + if ((tab1->max_con + tab2->max_con) && !prod->con) + goto error; + for (i = 0; i < tab1->n_con; ++i) { + prod->con[i] = tab1->con[i]; + update_index1(&prod->con[i], r1, r2, d1, d2); + } + for (i = 0; i < tab2->n_con; ++i) { + prod->con[tab1->n_con + i] = tab2->con[i]; + update_index2(&prod->con[tab1->n_con + i], + tab1->n_row, tab1->n_col, + r1, r2, d1, d2); + } + prod->col_var = isl_alloc_array(tab1->mat->ctx, int, + tab1->n_col + tab2->n_col); + if ((tab1->n_col + tab2->n_col) && !prod->col_var) + goto error; + for (i = 0; i < tab1->n_col; ++i) { + int pos = i < d1 ? i : i + d2; + prod->col_var[pos] = tab1->col_var[i]; + } + for (i = 0; i < tab2->n_col; ++i) { + int pos = i < d2 ? d1 + i : tab1->n_col + i; + int t = tab2->col_var[i]; + if (t >= 0) + t += tab1->n_var; + else + t -= tab1->n_con; + prod->col_var[pos] = t; + } + prod->row_var = isl_alloc_array(tab1->mat->ctx, int, + tab1->mat->n_row + tab2->mat->n_row); + if ((tab1->mat->n_row + tab2->mat->n_row) && !prod->row_var) + goto error; + for (i = 0; i < tab1->n_row; ++i) { + int pos = i < r1 ? i : i + r2; + prod->row_var[pos] = tab1->row_var[i]; + } + for (i = 0; i < tab2->n_row; ++i) { + int pos = i < r2 ? r1 + i : tab1->n_row + i; + int t = tab2->row_var[i]; + if (t >= 0) + t += tab1->n_var; + else + t -= tab1->n_con; + prod->row_var[pos] = t; + } + prod->samples = NULL; + prod->sample_index = NULL; + prod->n_row = tab1->n_row + tab2->n_row; + prod->n_con = tab1->n_con + tab2->n_con; + prod->n_eq = 0; + prod->max_con = tab1->max_con + tab2->max_con; + prod->n_col = tab1->n_col + tab2->n_col; + prod->n_var = tab1->n_var + tab2->n_var; + prod->max_var = tab1->max_var + tab2->max_var; + prod->n_param = 0; + prod->n_div = 0; + prod->n_dead = tab1->n_dead + tab2->n_dead; + prod->n_redundant = tab1->n_redundant + tab2->n_redundant; + prod->rational = tab1->rational; + prod->empty = tab1->empty || tab2->empty; + prod->strict_redundant = tab1->strict_redundant || tab2->strict_redundant; + prod->need_undo = 0; + prod->in_undo = 0; + prod->M = tab1->M; + prod->cone = tab1->cone; + prod->bottom.type = isl_tab_undo_bottom; + prod->bottom.next = NULL; + prod->top = &prod->bottom; + + prod->n_zero = 0; + prod->n_unbounded = 0; + prod->basis = NULL; + + return prod; +error: + isl_tab_free(prod); + return NULL; +} + +static struct isl_tab_var *var_from_index(struct isl_tab *tab, int i) +{ + if (i >= 0) + return &tab->var[i]; + else + return &tab->con[~i]; +} + +struct isl_tab_var *isl_tab_var_from_row(struct isl_tab *tab, int i) +{ + return var_from_index(tab, tab->row_var[i]); +} + +static struct isl_tab_var *var_from_col(struct isl_tab *tab, int i) +{ + return var_from_index(tab, tab->col_var[i]); +} + +/* Check if there are any upper bounds on column variable "var", + * i.e., non-negative rows where var appears with a negative coefficient. + * Return 1 if there are no such bounds. + */ +static int max_is_manifestly_unbounded(struct isl_tab *tab, + struct isl_tab_var *var) +{ + int i; + unsigned off = 2 + tab->M; + + if (var->is_row) + return 0; + for (i = tab->n_redundant; i < tab->n_row; ++i) { + if (!isl_int_is_neg(tab->mat->row[i][off + var->index])) + continue; + if (isl_tab_var_from_row(tab, i)->is_nonneg) + return 0; + } + return 1; +} + +/* Check if there are any lower bounds on column variable "var", + * i.e., non-negative rows where var appears with a positive coefficient. + * Return 1 if there are no such bounds. + */ +static int min_is_manifestly_unbounded(struct isl_tab *tab, + struct isl_tab_var *var) +{ + int i; + unsigned off = 2 + tab->M; + + if (var->is_row) + return 0; + for (i = tab->n_redundant; i < tab->n_row; ++i) { + if (!isl_int_is_pos(tab->mat->row[i][off + var->index])) + continue; + if (isl_tab_var_from_row(tab, i)->is_nonneg) + return 0; + } + return 1; +} + +static int row_cmp(struct isl_tab *tab, int r1, int r2, int c, isl_int *t) +{ + unsigned off = 2 + tab->M; + + if (tab->M) { + int s; + isl_int_mul(*t, tab->mat->row[r1][2], tab->mat->row[r2][off+c]); + isl_int_submul(*t, tab->mat->row[r2][2], tab->mat->row[r1][off+c]); + s = isl_int_sgn(*t); + if (s) + return s; + } + isl_int_mul(*t, tab->mat->row[r1][1], tab->mat->row[r2][off + c]); + isl_int_submul(*t, tab->mat->row[r2][1], tab->mat->row[r1][off + c]); + return isl_int_sgn(*t); +} + +/* Given the index of a column "c", return the index of a row + * that can be used to pivot the column in, with either an increase + * (sgn > 0) or a decrease (sgn < 0) of the corresponding variable. + * If "var" is not NULL, then the row returned will be different from + * the one associated with "var". + * + * Each row in the tableau is of the form + * + * x_r = a_r0 + \sum_i a_ri x_i + * + * Only rows with x_r >= 0 and with the sign of a_ri opposite to "sgn" + * impose any limit on the increase or decrease in the value of x_c + * and this bound is equal to a_r0 / |a_rc|. We are therefore looking + * for the row with the smallest (most stringent) such bound. + * Note that the common denominator of each row drops out of the fraction. + * To check if row j has a smaller bound than row r, i.e., + * a_j0 / |a_jc| < a_r0 / |a_rc| or a_j0 |a_rc| < a_r0 |a_jc|, + * we check if -sign(a_jc) (a_j0 a_rc - a_r0 a_jc) < 0, + * where -sign(a_jc) is equal to "sgn". + */ +static int pivot_row(struct isl_tab *tab, + struct isl_tab_var *var, int sgn, int c) +{ + int j, r, tsgn; + isl_int t; + unsigned off = 2 + tab->M; + + isl_int_init(t); + r = -1; + for (j = tab->n_redundant; j < tab->n_row; ++j) { + if (var && j == var->index) + continue; + if (!isl_tab_var_from_row(tab, j)->is_nonneg) + continue; + if (sgn * isl_int_sgn(tab->mat->row[j][off + c]) >= 0) + continue; + if (r < 0) { + r = j; + continue; + } + tsgn = sgn * row_cmp(tab, r, j, c, &t); + if (tsgn < 0 || (tsgn == 0 && + tab->row_var[j] < tab->row_var[r])) + r = j; + } + isl_int_clear(t); + return r; +} + +/* Find a pivot (row and col) that will increase (sgn > 0) or decrease + * (sgn < 0) the value of row variable var. + * If not NULL, then skip_var is a row variable that should be ignored + * while looking for a pivot row. It is usually equal to var. + * + * As the given row in the tableau is of the form + * + * x_r = a_r0 + \sum_i a_ri x_i + * + * we need to find a column such that the sign of a_ri is equal to "sgn" + * (such that an increase in x_i will have the desired effect) or a + * column with a variable that may attain negative values. + * If a_ri is positive, then we need to move x_i in the same direction + * to obtain the desired effect. Otherwise, x_i has to move in the + * opposite direction. + */ +static void find_pivot(struct isl_tab *tab, + struct isl_tab_var *var, struct isl_tab_var *skip_var, + int sgn, int *row, int *col) +{ + int j, r, c; + isl_int *tr; + + *row = *col = -1; + + isl_assert(tab->mat->ctx, var->is_row, return); + tr = tab->mat->row[var->index] + 2 + tab->M; + + c = -1; + for (j = tab->n_dead; j < tab->n_col; ++j) { + if (isl_int_is_zero(tr[j])) + continue; + if (isl_int_sgn(tr[j]) != sgn && + var_from_col(tab, j)->is_nonneg) + continue; + if (c < 0 || tab->col_var[j] < tab->col_var[c]) + c = j; + } + if (c < 0) + return; + + sgn *= isl_int_sgn(tr[c]); + r = pivot_row(tab, skip_var, sgn, c); + *row = r < 0 ? var->index : r; + *col = c; +} + +/* Return 1 if row "row" represents an obviously redundant inequality. + * This means + * - it represents an inequality or a variable + * - that is the sum of a non-negative sample value and a positive + * combination of zero or more non-negative constraints. + */ +int isl_tab_row_is_redundant(struct isl_tab *tab, int row) +{ + int i; + unsigned off = 2 + tab->M; + + if (tab->row_var[row] < 0 && !isl_tab_var_from_row(tab, row)->is_nonneg) + return 0; + + if (isl_int_is_neg(tab->mat->row[row][1])) + return 0; + if (tab->strict_redundant && isl_int_is_zero(tab->mat->row[row][1])) + return 0; + if (tab->M && isl_int_is_neg(tab->mat->row[row][2])) + return 0; + + for (i = tab->n_dead; i < tab->n_col; ++i) { + if (isl_int_is_zero(tab->mat->row[row][off + i])) + continue; + if (tab->col_var[i] >= 0) + return 0; + if (isl_int_is_neg(tab->mat->row[row][off + i])) + return 0; + if (!var_from_col(tab, i)->is_nonneg) + return 0; + } + return 1; +} + +static void swap_rows(struct isl_tab *tab, int row1, int row2) +{ + int t; + enum isl_tab_row_sign s; + + t = tab->row_var[row1]; + tab->row_var[row1] = tab->row_var[row2]; + tab->row_var[row2] = t; + isl_tab_var_from_row(tab, row1)->index = row1; + isl_tab_var_from_row(tab, row2)->index = row2; + tab->mat = isl_mat_swap_rows(tab->mat, row1, row2); + + if (!tab->row_sign) + return; + s = tab->row_sign[row1]; + tab->row_sign[row1] = tab->row_sign[row2]; + tab->row_sign[row2] = s; +} + +static int push_union(struct isl_tab *tab, + enum isl_tab_undo_type type, union isl_tab_undo_val u) WARN_UNUSED; +static int push_union(struct isl_tab *tab, + enum isl_tab_undo_type type, union isl_tab_undo_val u) +{ + struct isl_tab_undo *undo; + + if (!tab) + return -1; + if (!tab->need_undo) + return 0; + + undo = isl_alloc_type(tab->mat->ctx, struct isl_tab_undo); + if (!undo) + return -1; + undo->type = type; + undo->u = u; + undo->next = tab->top; + tab->top = undo; + + return 0; +} + +int isl_tab_push_var(struct isl_tab *tab, + enum isl_tab_undo_type type, struct isl_tab_var *var) +{ + union isl_tab_undo_val u; + if (var->is_row) + u.var_index = tab->row_var[var->index]; + else + u.var_index = tab->col_var[var->index]; + return push_union(tab, type, u); +} + +int isl_tab_push(struct isl_tab *tab, enum isl_tab_undo_type type) +{ + union isl_tab_undo_val u = { 0 }; + return push_union(tab, type, u); +} + +/* Push a record on the undo stack describing the current basic + * variables, so that the this state can be restored during rollback. + */ +int isl_tab_push_basis(struct isl_tab *tab) +{ + int i; + union isl_tab_undo_val u; + + u.col_var = isl_alloc_array(tab->mat->ctx, int, tab->n_col); + if (tab->n_col && !u.col_var) + return -1; + for (i = 0; i < tab->n_col; ++i) + u.col_var[i] = tab->col_var[i]; + return push_union(tab, isl_tab_undo_saved_basis, u); +} + +int isl_tab_push_callback(struct isl_tab *tab, struct isl_tab_callback *callback) +{ + union isl_tab_undo_val u; + u.callback = callback; + return push_union(tab, isl_tab_undo_callback, u); +} + +struct isl_tab *isl_tab_init_samples(struct isl_tab *tab) +{ + if (!tab) + return NULL; + + tab->n_sample = 0; + tab->n_outside = 0; + tab->samples = isl_mat_alloc(tab->mat->ctx, 1, 1 + tab->n_var); + if (!tab->samples) + goto error; + tab->sample_index = isl_alloc_array(tab->mat->ctx, int, 1); + if (!tab->sample_index) + goto error; + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +int isl_tab_add_sample(struct isl_tab *tab, __isl_take isl_vec *sample) +{ + if (!tab || !sample) + goto error; + + if (tab->n_sample + 1 > tab->samples->n_row) { + int *t = isl_realloc_array(tab->mat->ctx, + tab->sample_index, int, tab->n_sample + 1); + if (!t) + goto error; + tab->sample_index = t; + } + + tab->samples = isl_mat_extend(tab->samples, + tab->n_sample + 1, tab->samples->n_col); + if (!tab->samples) + goto error; + + isl_seq_cpy(tab->samples->row[tab->n_sample], sample->el, sample->size); + isl_vec_free(sample); + tab->sample_index[tab->n_sample] = tab->n_sample; + tab->n_sample++; + + return 0; +error: + isl_vec_free(sample); + return -1; +} + +struct isl_tab *isl_tab_drop_sample(struct isl_tab *tab, int s) +{ + if (s != tab->n_outside) { + int t = tab->sample_index[tab->n_outside]; + tab->sample_index[tab->n_outside] = tab->sample_index[s]; + tab->sample_index[s] = t; + isl_mat_swap_rows(tab->samples, tab->n_outside, s); + } + tab->n_outside++; + if (isl_tab_push(tab, isl_tab_undo_drop_sample) < 0) { + isl_tab_free(tab); + return NULL; + } + + return tab; +} + +/* Record the current number of samples so that we can remove newer + * samples during a rollback. + */ +int isl_tab_save_samples(struct isl_tab *tab) +{ + union isl_tab_undo_val u; + + if (!tab) + return -1; + + u.n = tab->n_sample; + return push_union(tab, isl_tab_undo_saved_samples, u); +} + +/* Mark row with index "row" as being redundant. + * If we may need to undo the operation or if the row represents + * a variable of the original problem, the row is kept, + * but no longer considered when looking for a pivot row. + * Otherwise, the row is simply removed. + * + * The row may be interchanged with some other row. If it + * is interchanged with a later row, return 1. Otherwise return 0. + * If the rows are checked in order in the calling function, + * then a return value of 1 means that the row with the given + * row number may now contain a different row that hasn't been checked yet. + */ +int isl_tab_mark_redundant(struct isl_tab *tab, int row) +{ + struct isl_tab_var *var = isl_tab_var_from_row(tab, row); + var->is_redundant = 1; + isl_assert(tab->mat->ctx, row >= tab->n_redundant, return -1); + if (tab->preserve || tab->need_undo || tab->row_var[row] >= 0) { + if (tab->row_var[row] >= 0 && !var->is_nonneg) { + var->is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, var) < 0) + return -1; + } + if (row != tab->n_redundant) + swap_rows(tab, row, tab->n_redundant); + tab->n_redundant++; + return isl_tab_push_var(tab, isl_tab_undo_redundant, var); + } else { + if (row != tab->n_row - 1) + swap_rows(tab, row, tab->n_row - 1); + isl_tab_var_from_row(tab, tab->n_row - 1)->index = -1; + tab->n_row--; + return 1; + } +} + +/* Mark "tab" as a rational tableau. + * If it wasn't marked as a rational tableau already and if we may + * need to undo changes, then arrange for the marking to be undone + * during the undo. + */ +int isl_tab_mark_rational(struct isl_tab *tab) +{ + if (!tab) + return -1; + if (!tab->rational && tab->need_undo) + if (isl_tab_push(tab, isl_tab_undo_rational) < 0) + return -1; + tab->rational = 1; + return 0; +} + +isl_stat isl_tab_mark_empty(struct isl_tab *tab) +{ + if (!tab) + return isl_stat_error; + if (!tab->empty && tab->need_undo) + if (isl_tab_push(tab, isl_tab_undo_empty) < 0) + return isl_stat_error; + tab->empty = 1; + return isl_stat_ok; +} + +int isl_tab_freeze_constraint(struct isl_tab *tab, int con) +{ + struct isl_tab_var *var; + + if (!tab) + return -1; + + var = &tab->con[con]; + if (var->frozen) + return 0; + if (var->index < 0) + return 0; + var->frozen = 1; + + if (tab->need_undo) + return isl_tab_push_var(tab, isl_tab_undo_freeze, var); + + return 0; +} + +/* Update the rows signs after a pivot of "row" and "col", with "row_sgn" + * the original sign of the pivot element. + * We only keep track of row signs during PILP solving and in this case + * we only pivot a row with negative sign (meaning the value is always + * non-positive) using a positive pivot element. + * + * For each row j, the new value of the parametric constant is equal to + * + * a_j0 - a_jc a_r0/a_rc + * + * where a_j0 is the original parametric constant, a_rc is the pivot element, + * a_r0 is the parametric constant of the pivot row and a_jc is the + * pivot column entry of the row j. + * Since a_r0 is non-positive and a_rc is positive, the sign of row j + * remains the same if a_jc has the same sign as the row j or if + * a_jc is zero. In all other cases, we reset the sign to "unknown". + */ +static void update_row_sign(struct isl_tab *tab, int row, int col, int row_sgn) +{ + int i; + struct isl_mat *mat = tab->mat; + unsigned off = 2 + tab->M; + + if (!tab->row_sign) + return; + + if (tab->row_sign[row] == 0) + return; + isl_assert(mat->ctx, row_sgn > 0, return); + isl_assert(mat->ctx, tab->row_sign[row] == isl_tab_row_neg, return); + tab->row_sign[row] = isl_tab_row_pos; + for (i = 0; i < tab->n_row; ++i) { + int s; + if (i == row) + continue; + s = isl_int_sgn(mat->row[i][off + col]); + if (!s) + continue; + if (!tab->row_sign[i]) + continue; + if (s < 0 && tab->row_sign[i] == isl_tab_row_neg) + continue; + if (s > 0 && tab->row_sign[i] == isl_tab_row_pos) + continue; + tab->row_sign[i] = isl_tab_row_unknown; + } +} + +/* Given a row number "row" and a column number "col", pivot the tableau + * such that the associated variables are interchanged. + * The given row in the tableau expresses + * + * x_r = a_r0 + \sum_i a_ri x_i + * + * or + * + * x_c = 1/a_rc x_r - a_r0/a_rc + sum_{i \ne r} -a_ri/a_rc + * + * Substituting this equality into the other rows + * + * x_j = a_j0 + \sum_i a_ji x_i + * + * with a_jc \ne 0, we obtain + * + * x_j = a_jc/a_rc x_r + a_j0 - a_jc a_r0/a_rc + sum a_ji - a_jc a_ri/a_rc + * + * The tableau + * + * n_rc/d_r n_ri/d_r + * n_jc/d_j n_ji/d_j + * + * where i is any other column and j is any other row, + * is therefore transformed into + * + * s(n_rc)d_r/|n_rc| -s(n_rc)n_ri/|n_rc| + * s(n_rc)d_r n_jc/(|n_rc| d_j) (n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j) + * + * The transformation is performed along the following steps + * + * d_r/n_rc n_ri/n_rc + * n_jc/d_j n_ji/d_j + * + * s(n_rc)d_r/|n_rc| -s(n_rc)n_ri/|n_rc| + * n_jc/d_j n_ji/d_j + * + * s(n_rc)d_r/|n_rc| -s(n_rc)n_ri/|n_rc| + * n_jc/(|n_rc| d_j) n_ji/(|n_rc| d_j) + * + * s(n_rc)d_r/|n_rc| -s(n_rc)n_ri/|n_rc| + * n_jc/(|n_rc| d_j) (n_ji |n_rc|)/(|n_rc| d_j) + * + * s(n_rc)d_r/|n_rc| -s(n_rc)n_ri/|n_rc| + * n_jc/(|n_rc| d_j) (n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j) + * + * s(n_rc)d_r/|n_rc| -s(n_rc)n_ri/|n_rc| + * s(n_rc)d_r n_jc/(|n_rc| d_j) (n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j) + * + */ +int isl_tab_pivot(struct isl_tab *tab, int row, int col) +{ + int i, j; + int sgn; + int t; + isl_ctx *ctx; + struct isl_mat *mat = tab->mat; + struct isl_tab_var *var; + unsigned off = 2 + tab->M; + + ctx = isl_tab_get_ctx(tab); + if (isl_ctx_next_operation(ctx) < 0) + return -1; + + isl_int_swap(mat->row[row][0], mat->row[row][off + col]); + sgn = isl_int_sgn(mat->row[row][0]); + if (sgn < 0) { + isl_int_neg(mat->row[row][0], mat->row[row][0]); + isl_int_neg(mat->row[row][off + col], mat->row[row][off + col]); + } else + for (j = 0; j < off - 1 + tab->n_col; ++j) { + if (j == off - 1 + col) + continue; + isl_int_neg(mat->row[row][1 + j], mat->row[row][1 + j]); + } + if (!isl_int_is_one(mat->row[row][0])) + isl_seq_normalize(mat->ctx, mat->row[row], off + tab->n_col); + for (i = 0; i < tab->n_row; ++i) { + if (i == row) + continue; + if (isl_int_is_zero(mat->row[i][off + col])) + continue; + isl_int_mul(mat->row[i][0], mat->row[i][0], mat->row[row][0]); + for (j = 0; j < off - 1 + tab->n_col; ++j) { + if (j == off - 1 + col) + continue; + isl_int_mul(mat->row[i][1 + j], + mat->row[i][1 + j], mat->row[row][0]); + isl_int_addmul(mat->row[i][1 + j], + mat->row[i][off + col], mat->row[row][1 + j]); + } + isl_int_mul(mat->row[i][off + col], + mat->row[i][off + col], mat->row[row][off + col]); + if (!isl_int_is_one(mat->row[i][0])) + isl_seq_normalize(mat->ctx, mat->row[i], off + tab->n_col); + } + t = tab->row_var[row]; + tab->row_var[row] = tab->col_var[col]; + tab->col_var[col] = t; + var = isl_tab_var_from_row(tab, row); + var->is_row = 1; + var->index = row; + var = var_from_col(tab, col); + var->is_row = 0; + var->index = col; + update_row_sign(tab, row, col, sgn); + if (tab->in_undo) + return 0; + for (i = tab->n_redundant; i < tab->n_row; ++i) { + if (isl_int_is_zero(mat->row[i][off + col])) + continue; + if (!isl_tab_var_from_row(tab, i)->frozen && + isl_tab_row_is_redundant(tab, i)) { + int redo = isl_tab_mark_redundant(tab, i); + if (redo < 0) + return -1; + if (redo) + --i; + } + } + return 0; +} + +/* If "var" represents a column variable, then pivot is up (sgn > 0) + * or down (sgn < 0) to a row. The variable is assumed not to be + * unbounded in the specified direction. + * If sgn = 0, then the variable is unbounded in both directions, + * and we pivot with any row we can find. + */ +static int to_row(struct isl_tab *tab, struct isl_tab_var *var, int sign) WARN_UNUSED; +static int to_row(struct isl_tab *tab, struct isl_tab_var *var, int sign) +{ + int r; + unsigned off = 2 + tab->M; + + if (var->is_row) + return 0; + + if (sign == 0) { + for (r = tab->n_redundant; r < tab->n_row; ++r) + if (!isl_int_is_zero(tab->mat->row[r][off+var->index])) + break; + isl_assert(tab->mat->ctx, r < tab->n_row, return -1); + } else { + r = pivot_row(tab, NULL, sign, var->index); + isl_assert(tab->mat->ctx, r >= 0, return -1); + } + + return isl_tab_pivot(tab, r, var->index); +} + +/* Check whether all variables that are marked as non-negative + * also have a non-negative sample value. This function is not + * called from the current code but is useful during debugging. + */ +static void check_table(struct isl_tab *tab) __attribute__ ((unused)); +static void check_table(struct isl_tab *tab) +{ + int i; + + if (tab->empty) + return; + for (i = tab->n_redundant; i < tab->n_row; ++i) { + struct isl_tab_var *var; + var = isl_tab_var_from_row(tab, i); + if (!var->is_nonneg) + continue; + if (tab->M) { + isl_assert(tab->mat->ctx, + !isl_int_is_neg(tab->mat->row[i][2]), abort()); + if (isl_int_is_pos(tab->mat->row[i][2])) + continue; + } + isl_assert(tab->mat->ctx, !isl_int_is_neg(tab->mat->row[i][1]), + abort()); + } +} + +/* Return the sign of the maximal value of "var". + * If the sign is not negative, then on return from this function, + * the sample value will also be non-negative. + * + * If "var" is manifestly unbounded wrt positive values, we are done. + * Otherwise, we pivot the variable up to a row if needed + * Then we continue pivoting down until either + * - no more down pivots can be performed + * - the sample value is positive + * - the variable is pivoted into a manifestly unbounded column + */ +static int sign_of_max(struct isl_tab *tab, struct isl_tab_var *var) +{ + int row, col; + + if (max_is_manifestly_unbounded(tab, var)) + return 1; + if (to_row(tab, var, 1) < 0) + return -2; + while (!isl_int_is_pos(tab->mat->row[var->index][1])) { + find_pivot(tab, var, var, 1, &row, &col); + if (row == -1) + return isl_int_sgn(tab->mat->row[var->index][1]); + if (isl_tab_pivot(tab, row, col) < 0) + return -2; + if (!var->is_row) /* manifestly unbounded */ + return 1; + } + return 1; +} + +int isl_tab_sign_of_max(struct isl_tab *tab, int con) +{ + struct isl_tab_var *var; + + if (!tab) + return -2; + + var = &tab->con[con]; + isl_assert(tab->mat->ctx, !var->is_redundant, return -2); + isl_assert(tab->mat->ctx, !var->is_zero, return -2); + + return sign_of_max(tab, var); +} + +static int row_is_neg(struct isl_tab *tab, int row) +{ + if (!tab->M) + return isl_int_is_neg(tab->mat->row[row][1]); + if (isl_int_is_pos(tab->mat->row[row][2])) + return 0; + if (isl_int_is_neg(tab->mat->row[row][2])) + return 1; + return isl_int_is_neg(tab->mat->row[row][1]); +} + +static int row_sgn(struct isl_tab *tab, int row) +{ + if (!tab->M) + return isl_int_sgn(tab->mat->row[row][1]); + if (!isl_int_is_zero(tab->mat->row[row][2])) + return isl_int_sgn(tab->mat->row[row][2]); + else + return isl_int_sgn(tab->mat->row[row][1]); +} + +/* Perform pivots until the row variable "var" has a non-negative + * sample value or until no more upward pivots can be performed. + * Return the sign of the sample value after the pivots have been + * performed. + */ +static int restore_row(struct isl_tab *tab, struct isl_tab_var *var) +{ + int row, col; + + while (row_is_neg(tab, var->index)) { + find_pivot(tab, var, var, 1, &row, &col); + if (row == -1) + break; + if (isl_tab_pivot(tab, row, col) < 0) + return -2; + if (!var->is_row) /* manifestly unbounded */ + return 1; + } + return row_sgn(tab, var->index); +} + +/* Perform pivots until we are sure that the row variable "var" + * can attain non-negative values. After return from this + * function, "var" is still a row variable, but its sample + * value may not be non-negative, even if the function returns 1. + */ +static int at_least_zero(struct isl_tab *tab, struct isl_tab_var *var) +{ + int row, col; + + while (isl_int_is_neg(tab->mat->row[var->index][1])) { + find_pivot(tab, var, var, 1, &row, &col); + if (row == -1) + break; + if (row == var->index) /* manifestly unbounded */ + return 1; + if (isl_tab_pivot(tab, row, col) < 0) + return -1; + } + return !isl_int_is_neg(tab->mat->row[var->index][1]); +} + +/* Return a negative value if "var" can attain negative values. + * Return a non-negative value otherwise. + * + * If "var" is manifestly unbounded wrt negative values, we are done. + * Otherwise, if var is in a column, we can pivot it down to a row. + * Then we continue pivoting down until either + * - the pivot would result in a manifestly unbounded column + * => we don't perform the pivot, but simply return -1 + * - no more down pivots can be performed + * - the sample value is negative + * If the sample value becomes negative and the variable is supposed + * to be nonnegative, then we undo the last pivot. + * However, if the last pivot has made the pivoting variable + * obviously redundant, then it may have moved to another row. + * In that case we look for upward pivots until we reach a non-negative + * value again. + */ +static int sign_of_min(struct isl_tab *tab, struct isl_tab_var *var) +{ + int row, col; + struct isl_tab_var *pivot_var = NULL; + + if (min_is_manifestly_unbounded(tab, var)) + return -1; + if (!var->is_row) { + col = var->index; + row = pivot_row(tab, NULL, -1, col); + pivot_var = var_from_col(tab, col); + if (isl_tab_pivot(tab, row, col) < 0) + return -2; + if (var->is_redundant) + return 0; + if (isl_int_is_neg(tab->mat->row[var->index][1])) { + if (var->is_nonneg) { + if (!pivot_var->is_redundant && + pivot_var->index == row) { + if (isl_tab_pivot(tab, row, col) < 0) + return -2; + } else + if (restore_row(tab, var) < -1) + return -2; + } + return -1; + } + } + if (var->is_redundant) + return 0; + while (!isl_int_is_neg(tab->mat->row[var->index][1])) { + find_pivot(tab, var, var, -1, &row, &col); + if (row == var->index) + return -1; + if (row == -1) + return isl_int_sgn(tab->mat->row[var->index][1]); + pivot_var = var_from_col(tab, col); + if (isl_tab_pivot(tab, row, col) < 0) + return -2; + if (var->is_redundant) + return 0; + } + if (pivot_var && var->is_nonneg) { + /* pivot back to non-negative value */ + if (!pivot_var->is_redundant && pivot_var->index == row) { + if (isl_tab_pivot(tab, row, col) < 0) + return -2; + } else + if (restore_row(tab, var) < -1) + return -2; + } + return -1; +} + +static int row_at_most_neg_one(struct isl_tab *tab, int row) +{ + if (tab->M) { + if (isl_int_is_pos(tab->mat->row[row][2])) + return 0; + if (isl_int_is_neg(tab->mat->row[row][2])) + return 1; + } + return isl_int_is_neg(tab->mat->row[row][1]) && + isl_int_abs_ge(tab->mat->row[row][1], + tab->mat->row[row][0]); +} + +/* Return 1 if "var" can attain values <= -1. + * Return 0 otherwise. + * + * If the variable "var" is supposed to be non-negative (is_nonneg is set), + * then the sample value of "var" is assumed to be non-negative when the + * the function is called. If 1 is returned then the constraint + * is not redundant and the sample value is made non-negative again before + * the function returns. + */ +int isl_tab_min_at_most_neg_one(struct isl_tab *tab, struct isl_tab_var *var) +{ + int row, col; + struct isl_tab_var *pivot_var; + + if (min_is_manifestly_unbounded(tab, var)) + return 1; + if (!var->is_row) { + col = var->index; + row = pivot_row(tab, NULL, -1, col); + pivot_var = var_from_col(tab, col); + if (isl_tab_pivot(tab, row, col) < 0) + return -1; + if (var->is_redundant) + return 0; + if (row_at_most_neg_one(tab, var->index)) { + if (var->is_nonneg) { + if (!pivot_var->is_redundant && + pivot_var->index == row) { + if (isl_tab_pivot(tab, row, col) < 0) + return -1; + } else + if (restore_row(tab, var) < -1) + return -1; + } + return 1; + } + } + if (var->is_redundant) + return 0; + do { + find_pivot(tab, var, var, -1, &row, &col); + if (row == var->index) { + if (var->is_nonneg && restore_row(tab, var) < -1) + return -1; + return 1; + } + if (row == -1) + return 0; + pivot_var = var_from_col(tab, col); + if (isl_tab_pivot(tab, row, col) < 0) + return -1; + if (var->is_redundant) + return 0; + } while (!row_at_most_neg_one(tab, var->index)); + if (var->is_nonneg) { + /* pivot back to non-negative value */ + if (!pivot_var->is_redundant && pivot_var->index == row) + if (isl_tab_pivot(tab, row, col) < 0) + return -1; + if (restore_row(tab, var) < -1) + return -1; + } + return 1; +} + +/* Return 1 if "var" can attain values >= 1. + * Return 0 otherwise. + */ +static int at_least_one(struct isl_tab *tab, struct isl_tab_var *var) +{ + int row, col; + isl_int *r; + + if (max_is_manifestly_unbounded(tab, var)) + return 1; + if (to_row(tab, var, 1) < 0) + return -1; + r = tab->mat->row[var->index]; + while (isl_int_lt(r[1], r[0])) { + find_pivot(tab, var, var, 1, &row, &col); + if (row == -1) + return isl_int_ge(r[1], r[0]); + if (row == var->index) /* manifestly unbounded */ + return 1; + if (isl_tab_pivot(tab, row, col) < 0) + return -1; + } + return 1; +} + +static void swap_cols(struct isl_tab *tab, int col1, int col2) +{ + int t; + unsigned off = 2 + tab->M; + t = tab->col_var[col1]; + tab->col_var[col1] = tab->col_var[col2]; + tab->col_var[col2] = t; + var_from_col(tab, col1)->index = col1; + var_from_col(tab, col2)->index = col2; + tab->mat = isl_mat_swap_cols(tab->mat, off + col1, off + col2); +} + +/* Mark column with index "col" as representing a zero variable. + * If we may need to undo the operation the column is kept, + * but no longer considered. + * Otherwise, the column is simply removed. + * + * The column may be interchanged with some other column. If it + * is interchanged with a later column, return 1. Otherwise return 0. + * If the columns are checked in order in the calling function, + * then a return value of 1 means that the column with the given + * column number may now contain a different column that + * hasn't been checked yet. + */ +int isl_tab_kill_col(struct isl_tab *tab, int col) +{ + var_from_col(tab, col)->is_zero = 1; + if (tab->need_undo) { + if (isl_tab_push_var(tab, isl_tab_undo_zero, + var_from_col(tab, col)) < 0) + return -1; + if (col != tab->n_dead) + swap_cols(tab, col, tab->n_dead); + tab->n_dead++; + return 0; + } else { + if (col != tab->n_col - 1) + swap_cols(tab, col, tab->n_col - 1); + var_from_col(tab, tab->n_col - 1)->index = -1; + tab->n_col--; + return 1; + } +} + +static int row_is_manifestly_non_integral(struct isl_tab *tab, int row) +{ + unsigned off = 2 + tab->M; + + if (tab->M && !isl_int_eq(tab->mat->row[row][2], + tab->mat->row[row][0])) + return 0; + if (isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead, + tab->n_col - tab->n_dead) != -1) + return 0; + + return !isl_int_is_divisible_by(tab->mat->row[row][1], + tab->mat->row[row][0]); +} + +/* For integer tableaus, check if any of the coordinates are stuck + * at a non-integral value. + */ +static int tab_is_manifestly_empty(struct isl_tab *tab) +{ + int i; + + if (tab->empty) + return 1; + if (tab->rational) + return 0; + + for (i = 0; i < tab->n_var; ++i) { + if (!tab->var[i].is_row) + continue; + if (row_is_manifestly_non_integral(tab, tab->var[i].index)) + return 1; + } + + return 0; +} + +/* Row variable "var" is non-negative and cannot attain any values + * larger than zero. This means that the coefficients of the unrestricted + * column variables are zero and that the coefficients of the non-negative + * column variables are zero or negative. + * Each of the non-negative variables with a negative coefficient can + * then also be written as the negative sum of non-negative variables + * and must therefore also be zero. + * + * If "temp_var" is set, then "var" is a temporary variable that + * will be removed after this function returns and for which + * no information is recorded on the undo stack. + * Do not add any undo records involving this variable in this case + * since the variable will have been removed before any future undo + * operations. Also avoid marking the variable as redundant, + * since that either adds an undo record or needlessly removes the row + * (the caller will take care of removing the row). + */ +static isl_stat close_row(struct isl_tab *tab, struct isl_tab_var *var, + int temp_var) WARN_UNUSED; +static isl_stat close_row(struct isl_tab *tab, struct isl_tab_var *var, + int temp_var) +{ + int j; + struct isl_mat *mat = tab->mat; + unsigned off = 2 + tab->M; + + if (!var->is_nonneg) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "expecting non-negative variable", + return isl_stat_error); + var->is_zero = 1; + if (!temp_var && tab->need_undo) + if (isl_tab_push_var(tab, isl_tab_undo_zero, var) < 0) + return isl_stat_error; + for (j = tab->n_dead; j < tab->n_col; ++j) { + int recheck; + if (isl_int_is_zero(mat->row[var->index][off + j])) + continue; + if (isl_int_is_pos(mat->row[var->index][off + j])) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "row cannot have positive coefficients", + return isl_stat_error); + recheck = isl_tab_kill_col(tab, j); + if (recheck < 0) + return isl_stat_error; + if (recheck) + --j; + } + if (!temp_var && isl_tab_mark_redundant(tab, var->index) < 0) + return isl_stat_error; + if (tab_is_manifestly_empty(tab) && isl_tab_mark_empty(tab) < 0) + return isl_stat_error; + return isl_stat_ok; +} + +/* Add a constraint to the tableau and allocate a row for it. + * Return the index into the constraint array "con". + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +int isl_tab_allocate_con(struct isl_tab *tab) +{ + int r; + + isl_assert(tab->mat->ctx, tab->n_row < tab->mat->n_row, return -1); + isl_assert(tab->mat->ctx, tab->n_con < tab->max_con, return -1); + + r = tab->n_con; + tab->con[r].index = tab->n_row; + tab->con[r].is_row = 1; + tab->con[r].is_nonneg = 0; + tab->con[r].is_zero = 0; + tab->con[r].is_redundant = 0; + tab->con[r].frozen = 0; + tab->con[r].negated = 0; + tab->row_var[tab->n_row] = ~r; + + tab->n_row++; + tab->n_con++; + if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->con[r]) < 0) + return -1; + + return r; +} + +/* Move the entries in tab->var up one position, starting at "first", + * creating room for an extra entry at position "first". + * Since some of the entries of tab->row_var and tab->col_var contain + * indices into this array, they have to be updated accordingly. + */ +static int var_insert_entry(struct isl_tab *tab, int first) +{ + int i; + + if (tab->n_var >= tab->max_var) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "not enough room for new variable", return -1); + if (first > tab->n_var) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "invalid initial position", return -1); + + for (i = tab->n_var - 1; i >= first; --i) { + tab->var[i + 1] = tab->var[i]; + if (tab->var[i + 1].is_row) + tab->row_var[tab->var[i + 1].index]++; + else + tab->col_var[tab->var[i + 1].index]++; + } + + tab->n_var++; + + return 0; +} + +/* Drop the entry at position "first" in tab->var, moving all + * subsequent entries down. + * Since some of the entries of tab->row_var and tab->col_var contain + * indices into this array, they have to be updated accordingly. + */ +static int var_drop_entry(struct isl_tab *tab, int first) +{ + int i; + + if (first >= tab->n_var) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "invalid initial position", return -1); + + tab->n_var--; + + for (i = first; i < tab->n_var; ++i) { + tab->var[i] = tab->var[i + 1]; + if (tab->var[i + 1].is_row) + tab->row_var[tab->var[i].index]--; + else + tab->col_var[tab->var[i].index]--; + } + + return 0; +} + +/* Add a variable to the tableau at position "r" and allocate a column for it. + * Return the index into the variable array "var", i.e., "r", + * or -1 on error. + */ +int isl_tab_insert_var(struct isl_tab *tab, int r) +{ + int i; + unsigned off = 2 + tab->M; + + isl_assert(tab->mat->ctx, tab->n_col < tab->mat->n_col, return -1); + + if (var_insert_entry(tab, r) < 0) + return -1; + + tab->var[r].index = tab->n_col; + tab->var[r].is_row = 0; + tab->var[r].is_nonneg = 0; + tab->var[r].is_zero = 0; + tab->var[r].is_redundant = 0; + tab->var[r].frozen = 0; + tab->var[r].negated = 0; + tab->col_var[tab->n_col] = r; + + for (i = 0; i < tab->n_row; ++i) + isl_int_set_si(tab->mat->row[i][off + tab->n_col], 0); + + tab->n_col++; + if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->var[r]) < 0) + return -1; + + return r; +} + +/* Add a variable to the tableau and allocate a column for it. + * Return the index into the variable array "var". + */ +int isl_tab_allocate_var(struct isl_tab *tab) +{ + if (!tab) + return -1; + + return isl_tab_insert_var(tab, tab->n_var); +} + +/* Add a row to the tableau. The row is given as an affine combination + * of the original variables and needs to be expressed in terms of the + * column variables. + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + * + * We add each term in turn. + * If r = n/d_r is the current sum and we need to add k x, then + * if x is a column variable, we increase the numerator of + * this column by k d_r + * if x = f/d_x is a row variable, then the new representation of r is + * + * n k f d_x/g n + d_r/g k f m/d_r n + m/d_g k f + * --- + --- = ------------------- = ------------------- + * d_r d_r d_r d_x/g m + * + * with g the gcd of d_r and d_x and m the lcm of d_r and d_x. + * + * If tab->M is set, then, internally, each variable x is represented + * as x' - M. We then also need no subtract k d_r from the coefficient of M. + */ +int isl_tab_add_row(struct isl_tab *tab, isl_int *line) +{ + int i; + int r; + isl_int *row; + isl_int a, b; + unsigned off = 2 + tab->M; + + r = isl_tab_allocate_con(tab); + if (r < 0) + return -1; + + isl_int_init(a); + isl_int_init(b); + row = tab->mat->row[tab->con[r].index]; + isl_int_set_si(row[0], 1); + isl_int_set(row[1], line[0]); + isl_seq_clr(row + 2, tab->M + tab->n_col); + for (i = 0; i < tab->n_var; ++i) { + if (tab->var[i].is_zero) + continue; + if (tab->var[i].is_row) { + isl_int_lcm(a, + row[0], tab->mat->row[tab->var[i].index][0]); + isl_int_swap(a, row[0]); + isl_int_divexact(a, row[0], a); + isl_int_divexact(b, + row[0], tab->mat->row[tab->var[i].index][0]); + isl_int_mul(b, b, line[1 + i]); + isl_seq_combine(row + 1, a, row + 1, + b, tab->mat->row[tab->var[i].index] + 1, + 1 + tab->M + tab->n_col); + } else + isl_int_addmul(row[off + tab->var[i].index], + line[1 + i], row[0]); + if (tab->M && i >= tab->n_param && i < tab->n_var - tab->n_div) + isl_int_submul(row[2], line[1 + i], row[0]); + } + isl_seq_normalize(tab->mat->ctx, row, off + tab->n_col); + isl_int_clear(a); + isl_int_clear(b); + + if (tab->row_sign) + tab->row_sign[tab->con[r].index] = isl_tab_row_unknown; + + return r; +} + +static isl_stat drop_row(struct isl_tab *tab, int row) +{ + isl_assert(tab->mat->ctx, ~tab->row_var[row] == tab->n_con - 1, + return isl_stat_error); + if (row != tab->n_row - 1) + swap_rows(tab, row, tab->n_row - 1); + tab->n_row--; + tab->n_con--; + return isl_stat_ok; +} + +/* Drop the variable in column "col" along with the column. + * The column is removed first because it may need to be moved + * into the last position and this process requires + * the contents of the col_var array in a state + * before the removal of the variable. + */ +static isl_stat drop_col(struct isl_tab *tab, int col) +{ + int var; + + var = tab->col_var[col]; + if (col != tab->n_col - 1) + swap_cols(tab, col, tab->n_col - 1); + tab->n_col--; + if (var_drop_entry(tab, var) < 0) + return isl_stat_error; + return isl_stat_ok; +} + +/* Add inequality "ineq" and check if it conflicts with the + * previously added constraints or if it is obviously redundant. + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +isl_stat isl_tab_add_ineq(struct isl_tab *tab, isl_int *ineq) +{ + int r; + int sgn; + isl_int cst; + + if (!tab) + return isl_stat_error; + if (tab->bmap) { + struct isl_basic_map *bmap = tab->bmap; + + isl_assert(tab->mat->ctx, tab->n_eq == bmap->n_eq, + return isl_stat_error); + isl_assert(tab->mat->ctx, + tab->n_con == bmap->n_eq + bmap->n_ineq, + return isl_stat_error); + tab->bmap = isl_basic_map_add_ineq(tab->bmap, ineq); + if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0) + return isl_stat_error; + if (!tab->bmap) + return isl_stat_error; + } + if (tab->cone) { + isl_int_init(cst); + isl_int_set_si(cst, 0); + isl_int_swap(ineq[0], cst); + } + r = isl_tab_add_row(tab, ineq); + if (tab->cone) { + isl_int_swap(ineq[0], cst); + isl_int_clear(cst); + } + if (r < 0) + return isl_stat_error; + tab->con[r].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0) + return isl_stat_error; + if (isl_tab_row_is_redundant(tab, tab->con[r].index)) { + if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0) + return isl_stat_error; + return isl_stat_ok; + } + + sgn = restore_row(tab, &tab->con[r]); + if (sgn < -1) + return isl_stat_error; + if (sgn < 0) + return isl_tab_mark_empty(tab); + if (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) + return isl_stat_error; + return isl_stat_ok; +} + +/* Pivot a non-negative variable down until it reaches the value zero + * and then pivot the variable into a column position. + */ +static int to_col(struct isl_tab *tab, struct isl_tab_var *var) WARN_UNUSED; +static int to_col(struct isl_tab *tab, struct isl_tab_var *var) +{ + int i; + int row, col; + unsigned off = 2 + tab->M; + + if (!var->is_row) + return 0; + + while (isl_int_is_pos(tab->mat->row[var->index][1])) { + find_pivot(tab, var, NULL, -1, &row, &col); + isl_assert(tab->mat->ctx, row != -1, return -1); + if (isl_tab_pivot(tab, row, col) < 0) + return -1; + if (!var->is_row) + return 0; + } + + for (i = tab->n_dead; i < tab->n_col; ++i) + if (!isl_int_is_zero(tab->mat->row[var->index][off + i])) + break; + + isl_assert(tab->mat->ctx, i < tab->n_col, return -1); + if (isl_tab_pivot(tab, var->index, i) < 0) + return -1; + + return 0; +} + +/* We assume Gaussian elimination has been performed on the equalities. + * The equalities can therefore never conflict. + * Adding the equalities is currently only really useful for a later call + * to isl_tab_ineq_type. + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +static struct isl_tab *add_eq(struct isl_tab *tab, isl_int *eq) +{ + int i; + int r; + + if (!tab) + return NULL; + r = isl_tab_add_row(tab, eq); + if (r < 0) + goto error; + + r = tab->con[r].index; + i = isl_seq_first_non_zero(tab->mat->row[r] + 2 + tab->M + tab->n_dead, + tab->n_col - tab->n_dead); + isl_assert(tab->mat->ctx, i >= 0, goto error); + i += tab->n_dead; + if (isl_tab_pivot(tab, r, i) < 0) + goto error; + if (isl_tab_kill_col(tab, i) < 0) + goto error; + tab->n_eq++; + + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Does the sample value of row "row" of "tab" involve the big parameter, + * if any? + */ +static int row_is_big(struct isl_tab *tab, int row) +{ + return tab->M && !isl_int_is_zero(tab->mat->row[row][2]); +} + +static int row_is_manifestly_zero(struct isl_tab *tab, int row) +{ + unsigned off = 2 + tab->M; + + if (!isl_int_is_zero(tab->mat->row[row][1])) + return 0; + if (row_is_big(tab, row)) + return 0; + return isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead, + tab->n_col - tab->n_dead) == -1; +} + +/* Add an equality that is known to be valid for the given tableau. + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +int isl_tab_add_valid_eq(struct isl_tab *tab, isl_int *eq) +{ + struct isl_tab_var *var; + int r; + + if (!tab) + return -1; + r = isl_tab_add_row(tab, eq); + if (r < 0) + return -1; + + var = &tab->con[r]; + r = var->index; + if (row_is_manifestly_zero(tab, r)) { + var->is_zero = 1; + if (isl_tab_mark_redundant(tab, r) < 0) + return -1; + return 0; + } + + if (isl_int_is_neg(tab->mat->row[r][1])) { + isl_seq_neg(tab->mat->row[r] + 1, tab->mat->row[r] + 1, + 1 + tab->n_col); + var->negated = 1; + } + var->is_nonneg = 1; + if (to_col(tab, var) < 0) + return -1; + var->is_nonneg = 0; + if (isl_tab_kill_col(tab, var->index) < 0) + return -1; + + return 0; +} + +/* Add a zero row to "tab" and return the corresponding index + * in the constraint array. + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +static int add_zero_row(struct isl_tab *tab) +{ + int r; + isl_int *row; + + r = isl_tab_allocate_con(tab); + if (r < 0) + return -1; + + row = tab->mat->row[tab->con[r].index]; + isl_seq_clr(row + 1, 1 + tab->M + tab->n_col); + isl_int_set_si(row[0], 1); + + return r; +} + +/* Add equality "eq" and check if it conflicts with the + * previously added constraints or if it is obviously redundant. + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + * If tab->bmap is set, then two rows are needed instead of one. + */ +int isl_tab_add_eq(struct isl_tab *tab, isl_int *eq) +{ + struct isl_tab_undo *snap = NULL; + struct isl_tab_var *var; + int r; + int row; + int sgn; + isl_int cst; + + if (!tab) + return -1; + isl_assert(tab->mat->ctx, !tab->M, return -1); + + if (tab->need_undo) + snap = isl_tab_snap(tab); + + if (tab->cone) { + isl_int_init(cst); + isl_int_set_si(cst, 0); + isl_int_swap(eq[0], cst); + } + r = isl_tab_add_row(tab, eq); + if (tab->cone) { + isl_int_swap(eq[0], cst); + isl_int_clear(cst); + } + if (r < 0) + return -1; + + var = &tab->con[r]; + row = var->index; + if (row_is_manifestly_zero(tab, row)) { + if (snap) + return isl_tab_rollback(tab, snap); + return drop_row(tab, row); + } + + if (tab->bmap) { + tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq); + if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0) + 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) + return -1; + if (!tab->bmap) + return -1; + if (add_zero_row(tab) < 0) + return -1; + } + + sgn = isl_int_sgn(tab->mat->row[row][1]); + + if (sgn > 0) { + isl_seq_neg(tab->mat->row[row] + 1, tab->mat->row[row] + 1, + 1 + tab->n_col); + var->negated = 1; + sgn = -1; + } + + if (sgn < 0) { + sgn = sign_of_max(tab, var); + if (sgn < -1) + return -1; + if (sgn < 0) { + if (isl_tab_mark_empty(tab) < 0) + return -1; + return 0; + } + } + + var->is_nonneg = 1; + if (to_col(tab, var) < 0) + return -1; + var->is_nonneg = 0; + if (isl_tab_kill_col(tab, var->index) < 0) + return -1; + + return 0; +} + +/* Construct and return an inequality that expresses an upper bound + * on the given div. + * In particular, if the div is given by + * + * d = floor(e/m) + * + * then the inequality expresses + * + * m d <= e + */ +static struct isl_vec *ineq_for_div(struct isl_basic_map *bmap, unsigned div) +{ + unsigned total; + unsigned div_pos; + struct isl_vec *ineq; + + if (!bmap) + return NULL; + + total = isl_basic_map_total_dim(bmap); + div_pos = 1 + total - bmap->n_div + div; + + ineq = isl_vec_alloc(bmap->ctx, 1 + total); + if (!ineq) + return NULL; + + isl_seq_cpy(ineq->el, bmap->div[div] + 1, 1 + total); + isl_int_neg(ineq->el[div_pos], bmap->div[div][0]); + return ineq; +} + +/* For a div d = floor(f/m), add the constraints + * + * f - m d >= 0 + * -(f-(m-1)) + m d >= 0 + * + * Note that the second constraint is the negation of + * + * f - m d >= m + * + * If add_ineq is not NULL, then this function is used + * instead of isl_tab_add_ineq to effectively add the inequalities. + * + * This function assumes that at least two more rows and at least + * two more elements in the constraint array are available in the tableau. + */ +static isl_stat add_div_constraints(struct isl_tab *tab, unsigned div, + isl_stat (*add_ineq)(void *user, isl_int *), void *user) +{ + unsigned total; + unsigned div_pos; + struct isl_vec *ineq; + + total = isl_basic_map_total_dim(tab->bmap); + div_pos = 1 + total - tab->bmap->n_div + div; + + ineq = ineq_for_div(tab->bmap, div); + if (!ineq) + goto error; + + if (add_ineq) { + if (add_ineq(user, ineq->el) < 0) + goto error; + } else { + if (isl_tab_add_ineq(tab, ineq->el) < 0) + goto error; + } + + isl_seq_neg(ineq->el, tab->bmap->div[div] + 1, 1 + total); + isl_int_set(ineq->el[div_pos], tab->bmap->div[div][0]); + isl_int_add(ineq->el[0], ineq->el[0], ineq->el[div_pos]); + isl_int_sub_ui(ineq->el[0], ineq->el[0], 1); + + if (add_ineq) { + if (add_ineq(user, ineq->el) < 0) + goto error; + } else { + if (isl_tab_add_ineq(tab, ineq->el) < 0) + goto error; + } + + isl_vec_free(ineq); + + return 0; +error: + isl_vec_free(ineq); + return -1; +} + +/* Check whether the div described by "div" is obviously non-negative. + * If we are using a big parameter, then we will encode the div + * as div' = M + div, which is always non-negative. + * Otherwise, we check whether div is a non-negative affine combination + * of non-negative variables. + */ +static int div_is_nonneg(struct isl_tab *tab, __isl_keep isl_vec *div) +{ + int i; + + if (tab->M) + return 1; + + if (isl_int_is_neg(div->el[1])) + return 0; + + for (i = 0; i < tab->n_var; ++i) { + if (isl_int_is_neg(div->el[2 + i])) + return 0; + if (isl_int_is_zero(div->el[2 + i])) + continue; + if (!tab->var[i].is_nonneg) + return 0; + } + + return 1; +} + +/* Insert an extra div, prescribed by "div", to the tableau and + * the associated bmap (which is assumed to be non-NULL). + * The extra integer division is inserted at (tableau) position "pos". + * Return "pos" or -1 if an error occurred. + * + * If add_ineq is not NULL, then this function is used instead + * of isl_tab_add_ineq to add the div constraints. + * This complication is needed because the code in isl_tab_pip + * wants to perform some extra processing when an inequality + * is added to the tableau. + */ +int isl_tab_insert_div(struct isl_tab *tab, int pos, __isl_keep isl_vec *div, + isl_stat (*add_ineq)(void *user, isl_int *), void *user) +{ + int r; + int nonneg; + int n_div, o_div; + + if (!tab || !div) + return -1; + + if (div->size != 1 + 1 + tab->n_var) + isl_die(isl_tab_get_ctx(tab), isl_error_invalid, + "unexpected size", return -1); + + isl_assert(tab->mat->ctx, tab->bmap, return -1); + n_div = isl_basic_map_dim(tab->bmap, isl_dim_div); + o_div = tab->n_var - n_div; + if (pos < o_div || pos > tab->n_var) + isl_die(isl_tab_get_ctx(tab), isl_error_invalid, + "invalid position", return -1); + + nonneg = div_is_nonneg(tab, div); + + if (isl_tab_extend_cons(tab, 3) < 0) + return -1; + if (isl_tab_extend_vars(tab, 1) < 0) + return -1; + r = isl_tab_insert_var(tab, pos); + if (r < 0) + return -1; + + if (nonneg) + tab->var[r].is_nonneg = 1; + + tab->bmap = isl_basic_map_insert_div(tab->bmap, pos - o_div, div); + if (!tab->bmap) + return -1; + if (isl_tab_push_var(tab, isl_tab_undo_bmap_div, &tab->var[r]) < 0) + return -1; + + if (add_div_constraints(tab, pos - o_div, add_ineq, user) < 0) + return -1; + + return r; +} + +/* Add an extra div, prescribed by "div", to the tableau and + * the associated bmap (which is assumed to be non-NULL). + */ +int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div) +{ + if (!tab) + return -1; + return isl_tab_insert_div(tab, tab->n_var, div, NULL, NULL); +} + +/* If "track" is set, then we want to keep track of all constraints in tab + * in its bmap field. This field is initialized from a copy of "bmap", + * so we need to make sure that all constraints in "bmap" also appear + * in the constructed tab. + */ +__isl_give struct isl_tab *isl_tab_from_basic_map( + __isl_keep isl_basic_map *bmap, int track) +{ + int i; + struct isl_tab *tab; + + if (!bmap) + return NULL; + tab = isl_tab_alloc(bmap->ctx, + isl_basic_map_total_dim(bmap) + bmap->n_ineq + 1, + isl_basic_map_total_dim(bmap), 0); + if (!tab) + return NULL; + tab->preserve = track; + tab->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) { + if (isl_tab_mark_empty(tab) < 0) + goto error; + goto done; + } + for (i = 0; i < bmap->n_eq; ++i) { + tab = add_eq(tab, bmap->eq[i]); + if (!tab) + return tab; + } + for (i = 0; i < bmap->n_ineq; ++i) { + if (isl_tab_add_ineq(tab, bmap->ineq[i]) < 0) + goto error; + if (tab->empty) + goto done; + } +done: + if (track && isl_tab_track_bmap(tab, isl_basic_map_copy(bmap)) < 0) + goto error; + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +__isl_give struct isl_tab *isl_tab_from_basic_set( + __isl_keep isl_basic_set *bset, int track) +{ + return isl_tab_from_basic_map(bset, track); +} + +/* Construct a tableau corresponding to the recession cone of "bset". + */ +struct isl_tab *isl_tab_from_recession_cone(__isl_keep isl_basic_set *bset, + int parametric) +{ + isl_int cst; + int i; + struct isl_tab *tab; + unsigned offset = 0; + + if (!bset) + return NULL; + if (parametric) + offset = isl_basic_set_dim(bset, isl_dim_param); + tab = isl_tab_alloc(bset->ctx, bset->n_eq + bset->n_ineq, + isl_basic_set_total_dim(bset) - offset, 0); + if (!tab) + return NULL; + tab->rational = ISL_F_ISSET(bset, ISL_BASIC_SET_RATIONAL); + tab->cone = 1; + + isl_int_init(cst); + isl_int_set_si(cst, 0); + for (i = 0; i < bset->n_eq; ++i) { + isl_int_swap(bset->eq[i][offset], cst); + if (offset > 0) { + if (isl_tab_add_eq(tab, bset->eq[i] + offset) < 0) + goto error; + } else + tab = add_eq(tab, bset->eq[i]); + isl_int_swap(bset->eq[i][offset], cst); + if (!tab) + goto done; + } + for (i = 0; i < bset->n_ineq; ++i) { + int r; + isl_int_swap(bset->ineq[i][offset], cst); + r = isl_tab_add_row(tab, bset->ineq[i] + offset); + isl_int_swap(bset->ineq[i][offset], cst); + if (r < 0) + goto error; + tab->con[r].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0) + goto error; + } +done: + isl_int_clear(cst); + return tab; +error: + isl_int_clear(cst); + isl_tab_free(tab); + return NULL; +} + +/* Assuming "tab" is the tableau of a cone, check if the cone is + * bounded, i.e., if it is empty or only contains the origin. + */ +isl_bool isl_tab_cone_is_bounded(struct isl_tab *tab) +{ + int i; + + if (!tab) + return isl_bool_error; + if (tab->empty) + return isl_bool_true; + if (tab->n_dead == tab->n_col) + return isl_bool_true; + + for (;;) { + for (i = tab->n_redundant; i < tab->n_row; ++i) { + struct isl_tab_var *var; + int sgn; + var = isl_tab_var_from_row(tab, i); + if (!var->is_nonneg) + continue; + sgn = sign_of_max(tab, var); + if (sgn < -1) + return isl_bool_error; + if (sgn != 0) + return isl_bool_false; + if (close_row(tab, var, 0) < 0) + return isl_bool_error; + break; + } + if (tab->n_dead == tab->n_col) + return isl_bool_true; + if (i == tab->n_row) + return isl_bool_false; + } +} + +int isl_tab_sample_is_integer(struct isl_tab *tab) +{ + int i; + + if (!tab) + return -1; + + for (i = 0; i < tab->n_var; ++i) { + int row; + if (!tab->var[i].is_row) + continue; + row = tab->var[i].index; + if (!isl_int_is_divisible_by(tab->mat->row[row][1], + tab->mat->row[row][0])) + return 0; + } + return 1; +} + +static struct isl_vec *extract_integer_sample(struct isl_tab *tab) +{ + int i; + struct isl_vec *vec; + + vec = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var); + if (!vec) + return NULL; + + isl_int_set_si(vec->block.data[0], 1); + for (i = 0; i < tab->n_var; ++i) { + if (!tab->var[i].is_row) + isl_int_set_si(vec->block.data[1 + i], 0); + else { + int row = tab->var[i].index; + isl_int_divexact(vec->block.data[1 + i], + tab->mat->row[row][1], tab->mat->row[row][0]); + } + } + + return vec; +} + +struct isl_vec *isl_tab_get_sample_value(struct isl_tab *tab) +{ + int i; + struct isl_vec *vec; + isl_int m; + + if (!tab) + return NULL; + + vec = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var); + if (!vec) + return NULL; + + isl_int_init(m); + + isl_int_set_si(vec->block.data[0], 1); + for (i = 0; i < tab->n_var; ++i) { + int row; + if (!tab->var[i].is_row) { + isl_int_set_si(vec->block.data[1 + i], 0); + continue; + } + row = tab->var[i].index; + isl_int_gcd(m, vec->block.data[0], tab->mat->row[row][0]); + isl_int_divexact(m, tab->mat->row[row][0], m); + isl_seq_scale(vec->block.data, vec->block.data, m, 1 + i); + isl_int_divexact(m, vec->block.data[0], tab->mat->row[row][0]); + isl_int_mul(vec->block.data[1 + i], m, tab->mat->row[row][1]); + } + vec = isl_vec_normalize(vec); + + isl_int_clear(m); + return vec; +} + +/* Store the sample value of "var" of "tab" rounded up (if sgn > 0) + * or down (if sgn < 0) to the nearest integer in *v. + */ +static void get_rounded_sample_value(struct isl_tab *tab, + struct isl_tab_var *var, int sgn, isl_int *v) +{ + if (!var->is_row) + isl_int_set_si(*v, 0); + else if (sgn > 0) + isl_int_cdiv_q(*v, tab->mat->row[var->index][1], + tab->mat->row[var->index][0]); + else + isl_int_fdiv_q(*v, tab->mat->row[var->index][1], + tab->mat->row[var->index][0]); +} + +/* Update "bmap" based on the results of the tableau "tab". + * In particular, implicit equalities are made explicit, redundant constraints + * are removed and if the sample value happens to be integer, it is stored + * in "bmap" (unless "bmap" already had an integer sample). + * + * The tableau is assumed to have been created from "bmap" using + * isl_tab_from_basic_map. + */ +struct isl_basic_map *isl_basic_map_update_from_tab(struct isl_basic_map *bmap, + struct isl_tab *tab) +{ + int i; + unsigned n_eq; + + if (!bmap) + return NULL; + if (!tab) + return bmap; + + n_eq = tab->n_eq; + if (tab->empty) + bmap = isl_basic_map_set_to_empty(bmap); + else + for (i = bmap->n_ineq - 1; i >= 0; --i) { + if (isl_tab_is_equality(tab, n_eq + i)) + isl_basic_map_inequality_to_equality(bmap, i); + else if (isl_tab_is_redundant(tab, n_eq + i)) + isl_basic_map_drop_inequality(bmap, i); + } + if (bmap->n_eq != n_eq) + bmap = isl_basic_map_gauss(bmap, NULL); + if (!tab->rational && + bmap && !bmap->sample && isl_tab_sample_is_integer(tab)) + bmap->sample = extract_integer_sample(tab); + return bmap; +} + +struct isl_basic_set *isl_basic_set_update_from_tab(struct isl_basic_set *bset, + struct isl_tab *tab) +{ + return bset_from_bmap(isl_basic_map_update_from_tab(bset_to_bmap(bset), + tab)); +} + +/* Drop the last constraint added to "tab" in position "r". + * The constraint is expected to have remained in a row. + */ +static isl_stat drop_last_con_in_row(struct isl_tab *tab, int r) +{ + if (!tab->con[r].is_row) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "row unexpectedly moved to column", + return isl_stat_error); + if (r + 1 != tab->n_con) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "additional constraints added", return isl_stat_error); + if (drop_row(tab, tab->con[r].index) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Given a non-negative variable "var", temporarily add a new non-negative + * variable that is the opposite of "var", ensuring that "var" can only attain + * the value zero. The new variable is removed again before this function + * returns. However, the effect of forcing "var" to be zero remains. + * If var = n/d is a row variable, then the new variable = -n/d. + * If var is a column variables, then the new variable = -var. + * If the new variable cannot attain non-negative values, then + * the resulting tableau is empty. + * Otherwise, we know the value will be zero and we close the row. + */ +static isl_stat cut_to_hyperplane(struct isl_tab *tab, struct isl_tab_var *var) +{ + unsigned r; + isl_int *row; + int sgn; + unsigned off = 2 + tab->M; + + if (var->is_zero) + return isl_stat_ok; + if (var->is_redundant || !var->is_nonneg) + isl_die(isl_tab_get_ctx(tab), isl_error_invalid, + "expecting non-redundant non-negative variable", + return isl_stat_error); + + if (isl_tab_extend_cons(tab, 1) < 0) + return isl_stat_error; + + r = tab->n_con; + tab->con[r].index = tab->n_row; + tab->con[r].is_row = 1; + tab->con[r].is_nonneg = 0; + tab->con[r].is_zero = 0; + tab->con[r].is_redundant = 0; + tab->con[r].frozen = 0; + tab->con[r].negated = 0; + tab->row_var[tab->n_row] = ~r; + row = tab->mat->row[tab->n_row]; + + if (var->is_row) { + isl_int_set(row[0], tab->mat->row[var->index][0]); + isl_seq_neg(row + 1, + tab->mat->row[var->index] + 1, 1 + tab->n_col); + } else { + isl_int_set_si(row[0], 1); + isl_seq_clr(row + 1, 1 + tab->n_col); + isl_int_set_si(row[off + var->index], -1); + } + + tab->n_row++; + tab->n_con++; + + sgn = sign_of_max(tab, &tab->con[r]); + if (sgn < -1) + return isl_stat_error; + if (sgn < 0) { + if (drop_last_con_in_row(tab, r) < 0) + return isl_stat_error; + if (isl_tab_mark_empty(tab) < 0) + return isl_stat_error; + return isl_stat_ok; + } + tab->con[r].is_nonneg = 1; + /* sgn == 0 */ + if (close_row(tab, &tab->con[r], 1) < 0) + return isl_stat_error; + if (drop_last_con_in_row(tab, r) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Given a tableau "tab" and an inequality constraint "con" of the tableau, + * relax the inequality by one. That is, the inequality r >= 0 is replaced + * by r' = r + 1 >= 0. + * If r is a row variable, we simply increase the constant term by one + * (taking into account the denominator). + * If r is a column variable, then we need to modify each row that + * refers to r = r' - 1 by substituting this equality, effectively + * subtracting the coefficient of the column from the constant. + * We should only do this if the minimum is manifestly unbounded, + * however. Otherwise, we may end up with negative sample values + * for non-negative variables. + * So, if r is a column variable with a minimum that is not + * manifestly unbounded, then we need to move it to a row. + * However, the sample value of this row may be negative, + * even after the relaxation, so we need to restore it. + * We therefore prefer to pivot a column up to a row, if possible. + */ +int isl_tab_relax(struct isl_tab *tab, int con) +{ + struct isl_tab_var *var; + + if (!tab) + return -1; + + var = &tab->con[con]; + + if (var->is_row && (var->index < 0 || var->index < tab->n_redundant)) + isl_die(tab->mat->ctx, isl_error_invalid, + "cannot relax redundant constraint", return -1); + if (!var->is_row && (var->index < 0 || var->index < tab->n_dead)) + isl_die(tab->mat->ctx, isl_error_invalid, + "cannot relax dead constraint", return -1); + + if (!var->is_row && !max_is_manifestly_unbounded(tab, var)) + if (to_row(tab, var, 1) < 0) + return -1; + if (!var->is_row && !min_is_manifestly_unbounded(tab, var)) + if (to_row(tab, var, -1) < 0) + return -1; + + if (var->is_row) { + isl_int_add(tab->mat->row[var->index][1], + tab->mat->row[var->index][1], tab->mat->row[var->index][0]); + if (restore_row(tab, var) < 0) + return -1; + } else { + int i; + unsigned off = 2 + tab->M; + + for (i = 0; i < tab->n_row; ++i) { + if (isl_int_is_zero(tab->mat->row[i][off + var->index])) + continue; + isl_int_sub(tab->mat->row[i][1], tab->mat->row[i][1], + tab->mat->row[i][off + var->index]); + } + + } + + if (isl_tab_push_var(tab, isl_tab_undo_relax, var) < 0) + return -1; + + return 0; +} + +/* Replace the variable v at position "pos" in the tableau "tab" + * by v' = v + shift. + * + * If the variable is in a column, then we first check if we can + * simply plug in v = v' - shift. The effect on a row with + * coefficient f/d for variable v is that the constant term c/d + * is replaced by (c - f * shift)/d. If shift is positive and + * f is negative for each row that needs to remain non-negative, + * then this is clearly safe. In other words, if the minimum of v + * is manifestly unbounded, then we can keep v in a column position. + * Otherwise, we can pivot it down to a row. + * Similarly, if shift is negative, we need to check if the maximum + * of is manifestly unbounded. + * + * If the variable is in a row (from the start or after pivoting), + * then the constant term c/d is replaced by (c + d * shift)/d. + */ +int isl_tab_shift_var(struct isl_tab *tab, int pos, isl_int shift) +{ + struct isl_tab_var *var; + + if (!tab) + return -1; + if (isl_int_is_zero(shift)) + return 0; + + var = &tab->var[pos]; + if (!var->is_row) { + if (isl_int_is_neg(shift)) { + if (!max_is_manifestly_unbounded(tab, var)) + if (to_row(tab, var, 1) < 0) + return -1; + } else { + if (!min_is_manifestly_unbounded(tab, var)) + if (to_row(tab, var, -1) < 0) + return -1; + } + } + + if (var->is_row) { + isl_int_addmul(tab->mat->row[var->index][1], + shift, tab->mat->row[var->index][0]); + } else { + int i; + unsigned off = 2 + tab->M; + + for (i = 0; i < tab->n_row; ++i) { + if (isl_int_is_zero(tab->mat->row[i][off + var->index])) + continue; + isl_int_submul(tab->mat->row[i][1], + shift, tab->mat->row[i][off + var->index]); + } + + } + + return 0; +} + +/* Remove the sign constraint from constraint "con". + * + * If the constraint variable was originally marked non-negative, + * then we make sure we mark it non-negative again during rollback. + */ +int isl_tab_unrestrict(struct isl_tab *tab, int con) +{ + struct isl_tab_var *var; + + if (!tab) + return -1; + + var = &tab->con[con]; + if (!var->is_nonneg) + return 0; + + var->is_nonneg = 0; + if (isl_tab_push_var(tab, isl_tab_undo_unrestrict, var) < 0) + return -1; + + return 0; +} + +int isl_tab_select_facet(struct isl_tab *tab, int con) +{ + if (!tab) + return -1; + + return cut_to_hyperplane(tab, &tab->con[con]); +} + +static int may_be_equality(struct isl_tab *tab, int row) +{ + return tab->rational ? isl_int_is_zero(tab->mat->row[row][1]) + : isl_int_lt(tab->mat->row[row][1], + tab->mat->row[row][0]); +} + +/* Return an isl_tab_var that has been marked or NULL if no such + * variable can be found. + * The marked field has only been set for variables that + * appear in non-redundant rows or non-dead columns. + * + * Pick the last constraint variable that is marked and + * that appears in either a non-redundant row or a non-dead columns. + * Since the returned variable is tested for being a redundant constraint or + * an implicit equality, there is no need to return any tab variable that + * corresponds to a variable. + */ +static struct isl_tab_var *select_marked(struct isl_tab *tab) +{ + int i; + struct isl_tab_var *var; + + for (i = tab->n_con - 1; i >= 0; --i) { + var = &tab->con[i]; + if (var->index < 0) + continue; + if (var->is_row && var->index < tab->n_redundant) + continue; + if (!var->is_row && var->index < tab->n_dead) + continue; + if (var->marked) + return var; + } + + return NULL; +} + +/* Check for (near) equalities among the constraints. + * A constraint is an equality if it is non-negative and if + * its maximal value is either + * - zero (in case of rational tableaus), or + * - strictly less than 1 (in case of integer tableaus) + * + * We first mark all non-redundant and non-dead variables that + * are not frozen and not obviously not an equality. + * Then we iterate over all marked variables if they can attain + * any values larger than zero or at least one. + * If the maximal value is zero, we mark any column variables + * that appear in the row as being zero and mark the row as being redundant. + * Otherwise, if the maximal value is strictly less than one (and the + * tableau is integer), then we restrict the value to being zero + * by adding an opposite non-negative variable. + * The order in which the variables are considered is not important. + */ +int isl_tab_detect_implicit_equalities(struct isl_tab *tab) +{ + int i; + unsigned n_marked; + + if (!tab) + return -1; + if (tab->empty) + return 0; + if (tab->n_dead == tab->n_col) + return 0; + + n_marked = 0; + for (i = tab->n_redundant; i < tab->n_row; ++i) { + struct isl_tab_var *var = isl_tab_var_from_row(tab, i); + var->marked = !var->frozen && var->is_nonneg && + may_be_equality(tab, i); + if (var->marked) + n_marked++; + } + for (i = tab->n_dead; i < tab->n_col; ++i) { + struct isl_tab_var *var = var_from_col(tab, i); + var->marked = !var->frozen && var->is_nonneg; + if (var->marked) + n_marked++; + } + while (n_marked) { + struct isl_tab_var *var; + int sgn; + var = select_marked(tab); + if (!var) + break; + var->marked = 0; + n_marked--; + sgn = sign_of_max(tab, var); + if (sgn < 0) + return -1; + if (sgn == 0) { + if (close_row(tab, var, 0) < 0) + return -1; + } else if (!tab->rational && !at_least_one(tab, var)) { + if (cut_to_hyperplane(tab, var) < 0) + return -1; + return isl_tab_detect_implicit_equalities(tab); + } + for (i = tab->n_redundant; i < tab->n_row; ++i) { + var = isl_tab_var_from_row(tab, i); + if (!var->marked) + continue; + if (may_be_equality(tab, i)) + continue; + var->marked = 0; + n_marked--; + } + } + + return 0; +} + +/* Update the element of row_var or col_var that corresponds to + * constraint tab->con[i] to a move from position "old" to position "i". + */ +static int update_con_after_move(struct isl_tab *tab, int i, int old) +{ + int *p; + int index; + + index = tab->con[i].index; + if (index == -1) + return 0; + p = tab->con[i].is_row ? tab->row_var : tab->col_var; + if (p[index] != ~old) + isl_die(tab->mat->ctx, isl_error_internal, + "broken internal state", return -1); + p[index] = ~i; + + return 0; +} + +/* Rotate the "n" constraints starting at "first" to the right, + * putting the last constraint in the position of the first constraint. + */ +static int rotate_constraints(struct isl_tab *tab, int first, int n) +{ + int i, last; + struct isl_tab_var var; + + if (n <= 1) + return 0; + + last = first + n - 1; + var = tab->con[last]; + for (i = last; i > first; --i) { + tab->con[i] = tab->con[i - 1]; + if (update_con_after_move(tab, i, i - 1) < 0) + return -1; + } + tab->con[first] = var; + if (update_con_after_move(tab, first, last) < 0) + return -1; + + return 0; +} + +/* Make the equalities that are implicit in "bmap" but that have been + * detected in the corresponding "tab" explicit in "bmap" and update + * "tab" to reflect the new order of the constraints. + * + * In particular, if inequality i is an implicit equality then + * isl_basic_map_inequality_to_equality will move the inequality + * in front of the other equality and it will move the last inequality + * in the position of inequality i. + * In the tableau, the inequalities of "bmap" are stored after the equalities + * and so the original order + * + * E E E E E A A A I B B B B L + * + * is changed into + * + * I E E E E E A A A L B B B B + * + * where I is the implicit equality, the E are equalities, + * the A inequalities before I, the B inequalities after I and + * L the last inequality. + * We therefore need to rotate to the right two sets of constraints, + * those up to and including I and those after I. + * + * If "tab" contains any constraints that are not in "bmap" then they + * appear after those in "bmap" and they should be left untouched. + * + * Note that this function leaves "bmap" in a temporary state + * as it does not call isl_basic_map_gauss. Calling this function + * is the responsibility of the caller. + */ +__isl_give isl_basic_map *isl_tab_make_equalities_explicit(struct isl_tab *tab, + __isl_take isl_basic_map *bmap) +{ + int i; + + if (!tab || !bmap) + return isl_basic_map_free(bmap); + if (tab->empty) + return bmap; + + for (i = bmap->n_ineq - 1; i >= 0; --i) { + if (!isl_tab_is_equality(tab, bmap->n_eq + i)) + continue; + isl_basic_map_inequality_to_equality(bmap, i); + if (rotate_constraints(tab, 0, tab->n_eq + i + 1) < 0) + return isl_basic_map_free(bmap); + if (rotate_constraints(tab, tab->n_eq + i + 1, + bmap->n_ineq - i) < 0) + return isl_basic_map_free(bmap); + tab->n_eq++; + } + + return bmap; +} + +static int con_is_redundant(struct isl_tab *tab, struct isl_tab_var *var) +{ + if (!tab) + return -1; + if (tab->rational) { + int sgn = sign_of_min(tab, var); + if (sgn < -1) + return -1; + return sgn >= 0; + } else { + int irred = isl_tab_min_at_most_neg_one(tab, var); + if (irred < 0) + return -1; + return !irred; + } +} + +/* Check for (near) redundant constraints. + * A constraint is redundant if it is non-negative and if + * its minimal value (temporarily ignoring the non-negativity) is either + * - zero (in case of rational tableaus), or + * - strictly larger than -1 (in case of integer tableaus) + * + * We first mark all non-redundant and non-dead variables that + * are not frozen and not obviously negatively unbounded. + * Then we iterate over all marked variables if they can attain + * any values smaller than zero or at most negative one. + * If not, we mark the row as being redundant (assuming it hasn't + * been detected as being obviously redundant in the mean time). + */ +int isl_tab_detect_redundant(struct isl_tab *tab) +{ + int i; + unsigned n_marked; + + if (!tab) + return -1; + if (tab->empty) + return 0; + if (tab->n_redundant == tab->n_row) + return 0; + + n_marked = 0; + for (i = tab->n_redundant; i < tab->n_row; ++i) { + struct isl_tab_var *var = isl_tab_var_from_row(tab, i); + var->marked = !var->frozen && var->is_nonneg; + if (var->marked) + n_marked++; + } + for (i = tab->n_dead; i < tab->n_col; ++i) { + struct isl_tab_var *var = var_from_col(tab, i); + var->marked = !var->frozen && var->is_nonneg && + !min_is_manifestly_unbounded(tab, var); + if (var->marked) + n_marked++; + } + while (n_marked) { + struct isl_tab_var *var; + int red; + var = select_marked(tab); + if (!var) + break; + var->marked = 0; + n_marked--; + red = con_is_redundant(tab, var); + if (red < 0) + return -1; + if (red && !var->is_redundant) + if (isl_tab_mark_redundant(tab, var->index) < 0) + return -1; + for (i = tab->n_dead; i < tab->n_col; ++i) { + var = var_from_col(tab, i); + if (!var->marked) + continue; + if (!min_is_manifestly_unbounded(tab, var)) + continue; + var->marked = 0; + n_marked--; + } + } + + return 0; +} + +int isl_tab_is_equality(struct isl_tab *tab, int con) +{ + int row; + unsigned off; + + if (!tab) + return -1; + if (tab->con[con].is_zero) + return 1; + if (tab->con[con].is_redundant) + return 0; + if (!tab->con[con].is_row) + return tab->con[con].index < tab->n_dead; + + row = tab->con[con].index; + + off = 2 + tab->M; + return isl_int_is_zero(tab->mat->row[row][1]) && + !row_is_big(tab, row) && + isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead, + tab->n_col - tab->n_dead) == -1; +} + +/* Return the minimal value of the affine expression "f" with denominator + * "denom" in *opt, *opt_denom, assuming the tableau is not empty and + * the expression cannot attain arbitrarily small values. + * If opt_denom is NULL, then *opt is rounded up to the nearest integer. + * The return value reflects the nature of the result (empty, unbounded, + * minimal value returned in *opt). + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +enum isl_lp_result isl_tab_min(struct isl_tab *tab, + isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom, + unsigned flags) +{ + int r; + enum isl_lp_result res = isl_lp_ok; + struct isl_tab_var *var; + struct isl_tab_undo *snap; + + if (!tab) + return isl_lp_error; + + if (tab->empty) + return isl_lp_empty; + + snap = isl_tab_snap(tab); + r = isl_tab_add_row(tab, f); + if (r < 0) + return isl_lp_error; + var = &tab->con[r]; + for (;;) { + int row, col; + find_pivot(tab, var, var, -1, &row, &col); + if (row == var->index) { + res = isl_lp_unbounded; + break; + } + if (row == -1) + break; + if (isl_tab_pivot(tab, row, col) < 0) + return isl_lp_error; + } + isl_int_mul(tab->mat->row[var->index][0], + tab->mat->row[var->index][0], denom); + if (ISL_FL_ISSET(flags, ISL_TAB_SAVE_DUAL)) { + int i; + + isl_vec_free(tab->dual); + tab->dual = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_con); + if (!tab->dual) + return isl_lp_error; + isl_int_set(tab->dual->el[0], tab->mat->row[var->index][0]); + for (i = 0; i < tab->n_con; ++i) { + int pos; + if (tab->con[i].is_row) { + isl_int_set_si(tab->dual->el[1 + i], 0); + continue; + } + pos = 2 + tab->M + tab->con[i].index; + if (tab->con[i].negated) + isl_int_neg(tab->dual->el[1 + i], + tab->mat->row[var->index][pos]); + else + isl_int_set(tab->dual->el[1 + i], + tab->mat->row[var->index][pos]); + } + } + if (opt && res == isl_lp_ok) { + if (opt_denom) { + isl_int_set(*opt, tab->mat->row[var->index][1]); + isl_int_set(*opt_denom, tab->mat->row[var->index][0]); + } else + get_rounded_sample_value(tab, var, 1, opt); + } + if (isl_tab_rollback(tab, snap) < 0) + return isl_lp_error; + return res; +} + +/* Is the constraint at position "con" marked as being redundant? + * If it is marked as representing an equality, then it is not + * considered to be redundant. + * Note that isl_tab_mark_redundant marks both the isl_tab_var as + * redundant and moves the corresponding row into the first + * tab->n_redundant positions (or removes the row, assigning it index -1), + * so the final test is actually redundant itself. + */ +int isl_tab_is_redundant(struct isl_tab *tab, int con) +{ + if (!tab) + return -1; + if (con < 0 || con >= tab->n_con) + isl_die(isl_tab_get_ctx(tab), isl_error_invalid, + "position out of bounds", return -1); + if (tab->con[con].is_zero) + return 0; + if (tab->con[con].is_redundant) + return 1; + return tab->con[con].is_row && tab->con[con].index < tab->n_redundant; +} + +/* Is variable "var" of "tab" fixed to a constant value by its row + * in the tableau? + * If so and if "value" is not NULL, then store this constant value + * in "value". + * + * That is, is it a row variable that only has non-zero coefficients + * for dead columns? + */ +static isl_bool is_constant(struct isl_tab *tab, struct isl_tab_var *var, + isl_int *value) +{ + unsigned off = 2 + tab->M; + isl_mat *mat = tab->mat; + int n; + int row; + int pos; + + if (!var->is_row) + return isl_bool_false; + row = var->index; + if (row_is_big(tab, row)) + return isl_bool_false; + n = tab->n_col - tab->n_dead; + pos = isl_seq_first_non_zero(mat->row[row] + off + tab->n_dead, n); + if (pos != -1) + return isl_bool_false; + if (value) + isl_int_divexact(*value, mat->row[row][1], mat->row[row][0]); + return isl_bool_true; +} + +/* Has the variable "var' of "tab" reached a value that is greater than + * or equal (if sgn > 0) or smaller than or equal (if sgn < 0) to "target"? + * "tmp" has been initialized by the caller and can be used + * to perform local computations. + * + * If the sample value involves the big parameter, then any value + * is reached. + * Otherwise check if n/d >= t, i.e., n >= d * t (if sgn > 0) + * or n/d <= t, i.e., n <= d * t (if sgn < 0). + */ +static int reached(struct isl_tab *tab, struct isl_tab_var *var, int sgn, + isl_int target, isl_int *tmp) +{ + if (row_is_big(tab, var->index)) + return 1; + isl_int_mul(*tmp, tab->mat->row[var->index][0], target); + if (sgn > 0) + return isl_int_ge(tab->mat->row[var->index][1], *tmp); + else + return isl_int_le(tab->mat->row[var->index][1], *tmp); +} + +/* Can variable "var" of "tab" attain the value "target" by + * pivoting up (if sgn > 0) or down (if sgn < 0)? + * If not, then pivot up [down] to the greatest [smallest] + * rational value. + * "tmp" has been initialized by the caller and can be used + * to perform local computations. + * + * If the variable is manifestly unbounded in the desired direction, + * then it can attain any value. + * Otherwise, it can be moved to a row. + * Continue pivoting until the target is reached. + * If no more pivoting can be performed, the maximal [minimal] + * rational value has been reached and the target cannot be reached. + * If the variable would be pivoted into a manifestly unbounded column, + * then the target can be reached. + */ +static isl_bool var_reaches(struct isl_tab *tab, struct isl_tab_var *var, + int sgn, isl_int target, isl_int *tmp) +{ + int row, col; + + if (sgn < 0 && min_is_manifestly_unbounded(tab, var)) + return isl_bool_true; + if (sgn > 0 && max_is_manifestly_unbounded(tab, var)) + return isl_bool_true; + if (to_row(tab, var, sgn) < 0) + return isl_bool_error; + while (!reached(tab, var, sgn, target, tmp)) { + find_pivot(tab, var, var, sgn, &row, &col); + if (row == -1) + return isl_bool_false; + if (row == var->index) + return isl_bool_true; + if (isl_tab_pivot(tab, row, col) < 0) + return isl_bool_error; + } + + return isl_bool_true; +} + +/* Check if variable "var" of "tab" can only attain a single (integer) + * value, and, if so, add an equality constraint to fix the variable + * to this single value and store the result in "target". + * "target" and "tmp" have been initialized by the caller. + * + * Given the current sample value, round it down and check + * whether it is possible to attain a strictly smaller integer value. + * If so, the variable is not restricted to a single integer value. + * Otherwise, the search stops at the smallest rational value. + * Round up this value and check whether it is possible to attain + * a strictly greater integer value. + * If so, the variable is not restricted to a single integer value. + * Otherwise, the search stops at the greatest rational value. + * If rounding down this value yields a value that is different + * from rounding up the smallest rational value, then the variable + * cannot attain any integer value. Mark the tableau empty. + * Otherwise, add an equality constraint that fixes the variable + * to the single integer value found. + */ +static isl_bool detect_constant_with_tmp(struct isl_tab *tab, + struct isl_tab_var *var, isl_int *target, isl_int *tmp) +{ + isl_bool reached; + isl_vec *eq; + int pos; + isl_stat r; + + get_rounded_sample_value(tab, var, -1, target); + isl_int_sub_ui(*target, *target, 1); + reached = var_reaches(tab, var, -1, *target, tmp); + if (reached < 0 || reached) + return isl_bool_not(reached); + get_rounded_sample_value(tab, var, 1, target); + isl_int_add_ui(*target, *target, 1); + reached = var_reaches(tab, var, 1, *target, tmp); + if (reached < 0 || reached) + return isl_bool_not(reached); + get_rounded_sample_value(tab, var, -1, tmp); + isl_int_sub_ui(*target, *target, 1); + if (isl_int_ne(*target, *tmp)) { + if (isl_tab_mark_empty(tab) < 0) + return isl_bool_error; + return isl_bool_false; + } + + if (isl_tab_extend_cons(tab, 1) < 0) + return isl_bool_error; + eq = isl_vec_alloc(isl_tab_get_ctx(tab), 1 + tab->n_var); + if (!eq) + return isl_bool_error; + pos = var - tab->var; + isl_seq_clr(eq->el + 1, tab->n_var); + isl_int_set_si(eq->el[1 + pos], -1); + isl_int_set(eq->el[0], *target); + r = isl_tab_add_eq(tab, eq->el); + isl_vec_free(eq); + + return r < 0 ? isl_bool_error : isl_bool_true; +} + +/* Check if variable "var" of "tab" can only attain a single (integer) + * value, and, if so, add an equality constraint to fix the variable + * to this single value and store the result in "value" (if "value" + * is not NULL). + * + * If the current sample value involves the big parameter, + * then the variable cannot have a fixed integer value. + * If the variable is already fixed to a single value by its row, then + * there is no need to add another equality constraint. + * + * Otherwise, allocate some temporary variables and continue + * with detect_constant_with_tmp. + */ +static isl_bool get_constant(struct isl_tab *tab, struct isl_tab_var *var, + isl_int *value) +{ + isl_int target, tmp; + isl_bool is_cst; + + if (var->is_row && row_is_big(tab, var->index)) + return isl_bool_false; + is_cst = is_constant(tab, var, value); + if (is_cst < 0 || is_cst) + return is_cst; + + if (!value) + isl_int_init(target); + isl_int_init(tmp); + + is_cst = detect_constant_with_tmp(tab, var, + value ? value : &target, &tmp); + + isl_int_clear(tmp); + if (!value) + isl_int_clear(target); + + return is_cst; +} + +/* Check if variable "var" of "tab" can only attain a single (integer) + * value, and, if so, add an equality constraint to fix the variable + * to this single value and store the result in "value" (if "value" + * is not NULL). + * + * For rational tableaus, nothing needs to be done. + */ +isl_bool isl_tab_is_constant(struct isl_tab *tab, int var, isl_int *value) +{ + if (!tab) + return isl_bool_error; + if (var < 0 || var >= tab->n_var) + isl_die(isl_tab_get_ctx(tab), isl_error_invalid, + "position out of bounds", return isl_bool_error); + if (tab->rational) + return isl_bool_false; + + return get_constant(tab, &tab->var[var], value); +} + +/* Check if any of the variables of "tab" can only attain a single (integer) + * value, and, if so, add equality constraints to fix those variables + * to these single values. + * + * For rational tableaus, nothing needs to be done. + */ +isl_stat isl_tab_detect_constants(struct isl_tab *tab) +{ + int i; + + if (!tab) + return isl_stat_error; + if (tab->rational) + return isl_stat_ok; + + for (i = 0; i < tab->n_var; ++i) { + if (get_constant(tab, &tab->var[i], NULL) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Take a snapshot of the tableau that can be restored by a call to + * isl_tab_rollback. + */ +struct isl_tab_undo *isl_tab_snap(struct isl_tab *tab) +{ + if (!tab) + return NULL; + tab->need_undo = 1; + return tab->top; +} + +/* Does "tab" need to keep track of undo information? + * That is, was a snapshot taken that may need to be restored? + */ +isl_bool isl_tab_need_undo(struct isl_tab *tab) +{ + if (!tab) + return isl_bool_error; + + return tab->need_undo; +} + +/* Remove all tracking of undo information from "tab", invalidating + * any snapshots that may have been taken of the tableau. + * Since all snapshots have been invalidated, there is also + * no need to start keeping track of undo information again. + */ +void isl_tab_clear_undo(struct isl_tab *tab) +{ + if (!tab) + return; + + free_undo(tab); + tab->need_undo = 0; +} + +/* Undo the operation performed by isl_tab_relax. + */ +static isl_stat unrelax(struct isl_tab *tab, struct isl_tab_var *var) + WARN_UNUSED; +static isl_stat unrelax(struct isl_tab *tab, struct isl_tab_var *var) +{ + unsigned off = 2 + tab->M; + + if (!var->is_row && !max_is_manifestly_unbounded(tab, var)) + if (to_row(tab, var, 1) < 0) + return isl_stat_error; + + if (var->is_row) { + isl_int_sub(tab->mat->row[var->index][1], + tab->mat->row[var->index][1], tab->mat->row[var->index][0]); + if (var->is_nonneg) { + int sgn = restore_row(tab, var); + isl_assert(tab->mat->ctx, sgn >= 0, + return isl_stat_error); + } + } else { + int i; + + for (i = 0; i < tab->n_row; ++i) { + if (isl_int_is_zero(tab->mat->row[i][off + var->index])) + continue; + isl_int_add(tab->mat->row[i][1], tab->mat->row[i][1], + tab->mat->row[i][off + var->index]); + } + + } + + return isl_stat_ok; +} + +/* Undo the operation performed by isl_tab_unrestrict. + * + * In particular, mark the variable as being non-negative and make + * sure the sample value respects this constraint. + */ +static isl_stat ununrestrict(struct isl_tab *tab, struct isl_tab_var *var) +{ + var->is_nonneg = 1; + + if (var->is_row && restore_row(tab, var) < -1) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Unmark the last redundant row in "tab" as being redundant. + * This undoes part of the modifications performed by isl_tab_mark_redundant. + * In particular, remove the redundant mark and make + * sure the sample value respects the constraint again. + * A variable that is marked non-negative by isl_tab_mark_redundant + * is covered by a separate undo record. + */ +static isl_stat restore_last_redundant(struct isl_tab *tab) +{ + struct isl_tab_var *var; + + if (tab->n_redundant < 1) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "no redundant rows", return isl_stat_error); + + var = isl_tab_var_from_row(tab, tab->n_redundant - 1); + var->is_redundant = 0; + tab->n_redundant--; + restore_row(tab, var); + + return isl_stat_ok; +} + +static isl_stat perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo) + WARN_UNUSED; +static isl_stat perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo) +{ + struct isl_tab_var *var = var_from_index(tab, undo->u.var_index); + switch (undo->type) { + case isl_tab_undo_nonneg: + var->is_nonneg = 0; + break; + case isl_tab_undo_redundant: + if (!var->is_row || var->index != tab->n_redundant - 1) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "not undoing last redundant row", return -1); + return restore_last_redundant(tab); + case isl_tab_undo_freeze: + var->frozen = 0; + break; + case isl_tab_undo_zero: + var->is_zero = 0; + if (!var->is_row) + tab->n_dead--; + break; + case isl_tab_undo_allocate: + if (undo->u.var_index >= 0) { + isl_assert(tab->mat->ctx, !var->is_row, + return isl_stat_error); + return drop_col(tab, var->index); + } + if (!var->is_row) { + if (!max_is_manifestly_unbounded(tab, var)) { + if (to_row(tab, var, 1) < 0) + return isl_stat_error; + } else if (!min_is_manifestly_unbounded(tab, var)) { + if (to_row(tab, var, -1) < 0) + return isl_stat_error; + } else + if (to_row(tab, var, 0) < 0) + return isl_stat_error; + } + return drop_row(tab, var->index); + case isl_tab_undo_relax: + return unrelax(tab, var); + case isl_tab_undo_unrestrict: + return ununrestrict(tab, var); + default: + isl_die(tab->mat->ctx, isl_error_internal, + "perform_undo_var called on invalid undo record", + return isl_stat_error); + } + + return isl_stat_ok; +} + +/* Restore all rows that have been marked redundant by isl_tab_mark_redundant + * and that have been preserved in the tableau. + * Note that isl_tab_mark_redundant may also have marked some variables + * as being non-negative before marking them redundant. These need + * to be removed as well as otherwise some constraints could end up + * getting marked redundant with respect to the variable. + */ +isl_stat isl_tab_restore_redundant(struct isl_tab *tab) +{ + if (!tab) + return isl_stat_error; + + if (tab->need_undo) + isl_die(isl_tab_get_ctx(tab), isl_error_invalid, + "manually restoring redundant constraints " + "interferes with undo history", + return isl_stat_error); + + while (tab->n_redundant > 0) { + if (tab->row_var[tab->n_redundant - 1] >= 0) { + struct isl_tab_var *var; + + var = isl_tab_var_from_row(tab, tab->n_redundant - 1); + var->is_nonneg = 0; + } + restore_last_redundant(tab); + } + return isl_stat_ok; +} + +/* Undo the addition of an integer division to the basic map representation + * of "tab" in position "pos". + */ +static isl_stat drop_bmap_div(struct isl_tab *tab, int pos) +{ + int off; + + off = tab->n_var - isl_basic_map_dim(tab->bmap, isl_dim_div); + if (isl_basic_map_drop_div(tab->bmap, pos - off) < 0) + return isl_stat_error; + if (tab->samples) { + tab->samples = isl_mat_drop_cols(tab->samples, 1 + pos, 1); + if (!tab->samples) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Restore the tableau to the state where the basic variables + * are those in "col_var". + * We first construct a list of variables that are currently in + * the basis, but shouldn't. Then we iterate over all variables + * that should be in the basis and for each one that is currently + * not in the basis, we exchange it with one of the elements of the + * list constructed before. + * We can always find an appropriate variable to pivot with because + * the current basis is mapped to the old basis by a non-singular + * matrix and so we can never end up with a zero row. + */ +static int restore_basis(struct isl_tab *tab, int *col_var) +{ + int i, j; + int n_extra = 0; + int *extra = NULL; /* current columns that contain bad stuff */ + unsigned off = 2 + tab->M; + + extra = isl_alloc_array(tab->mat->ctx, int, tab->n_col); + if (tab->n_col && !extra) + goto error; + for (i = 0; i < tab->n_col; ++i) { + for (j = 0; j < tab->n_col; ++j) + if (tab->col_var[i] == col_var[j]) + break; + if (j < tab->n_col) + continue; + extra[n_extra++] = i; + } + for (i = 0; i < tab->n_col && n_extra > 0; ++i) { + struct isl_tab_var *var; + int row; + + for (j = 0; j < tab->n_col; ++j) + if (col_var[i] == tab->col_var[j]) + break; + if (j < tab->n_col) + continue; + var = var_from_index(tab, col_var[i]); + row = var->index; + for (j = 0; j < n_extra; ++j) + if (!isl_int_is_zero(tab->mat->row[row][off+extra[j]])) + break; + isl_assert(tab->mat->ctx, j < n_extra, goto error); + if (isl_tab_pivot(tab, row, extra[j]) < 0) + goto error; + extra[j] = extra[--n_extra]; + } + + free(extra); + return 0; +error: + free(extra); + return -1; +} + +/* Remove all samples with index n or greater, i.e., those samples + * that were added since we saved this number of samples in + * isl_tab_save_samples. + */ +static void drop_samples_since(struct isl_tab *tab, int n) +{ + int i; + + for (i = tab->n_sample - 1; i >= 0 && tab->n_sample > n; --i) { + if (tab->sample_index[i] < n) + continue; + + if (i != tab->n_sample - 1) { + int t = tab->sample_index[tab->n_sample-1]; + tab->sample_index[tab->n_sample-1] = tab->sample_index[i]; + tab->sample_index[i] = t; + isl_mat_swap_rows(tab->samples, tab->n_sample-1, i); + } + tab->n_sample--; + } +} + +static isl_stat perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo) + WARN_UNUSED; +static isl_stat perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo) +{ + switch (undo->type) { + case isl_tab_undo_rational: + tab->rational = 0; + break; + case isl_tab_undo_empty: + tab->empty = 0; + break; + case isl_tab_undo_nonneg: + case isl_tab_undo_redundant: + case isl_tab_undo_freeze: + case isl_tab_undo_zero: + case isl_tab_undo_allocate: + case isl_tab_undo_relax: + case isl_tab_undo_unrestrict: + return perform_undo_var(tab, undo); + case isl_tab_undo_bmap_eq: + return isl_basic_map_free_equality(tab->bmap, 1); + case isl_tab_undo_bmap_ineq: + return isl_basic_map_free_inequality(tab->bmap, 1); + case isl_tab_undo_bmap_div: + return drop_bmap_div(tab, undo->u.var_index); + case isl_tab_undo_saved_basis: + if (restore_basis(tab, undo->u.col_var) < 0) + return isl_stat_error; + break; + case isl_tab_undo_drop_sample: + tab->n_outside--; + break; + case isl_tab_undo_saved_samples: + drop_samples_since(tab, undo->u.n); + break; + case isl_tab_undo_callback: + return undo->u.callback->run(undo->u.callback); + default: + isl_assert(tab->mat->ctx, 0, return isl_stat_error); + } + return isl_stat_ok; +} + +/* Return the tableau to the state it was in when the snapshot "snap" + * was taken. + */ +int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap) +{ + struct isl_tab_undo *undo, *next; + + if (!tab) + return -1; + + tab->in_undo = 1; + for (undo = tab->top; undo && undo != &tab->bottom; undo = next) { + next = undo->next; + if (undo == snap) + break; + if (perform_undo(tab, undo) < 0) { + tab->top = undo; + free_undo(tab); + tab->in_undo = 0; + return -1; + } + free_undo_record(undo); + } + tab->in_undo = 0; + tab->top = undo; + if (!undo) + return -1; + return 0; +} + +/* The given row "row" represents an inequality violated by all + * points in the tableau. Check for some special cases of such + * separating constraints. + * In particular, if the row has been reduced to the constant -1, + * then we know the inequality is adjacent (but opposite) to + * an equality in the tableau. + * If the row has been reduced to r = c*(-1 -r'), with r' an inequality + * of the tableau and c a positive constant, then the inequality + * is adjacent (but opposite) to the inequality r'. + */ +static enum isl_ineq_type separation_type(struct isl_tab *tab, unsigned row) +{ + int pos; + unsigned off = 2 + tab->M; + + if (tab->rational) + return isl_ineq_separate; + + if (!isl_int_is_one(tab->mat->row[row][0])) + return isl_ineq_separate; + + pos = isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead, + tab->n_col - tab->n_dead); + if (pos == -1) { + if (isl_int_is_negone(tab->mat->row[row][1])) + return isl_ineq_adj_eq; + else + return isl_ineq_separate; + } + + if (!isl_int_eq(tab->mat->row[row][1], + tab->mat->row[row][off + tab->n_dead + pos])) + return isl_ineq_separate; + + pos = isl_seq_first_non_zero( + tab->mat->row[row] + off + tab->n_dead + pos + 1, + tab->n_col - tab->n_dead - pos - 1); + + return pos == -1 ? isl_ineq_adj_ineq : isl_ineq_separate; +} + +/* Check the effect of inequality "ineq" on the tableau "tab". + * The result may be + * isl_ineq_redundant: satisfied by all points in the tableau + * isl_ineq_separate: satisfied by no point in the tableau + * isl_ineq_cut: satisfied by some by not all points + * isl_ineq_adj_eq: adjacent to an equality + * isl_ineq_adj_ineq: adjacent to an inequality. + */ +enum isl_ineq_type isl_tab_ineq_type(struct isl_tab *tab, isl_int *ineq) +{ + enum isl_ineq_type type = isl_ineq_error; + struct isl_tab_undo *snap = NULL; + int con; + int row; + + if (!tab) + return isl_ineq_error; + + if (isl_tab_extend_cons(tab, 1) < 0) + return isl_ineq_error; + + snap = isl_tab_snap(tab); + + con = isl_tab_add_row(tab, ineq); + if (con < 0) + goto error; + + row = tab->con[con].index; + if (isl_tab_row_is_redundant(tab, row)) + type = isl_ineq_redundant; + else if (isl_int_is_neg(tab->mat->row[row][1]) && + (tab->rational || + isl_int_abs_ge(tab->mat->row[row][1], + tab->mat->row[row][0]))) { + int nonneg = at_least_zero(tab, &tab->con[con]); + if (nonneg < 0) + goto error; + if (nonneg) + type = isl_ineq_cut; + else + type = separation_type(tab, row); + } else { + int red = con_is_redundant(tab, &tab->con[con]); + if (red < 0) + goto error; + if (!red) + type = isl_ineq_cut; + else + type = isl_ineq_redundant; + } + + if (isl_tab_rollback(tab, snap)) + return isl_ineq_error; + return type; +error: + return isl_ineq_error; +} + +isl_stat isl_tab_track_bmap(struct isl_tab *tab, __isl_take isl_basic_map *bmap) +{ + bmap = isl_basic_map_cow(bmap); + if (!tab || !bmap) + goto error; + + if (tab->empty) { + bmap = isl_basic_map_set_to_empty(bmap); + if (!bmap) + goto error; + tab->bmap = bmap; + return isl_stat_ok; + } + + isl_assert(tab->mat->ctx, tab->n_eq == bmap->n_eq, goto error); + isl_assert(tab->mat->ctx, + tab->n_con == bmap->n_eq + bmap->n_ineq, goto error); + + tab->bmap = bmap; + + return isl_stat_ok; +error: + isl_basic_map_free(bmap); + return isl_stat_error; +} + +isl_stat isl_tab_track_bset(struct isl_tab *tab, __isl_take isl_basic_set *bset) +{ + return isl_tab_track_bmap(tab, bset_to_bmap(bset)); +} + +__isl_keep isl_basic_set *isl_tab_peek_bset(struct isl_tab *tab) +{ + if (!tab) + return NULL; + + return bset_from_bmap(tab->bmap); +} + +static void isl_tab_print_internal(__isl_keep struct isl_tab *tab, + FILE *out, int indent) +{ + unsigned r, c; + int i; + + if (!tab) { + fprintf(out, "%*snull tab\n", indent, ""); + return; + } + fprintf(out, "%*sn_redundant: %d, n_dead: %d", indent, "", + tab->n_redundant, tab->n_dead); + if (tab->rational) + fprintf(out, ", rational"); + if (tab->empty) + fprintf(out, ", empty"); + fprintf(out, "\n"); + fprintf(out, "%*s[", indent, ""); + for (i = 0; i < tab->n_var; ++i) { + if (i) + fprintf(out, (i == tab->n_param || + i == tab->n_var - tab->n_div) ? "; " + : ", "); + fprintf(out, "%c%d%s", tab->var[i].is_row ? 'r' : 'c', + tab->var[i].index, + tab->var[i].is_zero ? " [=0]" : + tab->var[i].is_redundant ? " [R]" : ""); + } + fprintf(out, "]\n"); + fprintf(out, "%*s[", indent, ""); + for (i = 0; i < tab->n_con; ++i) { + if (i) + fprintf(out, ", "); + fprintf(out, "%c%d%s", tab->con[i].is_row ? 'r' : 'c', + tab->con[i].index, + tab->con[i].is_zero ? " [=0]" : + tab->con[i].is_redundant ? " [R]" : ""); + } + fprintf(out, "]\n"); + fprintf(out, "%*s[", indent, ""); + for (i = 0; i < tab->n_row; ++i) { + const char *sign = ""; + if (i) + fprintf(out, ", "); + if (tab->row_sign) { + if (tab->row_sign[i] == isl_tab_row_unknown) + sign = "?"; + else if (tab->row_sign[i] == isl_tab_row_neg) + sign = "-"; + else if (tab->row_sign[i] == isl_tab_row_pos) + sign = "+"; + else + sign = "+-"; + } + fprintf(out, "r%d: %d%s%s", i, tab->row_var[i], + isl_tab_var_from_row(tab, i)->is_nonneg ? " [>=0]" : "", sign); + } + fprintf(out, "]\n"); + fprintf(out, "%*s[", indent, ""); + for (i = 0; i < tab->n_col; ++i) { + if (i) + fprintf(out, ", "); + fprintf(out, "c%d: %d%s", i, tab->col_var[i], + var_from_col(tab, i)->is_nonneg ? " [>=0]" : ""); + } + fprintf(out, "]\n"); + r = tab->mat->n_row; + tab->mat->n_row = tab->n_row; + c = tab->mat->n_col; + tab->mat->n_col = 2 + tab->M + tab->n_col; + isl_mat_print_internal(tab->mat, out, indent); + tab->mat->n_row = r; + tab->mat->n_col = c; + if (tab->bmap) + isl_basic_map_print_internal(tab->bmap, out, indent); +} + +void isl_tab_dump(__isl_keep struct isl_tab *tab) +{ + isl_tab_print_internal(tab, stderr, 0); +} Index: contrib/isl/isl_tab_lexopt_templ.c =================================================================== --- /dev/null +++ contrib/isl/isl_tab_lexopt_templ.c @@ -0,0 +1,230 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2011 Sven Verdoolaege + * + * Use of this software is governed by the MIT 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 + */ + +#define xSF(TYPE,SUFFIX) TYPE ## SUFFIX +#define SF(TYPE,SUFFIX) xSF(TYPE,SUFFIX) + +/* Given a basic map with at least two parallel constraints (as found + * by the function parallel_constraints), first look for more constraints + * parallel to the two constraint and replace the found list of parallel + * constraints by a single constraint with as "input" part the minimum + * of the input parts of the list of constraints. Then, recursively call + * basic_map_partial_lexopt (possibly finding more parallel constraints) + * and plug in the definition of the minimum in the result. + * + * As in parallel_constraints, only inequality constraints that only + * involve input variables that do not occur in any other inequality + * constraints are considered. + * + * More specifically, given a set of constraints + * + * a x + b_i(p) >= 0 + * + * Replace this set by a single constraint + * + * a x + u >= 0 + * + * with u a new parameter with constraints + * + * u <= b_i(p) + * + * Any solution to the new system is also a solution for the original system + * since + * + * a x >= -u >= -b_i(p) + * + * Moreover, m = min_i(b_i(p)) satisfies the constraints on u and can + * therefore be plugged into the solution. + */ +static TYPE *SF(basic_map_partial_lexopt_symm,SUFFIX)( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max, int first, int second) +{ + int i, n, k; + int *list = NULL; + unsigned n_in, n_out, n_div; + isl_ctx *ctx; + isl_vec *var = NULL; + isl_mat *cst = NULL; + isl_space *map_space, *set_space; + + map_space = isl_basic_map_get_space(bmap); + set_space = empty ? isl_basic_set_get_space(dom) : NULL; + + n_in = isl_basic_map_dim(bmap, isl_dim_param) + + isl_basic_map_dim(bmap, isl_dim_in); + n_out = isl_basic_map_dim(bmap, isl_dim_all) - n_in; + + ctx = isl_basic_map_get_ctx(bmap); + list = isl_alloc_array(ctx, int, bmap->n_ineq); + var = isl_vec_alloc(ctx, n_out); + if ((bmap->n_ineq && !list) || (n_out && !var)) + goto error; + + list[0] = first; + list[1] = second; + isl_seq_cpy(var->el, bmap->ineq[first] + 1 + n_in, n_out); + for (i = second + 1, n = 2; i < bmap->n_ineq; ++i) { + if (isl_seq_eq(var->el, bmap->ineq[i] + 1 + n_in, n_out) && + all_single_occurrence(bmap, i, n_in)) + list[n++] = i; + } + + cst = isl_mat_alloc(ctx, n, 1 + n_in); + if (!cst) + goto error; + + for (i = 0; i < n; ++i) + isl_seq_cpy(cst->row[i], bmap->ineq[list[i]], 1 + n_in); + + bmap = isl_basic_map_cow(bmap); + if (!bmap) + goto error; + for (i = n - 1; i >= 0; --i) + if (isl_basic_map_drop_inequality(bmap, list[i]) < 0) + goto error; + + bmap = isl_basic_map_add_dims(bmap, isl_dim_in, 1); + bmap = isl_basic_map_extend_constraints(bmap, 0, 1); + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->ineq[k], 1 + n_in); + isl_int_set_si(bmap->ineq[k][1 + n_in], 1); + isl_seq_cpy(bmap->ineq[k] + 1 + n_in + 1, var->el, n_out); + bmap = isl_basic_map_finalize(bmap); + + n_div = isl_basic_set_dim(dom, isl_dim_div); + dom = isl_basic_set_add_dims(dom, isl_dim_set, 1); + dom = isl_basic_set_extend_constraints(dom, 0, n); + for (i = 0; i < n; ++i) { + k = isl_basic_set_alloc_inequality(dom); + if (k < 0) + goto error; + isl_seq_cpy(dom->ineq[k], cst->row[i], 1 + n_in); + isl_int_set_si(dom->ineq[k][1 + n_in], -1); + isl_seq_clr(dom->ineq[k] + 1 + n_in + 1, n_div); + } + + isl_vec_free(var); + free(list); + + return SF(basic_map_partial_lexopt_symm_core,SUFFIX)(bmap, dom, empty, + max, cst, map_space, set_space); +error: + isl_space_free(map_space); + isl_space_free(set_space); + isl_mat_free(cst); + isl_vec_free(var); + free(list); + isl_basic_set_free(dom); + isl_basic_map_free(bmap); + return NULL; +} + +/* Recursive part of isl_tab_basic_map_partial_lexopt*, after detecting + * equalities and removing redundant constraints. + * + * We first check if there are any parallel constraints (left). + * If not, we are in the base case. + * If there are parallel constraints, we replace them by a single + * constraint in basic_map_partial_lexopt_symm_pma and then call + * this function recursively to look for more parallel constraints. + */ +static __isl_give TYPE *SF(basic_map_partial_lexopt,SUFFIX)( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max) +{ + isl_bool par = isl_bool_false; + int first, second; + + if (!bmap) + goto error; + + if (bmap->ctx->opt->pip_symmetry) + par = parallel_constraints(bmap, &first, &second); + if (par < 0) + goto error; + if (!par) + return SF(basic_map_partial_lexopt_base,SUFFIX)(bmap, dom, + empty, max); + + return SF(basic_map_partial_lexopt_symm,SUFFIX)(bmap, dom, empty, max, + first, second); +error: + isl_basic_set_free(dom); + isl_basic_map_free(bmap); + return NULL; +} + +/* Compute the lexicographic minimum (or maximum if "flags" includes + * ISL_OPT_MAX) of "bmap" over the domain "dom" and return the result as + * either a map or a piecewise multi-affine expression depending on TYPE. + * If "empty" is not NULL, then *empty is assigned a set that + * contains those parts of the domain where there is no solution. + * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum + * should be computed over the domain of "bmap". "empty" is also NULL + * in this case. + * If "bmap" is marked as rational (ISL_BASIC_MAP_RATIONAL), + * then we compute the rational optimum. Otherwise, we compute + * the integral optimum. + * + * We perform some preprocessing. As the PILP solver does not + * handle implicit equalities very well, we first make sure all + * the equalities are explicitly available. + * + * We also add context constraints to the basic map and remove + * redundant constraints. This is only needed because of the + * way we handle simple symmetries. In particular, we currently look + * for symmetries on the constraints, before we set up the main tableau. + * It is then no good to look for symmetries on possibly redundant constraints. + * If the domain was extracted from the basic map, then there is + * no need to add back those constraints again. + */ +__isl_give TYPE *SF(isl_tab_basic_map_partial_lexopt,SUFFIX)( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, unsigned flags) +{ + int max, full; + isl_bool compatible; + + if (empty) + *empty = NULL; + + full = ISL_FL_ISSET(flags, ISL_OPT_FULL); + if (full) + dom = extract_domain(bmap, flags); + compatible = isl_basic_map_compatible_domain(bmap, dom); + if (compatible < 0) + goto error; + if (!compatible) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "domain does not match input", goto error); + + max = ISL_FL_ISSET(flags, ISL_OPT_MAX); + if (isl_basic_set_dim(dom, isl_dim_all) == 0) + return SF(basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty, + max); + + if (!full) + 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); + + return SF(basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty, max); +error: + isl_basic_set_free(dom); + isl_basic_map_free(bmap); + return NULL; +} Index: contrib/isl/isl_tab_pip.c =================================================================== --- /dev/null +++ contrib/isl/isl_tab_pip.c @@ -0,0 +1,5950 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2016-2017 Sven Verdoolaege + * + * Use of this software is governed by the MIT 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 +#include "isl_map_private.h" +#include +#include "isl_tab.h" +#include "isl_sample.h" +#include +#include +#include +#include +#include +#include + +#include + +/* + * The implementation of parametric integer linear programming in this file + * was inspired by the paper "Parametric Integer Programming" and the + * report "Solving systems of affine (in)equalities" by Paul Feautrier + * (and others). + * + * 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 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, + * choosing a column that induces the lexicographically smallest + * increment to the sample solution. + * + * By starting out from a sample value that is lexicographically + * smaller than any integer point in the problem space, the first + * feasible integer sample point we find will also be the lexicographically + * smallest. If all variables can be assumed to be non-negative, + * then the initial sample value may be chosen equal to zero. + * However, we will not make this assumption. Instead, we apply + * the "big parameter" trick. Any variable x is then not directly + * used in the tableau, but instead it is represented by another + * variable x' = M + x, where M is an arbitrarily large (positive) + * value. x' is therefore always non-negative, whatever the value of x. + * Taking as initial sample value x' = 0 corresponds to x = -M, + * which is always smaller than any possible value of x. + * + * The big parameter trick is used in the main tableau and + * also in the context tableau if isl_context_lex is used. + * In this case, each tableaus has its own big parameter. + * Before doing any real work, we check if all the parameters + * happen to be non-negative. If so, we drop the column corresponding + * to M from the initial context tableau. + * If isl_context_gbr is used, then the big parameter trick is only + * used in the main tableau. + */ + +struct isl_context; +struct isl_context_op { + /* detect nonnegative parameters in context and mark them in tab */ + struct isl_tab *(*detect_nonnegative_parameters)( + struct isl_context *context, struct isl_tab *tab); + /* return temporary reference to basic set representation of context */ + struct isl_basic_set *(*peek_basic_set)(struct isl_context *context); + /* return temporary reference to tableau representation of context */ + struct isl_tab *(*peek_tab)(struct isl_context *context); + /* add equality; check is 1 if eq may not be valid; + * update is 1 if we may want to call ineq_sign on context later. + */ + void (*add_eq)(struct isl_context *context, isl_int *eq, + int check, int update); + /* add inequality; check is 1 if ineq may not be valid; + * update is 1 if we may want to call ineq_sign on context later. + */ + void (*add_ineq)(struct isl_context *context, isl_int *ineq, + int check, int update); + /* check sign of ineq based on previous information. + * strict is 1 if saturation should be treated as a positive sign. + */ + enum isl_tab_row_sign (*ineq_sign)(struct isl_context *context, + isl_int *ineq, int strict); + /* check if inequality maintains feasibility */ + int (*test_ineq)(struct isl_context *context, isl_int *ineq); + /* return index of a div that corresponds to "div" */ + int (*get_div)(struct isl_context *context, struct isl_tab *tab, + struct isl_vec *div); + /* insert div "div" to context at "pos" and return non-negativity */ + isl_bool (*insert_div)(struct isl_context *context, int pos, + __isl_keep isl_vec *div); + int (*detect_equalities)(struct isl_context *context, + struct isl_tab *tab); + /* return row index of "best" split */ + int (*best_split)(struct isl_context *context, struct isl_tab *tab); + /* check if context has already been determined to be empty */ + int (*is_empty)(struct isl_context *context); + /* check if context is still usable */ + int (*is_ok)(struct isl_context *context); + /* save a copy/snapshot of context */ + void *(*save)(struct isl_context *context); + /* restore saved context */ + void (*restore)(struct isl_context *context, void *); + /* discard saved context */ + void (*discard)(void *); + /* invalidate context */ + void (*invalidate)(struct isl_context *context); + /* free context */ + __isl_null struct isl_context *(*free)(struct isl_context *context); +}; + +/* Shared parts of context representation. + * + * "n_unknown" is the number of final unknown integer divisions + * in the input domain. + */ +struct isl_context { + struct isl_context_op *op; + int n_unknown; +}; + +struct isl_context_lex { + struct isl_context context; + struct isl_tab *tab; +}; + +/* A stack (linked list) of solutions of subtrees of the search space. + * + * "ma" describes the solution as a function of "dom". + * In particular, the domain space of "ma" is equal to the space of "dom". + * + * If "ma" is NULL, then there is no solution on "dom". + */ +struct isl_partial_sol { + int level; + struct isl_basic_set *dom; + isl_multi_aff *ma; + + struct isl_partial_sol *next; +}; + +struct isl_sol; +struct isl_sol_callback { + struct isl_tab_callback callback; + struct isl_sol *sol; +}; + +/* isl_sol is an interface for constructing a solution to + * a parametric integer linear programming problem. + * Every time the algorithm reaches a state where a solution + * can be read off from the tableau, the function "add" is called + * on the isl_sol passed to find_solutions_main. In a state where + * the tableau is empty, "add_empty" is called instead. + * "free" is called to free the implementation specific fields, if any. + * + * "error" is set if some error has occurred. This flag invalidates + * the remainder of the data structure. + * If "rational" is set, then a rational optimization is being performed. + * "level" is the current level in the tree with nodes for each + * split in the context. + * If "max" is set, then a maximization problem is being solved, rather than + * a minimization problem, which means that the variables in the + * tableau have value "M - x" rather than "M + x". + * "n_out" is the number of output dimensions in the input. + * "space" is the space in which the solution (and also the input) lives. + * + * The context tableau is owned by isl_sol and is updated incrementally. + * + * There are currently two implementations of this interface, + * isl_sol_map, which simply collects the solutions in an isl_map + * and (optionally) the parts of the context where there is no solution + * in an isl_set, and + * isl_sol_pma, which collects an isl_pw_multi_aff instead. + */ +struct isl_sol { + int error; + int rational; + int level; + int max; + int n_out; + isl_space *space; + struct isl_context *context; + struct isl_partial_sol *partial; + void (*add)(struct isl_sol *sol, + __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma); + void (*add_empty)(struct isl_sol *sol, struct isl_basic_set *bset); + void (*free)(struct isl_sol *sol); + struct isl_sol_callback dec_level; +}; + +static void sol_free(struct isl_sol *sol) +{ + struct isl_partial_sol *partial, *next; + if (!sol) + return; + for (partial = sol->partial; partial; partial = next) { + next = partial->next; + isl_basic_set_free(partial->dom); + isl_multi_aff_free(partial->ma); + free(partial); + } + isl_space_free(sol->space); + if (sol->context) + sol->context->op->free(sol->context); + sol->free(sol); + free(sol); +} + +/* Push a partial solution represented by a domain and function "ma" + * onto the stack of partial solutions. + * If "ma" is NULL, then "dom" represents a part of the domain + * with no solution. + */ +static void sol_push_sol(struct isl_sol *sol, + __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma) +{ + struct isl_partial_sol *partial; + + if (sol->error || !dom) + goto error; + + partial = isl_alloc_type(dom->ctx, struct isl_partial_sol); + if (!partial) + goto error; + + partial->level = sol->level; + partial->dom = dom; + partial->ma = ma; + partial->next = sol->partial; + + sol->partial = partial; + + return; +error: + isl_basic_set_free(dom); + isl_multi_aff_free(ma); + sol->error = 1; +} + +/* Check that the final columns of "M", starting at "first", are zero. + */ +static isl_stat check_final_columns_are_zero(__isl_keep isl_mat *M, + unsigned first) +{ + int i; + unsigned rows, cols, n; + + if (!M) + return isl_stat_error; + rows = isl_mat_rows(M); + cols = isl_mat_cols(M); + n = cols - first; + for (i = 0; i < rows; ++i) + if (isl_seq_first_non_zero(M->row[i] + first, n) != -1) + isl_die(isl_mat_get_ctx(M), isl_error_internal, + "final columns should be zero", + return isl_stat_error); + return isl_stat_ok; +} + +/* Set the affine expressions in "ma" according to the rows in "M", which + * are defined over the local space "ls". + * The matrix "M" may have extra (zero) columns beyond the number + * of variables in "ls". + */ +static __isl_give isl_multi_aff *set_from_affine_matrix( + __isl_take isl_multi_aff *ma, __isl_take isl_local_space *ls, + __isl_take isl_mat *M) +{ + int i, dim; + isl_aff *aff; + + if (!ma || !ls || !M) + goto error; + + dim = isl_local_space_dim(ls, isl_dim_all); + if (check_final_columns_are_zero(M, 1 + dim) < 0) + goto error; + for (i = 1; i < M->n_row; ++i) { + aff = isl_aff_alloc(isl_local_space_copy(ls)); + if (aff) { + isl_int_set(aff->v->el[0], M->row[0][0]); + isl_seq_cpy(aff->v->el + 1, M->row[i], 1 + dim); + } + aff = isl_aff_normalize(aff); + ma = isl_multi_aff_set_aff(ma, i - 1, aff); + } + isl_local_space_free(ls); + isl_mat_free(M); + + return ma; +error: + isl_local_space_free(ls); + isl_mat_free(M); + isl_multi_aff_free(ma); + return NULL; +} + +/* Push a partial solution represented by a domain and mapping M + * onto the stack of partial solutions. + * + * The affine matrix "M" maps the dimensions of the context + * to the output variables. Convert it into an isl_multi_aff and + * then call sol_push_sol. + * + * Note that the description of the initial context may have involved + * existentially quantified variables, in which case they also appear + * in "dom". These need to be removed before creating the affine + * expression because an affine expression cannot be defined in terms + * of existentially quantified variables without a known representation. + * Since newly added integer divisions are inserted before these + * existentially quantified variables, they are still in the final + * positions and the corresponding final columns of "M" are zero + * because align_context_divs adds the existentially quantified + * variables of the context to the main tableau without any constraints and + * any equality constraints that are added later on can only serve + * to eliminate these existentially quantified variables. + */ +static void sol_push_sol_mat(struct isl_sol *sol, + __isl_take isl_basic_set *dom, __isl_take isl_mat *M) +{ + isl_local_space *ls; + isl_multi_aff *ma; + int n_div, n_known; + + n_div = isl_basic_set_dim(dom, isl_dim_div); + n_known = n_div - sol->context->n_unknown; + + ma = isl_multi_aff_alloc(isl_space_copy(sol->space)); + ls = isl_basic_set_get_local_space(dom); + ls = isl_local_space_drop_dims(ls, isl_dim_div, + n_known, n_div - n_known); + ma = set_from_affine_matrix(ma, ls, M); + + if (!ma) + dom = isl_basic_set_free(dom); + sol_push_sol(sol, dom, ma); +} + +/* Pop one partial solution from the partial solution stack and + * pass it on to sol->add or sol->add_empty. + */ +static void sol_pop_one(struct isl_sol *sol) +{ + struct isl_partial_sol *partial; + + partial = sol->partial; + sol->partial = partial->next; + + if (partial->ma) + sol->add(sol, partial->dom, partial->ma); + else + sol->add_empty(sol, partial->dom); + free(partial); +} + +/* Return a fresh copy of the domain represented by the context tableau. + */ +static struct isl_basic_set *sol_domain(struct isl_sol *sol) +{ + struct isl_basic_set *bset; + + if (sol->error) + return NULL; + + bset = isl_basic_set_dup(sol->context->op->peek_basic_set(sol->context)); + bset = isl_basic_set_update_from_tab(bset, + sol->context->op->peek_tab(sol->context)); + + return bset; +} + +/* Check whether two partial solutions have the same affine expressions. + */ +static isl_bool same_solution(struct isl_partial_sol *s1, + struct isl_partial_sol *s2) +{ + if (!s1->ma != !s2->ma) + return isl_bool_false; + if (!s1->ma) + return isl_bool_true; + + return isl_multi_aff_plain_is_equal(s1->ma, s2->ma); +} + +/* Swap the initial two partial solutions in "sol". + * + * That is, go from + * + * sol->partial = p1; p1->next = p2; p2->next = p3 + * + * to + * + * sol->partial = p2; p2->next = p1; p1->next = p3 + */ +static void swap_initial(struct isl_sol *sol) +{ + struct isl_partial_sol *partial; + + partial = sol->partial; + sol->partial = partial->next; + partial->next = partial->next->next; + sol->partial->next = partial; +} + +/* Combine the initial two partial solution of "sol" into + * a partial solution with the current context domain of "sol" and + * the function description of the second partial solution in the list. + * The level of the new partial solution is set to the current level. + * + * That is, the first two partial solutions (D1,M1) and (D2,M2) are + * replaced by (D,M2), where D is the domain of "sol", which is assumed + * to be the union of D1 and D2, while M1 is assumed to be equal to M2 + * (at least on D1). + */ +static isl_stat combine_initial_into_second(struct isl_sol *sol) +{ + struct isl_partial_sol *partial; + isl_basic_set *bset; + + partial = sol->partial; + + bset = sol_domain(sol); + isl_basic_set_free(partial->next->dom); + partial->next->dom = bset; + partial->next->level = sol->level; + + if (!bset) + return isl_stat_error; + + sol->partial = partial->next; + isl_basic_set_free(partial->dom); + isl_multi_aff_free(partial->ma); + free(partial); + + return isl_stat_ok; +} + +/* Are "ma1" and "ma2" equal to each other on "dom"? + * + * Combine "ma1" and "ma2" with "dom" and check if the results are the same. + * "dom" may have existentially quantified variables. Eliminate them first + * as otherwise they would have to be eliminated twice, in a more complicated + * context. + */ +static isl_bool equal_on_domain(__isl_keep isl_multi_aff *ma1, + __isl_keep isl_multi_aff *ma2, __isl_keep isl_basic_set *dom) +{ + isl_set *set; + isl_pw_multi_aff *pma1, *pma2; + isl_bool equal; + + set = isl_basic_set_compute_divs(isl_basic_set_copy(dom)); + pma1 = isl_pw_multi_aff_alloc(isl_set_copy(set), + isl_multi_aff_copy(ma1)); + pma2 = isl_pw_multi_aff_alloc(set, isl_multi_aff_copy(ma2)); + equal = isl_pw_multi_aff_is_equal(pma1, pma2); + isl_pw_multi_aff_free(pma1); + isl_pw_multi_aff_free(pma2); + + return equal; +} + +/* The initial two partial solutions of "sol" are known to be at + * the same level. + * If they represent the same solution (on different parts of the domain), + * then combine them into a single solution at the current level. + * Otherwise, pop them both. + * + * Even if the two partial solution are not obviously the same, + * one may still be a simplification of the other over its own domain. + * Also check if the two sets of affine functions are equal when + * restricted to one of the domains. If so, combine the two + * using the set of affine functions on the other domain. + * That is, for two partial solutions (D1,M1) and (D2,M2), + * if M1 = M2 on D1, then the pair of partial solutions can + * be replaced by (D1+D2,M2) and similarly when M1 = M2 on D2. + */ +static isl_stat combine_initial_if_equal(struct isl_sol *sol) +{ + struct isl_partial_sol *partial; + isl_bool same; + + partial = sol->partial; + + same = same_solution(partial, partial->next); + if (same < 0) + return isl_stat_error; + if (same) + return combine_initial_into_second(sol); + if (partial->ma && partial->next->ma) { + same = equal_on_domain(partial->ma, partial->next->ma, + partial->dom); + if (same < 0) + return isl_stat_error; + if (same) + return combine_initial_into_second(sol); + same = equal_on_domain(partial->ma, partial->next->ma, + partial->next->dom); + if (same) { + swap_initial(sol); + return combine_initial_into_second(sol); + } + } + + sol_pop_one(sol); + sol_pop_one(sol); + + return isl_stat_ok; +} + +/* Pop all solutions from the partial solution stack that were pushed onto + * the stack at levels that are deeper than the current level. + * If the two topmost elements on the stack have the same level + * and represent the same solution, then their domains are combined. + * This combined domain is the same as the current context domain + * as sol_pop is called each time we move back to a higher level. + * If the outer level (0) has been reached, then all partial solutions + * at the current level are also popped off. + */ +static void sol_pop(struct isl_sol *sol) +{ + struct isl_partial_sol *partial; + + if (sol->error) + return; + + partial = sol->partial; + if (!partial) + return; + + if (partial->level == 0 && sol->level == 0) { + for (partial = sol->partial; partial; partial = sol->partial) + sol_pop_one(sol); + return; + } + + if (partial->level <= sol->level) + return; + + if (partial->next && partial->next->level == partial->level) { + if (combine_initial_if_equal(sol) < 0) + goto error; + } else + sol_pop_one(sol); + + if (sol->level == 0) { + for (partial = sol->partial; partial; partial = sol->partial) + sol_pop_one(sol); + return; + } + + if (0) +error: sol->error = 1; +} + +static void sol_dec_level(struct isl_sol *sol) +{ + if (sol->error) + return; + + sol->level--; + + sol_pop(sol); +} + +static isl_stat sol_dec_level_wrap(struct isl_tab_callback *cb) +{ + struct isl_sol_callback *callback = (struct isl_sol_callback *)cb; + + sol_dec_level(callback->sol); + + return callback->sol->error ? isl_stat_error : isl_stat_ok; +} + +/* Move down to next level and push callback onto context tableau + * to decrease the level again when it gets rolled back across + * the current state. That is, dec_level will be called with + * the context tableau in the same state as it is when inc_level + * is called. + */ +static void sol_inc_level(struct isl_sol *sol) +{ + struct isl_tab *tab; + + if (sol->error) + return; + + sol->level++; + tab = sol->context->op->peek_tab(sol->context); + if (isl_tab_push_callback(tab, &sol->dec_level.callback) < 0) + sol->error = 1; +} + +static void scale_rows(struct isl_mat *mat, isl_int m, int n_row) +{ + int i; + + if (isl_int_is_one(m)) + return; + + for (i = 0; i < n_row; ++i) + isl_seq_scale(mat->row[i], mat->row[i], m, mat->n_col); +} + +/* Add the solution identified by the tableau and the context tableau. + * + * The layout of the variables is as follows. + * tab->n_var is equal to the total number of variables in the input + * map (including divs that were copied from the context) + * + the number of extra divs constructed + * Of these, the first tab->n_param and the last tab->n_div variables + * correspond to the variables in the context, i.e., + * tab->n_param + tab->n_div = context_tab->n_var + * tab->n_param is equal to the number of parameters and input + * dimensions in the input map + * tab->n_div is equal to the number of divs in the context + * + * If there is no solution, then call add_empty with a basic set + * that corresponds to the context tableau. (If add_empty is NULL, + * then do nothing). + * + * If there is a solution, then first construct a matrix that maps + * all dimensions of the context to the output variables, i.e., + * the output dimensions in the input map. + * The divs in the input map (if any) that do not correspond to any + * div in the context do not appear in the solution. + * The algorithm will make sure that they have an integer value, + * but these values themselves are of no interest. + * We have to be careful not to drop or rearrange any divs in the + * context because that would change the meaning of the matrix. + * + * To extract the value of the output variables, it should be noted + * that we always use a big parameter M in the main tableau and so + * the variable stored in this tableau is not an output variable x itself, but + * x' = M + x (in case of minimization) + * or + * x' = M - x (in case of maximization) + * If x' appears in a column, then its optimal value is zero, + * which means that the optimal value of x is an unbounded number + * (-M for minimization and M for maximization). + * We currently assume that the output dimensions in the original map + * are bounded, so this cannot occur. + * Similarly, when x' appears in a row, then the coefficient of M in that + * row is necessarily 1. + * If the row in the tableau represents + * d x' = c + d M + e(y) + * then, in case of minimization, the corresponding row in the matrix + * will be + * a c + a e(y) + * with a d = m, the (updated) common denominator of the matrix. + * In case of maximization, the row will be + * -a c - a e(y) + */ +static void sol_add(struct isl_sol *sol, struct isl_tab *tab) +{ + struct isl_basic_set *bset = NULL; + struct isl_mat *mat = NULL; + unsigned off; + int row; + isl_int m; + + if (sol->error || !tab) + goto error; + + if (tab->empty && !sol->add_empty) + return; + if (sol->context->op->is_empty(sol->context)) + return; + + bset = sol_domain(sol); + + if (tab->empty) { + sol_push_sol(sol, bset, NULL); + return; + } + + off = 2 + tab->M; + + mat = isl_mat_alloc(tab->mat->ctx, 1 + sol->n_out, + 1 + tab->n_param + tab->n_div); + if (!mat) + goto error; + + isl_int_init(m); + + isl_seq_clr(mat->row[0] + 1, mat->n_col - 1); + isl_int_set_si(mat->row[0][0], 1); + for (row = 0; row < sol->n_out; ++row) { + int i = tab->n_param + row; + int r, j; + + isl_seq_clr(mat->row[1 + row], mat->n_col); + if (!tab->var[i].is_row) { + if (tab->M) + isl_die(mat->ctx, isl_error_invalid, + "unbounded optimum", goto error2); + continue; + } + + r = tab->var[i].index; + if (tab->M && + isl_int_ne(tab->mat->row[r][2], tab->mat->row[r][0])) + isl_die(mat->ctx, isl_error_invalid, + "unbounded optimum", goto error2); + isl_int_gcd(m, mat->row[0][0], tab->mat->row[r][0]); + isl_int_divexact(m, tab->mat->row[r][0], m); + scale_rows(mat, m, 1 + row); + isl_int_divexact(m, mat->row[0][0], tab->mat->row[r][0]); + isl_int_mul(mat->row[1 + row][0], m, tab->mat->row[r][1]); + for (j = 0; j < tab->n_param; ++j) { + int col; + if (tab->var[j].is_row) + continue; + col = tab->var[j].index; + isl_int_mul(mat->row[1 + row][1 + j], m, + tab->mat->row[r][off + col]); + } + for (j = 0; j < tab->n_div; ++j) { + int col; + if (tab->var[tab->n_var - tab->n_div+j].is_row) + continue; + col = tab->var[tab->n_var - tab->n_div+j].index; + isl_int_mul(mat->row[1 + row][1 + tab->n_param + j], m, + tab->mat->row[r][off + col]); + } + if (sol->max) + isl_seq_neg(mat->row[1 + row], mat->row[1 + row], + mat->n_col); + } + + isl_int_clear(m); + + sol_push_sol_mat(sol, bset, mat); + return; +error2: + isl_int_clear(m); +error: + isl_basic_set_free(bset); + isl_mat_free(mat); + sol->error = 1; +} + +struct isl_sol_map { + struct isl_sol sol; + struct isl_map *map; + struct isl_set *empty; +}; + +static void sol_map_free(struct isl_sol *sol) +{ + struct isl_sol_map *sol_map = (struct isl_sol_map *) sol; + isl_map_free(sol_map->map); + isl_set_free(sol_map->empty); +} + +/* This function is called for parts of the context where there is + * no solution, with "bset" corresponding to the context tableau. + * Simply add the basic set to the set "empty". + */ +static void sol_map_add_empty(struct isl_sol_map *sol, + struct isl_basic_set *bset) +{ + if (!bset || !sol->empty) + goto error; + + sol->empty = isl_set_grow(sol->empty, 1); + bset = isl_basic_set_simplify(bset); + bset = isl_basic_set_finalize(bset); + sol->empty = isl_set_add_basic_set(sol->empty, isl_basic_set_copy(bset)); + if (!sol->empty) + goto error; + isl_basic_set_free(bset); + return; +error: + isl_basic_set_free(bset); + sol->sol.error = 1; +} + +static void sol_map_add_empty_wrap(struct isl_sol *sol, + struct isl_basic_set *bset) +{ + sol_map_add_empty((struct isl_sol_map *)sol, bset); +} + +/* Given a basic set "dom" that represents the context and a tuple of + * affine expressions "ma" defined over this domain, construct a basic map + * that expresses this function on the domain. + */ +static void sol_map_add(struct isl_sol_map *sol, + __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma) +{ + isl_basic_map *bmap; + + if (sol->sol.error || !dom || !ma) + goto error; + + bmap = isl_basic_map_from_multi_aff2(ma, sol->sol.rational); + bmap = isl_basic_map_intersect_domain(bmap, dom); + sol->map = isl_map_grow(sol->map, 1); + sol->map = isl_map_add_basic_map(sol->map, bmap); + if (!sol->map) + sol->sol.error = 1; + return; +error: + isl_basic_set_free(dom); + isl_multi_aff_free(ma); + sol->sol.error = 1; +} + +static void sol_map_add_wrap(struct isl_sol *sol, + __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma) +{ + sol_map_add((struct isl_sol_map *)sol, dom, ma); +} + + +/* Store the "parametric constant" of row "row" of tableau "tab" in "line", + * i.e., the constant term and the coefficients of all variables that + * appear in the context tableau. + * Note that the coefficient of the big parameter M is NOT copied. + * The context tableau may not have a big parameter and even when it + * does, it is a different big parameter. + */ +static void get_row_parameter_line(struct isl_tab *tab, int row, isl_int *line) +{ + int i; + unsigned off = 2 + tab->M; + + isl_int_set(line[0], tab->mat->row[row][1]); + for (i = 0; i < tab->n_param; ++i) { + if (tab->var[i].is_row) + isl_int_set_si(line[1 + i], 0); + else { + int col = tab->var[i].index; + isl_int_set(line[1 + i], tab->mat->row[row][off + col]); + } + } + for (i = 0; i < tab->n_div; ++i) { + if (tab->var[tab->n_var - tab->n_div + i].is_row) + isl_int_set_si(line[1 + tab->n_param + i], 0); + else { + int col = tab->var[tab->n_var - tab->n_div + i].index; + isl_int_set(line[1 + tab->n_param + i], + tab->mat->row[row][off + col]); + } + } +} + +/* Check if rows "row1" and "row2" have identical "parametric constants", + * as explained above. + * In this case, we also insist that the coefficients of the big parameter + * be the same as the values of the constants will only be the same + * if these coefficients are also the same. + */ +static int identical_parameter_line(struct isl_tab *tab, int row1, int row2) +{ + int i; + unsigned off = 2 + tab->M; + + if (isl_int_ne(tab->mat->row[row1][1], tab->mat->row[row2][1])) + return 0; + + if (tab->M && isl_int_ne(tab->mat->row[row1][2], + tab->mat->row[row2][2])) + return 0; + + for (i = 0; i < tab->n_param + tab->n_div; ++i) { + int pos = i < tab->n_param ? i : + tab->n_var - tab->n_div + i - tab->n_param; + int col; + + if (tab->var[pos].is_row) + continue; + col = tab->var[pos].index; + if (isl_int_ne(tab->mat->row[row1][off + col], + tab->mat->row[row2][off + col])) + return 0; + } + return 1; +} + +/* Return an inequality that expresses that the "parametric constant" + * should be non-negative. + * This function is only called when the coefficient of the big parameter + * is equal to zero. + */ +static struct isl_vec *get_row_parameter_ineq(struct isl_tab *tab, int row) +{ + struct isl_vec *ineq; + + ineq = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_param + tab->n_div); + if (!ineq) + return NULL; + + get_row_parameter_line(tab, row, ineq->el); + if (ineq) + ineq = isl_vec_normalize(ineq); + + return ineq; +} + +/* Normalize a div expression of the form + * + * [(g*f(x) + c)/(g * m)] + * + * with c the constant term and f(x) the remaining coefficients, to + * + * [(f(x) + [c/g])/m] + */ +static void normalize_div(__isl_keep isl_vec *div) +{ + isl_ctx *ctx = isl_vec_get_ctx(div); + int len = div->size - 2; + + isl_seq_gcd(div->el + 2, len, &ctx->normalize_gcd); + isl_int_gcd(ctx->normalize_gcd, ctx->normalize_gcd, div->el[0]); + + if (isl_int_is_one(ctx->normalize_gcd)) + return; + + isl_int_divexact(div->el[0], div->el[0], ctx->normalize_gcd); + isl_int_fdiv_q(div->el[1], div->el[1], ctx->normalize_gcd); + isl_seq_scale_down(div->el + 2, div->el + 2, ctx->normalize_gcd, len); +} + +/* Return an integer division for use in a parametric cut based + * on the given row. + * In particular, let the parametric constant of the row be + * + * \sum_i a_i y_i + * + * where y_0 = 1, but none of the y_i corresponds to the big parameter M. + * The div returned is equal to + * + * floor(\sum_i {-a_i} y_i) = floor((\sum_i (-a_i mod d) y_i)/d) + */ +static struct isl_vec *get_row_parameter_div(struct isl_tab *tab, int row) +{ + struct isl_vec *div; + + div = isl_vec_alloc(tab->mat->ctx, 1 + 1 + tab->n_param + tab->n_div); + if (!div) + return NULL; + + isl_int_set(div->el[0], tab->mat->row[row][0]); + get_row_parameter_line(tab, row, div->el + 1); + isl_seq_neg(div->el + 1, div->el + 1, div->size - 1); + normalize_div(div); + isl_seq_fdiv_r(div->el + 1, div->el + 1, div->el[0], div->size - 1); + + return div; +} + +/* Return an integer division for use in transferring an integrality constraint + * to the context. + * In particular, let the parametric constant of the row be + * + * \sum_i a_i y_i + * + * where y_0 = 1, but none of the y_i corresponds to the big parameter M. + * The the returned div is equal to + * + * floor(\sum_i {a_i} y_i) = floor((\sum_i (a_i mod d) y_i)/d) + */ +static struct isl_vec *get_row_split_div(struct isl_tab *tab, int row) +{ + struct isl_vec *div; + + div = isl_vec_alloc(tab->mat->ctx, 1 + 1 + tab->n_param + tab->n_div); + if (!div) + return NULL; + + isl_int_set(div->el[0], tab->mat->row[row][0]); + get_row_parameter_line(tab, row, div->el + 1); + normalize_div(div); + isl_seq_fdiv_r(div->el + 1, div->el + 1, div->el[0], div->size - 1); + + return div; +} + +/* Construct and return an inequality that expresses an upper bound + * on the given div. + * In particular, if the div is given by + * + * d = floor(e/m) + * + * then the inequality expresses + * + * m d <= e + */ +static __isl_give isl_vec *ineq_for_div(__isl_keep isl_basic_set *bset, + unsigned div) +{ + unsigned total; + unsigned div_pos; + struct isl_vec *ineq; + + if (!bset) + return NULL; + + total = isl_basic_set_total_dim(bset); + div_pos = 1 + total - bset->n_div + div; + + ineq = isl_vec_alloc(bset->ctx, 1 + total); + if (!ineq) + return NULL; + + isl_seq_cpy(ineq->el, bset->div[div] + 1, 1 + total); + isl_int_neg(ineq->el[div_pos], bset->div[div][0]); + return ineq; +} + +/* Given a row in the tableau and a div that was created + * using get_row_split_div and that has been constrained to equality, i.e., + * + * d = floor(\sum_i {a_i} y_i) = \sum_i {a_i} y_i + * + * replace the expression "\sum_i {a_i} y_i" in the row by d, + * i.e., we subtract "\sum_i {a_i} y_i" and add 1 d. + * The coefficients of the non-parameters in the tableau have been + * verified to be integral. We can therefore simply replace coefficient b + * by floor(b). For the coefficients of the parameters we have + * floor(a_i) = a_i - {a_i}, while for the other coefficients, we have + * floor(b) = b. + */ +static struct isl_tab *set_row_cst_to_div(struct isl_tab *tab, int row, int div) +{ + isl_seq_fdiv_q(tab->mat->row[row] + 1, tab->mat->row[row] + 1, + tab->mat->row[row][0], 1 + tab->M + tab->n_col); + + isl_int_set_si(tab->mat->row[row][0], 1); + + if (tab->var[tab->n_var - tab->n_div + div].is_row) { + int drow = tab->var[tab->n_var - tab->n_div + div].index; + + isl_assert(tab->mat->ctx, + isl_int_is_one(tab->mat->row[drow][0]), goto error); + isl_seq_combine(tab->mat->row[row] + 1, + tab->mat->ctx->one, tab->mat->row[row] + 1, + tab->mat->ctx->one, tab->mat->row[drow] + 1, + 1 + tab->M + tab->n_col); + } else { + int dcol = tab->var[tab->n_var - tab->n_div + div].index; + + isl_int_add_ui(tab->mat->row[row][2 + tab->M + dcol], + tab->mat->row[row][2 + tab->M + dcol], 1); + } + + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Check if the (parametric) constant of the given row is obviously + * negative, meaning that we don't need to consult the context tableau. + * If there is a big parameter and its coefficient is non-zero, + * then this coefficient determines the outcome. + * Otherwise, we check whether the constant is negative and + * all non-zero coefficients of parameters are negative and + * belong to non-negative parameters. + */ +static int is_obviously_neg(struct isl_tab *tab, int row) +{ + int i; + int col; + unsigned off = 2 + tab->M; + + if (tab->M) { + if (isl_int_is_pos(tab->mat->row[row][2])) + return 0; + if (isl_int_is_neg(tab->mat->row[row][2])) + return 1; + } + + if (isl_int_is_nonneg(tab->mat->row[row][1])) + return 0; + for (i = 0; i < tab->n_param; ++i) { + /* Eliminated parameter */ + if (tab->var[i].is_row) + continue; + col = tab->var[i].index; + if (isl_int_is_zero(tab->mat->row[row][off + col])) + continue; + if (!tab->var[i].is_nonneg) + return 0; + if (isl_int_is_pos(tab->mat->row[row][off + col])) + return 0; + } + for (i = 0; i < tab->n_div; ++i) { + if (tab->var[tab->n_var - tab->n_div + i].is_row) + continue; + col = tab->var[tab->n_var - tab->n_div + i].index; + if (isl_int_is_zero(tab->mat->row[row][off + col])) + continue; + if (!tab->var[tab->n_var - tab->n_div + i].is_nonneg) + return 0; + if (isl_int_is_pos(tab->mat->row[row][off + col])) + return 0; + } + return 1; +} + +/* Check if the (parametric) constant of the given row is obviously + * non-negative, meaning that we don't need to consult the context tableau. + * If there is a big parameter and its coefficient is non-zero, + * then this coefficient determines the outcome. + * Otherwise, we check whether the constant is non-negative and + * all non-zero coefficients of parameters are positive and + * belong to non-negative parameters. + */ +static int is_obviously_nonneg(struct isl_tab *tab, int row) +{ + int i; + int col; + unsigned off = 2 + tab->M; + + if (tab->M) { + if (isl_int_is_pos(tab->mat->row[row][2])) + return 1; + if (isl_int_is_neg(tab->mat->row[row][2])) + return 0; + } + + if (isl_int_is_neg(tab->mat->row[row][1])) + return 0; + for (i = 0; i < tab->n_param; ++i) { + /* Eliminated parameter */ + if (tab->var[i].is_row) + continue; + col = tab->var[i].index; + if (isl_int_is_zero(tab->mat->row[row][off + col])) + continue; + if (!tab->var[i].is_nonneg) + return 0; + if (isl_int_is_neg(tab->mat->row[row][off + col])) + return 0; + } + for (i = 0; i < tab->n_div; ++i) { + if (tab->var[tab->n_var - tab->n_div + i].is_row) + continue; + col = tab->var[tab->n_var - tab->n_div + i].index; + if (isl_int_is_zero(tab->mat->row[row][off + col])) + continue; + if (!tab->var[tab->n_var - tab->n_div + i].is_nonneg) + return 0; + if (isl_int_is_neg(tab->mat->row[row][off + col])) + return 0; + } + return 1; +} + +/* Given a row r and two columns, return the column that would + * lead to the lexicographically smallest increment in the sample + * solution when leaving the basis in favor of the row. + * Pivoting with column c will increment the sample value by a non-negative + * constant times a_{V,c}/a_{r,c}, with a_{V,c} the elements of column c + * corresponding to the non-parametric variables. + * If variable v appears in a column c_v, the a_{v,c} = 1 iff c = c_v, + * with all other entries in this virtual row equal to zero. + * If variable v appears in a row, then a_{v,c} is the element in column c + * of that row. + * + * Let v be the first variable with a_{v,c1}/a_{r,c1} != a_{v,c2}/a_{r,c2}. + * Then if a_{v,c1}/a_{r,c1} < a_{v,c2}/a_{r,c2}, i.e., + * a_{v,c2} a_{r,c1} - a_{v,c1} a_{r,c2} > 0, c1 results in the minimal + * increment. Otherwise, it's c2. + */ +static int lexmin_col_pair(struct isl_tab *tab, + int row, int col1, int col2, isl_int tmp) +{ + int i; + isl_int *tr; + + tr = tab->mat->row[row] + 2 + tab->M; + + for (i = tab->n_param; i < tab->n_var - tab->n_div; ++i) { + int s1, s2; + isl_int *r; + + if (!tab->var[i].is_row) { + if (tab->var[i].index == col1) + return col2; + if (tab->var[i].index == col2) + return col1; + continue; + } + + if (tab->var[i].index == row) + continue; + + r = tab->mat->row[tab->var[i].index] + 2 + tab->M; + s1 = isl_int_sgn(r[col1]); + s2 = isl_int_sgn(r[col2]); + if (s1 == 0 && s2 == 0) + continue; + if (s1 < s2) + return col1; + if (s2 < s1) + return col2; + + isl_int_mul(tmp, r[col2], tr[col1]); + isl_int_submul(tmp, r[col1], tr[col2]); + if (isl_int_is_pos(tmp)) + return col1; + if (isl_int_is_neg(tmp)) + return col2; + } + return -1; +} + +/* Does the index into the tab->var or tab->con array "index" + * correspond to a variable in the context tableau? + * In particular, it needs to be an index into the tab->var array and + * it needs to refer to either one of the first tab->n_param variables or + * one of the last tab->n_div variables. + */ +static int is_parameter_var(struct isl_tab *tab, int index) +{ + if (index < 0) + return 0; + if (index < tab->n_param) + return 1; + if (index >= tab->n_var - tab->n_div) + return 1; + return 0; +} + +/* Does column "col" of "tab" refer to a variable in the context tableau? + */ +static int col_is_parameter_var(struct isl_tab *tab, int col) +{ + return is_parameter_var(tab, tab->col_var[col]); +} + +/* Does row "row" of "tab" refer to a variable in the context tableau? + */ +static int row_is_parameter_var(struct isl_tab *tab, int row) +{ + return is_parameter_var(tab, tab->row_var[row]); +} + +/* Given a row in the tableau, find and return the column that would + * result in the lexicographically smallest, but positive, increment + * in the sample point. + * If there is no such column, then return tab->n_col. + * If anything goes wrong, return -1. + */ +static int lexmin_pivot_col(struct isl_tab *tab, int row) +{ + int j; + int col = tab->n_col; + isl_int *tr; + isl_int tmp; + + tr = tab->mat->row[row] + 2 + tab->M; + + isl_int_init(tmp); + + for (j = tab->n_dead; j < tab->n_col; ++j) { + if (col_is_parameter_var(tab, j)) + continue; + + if (!isl_int_is_pos(tr[j])) + continue; + + if (col == tab->n_col) + col = j; + else + col = lexmin_col_pair(tab, row, col, j, tmp); + isl_assert(tab->mat->ctx, col >= 0, goto error); + } + + isl_int_clear(tmp); + return col; +error: + isl_int_clear(tmp); + return -1; +} + +/* Return the first known violated constraint, i.e., a non-negative + * constraint that currently has an either obviously negative value + * or a previously determined to be negative value. + * + * If any constraint has a negative coefficient for the big parameter, + * if any, then we return one of these first. + */ +static int first_neg(struct isl_tab *tab) +{ + int row; + + if (tab->M) + for (row = tab->n_redundant; row < tab->n_row; ++row) { + if (!isl_tab_var_from_row(tab, row)->is_nonneg) + continue; + if (!isl_int_is_neg(tab->mat->row[row][2])) + continue; + if (tab->row_sign) + tab->row_sign[row] = isl_tab_row_neg; + return row; + } + for (row = tab->n_redundant; row < tab->n_row; ++row) { + if (!isl_tab_var_from_row(tab, row)->is_nonneg) + continue; + if (tab->row_sign) { + if (tab->row_sign[row] == 0 && + is_obviously_neg(tab, row)) + tab->row_sign[row] = isl_tab_row_neg; + if (tab->row_sign[row] != isl_tab_row_neg) + continue; + } else if (!is_obviously_neg(tab, row)) + continue; + return row; + } + 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) __attribute__ ((unused)); +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 (col_is_parameter_var(tab, col)) + 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 it represents a constraint) and all constraint columns with + * non-zero (and therefore negative) coefficients. + */ +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 (col_is_parameter_var(tab, j)) + 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 int restore_lexmin(struct isl_tab *tab) WARN_UNUSED; +static int restore_lexmin(struct isl_tab *tab) +{ + int row, col; + + if (!tab) + return -1; + if (tab->empty) + 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) + return -1; + return 0; + } + if (col < 0) + return -1; + if (isl_tab_pivot(tab, row, col) < 0) + return -1; + } + return 0; +} + +/* Given a row that represents an equality, look for an appropriate + * pivoting column. + * In particular, if there are any non-zero coefficients among + * the non-parameter variables, then we take the last of these + * variables. Eliminating this variable in terms of the other + * variables and/or parameters does not influence the property + * that all column in the initial tableau are lexicographically + * positive. The row corresponding to the eliminated variable + * will only have non-zero entries below the diagonal of the + * initial tableau. That is, we transform + * + * I I + * 1 into a + * I I + * + * If there is no such non-parameter variable, then we are dealing with + * pure parameter equality and we pick any parameter with coefficient 1 or -1 + * for elimination. This will ensure that the eliminated parameter + * always has an integer value whenever all the other parameters are integral. + * If there is no such parameter then we return -1. + */ +static int last_var_col_or_int_par_col(struct isl_tab *tab, int row) +{ + unsigned off = 2 + tab->M; + int i; + + for (i = tab->n_var - tab->n_div - 1; i >= 0 && i >= tab->n_param; --i) { + int col; + if (tab->var[i].is_row) + continue; + col = tab->var[i].index; + if (col <= tab->n_dead) + continue; + if (!isl_int_is_zero(tab->mat->row[row][off + col])) + return col; + } + for (i = tab->n_dead; i < tab->n_col; ++i) { + if (isl_int_is_one(tab->mat->row[row][off + i])) + return i; + if (isl_int_is_negone(tab->mat->row[row][off + i])) + return i; + } + return -1; +} + +/* Add an equality that is known to be valid to the tableau. + * We first check if we can eliminate a variable or a parameter. + * If not, we add the equality as two inequalities. + * In this case, the equality was a pure parameter equality and there + * is no need to resolve any constraint violations. + * + * This function assumes that at least two more rows and at least + * two more elements in the constraint array are available in the tableau. + */ +static struct isl_tab *add_lexmin_valid_eq(struct isl_tab *tab, isl_int *eq) +{ + int i; + int r; + + if (!tab) + return NULL; + r = isl_tab_add_row(tab, eq); + if (r < 0) + goto error; + + r = tab->con[r].index; + i = last_var_col_or_int_par_col(tab, r); + if (i < 0) { + tab->con[r].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0) + goto error; + isl_seq_neg(eq, eq, 1 + tab->n_var); + r = isl_tab_add_row(tab, eq); + if (r < 0) + goto error; + tab->con[r].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0) + goto error; + } else { + if (isl_tab_pivot(tab, r, i) < 0) + goto error; + if (isl_tab_kill_col(tab, i) < 0) + goto error; + tab->n_eq++; + } + + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Check if the given row is a pure constant. + */ +static int is_constant(struct isl_tab *tab, int row) +{ + unsigned off = 2 + tab->M; + + return isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead, + tab->n_col - tab->n_dead) == -1; +} + +/* Is the given row a parametric constant? + * That is, does it only involve variables that also appear in the context? + */ +static int is_parametric_constant(struct isl_tab *tab, int row) +{ + unsigned off = 2 + tab->M; + int col; + + for (col = tab->n_dead; col < tab->n_col; ++col) { + if (col_is_parameter_var(tab, col)) + continue; + if (isl_int_is_zero(tab->mat->row[row][off + col])) + continue; + return 0; + } + + return 1; +} + +/* Add an equality that may or may not be valid to the tableau. + * If the resulting row is a pure constant, then it must be zero. + * Otherwise, the resulting tableau is empty. + * + * If the row is not a pure constant, then we add two inequalities, + * each time checking that they can be satisfied. + * In the end we try to use one of the two constraints to eliminate + * a column. + * + * This function assumes that at least two more rows and at least + * two more elements in the constraint array are available in the tableau. + */ +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 -1; + snap = isl_tab_snap(tab); + r1 = isl_tab_add_row(tab, eq); + if (r1 < 0) + return -1; + tab->con[r1].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r1]) < 0) + 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) + return -1; + return 0; + } + if (isl_tab_rollback(tab, snap) < 0) + return -1; + return 0; + } + + 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) + return -1; + tab->con[r2].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r2]) < 0) + return -1; + + 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) + return -1; + } else if (!tab->con[r2].is_row) { + if (isl_tab_kill_col(tab, tab->con[r2].index) < 0) + 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) + 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) + return -1; + if (!tab->bmap) + return -1; + } + + return 0; +} + +/* Add an inequality to the tableau, resolving violations using + * restore_lexmin. + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +static struct isl_tab *add_lexmin_ineq(struct isl_tab *tab, isl_int *ineq) +{ + int r; + + if (!tab) + return NULL; + if (tab->bmap) { + tab->bmap = isl_basic_map_add_ineq(tab->bmap, ineq); + if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0) + goto error; + if (!tab->bmap) + goto error; + } + r = isl_tab_add_row(tab, ineq); + if (r < 0) + goto error; + tab->con[r].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0) + goto error; + if (isl_tab_row_is_redundant(tab, tab->con[r].index)) { + if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0) + goto error; + return tab; + } + + 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; + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Check if the coefficients of the parameters are all integral. + */ +static int integer_parameter(struct isl_tab *tab, int row) +{ + int i; + int col; + unsigned off = 2 + tab->M; + + for (i = 0; i < tab->n_param; ++i) { + /* Eliminated parameter */ + if (tab->var[i].is_row) + continue; + col = tab->var[i].index; + if (!isl_int_is_divisible_by(tab->mat->row[row][off + col], + tab->mat->row[row][0])) + return 0; + } + for (i = 0; i < tab->n_div; ++i) { + if (tab->var[tab->n_var - tab->n_div + i].is_row) + continue; + col = tab->var[tab->n_var - tab->n_div + i].index; + if (!isl_int_is_divisible_by(tab->mat->row[row][off + col], + tab->mat->row[row][0])) + return 0; + } + return 1; +} + +/* Check if the coefficients of the non-parameter variables are all integral. + */ +static int integer_variable(struct isl_tab *tab, int row) +{ + int i; + unsigned off = 2 + tab->M; + + for (i = tab->n_dead; i < tab->n_col; ++i) { + if (col_is_parameter_var(tab, i)) + continue; + if (!isl_int_is_divisible_by(tab->mat->row[row][off + i], + tab->mat->row[row][0])) + return 0; + } + return 1; +} + +/* Check if the constant term is integral. + */ +static int integer_constant(struct isl_tab *tab, int row) +{ + return isl_int_is_divisible_by(tab->mat->row[row][1], + tab->mat->row[row][0]); +} + +#define I_CST 1 << 0 +#define I_PAR 1 << 1 +#define I_VAR 1 << 2 + +/* Check for next (non-parameter) variable after "var" (first if var == -1) + * that is non-integer and therefore requires a cut and return + * the index of the variable. + * For parametric tableaus, there are three parts in a row, + * the constant, the coefficients of the parameters and the rest. + * For each part, we check whether the coefficients in that part + * are all integral and if so, set the corresponding flag in *f. + * If the constant and the parameter part are integral, then the + * current sample value is integral and no cut is required + * (irrespective of whether the variable part is integral). + */ +static int next_non_integer_var(struct isl_tab *tab, int var, int *f) +{ + var = var < 0 ? tab->n_param : var + 1; + + for (; var < tab->n_var - tab->n_div; ++var) { + int flags = 0; + int row; + if (!tab->var[var].is_row) + continue; + row = tab->var[var].index; + if (integer_constant(tab, row)) + ISL_FL_SET(flags, I_CST); + if (integer_parameter(tab, row)) + ISL_FL_SET(flags, I_PAR); + if (ISL_FL_ISSET(flags, I_CST) && ISL_FL_ISSET(flags, I_PAR)) + continue; + if (integer_variable(tab, row)) + ISL_FL_SET(flags, I_VAR); + *f = flags; + return var; + } + return -1; +} + +/* Check for first (non-parameter) variable that is non-integer and + * therefore requires a cut and return the corresponding row. + * For parametric tableaus, there are three parts in a row, + * the constant, the coefficients of the parameters and the rest. + * For each part, we check whether the coefficients in that part + * are all integral and if so, set the corresponding flag in *f. + * If the constant and the parameter part are integral, then the + * current sample value is integral and no cut is required + * (irrespective of whether the variable part is integral). + */ +static int first_non_integer_row(struct isl_tab *tab, int *f) +{ + int var = next_non_integer_var(tab, -1, f); + + return var < 0 ? -1 : tab->var[var].index; +} + +/* Add a (non-parametric) cut to cut away the non-integral sample + * value of the given row. + * + * If the row is given by + * + * m r = f + \sum_i a_i y_i + * + * then the cut is + * + * c = - {-f/m} + \sum_i {a_i/m} y_i >= 0 + * + * The big parameter, if any, is ignored, since it is assumed to be big + * enough to be divisible by any integer. + * If the tableau is actually a parametric tableau, then this function + * is only called when all coefficients of the parameters are integral. + * The cut therefore has zero coefficients for the parameters. + * + * The current value is known to be negative, so row_sign, if it + * exists, is set accordingly. + * + * Return the row of the cut or -1. + */ +static int add_cut(struct isl_tab *tab, int row) +{ + int i; + int r; + isl_int *r_row; + unsigned off = 2 + tab->M; + + if (isl_tab_extend_cons(tab, 1) < 0) + return -1; + r = isl_tab_allocate_con(tab); + if (r < 0) + return -1; + + r_row = tab->mat->row[tab->con[r].index]; + isl_int_set(r_row[0], tab->mat->row[row][0]); + isl_int_neg(r_row[1], tab->mat->row[row][1]); + isl_int_fdiv_r(r_row[1], r_row[1], tab->mat->row[row][0]); + isl_int_neg(r_row[1], r_row[1]); + if (tab->M) + isl_int_set_si(r_row[2], 0); + for (i = 0; i < tab->n_col; ++i) + isl_int_fdiv_r(r_row[off + i], + tab->mat->row[row][off + i], tab->mat->row[row][0]); + + tab->con[r].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0) + return -1; + if (tab->row_sign) + tab->row_sign[tab->con[r].index] = isl_tab_row_neg; + + return tab->con[r].index; +} + +#define CUT_ALL 1 +#define CUT_ONE 0 + +/* Given a non-parametric tableau, add cuts until an integer + * sample point is obtained or until the tableau is determined + * to be integer infeasible. + * As long as there is any non-integer value in the sample point, + * we add appropriate cuts, if possible, for each of these + * non-integer values and then resolve the violated + * cut constraints using restore_lexmin. + * If one of the corresponding rows is equal to an integral + * combination of variables/constraints plus a non-integral constant, + * then there is no way to obtain an integer point and we return + * a tableau that is marked empty. + * The parameter cutting_strategy controls the strategy used when adding cuts + * to remove non-integer points. CUT_ALL adds all possible cuts + * before continuing the search. CUT_ONE adds only one cut at a time. + */ +static struct isl_tab *cut_to_integer_lexmin(struct isl_tab *tab, + int cutting_strategy) +{ + int var; + int row; + int flags; + + if (!tab) + return NULL; + if (tab->empty) + return tab; + + while ((var = next_non_integer_var(tab, -1, &flags)) != -1) { + do { + if (ISL_FL_ISSET(flags, I_VAR)) { + if (isl_tab_mark_empty(tab) < 0) + goto error; + return tab; + } + row = tab->var[var].index; + row = add_cut(tab, row); + if (row < 0) + goto error; + if (cutting_strategy == CUT_ONE) + break; + } while ((var = next_non_integer_var(tab, var, &flags)) != -1); + if (restore_lexmin(tab) < 0) + goto error; + if (tab->empty) + break; + } + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Check whether all the currently active samples also satisfy the inequality + * "ineq" (treated as an equality if eq is set). + * Remove those samples that do not. + */ +static struct isl_tab *check_samples(struct isl_tab *tab, isl_int *ineq, int eq) +{ + int i; + isl_int v; + + if (!tab) + return NULL; + + isl_assert(tab->mat->ctx, tab->bmap, goto error); + isl_assert(tab->mat->ctx, tab->samples, goto error); + isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, goto error); + + isl_int_init(v); + for (i = tab->n_outside; i < tab->n_sample; ++i) { + int sgn; + isl_seq_inner_product(ineq, tab->samples->row[i], + 1 + tab->n_var, &v); + sgn = isl_int_sgn(v); + if (eq ? (sgn == 0) : (sgn >= 0)) + continue; + tab = isl_tab_drop_sample(tab, i); + if (!tab) + break; + } + isl_int_clear(v); + + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Check whether the sample value of the tableau is finite, + * i.e., either the tableau does not use a big parameter, or + * all values of the variables are equal to the big parameter plus + * some constant. This constant is the actual sample value. + */ +static int sample_is_finite(struct isl_tab *tab) +{ + int i; + + if (!tab->M) + return 1; + + for (i = 0; i < tab->n_var; ++i) { + int row; + if (!tab->var[i].is_row) + return 0; + row = tab->var[i].index; + if (isl_int_ne(tab->mat->row[row][0], tab->mat->row[row][2])) + return 0; + } + return 1; +} + +/* Check if the context tableau of sol has any integer points. + * Leave tab in empty state if no integer point can be found. + * If an integer point can be found and if moreover it is finite, + * then it is added to the list of sample values. + * + * This function is only called when none of the currently active sample + * values satisfies the most recently added constraint. + */ +static struct isl_tab *check_integer_feasible(struct isl_tab *tab) +{ + struct isl_tab_undo *snap; + + if (!tab) + return NULL; + + snap = isl_tab_snap(tab); + if (isl_tab_push_basis(tab) < 0) + goto error; + + tab = cut_to_integer_lexmin(tab, CUT_ALL); + if (!tab) + goto error; + + if (!tab->empty && sample_is_finite(tab)) { + struct isl_vec *sample; + + sample = isl_tab_get_sample_value(tab); + + if (isl_tab_add_sample(tab, sample) < 0) + goto error; + } + + if (!tab->empty && isl_tab_rollback(tab, snap) < 0) + goto error; + + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Check if any of the currently active sample values satisfies + * the inequality "ineq" (an equality if eq is set). + */ +static int tab_has_valid_sample(struct isl_tab *tab, isl_int *ineq, int eq) +{ + int i; + isl_int v; + + if (!tab) + return -1; + + isl_assert(tab->mat->ctx, tab->bmap, return -1); + isl_assert(tab->mat->ctx, tab->samples, return -1); + isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, return -1); + + isl_int_init(v); + for (i = tab->n_outside; i < tab->n_sample; ++i) { + int sgn; + isl_seq_inner_product(ineq, tab->samples->row[i], + 1 + tab->n_var, &v); + sgn = isl_int_sgn(v); + if (eq ? (sgn == 0) : (sgn >= 0)) + break; + } + isl_int_clear(v); + + return i < tab->n_sample; +} + +/* Insert a div specified by "div" to the tableau "tab" at position "pos" and + * return isl_bool_true if the div is obviously non-negative. + */ +static isl_bool context_tab_insert_div(struct isl_tab *tab, int pos, + __isl_keep isl_vec *div, + isl_stat (*add_ineq)(void *user, isl_int *), void *user) +{ + int i; + int r; + struct isl_mat *samples; + int nonneg; + + r = isl_tab_insert_div(tab, pos, div, add_ineq, user); + if (r < 0) + return isl_bool_error; + nonneg = tab->var[r].is_nonneg; + tab->var[r].frozen = 1; + + samples = isl_mat_extend(tab->samples, + tab->n_sample, 1 + tab->n_var); + tab->samples = samples; + if (!samples) + return isl_bool_error; + for (i = tab->n_outside; i < samples->n_row; ++i) { + isl_seq_inner_product(div->el + 1, samples->row[i], + div->size - 1, &samples->row[i][samples->n_col - 1]); + isl_int_fdiv_q(samples->row[i][samples->n_col - 1], + samples->row[i][samples->n_col - 1], div->el[0]); + } + tab->samples = isl_mat_move_cols(tab->samples, 1 + pos, + 1 + tab->n_var - 1, 1); + if (!tab->samples) + return isl_bool_error; + + return nonneg; +} + +/* Add a div specified by "div" to both the main tableau and + * the context tableau. In case of the main tableau, we only + * need to add an extra div. In the context tableau, we also + * need to express the meaning of the div. + * Return the index of the div or -1 if anything went wrong. + * + * The new integer division is added before any unknown integer + * divisions in the context to ensure that it does not get + * equated to some linear combination involving unknown integer + * divisions. + */ +static int add_div(struct isl_tab *tab, struct isl_context *context, + __isl_keep isl_vec *div) +{ + int r; + int pos; + isl_bool nonneg; + struct isl_tab *context_tab = context->op->peek_tab(context); + + if (!tab || !context_tab) + goto error; + + pos = context_tab->n_var - context->n_unknown; + if ((nonneg = context->op->insert_div(context, pos, div)) < 0) + goto error; + + if (!context->op->is_ok(context)) + goto error; + + pos = tab->n_var - context->n_unknown; + if (isl_tab_extend_vars(tab, 1) < 0) + goto error; + r = isl_tab_insert_var(tab, pos); + if (r < 0) + goto error; + if (nonneg) + tab->var[r].is_nonneg = 1; + tab->var[r].frozen = 1; + tab->n_div++; + + return tab->n_div - 1 - context->n_unknown; +error: + context->op->invalidate(context); + return -1; +} + +static int find_div(struct isl_tab *tab, isl_int *div, isl_int denom) +{ + int i; + unsigned total = isl_basic_map_total_dim(tab->bmap); + + for (i = 0; i < tab->bmap->n_div; ++i) { + if (isl_int_ne(tab->bmap->div[i][0], denom)) + continue; + if (!isl_seq_eq(tab->bmap->div[i] + 1, div, 1 + total)) + continue; + return i; + } + return -1; +} + +/* Return the index of a div that corresponds to "div". + * We first check if we already have such a div and if not, we create one. + */ +static int get_div(struct isl_tab *tab, struct isl_context *context, + struct isl_vec *div) +{ + int d; + struct isl_tab *context_tab = context->op->peek_tab(context); + + if (!context_tab) + return -1; + + d = find_div(context_tab, div->el + 1, div->el[0]); + if (d != -1) + return d; + + return add_div(tab, context, div); +} + +/* Add a parametric cut to cut away the non-integral sample value + * of the given row. + * Let a_i be the coefficients of the constant term and the parameters + * and let b_i be the coefficients of the variables or constraints + * in basis of the tableau. + * Let q be the div q = floor(\sum_i {-a_i} y_i). + * + * The cut is expressed as + * + * c = \sum_i -{-a_i} y_i + \sum_i {b_i} x_i + q >= 0 + * + * If q did not already exist in the context tableau, then it is added first. + * If q is in a column of the main tableau then the "+ q" can be accomplished + * by setting the corresponding entry to the denominator of the constraint. + * If q happens to be in a row of the main tableau, then the corresponding + * row needs to be added instead (taking care of the denominators). + * Note that this is very unlikely, but perhaps not entirely impossible. + * + * The current value of the cut is known to be negative (or at least + * non-positive), so row_sign is set accordingly. + * + * Return the row of the cut or -1. + */ +static int add_parametric_cut(struct isl_tab *tab, int row, + struct isl_context *context) +{ + struct isl_vec *div; + int d; + int i; + int r; + isl_int *r_row; + int col; + int n; + unsigned off = 2 + tab->M; + + if (!context) + return -1; + + div = get_row_parameter_div(tab, row); + if (!div) + return -1; + + n = tab->n_div - context->n_unknown; + d = context->op->get_div(context, tab, div); + isl_vec_free(div); + if (d < 0) + return -1; + + if (isl_tab_extend_cons(tab, 1) < 0) + return -1; + r = isl_tab_allocate_con(tab); + if (r < 0) + return -1; + + r_row = tab->mat->row[tab->con[r].index]; + isl_int_set(r_row[0], tab->mat->row[row][0]); + isl_int_neg(r_row[1], tab->mat->row[row][1]); + isl_int_fdiv_r(r_row[1], r_row[1], tab->mat->row[row][0]); + isl_int_neg(r_row[1], r_row[1]); + if (tab->M) + isl_int_set_si(r_row[2], 0); + for (i = 0; i < tab->n_param; ++i) { + if (tab->var[i].is_row) + continue; + col = tab->var[i].index; + isl_int_neg(r_row[off + col], tab->mat->row[row][off + col]); + isl_int_fdiv_r(r_row[off + col], r_row[off + col], + tab->mat->row[row][0]); + isl_int_neg(r_row[off + col], r_row[off + col]); + } + for (i = 0; i < tab->n_div; ++i) { + if (tab->var[tab->n_var - tab->n_div + i].is_row) + continue; + col = tab->var[tab->n_var - tab->n_div + i].index; + isl_int_neg(r_row[off + col], tab->mat->row[row][off + col]); + isl_int_fdiv_r(r_row[off + col], r_row[off + col], + tab->mat->row[row][0]); + isl_int_neg(r_row[off + col], r_row[off + col]); + } + for (i = 0; i < tab->n_col; ++i) { + if (tab->col_var[i] >= 0 && + (tab->col_var[i] < tab->n_param || + tab->col_var[i] >= tab->n_var - tab->n_div)) + continue; + isl_int_fdiv_r(r_row[off + i], + tab->mat->row[row][off + i], tab->mat->row[row][0]); + } + if (tab->var[tab->n_var - tab->n_div + d].is_row) { + isl_int gcd; + int d_row = tab->var[tab->n_var - tab->n_div + d].index; + isl_int_init(gcd); + isl_int_gcd(gcd, tab->mat->row[d_row][0], r_row[0]); + isl_int_divexact(r_row[0], r_row[0], gcd); + isl_int_divexact(gcd, tab->mat->row[d_row][0], gcd); + isl_seq_combine(r_row + 1, gcd, r_row + 1, + r_row[0], tab->mat->row[d_row] + 1, + off - 1 + tab->n_col); + isl_int_mul(r_row[0], r_row[0], tab->mat->row[d_row][0]); + isl_int_clear(gcd); + } else { + col = tab->var[tab->n_var - tab->n_div + d].index; + isl_int_set(r_row[off + col], tab->mat->row[row][0]); + } + + tab->con[r].is_nonneg = 1; + if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0) + return -1; + if (tab->row_sign) + tab->row_sign[tab->con[r].index] = isl_tab_row_neg; + + row = tab->con[r].index; + + if (d >= n && context->op->detect_equalities(context, tab) < 0) + return -1; + + return row; +} + +/* Construct a tableau for bmap that can be used for computing + * the lexicographic minimum (or maximum) of bmap. + * If not NULL, then dom is the domain where the minimum + * should be computed. In this case, we set up a parametric + * tableau with row signs (initialized to "unknown"). + * If M is set, then the tableau will use a big parameter. + * If max is set, then a maximum should be computed instead of a minimum. + * This means that for each variable x, the tableau will contain the variable + * x' = M - x, rather than x' = M + x. This in turn means that the coefficient + * of the variables in all constraints are negated prior to adding them + * to the tableau. + */ +static __isl_give struct isl_tab *tab_for_lexmin(__isl_keep isl_basic_map *bmap, + __isl_keep isl_basic_set *dom, unsigned M, int max) +{ + int i; + struct isl_tab *tab; + unsigned n_var; + unsigned o_var; + + tab = isl_tab_alloc(bmap->ctx, 2 * bmap->n_eq + bmap->n_ineq + 1, + isl_basic_map_total_dim(bmap), M); + if (!tab) + return NULL; + + tab->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); + if (dom) { + tab->n_param = isl_basic_set_total_dim(dom) - dom->n_div; + tab->n_div = dom->n_div; + tab->row_sign = isl_calloc_array(bmap->ctx, + enum isl_tab_row_sign, tab->mat->n_row); + if (tab->mat->n_row && !tab->row_sign) + goto error; + } + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) { + if (isl_tab_mark_empty(tab) < 0) + goto error; + return tab; + } + + for (i = tab->n_param; i < tab->n_var - tab->n_div; ++i) { + tab->var[i].is_nonneg = 1; + tab->var[i].frozen = 1; + } + o_var = 1 + tab->n_param; + n_var = tab->n_var - tab->n_param - tab->n_div; + for (i = 0; i < bmap->n_eq; ++i) { + if (max) + isl_seq_neg(bmap->eq[i] + o_var, + bmap->eq[i] + o_var, n_var); + tab = add_lexmin_valid_eq(tab, bmap->eq[i]); + if (max) + isl_seq_neg(bmap->eq[i] + o_var, + bmap->eq[i] + o_var, n_var); + if (!tab || tab->empty) + return 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] + o_var, + bmap->ineq[i] + o_var, n_var); + tab = add_lexmin_ineq(tab, bmap->ineq[i]); + if (max) + isl_seq_neg(bmap->ineq[i] + o_var, + bmap->ineq[i] + o_var, n_var); + if (!tab || tab->empty) + return tab; + } + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Given a main tableau where more than one row requires a split, + * determine and return the "best" row to split on. + * + * If any of the rows requiring a split only involves + * variables that also appear in the context tableau, + * then the negative part is guaranteed not to have a solution. + * It is therefore best to split on any of these rows first. + * + * Otherwise, + * given two rows in the main tableau, if the inequality corresponding + * to the first row is redundant with respect to that of the second row + * in the current tableau, then it is better to split on the second row, + * since in the positive part, both rows will be positive. + * (In the negative part a pivot will have to be performed and just about + * anything can happen to the sign of the other row.) + * + * As a simple heuristic, we therefore select the row that makes the most + * of the other rows redundant. + * + * Perhaps it would also be useful to look at the number of constraints + * that conflict with any given constraint. + * + * best is the best row so far (-1 when we have not found any row yet). + * best_r is the number of other rows made redundant by row best. + * When best is still -1, bset_r is meaningless, but it is initialized + * to some arbitrary value (0) anyway. Without this redundant initialization + * valgrind may warn about uninitialized memory accesses when isl + * is compiled with some versions of gcc. + */ +static int best_split(struct isl_tab *tab, struct isl_tab *context_tab) +{ + struct isl_tab_undo *snap; + int split; + int row; + int best = -1; + int best_r = 0; + + if (isl_tab_extend_cons(context_tab, 2) < 0) + return -1; + + snap = isl_tab_snap(context_tab); + + for (split = tab->n_redundant; split < tab->n_row; ++split) { + struct isl_tab_undo *snap2; + struct isl_vec *ineq = NULL; + int r = 0; + int ok; + + if (!isl_tab_var_from_row(tab, split)->is_nonneg) + continue; + if (tab->row_sign[split] != isl_tab_row_any) + continue; + + if (is_parametric_constant(tab, split)) + return split; + + ineq = get_row_parameter_ineq(tab, split); + if (!ineq) + return -1; + ok = isl_tab_add_ineq(context_tab, ineq->el) >= 0; + isl_vec_free(ineq); + if (!ok) + return -1; + + snap2 = isl_tab_snap(context_tab); + + for (row = tab->n_redundant; row < tab->n_row; ++row) { + struct isl_tab_var *var; + + if (row == split) + continue; + if (!isl_tab_var_from_row(tab, row)->is_nonneg) + continue; + if (tab->row_sign[row] != isl_tab_row_any) + continue; + + ineq = get_row_parameter_ineq(tab, row); + if (!ineq) + return -1; + ok = isl_tab_add_ineq(context_tab, ineq->el) >= 0; + isl_vec_free(ineq); + if (!ok) + return -1; + var = &context_tab->con[context_tab->n_con - 1]; + if (!context_tab->empty && + !isl_tab_min_at_most_neg_one(context_tab, var)) + r++; + if (isl_tab_rollback(context_tab, snap2) < 0) + return -1; + } + if (best == -1 || r > best_r) { + best = split; + best_r = r; + } + if (isl_tab_rollback(context_tab, snap) < 0) + return -1; + } + + return best; +} + +static struct isl_basic_set *context_lex_peek_basic_set( + struct isl_context *context) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + if (!clex->tab) + return NULL; + return isl_tab_peek_bset(clex->tab); +} + +static struct isl_tab *context_lex_peek_tab(struct isl_context *context) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + return clex->tab; +} + +static void context_lex_add_eq(struct isl_context *context, isl_int *eq, + int check, int update) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + if (isl_tab_extend_cons(clex->tab, 2) < 0) + goto error; + 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) + goto error; + if (!v) + clex->tab = check_integer_feasible(clex->tab); + } + if (update) + clex->tab = check_samples(clex->tab, eq, 1); + return; +error: + isl_tab_free(clex->tab); + clex->tab = NULL; +} + +static void context_lex_add_ineq(struct isl_context *context, isl_int *ineq, + int check, int update) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + if (isl_tab_extend_cons(clex->tab, 1) < 0) + goto error; + clex->tab = add_lexmin_ineq(clex->tab, ineq); + if (check) { + int v = tab_has_valid_sample(clex->tab, ineq, 0); + if (v < 0) + goto error; + if (!v) + clex->tab = check_integer_feasible(clex->tab); + } + if (update) + clex->tab = check_samples(clex->tab, ineq, 0); + return; +error: + isl_tab_free(clex->tab); + clex->tab = NULL; +} + +static isl_stat context_lex_add_ineq_wrap(void *user, isl_int *ineq) +{ + struct isl_context *context = (struct isl_context *)user; + context_lex_add_ineq(context, ineq, 0, 0); + return context->op->is_ok(context) ? isl_stat_ok : isl_stat_error; +} + +/* Check which signs can be obtained by "ineq" on all the currently + * active sample values. See row_sign for more information. + */ +static enum isl_tab_row_sign tab_ineq_sign(struct isl_tab *tab, isl_int *ineq, + int strict) +{ + int i; + int sgn; + isl_int tmp; + enum isl_tab_row_sign res = isl_tab_row_unknown; + + isl_assert(tab->mat->ctx, tab->samples, return isl_tab_row_unknown); + isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, + return isl_tab_row_unknown); + + isl_int_init(tmp); + for (i = tab->n_outside; i < tab->n_sample; ++i) { + isl_seq_inner_product(tab->samples->row[i], ineq, + 1 + tab->n_var, &tmp); + sgn = isl_int_sgn(tmp); + if (sgn > 0 || (sgn == 0 && strict)) { + if (res == isl_tab_row_unknown) + res = isl_tab_row_pos; + if (res == isl_tab_row_neg) + res = isl_tab_row_any; + } + if (sgn < 0) { + if (res == isl_tab_row_unknown) + res = isl_tab_row_neg; + if (res == isl_tab_row_pos) + res = isl_tab_row_any; + } + if (res == isl_tab_row_any) + break; + } + isl_int_clear(tmp); + + return res; +} + +static enum isl_tab_row_sign context_lex_ineq_sign(struct isl_context *context, + isl_int *ineq, int strict) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + return tab_ineq_sign(clex->tab, ineq, strict); +} + +/* Check whether "ineq" can be added to the tableau without rendering + * it infeasible. + */ +static int context_lex_test_ineq(struct isl_context *context, isl_int *ineq) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + struct isl_tab_undo *snap; + int feasible; + + if (!clex->tab) + return -1; + + if (isl_tab_extend_cons(clex->tab, 1) < 0) + return -1; + + snap = isl_tab_snap(clex->tab); + if (isl_tab_push_basis(clex->tab) < 0) + return -1; + clex->tab = add_lexmin_ineq(clex->tab, ineq); + clex->tab = check_integer_feasible(clex->tab); + if (!clex->tab) + return -1; + feasible = !clex->tab->empty; + if (isl_tab_rollback(clex->tab, snap) < 0) + return -1; + + return feasible; +} + +static int context_lex_get_div(struct isl_context *context, struct isl_tab *tab, + struct isl_vec *div) +{ + return get_div(tab, context, div); +} + +/* Insert a div specified by "div" to the context tableau at position "pos" and + * return isl_bool_true if the div is obviously non-negative. + * context_tab_add_div will always return isl_bool_true, because all variables + * in a isl_context_lex tableau are non-negative. + * However, if we are using a big parameter in the context, then this only + * reflects the non-negativity of the variable used to _encode_ the + * div, i.e., div' = M + div, so we can't draw any conclusions. + */ +static isl_bool context_lex_insert_div(struct isl_context *context, int pos, + __isl_keep isl_vec *div) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + isl_bool nonneg; + nonneg = context_tab_insert_div(clex->tab, pos, div, + context_lex_add_ineq_wrap, context); + if (nonneg < 0) + return isl_bool_error; + if (clex->tab->M) + return isl_bool_false; + return nonneg; +} + +static int context_lex_detect_equalities(struct isl_context *context, + struct isl_tab *tab) +{ + return 0; +} + +static int context_lex_best_split(struct isl_context *context, + struct isl_tab *tab) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + struct isl_tab_undo *snap; + int r; + + snap = isl_tab_snap(clex->tab); + if (isl_tab_push_basis(clex->tab) < 0) + return -1; + r = best_split(tab, clex->tab); + + if (r >= 0 && isl_tab_rollback(clex->tab, snap) < 0) + return -1; + + return r; +} + +static int context_lex_is_empty(struct isl_context *context) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + if (!clex->tab) + return -1; + return clex->tab->empty; +} + +static void *context_lex_save(struct isl_context *context) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + struct isl_tab_undo *snap; + + snap = isl_tab_snap(clex->tab); + if (isl_tab_push_basis(clex->tab) < 0) + return NULL; + if (isl_tab_save_samples(clex->tab) < 0) + return NULL; + + return snap; +} + +static void context_lex_restore(struct isl_context *context, void *save) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + if (isl_tab_rollback(clex->tab, (struct isl_tab_undo *)save) < 0) { + isl_tab_free(clex->tab); + clex->tab = NULL; + } +} + +static void context_lex_discard(void *save) +{ +} + +static int context_lex_is_ok(struct isl_context *context) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + return !!clex->tab; +} + +/* For each variable in the context tableau, check if the variable can + * only attain non-negative values. If so, mark the parameter as non-negative + * in the main tableau. This allows for a more direct identification of some + * cases of violated constraints. + */ +static struct isl_tab *tab_detect_nonnegative_parameters(struct isl_tab *tab, + struct isl_tab *context_tab) +{ + int i; + struct isl_tab_undo *snap; + struct isl_vec *ineq = NULL; + struct isl_tab_var *var; + int n; + + if (context_tab->n_var == 0) + return tab; + + ineq = isl_vec_alloc(tab->mat->ctx, 1 + context_tab->n_var); + if (!ineq) + goto error; + + if (isl_tab_extend_cons(context_tab, 1) < 0) + goto error; + + snap = isl_tab_snap(context_tab); + + n = 0; + isl_seq_clr(ineq->el, ineq->size); + for (i = 0; i < context_tab->n_var; ++i) { + isl_int_set_si(ineq->el[1 + i], 1); + if (isl_tab_add_ineq(context_tab, ineq->el) < 0) + goto error; + var = &context_tab->con[context_tab->n_con - 1]; + if (!context_tab->empty && + !isl_tab_min_at_most_neg_one(context_tab, var)) { + int j = i; + if (i >= tab->n_param) + j = i - tab->n_param + tab->n_var - tab->n_div; + tab->var[j].is_nonneg = 1; + n++; + } + isl_int_set_si(ineq->el[1 + i], 0); + if (isl_tab_rollback(context_tab, snap) < 0) + goto error; + } + + if (context_tab->M && n == context_tab->n_var) { + context_tab->mat = isl_mat_drop_cols(context_tab->mat, 2, 1); + context_tab->M = 0; + } + + isl_vec_free(ineq); + return tab; +error: + isl_vec_free(ineq); + isl_tab_free(tab); + return NULL; +} + +static struct isl_tab *context_lex_detect_nonnegative_parameters( + struct isl_context *context, struct isl_tab *tab) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + struct isl_tab_undo *snap; + + if (!tab) + return NULL; + + snap = isl_tab_snap(clex->tab); + if (isl_tab_push_basis(clex->tab) < 0) + goto error; + + tab = tab_detect_nonnegative_parameters(tab, clex->tab); + + if (isl_tab_rollback(clex->tab, snap) < 0) + goto error; + + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +static void context_lex_invalidate(struct isl_context *context) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + isl_tab_free(clex->tab); + clex->tab = NULL; +} + +static __isl_null struct isl_context *context_lex_free( + struct isl_context *context) +{ + struct isl_context_lex *clex = (struct isl_context_lex *)context; + isl_tab_free(clex->tab); + free(clex); + + return NULL; +} + +struct isl_context_op isl_context_lex_op = { + context_lex_detect_nonnegative_parameters, + context_lex_peek_basic_set, + context_lex_peek_tab, + context_lex_add_eq, + context_lex_add_ineq, + context_lex_ineq_sign, + context_lex_test_ineq, + context_lex_get_div, + context_lex_insert_div, + context_lex_detect_equalities, + context_lex_best_split, + context_lex_is_empty, + context_lex_is_ok, + context_lex_save, + context_lex_restore, + context_lex_discard, + context_lex_invalidate, + context_lex_free, +}; + +static struct isl_tab *context_tab_for_lexmin(__isl_take isl_basic_set *bset) +{ + struct isl_tab *tab; + + if (!bset) + return NULL; + tab = tab_for_lexmin(bset_to_bmap(bset), NULL, 1, 0); + if (isl_tab_track_bset(tab, bset) < 0) + goto error; + tab = isl_tab_init_samples(tab); + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +static struct isl_context *isl_context_lex_alloc(struct isl_basic_set *dom) +{ + struct isl_context_lex *clex; + + if (!dom) + return NULL; + + clex = isl_alloc_type(dom->ctx, struct isl_context_lex); + if (!clex) + return NULL; + + clex->context.op = &isl_context_lex_op; + + clex->tab = context_tab_for_lexmin(isl_basic_set_copy(dom)); + if (restore_lexmin(clex->tab) < 0) + goto error; + clex->tab = check_integer_feasible(clex->tab); + if (!clex->tab) + goto error; + + return &clex->context; +error: + clex->context.op->free(&clex->context); + return NULL; +} + +/* Representation of the context when using generalized basis reduction. + * + * "shifted" contains the offsets of the unit hypercubes that lie inside the + * context. Any rational point in "shifted" can therefore be rounded + * up to an integer point in the context. + * If the context is constrained by any equality, then "shifted" is not used + * as it would be empty. + */ +struct isl_context_gbr { + struct isl_context context; + struct isl_tab *tab; + struct isl_tab *shifted; + struct isl_tab *cone; +}; + +static struct isl_tab *context_gbr_detect_nonnegative_parameters( + struct isl_context *context, struct isl_tab *tab) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + if (!tab) + return NULL; + return tab_detect_nonnegative_parameters(tab, cgbr->tab); +} + +static struct isl_basic_set *context_gbr_peek_basic_set( + struct isl_context *context) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + if (!cgbr->tab) + return NULL; + return isl_tab_peek_bset(cgbr->tab); +} + +static struct isl_tab *context_gbr_peek_tab(struct isl_context *context) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + return cgbr->tab; +} + +/* Initialize the "shifted" tableau of the context, which + * contains the constraints of the original tableau shifted + * by the sum of all negative coefficients. This ensures + * that any rational point in the shifted tableau can + * be rounded up to yield an integer point in the original tableau. + */ +static void gbr_init_shifted(struct isl_context_gbr *cgbr) +{ + int i, j; + struct isl_vec *cst; + struct isl_basic_set *bset = isl_tab_peek_bset(cgbr->tab); + unsigned dim = isl_basic_set_total_dim(bset); + + cst = isl_vec_alloc(cgbr->tab->mat->ctx, bset->n_ineq); + if (!cst) + return; + + for (i = 0; i < bset->n_ineq; ++i) { + isl_int_set(cst->el[i], bset->ineq[i][0]); + for (j = 0; j < dim; ++j) { + if (!isl_int_is_neg(bset->ineq[i][1 + j])) + continue; + isl_int_add(bset->ineq[i][0], bset->ineq[i][0], + bset->ineq[i][1 + j]); + } + } + + cgbr->shifted = isl_tab_from_basic_set(bset, 0); + + for (i = 0; i < bset->n_ineq; ++i) + isl_int_set(bset->ineq[i][0], cst->el[i]); + + isl_vec_free(cst); +} + +/* Check if the shifted tableau is non-empty, and if so + * use the sample point to construct an integer point + * of the context tableau. + */ +static struct isl_vec *gbr_get_shifted_sample(struct isl_context_gbr *cgbr) +{ + struct isl_vec *sample; + + if (!cgbr->shifted) + gbr_init_shifted(cgbr); + if (!cgbr->shifted) + return NULL; + if (cgbr->shifted->empty) + return isl_vec_alloc(cgbr->tab->mat->ctx, 0); + + sample = isl_tab_get_sample_value(cgbr->shifted); + sample = isl_vec_ceil(sample); + + return sample; +} + +static __isl_give isl_basic_set *drop_constant_terms( + __isl_take isl_basic_set *bset) +{ + int i; + + if (!bset) + return NULL; + + for (i = 0; i < bset->n_eq; ++i) + isl_int_set_si(bset->eq[i][0], 0); + + for (i = 0; i < bset->n_ineq; ++i) + isl_int_set_si(bset->ineq[i][0], 0); + + return bset; +} + +static int use_shifted(struct isl_context_gbr *cgbr) +{ + if (!cgbr->tab) + return 0; + return cgbr->tab->bmap->n_eq == 0 && cgbr->tab->bmap->n_div == 0; +} + +static struct isl_vec *gbr_get_sample(struct isl_context_gbr *cgbr) +{ + struct isl_basic_set *bset; + struct isl_basic_set *cone; + + if (isl_tab_sample_is_integer(cgbr->tab)) + return isl_tab_get_sample_value(cgbr->tab); + + if (use_shifted(cgbr)) { + struct isl_vec *sample; + + sample = gbr_get_shifted_sample(cgbr); + if (!sample || sample->size > 0) + return sample; + + isl_vec_free(sample); + } + + if (!cgbr->cone) { + bset = isl_tab_peek_bset(cgbr->tab); + cgbr->cone = isl_tab_from_recession_cone(bset, 0); + if (!cgbr->cone) + return NULL; + if (isl_tab_track_bset(cgbr->cone, + isl_basic_set_copy(bset)) < 0) + return NULL; + } + if (isl_tab_detect_implicit_equalities(cgbr->cone) < 0) + return NULL; + + if (cgbr->cone->n_dead == cgbr->cone->n_col) { + struct isl_vec *sample; + struct isl_tab_undo *snap; + + if (cgbr->tab->basis) { + if (cgbr->tab->basis->n_col != 1 + cgbr->tab->n_var) { + isl_mat_free(cgbr->tab->basis); + cgbr->tab->basis = NULL; + } + cgbr->tab->n_zero = 0; + cgbr->tab->n_unbounded = 0; + } + + snap = isl_tab_snap(cgbr->tab); + + sample = isl_tab_sample(cgbr->tab); + + if (!sample || isl_tab_rollback(cgbr->tab, snap) < 0) { + isl_vec_free(sample); + return NULL; + } + + return sample; + } + + cone = isl_basic_set_dup(isl_tab_peek_bset(cgbr->cone)); + cone = drop_constant_terms(cone); + cone = isl_basic_set_update_from_tab(cone, cgbr->cone); + cone = isl_basic_set_underlying_set(cone); + cone = isl_basic_set_gauss(cone, NULL); + + bset = isl_basic_set_dup(isl_tab_peek_bset(cgbr->tab)); + bset = isl_basic_set_update_from_tab(bset, cgbr->tab); + bset = isl_basic_set_underlying_set(bset); + bset = isl_basic_set_gauss(bset, NULL); + + return isl_basic_set_sample_with_cone(bset, cone); +} + +static void check_gbr_integer_feasible(struct isl_context_gbr *cgbr) +{ + struct isl_vec *sample; + + if (!cgbr->tab) + return; + + if (cgbr->tab->empty) + return; + + sample = gbr_get_sample(cgbr); + if (!sample) + goto error; + + if (sample->size == 0) { + isl_vec_free(sample); + if (isl_tab_mark_empty(cgbr->tab) < 0) + goto error; + return; + } + + if (isl_tab_add_sample(cgbr->tab, sample) < 0) + goto error; + + return; +error: + isl_tab_free(cgbr->tab); + cgbr->tab = NULL; +} + +static struct isl_tab *add_gbr_eq(struct isl_tab *tab, isl_int *eq) +{ + if (!tab) + return NULL; + + if (isl_tab_extend_cons(tab, 2) < 0) + goto error; + + if (isl_tab_add_eq(tab, eq) < 0) + goto error; + + return tab; +error: + isl_tab_free(tab); + return NULL; +} + +/* Add the equality described by "eq" to the context. + * If "check" is set, then we check if the context is empty after + * adding the equality. + * If "update" is set, then we check if the samples are still valid. + * + * We do not explicitly add shifted copies of the equality to + * cgbr->shifted since they would conflict with each other. + * Instead, we directly mark cgbr->shifted empty. + */ +static void context_gbr_add_eq(struct isl_context *context, isl_int *eq, + int check, int update) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + + cgbr->tab = add_gbr_eq(cgbr->tab, eq); + + if (cgbr->shifted && !cgbr->shifted->empty && use_shifted(cgbr)) { + if (isl_tab_mark_empty(cgbr->shifted) < 0) + goto error; + } + + if (cgbr->cone && cgbr->cone->n_col != cgbr->cone->n_dead) { + if (isl_tab_extend_cons(cgbr->cone, 2) < 0) + goto error; + if (isl_tab_add_eq(cgbr->cone, eq) < 0) + goto error; + } + + if (check) { + int v = tab_has_valid_sample(cgbr->tab, eq, 1); + if (v < 0) + goto error; + if (!v) + check_gbr_integer_feasible(cgbr); + } + if (update) + cgbr->tab = check_samples(cgbr->tab, eq, 1); + return; +error: + isl_tab_free(cgbr->tab); + cgbr->tab = NULL; +} + +static void add_gbr_ineq(struct isl_context_gbr *cgbr, isl_int *ineq) +{ + if (!cgbr->tab) + return; + + if (isl_tab_extend_cons(cgbr->tab, 1) < 0) + goto error; + + if (isl_tab_add_ineq(cgbr->tab, ineq) < 0) + goto error; + + if (cgbr->shifted && !cgbr->shifted->empty && use_shifted(cgbr)) { + int i; + unsigned dim; + dim = isl_basic_map_total_dim(cgbr->tab->bmap); + + if (isl_tab_extend_cons(cgbr->shifted, 1) < 0) + goto error; + + for (i = 0; i < dim; ++i) { + if (!isl_int_is_neg(ineq[1 + i])) + continue; + isl_int_add(ineq[0], ineq[0], ineq[1 + i]); + } + + if (isl_tab_add_ineq(cgbr->shifted, ineq) < 0) + goto error; + + for (i = 0; i < dim; ++i) { + if (!isl_int_is_neg(ineq[1 + i])) + continue; + isl_int_sub(ineq[0], ineq[0], ineq[1 + i]); + } + } + + if (cgbr->cone && cgbr->cone->n_col != cgbr->cone->n_dead) { + if (isl_tab_extend_cons(cgbr->cone, 1) < 0) + goto error; + if (isl_tab_add_ineq(cgbr->cone, ineq) < 0) + goto error; + } + + return; +error: + isl_tab_free(cgbr->tab); + cgbr->tab = NULL; +} + +static void context_gbr_add_ineq(struct isl_context *context, isl_int *ineq, + int check, int update) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + + add_gbr_ineq(cgbr, ineq); + if (!cgbr->tab) + return; + + if (check) { + int v = tab_has_valid_sample(cgbr->tab, ineq, 0); + if (v < 0) + goto error; + if (!v) + check_gbr_integer_feasible(cgbr); + } + if (update) + cgbr->tab = check_samples(cgbr->tab, ineq, 0); + return; +error: + isl_tab_free(cgbr->tab); + cgbr->tab = NULL; +} + +static isl_stat context_gbr_add_ineq_wrap(void *user, isl_int *ineq) +{ + struct isl_context *context = (struct isl_context *)user; + context_gbr_add_ineq(context, ineq, 0, 0); + return context->op->is_ok(context) ? isl_stat_ok : isl_stat_error; +} + +static enum isl_tab_row_sign context_gbr_ineq_sign(struct isl_context *context, + isl_int *ineq, int strict) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + return tab_ineq_sign(cgbr->tab, ineq, strict); +} + +/* Check whether "ineq" can be added to the tableau without rendering + * it infeasible. + */ +static int context_gbr_test_ineq(struct isl_context *context, isl_int *ineq) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + struct isl_tab_undo *snap; + struct isl_tab_undo *shifted_snap = NULL; + struct isl_tab_undo *cone_snap = NULL; + int feasible; + + if (!cgbr->tab) + return -1; + + if (isl_tab_extend_cons(cgbr->tab, 1) < 0) + return -1; + + snap = isl_tab_snap(cgbr->tab); + if (cgbr->shifted) + shifted_snap = isl_tab_snap(cgbr->shifted); + if (cgbr->cone) + cone_snap = isl_tab_snap(cgbr->cone); + add_gbr_ineq(cgbr, ineq); + check_gbr_integer_feasible(cgbr); + if (!cgbr->tab) + return -1; + feasible = !cgbr->tab->empty; + if (isl_tab_rollback(cgbr->tab, snap) < 0) + return -1; + if (shifted_snap) { + if (isl_tab_rollback(cgbr->shifted, shifted_snap)) + return -1; + } else if (cgbr->shifted) { + isl_tab_free(cgbr->shifted); + cgbr->shifted = NULL; + } + if (cone_snap) { + if (isl_tab_rollback(cgbr->cone, cone_snap)) + return -1; + } else if (cgbr->cone) { + isl_tab_free(cgbr->cone); + cgbr->cone = NULL; + } + + return feasible; +} + +/* Return the column of the last of the variables associated to + * a column that has a non-zero coefficient. + * This function is called in a context where only coefficients + * of parameters or divs can be non-zero. + */ +static int last_non_zero_var_col(struct isl_tab *tab, isl_int *p) +{ + int i; + int col; + + if (tab->n_var == 0) + return -1; + + for (i = tab->n_var - 1; i >= 0; --i) { + if (i >= tab->n_param && i < tab->n_var - tab->n_div) + continue; + if (tab->var[i].is_row) + continue; + col = tab->var[i].index; + if (!isl_int_is_zero(p[col])) + return col; + } + + return -1; +} + +/* Look through all the recently added equalities in the context + * to see if we can propagate any of them to the main tableau. + * + * The newly added equalities in the context are encoded as pairs + * of inequalities starting at inequality "first". + * + * We tentatively add each of these equalities to the main tableau + * and if this happens to result in a row with a final coefficient + * that is one or negative one, we use it to kill a column + * in the main tableau. Otherwise, we discard the tentatively + * added row. + * This tentative addition of equality constraints turns + * on the undo facility of the tableau. Turn it off again + * at the end, assuming it was turned off to begin with. + * + * Return 0 on success and -1 on failure. + */ +static int propagate_equalities(struct isl_context_gbr *cgbr, + struct isl_tab *tab, unsigned first) +{ + int i; + struct isl_vec *eq = NULL; + isl_bool needs_undo; + + needs_undo = isl_tab_need_undo(tab); + if (needs_undo < 0) + goto error; + eq = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var); + if (!eq) + goto error; + + if (isl_tab_extend_cons(tab, (cgbr->tab->bmap->n_ineq - first)/2) < 0) + goto error; + + isl_seq_clr(eq->el + 1 + tab->n_param, + tab->n_var - tab->n_param - tab->n_div); + for (i = first; i < cgbr->tab->bmap->n_ineq; i += 2) { + int j; + int r; + struct isl_tab_undo *snap; + snap = isl_tab_snap(tab); + + isl_seq_cpy(eq->el, cgbr->tab->bmap->ineq[i], 1 + tab->n_param); + isl_seq_cpy(eq->el + 1 + tab->n_var - tab->n_div, + cgbr->tab->bmap->ineq[i] + 1 + tab->n_param, + tab->n_div); + + r = isl_tab_add_row(tab, eq->el); + if (r < 0) + goto error; + r = tab->con[r].index; + j = last_non_zero_var_col(tab, tab->mat->row[r] + 2 + tab->M); + if (j < 0 || j < tab->n_dead || + !isl_int_is_one(tab->mat->row[r][0]) || + (!isl_int_is_one(tab->mat->row[r][2 + tab->M + j]) && + !isl_int_is_negone(tab->mat->row[r][2 + tab->M + j]))) { + if (isl_tab_rollback(tab, snap) < 0) + goto error; + continue; + } + if (isl_tab_pivot(tab, r, j) < 0) + goto error; + if (isl_tab_kill_col(tab, j) < 0) + goto error; + + if (restore_lexmin(tab) < 0) + goto error; + } + + if (!needs_undo) + isl_tab_clear_undo(tab); + isl_vec_free(eq); + + return 0; +error: + isl_vec_free(eq); + isl_tab_free(cgbr->tab); + cgbr->tab = NULL; + return -1; +} + +static int context_gbr_detect_equalities(struct isl_context *context, + struct isl_tab *tab) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + unsigned n_ineq; + + if (!cgbr->cone) { + struct isl_basic_set *bset = isl_tab_peek_bset(cgbr->tab); + cgbr->cone = isl_tab_from_recession_cone(bset, 0); + if (!cgbr->cone) + goto error; + if (isl_tab_track_bset(cgbr->cone, + isl_basic_set_copy(bset)) < 0) + goto error; + } + if (isl_tab_detect_implicit_equalities(cgbr->cone) < 0) + goto error; + + n_ineq = cgbr->tab->bmap->n_ineq; + cgbr->tab = isl_tab_detect_equalities(cgbr->tab, cgbr->cone); + if (!cgbr->tab) + return -1; + if (cgbr->tab->bmap->n_ineq > n_ineq && + propagate_equalities(cgbr, tab, n_ineq) < 0) + return -1; + + return 0; +error: + isl_tab_free(cgbr->tab); + cgbr->tab = NULL; + return -1; +} + +static int context_gbr_get_div(struct isl_context *context, struct isl_tab *tab, + struct isl_vec *div) +{ + return get_div(tab, context, div); +} + +static isl_bool context_gbr_insert_div(struct isl_context *context, int pos, + __isl_keep isl_vec *div) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + if (cgbr->cone) { + int r, n_div, o_div; + + n_div = isl_basic_map_dim(cgbr->cone->bmap, isl_dim_div); + o_div = cgbr->cone->n_var - n_div; + + if (isl_tab_extend_cons(cgbr->cone, 3) < 0) + return isl_bool_error; + if (isl_tab_extend_vars(cgbr->cone, 1) < 0) + return isl_bool_error; + if ((r = isl_tab_insert_var(cgbr->cone, pos)) <0) + return isl_bool_error; + + cgbr->cone->bmap = isl_basic_map_insert_div(cgbr->cone->bmap, + r - o_div, div); + if (!cgbr->cone->bmap) + return isl_bool_error; + if (isl_tab_push_var(cgbr->cone, isl_tab_undo_bmap_div, + &cgbr->cone->var[r]) < 0) + return isl_bool_error; + } + return context_tab_insert_div(cgbr->tab, pos, div, + context_gbr_add_ineq_wrap, context); +} + +static int context_gbr_best_split(struct isl_context *context, + struct isl_tab *tab) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + struct isl_tab_undo *snap; + int r; + + snap = isl_tab_snap(cgbr->tab); + r = best_split(tab, cgbr->tab); + + if (r >= 0 && isl_tab_rollback(cgbr->tab, snap) < 0) + return -1; + + return r; +} + +static int context_gbr_is_empty(struct isl_context *context) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + if (!cgbr->tab) + return -1; + return cgbr->tab->empty; +} + +struct isl_gbr_tab_undo { + struct isl_tab_undo *tab_snap; + struct isl_tab_undo *shifted_snap; + struct isl_tab_undo *cone_snap; +}; + +static void *context_gbr_save(struct isl_context *context) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + struct isl_gbr_tab_undo *snap; + + if (!cgbr->tab) + return NULL; + + snap = isl_alloc_type(cgbr->tab->mat->ctx, struct isl_gbr_tab_undo); + if (!snap) + return NULL; + + snap->tab_snap = isl_tab_snap(cgbr->tab); + if (isl_tab_save_samples(cgbr->tab) < 0) + goto error; + + if (cgbr->shifted) + snap->shifted_snap = isl_tab_snap(cgbr->shifted); + else + snap->shifted_snap = NULL; + + if (cgbr->cone) + snap->cone_snap = isl_tab_snap(cgbr->cone); + else + snap->cone_snap = NULL; + + return snap; +error: + free(snap); + return NULL; +} + +static void context_gbr_restore(struct isl_context *context, void *save) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + struct isl_gbr_tab_undo *snap = (struct isl_gbr_tab_undo *)save; + if (!snap) + goto error; + if (isl_tab_rollback(cgbr->tab, snap->tab_snap) < 0) + goto error; + + if (snap->shifted_snap) { + if (isl_tab_rollback(cgbr->shifted, snap->shifted_snap) < 0) + goto error; + } else if (cgbr->shifted) { + isl_tab_free(cgbr->shifted); + cgbr->shifted = NULL; + } + + if (snap->cone_snap) { + if (isl_tab_rollback(cgbr->cone, snap->cone_snap) < 0) + goto error; + } else if (cgbr->cone) { + isl_tab_free(cgbr->cone); + cgbr->cone = NULL; + } + + free(snap); + + return; +error: + free(snap); + isl_tab_free(cgbr->tab); + cgbr->tab = NULL; +} + +static void context_gbr_discard(void *save) +{ + struct isl_gbr_tab_undo *snap = (struct isl_gbr_tab_undo *)save; + free(snap); +} + +static int context_gbr_is_ok(struct isl_context *context) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + return !!cgbr->tab; +} + +static void context_gbr_invalidate(struct isl_context *context) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + isl_tab_free(cgbr->tab); + cgbr->tab = NULL; +} + +static __isl_null struct isl_context *context_gbr_free( + struct isl_context *context) +{ + struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context; + isl_tab_free(cgbr->tab); + isl_tab_free(cgbr->shifted); + isl_tab_free(cgbr->cone); + free(cgbr); + + return NULL; +} + +struct isl_context_op isl_context_gbr_op = { + context_gbr_detect_nonnegative_parameters, + context_gbr_peek_basic_set, + context_gbr_peek_tab, + context_gbr_add_eq, + context_gbr_add_ineq, + context_gbr_ineq_sign, + context_gbr_test_ineq, + context_gbr_get_div, + context_gbr_insert_div, + context_gbr_detect_equalities, + context_gbr_best_split, + context_gbr_is_empty, + context_gbr_is_ok, + context_gbr_save, + context_gbr_restore, + context_gbr_discard, + context_gbr_invalidate, + context_gbr_free, +}; + +static struct isl_context *isl_context_gbr_alloc(__isl_keep isl_basic_set *dom) +{ + struct isl_context_gbr *cgbr; + + if (!dom) + return NULL; + + cgbr = isl_calloc_type(dom->ctx, struct isl_context_gbr); + if (!cgbr) + return NULL; + + cgbr->context.op = &isl_context_gbr_op; + + cgbr->shifted = NULL; + cgbr->cone = NULL; + cgbr->tab = isl_tab_from_basic_set(dom, 1); + cgbr->tab = isl_tab_init_samples(cgbr->tab); + if (!cgbr->tab) + goto error; + check_gbr_integer_feasible(cgbr); + + return &cgbr->context; +error: + cgbr->context.op->free(&cgbr->context); + return NULL; +} + +/* Allocate a context corresponding to "dom". + * The representation specific fields are initialized by + * isl_context_lex_alloc or isl_context_gbr_alloc. + * The shared "n_unknown" field is initialized to the number + * of final unknown integer divisions in "dom". + */ +static struct isl_context *isl_context_alloc(__isl_keep isl_basic_set *dom) +{ + struct isl_context *context; + int first; + + if (!dom) + return NULL; + + if (dom->ctx->opt->context == ISL_CONTEXT_LEXMIN) + context = isl_context_lex_alloc(dom); + else + context = isl_context_gbr_alloc(dom); + + if (!context) + return NULL; + + first = isl_basic_set_first_unknown_div(dom); + if (first < 0) + return context->op->free(context); + context->n_unknown = isl_basic_set_dim(dom, isl_dim_div) - first; + + return context; +} + +/* Initialize some common fields of "sol", which keeps track + * of the solution of an optimization problem on "bmap" over + * the domain "dom". + * If "max" is set, then a maximization problem is being solved, rather than + * a minimization problem, which means that the variables in the + * tableau have value "M - x" rather than "M + x". + */ +static isl_stat sol_init(struct isl_sol *sol, __isl_keep isl_basic_map *bmap, + __isl_keep isl_basic_set *dom, int max) +{ + sol->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); + sol->dec_level.callback.run = &sol_dec_level_wrap; + sol->dec_level.sol = sol; + sol->max = max; + sol->n_out = isl_basic_map_dim(bmap, isl_dim_out); + sol->space = isl_basic_map_get_space(bmap); + + sol->context = isl_context_alloc(dom); + if (!sol->space || !sol->context) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Construct an isl_sol_map structure for accumulating the solution. + * If track_empty is set, then we also keep track of the parts + * of the context where there is no solution. + * If max is set, then we are solving a maximization, rather than + * a minimization problem, which means that the variables in the + * tableau have value "M - x" rather than "M + x". + */ +static struct isl_sol *sol_map_init(__isl_keep isl_basic_map *bmap, + __isl_take isl_basic_set *dom, int track_empty, int max) +{ + struct isl_sol_map *sol_map = NULL; + isl_space *space; + + if (!bmap) + goto error; + + sol_map = isl_calloc_type(bmap->ctx, struct isl_sol_map); + if (!sol_map) + goto error; + + sol_map->sol.free = &sol_map_free; + if (sol_init(&sol_map->sol, bmap, dom, max) < 0) + goto error; + sol_map->sol.add = &sol_map_add_wrap; + sol_map->sol.add_empty = track_empty ? &sol_map_add_empty_wrap : NULL; + space = isl_space_copy(sol_map->sol.space); + sol_map->map = isl_map_alloc_space(space, 1, ISL_MAP_DISJOINT); + if (!sol_map->map) + goto error; + + if (track_empty) { + sol_map->empty = isl_set_alloc_space(isl_basic_set_get_space(dom), + 1, ISL_SET_DISJOINT); + if (!sol_map->empty) + goto error; + } + + isl_basic_set_free(dom); + return &sol_map->sol; +error: + isl_basic_set_free(dom); + sol_free(&sol_map->sol); + return NULL; +} + +/* Check whether all coefficients of (non-parameter) variables + * are non-positive, meaning that no pivots can be performed on the row. + */ +static int is_critical(struct isl_tab *tab, int row) +{ + int j; + unsigned off = 2 + tab->M; + + for (j = tab->n_dead; j < tab->n_col; ++j) { + if (col_is_parameter_var(tab, j)) + continue; + + if (isl_int_is_pos(tab->mat->row[row][off + j])) + return 0; + } + + return 1; +} + +/* Check whether the inequality represented by vec is strict over the integers, + * i.e., there are no integer values satisfying the constraint with + * equality. This happens if the gcd of the coefficients is not a divisor + * of the constant term. If so, scale the constraint down by the gcd + * of the coefficients. + */ +static int is_strict(struct isl_vec *vec) +{ + isl_int gcd; + int strict = 0; + + isl_int_init(gcd); + isl_seq_gcd(vec->el + 1, vec->size - 1, &gcd); + if (!isl_int_is_one(gcd)) { + strict = !isl_int_is_divisible_by(vec->el[0], gcd); + isl_int_fdiv_q(vec->el[0], vec->el[0], gcd); + isl_seq_scale_down(vec->el + 1, vec->el + 1, gcd, vec->size-1); + } + isl_int_clear(gcd); + + return strict; +} + +/* Determine the sign of the given row of the main tableau. + * The result is one of + * isl_tab_row_pos: always non-negative; no pivot needed + * isl_tab_row_neg: always non-positive; pivot + * isl_tab_row_any: can be both positive and negative; split + * + * We first handle some simple cases + * - the row sign may be known already + * - the row may be obviously non-negative + * - the parametric constant may be equal to that of another row + * for which we know the sign. This sign will be either "pos" or + * "any". If it had been "neg" then we would have pivoted before. + * + * If none of these cases hold, we check the value of the row for each + * of the currently active samples. Based on the signs of these values + * we make an initial determination of the sign of the row. + * + * all zero -> unk(nown) + * all non-negative -> pos + * all non-positive -> neg + * both negative and positive -> all + * + * If we end up with "all", we are done. + * Otherwise, we perform a check for positive and/or negative + * values as follows. + * + * samples neg unk pos + * <0 ? Y N Y N + * pos any pos + * >0 ? Y N Y N + * any neg any neg + * + * There is no special sign for "zero", because we can usually treat zero + * as either non-negative or non-positive, whatever works out best. + * However, if the row is "critical", meaning that pivoting is impossible + * then we don't want to limp zero with the non-positive case, because + * then we we would lose the solution for those values of the parameters + * where the value of the row is zero. Instead, we treat 0 as non-negative + * ensuring a split if the row can attain both zero and negative values. + * The same happens when the original constraint was one that could not + * be satisfied with equality by any integer values of the parameters. + * In this case, we normalize the constraint, but then a value of zero + * for the normalized constraint is actually a positive value for the + * original constraint, so again we need to treat zero as non-negative. + * In both these cases, we have the following decision tree instead: + * + * all non-negative -> pos + * all negative -> neg + * both negative and non-negative -> all + * + * samples neg pos + * <0 ? Y N + * any pos + * >=0 ? Y N + * any neg + */ +static enum isl_tab_row_sign row_sign(struct isl_tab *tab, + struct isl_sol *sol, int row) +{ + struct isl_vec *ineq = NULL; + enum isl_tab_row_sign res = isl_tab_row_unknown; + int critical; + int strict; + int row2; + + if (tab->row_sign[row] != isl_tab_row_unknown) + return tab->row_sign[row]; + if (is_obviously_nonneg(tab, row)) + return isl_tab_row_pos; + for (row2 = tab->n_redundant; row2 < tab->n_row; ++row2) { + if (tab->row_sign[row2] == isl_tab_row_unknown) + continue; + if (identical_parameter_line(tab, row, row2)) + return tab->row_sign[row2]; + } + + critical = is_critical(tab, row); + + ineq = get_row_parameter_ineq(tab, row); + if (!ineq) + goto error; + + strict = is_strict(ineq); + + res = sol->context->op->ineq_sign(sol->context, ineq->el, + critical || strict); + + if (res == isl_tab_row_unknown || res == isl_tab_row_pos) { + /* test for negative values */ + int feasible; + isl_seq_neg(ineq->el, ineq->el, ineq->size); + isl_int_sub_ui(ineq->el[0], ineq->el[0], 1); + + feasible = sol->context->op->test_ineq(sol->context, ineq->el); + if (feasible < 0) + goto error; + if (!feasible) + res = isl_tab_row_pos; + else + res = (res == isl_tab_row_unknown) ? isl_tab_row_neg + : isl_tab_row_any; + if (res == isl_tab_row_neg) { + isl_seq_neg(ineq->el, ineq->el, ineq->size); + isl_int_sub_ui(ineq->el[0], ineq->el[0], 1); + } + } + + if (res == isl_tab_row_neg) { + /* test for positive values */ + int feasible; + if (!critical && !strict) + isl_int_sub_ui(ineq->el[0], ineq->el[0], 1); + + feasible = sol->context->op->test_ineq(sol->context, ineq->el); + if (feasible < 0) + goto error; + if (feasible) + res = isl_tab_row_any; + } + + isl_vec_free(ineq); + return res; +error: + isl_vec_free(ineq); + return isl_tab_row_unknown; +} + +static void find_solutions(struct isl_sol *sol, struct isl_tab *tab); + +/* Find solutions for values of the parameters that satisfy the given + * inequality. + * + * We currently take a snapshot of the context tableau that is reset + * when we return from this function, while we make a copy of the main + * tableau, leaving the original main tableau untouched. + * These are fairly arbitrary choices. Making a copy also of the context + * tableau would obviate the need to undo any changes made to it later, + * while taking a snapshot of the main tableau could reduce memory usage. + * If we were to switch to taking a snapshot of the main tableau, + * we would have to keep in mind that we need to save the row signs + * and that we need to do this before saving the current basis + * such that the basis has been restore before we restore the row signs. + */ +static void find_in_pos(struct isl_sol *sol, struct isl_tab *tab, isl_int *ineq) +{ + void *saved; + + if (!sol->context) + goto error; + saved = sol->context->op->save(sol->context); + + tab = isl_tab_dup(tab); + if (!tab) + goto error; + + sol->context->op->add_ineq(sol->context, ineq, 0, 1); + + find_solutions(sol, tab); + + if (!sol->error) + sol->context->op->restore(sol->context, saved); + else + sol->context->op->discard(saved); + return; +error: + sol->error = 1; +} + +/* Record the absence of solutions for those values of the parameters + * that do not satisfy the given inequality with equality. + */ +static void no_sol_in_strict(struct isl_sol *sol, + struct isl_tab *tab, struct isl_vec *ineq) +{ + int empty; + void *saved; + + if (!sol->context || sol->error) + goto error; + saved = sol->context->op->save(sol->context); + + isl_int_sub_ui(ineq->el[0], ineq->el[0], 1); + + sol->context->op->add_ineq(sol->context, ineq->el, 1, 0); + if (!sol->context) + goto error; + + empty = tab->empty; + tab->empty = 1; + sol_add(sol, tab); + tab->empty = empty; + + isl_int_add_ui(ineq->el[0], ineq->el[0], 1); + + sol->context->op->restore(sol->context, saved); + return; +error: + sol->error = 1; +} + +/* Reset all row variables that are marked to have a sign that may + * be both positive and negative to have an unknown sign. + */ +static void reset_any_to_unknown(struct isl_tab *tab) +{ + int row; + + for (row = tab->n_redundant; row < tab->n_row; ++row) { + if (!isl_tab_var_from_row(tab, row)->is_nonneg) + continue; + if (tab->row_sign[row] == isl_tab_row_any) + tab->row_sign[row] = isl_tab_row_unknown; + } +} + +/* Compute the lexicographic minimum of the set represented by the main + * tableau "tab" within the context "sol->context_tab". + * On entry the sample value of the main tableau is lexicographically + * less than or equal to this lexicographic minimum. + * Pivots are performed until a feasible point is found, which is then + * necessarily equal to the minimum, or until the tableau is found to + * be infeasible. Some pivots may need to be performed for only some + * feasible values of the context tableau. If so, the context tableau + * is split into a part where the pivot is needed and a part where it is not. + * + * Whenever we enter the main loop, the main tableau is such that no + * "obvious" pivots need to be performed on it, where "obvious" means + * that the given row can be seen to be negative without looking at + * the context tableau. In particular, for non-parametric problems, + * no pivots need to be performed on the main tableau. + * The caller of find_solutions is responsible for making this property + * hold prior to the first iteration of the loop, while restore_lexmin + * is called before every other iteration. + * + * Inside the main loop, we first examine the signs of the rows of + * the main tableau within the context of the context tableau. + * If we find a row that is always non-positive for all values of + * the parameters satisfying the context tableau and negative for at + * least one value of the parameters, we perform the appropriate pivot + * and start over. An exception is the case where no pivot can be + * performed on the row. In this case, we require that the sign of + * the row is negative for all values of the parameters (rather than just + * non-positive). This special case is handled inside row_sign, which + * will say that the row can have any sign if it determines that it can + * attain both negative and zero values. + * + * If we can't find a row that always requires a pivot, but we can find + * one or more rows that require a pivot for some values of the parameters + * (i.e., the row can attain both positive and negative signs), then we split + * the context tableau into two parts, one where we force the sign to be + * non-negative and one where we force is to be negative. + * The non-negative part is handled by a recursive call (through find_in_pos). + * Upon returning from this call, we continue with the negative part and + * perform the required pivot. + * + * If no such rows can be found, all rows are non-negative and we have + * found a (rational) feasible point. If we only wanted a rational point + * then we are done. + * Otherwise, we check if all values of the sample point of the tableau + * are integral for the variables. If so, we have found the minimal + * integral point and we are done. + * If the sample point is not integral, then we need to make a distinction + * based on whether the constant term is non-integral or the coefficients + * of the parameters. Furthermore, in order to decide how to handle + * the non-integrality, we also need to know whether the coefficients + * of the other columns in the tableau are integral. This leads + * to the following table. The first two rows do not correspond + * to a non-integral sample point and are only mentioned for completeness. + * + * constant parameters other + * + * int int int | + * int int rat | -> no problem + * + * rat int int -> fail + * + * rat int rat -> cut + * + * int rat rat | + * rat rat rat | -> parametric cut + * + * int rat int | + * rat rat int | -> split context + * + * If the parametric constant is completely integral, then there is nothing + * to be done. If the constant term is non-integral, but all the other + * coefficient are integral, then there is nothing that can be done + * and the tableau has no integral solution. + * If, on the other hand, one or more of the other columns have rational + * coefficients, but the parameter coefficients are all integral, then + * we can perform a regular (non-parametric) cut. + * Finally, if there is any parameter coefficient that is non-integral, + * then we need to involve the context tableau. There are two cases here. + * If at least one other column has a rational coefficient, then we + * can perform a parametric cut in the main tableau by adding a new + * integer division in the context tableau. + * If all other columns have integral coefficients, then we need to + * enforce that the rational combination of parameters (c + \sum a_i y_i)/m + * is always integral. We do this by introducing an integer division + * q = floor((c + \sum a_i y_i)/m) and stipulating that its argument should + * always be integral in the context tableau, i.e., m q = c + \sum a_i y_i. + * Since q is expressed in the tableau as + * c + \sum a_i y_i - m q >= 0 + * -c - \sum a_i y_i + m q + m - 1 >= 0 + * it is sufficient to add the inequality + * -c - \sum a_i y_i + m q >= 0 + * In the part of the context where this inequality does not hold, the + * main tableau is marked as being empty. + */ +static void find_solutions(struct isl_sol *sol, struct isl_tab *tab) +{ + struct isl_context *context; + int r; + + if (!tab || sol->error) + goto error; + + context = sol->context; + + if (tab->empty) + goto done; + if (context->op->is_empty(context)) + goto done; + + for (r = 0; r >= 0 && tab && !tab->empty; r = restore_lexmin(tab)) { + int flags; + int row; + enum isl_tab_row_sign sgn; + int split = -1; + int n_split = 0; + + for (row = tab->n_redundant; row < tab->n_row; ++row) { + if (!isl_tab_var_from_row(tab, row)->is_nonneg) + continue; + sgn = row_sign(tab, sol, row); + if (!sgn) + goto error; + tab->row_sign[row] = sgn; + if (sgn == isl_tab_row_any) + n_split++; + if (sgn == isl_tab_row_any && split == -1) + split = row; + if (sgn == isl_tab_row_neg) + break; + } + if (row < tab->n_row) + continue; + if (split != -1) { + struct isl_vec *ineq; + if (n_split != 1) + split = context->op->best_split(context, tab); + if (split < 0) + goto error; + ineq = get_row_parameter_ineq(tab, split); + if (!ineq) + goto error; + is_strict(ineq); + reset_any_to_unknown(tab); + tab->row_sign[split] = isl_tab_row_pos; + sol_inc_level(sol); + find_in_pos(sol, tab, ineq->el); + tab->row_sign[split] = isl_tab_row_neg; + isl_seq_neg(ineq->el, ineq->el, ineq->size); + isl_int_sub_ui(ineq->el[0], ineq->el[0], 1); + if (!sol->error) + context->op->add_ineq(context, ineq->el, 0, 1); + isl_vec_free(ineq); + if (sol->error) + goto error; + continue; + } + if (tab->rational) + break; + row = first_non_integer_row(tab, &flags); + if (row < 0) + break; + if (ISL_FL_ISSET(flags, I_PAR)) { + if (ISL_FL_ISSET(flags, I_VAR)) { + if (isl_tab_mark_empty(tab) < 0) + goto error; + break; + } + row = add_cut(tab, row); + } else if (ISL_FL_ISSET(flags, I_VAR)) { + struct isl_vec *div; + struct isl_vec *ineq; + int d; + div = get_row_split_div(tab, row); + if (!div) + goto error; + d = context->op->get_div(context, tab, div); + isl_vec_free(div); + if (d < 0) + goto error; + ineq = ineq_for_div(context->op->peek_basic_set(context), d); + if (!ineq) + goto error; + sol_inc_level(sol); + no_sol_in_strict(sol, tab, ineq); + isl_seq_neg(ineq->el, ineq->el, ineq->size); + context->op->add_ineq(context, ineq->el, 1, 1); + isl_vec_free(ineq); + if (sol->error || !context->op->is_ok(context)) + goto error; + tab = set_row_cst_to_div(tab, row, d); + if (context->op->is_empty(context)) + break; + } else + row = add_parametric_cut(tab, row, context); + if (row < 0) + goto error; + } + if (r < 0) + goto error; +done: + sol_add(sol, tab); + isl_tab_free(tab); + return; +error: + isl_tab_free(tab); + sol->error = 1; +} + +/* Does "sol" contain a pair of partial solutions that could potentially + * be merged? + * + * We currently only check that "sol" is not in an error state + * and that there are at least two partial solutions of which the final two + * are defined at the same level. + */ +static int sol_has_mergeable_solutions(struct isl_sol *sol) +{ + if (sol->error) + return 0; + if (!sol->partial) + return 0; + if (!sol->partial->next) + return 0; + return sol->partial->level == sol->partial->next->level; +} + +/* Compute the lexicographic minimum of the set represented by the main + * tableau "tab" within the context "sol->context_tab". + * + * As a preprocessing step, we first transfer all the purely parametric + * equalities from the main tableau to the context tableau, i.e., + * parameters that have been pivoted to a row. + * These equalities are ignored by the main algorithm, because the + * corresponding rows may not be marked as being non-negative. + * In parts of the context where the added equality does not hold, + * the main tableau is marked as being empty. + * + * Before we embark on the actual computation, we save a copy + * of the context. When we return, we check if there are any + * partial solutions that can potentially be merged. If so, + * we perform a rollback to the initial state of the context. + * The merging of partial solutions happens inside calls to + * sol_dec_level that are pushed onto the undo stack of the context. + * If there are no partial solutions that can potentially be merged + * then the rollback is skipped as it would just be wasted effort. + */ +static void find_solutions_main(struct isl_sol *sol, struct isl_tab *tab) +{ + int row; + void *saved; + + if (!tab) + goto error; + + sol->level = 0; + + for (row = tab->n_redundant; row < tab->n_row; ++row) { + int p; + struct isl_vec *eq; + + if (!row_is_parameter_var(tab, row)) + continue; + if (tab->row_var[row] < tab->n_param) + p = tab->row_var[row]; + else + p = tab->row_var[row] + + tab->n_param - (tab->n_var - tab->n_div); + + eq = isl_vec_alloc(tab->mat->ctx, 1+tab->n_param+tab->n_div); + if (!eq) + goto error; + get_row_parameter_line(tab, row, eq->el); + isl_int_neg(eq->el[1 + p], tab->mat->row[row][0]); + eq = isl_vec_normalize(eq); + + sol_inc_level(sol); + no_sol_in_strict(sol, tab, eq); + + isl_seq_neg(eq->el, eq->el, eq->size); + sol_inc_level(sol); + no_sol_in_strict(sol, tab, eq); + isl_seq_neg(eq->el, eq->el, eq->size); + + sol->context->op->add_eq(sol->context, eq->el, 1, 1); + + isl_vec_free(eq); + + if (isl_tab_mark_redundant(tab, row) < 0) + goto error; + + if (sol->context->op->is_empty(sol->context)) + break; + + row = tab->n_redundant - 1; + } + + saved = sol->context->op->save(sol->context); + + find_solutions(sol, tab); + + if (sol_has_mergeable_solutions(sol)) + sol->context->op->restore(sol->context, saved); + else + sol->context->op->discard(saved); + + sol->level = 0; + sol_pop(sol); + + return; +error: + isl_tab_free(tab); + sol->error = 1; +} + +/* Check if integer division "div" of "dom" also occurs in "bmap". + * If so, return its position within the divs. + * If not, return -1. + */ +static int find_context_div(struct isl_basic_map *bmap, + struct isl_basic_set *dom, unsigned div) +{ + int i; + unsigned b_dim = isl_space_dim(bmap->dim, isl_dim_all); + unsigned d_dim = isl_space_dim(dom->dim, isl_dim_all); + + if (isl_int_is_zero(dom->div[div][0])) + return -1; + if (isl_seq_first_non_zero(dom->div[div] + 2 + d_dim, dom->n_div) != -1) + return -1; + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_seq_first_non_zero(bmap->div[i] + 2 + d_dim, + (b_dim - d_dim) + bmap->n_div) != -1) + continue; + if (isl_seq_eq(bmap->div[i], dom->div[div], 2 + d_dim)) + return i; + } + return -1; +} + +/* The correspondence between the variables in the main tableau, + * the context tableau, and the input map and domain is as follows. + * The first n_param and the last n_div variables of the main tableau + * form the variables of the context tableau. + * In the basic map, these n_param variables correspond to the + * parameters and the input dimensions. In the domain, they correspond + * to the parameters and the set dimensions. + * The n_div variables correspond to the integer divisions in the domain. + * To ensure that everything lines up, we may need to copy some of the + * integer divisions of the domain to the map. These have to be placed + * in the same order as those in the context and they have to be placed + * after any other integer divisions that the map may have. + * This function performs the required reordering. + */ +static __isl_give isl_basic_map *align_context_divs( + __isl_take isl_basic_map *bmap, __isl_keep isl_basic_set *dom) +{ + int i; + int common = 0; + int other; + + for (i = 0; i < dom->n_div; ++i) + if (find_context_div(bmap, dom, i) != -1) + common++; + other = bmap->n_div - common; + if (dom->n_div - common > 0) { + bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim), + dom->n_div - common, 0, 0); + if (!bmap) + return NULL; + } + for (i = 0; i < dom->n_div; ++i) { + int pos = find_context_div(bmap, dom, i); + if (pos < 0) { + pos = isl_basic_map_alloc_div(bmap); + if (pos < 0) + goto error; + isl_int_set_si(bmap->div[pos][0], 0); + } + if (pos != other + i) + isl_basic_map_swap_div(bmap, pos, other + i); + } + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Base case of isl_tab_basic_map_partial_lexopt, after removing + * some obvious symmetries. + * + * We make sure the divs in the domain are properly ordered, + * because they will be added one by one in the given order + * during the construction of the solution map. + * Furthermore, make sure that the known integer divisions + * appear before any unknown integer division because the solution + * may depend on the known integer divisions, while anything that + * depends on any variable starting from the first unknown integer + * division is ignored in sol_pma_add. + */ +static struct isl_sol *basic_map_partial_lexopt_base_sol( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max, + struct isl_sol *(*init)(__isl_keep isl_basic_map *bmap, + __isl_take isl_basic_set *dom, int track_empty, int max)) +{ + struct isl_tab *tab; + struct isl_sol *sol = NULL; + struct isl_context *context; + + if (dom->n_div) { + dom = isl_basic_set_sort_divs(dom); + bmap = align_context_divs(bmap, dom); + } + sol = init(bmap, dom, !!empty, max); + if (!sol) + goto error; + + context = sol->context; + if (isl_basic_set_plain_is_empty(context->op->peek_basic_set(context))) + /* nothing */; + else if (isl_basic_map_plain_is_empty(bmap)) { + if (sol->add_empty) + sol->add_empty(sol, + isl_basic_set_copy(context->op->peek_basic_set(context))); + } else { + tab = tab_for_lexmin(bmap, + context->op->peek_basic_set(context), 1, max); + tab = context->op->detect_nonnegative_parameters(context, tab); + find_solutions_main(sol, tab); + } + if (sol->error) + goto error; + + isl_basic_map_free(bmap); + return sol; +error: + sol_free(sol); + isl_basic_map_free(bmap); + return NULL; +} + +/* Base case of isl_tab_basic_map_partial_lexopt, after removing + * some obvious symmetries. + * + * We call basic_map_partial_lexopt_base_sol and extract the results. + */ +static __isl_give isl_map *basic_map_partial_lexopt_base( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max) +{ + isl_map *result = NULL; + struct isl_sol *sol; + struct isl_sol_map *sol_map; + + sol = basic_map_partial_lexopt_base_sol(bmap, dom, empty, max, + &sol_map_init); + if (!sol) + return NULL; + sol_map = (struct isl_sol_map *) sol; + + result = isl_map_copy(sol_map->map); + if (empty) + *empty = isl_set_copy(sol_map->empty); + sol_free(&sol_map->sol); + return result; +} + +/* Return a count of the number of occurrences of the "n" first + * variables in the inequality constraints of "bmap". + */ +static __isl_give int *count_occurrences(__isl_keep isl_basic_map *bmap, + int n) +{ + int i, j; + isl_ctx *ctx; + int *occurrences; + + if (!bmap) + return NULL; + ctx = isl_basic_map_get_ctx(bmap); + occurrences = isl_calloc_array(ctx, int, n); + if (!occurrences) + return NULL; + + for (i = 0; i < bmap->n_ineq; ++i) { + for (j = 0; j < n; ++j) { + if (!isl_int_is_zero(bmap->ineq[i][1 + j])) + occurrences[j]++; + } + } + + return occurrences; +} + +/* Do all of the "n" variables with non-zero coefficients in "c" + * occur in exactly a single constraint. + * "occurrences" is an array of length "n" containing the number + * of occurrences of each of the variables in the inequality constraints. + */ +static int single_occurrence(int n, isl_int *c, int *occurrences) +{ + int i; + + for (i = 0; i < n; ++i) { + if (isl_int_is_zero(c[i])) + continue; + if (occurrences[i] != 1) + return 0; + } + + return 1; +} + +/* Do all of the "n" initial variables that occur in inequality constraint + * "ineq" of "bmap" only occur in that constraint? + */ +static int all_single_occurrence(__isl_keep isl_basic_map *bmap, int ineq, + int n) +{ + int i, j; + + for (i = 0; i < n; ++i) { + if (isl_int_is_zero(bmap->ineq[ineq][1 + i])) + continue; + for (j = 0; j < bmap->n_ineq; ++j) { + if (j == ineq) + continue; + if (!isl_int_is_zero(bmap->ineq[j][1 + i])) + return 0; + } + } + + return 1; +} + +/* Structure used during detection of parallel constraints. + * n_in: number of "input" variables: isl_dim_param + isl_dim_in + * n_out: number of "output" variables: isl_dim_out + isl_dim_div + * val: the coefficients of the output variables + */ +struct isl_constraint_equal_info { + unsigned n_in; + unsigned n_out; + isl_int *val; +}; + +/* Check whether the coefficients of the output variables + * of the constraint in "entry" are equal to info->val. + */ +static int constraint_equal(const void *entry, const void *val) +{ + isl_int **row = (isl_int **)entry; + const struct isl_constraint_equal_info *info = val; + + return isl_seq_eq((*row) + 1 + info->n_in, info->val, info->n_out); +} + +/* Check whether "bmap" has a pair of constraints that have + * the same coefficients for the output variables. + * Note that the coefficients of the existentially quantified + * variables need to be zero since the existentially quantified + * of the result are usually not the same as those of the input. + * Furthermore, check that each of the input variables that occur + * in those constraints does not occur in any other constraint. + * If so, return true and return the row indices of the two constraints + * in *first and *second. + */ +static isl_bool parallel_constraints(__isl_keep isl_basic_map *bmap, + int *first, int *second) +{ + int i; + isl_ctx *ctx; + int *occurrences = NULL; + struct isl_hash_table *table = NULL; + struct isl_hash_table_entry *entry; + struct isl_constraint_equal_info info; + unsigned n_out; + unsigned n_div; + + ctx = isl_basic_map_get_ctx(bmap); + table = isl_hash_table_alloc(ctx, bmap->n_ineq); + if (!table) + goto error; + + info.n_in = isl_basic_map_dim(bmap, isl_dim_param) + + isl_basic_map_dim(bmap, isl_dim_in); + occurrences = count_occurrences(bmap, info.n_in); + if (info.n_in && !occurrences) + goto error; + n_out = isl_basic_map_dim(bmap, isl_dim_out); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + info.n_out = n_out + n_div; + for (i = 0; i < bmap->n_ineq; ++i) { + uint32_t hash; + + info.val = bmap->ineq[i] + 1 + info.n_in; + if (isl_seq_first_non_zero(info.val, n_out) < 0) + continue; + if (isl_seq_first_non_zero(info.val + n_out, n_div) >= 0) + continue; + if (!single_occurrence(info.n_in, bmap->ineq[i] + 1, + occurrences)) + continue; + hash = isl_seq_get_hash(info.val, info.n_out); + entry = isl_hash_table_find(ctx, table, hash, + constraint_equal, &info, 1); + if (!entry) + goto error; + if (entry->data) + break; + entry->data = &bmap->ineq[i]; + } + + if (i < bmap->n_ineq) { + *first = ((isl_int **)entry->data) - bmap->ineq; + *second = i; + } + + isl_hash_table_free(ctx, table); + free(occurrences); + + return i < bmap->n_ineq; +error: + isl_hash_table_free(ctx, table); + free(occurrences); + return isl_bool_error; +} + +/* Given a set of upper bounds in "var", add constraints to "bset" + * that make the i-th bound smallest. + * + * In particular, if there are n bounds b_i, then add the constraints + * + * b_i <= b_j for j > i + * b_i < b_j for j < i + */ +static __isl_give isl_basic_set *select_minimum(__isl_take isl_basic_set *bset, + __isl_keep isl_mat *var, int i) +{ + isl_ctx *ctx; + int j, k; + + ctx = isl_mat_get_ctx(var); + + for (j = 0; j < var->n_row; ++j) { + if (j == i) + continue; + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_combine(bset->ineq[k], ctx->one, var->row[j], + ctx->negone, var->row[i], var->n_col); + isl_int_set_si(bset->ineq[k][var->n_col], 0); + if (j < i) + isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1); + } + + bset = isl_basic_set_finalize(bset); + + return bset; +error: + isl_basic_set_free(bset); + return NULL; +} + +/* Given a set of upper bounds on the last "input" variable m, + * construct a set that assigns the minimal upper bound to m, i.e., + * construct a set that divides the space into cells where one + * of the upper bounds is smaller than all the others and assign + * this upper bound to m. + * + * In particular, if there are n bounds b_i, then the result + * consists of n basic sets, each one of the form + * + * m = b_i + * b_i <= b_j for j > i + * b_i < b_j for j < i + */ +static __isl_give isl_set *set_minimum(__isl_take isl_space *dim, + __isl_take isl_mat *var) +{ + int i, k; + isl_basic_set *bset = NULL; + isl_set *set = NULL; + + if (!dim || !var) + goto error; + + set = isl_set_alloc_space(isl_space_copy(dim), + var->n_row, ISL_SET_DISJOINT); + + for (i = 0; i < var->n_row; ++i) { + bset = isl_basic_set_alloc_space(isl_space_copy(dim), 0, + 1, var->n_row - 1); + k = isl_basic_set_alloc_equality(bset); + if (k < 0) + goto error; + isl_seq_cpy(bset->eq[k], var->row[i], var->n_col); + isl_int_set_si(bset->eq[k][var->n_col], -1); + bset = select_minimum(bset, var, i); + set = isl_set_add_basic_set(set, bset); + } + + isl_space_free(dim); + isl_mat_free(var); + return set; +error: + isl_basic_set_free(bset); + isl_set_free(set); + isl_space_free(dim); + isl_mat_free(var); + return NULL; +} + +/* Given that the last input variable of "bmap" represents the minimum + * of the bounds in "cst", check whether we need to split the domain + * based on which bound attains the minimum. + * + * A split is needed when the minimum appears in an integer division + * or in an equality. Otherwise, it is only needed if it appears in + * an upper bound that is different from the upper bounds on which it + * is defined. + */ +static isl_bool need_split_basic_map(__isl_keep isl_basic_map *bmap, + __isl_keep isl_mat *cst) +{ + int i, j; + unsigned total; + unsigned pos; + + pos = cst->n_col - 1; + total = isl_basic_map_dim(bmap, isl_dim_all); + + for (i = 0; i < bmap->n_div; ++i) + if (!isl_int_is_zero(bmap->div[i][2 + pos])) + return isl_bool_true; + + for (i = 0; i < bmap->n_eq; ++i) + if (!isl_int_is_zero(bmap->eq[i][1 + pos])) + return isl_bool_true; + + for (i = 0; i < bmap->n_ineq; ++i) { + if (isl_int_is_nonneg(bmap->ineq[i][1 + pos])) + continue; + if (!isl_int_is_negone(bmap->ineq[i][1 + pos])) + return isl_bool_true; + if (isl_seq_first_non_zero(bmap->ineq[i] + 1 + pos + 1, + total - pos - 1) >= 0) + return isl_bool_true; + + for (j = 0; j < cst->n_row; ++j) + if (isl_seq_eq(bmap->ineq[i], cst->row[j], cst->n_col)) + break; + if (j >= cst->n_row) + return isl_bool_true; + } + + return isl_bool_false; +} + +/* Given that the last set variable of "bset" represents the minimum + * of the bounds in "cst", check whether we need to split the domain + * based on which bound attains the minimum. + * + * We simply call need_split_basic_map here. This is safe because + * the position of the minimum is computed from "cst" and not + * from "bmap". + */ +static isl_bool need_split_basic_set(__isl_keep isl_basic_set *bset, + __isl_keep isl_mat *cst) +{ + return need_split_basic_map(bset_to_bmap(bset), cst); +} + +/* Given that the last set variable of "set" represents the minimum + * of the bounds in "cst", check whether we need to split the domain + * based on which bound attains the minimum. + */ +static isl_bool need_split_set(__isl_keep isl_set *set, __isl_keep isl_mat *cst) +{ + int i; + + for (i = 0; i < set->n; ++i) { + isl_bool split; + + split = need_split_basic_set(set->p[i], cst); + if (split < 0 || split) + return split; + } + + return isl_bool_false; +} + +/* Given a set of which the last set variable is the minimum + * of the bounds in "cst", split each basic set in the set + * in pieces where one of the bounds is (strictly) smaller than the others. + * This subdivision is given in "min_expr". + * The variable is subsequently projected out. + * + * We only do the split when it is needed. + * For example if the last input variable m = min(a,b) and the only + * constraints in the given basic set are lower bounds on m, + * i.e., l <= m = min(a,b), then we can simply project out m + * to obtain l <= a and l <= b, without having to split on whether + * m is equal to a or b. + */ +static __isl_give isl_set *split(__isl_take isl_set *empty, + __isl_take isl_set *min_expr, __isl_take isl_mat *cst) +{ + int n_in; + int i; + isl_space *dim; + isl_set *res; + + if (!empty || !min_expr || !cst) + goto error; + + n_in = isl_set_dim(empty, isl_dim_set); + dim = isl_set_get_space(empty); + dim = isl_space_drop_dims(dim, isl_dim_set, n_in - 1, 1); + res = isl_set_empty(dim); + + for (i = 0; i < empty->n; ++i) { + isl_bool split; + isl_set *set; + + set = isl_set_from_basic_set(isl_basic_set_copy(empty->p[i])); + split = need_split_basic_set(empty->p[i], cst); + if (split < 0) + set = isl_set_free(set); + else if (split) + set = isl_set_intersect(set, isl_set_copy(min_expr)); + set = isl_set_remove_dims(set, isl_dim_set, n_in - 1, 1); + + res = isl_set_union_disjoint(res, set); + } + + isl_set_free(empty); + isl_set_free(min_expr); + isl_mat_free(cst); + return res; +error: + isl_set_free(empty); + isl_set_free(min_expr); + isl_mat_free(cst); + return NULL; +} + +/* Given a map of which the last input variable is the minimum + * of the bounds in "cst", split each basic set in the set + * in pieces where one of the bounds is (strictly) smaller than the others. + * This subdivision is given in "min_expr". + * The variable is subsequently projected out. + * + * The implementation is essentially the same as that of "split". + */ +static __isl_give isl_map *split_domain(__isl_take isl_map *opt, + __isl_take isl_set *min_expr, __isl_take isl_mat *cst) +{ + int n_in; + int i; + isl_space *dim; + isl_map *res; + + if (!opt || !min_expr || !cst) + goto error; + + n_in = isl_map_dim(opt, isl_dim_in); + dim = isl_map_get_space(opt); + dim = isl_space_drop_dims(dim, isl_dim_in, n_in - 1, 1); + res = isl_map_empty(dim); + + for (i = 0; i < opt->n; ++i) { + isl_map *map; + isl_bool split; + + map = isl_map_from_basic_map(isl_basic_map_copy(opt->p[i])); + split = need_split_basic_map(opt->p[i], cst); + if (split < 0) + map = isl_map_free(map); + else if (split) + map = isl_map_intersect_domain(map, + isl_set_copy(min_expr)); + map = isl_map_remove_dims(map, isl_dim_in, n_in - 1, 1); + + res = isl_map_union_disjoint(res, map); + } + + isl_map_free(opt); + isl_set_free(min_expr); + isl_mat_free(cst); + return res; +error: + isl_map_free(opt); + isl_set_free(min_expr); + isl_mat_free(cst); + return NULL; +} + +static __isl_give isl_map *basic_map_partial_lexopt( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max); + +/* This function is called from basic_map_partial_lexopt_symm. + * The last variable of "bmap" and "dom" corresponds to the minimum + * of the bounds in "cst". "map_space" is the space of the original + * input relation (of basic_map_partial_lexopt_symm) and "set_space" + * is the space of the original domain. + * + * We recursively call basic_map_partial_lexopt and then plug in + * the definition of the minimum in the result. + */ +static __isl_give isl_map *basic_map_partial_lexopt_symm_core( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max, __isl_take isl_mat *cst, + __isl_take isl_space *map_space, __isl_take isl_space *set_space) +{ + isl_map *opt; + isl_set *min_expr; + + min_expr = set_minimum(isl_basic_set_get_space(dom), isl_mat_copy(cst)); + + opt = basic_map_partial_lexopt(bmap, dom, empty, max); + + if (empty) { + *empty = split(*empty, + isl_set_copy(min_expr), isl_mat_copy(cst)); + *empty = isl_set_reset_space(*empty, set_space); + } + + opt = split_domain(opt, min_expr, cst); + opt = isl_map_reset_space(opt, map_space); + + return opt; +} + +/* Extract a domain from "bmap" for the purpose of computing + * a lexicographic optimum. + * + * This function is only called when the caller wants to compute a full + * lexicographic optimum, i.e., without specifying a domain. In this case, + * the caller is not interested in the part of the domain space where + * there is no solution and the domain can be initialized to those constraints + * of "bmap" that only involve the parameters and the input dimensions. + * This relieves the parametric programming engine from detecting those + * inequalities and transferring them to the context. More importantly, + * it ensures that those inequalities are transferred first and not + * intermixed with inequalities that actually split the domain. + * + * If the caller does not require the absence of existentially quantified + * variables in the result (i.e., if ISL_OPT_QE is not set in "flags"), + * then the actual domain of "bmap" can be used. This ensures that + * the domain does not need to be split at all just to separate out + * pieces of the domain that do not have a solution from piece that do. + * This domain cannot be used in general because it may involve + * (unknown) existentially quantified variables which will then also + * appear in the solution. + */ +static __isl_give isl_basic_set *extract_domain(__isl_keep isl_basic_map *bmap, + unsigned flags) +{ + int n_div; + int n_out; + + n_div = isl_basic_map_dim(bmap, isl_dim_div); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + bmap = isl_basic_map_copy(bmap); + if (ISL_FL_ISSET(flags, ISL_OPT_QE)) { + bmap = isl_basic_map_drop_constraints_involving_dims(bmap, + isl_dim_div, 0, n_div); + bmap = isl_basic_map_drop_constraints_involving_dims(bmap, + isl_dim_out, 0, n_out); + } + return isl_basic_map_domain(bmap); +} + +#undef TYPE +#define TYPE isl_map +#undef SUFFIX +#define SUFFIX +#include "isl_tab_lexopt_templ.c" + +/* Extract the subsequence of the sample value of "tab" + * starting at "pos" and of length "len". + */ +static __isl_give isl_vec *extract_sample_sequence(struct isl_tab *tab, + int pos, int len) +{ + int i; + isl_ctx *ctx; + isl_vec *v; + + ctx = isl_tab_get_ctx(tab); + v = isl_vec_alloc(ctx, len); + if (!v) + return NULL; + for (i = 0; i < len; ++i) { + if (!tab->var[pos + i].is_row) { + isl_int_set_si(v->el[i], 0); + } else { + int row; + + row = tab->var[pos + i].index; + isl_int_divexact(v->el[i], tab->mat->row[row][1], + tab->mat->row[row][0]); + } + } + + return v; +} + +/* Check if the sequence of variables starting at "pos" + * represents a trivial solution according to "trivial". + * That is, is the result of applying "trivial" to this sequence + * equal to the zero vector? + */ +static isl_bool region_is_trivial(struct isl_tab *tab, int pos, + __isl_keep isl_mat *trivial) +{ + int n, len; + isl_vec *v; + isl_bool is_trivial; + + if (!trivial) + return isl_bool_error; + + n = isl_mat_rows(trivial); + if (n == 0) + return isl_bool_false; + + len = isl_mat_cols(trivial); + v = extract_sample_sequence(tab, pos, len); + v = isl_mat_vec_product(isl_mat_copy(trivial), v); + is_trivial = isl_vec_is_zero(v); + isl_vec_free(v); + + return is_trivial; +} + +/* Global internal data for isl_tab_basic_set_non_trivial_lexmin. + * + * "n_op" is the number of initial coordinates to optimize, + * as passed to isl_tab_basic_set_non_trivial_lexmin. + * "region" is the "n_region"-sized array of regions passed + * to isl_tab_basic_set_non_trivial_lexmin. + * + * "tab" is the tableau that corresponds to the ILP problem. + * "local" is an array of local data structure, one for each + * (potential) level of the backtracking procedure of + * isl_tab_basic_set_non_trivial_lexmin. + * "v" is a pre-allocated vector that can be used for adding + * constraints to the tableau. + * + * "sol" contains the best solution found so far. + * It is initialized to a vector of size zero. + */ +struct isl_lexmin_data { + int n_op; + int n_region; + struct isl_trivial_region *region; + + struct isl_tab *tab; + struct isl_local_region *local; + isl_vec *v; + + isl_vec *sol; +}; + +/* Return the index of the first trivial region, "n_region" if all regions + * are non-trivial or -1 in case of error. + */ +static int first_trivial_region(struct isl_lexmin_data *data) +{ + int i; + + for (i = 0; i < data->n_region; ++i) { + isl_bool trivial; + trivial = region_is_trivial(data->tab, data->region[i].pos, + data->region[i].trivial); + if (trivial < 0) + return -1; + if (trivial) + return i; + } + + return data->n_region; +} + +/* 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 than 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. + * "n_zero" is the number of coefficients that have been forced zero + * by previous calls to this function at the same level. + * Return the updated number of forced zero coefficients or -1 on error. + * + * This function assumes that at least 2 * (n_op - n_zero) more rows and + * at least 2 * (n_op - n_zero) more elements in the constraint array + * are available in the tableau. + */ +static int force_better_solution(struct isl_tab *tab, + __isl_keep isl_vec *sol, int n_op, int n_zero) +{ + int i, n; + isl_ctx *ctx; + isl_vec *v = NULL; + + if (!sol) + return -1; + + for (i = n_zero; 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 n_op; + } + + ctx = isl_vec_get_ctx(sol); + v = isl_vec_alloc(ctx, 1 + tab->n_var); + if (!v) + return -1; + + n = i + 1; + for (; i >= n_zero; --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 n; +error: + isl_vec_free(v); + return -1; +} + +/* Fix triviality direction "dir" of the given region to zero. + * + * This function assumes that at least two more rows and at least + * two more elements in the constraint array are available in the tableau. + */ +static isl_stat fix_zero(struct isl_tab *tab, struct isl_trivial_region *region, + int dir, struct isl_lexmin_data *data) +{ + int len; + + data->v = isl_vec_clr(data->v); + if (!data->v) + return isl_stat_error; + len = isl_mat_cols(region->trivial); + isl_seq_cpy(data->v->el + 1 + region->pos, region->trivial->row[dir], + len); + if (add_lexmin_eq(tab, data->v->el) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +/* This function selects case "side" for non-triviality region "region", + * assuming all the equality constraints have been imposed already. + * In particular, the triviality direction side/2 is made positive + * if side is even and made negative if side is odd. + * + * This function assumes that at least one more row and at least + * one more element in the constraint array are available in the tableau. + */ +static struct isl_tab *pos_neg(struct isl_tab *tab, + struct isl_trivial_region *region, + int side, struct isl_lexmin_data *data) +{ + int len; + + data->v = isl_vec_clr(data->v); + if (!data->v) + goto error; + isl_int_set_si(data->v->el[0], -1); + len = isl_mat_cols(region->trivial); + if (side % 2 == 0) + isl_seq_cpy(data->v->el + 1 + region->pos, + region->trivial->row[side / 2], len); + else + isl_seq_neg(data->v->el + 1 + region->pos, + region->trivial->row[side / 2], len); + return add_lexmin_ineq(tab, data->v->el); +error: + isl_tab_free(tab); + return NULL; +} + +/* Local data at each level of the backtracking procedure of + * isl_tab_basic_set_non_trivial_lexmin. + * + * "update" is set if a solution has been found in the current case + * of this level, such that a better solution needs to be enforced + * in the next case. + * "n_zero" is the number of initial coordinates that have already + * been forced to be zero at this level. + * "region" is the non-triviality region considered at this level. + * "side" is the index of the current case at this level. + * "n" is the number of triviality directions. + * "snap" is a snapshot of the tableau holding a state that needs + * to be satisfied by all subsequent cases. + */ +struct isl_local_region { + int update; + int n_zero; + int region; + int side; + int n; + struct isl_tab_undo *snap; +}; + +/* Initialize the global data structure "data" used while solving + * the ILP problem "bset". + */ +static isl_stat init_lexmin_data(struct isl_lexmin_data *data, + __isl_keep isl_basic_set *bset) +{ + isl_ctx *ctx; + + ctx = isl_basic_set_get_ctx(bset); + + data->tab = tab_for_lexmin(bset, NULL, 0, 0); + if (!data->tab) + return isl_stat_error; + + data->v = isl_vec_alloc(ctx, 1 + data->tab->n_var); + if (!data->v) + return isl_stat_error; + data->local = isl_calloc_array(ctx, struct isl_local_region, + data->n_region); + if (data->n_region && !data->local) + return isl_stat_error; + + data->sol = isl_vec_alloc(ctx, 0); + + return isl_stat_ok; +} + +/* Mark all outer levels as requiring a better solution + * in the next cases. + */ +static void update_outer_levels(struct isl_lexmin_data *data, int level) +{ + int i; + + for (i = 0; i < level; ++i) + data->local[i].update = 1; +} + +/* Initialize "local" to refer to region "region" and + * to initiate processing at this level. + */ +static void init_local_region(struct isl_local_region *local, int region, + struct isl_lexmin_data *data) +{ + local->n = isl_mat_rows(data->region[region].trivial); + local->region = region; + local->side = 0; + local->update = 0; + local->n_zero = 0; +} + +/* What to do next after entering a level of the backtracking procedure. + * + * error: some error has occurred; abort + * done: an optimal solution has been found; stop search + * backtrack: backtrack to the previous level + * handle: add the constraints for the current level and + * move to the next level + */ +enum isl_next { + isl_next_error = -1, + isl_next_done, + isl_next_backtrack, + isl_next_handle, +}; + +/* Have all cases of the current region been considered? + * If there are n directions, then there are 2n cases. + * + * The constraints in the current tableau are imposed + * in all subsequent cases. This means that if the current + * tableau is empty, then none of those cases should be considered + * anymore and all cases have effectively been considered. + */ +static int finished_all_cases(struct isl_local_region *local, + struct isl_lexmin_data *data) +{ + if (data->tab->empty) + return 1; + return local->side >= 2 * local->n; +} + +/* Enter level "level" of the backtracking search and figure out + * what to do next. "init" is set if the level was entered + * from a higher level and needs to be initialized. + * Otherwise, the level is entered as a result of backtracking and + * the tableau needs to be restored to a position that can + * be used for the next case at this level. + * The snapshot is assumed to have been saved in the previous case, + * before the constraints specific to that case were added. + * + * In the initialization case, the local region is initialized + * to point to the first violated region. + * If the constraints of all regions are satisfied by the current + * sample of the tableau, then tell the caller to continue looking + * for a better solution or to stop searching if an optimal solution + * has been found. + * + * If the tableau is empty or if all cases at the current level + * have been considered, then the caller needs to backtrack as well. + */ +static enum isl_next enter_level(int level, int init, + struct isl_lexmin_data *data) +{ + struct isl_local_region *local = &data->local[level]; + + if (init) { + int r; + + data->tab = cut_to_integer_lexmin(data->tab, CUT_ONE); + if (!data->tab) + return isl_next_error; + if (data->tab->empty) + return isl_next_backtrack; + r = first_trivial_region(data); + if (r < 0) + return isl_next_error; + if (r == data->n_region) { + update_outer_levels(data, level); + isl_vec_free(data->sol); + data->sol = isl_tab_get_sample_value(data->tab); + if (!data->sol) + return isl_next_error; + if (is_optimal(data->sol, data->n_op)) + return isl_next_done; + return isl_next_backtrack; + } + if (level >= data->n_region) + isl_die(isl_vec_get_ctx(data->v), isl_error_internal, + "nesting level too deep", + return isl_next_error); + init_local_region(local, r, data); + if (isl_tab_extend_cons(data->tab, + 2 * local->n + 2 * data->n_op) < 0) + return isl_next_error; + } else { + if (isl_tab_rollback(data->tab, local->snap) < 0) + return isl_next_error; + } + + if (finished_all_cases(local, data)) + return isl_next_backtrack; + return isl_next_handle; +} + +/* If a solution has been found in the previous case at this level + * (marked by local->update being set), then add constraints + * that enforce a better solution in the present and all following cases. + * The constraints only need to be imposed once because they are + * included in the snapshot (taken in pick_side) that will be used in + * subsequent cases. + */ +static isl_stat better_next_side(struct isl_local_region *local, + struct isl_lexmin_data *data) +{ + if (!local->update) + return isl_stat_ok; + + local->n_zero = force_better_solution(data->tab, + data->sol, data->n_op, local->n_zero); + if (local->n_zero < 0) + return isl_stat_error; + + local->update = 0; + + return isl_stat_ok; +} + +/* Add constraints to data->tab that select the current case (local->side) + * at the current level. + * + * If the linear combinations v should not be zero, then the cases are + * v_0 >= 1 + * v_0 <= -1 + * v_0 = 0 and v_1 >= 1 + * v_0 = 0 and v_1 <= -1 + * v_0 = 0 and v_1 = 0 and v_2 >= 1 + * v_0 = 0 and v_1 = 0 and v_2 <= -1 + * ... + * in this order. + * + * A snapshot is taken after the equality constraint (if any) has been added + * such that the next case can start off from this position. + * The rollback to this position is performed in enter_level. + */ +static isl_stat pick_side(struct isl_local_region *local, + struct isl_lexmin_data *data) +{ + struct isl_trivial_region *region; + int side, base; + + region = &data->region[local->region]; + side = local->side; + base = 2 * (side/2); + + if (side == base && base >= 2 && + fix_zero(data->tab, region, base / 2 - 1, data) < 0) + return isl_stat_error; + + local->snap = isl_tab_snap(data->tab); + if (isl_tab_push_basis(data->tab) < 0) + return isl_stat_error; + + data->tab = pos_neg(data->tab, region, side, data); + if (!data->tab) + return isl_stat_error; + return isl_stat_ok; +} + +/* Free the memory associated to "data". + */ +static void clear_lexmin_data(struct isl_lexmin_data *data) +{ + free(data->local); + isl_vec_free(data->v); + isl_tab_free(data->tab); +} + +/* 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 solutions 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 + * triviality directions on a sequence of variables that starts + * at a given position. A solution is non-trivial on such a region if + * at least one of the triviality directions is non-zero + * on that sequence of variables. + * + * 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 an initially trivial region + * that is forced to be non-trivial. + * At each level we consider 2 * n cases, where n + * is the number of triviality directions. + * In terms of those n directions v_i, we consider the cases + * v_0 >= 1 + * v_0 <= -1 + * v_0 = 0 and v_1 >= 1 + * v_0 = 0 and v_1 <= -1 + * v_0 = 0 and v_1 = 0 and v_2 >= 1 + * v_0 = 0 and v_1 = 0 and v_2 <= -1 + * ... + * in this order. + */ +__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_trivial_region *region, + int (*conflict)(int con, void *user), void *user) +{ + struct isl_lexmin_data data = { n_op, n_region, region }; + int level, init; + + if (!bset) + return NULL; + + if (init_lexmin_data(&data, bset) < 0) + goto error; + data.tab->conflict = conflict; + data.tab->conflict_user = user; + + level = 0; + init = 1; + + while (level >= 0) { + enum isl_next next; + struct isl_local_region *local = &data.local[level]; + + next = enter_level(level, init, &data); + if (next < 0) + goto error; + if (next == isl_next_done) + break; + if (next == isl_next_backtrack) { + level--; + init = 0; + continue; + } + + if (better_next_side(local, &data) < 0) + goto error; + if (pick_side(local, &data) < 0) + goto error; + + local->side++; + level++; + init = 1; + } + + clear_lexmin_data(&data); + isl_basic_set_free(bset); + + return data.sol; +error: + clear_lexmin_data(&data); + isl_basic_set_free(bset); + isl_vec_free(data.sol); + return NULL; +} + +/* Wrapper for a tableau that is used for computing + * the lexicographically smallest rational point of a non-negative set. + * This point is represented by the sample value of "tab", + * unless "tab" is empty. + */ +struct isl_tab_lexmin { + isl_ctx *ctx; + struct isl_tab *tab; +}; + +/* Free "tl" and return NULL. + */ +__isl_null isl_tab_lexmin *isl_tab_lexmin_free(__isl_take isl_tab_lexmin *tl) +{ + if (!tl) + return NULL; + isl_ctx_deref(tl->ctx); + isl_tab_free(tl->tab); + free(tl); + + return NULL; +} + +/* Construct an isl_tab_lexmin for computing + * the lexicographically smallest rational point in "bset", + * assuming that all variables are non-negative. + */ +__isl_give isl_tab_lexmin *isl_tab_lexmin_from_basic_set( + __isl_take isl_basic_set *bset) +{ + isl_ctx *ctx; + isl_tab_lexmin *tl; + + if (!bset) + return NULL; + + ctx = isl_basic_set_get_ctx(bset); + tl = isl_calloc_type(ctx, struct isl_tab_lexmin); + if (!tl) + goto error; + tl->ctx = ctx; + isl_ctx_ref(ctx); + tl->tab = tab_for_lexmin(bset, NULL, 0, 0); + isl_basic_set_free(bset); + if (!tl->tab) + return isl_tab_lexmin_free(tl); + return tl; +error: + isl_basic_set_free(bset); + isl_tab_lexmin_free(tl); + return NULL; +} + +/* Return the dimension of the set represented by "tl". + */ +int isl_tab_lexmin_dim(__isl_keep isl_tab_lexmin *tl) +{ + return tl ? tl->tab->n_var : -1; +} + +/* Add the equality with coefficients "eq" to "tl", updating the optimal + * solution if needed. + * The equality is added as two opposite inequality constraints. + */ +__isl_give isl_tab_lexmin *isl_tab_lexmin_add_eq(__isl_take isl_tab_lexmin *tl, + isl_int *eq) +{ + unsigned n_var; + + if (!tl || !eq) + return isl_tab_lexmin_free(tl); + + if (isl_tab_extend_cons(tl->tab, 2) < 0) + return isl_tab_lexmin_free(tl); + n_var = tl->tab->n_var; + isl_seq_neg(eq, eq, 1 + n_var); + tl->tab = add_lexmin_ineq(tl->tab, eq); + isl_seq_neg(eq, eq, 1 + n_var); + tl->tab = add_lexmin_ineq(tl->tab, eq); + + if (!tl->tab) + return isl_tab_lexmin_free(tl); + + return tl; +} + +/* Add cuts to "tl" until the sample value reaches an integer value or + * until the result becomes empty. + */ +__isl_give isl_tab_lexmin *isl_tab_lexmin_cut_to_integer( + __isl_take isl_tab_lexmin *tl) +{ + if (!tl) + return NULL; + tl->tab = cut_to_integer_lexmin(tl->tab, CUT_ONE); + if (!tl->tab) + return isl_tab_lexmin_free(tl); + return tl; +} + +/* Return the lexicographically smallest rational point in the basic set + * from which "tl" was constructed. + * If the original input was empty, then return a zero-length vector. + */ +__isl_give isl_vec *isl_tab_lexmin_get_solution(__isl_keep isl_tab_lexmin *tl) +{ + if (!tl) + return NULL; + if (tl->tab->empty) + return isl_vec_alloc(tl->ctx, 0); + else + return isl_tab_get_sample_value(tl->tab); +} + +struct isl_sol_pma { + struct isl_sol sol; + isl_pw_multi_aff *pma; + isl_set *empty; +}; + +static void sol_pma_free(struct isl_sol *sol) +{ + struct isl_sol_pma *sol_pma = (struct isl_sol_pma *) sol; + isl_pw_multi_aff_free(sol_pma->pma); + isl_set_free(sol_pma->empty); +} + +/* This function is called for parts of the context where there is + * no solution, with "bset" corresponding to the context tableau. + * Simply add the basic set to the set "empty". + */ +static void sol_pma_add_empty(struct isl_sol_pma *sol, + __isl_take isl_basic_set *bset) +{ + if (!bset || !sol->empty) + goto error; + + sol->empty = isl_set_grow(sol->empty, 1); + bset = isl_basic_set_simplify(bset); + bset = isl_basic_set_finalize(bset); + sol->empty = isl_set_add_basic_set(sol->empty, bset); + if (!sol->empty) + sol->sol.error = 1; + return; +error: + isl_basic_set_free(bset); + sol->sol.error = 1; +} + +/* Given a basic set "dom" that represents the context and a tuple of + * affine expressions "maff" defined over this domain, construct + * an isl_pw_multi_aff with a single cell corresponding to "dom" and + * the affine expressions in "maff". + */ +static void sol_pma_add(struct isl_sol_pma *sol, + __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *maff) +{ + isl_pw_multi_aff *pma; + + dom = isl_basic_set_simplify(dom); + dom = isl_basic_set_finalize(dom); + pma = isl_pw_multi_aff_alloc(isl_set_from_basic_set(dom), maff); + sol->pma = isl_pw_multi_aff_add_disjoint(sol->pma, pma); + if (!sol->pma) + sol->sol.error = 1; +} + +static void sol_pma_add_empty_wrap(struct isl_sol *sol, + __isl_take isl_basic_set *bset) +{ + sol_pma_add_empty((struct isl_sol_pma *)sol, bset); +} + +static void sol_pma_add_wrap(struct isl_sol *sol, + __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma) +{ + sol_pma_add((struct isl_sol_pma *)sol, dom, ma); +} + +/* Construct an isl_sol_pma structure for accumulating the solution. + * If track_empty is set, then we also keep track of the parts + * of the context where there is no solution. + * If max is set, then we are solving a maximization, rather than + * a minimization problem, which means that the variables in the + * tableau have value "M - x" rather than "M + x". + */ +static struct isl_sol *sol_pma_init(__isl_keep isl_basic_map *bmap, + __isl_take isl_basic_set *dom, int track_empty, int max) +{ + struct isl_sol_pma *sol_pma = NULL; + isl_space *space; + + if (!bmap) + goto error; + + sol_pma = isl_calloc_type(bmap->ctx, struct isl_sol_pma); + if (!sol_pma) + goto error; + + sol_pma->sol.free = &sol_pma_free; + if (sol_init(&sol_pma->sol, bmap, dom, max) < 0) + goto error; + sol_pma->sol.add = &sol_pma_add_wrap; + sol_pma->sol.add_empty = track_empty ? &sol_pma_add_empty_wrap : NULL; + space = isl_space_copy(sol_pma->sol.space); + sol_pma->pma = isl_pw_multi_aff_empty(space); + if (!sol_pma->pma) + goto error; + + if (track_empty) { + sol_pma->empty = isl_set_alloc_space(isl_basic_set_get_space(dom), + 1, ISL_SET_DISJOINT); + if (!sol_pma->empty) + goto error; + } + + isl_basic_set_free(dom); + return &sol_pma->sol; +error: + isl_basic_set_free(dom); + sol_free(&sol_pma->sol); + return NULL; +} + +/* Base case of isl_tab_basic_map_partial_lexopt, after removing + * some obvious symmetries. + * + * We call basic_map_partial_lexopt_base_sol and extract the results. + */ +static __isl_give isl_pw_multi_aff *basic_map_partial_lexopt_base_pw_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max) +{ + isl_pw_multi_aff *result = NULL; + struct isl_sol *sol; + struct isl_sol_pma *sol_pma; + + sol = basic_map_partial_lexopt_base_sol(bmap, dom, empty, max, + &sol_pma_init); + if (!sol) + return NULL; + sol_pma = (struct isl_sol_pma *) sol; + + result = isl_pw_multi_aff_copy(sol_pma->pma); + if (empty) + *empty = isl_set_copy(sol_pma->empty); + sol_free(&sol_pma->sol); + return result; +} + +/* Given that the last input variable of "maff" represents the minimum + * of some bounds, check whether we need to plug in the expression + * of the minimum. + * + * In particular, check if the last input variable appears in any + * of the expressions in "maff". + */ +static int need_substitution(__isl_keep isl_multi_aff *maff) +{ + int i; + unsigned pos; + + pos = isl_multi_aff_dim(maff, isl_dim_in) - 1; + + for (i = 0; i < maff->n; ++i) + if (isl_aff_involves_dims(maff->p[i], isl_dim_in, pos, 1)) + return 1; + + return 0; +} + +/* Given a set of upper bounds on the last "input" variable m, + * construct a piecewise affine expression that selects + * the minimal upper bound to m, i.e., + * divide the space into cells where one + * of the upper bounds is smaller than all the others and select + * this upper bound on that cell. + * + * In particular, if there are n bounds b_i, then the result + * consists of n cell, each one of the form + * + * b_i <= b_j for j > i + * b_i < b_j for j < i + * + * The affine expression on this cell is + * + * b_i + */ +static __isl_give isl_pw_aff *set_minimum_pa(__isl_take isl_space *space, + __isl_take isl_mat *var) +{ + int i; + isl_aff *aff = NULL; + isl_basic_set *bset = NULL; + isl_pw_aff *paff = NULL; + isl_space *pw_space; + isl_local_space *ls = NULL; + + if (!space || !var) + goto error; + + ls = isl_local_space_from_space(isl_space_copy(space)); + pw_space = isl_space_copy(space); + pw_space = isl_space_from_domain(pw_space); + pw_space = isl_space_add_dims(pw_space, isl_dim_out, 1); + paff = isl_pw_aff_alloc_size(pw_space, var->n_row); + + for (i = 0; i < var->n_row; ++i) { + isl_pw_aff *paff_i; + + aff = isl_aff_alloc(isl_local_space_copy(ls)); + bset = isl_basic_set_alloc_space(isl_space_copy(space), 0, + 0, var->n_row - 1); + if (!aff || !bset) + goto error; + isl_int_set_si(aff->v->el[0], 1); + isl_seq_cpy(aff->v->el + 1, var->row[i], var->n_col); + isl_int_set_si(aff->v->el[1 + var->n_col], 0); + bset = select_minimum(bset, var, i); + paff_i = isl_pw_aff_alloc(isl_set_from_basic_set(bset), aff); + paff = isl_pw_aff_add_disjoint(paff, paff_i); + } + + isl_local_space_free(ls); + isl_space_free(space); + isl_mat_free(var); + return paff; +error: + isl_aff_free(aff); + isl_basic_set_free(bset); + isl_pw_aff_free(paff); + isl_local_space_free(ls); + isl_space_free(space); + isl_mat_free(var); + return NULL; +} + +/* Given a piecewise multi-affine expression of which the last input variable + * is the minimum of the bounds in "cst", plug in the value of the minimum. + * This minimum expression is given in "min_expr_pa". + * The set "min_expr" contains the same information, but in the form of a set. + * The variable is subsequently projected out. + * + * The implementation is similar to those of "split" and "split_domain". + * If the variable appears in a given expression, then minimum expression + * is plugged in. Otherwise, if the variable appears in the constraints + * and a split is required, then the domain is split. Otherwise, no split + * is performed. + */ +static __isl_give isl_pw_multi_aff *split_domain_pma( + __isl_take isl_pw_multi_aff *opt, __isl_take isl_pw_aff *min_expr_pa, + __isl_take isl_set *min_expr, __isl_take isl_mat *cst) +{ + int n_in; + int i; + isl_space *space; + isl_pw_multi_aff *res; + + if (!opt || !min_expr || !cst) + goto error; + + n_in = isl_pw_multi_aff_dim(opt, isl_dim_in); + space = isl_pw_multi_aff_get_space(opt); + space = isl_space_drop_dims(space, isl_dim_in, n_in - 1, 1); + res = isl_pw_multi_aff_empty(space); + + for (i = 0; i < opt->n; ++i) { + isl_pw_multi_aff *pma; + + pma = isl_pw_multi_aff_alloc(isl_set_copy(opt->p[i].set), + isl_multi_aff_copy(opt->p[i].maff)); + if (need_substitution(opt->p[i].maff)) + pma = isl_pw_multi_aff_substitute(pma, + isl_dim_in, n_in - 1, min_expr_pa); + else { + isl_bool split; + split = need_split_set(opt->p[i].set, cst); + if (split < 0) + pma = isl_pw_multi_aff_free(pma); + else if (split) + pma = isl_pw_multi_aff_intersect_domain(pma, + isl_set_copy(min_expr)); + } + pma = isl_pw_multi_aff_project_out(pma, + isl_dim_in, n_in - 1, 1); + + res = isl_pw_multi_aff_add_disjoint(res, pma); + } + + isl_pw_multi_aff_free(opt); + isl_pw_aff_free(min_expr_pa); + isl_set_free(min_expr); + isl_mat_free(cst); + return res; +error: + isl_pw_multi_aff_free(opt); + isl_pw_aff_free(min_expr_pa); + isl_set_free(min_expr); + isl_mat_free(cst); + return NULL; +} + +static __isl_give isl_pw_multi_aff *basic_map_partial_lexopt_pw_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max); + +/* This function is called from basic_map_partial_lexopt_symm. + * The last variable of "bmap" and "dom" corresponds to the minimum + * of the bounds in "cst". "map_space" is the space of the original + * input relation (of basic_map_partial_lexopt_symm) and "set_space" + * is the space of the original domain. + * + * We recursively call basic_map_partial_lexopt and then plug in + * the definition of the minimum in the result. + */ +static __isl_give isl_pw_multi_aff * +basic_map_partial_lexopt_symm_core_pw_multi_aff( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom, + __isl_give isl_set **empty, int max, __isl_take isl_mat *cst, + __isl_take isl_space *map_space, __isl_take isl_space *set_space) +{ + isl_pw_multi_aff *opt; + isl_pw_aff *min_expr_pa; + isl_set *min_expr; + + min_expr = set_minimum(isl_basic_set_get_space(dom), isl_mat_copy(cst)); + min_expr_pa = set_minimum_pa(isl_basic_set_get_space(dom), + isl_mat_copy(cst)); + + opt = basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, max); + + if (empty) { + *empty = split(*empty, + isl_set_copy(min_expr), isl_mat_copy(cst)); + *empty = isl_set_reset_space(*empty, set_space); + } + + opt = split_domain_pma(opt, min_expr_pa, min_expr, cst); + opt = isl_pw_multi_aff_reset_space(opt, map_space); + + return opt; +} + +#undef TYPE +#define TYPE isl_pw_multi_aff +#undef SUFFIX +#define SUFFIX _pw_multi_aff +#include "isl_tab_lexopt_templ.c" Index: contrib/isl/isl_tarjan.h =================================================================== --- /dev/null +++ contrib/isl/isl_tarjan.h @@ -0,0 +1,42 @@ +#ifndef ISL_TARJAN_H +#define ISL_TARJAN_H + +/* Structure for representing the nodes in the graph being traversed + * using Tarjan's algorithm. + * 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_tarjan_node { + int index; + int min_index; + int on_stack; +}; + +/* Structure for representing the graph being traversed + * using Tarjan's algorithm. + * len is the number of nodes + * node is an array of nodes + * 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 + * order contains the elements of the components separated by -1 + * op represents the current position in order + */ +struct isl_tarjan_graph { + int len; + struct isl_tarjan_node *node; + int *stack; + int sp; + int index; + int *order; + int op; +}; + +struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len, + isl_bool (*follows)(int i, int j, void *user), void *user); +struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len, + int node, isl_bool (*follows)(int i, int j, void *user), void *user); +struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g); + +#endif Index: contrib/isl/isl_tarjan.c =================================================================== --- /dev/null +++ contrib/isl/isl_tarjan.c @@ -0,0 +1,159 @@ +/* + * Copyright 2010-2011 INRIA Saclay + * Copyright 2012 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include + +struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g) +{ + if (!g) + return NULL; + free(g->node); + free(g->stack); + free(g->order); + free(g); + return NULL; +} + +static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len) +{ + struct isl_tarjan_graph *g; + int i; + + g = isl_calloc_type(ctx, struct isl_tarjan_graph); + if (!g) + return NULL; + g->len = len; + g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len); + if (len && !g->node) + goto error; + for (i = 0; i < len; ++i) + g->node[i].index = -1; + g->stack = isl_alloc_array(ctx, int, len); + if (len && !g->stack) + goto error; + g->order = isl_alloc_array(ctx, int, 2 * len); + if (len && !g->order) + goto error; + + g->sp = 0; + g->index = 0; + g->op = 0; + + return g; +error: + isl_tarjan_graph_free(g); + return NULL; +} + +/* Perform Tarjan's algorithm for computing the strongly connected components + * in the graph with g->len nodes and with edges defined by "follows". + */ +static isl_stat isl_tarjan_components(struct isl_tarjan_graph *g, int i, + isl_bool (*follows)(int i, int j, void *user), void *user) +{ + 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->len - 1; j >= 0; --j) { + isl_bool 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 = follows(i, j, user); + if (f < 0) + return isl_stat_error; + if (!f) + continue; + + if (g->node[j].index < 0) { + isl_tarjan_components(g, j, follows, user); + 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 isl_stat_ok; + + do { + j = g->stack[--g->sp]; + g->node[j].on_stack = 0; + g->order[g->op++] = j; + } while (j != i); + g->order[g->op++] = -1; + + return isl_stat_ok; +} + +/* Decompose the graph with "len" nodes and edges defined by "follows" + * into strongly connected components (SCCs). + * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise. + * It should return -1 on error. + * + * If SCC a contains a node i that follows a node j in another SCC b + * (i.e., follows(i, j, user) returns 1), then SCC a will appear after SCC b + * in the result. + */ +struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len, + isl_bool (*follows)(int i, int j, void *user), void *user) +{ + int i; + struct isl_tarjan_graph *g = NULL; + + g = isl_tarjan_graph_alloc(ctx, len); + if (!g) + return NULL; + for (i = len - 1; i >= 0; --i) { + if (g->node[i].index >= 0) + continue; + if (isl_tarjan_components(g, i, follows, user) < 0) + return isl_tarjan_graph_free(g); + } + + return g; +} + +/* Decompose the graph with "len" nodes and edges defined by "follows" + * into the strongly connected component (SCC) that contains "node" + * as well as all SCCs that are followed by this SCC. + * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise. + * It should return -1 on error. + * + * The SCC containing "node" will appear as the last component + * in g->order. + */ +struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len, + int node, isl_bool (*follows)(int i, int j, void *user), void *user) +{ + struct isl_tarjan_graph *g; + + g = isl_tarjan_graph_alloc(ctx, len); + if (!g) + return NULL; + if (isl_tarjan_components(g, node, follows, user) < 0) + return isl_tarjan_graph_free(g); + + return g; +} Index: contrib/isl/isl_test.c =================================================================== --- /dev/null +++ contrib/isl/isl_test.c @@ -0,0 +1,7279 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * + * Use of this software is governed by the MIT 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 + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "isl_srcdir.c" + +#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array)) + +static char *get_filename(isl_ctx *ctx, const char *name, const char *suffix) { + char *filename; + int length; + char *pattern = "%s/test_inputs/%s.%s"; + + length = strlen(pattern) - 6 + strlen(srcdir) + strlen(name) + + strlen(suffix) + 1; + filename = isl_alloc_array(ctx, char, length); + + if (!filename) + return NULL; + + sprintf(filename, pattern, srcdir, name, suffix); + + return filename; +} + +void test_parse_map(isl_ctx *ctx, const char *str) +{ + isl_map *map; + + map = isl_map_read_from_str(ctx, str); + assert(map); + isl_map_free(map); +} + +int test_parse_map_equal(isl_ctx *ctx, const char *str, const char *str2) +{ + isl_map *map, *map2; + int equal; + + map = isl_map_read_from_str(ctx, str); + map2 = isl_map_read_from_str(ctx, str2); + equal = isl_map_is_equal(map, map2); + isl_map_free(map); + isl_map_free(map2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "maps not equal", + return -1); + + return 0; +} + +void test_parse_pwqp(isl_ctx *ctx, const char *str) +{ + isl_pw_qpolynomial *pwqp; + + pwqp = isl_pw_qpolynomial_read_from_str(ctx, str); + assert(pwqp); + isl_pw_qpolynomial_free(pwqp); +} + +static void test_parse_pwaff(isl_ctx *ctx, const char *str) +{ + isl_pw_aff *pwaff; + + pwaff = isl_pw_aff_read_from_str(ctx, str); + assert(pwaff); + isl_pw_aff_free(pwaff); +} + +/* Check that we can read an isl_multi_val from "str" without errors. + */ +static int test_parse_multi_val(isl_ctx *ctx, const char *str) +{ + isl_multi_val *mv; + + mv = isl_multi_val_read_from_str(ctx, str); + isl_multi_val_free(mv); + + return mv ? 0 : -1; +} + +/* Pairs of binary relation representations that should represent + * the same binary relations. + */ +struct { + const char *map1; + const char *map2; +} parse_map_equal_tests[] = { + { "{ [x,y] : [([x/2]+y)/3] >= 1 }", + "{ [x, y] : 2y >= 6 - x }" }, + { "{ [x,y] : x <= min(y, 2*y+3) }", + "{ [x,y] : x <= y, 2*y + 3 }" }, + { "{ [x,y] : x >= min(y, 2*y+3) }", + "{ [x, y] : (y <= x and y >= -3) or (2y <= -3 + x and y <= -4) }" }, + { "[n] -> { [c1] : c1>=0 and c1<=floord(n-4,3) }", + "[n] -> { [c1] : c1 >= 0 and 3c1 <= -4 + n }" }, + { "{ [i,j] -> [i] : i < j; [i,j] -> [j] : j <= i }", + "{ [i,j] -> [min(i,j)] }" }, + { "{ [i,j] : i != j }", + "{ [i,j] : i < j or i > j }" }, + { "{ [i,j] : (i+1)*2 >= j }", + "{ [i, j] : j <= 2 + 2i }" }, + { "{ [i] -> [i > 0 ? 4 : 5] }", + "{ [i] -> [5] : i <= 0; [i] -> [4] : i >= 1 }" }, + { "[N=2,M] -> { [i=[(M+N)/4]] }", + "[N, M] -> { [i] : N = 2 and 4i <= 2 + M and 4i >= -1 + M }" }, + { "{ [x] : x >= 0 }", + "{ [x] : x-0 >= 0 }" }, + { "{ [i] : ((i > 10)) }", + "{ [i] : i >= 11 }" }, + { "{ [i] -> [0] }", + "{ [i] -> [0 * i] }" }, + { "{ [a] -> [b] : (not false) }", + "{ [a] -> [b] : true }" }, + { "{ [i] : i/2 <= 5 }", + "{ [i] : i <= 10 }" }, + { "{Sym=[n] [i] : i <= n }", + "[n] -> { [i] : i <= n }" }, + { "{ [*] }", + "{ [a] }" }, + { "{ [i] : 2*floor(i/2) = i }", + "{ [i] : exists a : i = 2 a }" }, + { "{ [a] -> [b] : a = 5 implies b = 5 }", + "{ [a] -> [b] : a != 5 or b = 5 }" }, + { "{ [a] -> [a - 1 : a > 0] }", + "{ [a] -> [a - 1] : a > 0 }" }, + { "{ [a] -> [a - 1 : a > 0; a : a <= 0] }", + "{ [a] -> [a - 1] : a > 0; [a] -> [a] : a <= 0 }" }, + { "{ [a] -> [(a) * 2 : a >= 0; 0 : a < 0] }", + "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }" }, + { "{ [a] -> [(a * 2) : a >= 0; 0 : a < 0] }", + "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }" }, + { "{ [a] -> [(a * 2 : a >= 0); 0 : a < 0] }", + "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }" }, + { "{ [a] -> [(a * 2 : a >= 0; 0 : a < 0)] }", + "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }" }, + { "{ [a,b] -> [i,j] : a,b << i,j }", + "{ [a,b] -> [i,j] : a < i or (a = i and b < j) }" }, + { "{ [a,b] -> [i,j] : a,b <<= i,j }", + "{ [a,b] -> [i,j] : a < i or (a = i and b <= j) }" }, + { "{ [a,b] -> [i,j] : a,b >> i,j }", + "{ [a,b] -> [i,j] : a > i or (a = i and b > j) }" }, + { "{ [a,b] -> [i,j] : a,b >>= i,j }", + "{ [a,b] -> [i,j] : a > i or (a = i and b >= j) }" }, + { "{ [n] -> [i] : exists (a, b, c: 8b <= i - 32a and " + "8b >= -7 + i - 32 a and b >= 0 and b <= 3 and " + "8c < n - 32a and i < n and c >= 0 and " + "c <= 3 and c >= -4a) }", + "{ [n] -> [i] : 0 <= i < n }" }, + { "{ [x] -> [] : exists (a, b: 0 <= a <= 1 and 0 <= b <= 3 and " + "2b <= x - 8a and 2b >= -1 + x - 8a) }", + "{ [x] -> [] : 0 <= x <= 15 }" }, + { "{ [x] -> [x] : }", + "{ [x] -> [x] }" }, +}; + +int test_parse(struct isl_ctx *ctx) +{ + int i; + isl_map *map, *map2; + const char *str, *str2; + + if (test_parse_multi_val(ctx, "{ A[B[2] -> C[5, 7]] }") < 0) + return -1; + if (test_parse_multi_val(ctx, "[n] -> { [2] }") < 0) + return -1; + if (test_parse_multi_val(ctx, "{ A[4, infty, NaN, -1/2, 2/3] }") < 0) + return -1; + + str = "{ [i] -> [-i] }"; + map = isl_map_read_from_str(ctx, str); + assert(map); + isl_map_free(map); + + str = "{ A[i] -> L[([i/3])] }"; + map = isl_map_read_from_str(ctx, str); + assert(map); + isl_map_free(map); + + test_parse_map(ctx, "{[[s] -> A[i]] -> [[s+1] -> A[i]]}"); + test_parse_map(ctx, "{ [p1, y1, y2] -> [2, y1, y2] : " + "p1 = 1 && (y1 <= y2 || y2 = 0) }"); + + for (i = 0; i < ARRAY_SIZE(parse_map_equal_tests); ++i) { + str = parse_map_equal_tests[i].map1; + str2 = parse_map_equal_tests[i].map2; + if (test_parse_map_equal(ctx, str, str2) < 0) + return -1; + } + + str = "{[new,old] -> [new+1-2*[(new+1)/2],old+1-2*[(old+1)/2]]}"; + map = isl_map_read_from_str(ctx, str); + str = "{ [new, old] -> [o0, o1] : " + "exists (e0 = [(-1 - new + o0)/2], e1 = [(-1 - old + o1)/2]: " + "2e0 = -1 - new + o0 and 2e1 = -1 - old + o1 and o0 >= 0 and " + "o0 <= 1 and o1 >= 0 and o1 <= 1) }"; + map2 = isl_map_read_from_str(ctx, str); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map); + isl_map_free(map2); + + str = "{[new,old] -> [new+1-2*[(new+1)/2],old+1-2*[(old+1)/2]]}"; + map = isl_map_read_from_str(ctx, str); + str = "{[new,old] -> [(new+1)%2,(old+1)%2]}"; + map2 = isl_map_read_from_str(ctx, str); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map); + isl_map_free(map2); + + test_parse_pwqp(ctx, "{ [i] -> i + [ (i + [i/3])/2 ] }"); + test_parse_map(ctx, "{ S1[i] -> [([i/10]),i%10] : 0 <= i <= 45 }"); + test_parse_pwaff(ctx, "{ [i] -> [i + 1] : i > 0; [a] -> [a] : a < 0 }"); + test_parse_pwqp(ctx, "{ [x] -> ([(x)/2] * [(x)/3]) }"); + test_parse_pwaff(ctx, "{ [] -> [(100)] }"); + + return 0; +} + +static int test_read(isl_ctx *ctx) +{ + char *filename; + FILE *input; + isl_basic_set *bset1, *bset2; + const char *str = "{[y]: Exists ( alpha : 2alpha = y)}"; + int equal; + + filename = get_filename(ctx, "set", "omega"); + assert(filename); + input = fopen(filename, "r"); + assert(input); + + bset1 = isl_basic_set_read_from_file(ctx, input); + bset2 = isl_basic_set_read_from_str(ctx, str); + + equal = isl_basic_set_is_equal(bset1, bset2); + + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + free(filename); + + fclose(input); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "read sets not equal", return -1); + + return 0; +} + +static int test_bounded(isl_ctx *ctx) +{ + isl_set *set; + isl_bool bounded; + + set = isl_set_read_from_str(ctx, "[n] -> {[i] : 0 <= i <= n }"); + bounded = isl_set_is_bounded(set); + isl_set_free(set); + + if (bounded < 0) + return -1; + if (!bounded) + isl_die(ctx, isl_error_unknown, + "set not considered bounded", return -1); + + set = isl_set_read_from_str(ctx, "{[n, i] : 0 <= i <= n }"); + bounded = isl_set_is_bounded(set); + assert(!bounded); + isl_set_free(set); + + if (bounded < 0) + return -1; + if (bounded) + isl_die(ctx, isl_error_unknown, + "set considered bounded", return -1); + + set = isl_set_read_from_str(ctx, "[n] -> {[i] : i <= n }"); + bounded = isl_set_is_bounded(set); + isl_set_free(set); + + if (bounded < 0) + return -1; + if (bounded) + isl_die(ctx, isl_error_unknown, + "set considered bounded", return -1); + + return 0; +} + +/* Construct the basic set { [i] : 5 <= i <= N } */ +static int test_construction_1(isl_ctx *ctx) +{ + isl_space *dim; + isl_local_space *ls; + isl_basic_set *bset; + isl_constraint *c; + + dim = isl_space_set_alloc(ctx, 1, 1); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_inequality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_param, 0, 1); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_inequality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_constant_si(c, -5); + bset = isl_basic_set_add_constraint(bset, c); + + isl_local_space_free(ls); + isl_basic_set_free(bset); + + return 0; +} + +/* Construct the basic set { [x] : -100 <= x <= 100 } + * using isl_basic_set_{lower,upper}_bound_val and + * check that it is equal the same basic set parsed from a string. + */ +static int test_construction_2(isl_ctx *ctx) +{ + isl_bool equal; + isl_val *v; + isl_space *space; + isl_basic_set *bset1, *bset2; + + v = isl_val_int_from_si(ctx, 100); + space = isl_space_set_alloc(ctx, 0, 1); + bset1 = isl_basic_set_universe(space); + bset1 = isl_basic_set_upper_bound_val(bset1, isl_dim_set, 0, + isl_val_copy(v)); + bset1 = isl_basic_set_lower_bound_val(bset1, isl_dim_set, 0, + isl_val_neg(v)); + bset2 = isl_basic_set_read_from_str(ctx, "{ [x] : -100 <= x <= 100 }"); + equal = isl_basic_set_is_equal(bset1, bset2); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "failed construction", return -1); + + return 0; +} + +/* Basic tests for constructing basic sets. + */ +static int test_construction(isl_ctx *ctx) +{ + if (test_construction_1(ctx) < 0) + return -1; + if (test_construction_2(ctx) < 0) + return -1; + return 0; +} + +static int test_dim(isl_ctx *ctx) +{ + const char *str; + isl_map *map1, *map2; + int equal; + + map1 = isl_map_read_from_str(ctx, + "[n] -> { [i] -> [j] : exists (a = [i/10] : i - 10a <= n ) }"); + map1 = isl_map_add_dims(map1, isl_dim_in, 1); + map2 = isl_map_read_from_str(ctx, + "[n] -> { [i,k] -> [j] : exists (a = [i/10] : i - 10a <= n ) }"); + equal = isl_map_is_equal(map1, map2); + isl_map_free(map2); + + map1 = isl_map_project_out(map1, isl_dim_in, 0, 1); + map2 = isl_map_read_from_str(ctx, "[n] -> { [i] -> [j] : n >= 0 }"); + if (equal >= 0 && equal) + equal = isl_map_is_equal(map1, map2); + + isl_map_free(map1); + isl_map_free(map2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + + str = "[n] -> { [i] -> [] : exists a : 0 <= i <= n and i = 2 a }"; + map1 = isl_map_read_from_str(ctx, str); + str = "{ [i] -> [j] : exists a : 0 <= i <= j and i = 2 a }"; + map2 = isl_map_read_from_str(ctx, str); + map1 = isl_map_move_dims(map1, isl_dim_out, 0, isl_dim_param, 0, 1); + equal = isl_map_is_equal(map1, map2); + isl_map_free(map1); + isl_map_free(map2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + + return 0; +} + +struct { + __isl_give isl_val *(*op)(__isl_take isl_val *v); + const char *arg; + const char *res; +} val_un_tests[] = { + { &isl_val_neg, "0", "0" }, + { &isl_val_abs, "0", "0" }, + { &isl_val_2exp, "0", "1" }, + { &isl_val_floor, "0", "0" }, + { &isl_val_ceil, "0", "0" }, + { &isl_val_neg, "1", "-1" }, + { &isl_val_neg, "-1", "1" }, + { &isl_val_neg, "1/2", "-1/2" }, + { &isl_val_neg, "-1/2", "1/2" }, + { &isl_val_neg, "infty", "-infty" }, + { &isl_val_neg, "-infty", "infty" }, + { &isl_val_neg, "NaN", "NaN" }, + { &isl_val_abs, "1", "1" }, + { &isl_val_abs, "-1", "1" }, + { &isl_val_abs, "1/2", "1/2" }, + { &isl_val_abs, "-1/2", "1/2" }, + { &isl_val_abs, "infty", "infty" }, + { &isl_val_abs, "-infty", "infty" }, + { &isl_val_abs, "NaN", "NaN" }, + { &isl_val_floor, "1", "1" }, + { &isl_val_floor, "-1", "-1" }, + { &isl_val_floor, "1/2", "0" }, + { &isl_val_floor, "-1/2", "-1" }, + { &isl_val_floor, "infty", "infty" }, + { &isl_val_floor, "-infty", "-infty" }, + { &isl_val_floor, "NaN", "NaN" }, + { &isl_val_ceil, "1", "1" }, + { &isl_val_ceil, "-1", "-1" }, + { &isl_val_ceil, "1/2", "1" }, + { &isl_val_ceil, "-1/2", "0" }, + { &isl_val_ceil, "infty", "infty" }, + { &isl_val_ceil, "-infty", "-infty" }, + { &isl_val_ceil, "NaN", "NaN" }, + { &isl_val_2exp, "-3", "1/8" }, + { &isl_val_2exp, "-1", "1/2" }, + { &isl_val_2exp, "1", "2" }, + { &isl_val_2exp, "2", "4" }, + { &isl_val_2exp, "3", "8" }, + { &isl_val_inv, "1", "1" }, + { &isl_val_inv, "2", "1/2" }, + { &isl_val_inv, "1/2", "2" }, + { &isl_val_inv, "-2", "-1/2" }, + { &isl_val_inv, "-1/2", "-2" }, + { &isl_val_inv, "0", "NaN" }, + { &isl_val_inv, "NaN", "NaN" }, + { &isl_val_inv, "infty", "0" }, + { &isl_val_inv, "-infty", "0" }, +}; + +/* Perform some basic tests of unary operations on isl_val objects. + */ +static int test_un_val(isl_ctx *ctx) +{ + int i; + isl_val *v, *res; + __isl_give isl_val *(*fn)(__isl_take isl_val *v); + isl_bool ok, is_nan; + + for (i = 0; i < ARRAY_SIZE(val_un_tests); ++i) { + v = isl_val_read_from_str(ctx, val_un_tests[i].arg); + res = isl_val_read_from_str(ctx, val_un_tests[i].res); + fn = val_un_tests[i].op; + v = fn(v); + is_nan = isl_val_is_nan(res); + if (is_nan < 0) + ok = isl_bool_error; + else if (is_nan) + ok = isl_val_is_nan(v); + else + ok = isl_val_eq(v, res); + isl_val_free(v); + isl_val_free(res); + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + return 0; +} + +struct { + __isl_give isl_val *(*fn)(__isl_take isl_val *v1, + __isl_take isl_val *v2); +} val_bin_op[] = { + ['+'] = { &isl_val_add }, + ['-'] = { &isl_val_sub }, + ['*'] = { &isl_val_mul }, + ['/'] = { &isl_val_div }, + ['g'] = { &isl_val_gcd }, + ['m'] = { &isl_val_min }, + ['M'] = { &isl_val_max }, +}; + +struct { + const char *arg1; + unsigned char op; + const char *arg2; + const char *res; +} val_bin_tests[] = { + { "0", '+', "0", "0" }, + { "1", '+', "0", "1" }, + { "1", '+', "1", "2" }, + { "1", '-', "1", "0" }, + { "1", '*', "1", "1" }, + { "1", '/', "1", "1" }, + { "2", '*', "3", "6" }, + { "2", '*', "1/2", "1" }, + { "2", '*', "1/3", "2/3" }, + { "2/3", '*', "3/5", "2/5" }, + { "2/3", '*', "7/5", "14/15" }, + { "2", '/', "1/2", "4" }, + { "-2", '/', "-1/2", "4" }, + { "-2", '/', "1/2", "-4" }, + { "2", '/', "-1/2", "-4" }, + { "2", '/', "2", "1" }, + { "2", '/', "3", "2/3" }, + { "2/3", '/', "5/3", "2/5" }, + { "2/3", '/', "5/7", "14/15" }, + { "0", '/', "0", "NaN" }, + { "42", '/', "0", "NaN" }, + { "-42", '/', "0", "NaN" }, + { "infty", '/', "0", "NaN" }, + { "-infty", '/', "0", "NaN" }, + { "NaN", '/', "0", "NaN" }, + { "0", '/', "NaN", "NaN" }, + { "42", '/', "NaN", "NaN" }, + { "-42", '/', "NaN", "NaN" }, + { "infty", '/', "NaN", "NaN" }, + { "-infty", '/', "NaN", "NaN" }, + { "NaN", '/', "NaN", "NaN" }, + { "0", '/', "infty", "0" }, + { "42", '/', "infty", "0" }, + { "-42", '/', "infty", "0" }, + { "infty", '/', "infty", "NaN" }, + { "-infty", '/', "infty", "NaN" }, + { "NaN", '/', "infty", "NaN" }, + { "0", '/', "-infty", "0" }, + { "42", '/', "-infty", "0" }, + { "-42", '/', "-infty", "0" }, + { "infty", '/', "-infty", "NaN" }, + { "-infty", '/', "-infty", "NaN" }, + { "NaN", '/', "-infty", "NaN" }, + { "1", '-', "1/3", "2/3" }, + { "1/3", '+', "1/2", "5/6" }, + { "1/2", '+', "1/2", "1" }, + { "3/4", '-', "1/4", "1/2" }, + { "1/2", '-', "1/3", "1/6" }, + { "infty", '+', "42", "infty" }, + { "infty", '+', "infty", "infty" }, + { "42", '+', "infty", "infty" }, + { "infty", '-', "infty", "NaN" }, + { "infty", '*', "infty", "infty" }, + { "infty", '*', "-infty", "-infty" }, + { "-infty", '*', "infty", "-infty" }, + { "-infty", '*', "-infty", "infty" }, + { "0", '*', "infty", "NaN" }, + { "1", '*', "infty", "infty" }, + { "infty", '*', "0", "NaN" }, + { "infty", '*', "42", "infty" }, + { "42", '-', "infty", "-infty" }, + { "infty", '+', "-infty", "NaN" }, + { "4", 'g', "6", "2" }, + { "5", 'g', "6", "1" }, + { "42", 'm', "3", "3" }, + { "42", 'M', "3", "42" }, + { "3", 'm', "42", "3" }, + { "3", 'M', "42", "42" }, + { "42", 'm', "infty", "42" }, + { "42", 'M', "infty", "infty" }, + { "42", 'm', "-infty", "-infty" }, + { "42", 'M', "-infty", "42" }, + { "42", 'm', "NaN", "NaN" }, + { "42", 'M', "NaN", "NaN" }, + { "infty", 'm', "-infty", "-infty" }, + { "infty", 'M', "-infty", "infty" }, +}; + +/* Perform some basic tests of binary operations on isl_val objects. + */ +static int test_bin_val(isl_ctx *ctx) +{ + int i; + isl_val *v1, *v2, *res; + __isl_give isl_val *(*fn)(__isl_take isl_val *v1, + __isl_take isl_val *v2); + int ok; + + for (i = 0; i < ARRAY_SIZE(val_bin_tests); ++i) { + v1 = isl_val_read_from_str(ctx, val_bin_tests[i].arg1); + v2 = isl_val_read_from_str(ctx, val_bin_tests[i].arg2); + res = isl_val_read_from_str(ctx, val_bin_tests[i].res); + fn = val_bin_op[val_bin_tests[i].op].fn; + v1 = fn(v1, v2); + if (isl_val_is_nan(res)) + ok = isl_val_is_nan(v1); + else + ok = isl_val_eq(v1, res); + isl_val_free(v1); + isl_val_free(res); + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + return 0; +} + +/* Perform some basic tests on isl_val objects. + */ +static int test_val(isl_ctx *ctx) +{ + if (test_un_val(ctx) < 0) + return -1; + if (test_bin_val(ctx) < 0) + return -1; + return 0; +} + +/* Sets described using existentially quantified variables that + * can also be described without. + */ +static const char *elimination_tests[] = { + "{ [i,j] : 2 * [i/2] + 3 * [j/4] <= 10 and 2 i = j }", + "{ [m, w] : exists a : w - 2m - 5 <= 3a <= m - 2w }", + "{ [m, w] : exists a : w >= 0 and a < m and -1 + w <= a <= 2m - w }", +}; + +/* Check that redundant existentially quantified variables are + * getting removed. + */ +static int test_elimination(isl_ctx *ctx) +{ + int i; + unsigned n; + isl_basic_set *bset; + + for (i = 0; i < ARRAY_SIZE(elimination_tests); ++i) { + bset = isl_basic_set_read_from_str(ctx, elimination_tests[i]); + n = isl_basic_set_dim(bset, isl_dim_div); + isl_basic_set_free(bset); + if (!bset) + return -1; + if (n != 0) + isl_die(ctx, isl_error_unknown, + "expecting no existentials", return -1); + } + + return 0; +} + +static int test_div(isl_ctx *ctx) +{ + const char *str; + int empty; + isl_space *dim; + isl_set *set; + isl_local_space *ls; + struct isl_basic_set *bset; + struct isl_constraint *c; + + /* test 1 */ + dim = isl_space_set_alloc(ctx, 0, 3); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, 3); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, 3); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 2); + + assert(bset && bset->n_div == 1); + isl_local_space_free(ls); + isl_basic_set_free(bset); + + /* test 2 */ + dim = isl_space_set_alloc(ctx, 0, 3); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, 3); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, 3); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 2); + + assert(bset && bset->n_div == 1); + isl_local_space_free(ls); + isl_basic_set_free(bset); + + /* test 3 */ + dim = isl_space_set_alloc(ctx, 0, 3); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, 3); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, -3); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, 4); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 2); + + assert(bset && bset->n_div == 1); + isl_local_space_free(ls); + isl_basic_set_free(bset); + + /* test 4 */ + dim = isl_space_set_alloc(ctx, 0, 3); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, 2); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, 3); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_constant_si(c, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, 6); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 2); + + assert(isl_basic_set_is_empty(bset)); + isl_local_space_free(ls); + isl_basic_set_free(bset); + + /* test 5 */ + dim = isl_space_set_alloc(ctx, 0, 3); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, 3); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, -3); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 2, 1); + + assert(bset && bset->n_div == 0); + isl_basic_set_free(bset); + isl_local_space_free(ls); + + /* test 6 */ + dim = isl_space_set_alloc(ctx, 0, 3); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, 6); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, -3); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 2, 1); + + assert(bset && bset->n_div == 1); + isl_basic_set_free(bset); + isl_local_space_free(ls); + + /* test 7 */ + /* This test is a bit tricky. We set up an equality + * a + 3b + 3c = 6 e0 + * Normalization of divs creates _two_ divs + * a = 3 e0 + * c - b - e0 = 2 e1 + * Afterwards e0 is removed again because it has coefficient -1 + * and we end up with the original equality and div again. + * Perhaps we can avoid the introduction of this temporary div. + */ + dim = isl_space_set_alloc(ctx, 0, 4); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, -3); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, -3); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 3, 6); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 3, 1); + + /* Test disabled for now */ + /* + assert(bset && bset->n_div == 1); + */ + isl_local_space_free(ls); + isl_basic_set_free(bset); + + /* test 8 */ + dim = isl_space_set_alloc(ctx, 0, 5); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, -3); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 3, -3); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 4, 6); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, 1); + c = isl_constraint_set_constant_si(c, 1); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 4, 1); + + /* Test disabled for now */ + /* + assert(bset && bset->n_div == 1); + */ + isl_local_space_free(ls); + isl_basic_set_free(bset); + + /* test 9 */ + dim = isl_space_set_alloc(ctx, 0, 4); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, -2); + bset = isl_basic_set_add_constraint(bset, c); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 3, 3); + c = isl_constraint_set_constant_si(c, 2); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 2, 2); + + bset = isl_basic_set_fix_si(bset, isl_dim_set, 0, 2); + + assert(!isl_basic_set_is_empty(bset)); + + isl_local_space_free(ls); + isl_basic_set_free(bset); + + /* test 10 */ + dim = isl_space_set_alloc(ctx, 0, 3); + bset = isl_basic_set_universe(isl_space_copy(dim)); + ls = isl_local_space_from_space(dim); + + c = isl_constraint_alloc_equality(isl_local_space_copy(ls)); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1); + c = isl_constraint_set_coefficient_si(c, isl_dim_set, 2, -2); + bset = isl_basic_set_add_constraint(bset, c); + + bset = isl_basic_set_project_out(bset, isl_dim_set, 2, 1); + + bset = isl_basic_set_fix_si(bset, isl_dim_set, 0, 2); + + isl_local_space_free(ls); + isl_basic_set_free(bset); + + str = "{ [i] : exists (e0, e1: 3e1 >= 1 + 2e0 and " + "8e1 <= -1 + 5i - 5e0 and 2e1 >= 1 + 2i - 5e0) }"; + set = isl_set_read_from_str(ctx, str); + set = isl_set_compute_divs(set); + isl_set_free(set); + if (!set) + return -1; + + if (test_elimination(ctx) < 0) + return -1; + + str = "{ [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k }"; + set = isl_set_read_from_str(ctx, str); + set = isl_set_remove_divs_involving_dims(set, isl_dim_set, 0, 2); + set = isl_set_fix_si(set, isl_dim_set, 2, -3); + empty = isl_set_is_empty(set); + isl_set_free(set); + if (empty < 0) + return -1; + if (!empty) + isl_die(ctx, isl_error_unknown, + "result not as accurate as expected", return -1); + + return 0; +} + +void test_application_case(struct isl_ctx *ctx, const char *name) +{ + char *filename; + FILE *input; + struct isl_basic_set *bset1, *bset2; + struct isl_basic_map *bmap; + + filename = get_filename(ctx, name, "omega"); + assert(filename); + input = fopen(filename, "r"); + assert(input); + + bset1 = isl_basic_set_read_from_file(ctx, input); + bmap = isl_basic_map_read_from_file(ctx, input); + + bset1 = isl_basic_set_apply(bset1, bmap); + + bset2 = isl_basic_set_read_from_file(ctx, input); + + assert(isl_basic_set_is_equal(bset1, bset2) == 1); + + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + free(filename); + + fclose(input); +} + +static int test_application(isl_ctx *ctx) +{ + test_application_case(ctx, "application"); + test_application_case(ctx, "application2"); + + return 0; +} + +void test_affine_hull_case(struct isl_ctx *ctx, const char *name) +{ + char *filename; + FILE *input; + struct isl_basic_set *bset1, *bset2; + + filename = get_filename(ctx, name, "polylib"); + assert(filename); + input = fopen(filename, "r"); + assert(input); + + bset1 = isl_basic_set_read_from_file(ctx, input); + bset2 = isl_basic_set_read_from_file(ctx, input); + + bset1 = isl_basic_set_affine_hull(bset1); + + assert(isl_basic_set_is_equal(bset1, bset2) == 1); + + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + free(filename); + + fclose(input); +} + +int test_affine_hull(struct isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_basic_set *bset, *bset2; + int n; + int subset; + + test_affine_hull_case(ctx, "affine2"); + test_affine_hull_case(ctx, "affine"); + test_affine_hull_case(ctx, "affine3"); + + str = "[m] -> { [i0] : exists (e0, e1: e1 <= 1 + i0 and " + "m >= 3 and 4i0 <= 2 + m and e1 >= i0 and " + "e1 >= 0 and e1 <= 2 and e1 >= 1 + 2e0 and " + "2e1 <= 1 + m + 4e0 and 2e1 >= 2 - m + 4i0 - 4e0) }"; + set = isl_set_read_from_str(ctx, str); + bset = isl_set_affine_hull(set); + n = isl_basic_set_dim(bset, isl_dim_div); + isl_basic_set_free(bset); + if (n != 0) + isl_die(ctx, isl_error_unknown, "not expecting any divs", + return -1); + + /* Check that isl_map_affine_hull is not confused by + * the reordering of divs in isl_map_align_divs. + */ + str = "{ [a, b, c, 0] : exists (e0 = [(b)/32], e1 = [(c)/32]: " + "32e0 = b and 32e1 = c); " + "[a, 0, c, 0] : exists (e0 = [(c)/32]: 32e0 = c) }"; + set = isl_set_read_from_str(ctx, str); + bset = isl_set_affine_hull(set); + isl_basic_set_free(bset); + if (!bset) + return -1; + + str = "{ [a] : exists e0, e1, e2: 32e1 = 31 + 31a + 31e0 and " + "32e2 = 31 + 31e0 }"; + set = isl_set_read_from_str(ctx, str); + bset = isl_set_affine_hull(set); + str = "{ [a] : exists e : a = 32 e }"; + bset2 = isl_basic_set_read_from_str(ctx, str); + subset = isl_basic_set_is_subset(bset, bset2); + isl_basic_set_free(bset); + isl_basic_set_free(bset2); + if (subset < 0) + return -1; + if (!subset) + isl_die(ctx, isl_error_unknown, "not as accurate as expected", + return -1); + + return 0; +} + +/* Pairs of maps and the corresponding expected results of + * isl_map_plain_unshifted_simple_hull. + */ +struct { + const char *map; + const char *hull; +} plain_unshifted_simple_hull_tests[] = { + { "{ [i] -> [j] : i >= 1 and j >= 1 or i >= 2 and j <= 10 }", + "{ [i] -> [j] : i >= 1 }" }, + { "{ [n] -> [i,j,k] : (i mod 3 = 2 and j mod 4 = 2) or " + "(j mod 4 = 2 and k mod 6 = n) }", + "{ [n] -> [i,j,k] : j mod 4 = 2 }" }, +}; + +/* Basic tests for isl_map_plain_unshifted_simple_hull. + */ +static int test_plain_unshifted_simple_hull(isl_ctx *ctx) +{ + int i; + isl_map *map; + isl_basic_map *hull, *expected; + isl_bool equal; + + for (i = 0; i < ARRAY_SIZE(plain_unshifted_simple_hull_tests); ++i) { + const char *str; + str = plain_unshifted_simple_hull_tests[i].map; + map = isl_map_read_from_str(ctx, str); + str = plain_unshifted_simple_hull_tests[i].hull; + expected = isl_basic_map_read_from_str(ctx, str); + hull = isl_map_plain_unshifted_simple_hull(map); + equal = isl_basic_map_is_equal(hull, expected); + isl_basic_map_free(hull); + isl_basic_map_free(expected); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected hull", + return -1); + } + + return 0; +} + +/* Pairs of sets and the corresponding expected results of + * isl_set_unshifted_simple_hull. + */ +struct { + const char *set; + const char *hull; +} unshifted_simple_hull_tests[] = { + { "{ [0,x,y] : x <= -1; [1,x,y] : x <= y <= -x; [2,x,y] : x <= 1 }", + "{ [t,x,y] : 0 <= t <= 2 and x <= 1 }" }, +}; + +/* Basic tests for isl_set_unshifted_simple_hull. + */ +static int test_unshifted_simple_hull(isl_ctx *ctx) +{ + int i; + isl_set *set; + isl_basic_set *hull, *expected; + isl_bool equal; + + for (i = 0; i < ARRAY_SIZE(unshifted_simple_hull_tests); ++i) { + const char *str; + str = unshifted_simple_hull_tests[i].set; + set = isl_set_read_from_str(ctx, str); + str = unshifted_simple_hull_tests[i].hull; + expected = isl_basic_set_read_from_str(ctx, str); + hull = isl_set_unshifted_simple_hull(set); + equal = isl_basic_set_is_equal(hull, expected); + isl_basic_set_free(hull); + isl_basic_set_free(expected); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected hull", + return -1); + } + + return 0; +} + +static int test_simple_hull(struct isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_basic_set *bset; + isl_bool is_empty; + + str = "{ [x, y] : 3y <= 2x and y >= -2 + 2x and 2y >= 2 - x;" + "[y, x] : 3y <= 2x and y >= -2 + 2x and 2y >= 2 - x }"; + set = isl_set_read_from_str(ctx, str); + bset = isl_set_simple_hull(set); + is_empty = isl_basic_set_is_empty(bset); + isl_basic_set_free(bset); + + if (is_empty == isl_bool_error) + return -1; + + if (is_empty == isl_bool_false) + isl_die(ctx, isl_error_unknown, "Empty set should be detected", + return -1); + + if (test_plain_unshifted_simple_hull(ctx) < 0) + return -1; + if (test_unshifted_simple_hull(ctx) < 0) + return -1; + + return 0; +} + +void test_convex_hull_case(struct isl_ctx *ctx, const char *name) +{ + char *filename; + FILE *input; + struct isl_basic_set *bset1, *bset2; + struct isl_set *set; + + filename = get_filename(ctx, name, "polylib"); + assert(filename); + input = fopen(filename, "r"); + assert(input); + + bset1 = isl_basic_set_read_from_file(ctx, input); + bset2 = isl_basic_set_read_from_file(ctx, input); + + set = isl_basic_set_union(bset1, bset2); + bset1 = isl_set_convex_hull(set); + + bset2 = isl_basic_set_read_from_file(ctx, input); + + assert(isl_basic_set_is_equal(bset1, bset2) == 1); + + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + free(filename); + + fclose(input); +} + +struct { + const char *set; + const char *hull; +} convex_hull_tests[] = { + { "{ [i0, i1, i2] : (i2 = 1 and i0 = 0 and i1 >= 0) or " + "(i0 = 1 and i1 = 0 and i2 = 1) or " + "(i0 = 0 and i1 = 0 and i2 = 0) }", + "{ [i0, i1, i2] : i0 >= 0 and i2 >= i0 and i2 <= 1 and i1 >= 0 }" }, + { "[n] -> { [i0, i1, i0] : i0 <= -4 + n; " + "[i0, i0, i2] : n = 6 and i0 >= 0 and i2 <= 7 - i0 and " + "i2 <= 5 and i2 >= 4; " + "[3, i1, 3] : n = 5 and i1 <= 2 and i1 >= 0 }", + "[n] -> { [i0, i1, i2] : i2 <= -1 + n and 2i2 <= -6 + 3n - i0 and " + "i2 <= 5 + i0 and i2 >= i0 }" }, + { "{ [x, y] : 3y <= 2x and y >= -2 + 2x and 2y >= 2 - x }", + "{ [x, y] : 1 = 0 }" }, + { "{ [x, y, z] : 0 <= x, y, z <= 10; [x, y, 0] : x >= 0 and y > 0; " + "[x, y, 0] : x >= 0 and y < 0 }", + "{ [x, y, z] : x >= 0 and 0 <= z <= 10 }" }, +}; + +static int test_convex_hull_algo(isl_ctx *ctx, int convex) +{ + int i; + int orig_convex = ctx->opt->convex; + ctx->opt->convex = convex; + + test_convex_hull_case(ctx, "convex0"); + test_convex_hull_case(ctx, "convex1"); + test_convex_hull_case(ctx, "convex2"); + test_convex_hull_case(ctx, "convex3"); + test_convex_hull_case(ctx, "convex4"); + test_convex_hull_case(ctx, "convex5"); + test_convex_hull_case(ctx, "convex6"); + test_convex_hull_case(ctx, "convex7"); + test_convex_hull_case(ctx, "convex8"); + test_convex_hull_case(ctx, "convex9"); + test_convex_hull_case(ctx, "convex10"); + test_convex_hull_case(ctx, "convex11"); + test_convex_hull_case(ctx, "convex12"); + test_convex_hull_case(ctx, "convex13"); + test_convex_hull_case(ctx, "convex14"); + test_convex_hull_case(ctx, "convex15"); + + for (i = 0; i < ARRAY_SIZE(convex_hull_tests); ++i) { + isl_set *set1, *set2; + int equal; + + set1 = isl_set_read_from_str(ctx, convex_hull_tests[i].set); + set2 = isl_set_read_from_str(ctx, convex_hull_tests[i].hull); + set1 = isl_set_from_basic_set(isl_set_convex_hull(set1)); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "unexpected convex hull", return -1); + } + + ctx->opt->convex = orig_convex; + + return 0; +} + +static int test_convex_hull(isl_ctx *ctx) +{ + if (test_convex_hull_algo(ctx, ISL_CONVEX_HULL_FM) < 0) + return -1; + if (test_convex_hull_algo(ctx, ISL_CONVEX_HULL_WRAP) < 0) + return -1; + return 0; +} + +void test_gist_case(struct isl_ctx *ctx, const char *name) +{ + char *filename; + FILE *input; + struct isl_basic_set *bset1, *bset2; + + filename = get_filename(ctx, name, "polylib"); + assert(filename); + input = fopen(filename, "r"); + assert(input); + + bset1 = isl_basic_set_read_from_file(ctx, input); + bset2 = isl_basic_set_read_from_file(ctx, input); + + bset1 = isl_basic_set_gist(bset1, bset2); + + bset2 = isl_basic_set_read_from_file(ctx, input); + + assert(isl_basic_set_is_equal(bset1, bset2) == 1); + + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + free(filename); + + fclose(input); +} + +/* Inputs to isl_map_plain_gist_basic_map, along with the expected output. + */ +struct { + const char *map; + const char *context; + const char *gist; +} plain_gist_tests[] = { + { "{ [i] -> [j] : i >= 1 and j >= 1 or i >= 2 and j <= 10 }", + "{ [i] -> [j] : i >= 1 }", + "{ [i] -> [j] : j >= 1 or i >= 2 and j <= 10 }" }, + { "{ [n] -> [i,j,k] : (i mod 3 = 2 and j mod 4 = 2) or " + "(j mod 4 = 2 and k mod 6 = n) }", + "{ [n] -> [i,j,k] : j mod 4 = 2 }", + "{ [n] -> [i,j,k] : (i mod 3 = 2) or (k mod 6 = n) }" }, + { "{ [i] -> [j] : i > j and (exists a,b : i <= 2a + 5b <= 2) }", + "{ [i] -> [j] : i > j }", + "{ [i] -> [j] : exists a,b : i <= 2a + 5b <= 2 }" }, +}; + +/* Basic tests for isl_map_plain_gist_basic_map. + */ +static int test_plain_gist(isl_ctx *ctx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(plain_gist_tests); ++i) { + const char *str; + int equal; + isl_map *map, *gist; + isl_basic_map *context; + + map = isl_map_read_from_str(ctx, plain_gist_tests[i].map); + str = plain_gist_tests[i].context; + context = isl_basic_map_read_from_str(ctx, str); + map = isl_map_plain_gist_basic_map(map, context); + gist = isl_map_read_from_str(ctx, plain_gist_tests[i].gist); + equal = isl_map_is_equal(map, gist); + isl_map_free(map); + isl_map_free(gist); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "incorrect gist result", return -1); + } + + return 0; +} + +struct { + const char *set; + const char *context; + const char *gist; +} gist_tests[] = { + { "{ [a, b, c] : a <= 15 and a >= 1 }", + "{ [a, b, c] : exists (e0 = floor((-1 + a)/16): a >= 1 and " + "c <= 30 and 32e0 >= -62 + 2a + 2b - c and b >= 0) }", + "{ [a, b, c] : a <= 15 }" }, + { "{ : }", "{ : 1 = 0 }", "{ : }" }, + { "{ : 1 = 0 }", "{ : 1 = 0 }", "{ : }" }, + { "[M] -> { [x] : exists (e0 = floor((-2 + x)/3): 3e0 = -2 + x) }", + "[M] -> { [3M] }" , "[M] -> { [x] : 1 = 0 }" }, + { "{ [m, n, a, b] : a <= 2147 + n }", + "{ [m, n, a, b] : (m >= 1 and n >= 1 and a <= 2148 - m and " + "b <= 2148 - n and b >= 0 and b >= 2149 - n - a) or " + "(n >= 1 and a >= 0 and b <= 2148 - n - a and " + "b >= 0) }", + "{ [m, n, ku, kl] }" }, + { "{ [a, a, b] : a >= 10 }", + "{ [a, b, c] : c >= a and c <= b and c >= 2 }", + "{ [a, a, b] : a >= 10 }" }, + { "{ [i, j] : i >= 0 and i + j >= 0 }", "{ [i, j] : i <= 0 }", + "{ [0, j] : j >= 0 }" }, + /* Check that no constraints on i6 are introduced in the gist */ + { "[t1] -> { [i4, i6] : exists (e0 = floor((1530 - 4t1 - 5i4)/20): " + "20e0 <= 1530 - 4t1 - 5i4 and 20e0 >= 1511 - 4t1 - 5i4 and " + "5e0 <= 381 - t1 and i4 <= 1) }", + "[t1] -> { [i4, i6] : exists (e0 = floor((-t1 + i6)/5): " + "5e0 = -t1 + i6 and i6 <= 6 and i6 >= 3) }", + "[t1] -> { [i4, i6] : exists (e0 = floor((1530 - 4t1 - 5i4)/20): " + "i4 <= 1 and 5e0 <= 381 - t1 and 20e0 <= 1530 - 4t1 - 5i4 and " + "20e0 >= 1511 - 4t1 - 5i4) }" }, + /* Check that no constraints on i6 are introduced in the gist */ + { "[t1, t2] -> { [i4, i5, i6] : exists (e0 = floor((1 + i4)/2), " + "e1 = floor((1530 - 4t1 - 5i4)/20), " + "e2 = floor((-4t1 - 5i4 + 10*floor((1 + i4)/2))/20), " + "e3 = floor((-1 + i4)/2): t2 = 0 and 2e3 = -1 + i4 and " + "20e2 >= -19 - 4t1 - 5i4 + 10e0 and 5e2 <= 1 - t1 and " + "2e0 <= 1 + i4 and 2e0 >= i4 and " + "20e1 <= 1530 - 4t1 - 5i4 and " + "20e1 >= 1511 - 4t1 - 5i4 and i4 <= 1 and " + "5e1 <= 381 - t1 and 20e2 <= -4t1 - 5i4 + 10e0) }", + "[t1, t2] -> { [i4, i5, i6] : exists (e0 = floor((-17 + i4)/2), " + "e1 = floor((-t1 + i6)/5): 5e1 = -t1 + i6 and " + "2e0 <= -17 + i4 and 2e0 >= -18 + i4 and " + "10e0 <= -91 + 5i4 + 4i6 and " + "10e0 >= -105 + 5i4 + 4i6) }", + "[t1, t2] -> { [i4, i5, i6] : exists (e0 = floor((381 - t1)/5), " + "e1 = floor((-1 + i4)/2): t2 = 0 and 2e1 = -1 + i4 and " + "i4 <= 1 and 5e0 <= 381 - t1 and 20e0 >= 1511 - 4t1 - 5i4) }" }, + { "{ [0, 0, q, p] : -5 <= q <= 5 and p >= 0 }", + "{ [a, b, q, p] : b >= 1 + a }", + "{ [a, b, q, p] : false }" }, + { "[n] -> { [x] : x = n && x mod 32 = 0 }", + "[n] -> { [x] : x mod 32 = 0 }", + "[n] -> { [x = n] }" }, + { "{ [x] : x mod 6 = 0 }", "{ [x] : x mod 3 = 0 }", + "{ [x] : x mod 2 = 0 }" }, + { "{ [x] : x mod 3200 = 0 }", "{ [x] : x mod 10000 = 0 }", + "{ [x] : x mod 128 = 0 }" }, + { "{ [x] : x mod 3200 = 0 }", "{ [x] : x mod 10 = 0 }", + "{ [x] : x mod 3200 = 0 }" }, + { "{ [a, b, c] : a mod 2 = 0 and a = c }", + "{ [a, b, c] : b mod 2 = 0 and b = c }", + "{ [a, b, c = a] }" }, + { "{ [a, b, c] : a mod 6 = 0 and a = c }", + "{ [a, b, c] : b mod 2 = 0 and b = c }", + "{ [a, b, c = a] : a mod 3 = 0 }" }, + { "{ [x] : 0 <= x <= 4 or 6 <= x <= 9 }", + "{ [x] : 1 <= x <= 3 or 7 <= x <= 8 }", + "{ [x] }" }, + { "{ [x,y] : x < 0 and 0 <= y <= 4 or x >= -2 and -x <= y <= 10 + x }", + "{ [x,y] : 1 <= y <= 3 }", + "{ [x,y] }" }, +}; + +/* Check that isl_set_gist behaves as expected. + * + * For the test cases in gist_tests, besides checking that the result + * is as expected, also check that applying the gist operation does + * not modify the input set (an earlier version of isl would do that) and + * that the test case is consistent, i.e., that the gist has the same + * intersection with the context as the input set. + */ +static int test_gist(struct isl_ctx *ctx) +{ + int i; + const char *str; + isl_basic_set *bset1, *bset2; + isl_map *map1, *map2; + int equal; + + for (i = 0; i < ARRAY_SIZE(gist_tests); ++i) { + int equal_input, equal_intersection; + isl_set *set1, *set2, *copy, *context; + + set1 = isl_set_read_from_str(ctx, gist_tests[i].set); + context = isl_set_read_from_str(ctx, gist_tests[i].context); + copy = isl_set_copy(set1); + set1 = isl_set_gist(set1, isl_set_copy(context)); + set2 = isl_set_read_from_str(ctx, gist_tests[i].gist); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + set1 = isl_set_read_from_str(ctx, gist_tests[i].set); + equal_input = isl_set_is_equal(set1, copy); + isl_set_free(copy); + set1 = isl_set_intersect(set1, isl_set_copy(context)); + set2 = isl_set_intersect(set2, context); + equal_intersection = isl_set_is_equal(set1, set2); + isl_set_free(set2); + isl_set_free(set1); + if (equal < 0 || equal_input < 0 || equal_intersection < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "incorrect gist result", return -1); + if (!equal_input) + isl_die(ctx, isl_error_unknown, + "gist modified input", return -1); + if (!equal_input) + isl_die(ctx, isl_error_unknown, + "inconsistent gist test case", return -1); + } + + test_gist_case(ctx, "gist1"); + + str = "[p0, p2, p3, p5, p6, p10] -> { [] : " + "exists (e0 = [(15 + p0 + 15p6 + 15p10)/16], e1 = [(p5)/8], " + "e2 = [(p6)/128], e3 = [(8p2 - p5)/128], " + "e4 = [(128p3 - p6)/4096]: 8e1 = p5 and 128e2 = p6 and " + "128e3 = 8p2 - p5 and 4096e4 = 128p3 - p6 and p2 >= 0 and " + "16e0 >= 16 + 16p6 + 15p10 and p2 <= 15 and p3 >= 0 and " + "p3 <= 31 and p6 >= 128p3 and p5 >= 8p2 and p10 >= 0 and " + "16e0 <= 15 + p0 + 15p6 + 15p10 and 16e0 >= p0 + 15p6 + 15p10 and " + "p10 <= 15 and p10 <= -1 + p0 - p6) }"; + bset1 = isl_basic_set_read_from_str(ctx, str); + str = "[p0, p2, p3, p5, p6, p10] -> { [] : exists (e0 = [(p5)/8], " + "e1 = [(p6)/128], e2 = [(8p2 - p5)/128], " + "e3 = [(128p3 - p6)/4096]: 8e0 = p5 and 128e1 = p6 and " + "128e2 = 8p2 - p5 and 4096e3 = 128p3 - p6 and p5 >= -7 and " + "p2 >= 0 and 8p2 <= -1 + p0 and p2 <= 15 and p3 >= 0 and " + "p3 <= 31 and 128p3 <= -1 + p0 and p6 >= -127 and " + "p5 <= -1 + p0 and p6 <= -1 + p0 and p6 >= 128p3 and " + "p0 >= 1 and p5 >= 8p2 and p10 >= 0 and p10 <= 15 ) }"; + bset2 = isl_basic_set_read_from_str(ctx, str); + bset1 = isl_basic_set_gist(bset1, bset2); + assert(bset1 && bset1->n_div == 0); + isl_basic_set_free(bset1); + + /* Check that the integer divisions of the second disjunct + * do not spread to the first disjunct. + */ + str = "[t1] -> { S_0[] -> A[o0] : (exists (e0 = [(-t1 + o0)/16]: " + "16e0 = -t1 + o0 and o0 >= 0 and o0 <= 15 and t1 >= 0)) or " + "(exists (e0 = [(-1 + t1)/16], " + "e1 = [(-16 + t1 - 16e0)/4294967296]: " + "4294967296e1 = -16 + t1 - o0 - 16e0 and " + "16e0 <= -1 + t1 and 16e0 >= -16 + t1 and o0 >= 0 and " + "o0 <= 4294967295 and t1 <= -1)) }"; + map1 = isl_map_read_from_str(ctx, str); + str = "[t1] -> { S_0[] -> A[o0] : t1 >= 0 and t1 <= 4294967295 }"; + map2 = isl_map_read_from_str(ctx, str); + map1 = isl_map_gist(map1, map2); + if (!map1) + return -1; + if (map1->n != 1) + isl_die(ctx, isl_error_unknown, "expecting single disjunct", + isl_map_free(map1); return -1); + if (isl_basic_map_dim(map1->p[0], isl_dim_div) != 1) + isl_die(ctx, isl_error_unknown, "expecting single div", + isl_map_free(map1); return -1); + isl_map_free(map1); + + if (test_plain_gist(ctx) < 0) + return -1; + + return 0; +} + +int test_coalesce_set(isl_ctx *ctx, const char *str, int check_one) +{ + isl_set *set, *set2; + int equal; + int one; + + set = isl_set_read_from_str(ctx, str); + set = isl_set_coalesce(set); + set2 = isl_set_read_from_str(ctx, str); + equal = isl_set_is_equal(set, set2); + one = set && set->n == 1; + isl_set_free(set); + isl_set_free(set2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "coalesced set not equal to input", return -1); + if (check_one && !one) + isl_die(ctx, isl_error_unknown, + "coalesced set should not be a union", return -1); + + return 0; +} + +/* Inputs for coalescing tests with unbounded wrapping. + * "str" is a string representation of the input set. + * "single_disjunct" is set if we expect the result to consist of + * a single disjunct. + */ +struct { + int single_disjunct; + const char *str; +} coalesce_unbounded_tests[] = { + { 1, "{ [x,y,z] : y + 2 >= 0 and x - y + 1 >= 0 and " + "-x - y + 1 >= 0 and -3 <= z <= 3;" + "[x,y,z] : -x+z + 20 >= 0 and -x-z + 20 >= 0 and " + "x-z + 20 >= 0 and x+z + 20 >= 0 and " + "-10 <= y <= 0}" }, + { 1, "{ [x,y] : 0 <= x,y <= 10; [5,y]: 4 <= y <= 11 }" }, + { 1, "{ [x,0,0] : -5 <= x <= 5; [0,y,1] : -5 <= y <= 5 }" }, + { 1, "{ [x,y] : 0 <= x <= 10 and 0 >= y >= -1 and x+y >= 0; [0,1] }" }, + { 1, "{ [x,y] : (0 <= x,y <= 4) or (2 <= x,y <= 5 and x + y <= 9) }" }, +}; + +/* Test the functionality of isl_set_coalesce with the bounded wrapping + * option turned off. + */ +int test_coalesce_unbounded_wrapping(isl_ctx *ctx) +{ + int i; + int r = 0; + int bounded; + + bounded = isl_options_get_coalesce_bounded_wrapping(ctx); + isl_options_set_coalesce_bounded_wrapping(ctx, 0); + + for (i = 0; i < ARRAY_SIZE(coalesce_unbounded_tests); ++i) { + const char *str = coalesce_unbounded_tests[i].str; + int check_one = coalesce_unbounded_tests[i].single_disjunct; + if (test_coalesce_set(ctx, str, check_one) >= 0) + continue; + r = -1; + break; + } + + isl_options_set_coalesce_bounded_wrapping(ctx, bounded); + + return r; +} + +/* Inputs for coalescing tests. + * "str" is a string representation of the input set. + * "single_disjunct" is set if we expect the result to consist of + * a single disjunct. + */ +struct { + int single_disjunct; + const char *str; +} coalesce_tests[] = { + { 1, "{[x,y]: x >= 0 & x <= 10 & y >= 0 & y <= 10 or " + "y >= x & x >= 2 & 5 >= y }" }, + { 1, "{[x,y]: y >= 0 & 2x + y <= 30 & y <= 10 & x >= 0 or " + "x + y >= 10 & y <= x & x + y <= 20 & y >= 0}" }, + { 0, "{[x,y]: y >= 0 & 2x + y <= 30 & y <= 10 & x >= 0 or " + "x + y >= 10 & y <= x & x + y <= 19 & y >= 0}" }, + { 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or " + "y >= 0 & x >= 6 & x <= 10 & y <= x}" }, + { 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or " + "y >= 0 & x >= 7 & x <= 10 & y <= x}" }, + { 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or " + "y >= 0 & x >= 6 & x <= 10 & y + 1 <= x}" }, + { 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 6}" }, + { 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 7 & y <= 6}" }, + { 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 5}" }, + { 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 7}" }, + { 1, "[n] -> { [i] : i = 1 and n >= 2 or 2 <= i and i <= n }" }, + { 0, "{[x,y] : x >= 0 and y >= 0 or 0 <= y and y <= 5 and x = -1}" }, + { 1, "[n] -> { [i] : 1 <= i and i <= n - 1 or 2 <= i and i <= n }" }, + { 0, "[n] -> { [[i0] -> [o0]] : exists (e0 = [(i0)/4], e1 = [(o0)/4], " + "e2 = [(n)/2], e3 = [(-2 + i0)/4], e4 = [(-2 + o0)/4], " + "e5 = [(-2n + i0)/4]: 2e2 = n and 4e3 = -2 + i0 and " + "4e4 = -2 + o0 and i0 >= 8 + 2n and o0 >= 2 + i0 and " + "o0 <= 56 + 2n and o0 <= -12 + 4n and i0 <= 57 + 2n and " + "i0 <= -11 + 4n and o0 >= 6 + 2n and 4e0 <= i0 and " + "4e0 >= -3 + i0 and 4e1 <= o0 and 4e1 >= -3 + o0 and " + "4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0);" + "[[i0] -> [o0]] : exists (e0 = [(i0)/4], e1 = [(o0)/4], " + "e2 = [(n)/2], e3 = [(-2 + i0)/4], e4 = [(-2 + o0)/4], " + "e5 = [(-2n + i0)/4]: 2e2 = n and 4e3 = -2 + i0 and " + "4e4 = -2 + o0 and 2e0 >= 3 + n and e0 <= -4 + n and " + "2e0 <= 27 + n and e1 <= -4 + n and 2e1 <= 27 + n and " + "2e1 >= 2 + n and e1 >= 1 + e0 and i0 >= 7 + 2n and " + "i0 <= -11 + 4n and i0 <= 57 + 2n and 4e0 <= -2 + i0 and " + "4e0 >= -3 + i0 and o0 >= 6 + 2n and o0 <= -11 + 4n and " + "o0 <= 57 + 2n and 4e1 <= -2 + o0 and 4e1 >= -3 + o0 and " + "4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0 ) }" }, + { 0, "[n, m] -> { [o0, o2, o3] : (o3 = 1 and o0 >= 1 + m and " + "o0 <= n + m and o2 <= m and o0 >= 2 + n and o2 >= 3) or " + "(o0 >= 2 + n and o0 >= 1 + m and o0 <= n + m and n >= 1 and " + "o3 <= -1 + o2 and o3 >= 1 - m + o2 and o3 >= 2 and o3 <= n) }" }, + { 0, "[M, N] -> { [[i0, i1, i2, i3, i4, i5, i6] -> " + "[o0, o1, o2, o3, o4, o5, o6]] : " + "(o6 <= -4 + 2M - 2N + i0 + i1 - i2 + i6 - o0 - o1 + o2 and " + "o3 <= -2 + i3 and o6 >= 2 + i0 + i3 + i6 - o0 - o3 and " + "o6 >= 2 - M + N + i3 + i4 + i6 - o3 - o4 and o0 <= -1 + i0 and " + "o4 >= 4 - 3M + 3N - i0 - i1 + i2 + 2i3 + i4 + o0 + o1 - o2 - 2o3 " + "and o6 <= -3 + 2M - 2N + i3 + i4 - i5 + i6 - o3 - o4 + o5 and " + "2o6 <= -5 + 5M - 5N + 2i0 + i1 - i2 - i5 + 2i6 - 2o0 - o1 + o2 + o5 " + "and o6 >= 2i0 + i1 + i6 - 2o0 - o1 and " + "3o6 <= -5 + 4M - 4N + 2i0 + i1 - i2 + 2i3 + i4 - i5 + 3i6 " + "- 2o0 - o1 + o2 - 2o3 - o4 + o5) or " + "(N >= 2 and o3 <= -1 + i3 and o0 <= -1 + i0 and " + "o6 >= i3 + i6 - o3 and M >= 0 and " + "2o6 >= 1 + i0 + i3 + 2i6 - o0 - o3 and " + "o6 >= 1 - M + i0 + i6 - o0 and N >= 2M and o6 >= i0 + i6 - o0) }" }, + { 0, "[M, N] -> { [o0] : (o0 = 0 and M >= 1 and N >= 2) or " + "(o0 = 0 and M >= 1 and N >= 2M and N >= 2 + M) or " + "(o0 = 0 and M >= 2 and N >= 3) or " + "(M = 0 and o0 = 0 and N >= 3) }" }, + { 0, "{ [i0, i1, i2, i3] : (i1 = 10i0 and i0 >= 1 and 10i0 <= 100 and " + "i3 <= 9 + 10 i2 and i3 >= 1 + 10i2 and i3 >= 0) or " + "(i1 <= 9 + 10i0 and i1 >= 1 + 10i0 and i2 >= 0 and " + "i0 >= 0 and i1 <= 100 and i3 <= 9 + 10i2 and i3 >= 1 + 10i2) }" }, + { 0, "[M] -> { [i1] : (i1 >= 2 and i1 <= M) or (i1 = M and M >= 1) }" }, + { 0, "{[x,y] : x,y >= 0; [x,y] : 10 <= x <= 20 and y >= -1 }" }, + { 1, "{ [x, y] : (x >= 1 and y >= 1 and x <= 2 and y <= 2) or " + "(y = 3 and x = 1) }" }, + { 1, "[M] -> { [i0, i1, i2, i3, i4] : (i1 >= 3 and i4 >= 2 + i2 and " + "i2 >= 2 and i0 >= 2 and i3 >= 1 + i2 and i0 <= M and " + "i1 <= M and i3 <= M and i4 <= M) or " + "(i1 >= 2 and i4 >= 1 + i2 and i2 >= 2 and i0 >= 2 and " + "i3 >= 1 + i2 and i0 <= M and i1 <= -1 + M and i3 <= M and " + "i4 <= -1 + M) }" }, + { 1, "{ [x, y] : (x >= 0 and y >= 0 and x <= 10 and y <= 10) or " + "(x >= 1 and y >= 1 and x <= 11 and y <= 11) }" }, + { 0, "{[x,0] : x >= 0; [x,1] : x <= 20}" }, + { 1, "{ [x, 1 - x] : 0 <= x <= 1; [0,0] }" }, + { 1, "{ [0,0]; [i,i] : 1 <= i <= 10 }" }, + { 0, "{ [0,0]; [i,j] : 1 <= i,j <= 10 }" }, + { 1, "{ [0,0]; [i,2i] : 1 <= i <= 10 }" }, + { 0, "{ [0,0]; [i,2i] : 2 <= i <= 10 }" }, + { 0, "{ [1,0]; [i,2i] : 1 <= i <= 10 }" }, + { 0, "{ [0,1]; [i,2i] : 1 <= i <= 10 }" }, + { 0, "{ [a, b] : exists e : 2e = a and " + "a >= 0 and (a <= 3 or (b <= 0 and b >= -4 + a)) }" }, + { 0, "{ [i, j, i', j'] : i <= 2 and j <= 2 and " + "j' >= -1 + 2i + j - 2i' and i' <= -1 + i and " + "j >= 1 and j' <= i + j - i' and i >= 1; " + "[1, 1, 1, 1] }" }, + { 1, "{ [i,j] : exists a,b : i = 2a and j = 3b; " + "[i,j] : exists a : j = 3a }" }, + { 1, "{ [a, b, c] : (c <= 7 - b and b <= 1 and b >= 0 and " + "c >= 3 + b and b <= 3 + 8a and b >= -26 + 8a and " + "a >= 3) or " + "(b <= 1 and c <= 7 and b >= 0 and c >= 4 + b and " + "b <= 3 + 8a and b >= -26 + 8a and a >= 3) }" }, + { 1, "{ [a, 0, c] : c >= 1 and c <= 29 and c >= -1 + 8a and " + "c <= 6 + 8a and a >= 3; " + "[a, -1, c] : c >= 1 and c <= 30 and c >= 8a and " + "c <= 7 + 8a and a >= 3 and a <= 4 }" }, + { 1, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + 2y <= 4; " + "[x,0] : 3 <= x <= 4 }" }, + { 1, "{ [x,y] : 0 <= x <= 3 and y >= 0 and x + 3y <= 6; " + "[x,0] : 4 <= x <= 5 }" }, + { 0, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + 2y <= 4; " + "[x,0] : 3 <= x <= 5 }" }, + { 0, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + y <= 4; " + "[x,0] : 3 <= x <= 4 }" }, + { 1, "{ [i0, i1] : i0 <= 122 and i0 >= 1 and 128i1 >= -249 + i0 and " + "i1 <= 0; " + "[i0, 0] : i0 >= 123 and i0 <= 124 }" }, + { 1, "{ [0,0]; [1,1] }" }, + { 1, "[n] -> { [k] : 16k <= -1 + n and k >= 1; [0] : n >= 2 }" }, + { 1, "{ [k, ii, k - ii] : ii >= -6 + k and ii <= 6 and ii >= 1 and " + "ii <= k;" + "[k, 0, k] : k <= 6 and k >= 1 }" }, + { 1, "{ [i,j] : i = 4 j and 0 <= i <= 100;" + "[i,j] : 1 <= i <= 100 and i >= 4j + 1 and i <= 4j + 2 }" }, + { 1, "{ [x,y] : x % 2 = 0 and y % 2 = 0; [x,x] : x % 2 = 0 }" }, + { 1, "[n] -> { [1] : n >= 0;" + "[x] : exists (e0 = floor((x)/2): x >= 2 and " + "2e0 >= -1 + x and 2e0 <= x and 2e0 <= n) }" }, + { 1, "[n] -> { [x, y] : exists (e0 = floor((x)/2), e1 = floor((y)/3): " + "3e1 = y and x >= 2 and 2e0 >= -1 + x and " + "2e0 <= x and 2e0 <= n);" + "[1, y] : exists (e0 = floor((y)/3): 3e0 = y and " + "n >= 0) }" }, + { 1, "[t1] -> { [i0] : (exists (e0 = floor((63t1)/64): " + "128e0 >= -134 + 127t1 and t1 >= 2 and " + "64e0 <= 63t1 and 64e0 >= -63 + 63t1)) or " + "t1 = 1 }" }, + { 1, "{ [i, i] : exists (e0 = floor((1 + 2i)/3): 3e0 <= 2i and " + "3e0 >= -1 + 2i and i <= 9 and i >= 1);" + "[0, 0] }" }, + { 1, "{ [t1] : exists (e0 = floor((-11 + t1)/2): 2e0 = -11 + t1 and " + "t1 >= 13 and t1 <= 16);" + "[t1] : t1 <= 15 and t1 >= 12 }" }, + { 1, "{ [x,y] : x = 3y and 0 <= y <= 2; [-3,-1] }" }, + { 1, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-3,-2] }" }, + { 0, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-2,-2] }" }, + { 0, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-3,-1] }" }, + { 1, "{ [i] : exists j : i = 4 j and 0 <= i <= 100;" + "[i] : exists j : 1 <= i <= 100 and i >= 4j + 1 and " + "i <= 4j + 2 }" }, + { 1, "{ [c0] : (exists (e0 : c0 - 1 <= 3e0 <= c0)) or " + "(exists (e0 : 3e0 = -2 + c0)) }" }, + { 0, "[n, b0, t0] -> " + "{ [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12] : " + "(exists (e0 = floor((-32b0 + i4)/1048576), " + "e1 = floor((i8)/32): 1048576e0 = -32b0 + i4 and 32e1 = i8 and " + "n <= 2147483647 and b0 <= 32767 and b0 >= 0 and " + "32b0 <= -2 + n and t0 <= 31 and t0 >= 0 and i0 >= 8 + n and " + "3i4 <= -96 + 3t0 + i0 and 3i4 >= -95 - n + 3t0 + i0 and " + "i8 >= -157 + i0 - 4i4 and i8 >= 0 and " + "i8 <= -33 + i0 - 4i4 and 3i8 <= -91 + 4n - i0)) or " + "(exists (e0 = floor((-32b0 + i4)/1048576), " + "e1 = floor((i8)/32): 1048576e0 = -32b0 + i4 and 32e1 = i8 and " + "n <= 2147483647 and b0 <= 32767 and b0 >= 0 and " + "32b0 <= -2 + n and t0 <= 31 and t0 >= 0 and i0 <= 7 + n and " + "4i4 <= -3 + i0 and 3i4 <= -96 + 3t0 + i0 and " + "3i4 >= -95 - n + 3t0 + i0 and i8 >= -157 + i0 - 4i4 and " + "i8 >= 0 and i8 <= -4 + i0 - 3i4 and i8 <= -41 + i0));" + "[i0, i1, i2, i3, 0, i5, i6, i7, i8, i9, i10, i11, i12] : " + "(exists (e0 = floor((i8)/32): b0 = 0 and 32e0 = i8 and " + "n <= 2147483647 and t0 <= 31 and t0 >= 0 and i0 >= 11 and " + "i0 >= 96 - 3t0 and i0 <= 95 + n - 3t0 and i0 <= 7 + n and " + "i8 >= -40 + i0 and i8 <= -10 + i0)) }" }, + { 0, "{ [i0, i1, i2] : " + "(exists (e0, e1 = floor((i0)/32), e2 = floor((i1)/32): " + "32e1 = i0 and 32e2 = i1 and i1 >= -31 + i0 and " + "i1 <= 31 + i0 and i2 >= -30 + i0 and i2 >= -30 + i1 and " + "32e0 >= -30 + i0 and 32e0 >= -30 + i1 and " + "32e0 >= -31 + i2 and 32e0 <= 30 + i2 and 32e0 <= 31 + i1 and " + "32e0 <= 31 + i0)) or " + "i0 >= 0 }" }, + { 1, "{ [a, b, c] : 2b = 1 + a and 2c = 2 + a; [0, 0, 0] }" }, + { 1, "{ [a, a, b, c] : 32*floor((a)/32) = a and 2*floor((b)/2) = b and " + "2*floor((c)/2) = c and 0 <= a <= 192;" + "[224, 224, b, c] : 2*floor((b)/2) = b and 2*floor((c)/2) = c }" + }, + { 1, "[n] -> { [a,b] : (exists e : 1 <= a <= 7e and 9e <= b <= n) or " + "(0 <= a <= b <= n) }" }, + { 1, "{ [a, b] : 0 <= a <= 2 and b >= 0 and " + "((0 < b <= 13) or (2*floor((a + b)/2) >= -5 + a + 2b)) }" }, + { 1, "{ [a] : (2 <= a <= 5) or (a mod 2 = 1 and 1 <= a <= 5) }" }, + { 1, "{ [a, b, c] : (b = -1 + a and 0 < a <= 3 and " + "9*floor((-4a + 2c)/9) <= -3 - 4a + 2c) or " + "(exists (e0 = floor((-16 + 2c)/9): a = 4 and " + "b = 3 and 9e0 <= -19 + 2c)) }" }, + { 1, "{ [a, b, c] : (b = -1 + a and 0 < a <= 3 and " + "9*floor((-4a + 2c)/9) <= -3 - 4a + 2c) or " + "(a = 4 and b = 3 and " + "9*floor((-16 + 2c)/9) <= -19 + 2c) }" }, + { 0, "{ [a, b, c] : (b <= 2 and b <= -2 + a) or " + "(b = -1 + a and 0 < a <= 3 and " + "9*floor((-4a + 2c)/9) <= -3 - 4a + 2c) or " + "(exists (e0 = floor((-16 + 2c)/9): a = 4 and " + "b = 3 and 9e0 <= -19 + 2c)) }" }, + { 1, "{ [y, x] : (x - y) mod 3 = 2 and 2 <= y <= 200 and 0 <= x <= 2;" + "[1, 0] }" }, + { 1, "{ [x, y] : (x - y) mod 3 = 2 and 2 <= y <= 200 and 0 <= x <= 2;" + "[0, 1] }" }, + { 1, "{ [1, y] : -1 <= y <= 1; [x, -x] : 0 <= x <= 1 }" }, + { 1, "{ [1, y] : 0 <= y <= 1; [x, -x] : 0 <= x <= 1 }" }, + { 1, "{ [x, y] : 0 <= x <= 10 and x - 4*floor(x/4) <= 1 and y <= 0; " + "[x, y] : 0 <= x <= 10 and x - 4*floor(x/4) > 1 and y <= 0; " + "[x, y] : 0 <= x <= 10 and x - 5*floor(x/5) <= 1 and 0 < y; " + "[x, y] : 0 <= x <= 10 and x - 5*floor(x/5) > 1 and 0 < y }" }, + { 1, "{ [x, 0] : 0 <= x <= 10 and x mod 2 = 0; " + "[x, 0] : 0 <= x <= 10 and x mod 2 = 1; " + "[x, y] : 0 <= x <= 10 and 1 <= y <= 10 }" }, + { 1, "{ [a] : a <= 8 and " + "(a mod 10 = 7 or a mod 10 = 8 or a mod 10 = 9) }" }, + { 1, "{ [x, y] : 2y = -x and x <= 0 or " + "x <= -1 and 2y <= -x - 1 and 2y >= x - 1 }" }, + { 0, "{ [x, y] : 2y = -x and x <= 0 or " + "x <= -2 and 2y <= -x - 1 and 2y >= x - 1 }" }, + { 1, "{ [a] : (a <= 0 and 3*floor((a)/3) = a) or " + "(a < 0 and 3*floor((a)/3) < a) }" }, + { 1, "{ [a] : (a <= 0 and 3*floor((a)/3) = a) or " + "(a < -1 and 3*floor((a)/3) < a) }" }, + { 1, "{ [a, b] : a <= 1024 and b >= 0 and " + "((-31 - a + b <= 32*floor((-1 - a)/32) <= -33 + b and " + "32*floor((-1 - a)/32) <= -16 + b + 16*floor((-1 - a)/16))" + "or (2 <= a <= 15 and b < a)) }" }, + { 1, "{ [a] : a > 0 and ((16*floor((a)/16) < a and " + "32*floor((a)/32) < a) or a <= 15) }" }, + { 1, "{ [a, b, c, d] : (-a + d) mod 64 = 0 and a <= 8 and b <= 1 and " + "10 - a <= c <= 3 and d >= 5 and 9 - 64b <= d <= 70;" + "[a, b = 1, c, d] : (-a + d) mod 64 = 0 and a <= 8 and c >= 4 and " + "10 - a <= c <= 5 and 5 <= d <= 73 - c }" }, + { 1, "[n, m] -> { S_0[i] : (-n + i) mod 3 = 0 and m >= 3 + n and " + "i >= n and 3*floor((2 + n + 2m)/3) <= n + 3m - i; " + "S_0[n] : n <= m <= 2 + n }" }, + { 1, "{ [a, b] : exists (e0: 0 <= a <= 1 and b >= 0 and " + "2e0 >= -5 + a + 2b and 2e0 >= -1 + a + b and " + "2e0 <= a + b); " + "[a, b] : exists (e0: 0 <= a <= 1 and 2e0 >= -5 + a + 2b and " + "2e0 >= -1 - a + b and 2e0 <= -a + b and " + "2e0 < -a + 2b) }" }, + { 1, "{ [i, j, i - 8j] : 8 <= i <= 63 and -7 + i <= 8j <= i; " + "[i, 0, i] : 0 <= i <= 7 }" }, + { 1, "{ [a, b] : a >= 0 and 0 <= b <= 1 - a; [1, 1] }" }, + { 0, "{ [a, b] : a >= 0 and 0 <= b <= 1 - a; [0, 2] }" }, + { 0, "{ [a, b] : a >= 0 and 0 <= b <= 1 - a; [-1, 3] }" }, + { 1, "{ [a, b] : a, b >= 0 and a + 2b <= 2; [1, 1] }" }, + { 0, "{ [a, b] : a, b >= 0 and a + 2b <= 2; [2, 1] }" }, +}; + +/* A specialized coalescing test case that would result + * in a segmentation fault or a failed assertion in earlier versions of isl. + */ +static int test_coalesce_special(struct isl_ctx *ctx) +{ + const char *str; + isl_map *map1, *map2; + + str = "[y] -> { [S_L220_OUT[] -> T7[]] -> " + "[[S_L309_IN[] -> T11[]] -> ce_imag2[1, o1]] : " + "(y = 201 and o1 <= 239 and o1 >= 212) or " + "(exists (e0 = [(y)/3]: 3e0 = y and y <= 198 and y >= 3 and " + "o1 <= 239 and o1 >= 212)) or " + "(exists (e0 = [(y)/3]: 3e0 = y and y <= 201 and y >= 3 and " + "o1 <= 241 and o1 >= 240));" + "[S_L220_OUT[] -> T7[]] -> " + "[[S_L309_IN[] -> T11[]] -> ce_imag2[0, o1]] : " + "(y = 2 and o1 <= 241 and o1 >= 212) or " + "(exists (e0 = [(-2 + y)/3]: 3e0 = -2 + y and y <= 200 and " + "y >= 5 and o1 <= 241 and o1 >= 212)) }"; + map1 = isl_map_read_from_str(ctx, str); + map1 = isl_map_align_divs_internal(map1); + map1 = isl_map_coalesce(map1); + str = "[y] -> { [S_L220_OUT[] -> T7[]] -> " + "[[S_L309_IN[] -> T11[]] -> ce_imag2[o0, o1]] : " + "exists (e0 = [(-1 - y + o0)/3]: 3e0 = -1 - y + o0 and " + "y <= 201 and o0 <= 2 and o1 >= 212 and o1 <= 241 and " + "o0 >= 3 - y and o0 <= -2 + y and o0 >= 0) }"; + map2 = isl_map_read_from_str(ctx, str); + map2 = isl_map_union(map2, map1); + map2 = isl_map_align_divs_internal(map2); + map2 = isl_map_coalesce(map2); + isl_map_free(map2); + if (!map2) + return -1; + + return 0; +} + +/* A specialized coalescing test case that would result in an assertion + * in an earlier version of isl. + * The explicit call to isl_basic_set_union prevents the implicit + * equality constraints in the first basic map from being detected prior + * to the call to isl_set_coalesce, at least at the point + * where this test case was introduced. + */ +static int test_coalesce_special2(struct isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset1, *bset2; + isl_set *set; + + str = "{ [x, y] : x, y >= 0 and x + 2y <= 1 and 2x + y <= 1 }"; + bset1 = isl_basic_set_read_from_str(ctx, str); + str = "{ [x,0] : -1 <= x <= 1 and x mod 2 = 1 }" ; + bset2 = isl_basic_set_read_from_str(ctx, str); + set = isl_basic_set_union(bset1, bset2); + set = isl_set_coalesce(set); + isl_set_free(set); + + if (!set) + return -1; + return 0; +} + +/* Check that calling isl_set_coalesce does not leave other sets + * that may share some information with the input to isl_set_coalesce + * in an inconsistent state. + * In particular, older versions of isl would modify all copies + * of the basic sets in the isl_set_coalesce input in a way + * that could leave them in an inconsistent state. + * The result of printing any other set containing one of these + * basic sets would then result in an invalid set description. + */ +static int test_coalesce_special3(isl_ctx *ctx) +{ + const char *str; + char *s; + isl_set *set1, *set2; + isl_printer *p; + + set1 = isl_set_read_from_str(ctx, "{ [0, 0, 0] }"); + str = "{ [a, b, a + b] : a >= 0 and b >= 0 and 0 < a + b }"; + set2 = isl_set_read_from_str(ctx, str); + set1 = isl_set_union(set1, isl_set_copy(set2)); + set1 = isl_set_coalesce(set1); + isl_set_free(set1); + + p = isl_printer_to_str(ctx); + p = isl_printer_print_set(p, set2); + isl_set_free(set2); + s = isl_printer_get_str(p); + isl_printer_free(p); + set1 = isl_set_read_from_str(ctx, s); + free(s); + isl_set_free(set1); + + if (!set1) + return -1; + + return 0; +} + +/* Test the functionality of isl_set_coalesce. + * That is, check that the output is always equal to the input + * and in some cases that the result consists of a single disjunct. + */ +static int test_coalesce(struct isl_ctx *ctx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coalesce_tests); ++i) { + const char *str = coalesce_tests[i].str; + int check_one = coalesce_tests[i].single_disjunct; + if (test_coalesce_set(ctx, str, check_one) < 0) + return -1; + } + + if (test_coalesce_unbounded_wrapping(ctx) < 0) + return -1; + if (test_coalesce_special(ctx) < 0) + return -1; + if (test_coalesce_special2(ctx) < 0) + return -1; + if (test_coalesce_special3(ctx) < 0) + return -1; + + return 0; +} + +/* Construct a representation of the graph on the right of Figure 1 + * in "Computing the Transitive Closure of a Union of + * Affine Integer Tuple Relations". + */ +static __isl_give isl_map *cocoa_fig_1_right_graph(isl_ctx *ctx) +{ + isl_set *dom; + isl_map *up, *right; + + dom = isl_set_read_from_str(ctx, + "{ [x,y] : x >= 0 and -2 x + 3 y >= 0 and x <= 3 and " + "2 x - 3 y + 3 >= 0 }"); + right = isl_map_read_from_str(ctx, + "{ [x,y] -> [x2,y2] : x2 = x + 1 and y2 = y }"); + up = isl_map_read_from_str(ctx, + "{ [x,y] -> [x2,y2] : x2 = x and y2 = y + 1 }"); + right = isl_map_intersect_domain(right, isl_set_copy(dom)); + right = isl_map_intersect_range(right, isl_set_copy(dom)); + up = isl_map_intersect_domain(up, isl_set_copy(dom)); + up = isl_map_intersect_range(up, dom); + return isl_map_union(up, right); +} + +/* Construct a representation of the power of the graph + * on the right of Figure 1 in "Computing the Transitive Closure of + * a Union of Affine Integer Tuple Relations". + */ +static __isl_give isl_map *cocoa_fig_1_right_power(isl_ctx *ctx) +{ + return isl_map_read_from_str(ctx, + "{ [1] -> [[0,0] -> [0,1]]; [2] -> [[0,0] -> [1,1]]; " + " [1] -> [[0,1] -> [1,1]]; [1] -> [[2,2] -> [3,2]]; " + " [2] -> [[2,2] -> [3,3]]; [1] -> [[3,2] -> [3,3]] }"); +} + +/* Construct a representation of the transitive closure of the graph + * on the right of Figure 1 in "Computing the Transitive Closure of + * a Union of Affine Integer Tuple Relations". + */ +static __isl_give isl_map *cocoa_fig_1_right_tc(isl_ctx *ctx) +{ + return isl_set_unwrap(isl_map_range(cocoa_fig_1_right_power(ctx))); +} + +static int test_closure(isl_ctx *ctx) +{ + const char *str; + isl_map *map, *map2; + int exact, equal; + + /* COCOA example 1 */ + map = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : i2 = i + 1 and j2 = j + 1 and " + "1 <= i and i < n and 1 <= j and j < n or " + "i2 = i + 1 and j2 = j - 1 and " + "1 <= i and i < n and 2 <= j and j <= n }"); + map = isl_map_power(map, &exact); + assert(exact); + isl_map_free(map); + + /* COCOA example 1 */ + map = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : i2 = i + 1 and j2 = j + 1 and " + "1 <= i and i < n and 1 <= j and j < n or " + "i2 = i + 1 and j2 = j - 1 and " + "1 <= i and i < n and 2 <= j and j <= n }"); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + map2 = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : exists (k1,k2,k : " + "1 <= i and i < n and 1 <= j and j <= n and " + "2 <= i2 and i2 <= n and 1 <= j2 and j2 <= n and " + "i2 = i + k1 + k2 and j2 = j + k1 - k2 and " + "k1 >= 0 and k2 >= 0 and k1 + k2 = k and k >= 1 )}"); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map2); + isl_map_free(map); + + map = isl_map_read_from_str(ctx, + "[n] -> { [x] -> [y] : y = x + 1 and 0 <= x and x <= n and " + " 0 <= y and y <= n }"); + map = isl_map_transitive_closure(map, &exact); + map2 = isl_map_read_from_str(ctx, + "[n] -> { [x] -> [y] : y > x and 0 <= x and x <= n and " + " 0 <= y and y <= n }"); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map2); + isl_map_free(map); + + /* COCOA example 2 */ + map = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : i2 = i + 2 and j2 = j + 2 and " + "1 <= i and i < n - 1 and 1 <= j and j < n - 1 or " + "i2 = i + 2 and j2 = j - 2 and " + "1 <= i and i < n - 1 and 3 <= j and j <= n }"); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + map2 = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : exists (k1,k2,k : " + "1 <= i and i < n - 1 and 1 <= j and j <= n and " + "3 <= i2 and i2 <= n and 1 <= j2 and j2 <= n and " + "i2 = i + 2 k1 + 2 k2 and j2 = j + 2 k1 - 2 k2 and " + "k1 >= 0 and k2 >= 0 and k1 + k2 = k and k >= 1) }"); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map); + isl_map_free(map2); + + /* COCOA Fig.2 left */ + map = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : i2 = i + 2 and j2 = j and " + "i <= 2 j - 3 and i <= n - 2 and j <= 2 i - 1 and " + "j <= n or " + "i2 = i and j2 = j + 2 and i <= 2 j - 1 and i <= n and " + "j <= 2 i - 3 and j <= n - 2 or " + "i2 = i + 1 and j2 = j + 1 and i <= 2 j - 1 and " + "i <= n - 1 and j <= 2 i - 1 and j <= n - 1 }"); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + isl_map_free(map); + + /* COCOA Fig.2 right */ + map = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : i2 = i + 3 and j2 = j and " + "i <= 2 j - 4 and i <= n - 3 and j <= 2 i - 1 and " + "j <= n or " + "i2 = i and j2 = j + 3 and i <= 2 j - 1 and i <= n and " + "j <= 2 i - 4 and j <= n - 3 or " + "i2 = i + 1 and j2 = j + 1 and i <= 2 j - 1 and " + "i <= n - 1 and j <= 2 i - 1 and j <= n - 1 }"); + map = isl_map_power(map, &exact); + assert(exact); + isl_map_free(map); + + /* COCOA Fig.2 right */ + map = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : i2 = i + 3 and j2 = j and " + "i <= 2 j - 4 and i <= n - 3 and j <= 2 i - 1 and " + "j <= n or " + "i2 = i and j2 = j + 3 and i <= 2 j - 1 and i <= n and " + "j <= 2 i - 4 and j <= n - 3 or " + "i2 = i + 1 and j2 = j + 1 and i <= 2 j - 1 and " + "i <= n - 1 and j <= 2 i - 1 and j <= n - 1 }"); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + map2 = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : exists (k1,k2,k3,k : " + "i <= 2 j - 1 and i <= n and j <= 2 i - 1 and " + "j <= n and 3 + i + 2 j <= 3 n and " + "3 + 2 i + j <= 3n and i2 <= 2 j2 -1 and i2 <= n and " + "i2 <= 3 j2 - 4 and j2 <= 2 i2 -1 and j2 <= n and " + "13 + 4 j2 <= 11 i2 and i2 = i + 3 k1 + k3 and " + "j2 = j + 3 k2 + k3 and k1 >= 0 and k2 >= 0 and " + "k3 >= 0 and k1 + k2 + k3 = k and k > 0) }"); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map2); + isl_map_free(map); + + map = cocoa_fig_1_right_graph(ctx); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + map2 = cocoa_fig_1_right_tc(ctx); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map2); + isl_map_free(map); + + map = cocoa_fig_1_right_graph(ctx); + map = isl_map_power(map, &exact); + map2 = cocoa_fig_1_right_power(ctx); + equal = isl_map_is_equal(map, map2); + isl_map_free(map2); + isl_map_free(map); + if (equal < 0) + return -1; + if (!exact) + isl_die(ctx, isl_error_unknown, "power not exact", return -1); + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected power", return -1); + + /* COCOA Theorem 1 counter example */ + map = isl_map_read_from_str(ctx, + "{ [i,j] -> [i2,j2] : i = 0 and 0 <= j and j <= 1 and " + "i2 = 1 and j2 = j or " + "i = 0 and j = 0 and i2 = 0 and j2 = 1 }"); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + isl_map_free(map); + + map = isl_map_read_from_str(ctx, + "[m,n] -> { [i,j] -> [i2,j2] : i2 = i and j2 = j + 2 and " + "1 <= i,i2 <= n and 1 <= j,j2 <= m or " + "i2 = i + 1 and 3 <= j2 - j <= 4 and " + "1 <= i,i2 <= n and 1 <= j,j2 <= m }"); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + isl_map_free(map); + + /* Kelly et al 1996, fig 12 */ + map = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : i2 = i and j2 = j + 1 and " + "1 <= i,j,j+1 <= n or " + "j = n and j2 = 1 and i2 = i + 1 and " + "1 <= i,i+1 <= n }"); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + map2 = isl_map_read_from_str(ctx, + "[n] -> { [i,j] -> [i2,j2] : 1 <= j < j2 <= n and " + "1 <= i <= n and i = i2 or " + "1 <= i < i2 <= n and 1 <= j <= n and " + "1 <= j2 <= n }"); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map2); + isl_map_free(map); + + /* Omega's closure4 */ + map = isl_map_read_from_str(ctx, + "[m,n] -> { [x,y] -> [x2,y2] : x2 = x and y2 = y + 1 and " + "1 <= x,y <= 10 or " + "x2 = x + 1 and y2 = y and " + "1 <= x <= 20 && 5 <= y <= 15 }"); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + isl_map_free(map); + + map = isl_map_read_from_str(ctx, + "[n] -> { [x] -> [y]: 1 <= n <= y - x <= 10 }"); + map = isl_map_transitive_closure(map, &exact); + assert(!exact); + map2 = isl_map_read_from_str(ctx, + "[n] -> { [x] -> [y] : 1 <= n <= 10 and y >= n + x }"); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map); + isl_map_free(map2); + + str = "[n, m] -> { [i0, i1, i2, i3] -> [o0, o1, o2, o3] : " + "i3 = 1 and o0 = i0 and o1 = -1 + i1 and o2 = -1 + i2 and " + "o3 = -2 + i2 and i1 <= -1 + i0 and i1 >= 1 - m + i0 and " + "i1 >= 2 and i1 <= n and i2 >= 3 and i2 <= 1 + n and i2 <= m }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + map2 = isl_map_read_from_str(ctx, str); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map); + isl_map_free(map2); + + str = "{[0] -> [1]; [2] -> [3]}"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_transitive_closure(map, &exact); + assert(exact); + map2 = isl_map_read_from_str(ctx, str); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map); + isl_map_free(map2); + + str = "[n] -> { [[i0, i1, 1, 0, i0] -> [i5, 1]] -> " + "[[i0, -1 + i1, 2, 0, i0] -> [-1 + i5, 2]] : " + "exists (e0 = [(3 - n)/3]: i5 >= 2 and i1 >= 2 and " + "3i0 <= -1 + n and i1 <= -1 + n and i5 <= -1 + n and " + "3e0 >= 1 - n and 3e0 <= 2 - n and 3i0 >= -2 + n); " + "[[i0, i1, 2, 0, i0] -> [i5, 1]] -> " + "[[i0, i1, 1, 0, i0] -> [-1 + i5, 2]] : " + "exists (e0 = [(3 - n)/3]: i5 >= 2 and i1 >= 1 and " + "3i0 <= -1 + n and i1 <= -1 + n and i5 <= -1 + n and " + "3e0 >= 1 - n and 3e0 <= 2 - n and 3i0 >= -2 + n); " + "[[i0, i1, 1, 0, i0] -> [i5, 2]] -> " + "[[i0, -1 + i1, 2, 0, i0] -> [i5, 1]] : " + "exists (e0 = [(3 - n)/3]: i1 >= 2 and i5 >= 1 and " + "3i0 <= -1 + n and i1 <= -1 + n and i5 <= -1 + n and " + "3e0 >= 1 - n and 3e0 <= 2 - n and 3i0 >= -2 + n); " + "[[i0, i1, 2, 0, i0] -> [i5, 2]] -> " + "[[i0, i1, 1, 0, i0] -> [i5, 1]] : " + "exists (e0 = [(3 - n)/3]: i5 >= 1 and i1 >= 1 and " + "3i0 <= -1 + n and i1 <= -1 + n and i5 <= -1 + n and " + "3e0 >= 1 - n and 3e0 <= 2 - n and 3i0 >= -2 + n) }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_transitive_closure(map, NULL); + assert(map); + isl_map_free(map); + + return 0; +} + +static int test_lex(struct isl_ctx *ctx) +{ + isl_space *dim; + isl_map *map; + int empty; + + dim = isl_space_set_alloc(ctx, 0, 0); + map = isl_map_lex_le(dim); + empty = isl_map_is_empty(map); + isl_map_free(map); + + if (empty < 0) + return -1; + if (empty) + isl_die(ctx, isl_error_unknown, + "expecting non-empty result", return -1); + + return 0; +} + +/* Inputs for isl_map_lexmin tests. + * "map" is the input and "lexmin" is the expected result. + */ +struct { + const char *map; + const char *lexmin; +} lexmin_tests [] = { + { "{ [x] -> [y] : x <= y <= 10; [x] -> [5] : -8 <= x <= 8 }", + "{ [x] -> [5] : 6 <= x <= 8; " + "[x] -> [x] : x <= 5 or (9 <= x <= 10) }" }, + { "{ [x] -> [y] : 4y = x or 4y = -1 + x or 4y = -2 + x }", + "{ [x] -> [y] : 4y = x or 4y = -1 + x or 4y = -2 + x }" }, + { "{ [x] -> [y] : x = 4y; [x] -> [y] : x = 2y }", + "{ [x] -> [y] : (4y = x and x >= 0) or " + "(exists (e0 = [(x)/4], e1 = [(-2 + x)/4]: 2y = x and " + "4e1 = -2 + x and 4e0 <= -1 + x and 4e0 >= -3 + x)) or " + "(exists (e0 = [(x)/4]: 2y = x and 4e0 = x and x <= -4)) }" }, + { "{ T[a] -> S[b, c] : a = 4b-2c and c >= b }", + "{ T[a] -> S[b, c] : 2b = a and 2c = a }" }, + /* Check that empty pieces are properly combined. */ + { "[K, N] -> { [x, y] -> [a, b] : K+2<=N<=K+4 and x>=4 and " + "2N-6<=x=N and a>=x+1 }", + "[K, N] -> { [x, y] -> [1 + x, N] : x >= -6 + 2N and " + "x <= -5 + 2N and x >= -1 + 3K - N and x <= -2 + K + N and " + "x >= 4 }" }, + { "{ [i, k, j] -> [a, b, c, d] : 8*floor((b)/8) = b and k <= 255 and " + "a <= 255 and c <= 255 and d <= 255 - j and " + "255 - j <= 7d <= 7 - i and 240d <= 239 + a and " + "247d <= 247 + k - j and 247d <= 247 + k - b and " + "247d <= 247 + i and 248 - b <= 248d <= c and " + "254d >= i - a + b and 254d >= -a + b and " + "255d >= -i + a - b and 1792d >= -63736 + 257b }", + "{ [i, k, j] -> " + "[-127762 + i + 502j, -62992 + 248j, 63240 - 248j, 255 - j] : " + "k <= 255 and 7j >= 1778 + i and 246j >= 62738 - k and " + "247j >= 62738 - i and 509j <= 129795 + i and " + "742j >= 188724 - i; " + "[0, k, j] -> [1, 0, 248, 1] : k <= 255 and 248 <= j <= 254, k }" }, + { "{ [a] -> [b] : 0 <= b <= 255 and -509 + a <= 512b < a and " + "16*floor((8 + b)/16) <= 7 + b; " + "[a] -> [1] }", + "{ [a] -> [b = 1] : a >= 510 or a <= 0; " + "[a] -> [b = 0] : 0 < a <= 509 }" }, + { "{ rat: [i] : 1 <= 2i <= 9 }", "{ rat: [i] : 2i = 1 }" }, + { "{ rat: [i] : 1 <= 2i <= 9 or i >= 10 }", "{ rat: [i] : 2i = 1 }" }, +}; + +static int test_lexmin(struct isl_ctx *ctx) +{ + int i; + int equal; + const char *str; + isl_basic_map *bmap; + isl_map *map, *map2; + isl_set *set; + isl_set *set2; + isl_pw_multi_aff *pma; + + str = "[p0, p1] -> { [] -> [] : " + "exists (e0 = [(2p1)/3], e1, e2, e3 = [(3 - p1 + 3e0)/3], " + "e4 = [(p1)/3], e5 = [(p1 + 3e4)/3]: " + "3e0 >= -2 + 2p1 and 3e0 >= p1 and 3e3 >= 1 - p1 + 3e0 and " + "3e0 <= 2p1 and 3e3 >= -2 + p1 and 3e3 <= -1 + p1 and p1 >= 3 and " + "3e5 >= -2 + 2p1 and 3e5 >= p1 and 3e5 <= -1 + p1 + 3e4 and " + "3e4 <= p1 and 3e4 >= -2 + p1 and e3 <= -1 + e0 and " + "3e4 >= 6 - p1 + 3e1 and 3e1 >= p1 and 3e5 >= -2 + p1 + 3e4 and " + "2e4 >= 3 - p1 + 2e1 and e4 <= e1 and 3e3 <= 2 - p1 + 3e0 and " + "e5 >= 1 + e1 and 3e4 >= 6 - 2p1 + 3e1 and " + "p0 >= 2 and p1 >= p0 and 3e2 >= p1 and 3e4 >= 6 - p1 + 3e2 and " + "e2 <= e1 and e3 >= 1 and e4 <= e2) }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_lexmin(map); + isl_map_free(map); + + str = "[C] -> { [obj,a,b,c] : obj <= 38 a + 7 b + 10 c and " + "a + b <= 1 and c <= 10 b and c <= C and a,b,c,C >= 0 }"; + set = isl_set_read_from_str(ctx, str); + set = isl_set_lexmax(set); + str = "[C] -> { [obj,a,b,c] : C = 8 }"; + set2 = isl_set_read_from_str(ctx, str); + set = isl_set_intersect(set, set2); + assert(!isl_set_is_empty(set)); + isl_set_free(set); + + for (i = 0; i < ARRAY_SIZE(lexmin_tests); ++i) { + map = isl_map_read_from_str(ctx, lexmin_tests[i].map); + map = isl_map_lexmin(map); + map2 = isl_map_read_from_str(ctx, lexmin_tests[i].lexmin); + equal = isl_map_is_equal(map, map2); + isl_map_free(map); + isl_map_free(map2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + str = "{ [i] -> [i', j] : j = i - 8i' and i' >= 0 and i' <= 7 and " + " 8i' <= i and 8i' >= -7 + i }"; + bmap = isl_basic_map_read_from_str(ctx, str); + pma = isl_basic_map_lexmin_pw_multi_aff(isl_basic_map_copy(bmap)); + map2 = isl_map_from_pw_multi_aff(pma); + map = isl_map_from_basic_map(bmap); + assert(isl_map_is_equal(map, map2)); + isl_map_free(map); + isl_map_free(map2); + + str = "[i] -> { [i', j] : j = i - 8i' and i' >= 0 and i' <= 7 and " + " 8i' <= i and 8i' >= -7 + i }"; + set = isl_set_read_from_str(ctx, str); + pma = isl_set_lexmin_pw_multi_aff(isl_set_copy(set)); + set2 = isl_set_from_pw_multi_aff(pma); + equal = isl_set_is_equal(set, set2); + isl_set_free(set); + isl_set_free(set2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "unexpected difference between set and " + "piecewise affine expression", return -1); + + return 0; +} + +/* A specialized isl_set_min_val test case that would return the wrong result + * in earlier versions of isl. + * The explicit call to isl_basic_set_union prevents the second basic set + * from being determined to be empty prior to the call to isl_set_min_val, + * at least at the point where this test case was introduced. + */ +static int test_min_special(isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset1, *bset2; + isl_set *set; + isl_aff *obj; + isl_val *res; + int ok; + + str = "{ [a, b] : a >= 2 and b >= 0 and 14 - a <= b <= 9 }"; + bset1 = isl_basic_set_read_from_str(ctx, str); + str = "{ [a, b] : 1 <= a, b and a + b <= 1 }"; + bset2 = isl_basic_set_read_from_str(ctx, str); + set = isl_basic_set_union(bset1, bset2); + obj = isl_aff_read_from_str(ctx, "{ [a, b] -> [a] }"); + + res = isl_set_min_val(set, obj); + ok = isl_val_cmp_si(res, 5) == 0; + + isl_aff_free(obj); + isl_set_free(set); + isl_val_free(res); + + if (!res) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, "unexpected minimum", + return -1); + + return 0; +} + +/* A specialized isl_set_min_val test case that would return an error + * in earlier versions of isl. + */ +static int test_min_special2(isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset; + isl_aff *obj; + isl_val *res; + + str = "{ [i, j, k] : 2j = i and 2k = i + 1 and i >= 2 }"; + bset = isl_basic_set_read_from_str(ctx, str); + + obj = isl_aff_read_from_str(ctx, "{ [i, j, k] -> [i] }"); + + res = isl_basic_set_max_val(bset, obj); + + isl_basic_set_free(bset); + isl_aff_free(obj); + isl_val_free(res); + + if (!res) + return -1; + + return 0; +} + +struct { + const char *set; + const char *obj; + __isl_give isl_val *(*fn)(__isl_keep isl_set *set, + __isl_keep isl_aff *obj); + const char *res; +} opt_tests[] = { + { "{ [-1]; [1] }", "{ [x] -> [x] }", &isl_set_min_val, "-1" }, + { "{ [-1]; [1] }", "{ [x] -> [x] }", &isl_set_max_val, "1" }, + { "{ [a, b] : 0 <= a, b <= 100 and b mod 2 = 0}", + "{ [a, b] -> [floor((b - 2*floor((-a)/4))/5)] }", + &isl_set_max_val, "30" }, + +}; + +/* Perform basic isl_set_min_val and isl_set_max_val tests. + * In particular, check the results on non-convex inputs. + */ +static int test_min(struct isl_ctx *ctx) +{ + int i; + isl_set *set; + isl_aff *obj; + isl_val *val, *res; + isl_bool ok; + + for (i = 0; i < ARRAY_SIZE(opt_tests); ++i) { + set = isl_set_read_from_str(ctx, opt_tests[i].set); + obj = isl_aff_read_from_str(ctx, opt_tests[i].obj); + res = isl_val_read_from_str(ctx, opt_tests[i].res); + val = opt_tests[i].fn(set, obj); + ok = isl_val_eq(res, val); + isl_val_free(res); + isl_val_free(val); + isl_aff_free(obj); + isl_set_free(set); + + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, + "unexpected optimum", return -1); + } + + if (test_min_special(ctx) < 0) + return -1; + if (test_min_special2(ctx) < 0) + return -1; + + return 0; +} + +struct must_may { + isl_map *must; + isl_map *may; +}; + +static isl_stat collect_must_may(__isl_take isl_map *dep, int must, + void *dep_user, void *user) +{ + struct must_may *mm = (struct must_may *)user; + + if (must) + mm->must = isl_map_union(mm->must, dep); + else + mm->may = isl_map_union(mm->may, dep); + + return isl_stat_ok; +} + +static int common_space(void *first, void *second) +{ + int depth = *(int *)first; + return 2 * depth; +} + +static int map_is_equal(__isl_keep isl_map *map, const char *str) +{ + isl_map *map2; + int equal; + + if (!map) + return -1; + + map2 = isl_map_read_from_str(map->ctx, str); + equal = isl_map_is_equal(map, map2); + isl_map_free(map2); + + return equal; +} + +static int map_check_equal(__isl_keep isl_map *map, const char *str) +{ + int equal; + + equal = map_is_equal(map, str); + if (equal < 0) + return -1; + if (!equal) + isl_die(isl_map_get_ctx(map), isl_error_unknown, + "result not as expected", return -1); + return 0; +} + +static int test_dep(struct isl_ctx *ctx) +{ + const char *str; + isl_space *dim; + isl_map *map; + isl_access_info *ai; + isl_flow *flow; + int depth; + struct must_may mm; + + depth = 3; + + str = "{ [2,i,0] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_alloc(map, &depth, &common_space, 2); + + str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 1, &depth); + + str = "{ [1,i,0] -> [5] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 1, &depth); + + flow = isl_access_info_compute_flow(ai); + dim = isl_space_alloc(ctx, 0, 3, 3); + mm.must = isl_map_empty(isl_space_copy(dim)); + mm.may = isl_map_empty(dim); + + isl_flow_foreach(flow, collect_must_may, &mm); + + str = "{ [0,i,0] -> [2,i,0] : (0 <= i <= 4) or (6 <= i <= 10); " + " [1,10,0] -> [2,5,0] }"; + assert(map_is_equal(mm.must, str)); + str = "{ [i,j,k] -> [l,m,n] : 1 = 0 }"; + assert(map_is_equal(mm.may, str)); + + isl_map_free(mm.must); + isl_map_free(mm.may); + isl_flow_free(flow); + + + str = "{ [2,i,0] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_alloc(map, &depth, &common_space, 2); + + str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 1, &depth); + + str = "{ [1,i,0] -> [5] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 0, &depth); + + flow = isl_access_info_compute_flow(ai); + dim = isl_space_alloc(ctx, 0, 3, 3); + mm.must = isl_map_empty(isl_space_copy(dim)); + mm.may = isl_map_empty(dim); + + isl_flow_foreach(flow, collect_must_may, &mm); + + str = "{ [0,i,0] -> [2,i,0] : (0 <= i <= 4) or (6 <= i <= 10) }"; + assert(map_is_equal(mm.must, str)); + str = "{ [0,5,0] -> [2,5,0]; [1,i,0] -> [2,5,0] : 0 <= i <= 10 }"; + assert(map_is_equal(mm.may, str)); + + isl_map_free(mm.must); + isl_map_free(mm.may); + isl_flow_free(flow); + + + str = "{ [2,i,0] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_alloc(map, &depth, &common_space, 2); + + str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 0, &depth); + + str = "{ [1,i,0] -> [5] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 0, &depth); + + flow = isl_access_info_compute_flow(ai); + dim = isl_space_alloc(ctx, 0, 3, 3); + mm.must = isl_map_empty(isl_space_copy(dim)); + mm.may = isl_map_empty(dim); + + isl_flow_foreach(flow, collect_must_may, &mm); + + str = "{ [0,i,0] -> [2,i,0] : 0 <= i <= 10; " + " [1,i,0] -> [2,5,0] : 0 <= i <= 10 }"; + assert(map_is_equal(mm.may, str)); + str = "{ [i,j,k] -> [l,m,n] : 1 = 0 }"; + assert(map_is_equal(mm.must, str)); + + isl_map_free(mm.must); + isl_map_free(mm.may); + isl_flow_free(flow); + + + str = "{ [0,i,2] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_alloc(map, &depth, &common_space, 2); + + str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 0, &depth); + + str = "{ [0,i,1] -> [5] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 0, &depth); + + flow = isl_access_info_compute_flow(ai); + dim = isl_space_alloc(ctx, 0, 3, 3); + mm.must = isl_map_empty(isl_space_copy(dim)); + mm.may = isl_map_empty(dim); + + isl_flow_foreach(flow, collect_must_may, &mm); + + str = "{ [0,i,0] -> [0,i,2] : 0 <= i <= 10; " + " [0,i,1] -> [0,5,2] : 0 <= i <= 5 }"; + assert(map_is_equal(mm.may, str)); + str = "{ [i,j,k] -> [l,m,n] : 1 = 0 }"; + assert(map_is_equal(mm.must, str)); + + isl_map_free(mm.must); + isl_map_free(mm.may); + isl_flow_free(flow); + + + str = "{ [0,i,1] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_alloc(map, &depth, &common_space, 2); + + str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 0, &depth); + + str = "{ [0,i,2] -> [5] : 0 <= i <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 0, &depth); + + flow = isl_access_info_compute_flow(ai); + dim = isl_space_alloc(ctx, 0, 3, 3); + mm.must = isl_map_empty(isl_space_copy(dim)); + mm.may = isl_map_empty(dim); + + isl_flow_foreach(flow, collect_must_may, &mm); + + str = "{ [0,i,0] -> [0,i,1] : 0 <= i <= 10; " + " [0,i,2] -> [0,5,1] : 0 <= i <= 4 }"; + assert(map_is_equal(mm.may, str)); + str = "{ [i,j,k] -> [l,m,n] : 1 = 0 }"; + assert(map_is_equal(mm.must, str)); + + isl_map_free(mm.must); + isl_map_free(mm.may); + isl_flow_free(flow); + + + depth = 5; + + str = "{ [1,i,0,0,0] -> [i,j] : 0 <= i <= 10 and 0 <= j <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_alloc(map, &depth, &common_space, 1); + + str = "{ [0,i,0,j,0] -> [i,j] : 0 <= i <= 10 and 0 <= j <= 10 }"; + map = isl_map_read_from_str(ctx, str); + ai = isl_access_info_add_source(ai, map, 1, &depth); + + flow = isl_access_info_compute_flow(ai); + dim = isl_space_alloc(ctx, 0, 5, 5); + mm.must = isl_map_empty(isl_space_copy(dim)); + mm.may = isl_map_empty(dim); + + isl_flow_foreach(flow, collect_must_may, &mm); + + str = "{ [0,i,0,j,0] -> [1,i,0,0,0] : 0 <= i,j <= 10 }"; + assert(map_is_equal(mm.must, str)); + str = "{ [0,0,0,0,0] -> [0,0,0,0,0] : 1 = 0 }"; + assert(map_is_equal(mm.may, str)); + + isl_map_free(mm.must); + isl_map_free(mm.may); + isl_flow_free(flow); + + return 0; +} + +/* Check that the dependence analysis proceeds without errors. + * Earlier versions of isl would break down during the analysis + * due to the use of the wrong spaces. + */ +static int test_flow(isl_ctx *ctx) +{ + const char *str; + isl_union_map *access, *schedule; + isl_union_map *must_dep, *may_dep; + int r; + + str = "{ S0[j] -> i[]; S1[j,i] -> i[]; S2[] -> i[]; S3[] -> i[] }"; + access = isl_union_map_read_from_str(ctx, str); + str = "{ S0[j] -> [0,j,0,0] : 0 <= j < 10; " + "S1[j,i] -> [0,j,1,i] : 0 <= j < i < 10; " + "S2[] -> [1,0,0,0]; " + "S3[] -> [-1,0,0,0] }"; + schedule = isl_union_map_read_from_str(ctx, str); + r = isl_union_map_compute_flow(access, isl_union_map_copy(access), + isl_union_map_copy(access), schedule, + &must_dep, &may_dep, NULL, NULL); + isl_union_map_free(may_dep); + isl_union_map_free(must_dep); + + return r; +} + +struct { + const char *map; + int sv; +} sv_tests[] = { + { "[N] -> { [i] -> [f] : 0 <= i <= N and 0 <= i - 10 f <= 9 }", 1 }, + { "[N] -> { [i] -> [f] : 0 <= i <= N and 0 <= i - 10 f <= 10 }", 0 }, + { "{ [i] -> [3*floor(i/2) + 5*floor(i/3)] }", 1 }, + { "{ S1[i] -> [i] : 0 <= i <= 9; S2[i] -> [i] : 0 <= i <= 9 }", 1 }, + { "{ [i] -> S1[i] : 0 <= i <= 9; [i] -> S2[i] : 0 <= i <= 9 }", 0 }, + { "{ A[i] -> [i]; B[i] -> [i]; B[i] -> [i + 1] }", 0 }, + { "{ A[i] -> [i]; B[i] -> [i] : i < 0; B[i] -> [i + 1] : i > 0 }", 1 }, + { "{ A[i] -> [i]; B[i] -> A[i] : i < 0; B[i] -> [i + 1] : i > 0 }", 1 }, + { "{ A[i] -> [i]; B[i] -> [j] : i - 1 <= j <= i }", 0 }, +}; + +int test_sv(isl_ctx *ctx) +{ + isl_union_map *umap; + int i; + int sv; + + for (i = 0; i < ARRAY_SIZE(sv_tests); ++i) { + umap = isl_union_map_read_from_str(ctx, sv_tests[i].map); + sv = isl_union_map_is_single_valued(umap); + isl_union_map_free(umap); + if (sv < 0) + return -1; + if (sv_tests[i].sv && !sv) + isl_die(ctx, isl_error_internal, + "map not detected as single valued", return -1); + if (!sv_tests[i].sv && sv) + isl_die(ctx, isl_error_internal, + "map detected as single valued", return -1); + } + + return 0; +} + +struct { + const char *str; + int bijective; +} bijective_tests[] = { + { "[N,M]->{[i,j] -> [i]}", 0 }, + { "[N,M]->{[i,j] -> [i] : j=i}", 1 }, + { "[N,M]->{[i,j] -> [i] : j=0}", 1 }, + { "[N,M]->{[i,j] -> [i] : j=N}", 1 }, + { "[N,M]->{[i,j] -> [j,i]}", 1 }, + { "[N,M]->{[i,j] -> [i+j]}", 0 }, + { "[N,M]->{[i,j] -> []}", 0 }, + { "[N,M]->{[i,j] -> [i,j,N]}", 1 }, + { "[N,M]->{[i,j] -> [2i]}", 0 }, + { "[N,M]->{[i,j] -> [i,i]}", 0 }, + { "[N,M]->{[i,j] -> [2i,i]}", 0 }, + { "[N,M]->{[i,j] -> [2i,j]}", 1 }, + { "[N,M]->{[i,j] -> [x,y] : 2x=i & y =j}", 1 }, +}; + +static int test_bijective(struct isl_ctx *ctx) +{ + isl_map *map; + int i; + int bijective; + + for (i = 0; i < ARRAY_SIZE(bijective_tests); ++i) { + map = isl_map_read_from_str(ctx, bijective_tests[i].str); + bijective = isl_map_is_bijective(map); + isl_map_free(map); + if (bijective < 0) + return -1; + if (bijective_tests[i].bijective && !bijective) + isl_die(ctx, isl_error_internal, + "map not detected as bijective", return -1); + if (!bijective_tests[i].bijective && bijective) + isl_die(ctx, isl_error_internal, + "map detected as bijective", return -1); + } + + return 0; +} + +/* Inputs for isl_pw_qpolynomial_gist tests. + * "pwqp" is the input, "set" is the context and "gist" is the expected result. + */ +struct { + const char *pwqp; + const char *set; + const char *gist; +} pwqp_gist_tests[] = { + { "{ [i] -> i }", "{ [k] : exists a : k = 2a }", "{ [i] -> i }" }, + { "{ [i] -> i + [ (i + [i/3])/2 ] }", "{ [10] }", "{ [i] -> 16 }" }, + { "{ [i] -> ([(i)/2]) }", "{ [k] : exists a : k = 2a+1 }", + "{ [i] -> -1/2 + 1/2 * i }" }, + { "{ [i] -> i^2 : i != 0 }", "{ [i] : i != 0 }", "{ [i] -> i^2 }" }, +}; + +static int test_pwqp(struct isl_ctx *ctx) +{ + int i; + const char *str; + isl_set *set; + isl_pw_qpolynomial *pwqp1, *pwqp2; + int equal; + + str = "{ [i,j,k] -> 1 + 9 * [i/5] + 7 * [j/11] + 4 * [k/13] }"; + pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str); + + pwqp1 = isl_pw_qpolynomial_move_dims(pwqp1, isl_dim_param, 0, + isl_dim_in, 1, 1); + + str = "[j] -> { [i,k] -> 1 + 9 * [i/5] + 7 * [j/11] + 4 * [k/13] }"; + pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str); + + pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2); + + assert(isl_pw_qpolynomial_is_zero(pwqp1)); + + isl_pw_qpolynomial_free(pwqp1); + + for (i = 0; i < ARRAY_SIZE(pwqp_gist_tests); ++i) { + str = pwqp_gist_tests[i].pwqp; + pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str); + str = pwqp_gist_tests[i].set; + set = isl_set_read_from_str(ctx, str); + pwqp1 = isl_pw_qpolynomial_gist(pwqp1, set); + str = pwqp_gist_tests[i].gist; + pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str); + pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2); + equal = isl_pw_qpolynomial_is_zero(pwqp1); + isl_pw_qpolynomial_free(pwqp1); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + str = "{ [i] -> ([([i/2] + [i/2])/5]) }"; + pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str); + str = "{ [i] -> ([(2 * [i/2])/5]) }"; + pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str); + + pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2); + + assert(isl_pw_qpolynomial_is_zero(pwqp1)); + + isl_pw_qpolynomial_free(pwqp1); + + str = "{ [x] -> ([x/2] + [(x+1)/2]) }"; + pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str); + str = "{ [x] -> x }"; + pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str); + + pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2); + + assert(isl_pw_qpolynomial_is_zero(pwqp1)); + + isl_pw_qpolynomial_free(pwqp1); + + str = "{ [i] -> ([i/2]) : i >= 0; [i] -> ([i/3]) : i < 0 }"; + pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str); + pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str); + pwqp1 = isl_pw_qpolynomial_coalesce(pwqp1); + pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2); + assert(isl_pw_qpolynomial_is_zero(pwqp1)); + isl_pw_qpolynomial_free(pwqp1); + + str = "{ [a,b,a] -> (([(2*[a/3]+b)/5]) * ([(2*[a/3]+b)/5])) }"; + pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str); + str = "{ [a,b,c] -> (([(2*[a/3]+b)/5]) * ([(2*[c/3]+b)/5])) }"; + pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str); + set = isl_set_read_from_str(ctx, "{ [a,b,a] }"); + pwqp1 = isl_pw_qpolynomial_intersect_domain(pwqp1, set); + equal = isl_pw_qpolynomial_plain_is_equal(pwqp1, pwqp2); + isl_pw_qpolynomial_free(pwqp1); + isl_pw_qpolynomial_free(pwqp2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + str = "{ [a,b,c] -> (([(2*[a/3]+1)/5]) * ([(2*[c/3]+1)/5])) : b = 1 }"; + pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str); + str = "{ [a,b,c] -> (([(2*[a/3]+b)/5]) * ([(2*[c/3]+b)/5])) }"; + pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str); + pwqp1 = isl_pw_qpolynomial_fix_val(pwqp1, isl_dim_set, 1, + isl_val_one(ctx)); + equal = isl_pw_qpolynomial_plain_is_equal(pwqp1, pwqp2); + isl_pw_qpolynomial_free(pwqp1); + isl_pw_qpolynomial_free(pwqp2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + return 0; +} + +static int test_split_periods(isl_ctx *ctx) +{ + const char *str; + isl_pw_qpolynomial *pwqp; + + str = "{ [U,V] -> 1/3 * U + 2/3 * V - [(U + 2V)/3] + [U/2] : " + "U + 2V + 3 >= 0 and - U -2V >= 0 and - U + 10 >= 0 and " + "U >= 0; [U,V] -> U^2 : U >= 100 }"; + pwqp = isl_pw_qpolynomial_read_from_str(ctx, str); + + pwqp = isl_pw_qpolynomial_split_periods(pwqp, 2); + + isl_pw_qpolynomial_free(pwqp); + + if (!pwqp) + return -1; + + return 0; +} + +static int test_union(isl_ctx *ctx) +{ + const char *str; + isl_union_set *uset1, *uset2; + isl_union_map *umap1, *umap2; + int equal; + + str = "{ [i] : 0 <= i <= 1 }"; + uset1 = isl_union_set_read_from_str(ctx, str); + str = "{ [1] -> [0] }"; + umap1 = isl_union_map_read_from_str(ctx, str); + + umap2 = isl_union_set_lex_gt_union_set(isl_union_set_copy(uset1), uset1); + equal = isl_union_map_is_equal(umap1, umap2); + + isl_union_map_free(umap1); + isl_union_map_free(umap2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "union maps not equal", + return -1); + + str = "{ A[i] -> B[i]; B[i] -> C[i]; A[0] -> C[1] }"; + umap1 = isl_union_map_read_from_str(ctx, str); + str = "{ A[i]; B[i] }"; + uset1 = isl_union_set_read_from_str(ctx, str); + + uset2 = isl_union_map_domain(umap1); + + equal = isl_union_set_is_equal(uset1, uset2); + + isl_union_set_free(uset1); + isl_union_set_free(uset2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "union sets not equal", + return -1); + + return 0; +} + +/* Check that computing a bound of a non-zero polynomial over an unbounded + * domain does not produce a rational value. + * In particular, check that the upper bound is infinity. + */ +static int test_bound_unbounded_domain(isl_ctx *ctx) +{ + const char *str; + isl_pw_qpolynomial *pwqp; + isl_pw_qpolynomial_fold *pwf, *pwf2; + isl_bool equal; + + str = "{ [m,n] -> -m * n }"; + pwqp = isl_pw_qpolynomial_read_from_str(ctx, str); + pwf = isl_pw_qpolynomial_bound(pwqp, isl_fold_max, NULL); + str = "{ infty }"; + pwqp = isl_pw_qpolynomial_read_from_str(ctx, str); + pwf2 = isl_pw_qpolynomial_bound(pwqp, isl_fold_max, NULL); + equal = isl_pw_qpolynomial_fold_plain_is_equal(pwf, pwf2); + isl_pw_qpolynomial_fold_free(pwf); + isl_pw_qpolynomial_fold_free(pwf2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "expecting infinite polynomial bound", return -1); + + return 0; +} + +static int test_bound(isl_ctx *ctx) +{ + const char *str; + unsigned dim; + isl_pw_qpolynomial *pwqp; + isl_pw_qpolynomial_fold *pwf; + + if (test_bound_unbounded_domain(ctx) < 0) + return -1; + + str = "{ [[a, b, c, d] -> [e]] -> 0 }"; + pwqp = isl_pw_qpolynomial_read_from_str(ctx, str); + pwf = isl_pw_qpolynomial_bound(pwqp, isl_fold_max, NULL); + dim = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_in); + isl_pw_qpolynomial_fold_free(pwf); + if (dim != 4) + isl_die(ctx, isl_error_unknown, "unexpected input dimension", + return -1); + + str = "{ [[x]->[x]] -> 1 : exists a : x = 2 a }"; + pwqp = isl_pw_qpolynomial_read_from_str(ctx, str); + pwf = isl_pw_qpolynomial_bound(pwqp, isl_fold_max, NULL); + dim = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_in); + isl_pw_qpolynomial_fold_free(pwf); + if (dim != 1) + isl_die(ctx, isl_error_unknown, "unexpected input dimension", + return -1); + + return 0; +} + +static int test_lift(isl_ctx *ctx) +{ + const char *str; + isl_basic_map *bmap; + isl_basic_set *bset; + + str = "{ [i0] : exists e0 : i0 = 4e0 }"; + bset = isl_basic_set_read_from_str(ctx, str); + bset = isl_basic_set_lift(bset); + bmap = isl_basic_map_from_range(bset); + bset = isl_basic_map_domain(bmap); + isl_basic_set_free(bset); + + return 0; +} + +struct { + const char *set1; + const char *set2; + int subset; +} subset_tests[] = { + { "{ [112, 0] }", + "{ [i0, i1] : exists (e0 = [(i0 - i1)/16], e1: " + "16e0 <= i0 - i1 and 16e0 >= -15 + i0 - i1 and " + "16e1 <= i1 and 16e0 >= -i1 and 16e1 >= -i0 + i1) }", 1 }, + { "{ [65] }", + "{ [i] : exists (e0 = [(255i)/256], e1 = [(127i + 65e0)/191], " + "e2 = [(3i + 61e1)/65], e3 = [(52i + 12e2)/61], " + "e4 = [(2i + e3)/3], e5 = [(4i + e3)/4], e6 = [(8i + e3)/12]: " + "3e4 = 2i + e3 and 4e5 = 4i + e3 and 12e6 = 8i + e3 and " + "i <= 255 and 64e3 >= -45 + 67i and i >= 0 and " + "256e0 <= 255i and 256e0 >= -255 + 255i and " + "191e1 <= 127i + 65e0 and 191e1 >= -190 + 127i + 65e0 and " + "65e2 <= 3i + 61e1 and 65e2 >= -64 + 3i + 61e1 and " + "61e3 <= 52i + 12e2 and 61e3 >= -60 + 52i + 12e2) }", 1 }, + { "{ [i] : 0 <= i <= 10 }", "{ rat: [i] : 0 <= i <= 10 }", 1 }, + { "{ rat: [i] : 0 <= i <= 10 }", "{ [i] : 0 <= i <= 10 }", 0 }, + { "{ rat: [0] }", "{ [i] : 0 <= i <= 10 }", 1 }, + { "{ rat: [(1)/2] }", "{ [i] : 0 <= i <= 10 }", 0 }, + { "{ [t, i] : (exists (e0 = [(2 + t)/4]: 4e0 <= 2 + t and " + "4e0 >= -1 + t and i >= 57 and i <= 62 and " + "4e0 <= 62 + t - i and 4e0 >= -61 + t + i and " + "t >= 0 and t <= 511 and 4e0 <= -57 + t + i and " + "4e0 >= 58 + t - i and i >= 58 + t and i >= 62 - t)) }", + "{ [i0, i1] : (exists (e0 = [(4 + i0)/4]: 4e0 <= 62 + i0 - i1 and " + "4e0 >= 1 + i0 and i0 >= 0 and i0 <= 511 and " + "4e0 <= -57 + i0 + i1)) or " + "(exists (e0 = [(2 + i0)/4]: 4e0 <= i0 and " + "4e0 >= 58 + i0 - i1 and i0 >= 2 and i0 <= 511 and " + "4e0 >= -61 + i0 + i1)) or " + "(i1 <= 66 - i0 and i0 >= 2 and i1 >= 59 + i0) }", 1 }, + { "[a, b] -> { : a = 0 and b = -1 }", "[b, a] -> { : b >= -10 }", 1 }, +}; + +static int test_subset(isl_ctx *ctx) +{ + int i; + isl_set *set1, *set2; + int subset; + + for (i = 0; i < ARRAY_SIZE(subset_tests); ++i) { + set1 = isl_set_read_from_str(ctx, subset_tests[i].set1); + set2 = isl_set_read_from_str(ctx, subset_tests[i].set2); + subset = isl_set_is_subset(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + if (subset < 0) + return -1; + if (subset != subset_tests[i].subset) + isl_die(ctx, isl_error_unknown, + "incorrect subset result", return -1); + } + + return 0; +} + +struct { + const char *minuend; + const char *subtrahend; + const char *difference; +} subtract_domain_tests[] = { + { "{ A[i] -> B[i] }", "{ A[i] }", "{ }" }, + { "{ A[i] -> B[i] }", "{ B[i] }", "{ A[i] -> B[i] }" }, + { "{ A[i] -> B[i] }", "{ A[i] : i > 0 }", "{ A[i] -> B[i] : i <= 0 }" }, +}; + +static int test_subtract(isl_ctx *ctx) +{ + int i; + isl_union_map *umap1, *umap2; + isl_union_pw_multi_aff *upma1, *upma2; + isl_union_set *uset; + int equal; + + for (i = 0; i < ARRAY_SIZE(subtract_domain_tests); ++i) { + umap1 = isl_union_map_read_from_str(ctx, + subtract_domain_tests[i].minuend); + uset = isl_union_set_read_from_str(ctx, + subtract_domain_tests[i].subtrahend); + umap2 = isl_union_map_read_from_str(ctx, + subtract_domain_tests[i].difference); + umap1 = isl_union_map_subtract_domain(umap1, uset); + equal = isl_union_map_is_equal(umap1, umap2); + isl_union_map_free(umap1); + isl_union_map_free(umap2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "incorrect subtract domain result", return -1); + } + + for (i = 0; i < ARRAY_SIZE(subtract_domain_tests); ++i) { + upma1 = isl_union_pw_multi_aff_read_from_str(ctx, + subtract_domain_tests[i].minuend); + uset = isl_union_set_read_from_str(ctx, + subtract_domain_tests[i].subtrahend); + upma2 = isl_union_pw_multi_aff_read_from_str(ctx, + subtract_domain_tests[i].difference); + upma1 = isl_union_pw_multi_aff_subtract_domain(upma1, uset); + equal = isl_union_pw_multi_aff_plain_is_equal(upma1, upma2); + isl_union_pw_multi_aff_free(upma1); + isl_union_pw_multi_aff_free(upma2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "incorrect subtract domain result", return -1); + } + + return 0; +} + +/* Check that intersecting the empty basic set with another basic set + * does not increase the number of constraints. In particular, + * the empty basic set should maintain its canonical representation. + */ +static int test_intersect(isl_ctx *ctx) +{ + int n1, n2; + isl_basic_set *bset1, *bset2; + + bset1 = isl_basic_set_read_from_str(ctx, "{ [a,b,c] : 1 = 0 }"); + bset2 = isl_basic_set_read_from_str(ctx, "{ [1,2,3] }"); + n1 = isl_basic_set_n_constraint(bset1); + bset1 = isl_basic_set_intersect(bset1, bset2); + n2 = isl_basic_set_n_constraint(bset1); + isl_basic_set_free(bset1); + if (!bset1) + return -1; + if (n1 != n2) + isl_die(ctx, isl_error_unknown, + "number of constraints of empty set changed", + return -1); + + return 0; +} + +int test_factorize(isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset; + isl_factorizer *f; + + str = "{ [i0, i1, i2, i3, i4, i5, i6, i7] : 3i5 <= 2 - 2i0 and " + "i0 >= -2 and i6 >= 1 + i3 and i7 >= 0 and 3i5 >= -2i0 and " + "2i4 <= i2 and i6 >= 1 + 2i0 + 3i1 and i4 <= -1 and " + "i6 >= 1 + 2i0 + 3i5 and i6 <= 2 + 2i0 + 3i5 and " + "3i5 <= 2 - 2i0 - i2 + 3i4 and i6 <= 2 + 2i0 + 3i1 and " + "i0 <= -1 and i7 <= i2 + i3 - 3i4 - i6 and " + "3i5 >= -2i0 - i2 + 3i4 }"; + bset = isl_basic_set_read_from_str(ctx, str); + f = isl_basic_set_factorizer(bset); + isl_basic_set_free(bset); + isl_factorizer_free(f); + if (!f) + isl_die(ctx, isl_error_unknown, + "failed to construct factorizer", return -1); + + str = "{ [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12] : " + "i12 <= 2 + i0 - i11 and 2i8 >= -i4 and i11 >= i1 and " + "3i5 <= -i2 and 2i11 >= -i4 - 2i7 and i11 <= 3 + i0 + 3i9 and " + "i11 <= -i4 - 2i7 and i12 >= -i10 and i2 >= -2 and " + "i11 >= i1 + 3i10 and i11 >= 1 + i0 + 3i9 and " + "i11 <= 1 - i4 - 2i8 and 6i6 <= 6 - i2 and 3i6 >= 1 - i2 and " + "i11 <= 2 + i1 and i12 <= i4 + i11 and i12 >= i0 - i11 and " + "3i5 >= -2 - i2 and i12 >= -1 + i4 + i11 and 3i3 <= 3 - i2 and " + "9i6 <= 11 - i2 + 6i5 and 3i3 >= 1 - i2 and " + "9i6 <= 5 - i2 + 6i3 and i12 <= -1 and i2 <= 0 }"; + bset = isl_basic_set_read_from_str(ctx, str); + f = isl_basic_set_factorizer(bset); + isl_basic_set_free(bset); + isl_factorizer_free(f); + if (!f) + isl_die(ctx, isl_error_unknown, + "failed to construct factorizer", return -1); + + return 0; +} + +static isl_stat 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 isl_stat_error; + + return isl_stat_ok; +} + +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, *coincidence; + 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_constraints *sc; + 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_space(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); + coincidence = isl_union_map_copy(dep); + proximity = isl_union_map_copy(dep); + + sc = isl_schedule_constraints_on_domain(isl_union_set_copy(D)); + sc = isl_schedule_constraints_set_validity(sc, validity); + sc = isl_schedule_constraints_set_coincidence(sc, coincidence); + sc = isl_schedule_constraints_set_proximity(sc, proximity); + sched = isl_schedule_constraints_compute_schedule(sc); + 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; + isl_union_set_free(delta); + } else { + delta_set = isl_set_from_union_set(delta); + + slice = isl_set_universe(isl_set_get_space(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_space(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_space(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); + } + + 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; +} + +/* Compute a schedule for the given instance set, validity constraints, + * proximity constraints and context and return a corresponding union map + * representation. + */ +static __isl_give isl_union_map *compute_schedule_with_context(isl_ctx *ctx, + const char *domain, const char *validity, const char *proximity, + const char *context) +{ + isl_set *con; + isl_union_set *dom; + isl_union_map *dep; + isl_union_map *prox; + isl_schedule_constraints *sc; + isl_schedule *schedule; + isl_union_map *sched; + + con = isl_set_read_from_str(ctx, context); + dom = isl_union_set_read_from_str(ctx, domain); + dep = isl_union_map_read_from_str(ctx, validity); + prox = isl_union_map_read_from_str(ctx, proximity); + sc = isl_schedule_constraints_on_domain(dom); + sc = isl_schedule_constraints_set_context(sc, con); + sc = isl_schedule_constraints_set_validity(sc, dep); + sc = isl_schedule_constraints_set_proximity(sc, prox); + schedule = isl_schedule_constraints_compute_schedule(sc); + sched = isl_schedule_get_map(schedule); + isl_schedule_free(schedule); + + return sched; +} + +/* Compute a schedule for the given instance set, validity constraints and + * proximity constraints and return a corresponding union map representation. + */ +static __isl_give isl_union_map *compute_schedule(isl_ctx *ctx, + const char *domain, const char *validity, const char *proximity) +{ + return compute_schedule_with_context(ctx, domain, validity, proximity, + "{ : }"); +} + +/* Check that a schedule can be constructed on the given domain + * with the given validity and proximity constraints. + */ +static int test_has_schedule(isl_ctx *ctx, const char *domain, + const char *validity, const char *proximity) +{ + isl_union_map *sched; + + sched = compute_schedule(ctx, domain, validity, proximity); + if (!sched) + return -1; + + isl_union_map_free(sched); + return 0; +} + +int test_special_schedule(isl_ctx *ctx, const char *domain, + const char *validity, const char *proximity, const char *expected_sched) +{ + isl_union_map *sched1, *sched2; + int equal; + + sched1 = compute_schedule(ctx, domain, validity, proximity); + sched2 = isl_union_map_read_from_str(ctx, expected_sched); + + 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; +} + +/* Check that the schedule map is properly padded, i.e., that the range + * lives in a single space. + */ +static int test_padded_schedule(isl_ctx *ctx) +{ + const char *str; + isl_union_set *D; + isl_union_map *validity, *proximity; + isl_schedule_constraints *sc; + isl_schedule *sched; + isl_union_map *umap; + isl_union_set *range; + isl_set *set; + + str = "[N] -> { S0[i] : 0 <= i <= N; S1[i, j] : 0 <= i, j <= N }"; + D = isl_union_set_read_from_str(ctx, str); + validity = isl_union_map_empty(isl_union_set_get_space(D)); + proximity = isl_union_map_copy(validity); + sc = isl_schedule_constraints_on_domain(D); + sc = isl_schedule_constraints_set_validity(sc, validity); + sc = isl_schedule_constraints_set_proximity(sc, proximity); + sched = isl_schedule_constraints_compute_schedule(sc); + umap = isl_schedule_get_map(sched); + isl_schedule_free(sched); + range = isl_union_map_range(umap); + set = isl_set_from_union_set(range); + isl_set_free(set); + + if (!set) + return -1; + + return 0; +} + +/* Check that conditional validity constraints are also taken into + * account across bands. + * In particular, try to make sure that live ranges D[1,0]->C[2,1] and + * D[2,0]->C[3,0] are not local in the outer band of the generated schedule + * and then check that the adjacent order constraint C[2,1]->D[2,0] + * is enforced by the rest of the schedule. + */ +static int test_special_conditional_schedule_constraints(isl_ctx *ctx) +{ + const char *str; + isl_union_set *domain; + isl_union_map *validity, *proximity, *condition; + isl_union_map *sink, *source, *dep; + isl_schedule_constraints *sc; + isl_schedule *schedule; + isl_union_access_info *access; + isl_union_flow *flow; + int empty; + + str = "[n] -> { C[k, i] : k <= -1 + n and i >= 0 and i <= -1 + k; " + "A[k] : k >= 1 and k <= -1 + n; " + "B[k, i] : k <= -1 + n and i >= 0 and i <= -1 + k; " + "D[k, i] : k <= -1 + n and i >= 0 and i <= -1 + k }"; + domain = isl_union_set_read_from_str(ctx, str); + sc = isl_schedule_constraints_on_domain(domain); + str = "[n] -> { D[k, i] -> C[1 + k, k - i] : " + "k <= -2 + n and i >= 1 and i <= -1 + k; " + "D[k, i] -> C[1 + k, i] : " + "k <= -2 + n and i >= 1 and i <= -1 + k; " + "D[k, 0] -> C[1 + k, k] : k >= 1 and k <= -2 + n; " + "D[k, 0] -> C[1 + k, 0] : k >= 1 and k <= -2 + n }"; + validity = isl_union_map_read_from_str(ctx, str); + sc = isl_schedule_constraints_set_validity(sc, validity); + str = "[n] -> { C[k, i] -> D[k, i] : " + "0 <= i <= -1 + k and k <= -1 + n }"; + proximity = isl_union_map_read_from_str(ctx, str); + sc = isl_schedule_constraints_set_proximity(sc, proximity); + str = "[n] -> { [D[k, i] -> a[]] -> [C[1 + k, k - i] -> b[]] : " + "i <= -1 + k and i >= 1 and k <= -2 + n; " + "[B[k, i] -> c[]] -> [B[k, 1 + i] -> c[]] : " + "k <= -1 + n and i >= 0 and i <= -2 + k }"; + condition = isl_union_map_read_from_str(ctx, str); + str = "[n] -> { [B[k, i] -> e[]] -> [D[k, i] -> a[]] : " + "i >= 0 and i <= -1 + k and k <= -1 + n; " + "[C[k, i] -> b[]] -> [D[k', -1 + k - i] -> a[]] : " + "i >= 0 and i <= -1 + k and k <= -1 + n and " + "k' <= -1 + n and k' >= k - i and k' >= 1 + k; " + "[C[k, i] -> b[]] -> [D[k, -1 + k - i] -> a[]] : " + "i >= 0 and i <= -1 + k and k <= -1 + n; " + "[B[k, i] -> c[]] -> [A[k'] -> d[]] : " + "k <= -1 + n and i >= 0 and i <= -1 + k and " + "k' >= 1 and k' <= -1 + n and k' >= 1 + k }"; + validity = isl_union_map_read_from_str(ctx, str); + sc = isl_schedule_constraints_set_conditional_validity(sc, condition, + validity); + schedule = isl_schedule_constraints_compute_schedule(sc); + str = "{ D[2,0] -> [] }"; + sink = isl_union_map_read_from_str(ctx, str); + access = isl_union_access_info_from_sink(sink); + str = "{ C[2,1] -> [] }"; + source = isl_union_map_read_from_str(ctx, str); + access = isl_union_access_info_set_must_source(access, source); + access = isl_union_access_info_set_schedule(access, schedule); + flow = isl_union_access_info_compute_flow(access); + dep = isl_union_flow_get_must_dependence(flow); + isl_union_flow_free(flow); + empty = isl_union_map_is_empty(dep); + isl_union_map_free(dep); + + if (empty < 0) + return -1; + if (empty) + isl_die(ctx, isl_error_unknown, + "conditional validity not respected", return -1); + + return 0; +} + +/* Check that the test for violated conditional validity constraints + * is not confused by domain compression. + * In particular, earlier versions of isl would apply + * a schedule on the compressed domains to the original domains, + * resulting in a failure to detect that the default schedule + * violates the conditional validity constraints. + */ +static int test_special_conditional_schedule_constraints_2(isl_ctx *ctx) +{ + const char *str; + isl_bool empty; + isl_union_set *domain; + isl_union_map *validity, *condition; + isl_schedule_constraints *sc; + isl_schedule *schedule; + isl_union_map *umap; + isl_map *map, *ge; + + str = "{ A[0, i] : 0 <= i <= 10; B[1, i] : 0 <= i <= 10 }"; + domain = isl_union_set_read_from_str(ctx, str); + sc = isl_schedule_constraints_on_domain(domain); + str = "{ B[1, i] -> A[0, i + 1] }"; + condition = isl_union_map_read_from_str(ctx, str); + str = "{ A[0, i] -> B[1, i - 1] }"; + validity = isl_union_map_read_from_str(ctx, str); + sc = isl_schedule_constraints_set_conditional_validity(sc, condition, + isl_union_map_copy(validity)); + schedule = isl_schedule_constraints_compute_schedule(sc); + umap = isl_schedule_get_map(schedule); + isl_schedule_free(schedule); + validity = isl_union_map_apply_domain(validity, + isl_union_map_copy(umap)); + validity = isl_union_map_apply_range(validity, umap); + map = isl_map_from_union_map(validity); + ge = isl_map_lex_ge(isl_space_domain(isl_map_get_space(map))); + map = isl_map_intersect(map, ge); + empty = isl_map_is_empty(map); + isl_map_free(map); + + if (empty < 0) + return -1; + if (!empty) + isl_die(ctx, isl_error_unknown, + "conditional validity constraints not satisfied", + return -1); + + return 0; +} + +/* Input for testing of schedule construction based on + * conditional constraints. + * + * domain is the iteration domain + * flow are the flow dependences, which determine the validity and + * proximity constraints + * condition are the conditions on the conditional validity constraints + * conditional_validity are the conditional validity constraints + * outer_band_n is the expected number of members in the outer band + */ +struct { + const char *domain; + const char *flow; + const char *condition; + const char *conditional_validity; + int outer_band_n; +} live_range_tests[] = { + /* Contrived example that illustrates that we need to keep + * track of tagged condition dependences and + * tagged conditional validity dependences + * in isl_sched_edge separately. + * In particular, the conditional validity constraints on A + * cannot be satisfied, + * but they can be ignored because there are no corresponding + * condition constraints. However, we do have an additional + * conditional validity constraint that maps to the same + * dependence relation + * as the condition constraint on B. If we did not make a distinction + * between tagged condition and tagged conditional validity + * dependences, then we + * could end up treating this shared dependence as an condition + * constraint on A, forcing a localization of the conditions, + * which is impossible. + */ + { "{ S[i] : 0 <= 1 < 100; T[i] : 0 <= 1 < 100 }", + "{ S[i] -> S[i+1] : 0 <= i < 99 }", + "{ [S[i] -> B[]] -> [S[i+1] -> B[]] : 0 <= i < 99 }", + "{ [S[i] -> A[]] -> [T[i'] -> A[]] : 0 <= i', i < 100 and i != i';" + "[T[i] -> A[]] -> [S[i'] -> A[]] : 0 <= i', i < 100 and i != i';" + "[S[i] -> A[]] -> [S[i+1] -> A[]] : 0 <= i < 99 }", + 1 + }, + /* TACO 2013 Fig. 7 */ + { "[n] -> { S1[i,j] : 0 <= i,j < n; S2[i,j] : 0 <= i,j < n }", + "[n] -> { S1[i,j] -> S2[i,j] : 0 <= i,j < n;" + "S2[i,j] -> S2[i,j+1] : 0 <= i < n and 0 <= j < n - 1 }", + "[n] -> { [S1[i,j] -> t[]] -> [S2[i,j] -> t[]] : 0 <= i,j < n;" + "[S2[i,j] -> x1[]] -> [S2[i,j+1] -> x1[]] : " + "0 <= i < n and 0 <= j < n - 1 }", + "[n] -> { [S2[i,j] -> t[]] -> [S1[i,j'] -> t[]] : " + "0 <= i < n and 0 <= j < j' < n;" + "[S2[i,j] -> t[]] -> [S1[i',j'] -> t[]] : " + "0 <= i < i' < n and 0 <= j,j' < n;" + "[S2[i,j] -> x1[]] -> [S2[i,j'] -> x1[]] : " + "0 <= i,j,j' < n and j < j' }", + 2 + }, + /* TACO 2013 Fig. 7, without tags */ + { "[n] -> { S1[i,j] : 0 <= i,j < n; S2[i,j] : 0 <= i,j < n }", + "[n] -> { S1[i,j] -> S2[i,j] : 0 <= i,j < n;" + "S2[i,j] -> S2[i,j+1] : 0 <= i < n and 0 <= j < n - 1 }", + "[n] -> { S1[i,j] -> S2[i,j] : 0 <= i,j < n;" + "S2[i,j] -> S2[i,j+1] : 0 <= i < n and 0 <= j < n - 1 }", + "[n] -> { S2[i,j] -> S1[i,j'] : 0 <= i < n and 0 <= j < j' < n;" + "S2[i,j] -> S1[i',j'] : 0 <= i < i' < n and 0 <= j,j' < n;" + "S2[i,j] -> S2[i,j'] : 0 <= i,j,j' < n and j < j' }", + 1 + }, + /* TACO 2013 Fig. 12 */ + { "{ S1[i,0] : 0 <= i <= 1; S2[i,j] : 0 <= i <= 1 and 1 <= j <= 2;" + "S3[i,3] : 0 <= i <= 1 }", + "{ S1[i,0] -> S2[i,1] : 0 <= i <= 1;" + "S2[i,1] -> S2[i,2] : 0 <= i <= 1;" + "S2[i,2] -> S3[i,3] : 0 <= i <= 1 }", + "{ [S1[i,0]->t[]] -> [S2[i,1]->t[]] : 0 <= i <= 1;" + "[S2[i,1]->t[]] -> [S2[i,2]->t[]] : 0 <= i <= 1;" + "[S2[i,2]->t[]] -> [S3[i,3]->t[]] : 0 <= i <= 1 }", + "{ [S2[i,1]->t[]] -> [S2[i,2]->t[]] : 0 <= i <= 1;" + "[S2[0,j]->t[]] -> [S2[1,j']->t[]] : 1 <= j,j' <= 2;" + "[S2[0,j]->t[]] -> [S1[1,0]->t[]] : 1 <= j <= 2;" + "[S3[0,3]->t[]] -> [S2[1,j]->t[]] : 1 <= j <= 2;" + "[S3[0,3]->t[]] -> [S1[1,0]->t[]] }", + 1 + } +}; + +/* Test schedule construction based on conditional constraints. + * In particular, check the number of members in the outer band node + * as an indication of whether tiling is possible or not. + */ +static int test_conditional_schedule_constraints(isl_ctx *ctx) +{ + int i; + isl_union_set *domain; + isl_union_map *condition; + isl_union_map *flow; + isl_union_map *validity; + isl_schedule_constraints *sc; + isl_schedule *schedule; + isl_schedule_node *node; + int n_member; + + if (test_special_conditional_schedule_constraints(ctx) < 0) + return -1; + if (test_special_conditional_schedule_constraints_2(ctx) < 0) + return -1; + + for (i = 0; i < ARRAY_SIZE(live_range_tests); ++i) { + domain = isl_union_set_read_from_str(ctx, + live_range_tests[i].domain); + flow = isl_union_map_read_from_str(ctx, + live_range_tests[i].flow); + condition = isl_union_map_read_from_str(ctx, + live_range_tests[i].condition); + validity = isl_union_map_read_from_str(ctx, + live_range_tests[i].conditional_validity); + sc = isl_schedule_constraints_on_domain(domain); + sc = isl_schedule_constraints_set_validity(sc, + isl_union_map_copy(flow)); + sc = isl_schedule_constraints_set_proximity(sc, flow); + sc = isl_schedule_constraints_set_conditional_validity(sc, + condition, validity); + schedule = isl_schedule_constraints_compute_schedule(sc); + node = isl_schedule_get_root(schedule); + while (node && + isl_schedule_node_get_type(node) != isl_schedule_node_band) + node = isl_schedule_node_first_child(node); + n_member = isl_schedule_node_band_n_member(node); + isl_schedule_node_free(node); + isl_schedule_free(schedule); + + if (!schedule) + return -1; + if (n_member != live_range_tests[i].outer_band_n) + isl_die(ctx, isl_error_unknown, + "unexpected number of members in outer band", + return -1); + } + return 0; +} + +/* Check that the schedule computed for the given instance set and + * dependence relation strongly satisfies the dependences. + * In particular, check that no instance is scheduled before + * or together with an instance on which it depends. + * Earlier versions of isl would produce a schedule that + * only weakly satisfies the dependences. + */ +static int test_strongly_satisfying_schedule(isl_ctx *ctx) +{ + const char *domain, *dep; + isl_union_map *D, *schedule; + isl_map *map, *ge; + int empty; + + domain = "{ B[i0, i1] : 0 <= i0 <= 1 and 0 <= i1 <= 11; " + "A[i0] : 0 <= i0 <= 1 }"; + dep = "{ B[i0, i1] -> B[i0, 1 + i1] : 0 <= i0 <= 1 and 0 <= i1 <= 10; " + "B[0, 11] -> A[1]; A[i0] -> B[i0, 0] : 0 <= i0 <= 1 }"; + schedule = compute_schedule(ctx, domain, dep, dep); + D = isl_union_map_read_from_str(ctx, dep); + D = isl_union_map_apply_domain(D, isl_union_map_copy(schedule)); + D = isl_union_map_apply_range(D, schedule); + map = isl_map_from_union_map(D); + ge = isl_map_lex_ge(isl_space_domain(isl_map_get_space(map))); + map = isl_map_intersect(map, ge); + empty = isl_map_is_empty(map); + isl_map_free(map); + + if (empty < 0) + return -1; + if (!empty) + isl_die(ctx, isl_error_unknown, + "dependences not strongly satisfied", return -1); + + return 0; +} + +/* Compute a schedule for input where the instance set constraints + * conflict with the context constraints. + * Earlier versions of isl did not properly handle this situation. + */ +static int test_conflicting_context_schedule(isl_ctx *ctx) +{ + isl_union_map *schedule; + const char *domain, *context; + + domain = "[n] -> { A[] : n >= 0 }"; + context = "[n] -> { : n < 0 }"; + schedule = compute_schedule_with_context(ctx, + domain, "{}", "{}", context); + isl_union_map_free(schedule); + + if (!schedule) + return -1; + + return 0; +} + +/* Check that the dependence carrying step is not confused by + * a bound on the coefficient size. + * In particular, force the scheduler to move to a dependence carrying + * step by demanding outer coincidence and bound the size of + * the coefficients. Earlier versions of isl would take this + * bound into account while carrying dependences, breaking + * fundamental assumptions. + * On the other hand, the dependence carrying step now tries + * to prevent loop coalescing by default, so check that indeed + * no loop coalescing occurs by comparing the computed schedule + * to the expected non-coalescing schedule. + */ +static int test_bounded_coefficients_schedule(isl_ctx *ctx) +{ + const char *domain, *dep; + isl_union_set *I; + isl_union_map *D; + isl_schedule_constraints *sc; + isl_schedule *schedule; + isl_union_map *sched1, *sched2; + isl_bool equal; + + domain = "{ C[i0, i1] : 2 <= i0 <= 3999 and 0 <= i1 <= -1 + i0 }"; + dep = "{ C[i0, i1] -> C[i0, 1 + i1] : i0 <= 3999 and i1 >= 0 and " + "i1 <= -2 + i0; " + "C[i0, -1 + i0] -> C[1 + i0, 0] : i0 <= 3998 and i0 >= 1 }"; + I = isl_union_set_read_from_str(ctx, domain); + D = isl_union_map_read_from_str(ctx, dep); + sc = isl_schedule_constraints_on_domain(I); + sc = isl_schedule_constraints_set_validity(sc, isl_union_map_copy(D)); + sc = isl_schedule_constraints_set_coincidence(sc, D); + isl_options_set_schedule_outer_coincidence(ctx, 1); + isl_options_set_schedule_max_coefficient(ctx, 20); + schedule = isl_schedule_constraints_compute_schedule(sc); + isl_options_set_schedule_max_coefficient(ctx, -1); + isl_options_set_schedule_outer_coincidence(ctx, 0); + sched1 = isl_schedule_get_map(schedule); + isl_schedule_free(schedule); + + sched2 = isl_union_map_read_from_str(ctx, "{ C[x,y] -> [x,y] }"); + 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; +} + +/* Check that the bounds on the coefficients are respected. + * This function checks for a particular output schedule, + * but the exact output is not important, only that it does + * not contain any coefficients greater than 4. + * It is, however, easier to check for a particular output. + * This test is only run for the whole component scheduler + * because the incremental scheduler produces a slightly different schedule. + */ +static int test_bounded_coefficients_schedule_whole(isl_ctx *ctx) +{ + const char *domain, *dep, *str; + isl_union_set *I; + isl_union_map *D; + isl_schedule_constraints *sc; + isl_schedule *schedule; + isl_union_map *sched1, *sched2; + isl_bool equal; + + domain = "{ S_4[i, j, k] : 0 <= i < j <= 10 and 0 <= k <= 100; " + "S_2[i, j] : 0 <= i < j <= 10; S_6[i, j] : 0 <= i < j <= 10 }"; + dep = "{ S_2[0, j] -> S_4[0, j, 0] : 0 < j <= 10; " + "S_4[0, j, 100] -> S_6[0, j] : 0 < j <= 10 }"; + I = isl_union_set_read_from_str(ctx, domain); + D = isl_union_map_read_from_str(ctx, dep); + sc = isl_schedule_constraints_on_domain(I); + sc = isl_schedule_constraints_set_validity(sc, D); + isl_options_set_schedule_max_constant_term(ctx, 10); + isl_options_set_schedule_max_coefficient(ctx, 4); + schedule = isl_schedule_constraints_compute_schedule(sc); + isl_options_set_schedule_max_coefficient(ctx, -1); + isl_options_set_schedule_max_constant_term(ctx, -1); + sched1 = isl_schedule_get_map(schedule); + isl_schedule_free(schedule); + + str = "{ S_4[i, j, k] -> [i, j, 10 - k]; " + "S_2[i, j] -> [0, i, j]; S_6[i, j] -> [0, 10 + i, j] }"; + 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; +} + +/* Check that a set of schedule constraints that only allow for + * a coalescing schedule still produces a schedule even if the user + * request a non-coalescing schedule. Earlier versions of isl + * would not handle this case correctly. + */ +static int test_coalescing_schedule(isl_ctx *ctx) +{ + const char *domain, *dep; + isl_union_set *I; + isl_union_map *D; + isl_schedule_constraints *sc; + isl_schedule *schedule; + int treat_coalescing; + + domain = "{ S[a, b] : 0 <= a <= 1 and 0 <= b <= 1 }"; + dep = "{ S[a, b] -> S[a + b, 1 - b] }"; + I = isl_union_set_read_from_str(ctx, domain); + D = isl_union_map_read_from_str(ctx, dep); + sc = isl_schedule_constraints_on_domain(I); + sc = isl_schedule_constraints_set_validity(sc, D); + treat_coalescing = isl_options_get_schedule_treat_coalescing(ctx); + isl_options_set_schedule_treat_coalescing(ctx, 1); + schedule = isl_schedule_constraints_compute_schedule(sc); + isl_options_set_schedule_treat_coalescing(ctx, treat_coalescing); + isl_schedule_free(schedule); + if (!schedule) + return -1; + return 0; +} + +/* Check that the scheduler does not perform any needless + * compound skewing. Earlier versions of isl would compute + * schedules in terms of transformed schedule coefficients and + * would not accurately keep track of the sum of the original + * schedule coefficients. It could then produce the schedule + * S[t,i,j,k] -> [t, 2t + i, 2t + i + j, 2t + i + j + k] + * for the input below instead of the schedule below. + */ +static int test_skewing_schedule(isl_ctx *ctx) +{ + const char *D, *V, *P, *S; + + D = "[n] -> { S[t,i,j,k] : 0 <= t,i,j,k < n }"; + V = "[n] -> { S[t,i,j,k] -> S[t+1,a,b,c] : 0 <= t,i,j,k,a,b,c < n and " + "-2 <= a-i <= 2 and -1 <= a-i + b-j <= 1 and " + "-1 <= a-i + b-j + c-k <= 1 }"; + P = "{ }"; + S = "{ S[t,i,j,k] -> [t, 2t + i, t + i + j, 2t + k] }"; + + return test_special_schedule(ctx, D, V, P, S); +} + +int test_schedule(isl_ctx *ctx) +{ + const char *D, *W, *R, *V, *P, *S; + int max_coincidence; + int treat_coalescing; + + /* Handle resulting schedule with zero bands. */ + if (test_one_schedule(ctx, "{[]}", "{}", "{}", "{[] -> []}", 0, 0) < 0) + return -1; + + /* 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] }"; + max_coincidence = isl_options_get_schedule_maximize_coincidence(ctx); + isl_options_set_schedule_maximize_coincidence(ctx, 0); + if (test_one_schedule(ctx, D, W, R, S, 2, 0) < 0) + return -1; + isl_options_set_schedule_maximize_coincidence(ctx, max_coincidence); + + 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; + + D = "[n] -> { S_0[j, k] : j <= -1 + n and j >= 0 and " + "k <= -1 + n and k >= 0 }"; + W = "[n] -> { S_0[j, k] -> B[j] : j <= -1 + n and j >= 0 and " "k <= -1 + n and k >= 0 }"; + R = "[n] -> { S_0[j, k] -> B[j] : j <= -1 + n and j >= 0 and " + "k <= -1 + n and k >= 0; " + "S_0[j, k] -> B[k] : j <= -1 + n and j >= 0 and " + "k <= -1 + n and k >= 0; " + "S_0[j, k] -> A[k] : j <= -1 + n and j >= 0 and " + "k <= -1 + n and k >= 0 }"; + S = "[n] -> { S_0[j, k] -> [2, j, k] }"; + ctx->opt->schedule_outer_coincidence = 1; + if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0) + return -1; + ctx->opt->schedule_outer_coincidence = 0; + + D = "{Stmt_for_body24[i0, i1, i2, i3]:" + "i0 >= 0 and i0 <= 1 and i1 >= 0 and i1 <= 6 and i2 >= 2 and " + "i2 <= 6 - i1 and i3 >= 0 and i3 <= -1 + i2;" + "Stmt_for_body24[i0, i1, 1, 0]:" + "i0 >= 0 and i0 <= 1 and i1 >= 0 and i1 <= 5;" + "Stmt_for_body7[i0, i1, i2]:" + "i0 >= 0 and i0 <= 1 and i1 >= 0 and i1 <= 7 and i2 >= 0 and " + "i2 <= 7 }"; + + V = "{Stmt_for_body24[0, i1, i2, i3] -> " + "Stmt_for_body24[1, i1, i2, i3]:" + "i3 >= 0 and i3 <= -1 + i2 and i1 >= 0 and i2 <= 6 - i1 and " + "i2 >= 1;" + "Stmt_for_body24[0, i1, i2, i3] -> " + "Stmt_for_body7[1, 1 + i1 + i3, 1 + i1 + i2]:" + "i3 <= -1 + i2 and i2 <= 6 - i1 and i2 >= 1 and i1 >= 0 and " + "i3 >= 0;" + "Stmt_for_body24[0, i1, i2, i3] ->" + "Stmt_for_body7[1, i1, 1 + i1 + i3]:" + "i3 >= 0 and i2 <= 6 - i1 and i1 >= 0 and i3 <= -1 + i2;" + "Stmt_for_body7[0, i1, i2] -> Stmt_for_body7[1, i1, i2]:" + "(i2 >= 1 + i1 and i2 <= 6 and i1 >= 0 and i1 <= 4) or " + "(i2 >= 3 and i2 <= 7 and i1 >= 1 and i2 >= 1 + i1) or " + "(i2 >= 0 and i2 <= i1 and i2 >= -7 + i1 and i1 <= 7);" + "Stmt_for_body7[0, i1, 1 + i1] -> Stmt_for_body7[1, i1, 1 + i1]:" + "i1 <= 6 and i1 >= 0;" + "Stmt_for_body7[0, 0, 7] -> Stmt_for_body7[1, 0, 7];" + "Stmt_for_body7[i0, i1, i2] -> " + "Stmt_for_body24[i0, o1, -1 + i2 - o1, -1 + i1 - o1]:" + "i0 >= 0 and i0 <= 1 and o1 >= 0 and i2 >= 1 + i1 and " + "o1 <= -2 + i2 and i2 <= 7 and o1 <= -1 + i1;" + "Stmt_for_body7[i0, i1, i2] -> " + "Stmt_for_body24[i0, i1, o2, -1 - i1 + i2]:" + "i0 >= 0 and i0 <= 1 and i1 >= 0 and o2 >= -i1 + i2 and " + "o2 >= 1 and o2 <= 6 - i1 and i2 >= 1 + i1 }"; + P = V; + + treat_coalescing = isl_options_get_schedule_treat_coalescing(ctx); + isl_options_set_schedule_treat_coalescing(ctx, 0); + if (test_has_schedule(ctx, D, V, P) < 0) + return -1; + isl_options_set_schedule_treat_coalescing(ctx, treat_coalescing); + + D = "{ S_0[i, j] : i >= 1 and i <= 10 and j >= 1 and j <= 8 }"; + V = "{ S_0[i, j] -> S_0[i, 1 + j] : i >= 1 and i <= 10 and " + "j >= 1 and j <= 7;" + "S_0[i, j] -> S_0[1 + i, j] : i >= 1 and i <= 9 and " + "j >= 1 and j <= 8 }"; + P = "{ }"; + S = "{ S_0[i, j] -> [i + j, i] }"; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER; + if (test_special_schedule(ctx, D, V, P, S) < 0) + return -1; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL; + + /* Fig. 1 from Feautrier's "Some Efficient Solutions..." pt. 2, 1992 */ + D = "[N] -> { S_0[i, j] : i >= 0 and i <= -1 + N and " + "j >= 0 and j <= -1 + i }"; + V = "[N] -> { S_0[i, j] -> S_0[i, 1 + j] : j <= -2 + i and " + "i <= -1 + N and j >= 0;" + "S_0[i, -1 + i] -> S_0[1 + i, 0] : i >= 1 and " + "i <= -2 + N }"; + P = "{ }"; + S = "{ S_0[i, j] -> [i, j] }"; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER; + if (test_special_schedule(ctx, D, V, P, S) < 0) + return -1; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL; + + /* Test both algorithms on a case with only proximity dependences. */ + D = "{ S[i,j] : 0 <= i <= 10 }"; + V = "{ }"; + P = "{ S[i,j] -> S[i+1,j] : 0 <= i,j <= 10 }"; + S = "{ S[i, j] -> [j, i] }"; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER; + if (test_special_schedule(ctx, D, V, P, S) < 0) + return -1; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL; + if (test_special_schedule(ctx, D, V, P, S) < 0) + return -1; + + D = "{ A[a]; B[] }"; + V = "{}"; + P = "{ A[a] -> B[] }"; + if (test_has_schedule(ctx, D, V, P) < 0) + return -1; + + if (test_padded_schedule(ctx) < 0) + return -1; + + /* Check that check for progress is not confused by rational + * solution. + */ + D = "[N] -> { S0[i, j] : i >= 0 and i <= N and j >= 0 and j <= N }"; + V = "[N] -> { S0[i0, -1 + N] -> S0[2 + i0, 0] : i0 >= 0 and " + "i0 <= -2 + N; " + "S0[i0, i1] -> S0[i0, 1 + i1] : i0 >= 0 and " + "i0 <= N and i1 >= 0 and i1 <= -1 + N }"; + P = "{}"; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER; + if (test_has_schedule(ctx, D, V, P) < 0) + return -1; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL; + + /* Check that we allow schedule rows that are only non-trivial + * on some full-dimensional domains. + */ + D = "{ S1[j] : 0 <= j <= 1; S0[]; S2[k] : 0 <= k <= 1 }"; + V = "{ S0[] -> S1[j] : 0 <= j <= 1; S2[0] -> S0[];" + "S1[j] -> S2[1] : 0 <= j <= 1 }"; + P = "{}"; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER; + if (test_has_schedule(ctx, D, V, P) < 0) + return -1; + ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL; + + if (test_conditional_schedule_constraints(ctx) < 0) + return -1; + + if (test_strongly_satisfying_schedule(ctx) < 0) + return -1; + + if (test_conflicting_context_schedule(ctx) < 0) + return -1; + + if (test_bounded_coefficients_schedule(ctx) < 0) + return -1; + if (test_coalescing_schedule(ctx) < 0) + return -1; + if (test_skewing_schedule(ctx) < 0) + return -1; + + return 0; +} + +/* Perform scheduling tests using the whole component scheduler. + */ +static int test_schedule_whole(isl_ctx *ctx) +{ + int whole; + int r; + + whole = isl_options_get_schedule_whole_component(ctx); + isl_options_set_schedule_whole_component(ctx, 1); + r = test_schedule(ctx); + if (r >= 0) + r = test_bounded_coefficients_schedule_whole(ctx); + isl_options_set_schedule_whole_component(ctx, whole); + + return r; +} + +/* Perform scheduling tests using the incremental scheduler. + */ +static int test_schedule_incremental(isl_ctx *ctx) +{ + int whole; + int r; + + whole = isl_options_get_schedule_whole_component(ctx); + isl_options_set_schedule_whole_component(ctx, 0); + r = test_schedule(ctx); + isl_options_set_schedule_whole_component(ctx, whole); + + return r; +} + +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; +} + +static int aff_plain_is_equal(__isl_keep isl_aff *aff, const char *str) +{ + isl_aff *aff2; + int equal; + + if (!aff) + return -1; + + aff2 = isl_aff_read_from_str(isl_aff_get_ctx(aff), str); + equal = isl_aff_plain_is_equal(aff, aff2); + isl_aff_free(aff2); + + return equal; +} + +static int aff_check_plain_equal(__isl_keep isl_aff *aff, const char *str) +{ + int equal; + + equal = aff_plain_is_equal(aff, str); + if (equal < 0) + return -1; + if (!equal) + isl_die(isl_aff_get_ctx(aff), isl_error_unknown, + "result not as expected", return -1); + return 0; +} + +struct { + __isl_give isl_aff *(*fn)(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); +} aff_bin_op[] = { + ['+'] = { &isl_aff_add }, + ['-'] = { &isl_aff_sub }, + ['*'] = { &isl_aff_mul }, + ['/'] = { &isl_aff_div }, +}; + +struct { + const char *arg1; + unsigned char op; + const char *arg2; + const char *res; +} aff_bin_tests[] = { + { "{ [i] -> [i] }", '+', "{ [i] -> [i] }", + "{ [i] -> [2i] }" }, + { "{ [i] -> [i] }", '-', "{ [i] -> [i] }", + "{ [i] -> [0] }" }, + { "{ [i] -> [i] }", '*', "{ [i] -> [2] }", + "{ [i] -> [2i] }" }, + { "{ [i] -> [2] }", '*', "{ [i] -> [i] }", + "{ [i] -> [2i] }" }, + { "{ [i] -> [i] }", '/', "{ [i] -> [2] }", + "{ [i] -> [i/2] }" }, + { "{ [i] -> [2i] }", '/', "{ [i] -> [2] }", + "{ [i] -> [i] }" }, + { "{ [i] -> [i] }", '+', "{ [i] -> [NaN] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [i] }", '-', "{ [i] -> [NaN] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [i] }", '*', "{ [i] -> [NaN] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [2] }", '*', "{ [i] -> [NaN] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [i] }", '/', "{ [i] -> [NaN] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [2] }", '/', "{ [i] -> [NaN] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [NaN] }", '+', "{ [i] -> [i] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [NaN] }", '-', "{ [i] -> [i] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [NaN] }", '*', "{ [i] -> [2] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [NaN] }", '*', "{ [i] -> [i] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [NaN] }", '/', "{ [i] -> [2] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [NaN] }", '/', "{ [i] -> [i] }", + "{ [i] -> [NaN] }" }, +}; + +/* Perform some basic tests of binary operations on isl_aff objects. + */ +static int test_bin_aff(isl_ctx *ctx) +{ + int i; + isl_aff *aff1, *aff2, *res; + __isl_give isl_aff *(*fn)(__isl_take isl_aff *aff1, + __isl_take isl_aff *aff2); + int ok; + + for (i = 0; i < ARRAY_SIZE(aff_bin_tests); ++i) { + aff1 = isl_aff_read_from_str(ctx, aff_bin_tests[i].arg1); + aff2 = isl_aff_read_from_str(ctx, aff_bin_tests[i].arg2); + res = isl_aff_read_from_str(ctx, aff_bin_tests[i].res); + fn = aff_bin_op[aff_bin_tests[i].op].fn; + aff1 = fn(aff1, aff2); + if (isl_aff_is_nan(res)) + ok = isl_aff_is_nan(aff1); + else + ok = isl_aff_plain_is_equal(aff1, res); + isl_aff_free(aff1); + isl_aff_free(res); + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + return 0; +} + +struct { + __isl_give isl_pw_aff *(*fn)(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); +} pw_aff_bin_op[] = { + ['m'] = { &isl_pw_aff_min }, + ['M'] = { &isl_pw_aff_max }, +}; + +/* Inputs for binary isl_pw_aff operation tests. + * "arg1" and "arg2" are the two arguments, "op" identifies the operation + * defined by pw_aff_bin_op, and "res" is the expected result. + */ +struct { + const char *arg1; + unsigned char op; + const char *arg2; + const char *res; +} pw_aff_bin_tests[] = { + { "{ [i] -> [i] }", 'm', "{ [i] -> [i] }", + "{ [i] -> [i] }" }, + { "{ [i] -> [i] }", 'M', "{ [i] -> [i] }", + "{ [i] -> [i] }" }, + { "{ [i] -> [i] }", 'm', "{ [i] -> [0] }", + "{ [i] -> [i] : i <= 0; [i] -> [0] : i > 0 }" }, + { "{ [i] -> [i] }", 'M', "{ [i] -> [0] }", + "{ [i] -> [i] : i >= 0; [i] -> [0] : i < 0 }" }, + { "{ [i] -> [i] }", 'm', "{ [i] -> [NaN] }", + "{ [i] -> [NaN] }" }, + { "{ [i] -> [NaN] }", 'm', "{ [i] -> [i] }", + "{ [i] -> [NaN] }" }, +}; + +/* Perform some basic tests of binary operations on isl_pw_aff objects. + */ +static int test_bin_pw_aff(isl_ctx *ctx) +{ + int i; + isl_bool ok; + isl_pw_aff *pa1, *pa2, *res; + + for (i = 0; i < ARRAY_SIZE(pw_aff_bin_tests); ++i) { + pa1 = isl_pw_aff_read_from_str(ctx, pw_aff_bin_tests[i].arg1); + pa2 = isl_pw_aff_read_from_str(ctx, pw_aff_bin_tests[i].arg2); + res = isl_pw_aff_read_from_str(ctx, pw_aff_bin_tests[i].res); + pa1 = pw_aff_bin_op[pw_aff_bin_tests[i].op].fn(pa1, pa2); + if (isl_pw_aff_involves_nan(res)) + ok = isl_pw_aff_involves_nan(pa1); + else + ok = isl_pw_aff_plain_is_equal(pa1, res); + isl_pw_aff_free(pa1); + isl_pw_aff_free(res); + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + return 0; +} + +struct { + __isl_give isl_union_pw_multi_aff *(*fn)( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + const char *arg1; + const char *arg2; + const char *res; +} upma_bin_tests[] = { + { &isl_union_pw_multi_aff_add, "{ A[] -> [0]; B[0] -> [1] }", + "{ B[x] -> [2] : x >= 0 }", "{ B[0] -> [3] }" }, + { &isl_union_pw_multi_aff_union_add, "{ A[] -> [0]; B[0] -> [1] }", + "{ B[x] -> [2] : x >= 0 }", + "{ A[] -> [0]; B[0] -> [3]; B[x] -> [2] : x >= 1 }" }, + { &isl_union_pw_multi_aff_pullback_union_pw_multi_aff, + "{ A[] -> B[0]; C[x] -> B[1] : x < 10; C[y] -> B[2] : y >= 10 }", + "{ D[i] -> A[] : i < 0; D[i] -> C[i + 5] : i >= 0 }", + "{ D[i] -> B[0] : i < 0; D[i] -> B[1] : 0 <= i < 5; " + "D[i] -> B[2] : i >= 5 }" }, + { &isl_union_pw_multi_aff_union_add, "{ B[x] -> A[1] : x <= 0 }", + "{ B[x] -> C[2] : x > 0 }", + "{ B[x] -> A[1] : x <= 0; B[x] -> C[2] : x > 0 }" }, + { &isl_union_pw_multi_aff_union_add, "{ B[x] -> A[1] : x <= 0 }", + "{ B[x] -> A[2] : x >= 0 }", + "{ B[x] -> A[1] : x < 0; B[x] -> A[2] : x > 0; B[0] -> A[3] }" }, +}; + +/* Perform some basic tests of binary operations on + * isl_union_pw_multi_aff objects. + */ +static int test_bin_upma(isl_ctx *ctx) +{ + int i; + isl_union_pw_multi_aff *upma1, *upma2, *res; + int ok; + + for (i = 0; i < ARRAY_SIZE(upma_bin_tests); ++i) { + upma1 = isl_union_pw_multi_aff_read_from_str(ctx, + upma_bin_tests[i].arg1); + upma2 = isl_union_pw_multi_aff_read_from_str(ctx, + upma_bin_tests[i].arg2); + res = isl_union_pw_multi_aff_read_from_str(ctx, + upma_bin_tests[i].res); + upma1 = upma_bin_tests[i].fn(upma1, upma2); + ok = isl_union_pw_multi_aff_plain_is_equal(upma1, res); + isl_union_pw_multi_aff_free(upma1); + isl_union_pw_multi_aff_free(res); + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + return 0; +} + +struct { + __isl_give isl_union_pw_multi_aff *(*fn)( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + const char *arg1; + const char *arg2; +} upma_bin_fail_tests[] = { + { &isl_union_pw_multi_aff_union_add, "{ B[x] -> A[1] : x <= 0 }", + "{ B[x] -> C[2] : x >= 0 }" }, +}; + +/* Perform some basic tests of binary operations on + * isl_union_pw_multi_aff objects that are expected to fail. + */ +static int test_bin_upma_fail(isl_ctx *ctx) +{ + int i, n; + isl_union_pw_multi_aff *upma1, *upma2; + int on_error; + + on_error = isl_options_get_on_error(ctx); + isl_options_set_on_error(ctx, ISL_ON_ERROR_CONTINUE); + n = ARRAY_SIZE(upma_bin_fail_tests); + for (i = 0; i < n; ++i) { + upma1 = isl_union_pw_multi_aff_read_from_str(ctx, + upma_bin_fail_tests[i].arg1); + upma2 = isl_union_pw_multi_aff_read_from_str(ctx, + upma_bin_fail_tests[i].arg2); + upma1 = upma_bin_fail_tests[i].fn(upma1, upma2); + isl_union_pw_multi_aff_free(upma1); + if (upma1) + break; + } + isl_options_set_on_error(ctx, on_error); + if (i < n) + isl_die(ctx, isl_error_unknown, + "operation not expected to succeed", return -1); + + return 0; +} + +int test_aff(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_space *space; + isl_local_space *ls; + isl_aff *aff; + int zero, equal; + + if (test_bin_aff(ctx) < 0) + return -1; + if (test_bin_pw_aff(ctx) < 0) + return -1; + if (test_bin_upma(ctx) < 0) + return -1; + if (test_bin_upma_fail(ctx) < 0) + return -1; + + space = isl_space_set_alloc(ctx, 0, 1); + ls = isl_local_space_from_space(space); + aff = isl_aff_zero_on_domain(ls); + + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, 0, 1); + aff = isl_aff_scale_down_ui(aff, 3); + aff = isl_aff_floor(aff); + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, 0, 1); + aff = isl_aff_scale_down_ui(aff, 2); + aff = isl_aff_floor(aff); + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, 0, 1); + + str = "{ [10] }"; + set = isl_set_read_from_str(ctx, str); + aff = isl_aff_gist(aff, set); + + aff = isl_aff_add_constant_si(aff, -16); + zero = isl_aff_plain_is_zero(aff); + isl_aff_free(aff); + + if (zero < 0) + return -1; + if (!zero) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + aff = isl_aff_read_from_str(ctx, "{ [-1] }"); + aff = isl_aff_scale_down_ui(aff, 64); + aff = isl_aff_floor(aff); + equal = aff_check_plain_equal(aff, "{ [-1] }"); + isl_aff_free(aff); + if (equal < 0) + return -1; + + return 0; +} + +/* Check that "pa" consists of a single expression. + */ +static int check_single_piece(isl_ctx *ctx, __isl_take isl_pw_aff *pa) +{ + int n; + + n = isl_pw_aff_n_piece(pa); + isl_pw_aff_free(pa); + + if (!pa) + return -1; + if (n != 1) + isl_die(ctx, isl_error_unknown, "expecting single expression", + return -1); + + return 0; +} + +/* Check that the computation below results in a single expression. + * One or two expressions may result depending on which constraint + * ends up being considered as redundant with respect to the other + * constraints after the projection that is performed internally + * by isl_set_dim_min. + */ +static int test_dim_max_1(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_pw_aff *pa; + + str = "[n] -> { [a, b] : n >= 0 and 4a >= -4 + n and b >= 0 and " + "-4a <= b <= 3 and b < n - 4a }"; + set = isl_set_read_from_str(ctx, str); + pa = isl_set_dim_min(set, 0); + return check_single_piece(ctx, pa); +} + +/* Check that the computation below results in a single expression. + * The PIP problem corresponding to these constraints has a row + * that causes a split of the solution domain. The solver should + * first pick rows that split off empty parts such that the actual + * solution domain does not get split. + * Note that the description contains some redundant constraints. + * If these constraints get removed first, then the row mentioned + * above does not appear in the PIP problem. + */ +static int test_dim_max_2(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_pw_aff *pa; + + str = "[P, N] -> { [a] : a < N and a >= 0 and N > P and a <= P and " + "N > 0 and P >= 0 }"; + set = isl_set_read_from_str(ctx, str); + pa = isl_set_dim_max(set, 0); + return check_single_piece(ctx, pa); +} + +int test_dim_max(isl_ctx *ctx) +{ + int equal; + const char *str; + isl_set *set1, *set2; + isl_set *set; + isl_map *map; + isl_pw_aff *pwaff; + + if (test_dim_max_1(ctx) < 0) + return -1; + if (test_dim_max_2(ctx) < 0) + return -1; + + str = "[N] -> { [i] : 0 <= i <= min(N,10) }"; + set = isl_set_read_from_str(ctx, str); + pwaff = isl_set_dim_max(set, 0); + set1 = isl_set_from_pw_aff(pwaff); + str = "[N] -> { [10] : N >= 10; [N] : N <= 9 and N >= 0 }"; + set2 = isl_set_read_from_str(ctx, str); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + str = "[N] -> { [i] : 0 <= i <= max(2N,N+6) }"; + set = isl_set_read_from_str(ctx, str); + pwaff = isl_set_dim_max(set, 0); + set1 = isl_set_from_pw_aff(pwaff); + str = "[N] -> { [6 + N] : -6 <= N <= 5; [2N] : N >= 6 }"; + set2 = isl_set_read_from_str(ctx, str); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + str = "[N] -> { [i] : 0 <= i <= 2N or 0 <= i <= N+6 }"; + set = isl_set_read_from_str(ctx, str); + pwaff = isl_set_dim_max(set, 0); + set1 = isl_set_from_pw_aff(pwaff); + str = "[N] -> { [6 + N] : -6 <= N <= 5; [2N] : N >= 6 }"; + set2 = isl_set_read_from_str(ctx, str); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + str = "[N,M] -> { [i,j] -> [([i/16]), i%16, ([j/16]), j%16] : " + "0 <= i < N and 0 <= j < M }"; + map = isl_map_read_from_str(ctx, str); + set = isl_map_range(map); + + pwaff = isl_set_dim_max(isl_set_copy(set), 0); + set1 = isl_set_from_pw_aff(pwaff); + str = "[N,M] -> { [([(N-1)/16])] : M,N > 0 }"; + set2 = isl_set_read_from_str(ctx, str); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + + pwaff = isl_set_dim_max(isl_set_copy(set), 3); + set1 = isl_set_from_pw_aff(pwaff); + str = "[N,M] -> { [t] : t = min(M-1,15) and M,N > 0 }"; + set2 = isl_set_read_from_str(ctx, str); + if (equal >= 0 && equal) + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + + isl_set_free(set); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + /* Check that solutions are properly merged. */ + str = "[n] -> { [a, b, c] : c >= -4a - 2b and " + "c <= -1 + n - 4a - 2b and c >= -2b and " + "4a >= -4 + n and c >= 0 }"; + set = isl_set_read_from_str(ctx, str); + pwaff = isl_set_dim_min(set, 2); + set1 = isl_set_from_pw_aff(pwaff); + str = "[n] -> { [(0)] : n >= 1 }"; + set2 = isl_set_read_from_str(ctx, str); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + /* Check that empty solution lie in the right space. */ + str = "[n] -> { [t,a] : 1 = 0 }"; + set = isl_set_read_from_str(ctx, str); + pwaff = isl_set_dim_max(set, 0); + set1 = isl_set_from_pw_aff(pwaff); + str = "[n] -> { [t] : 1 = 0 }"; + set2 = isl_set_read_from_str(ctx, str); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + return 0; +} + +/* Is "pma" obviously equal to the isl_pw_multi_aff represented by "str"? + */ +static int pw_multi_aff_plain_is_equal(__isl_keep isl_pw_multi_aff *pma, + const char *str) +{ + isl_ctx *ctx; + isl_pw_multi_aff *pma2; + int equal; + + if (!pma) + return -1; + + ctx = isl_pw_multi_aff_get_ctx(pma); + pma2 = isl_pw_multi_aff_read_from_str(ctx, str); + equal = isl_pw_multi_aff_plain_is_equal(pma, pma2); + isl_pw_multi_aff_free(pma2); + + return equal; +} + +/* Check that "pma" is obviously equal to the isl_pw_multi_aff + * represented by "str". + */ +static int pw_multi_aff_check_plain_equal(__isl_keep isl_pw_multi_aff *pma, + const char *str) +{ + int equal; + + equal = pw_multi_aff_plain_is_equal(pma, str); + if (equal < 0) + return -1; + if (!equal) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_unknown, + "result not as expected", return -1); + return 0; +} + +/* Basic test for isl_pw_multi_aff_product. + * + * Check that multiple pieces are properly handled. + */ +static int test_product_pma(isl_ctx *ctx) +{ + int equal; + const char *str; + isl_pw_multi_aff *pma1, *pma2; + + str = "{ A[i] -> B[1] : i < 0; A[i] -> B[2] : i >= 0 }"; + pma1 = isl_pw_multi_aff_read_from_str(ctx, str); + str = "{ C[] -> D[] }"; + pma2 = isl_pw_multi_aff_read_from_str(ctx, str); + pma1 = isl_pw_multi_aff_product(pma1, pma2); + str = "{ [A[i] -> C[]] -> [B[(1)] -> D[]] : i < 0;" + "[A[i] -> C[]] -> [B[(2)] -> D[]] : i >= 0 }"; + equal = pw_multi_aff_check_plain_equal(pma1, str); + isl_pw_multi_aff_free(pma1); + if (equal < 0) + return -1; + + return 0; +} + +int test_product(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_union_set *uset1, *uset2; + int ok; + + str = "{ A[i] }"; + set = isl_set_read_from_str(ctx, str); + set = isl_set_product(set, isl_set_copy(set)); + ok = isl_set_is_wrapping(set); + isl_set_free(set); + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + str = "{ [] }"; + uset1 = isl_union_set_read_from_str(ctx, str); + uset1 = isl_union_set_product(uset1, isl_union_set_copy(uset1)); + str = "{ [[] -> []] }"; + uset2 = isl_union_set_read_from_str(ctx, str); + ok = isl_union_set_is_equal(uset1, uset2); + isl_union_set_free(uset1); + isl_union_set_free(uset2); + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + if (test_product_pma(ctx) < 0) + return -1; + + return 0; +} + +/* Check that two sets are not considered disjoint just because + * they have a different set of (named) parameters. + */ +static int test_disjoint(isl_ctx *ctx) +{ + const char *str; + isl_set *set, *set2; + int disjoint; + + str = "[n] -> { [[]->[]] }"; + set = isl_set_read_from_str(ctx, str); + str = "{ [[]->[]] }"; + set2 = isl_set_read_from_str(ctx, str); + disjoint = isl_set_is_disjoint(set, set2); + isl_set_free(set); + isl_set_free(set2); + if (disjoint < 0) + return -1; + if (disjoint) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + return 0; +} + +/* Inputs for isl_pw_multi_aff_is_equal tests. + * "f1" and "f2" are the two function that need to be compared. + * "equal" is the expected result. + */ +struct { + int equal; + const char *f1; + const char *f2; +} pma_equal_tests[] = { + { 1, "[N] -> { [floor(N/2)] : 0 <= N <= 1 }", + "[N] -> { [0] : 0 <= N <= 1 }" }, + { 1, "[N] -> { [floor(N/2)] : 0 <= N <= 2 }", + "[N] -> { [0] : 0 <= N <= 1; [1] : N = 2 }" }, + { 0, "[N] -> { [floor(N/2)] : 0 <= N <= 2 }", + "[N] -> { [0] : 0 <= N <= 1 }" }, + { 0, "{ [NaN] }", "{ [NaN] }" }, +}; + +int test_equal(isl_ctx *ctx) +{ + int i; + const char *str; + isl_set *set, *set2; + int equal; + + str = "{ S_6[i] }"; + set = isl_set_read_from_str(ctx, str); + str = "{ S_7[i] }"; + set2 = isl_set_read_from_str(ctx, str); + equal = isl_set_is_equal(set, set2); + isl_set_free(set); + isl_set_free(set2); + if (equal < 0) + return -1; + if (equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + for (i = 0; i < ARRAY_SIZE(pma_equal_tests); ++i) { + int expected = pma_equal_tests[i].equal; + isl_pw_multi_aff *f1, *f2; + + f1 = isl_pw_multi_aff_read_from_str(ctx, pma_equal_tests[i].f1); + f2 = isl_pw_multi_aff_read_from_str(ctx, pma_equal_tests[i].f2); + equal = isl_pw_multi_aff_is_equal(f1, f2); + isl_pw_multi_aff_free(f1); + isl_pw_multi_aff_free(f2); + if (equal < 0) + return -1; + if (equal != expected) + isl_die(ctx, isl_error_unknown, + "unexpected equality result", return -1); + } + + return 0; +} + +static int test_plain_fixed(isl_ctx *ctx, __isl_take isl_map *map, + enum isl_dim_type type, unsigned pos, int fixed) +{ + isl_bool test; + + test = isl_map_plain_is_fixed(map, type, pos, NULL); + isl_map_free(map); + if (test < 0) + return -1; + if (test == fixed) + return 0; + if (fixed) + isl_die(ctx, isl_error_unknown, + "map not detected as fixed", return -1); + else + isl_die(ctx, isl_error_unknown, + "map detected as fixed", return -1); +} + +int test_fixed(isl_ctx *ctx) +{ + const char *str; + isl_map *map; + + str = "{ [i] -> [i] }"; + map = isl_map_read_from_str(ctx, str); + if (test_plain_fixed(ctx, map, isl_dim_out, 0, 0)) + return -1; + str = "{ [i] -> [1] }"; + map = isl_map_read_from_str(ctx, str); + if (test_plain_fixed(ctx, map, isl_dim_out, 0, 1)) + return -1; + str = "{ S_1[p1] -> [o0] : o0 = -2 and p1 >= 1 and p1 <= 7 }"; + map = isl_map_read_from_str(ctx, str); + if (test_plain_fixed(ctx, map, isl_dim_out, 0, 1)) + return -1; + map = isl_map_read_from_str(ctx, str); + map = isl_map_neg(map); + if (test_plain_fixed(ctx, map, isl_dim_out, 0, 1)) + return -1; + + return 0; +} + +struct isl_vertices_test_data { + const char *set; + int n; + const char *vertex[6]; +} vertices_tests[] = { + { "{ A[t, i] : t = 12 and i >= 4 and i <= 12 }", + 2, { "{ A[12, 4] }", "{ A[12, 12] }" } }, + { "{ A[t, i] : t = 14 and i = 1 }", + 1, { "{ A[14, 1] }" } }, + { "[n, m] -> { [a, b, c] : b <= a and a <= n and b > 0 and c >= b and " + "c <= m and m <= n and m > 0 }", + 6, { + "[n, m] -> { [n, m, m] : 0 < m <= n }", + "[n, m] -> { [n, 1, m] : 0 < m <= n }", + "[n, m] -> { [n, 1, 1] : 0 < m <= n }", + "[n, m] -> { [m, m, m] : 0 < m <= n }", + "[n, m] -> { [1, 1, m] : 0 < m <= n }", + "[n, m] -> { [1, 1, 1] : 0 < m <= n }" + } }, +}; + +/* Check that "vertex" corresponds to one of the vertices in data->vertex. + */ +static isl_stat find_vertex(__isl_take isl_vertex *vertex, void *user) +{ + struct isl_vertices_test_data *data = user; + isl_ctx *ctx; + isl_multi_aff *ma; + isl_basic_set *bset; + isl_pw_multi_aff *pma; + int i; + isl_bool equal; + + ctx = isl_vertex_get_ctx(vertex); + bset = isl_vertex_get_domain(vertex); + ma = isl_vertex_get_expr(vertex); + pma = isl_pw_multi_aff_alloc(isl_set_from_basic_set(bset), ma); + + for (i = 0; i < data->n; ++i) { + isl_pw_multi_aff *pma_i; + + pma_i = isl_pw_multi_aff_read_from_str(ctx, data->vertex[i]); + equal = isl_pw_multi_aff_plain_is_equal(pma, pma_i); + isl_pw_multi_aff_free(pma_i); + + if (equal < 0 || equal) + break; + } + + isl_pw_multi_aff_free(pma); + isl_vertex_free(vertex); + + if (equal < 0) + return isl_stat_error; + + return equal ? isl_stat_ok : isl_stat_error; +} + +int test_vertices(isl_ctx *ctx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vertices_tests); ++i) { + isl_basic_set *bset; + isl_vertices *vertices; + int ok = 1; + int n; + + bset = isl_basic_set_read_from_str(ctx, vertices_tests[i].set); + vertices = isl_basic_set_compute_vertices(bset); + n = isl_vertices_get_n_vertices(vertices); + if (vertices_tests[i].n != n) + ok = 0; + if (isl_vertices_foreach_vertex(vertices, &find_vertex, + &vertices_tests[i]) < 0) + ok = 0; + isl_vertices_free(vertices); + isl_basic_set_free(bset); + + if (!vertices) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, "unexpected vertices", + return -1); + } + + return 0; +} + +int test_union_pw(isl_ctx *ctx) +{ + int equal; + const char *str; + isl_union_set *uset; + isl_union_pw_qpolynomial *upwqp1, *upwqp2; + + str = "{ [x] -> x^2 }"; + upwqp1 = isl_union_pw_qpolynomial_read_from_str(ctx, str); + upwqp2 = isl_union_pw_qpolynomial_copy(upwqp1); + uset = isl_union_pw_qpolynomial_domain(upwqp1); + upwqp1 = isl_union_pw_qpolynomial_copy(upwqp2); + upwqp1 = isl_union_pw_qpolynomial_intersect_domain(upwqp1, uset); + equal = isl_union_pw_qpolynomial_plain_is_equal(upwqp1, upwqp2); + isl_union_pw_qpolynomial_free(upwqp1); + isl_union_pw_qpolynomial_free(upwqp2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + return 0; +} + +/* Test that isl_union_pw_qpolynomial_eval picks up the function + * defined over the correct domain space. + */ +static int test_eval_1(isl_ctx *ctx) +{ + const char *str; + isl_point *pnt; + isl_set *set; + isl_union_pw_qpolynomial *upwqp; + isl_val *v; + int cmp; + + str = "{ A[x] -> x^2; B[x] -> -x^2 }"; + upwqp = isl_union_pw_qpolynomial_read_from_str(ctx, str); + str = "{ A[6] }"; + set = isl_set_read_from_str(ctx, str); + pnt = isl_set_sample_point(set); + v = isl_union_pw_qpolynomial_eval(upwqp, pnt); + cmp = isl_val_cmp_si(v, 36); + isl_val_free(v); + + if (!v) + return -1; + if (cmp != 0) + isl_die(ctx, isl_error_unknown, "unexpected value", return -1); + + return 0; +} + +/* Check that isl_qpolynomial_eval handles getting called on a void point. + */ +static int test_eval_2(isl_ctx *ctx) +{ + const char *str; + isl_point *pnt; + isl_set *set; + isl_qpolynomial *qp; + isl_val *v; + isl_bool ok; + + str = "{ A[x] -> [x] }"; + qp = isl_qpolynomial_from_aff(isl_aff_read_from_str(ctx, str)); + str = "{ A[x] : false }"; + set = isl_set_read_from_str(ctx, str); + pnt = isl_set_sample_point(set); + v = isl_qpolynomial_eval(qp, pnt); + ok = isl_val_is_nan(v); + isl_val_free(v); + + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, "expecting NaN", return -1); + + return 0; +} + +/* Perform basic polynomial evaluation tests. + */ +static int test_eval(isl_ctx *ctx) +{ + if (test_eval_1(ctx) < 0) + return -1; + if (test_eval_2(ctx) < 0) + return -1; + return 0; +} + +/* Descriptions of sets that are tested for reparsing after printing. + */ +const char *output_tests[] = { + "{ [1, y] : 0 <= y <= 1; [x, -x] : 0 <= x <= 1 }", + "{ [x] : 1 = 0 }", + "{ [x] : false }", + "{ [x] : x mod 2 = 0 }", + "{ [x] : x mod 2 = 1 }", + "{ [x, y] : x mod 2 = 0 and 3*floor(y/2) < x }", + "{ [y, x] : x mod 2 = 0 and 3*floor(y/2) < x }", + "{ [x, y] : x mod 2 = 0 and 3*floor(y/2) = x + y }", + "{ [y, x] : x mod 2 = 0 and 3*floor(y/2) = x + y }", + "[n] -> { [y, x] : 2*((x + 2y) mod 3) = n }", + "{ [x, y] : (2*floor(x/3) + 3*floor(y/4)) mod 5 = x }", +}; + +/* Check that printing a set and reparsing a set from the printed output + * results in the same set. + */ +static int test_output_set(isl_ctx *ctx) +{ + int i; + char *str; + isl_set *set1, *set2; + isl_bool equal; + + for (i = 0; i < ARRAY_SIZE(output_tests); ++i) { + set1 = isl_set_read_from_str(ctx, output_tests[i]); + str = isl_set_to_str(set1); + set2 = isl_set_read_from_str(ctx, str); + free(str); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "parsed output not the same", return -1); + } + + return 0; +} + +int test_output(isl_ctx *ctx) +{ + char *s; + const char *str; + isl_pw_aff *pa; + isl_printer *p; + int equal; + + if (test_output_set(ctx) < 0) + return -1; + + str = "[x] -> { [1] : x % 4 <= 2; [2] : x = 3 }"; + pa = isl_pw_aff_read_from_str(ctx, str); + + p = isl_printer_to_str(ctx); + p = isl_printer_set_output_format(p, ISL_FORMAT_C); + p = isl_printer_print_pw_aff(p, pa); + s = isl_printer_get_str(p); + isl_printer_free(p); + isl_pw_aff_free(pa); + if (!s) + equal = -1; + else + equal = !strcmp(s, "4 * floord(x, 4) + 2 >= x ? 1 : 2"); + free(s); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + + return 0; +} + +int test_sample(isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset1, *bset2; + int empty, subset; + + str = "{ [a, b, c, d, e, f, g, h, i, j, k] : " + "3i >= 1073741823b - c - 1073741823e + f and c >= 0 and " + "3i >= -1 + 3221225466b + c + d - 3221225466e - f and " + "2e >= a - b and 3e <= 2a and 3k <= -a and f <= -1 + a and " + "3i <= 4 - a + 4b + 2c - e - 2f and 3k <= -a + c - f and " + "3h >= -2 + a and 3g >= -3 - a and 3k >= -2 - a and " + "3i >= -2 - a - 2c + 3e + 2f and 3h <= a + c - f and " + "3h >= a + 2147483646b + 2c - 2147483646e - 2f and " + "3g <= -1 - a and 3i <= 1 + c + d - f and a <= 1073741823 and " + "f >= 1 - a + 1073741822b + c + d - 1073741822e and " + "3i >= 1 + 2b - 2c + e + 2f + 3g and " + "1073741822f <= 1073741822 - a + 1073741821b + 1073741822c +" + "d - 1073741821e and " + "3j <= 3 - a + 3b and 3g <= -2 - 2b + c + d - e - f and " + "3j >= 1 - a + b + 2e and " + "3f >= -3 + a + 3221225462b + 3c + d - 3221225465e and " + "3i <= 4 - a + 4b - e and " + "f <= 1073741822 + 1073741822b - 1073741822e and 3h <= a and " + "f >= 0 and 2e <= 4 - a + 5b - d and 2e <= a - b + d and " + "c <= -1 + a and 3i >= -2 - a + 3e and " + "1073741822e <= 1073741823 - a + 1073741822b + c and " + "3g >= -4 + 3221225464b + 3c + d - 3221225467e - 3f and " + "3i >= -1 + 3221225466b + 3c + d - 3221225466e - 3f and " + "1073741823e >= 1 + 1073741823b - d and " + "3i >= 1073741823b + c - 1073741823e - f and " + "3i >= 1 + 2b + e + 3g }"; + bset1 = isl_basic_set_read_from_str(ctx, str); + bset2 = isl_basic_set_sample(isl_basic_set_copy(bset1)); + empty = isl_basic_set_is_empty(bset2); + subset = isl_basic_set_is_subset(bset2, bset1); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + if (empty < 0 || subset < 0) + return -1; + if (empty) + isl_die(ctx, isl_error_unknown, "point not found", return -1); + if (!subset) + isl_die(ctx, isl_error_unknown, "bad point found", return -1); + + return 0; +} + +int test_fixed_power(isl_ctx *ctx) +{ + const char *str; + isl_map *map; + isl_val *exp; + int equal; + + str = "{ [i] -> [i + 1] }"; + map = isl_map_read_from_str(ctx, str); + exp = isl_val_int_from_si(ctx, 23); + map = isl_map_fixed_power_val(map, exp); + equal = map_check_equal(map, "{ [i] -> [i + 23] }"); + isl_map_free(map); + if (equal < 0) + return -1; + + return 0; +} + +int test_slice(isl_ctx *ctx) +{ + const char *str; + isl_map *map; + int equal; + + str = "{ [i] -> [j] }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_equate(map, isl_dim_in, 0, isl_dim_out, 0); + equal = map_check_equal(map, "{ [i] -> [i] }"); + isl_map_free(map); + if (equal < 0) + return -1; + + str = "{ [i] -> [j] }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_equate(map, isl_dim_in, 0, isl_dim_in, 0); + equal = map_check_equal(map, "{ [i] -> [j] }"); + isl_map_free(map); + if (equal < 0) + return -1; + + str = "{ [i] -> [j] }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_oppose(map, isl_dim_in, 0, isl_dim_out, 0); + equal = map_check_equal(map, "{ [i] -> [-i] }"); + isl_map_free(map); + if (equal < 0) + return -1; + + str = "{ [i] -> [j] }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_oppose(map, isl_dim_in, 0, isl_dim_in, 0); + equal = map_check_equal(map, "{ [0] -> [j] }"); + isl_map_free(map); + if (equal < 0) + return -1; + + str = "{ [i] -> [j] }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_order_gt(map, isl_dim_in, 0, isl_dim_out, 0); + equal = map_check_equal(map, "{ [i] -> [j] : i > j }"); + isl_map_free(map); + if (equal < 0) + return -1; + + str = "{ [i] -> [j] }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_order_gt(map, isl_dim_in, 0, isl_dim_in, 0); + equal = map_check_equal(map, "{ [i] -> [j] : false }"); + isl_map_free(map); + if (equal < 0) + return -1; + + return 0; +} + +int test_eliminate(isl_ctx *ctx) +{ + const char *str; + isl_map *map; + int equal; + + str = "{ [i] -> [j] : i = 2j }"; + map = isl_map_read_from_str(ctx, str); + map = isl_map_eliminate(map, isl_dim_out, 0, 1); + equal = map_check_equal(map, "{ [i] -> [j] : exists a : i = 2a }"); + isl_map_free(map); + if (equal < 0) + return -1; + + return 0; +} + +/* Check that isl_set_dim_residue_class detects that the values of j + * in the set below are all odd and that it does not detect any spurious + * strides. + */ +static int test_residue_class(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_int m, r; + isl_stat res; + + str = "{ [i,j] : j = 4 i + 1 and 0 <= i <= 100; " + "[i,j] : j = 4 i + 3 and 500 <= i <= 600 }"; + set = isl_set_read_from_str(ctx, str); + isl_int_init(m); + isl_int_init(r); + res = isl_set_dim_residue_class(set, 1, &m, &r); + if (res >= 0 && + (isl_int_cmp_si(m, 2) != 0 || isl_int_cmp_si(r, 1) != 0)) + isl_die(ctx, isl_error_unknown, "incorrect residue class", + res = isl_stat_error); + isl_int_clear(r); + isl_int_clear(m); + isl_set_free(set); + + return res; +} + +int test_align_parameters(isl_ctx *ctx) +{ + const char *str; + isl_space *space; + isl_multi_aff *ma1, *ma2; + int equal; + + str = "{ A[B[] -> C[]] -> D[E[] -> F[]] }"; + ma1 = isl_multi_aff_read_from_str(ctx, str); + + space = isl_space_params_alloc(ctx, 1); + space = isl_space_set_dim_name(space, isl_dim_param, 0, "N"); + ma1 = isl_multi_aff_align_params(ma1, space); + + str = "[N] -> { A[B[] -> C[]] -> D[E[] -> F[]] }"; + ma2 = isl_multi_aff_read_from_str(ctx, str); + + equal = isl_multi_aff_plain_is_equal(ma1, ma2); + + isl_multi_aff_free(ma1); + isl_multi_aff_free(ma2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "result not as expected", return -1); + + return 0; +} + +static int test_list(isl_ctx *ctx) +{ + isl_id *a, *b, *c, *d, *id; + isl_id_list *list; + int ok; + + a = isl_id_alloc(ctx, "a", NULL); + b = isl_id_alloc(ctx, "b", NULL); + c = isl_id_alloc(ctx, "c", NULL); + d = isl_id_alloc(ctx, "d", NULL); + + list = isl_id_list_alloc(ctx, 4); + list = isl_id_list_add(list, b); + list = isl_id_list_insert(list, 0, a); + list = isl_id_list_add(list, c); + list = isl_id_list_add(list, d); + list = isl_id_list_drop(list, 1, 1); + + if (!list) + return -1; + if (isl_id_list_n_id(list) != 3) { + isl_id_list_free(list); + isl_die(ctx, isl_error_unknown, + "unexpected number of elements in list", return -1); + } + + id = isl_id_list_get_id(list, 0); + ok = id == a; + isl_id_free(id); + id = isl_id_list_get_id(list, 1); + ok = ok && id == c; + isl_id_free(id); + id = isl_id_list_get_id(list, 2); + ok = ok && id == d; + isl_id_free(id); + + isl_id_list_free(list); + + if (!ok) + isl_die(ctx, isl_error_unknown, + "unexpected elements in list", return -1); + + return 0; +} + +const char *set_conversion_tests[] = { + "[N] -> { [i] : N - 1 <= 2 i <= N }", + "[N] -> { [i] : exists a : i = 4 a and N - 1 <= i <= N }", + "[N] -> { [i,j] : exists a : i = 4 a and N - 1 <= i, 2j <= N }", + "[N] -> { [[i]->[j]] : exists a : i = 4 a and N - 1 <= i, 2j <= N }", + "[N] -> { [3*floor(N/2) + 5*floor(N/3)] }", + "[a, b] -> { [c, d] : (4*floor((-a + c)/4) = -a + c and " + "32*floor((-b + d)/32) = -b + d and 5 <= c <= 8 and " + "-3 + c <= d <= 28 + c) }", +}; + +/* Check that converting from isl_set to isl_pw_multi_aff and back + * to isl_set produces the original isl_set. + */ +static int test_set_conversion(isl_ctx *ctx) +{ + int i; + const char *str; + isl_set *set1, *set2; + isl_pw_multi_aff *pma; + int equal; + + for (i = 0; i < ARRAY_SIZE(set_conversion_tests); ++i) { + str = set_conversion_tests[i]; + set1 = isl_set_read_from_str(ctx, str); + pma = isl_pw_multi_aff_from_set(isl_set_copy(set1)); + set2 = isl_set_from_pw_multi_aff(pma); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "bad conversion", + return -1); + } + + return 0; +} + +const char *conversion_tests[] = { + "{ [a, b, c, d] -> s0[a, b, e, f] : " + "exists (e0 = [(a - 2c)/3], e1 = [(-4 + b - 5d)/9], " + "e2 = [(-d + f)/9]: 3e0 = a - 2c and 9e1 = -4 + b - 5d and " + "9e2 = -d + f and f >= 0 and f <= 8 and 9e >= -5 - 2a and " + "9e <= -2 - 2a) }", + "{ [a, b] -> [c] : exists (e0 = floor((-a - b + c)/5): " + "5e0 = -a - b + c and c >= -a and c <= 4 - a) }", + "{ [a, b] -> [c] : exists d : 18 * d = -3 - a + 2c and 1 <= c <= 3 }", +}; + +/* Check that converting from isl_map to isl_pw_multi_aff and back + * to isl_map produces the original isl_map. + */ +static int test_map_conversion(isl_ctx *ctx) +{ + int i; + isl_map *map1, *map2; + isl_pw_multi_aff *pma; + int equal; + + for (i = 0; i < ARRAY_SIZE(conversion_tests); ++i) { + map1 = isl_map_read_from_str(ctx, conversion_tests[i]); + pma = isl_pw_multi_aff_from_map(isl_map_copy(map1)); + map2 = isl_map_from_pw_multi_aff(pma); + equal = isl_map_is_equal(map1, map2); + isl_map_free(map1); + isl_map_free(map2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "bad conversion", + return -1); + } + + return 0; +} + +static int test_conversion(isl_ctx *ctx) +{ + if (test_set_conversion(ctx) < 0) + return -1; + if (test_map_conversion(ctx) < 0) + return -1; + return 0; +} + +/* Check that isl_basic_map_curry does not modify input. + */ +static int test_curry(isl_ctx *ctx) +{ + const char *str; + isl_basic_map *bmap1, *bmap2; + int equal; + + str = "{ [A[] -> B[]] -> C[] }"; + bmap1 = isl_basic_map_read_from_str(ctx, str); + bmap2 = isl_basic_map_curry(isl_basic_map_copy(bmap1)); + equal = isl_basic_map_is_equal(bmap1, bmap2); + isl_basic_map_free(bmap1); + isl_basic_map_free(bmap2); + + if (equal < 0) + return -1; + if (equal) + isl_die(ctx, isl_error_unknown, + "curried map should not be equal to original", + return -1); + + return 0; +} + +struct { + const char *set; + const char *ma; + const char *res; +} preimage_tests[] = { + { "{ B[i,j] : 0 <= i < 10 and 0 <= j < 100 }", + "{ A[j,i] -> B[i,j] }", + "{ A[j,i] : 0 <= i < 10 and 0 <= j < 100 }" }, + { "{ rat: B[i,j] : 0 <= i, j and 3 i + 5 j <= 100 }", + "{ A[a,b] -> B[a/2,b/6] }", + "{ rat: A[a,b] : 0 <= a, b and 9 a + 5 b <= 600 }" }, + { "{ B[i,j] : 0 <= i, j and 3 i + 5 j <= 100 }", + "{ A[a,b] -> B[a/2,b/6] }", + "{ A[a,b] : 0 <= a, b and 9 a + 5 b <= 600 and " + "exists i,j : a = 2 i and b = 6 j }" }, + { "[n] -> { S[i] : 0 <= i <= 100 }", "[n] -> { S[n] }", + "[n] -> { : 0 <= n <= 100 }" }, + { "{ B[i] : 0 <= i < 100 and exists a : i = 4 a }", + "{ A[a] -> B[2a] }", + "{ A[a] : 0 <= a < 50 and exists b : a = 2 b }" }, + { "{ B[i] : 0 <= i < 100 and exists a : i = 4 a }", + "{ A[a] -> B[([a/2])] }", + "{ A[a] : 0 <= a < 200 and exists b : [a/2] = 4 b }" }, + { "{ B[i,j,k] : 0 <= i,j,k <= 100 }", + "{ A[a] -> B[a,a,a/3] }", + "{ A[a] : 0 <= a <= 100 and exists b : a = 3 b }" }, + { "{ B[i,j] : j = [(i)/2] } ", "{ A[i,j] -> B[i/3,j] }", + "{ A[i,j] : j = [(i)/6] and exists a : i = 3 a }" }, +}; + +static int test_preimage_basic_set(isl_ctx *ctx) +{ + int i; + isl_basic_set *bset1, *bset2; + isl_multi_aff *ma; + int equal; + + for (i = 0; i < ARRAY_SIZE(preimage_tests); ++i) { + bset1 = isl_basic_set_read_from_str(ctx, preimage_tests[i].set); + ma = isl_multi_aff_read_from_str(ctx, preimage_tests[i].ma); + bset2 = isl_basic_set_read_from_str(ctx, preimage_tests[i].res); + bset1 = isl_basic_set_preimage_multi_aff(bset1, ma); + equal = isl_basic_set_is_equal(bset1, bset2); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "bad preimage", + return -1); + } + + return 0; +} + +struct { + const char *map; + const char *ma; + const char *res; +} preimage_domain_tests[] = { + { "{ B[i,j] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }", + "{ A[j,i] -> B[i,j] }", + "{ A[j,i] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }" }, + { "{ B[i] -> C[i]; D[i] -> E[i] }", + "{ A[i] -> B[i + 1] }", + "{ A[i] -> C[i + 1] }" }, + { "{ B[i] -> C[i]; B[i] -> E[i] }", + "{ A[i] -> B[i + 1] }", + "{ A[i] -> C[i + 1]; A[i] -> E[i + 1] }" }, + { "{ B[i] -> C[([i/2])] }", + "{ A[i] -> B[2i] }", + "{ A[i] -> C[i] }" }, + { "{ B[i,j] -> C[([i/2]), ([(i+j)/3])] }", + "{ A[i] -> B[([i/5]), ([i/7])] }", + "{ A[i] -> C[([([i/5])/2]), ([(([i/5])+([i/7]))/3])] }" }, + { "[N] -> { B[i] -> C[([N/2]), i, ([N/3])] }", + "[N] -> { A[] -> B[([N/5])] }", + "[N] -> { A[] -> C[([N/2]), ([N/5]), ([N/3])] }" }, + { "{ B[i] -> C[i] : exists a : i = 5 a }", + "{ A[i] -> B[2i] }", + "{ A[i] -> C[2i] : exists a : 2i = 5 a }" }, + { "{ B[i] -> C[i] : exists a : i = 2 a; " + "B[i] -> D[i] : exists a : i = 2 a + 1 }", + "{ A[i] -> B[2i] }", + "{ A[i] -> C[2i] }" }, + { "{ A[i] -> B[i] }", "{ C[i] -> A[(i + floor(i/3))/2] }", + "{ C[i] -> B[j] : 2j = i + floor(i/3) }" }, +}; + +static int test_preimage_union_map(isl_ctx *ctx) +{ + int i; + isl_union_map *umap1, *umap2; + isl_multi_aff *ma; + int equal; + + for (i = 0; i < ARRAY_SIZE(preimage_domain_tests); ++i) { + umap1 = isl_union_map_read_from_str(ctx, + preimage_domain_tests[i].map); + ma = isl_multi_aff_read_from_str(ctx, + preimage_domain_tests[i].ma); + umap2 = isl_union_map_read_from_str(ctx, + preimage_domain_tests[i].res); + umap1 = isl_union_map_preimage_domain_multi_aff(umap1, ma); + equal = isl_union_map_is_equal(umap1, umap2); + isl_union_map_free(umap1); + isl_union_map_free(umap2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "bad preimage", + return -1); + } + + return 0; +} + +static int test_preimage(isl_ctx *ctx) +{ + if (test_preimage_basic_set(ctx) < 0) + return -1; + if (test_preimage_union_map(ctx) < 0) + return -1; + + return 0; +} + +struct { + const char *ma1; + const char *ma; + const char *res; +} pullback_tests[] = { + { "{ B[i,j] -> C[i + 2j] }" , "{ A[a,b] -> B[b,a] }", + "{ A[a,b] -> C[b + 2a] }" }, + { "{ B[i] -> C[2i] }", "{ A[a] -> B[(a)/2] }", "{ A[a] -> C[a] }" }, + { "{ B[i] -> C[(i)/2] }", "{ A[a] -> B[2a] }", "{ A[a] -> C[a] }" }, + { "{ B[i] -> C[(i)/2] }", "{ A[a] -> B[(a)/3] }", + "{ A[a] -> C[(a)/6] }" }, + { "{ B[i] -> C[2i] }", "{ A[a] -> B[5a] }", "{ A[a] -> C[10a] }" }, + { "{ B[i] -> C[2i] }", "{ A[a] -> B[(a)/3] }", + "{ A[a] -> C[(2a)/3] }" }, + { "{ B[i,j] -> C[i + j] }", "{ A[a] -> B[a,a] }", "{ A[a] -> C[2a] }"}, + { "{ B[a] -> C[a,a] }", "{ A[i,j] -> B[i + j] }", + "{ A[i,j] -> C[i + j, i + j] }"}, + { "{ B[i] -> C[([i/2])] }", "{ B[5] }", "{ C[2] }" }, + { "[n] -> { B[i,j] -> C[([i/2]) + 2j] }", + "[n] -> { B[n,[n/3]] }", "[n] -> { C[([n/2]) + 2*[n/3]] }", }, + { "{ [i, j] -> [floor((i)/4) + floor((2*i+j)/5)] }", + "{ [i, j] -> [floor((i)/3), j] }", + "{ [i, j] -> [(floor((i)/12) + floor((j + 2*floor((i)/3))/5))] }" }, +}; + +static int test_pullback(isl_ctx *ctx) +{ + int i; + isl_multi_aff *ma1, *ma2; + isl_multi_aff *ma; + int equal; + + for (i = 0; i < ARRAY_SIZE(pullback_tests); ++i) { + ma1 = isl_multi_aff_read_from_str(ctx, pullback_tests[i].ma1); + ma = isl_multi_aff_read_from_str(ctx, pullback_tests[i].ma); + ma2 = isl_multi_aff_read_from_str(ctx, pullback_tests[i].res); + ma1 = isl_multi_aff_pullback_multi_aff(ma1, ma); + equal = isl_multi_aff_plain_is_equal(ma1, ma2); + isl_multi_aff_free(ma1); + isl_multi_aff_free(ma2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, "bad pullback", + return -1); + } + + return 0; +} + +/* Check that negation is printed correctly and that equal expressions + * are correctly identified. + */ +static int test_ast(isl_ctx *ctx) +{ + isl_ast_expr *expr, *expr1, *expr2, *expr3; + char *str; + int ok, equal; + + expr1 = isl_ast_expr_from_id(isl_id_alloc(ctx, "A", NULL)); + expr2 = isl_ast_expr_from_id(isl_id_alloc(ctx, "B", NULL)); + expr = isl_ast_expr_add(expr1, expr2); + expr2 = isl_ast_expr_copy(expr); + expr = isl_ast_expr_neg(expr); + expr2 = isl_ast_expr_neg(expr2); + equal = isl_ast_expr_is_equal(expr, expr2); + str = isl_ast_expr_to_C_str(expr); + ok = str ? !strcmp(str, "-(A + B)") : -1; + free(str); + isl_ast_expr_free(expr); + isl_ast_expr_free(expr2); + + if (ok < 0 || equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "equal expressions not considered equal", return -1); + if (!ok) + isl_die(ctx, isl_error_unknown, + "isl_ast_expr printed incorrectly", return -1); + + expr1 = isl_ast_expr_from_id(isl_id_alloc(ctx, "A", NULL)); + expr2 = isl_ast_expr_from_id(isl_id_alloc(ctx, "B", NULL)); + expr = isl_ast_expr_add(expr1, expr2); + expr3 = isl_ast_expr_from_id(isl_id_alloc(ctx, "C", NULL)); + expr = isl_ast_expr_sub(expr3, expr); + str = isl_ast_expr_to_C_str(expr); + ok = str ? !strcmp(str, "C - (A + B)") : -1; + free(str); + isl_ast_expr_free(expr); + + if (ok < 0) + return -1; + if (!ok) + isl_die(ctx, isl_error_unknown, + "isl_ast_expr printed incorrectly", return -1); + + return 0; +} + +/* Check that isl_ast_build_expr_from_set returns a valid expression + * for an empty set. Note that isl_ast_build_expr_from_set getting + * called on an empty set probably indicates a bug in the caller. + */ +static int test_ast_build(isl_ctx *ctx) +{ + isl_set *set; + isl_ast_build *build; + isl_ast_expr *expr; + + set = isl_set_universe(isl_space_params_alloc(ctx, 0)); + build = isl_ast_build_from_context(set); + + set = isl_set_empty(isl_space_params_alloc(ctx, 0)); + expr = isl_ast_build_expr_from_set(build, set); + + isl_ast_expr_free(expr); + isl_ast_build_free(build); + + if (!expr) + return -1; + + return 0; +} + +/* Internal data structure for before_for and after_for callbacks. + * + * depth is the current depth + * before is the number of times before_for has been called + * after is the number of times after_for has been called + */ +struct isl_test_codegen_data { + int depth; + int before; + int after; +}; + +/* This function is called before each for loop in the AST generated + * from test_ast_gen1. + * + * Increment the number of calls and the depth. + * Check that the space returned by isl_ast_build_get_schedule_space + * matches the target space of the schedule returned by + * isl_ast_build_get_schedule. + * Return an isl_id that is checked by the corresponding call + * to after_for. + */ +static __isl_give isl_id *before_for(__isl_keep isl_ast_build *build, + void *user) +{ + struct isl_test_codegen_data *data = user; + isl_ctx *ctx; + isl_space *space; + isl_union_map *schedule; + isl_union_set *uset; + isl_set *set; + int empty; + char name[] = "d0"; + + ctx = isl_ast_build_get_ctx(build); + + if (data->before >= 3) + isl_die(ctx, isl_error_unknown, + "unexpected number of for nodes", return NULL); + if (data->depth >= 2) + isl_die(ctx, isl_error_unknown, + "unexpected depth", return NULL); + + snprintf(name, sizeof(name), "d%d", data->depth); + data->before++; + data->depth++; + + schedule = isl_ast_build_get_schedule(build); + uset = isl_union_map_range(schedule); + if (!uset) + return NULL; + if (isl_union_set_n_set(uset) != 1) { + isl_union_set_free(uset); + isl_die(ctx, isl_error_unknown, + "expecting single range space", return NULL); + } + + space = isl_ast_build_get_schedule_space(build); + set = isl_union_set_extract_set(uset, space); + isl_union_set_free(uset); + empty = isl_set_is_empty(set); + isl_set_free(set); + + if (empty < 0) + return NULL; + if (empty) + isl_die(ctx, isl_error_unknown, + "spaces don't match", return NULL); + + return isl_id_alloc(ctx, name, NULL); +} + +/* This function is called after each for loop in the AST generated + * from test_ast_gen1. + * + * Increment the number of calls and decrement the depth. + * Check that the annotation attached to the node matches + * the isl_id returned by the corresponding call to before_for. + */ +static __isl_give isl_ast_node *after_for(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user) +{ + struct isl_test_codegen_data *data = user; + isl_id *id; + const char *name; + int valid; + + data->after++; + data->depth--; + + if (data->after > data->before) + isl_die(isl_ast_node_get_ctx(node), isl_error_unknown, + "mismatch in number of for nodes", + return isl_ast_node_free(node)); + + id = isl_ast_node_get_annotation(node); + if (!id) + isl_die(isl_ast_node_get_ctx(node), isl_error_unknown, + "missing annotation", return isl_ast_node_free(node)); + + name = isl_id_get_name(id); + valid = name && atoi(name + 1) == data->depth; + isl_id_free(id); + + if (!valid) + isl_die(isl_ast_node_get_ctx(node), isl_error_unknown, + "wrong annotation", return isl_ast_node_free(node)); + + return node; +} + +/* Check that the before_each_for and after_each_for callbacks + * are called for each for loop in the generated code, + * that they are called in the right order and that the isl_id + * returned from the before_each_for callback is attached to + * the isl_ast_node passed to the corresponding after_each_for call. + */ +static int test_ast_gen1(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_union_map *schedule; + isl_ast_build *build; + isl_ast_node *tree; + struct isl_test_codegen_data data; + + str = "[N] -> { : N >= 10 }"; + set = isl_set_read_from_str(ctx, str); + str = "[N] -> { A[i,j] -> S[8,i,3,j] : 0 <= i,j <= N; " + "B[i,j] -> S[8,j,9,i] : 0 <= i,j <= N }"; + schedule = isl_union_map_read_from_str(ctx, str); + + data.before = 0; + data.after = 0; + data.depth = 0; + build = isl_ast_build_from_context(set); + build = isl_ast_build_set_before_each_for(build, + &before_for, &data); + build = isl_ast_build_set_after_each_for(build, + &after_for, &data); + tree = isl_ast_build_node_from_schedule_map(build, schedule); + isl_ast_build_free(build); + if (!tree) + return -1; + + isl_ast_node_free(tree); + + if (data.before != 3 || data.after != 3) + isl_die(ctx, isl_error_unknown, + "unexpected number of for nodes", return -1); + + return 0; +} + +/* Check that the AST generator handles domains that are integrally disjoint + * but not rationally disjoint. + */ +static int test_ast_gen2(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_union_map *schedule; + isl_union_map *options; + isl_ast_build *build; + isl_ast_node *tree; + + str = "{ A[i,j] -> [i,j] : 0 <= i,j <= 1 }"; + schedule = isl_union_map_read_from_str(ctx, str); + set = isl_set_universe(isl_space_params_alloc(ctx, 0)); + build = isl_ast_build_from_context(set); + + str = "{ [i,j] -> atomic[1] : i + j = 1; [i,j] -> unroll[1] : i = j }"; + options = isl_union_map_read_from_str(ctx, str); + build = isl_ast_build_set_options(build, options); + tree = isl_ast_build_node_from_schedule_map(build, schedule); + isl_ast_build_free(build); + if (!tree) + return -1; + isl_ast_node_free(tree); + + return 0; +} + +/* Increment *user on each call. + */ +static __isl_give isl_ast_node *count_domains(__isl_take isl_ast_node *node, + __isl_keep isl_ast_build *build, void *user) +{ + int *n = user; + + (*n)++; + + return node; +} + +/* Test that unrolling tries to minimize the number of instances. + * In particular, for the schedule given below, make sure it generates + * 3 nodes (rather than 101). + */ +static int test_ast_gen3(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_union_map *schedule; + isl_union_map *options; + isl_ast_build *build; + isl_ast_node *tree; + int n_domain = 0; + + str = "[n] -> { A[i] -> [i] : 0 <= i <= 100 and n <= i <= n + 2 }"; + schedule = isl_union_map_read_from_str(ctx, str); + set = isl_set_universe(isl_space_params_alloc(ctx, 0)); + + str = "{ [i] -> unroll[0] }"; + options = isl_union_map_read_from_str(ctx, str); + + build = isl_ast_build_from_context(set); + build = isl_ast_build_set_options(build, options); + build = isl_ast_build_set_at_each_domain(build, + &count_domains, &n_domain); + tree = isl_ast_build_node_from_schedule_map(build, schedule); + isl_ast_build_free(build); + if (!tree) + return -1; + + isl_ast_node_free(tree); + + if (n_domain != 3) + isl_die(ctx, isl_error_unknown, + "unexpected number of for nodes", return -1); + + return 0; +} + +/* Check that if the ast_build_exploit_nested_bounds options is set, + * we do not get an outer if node in the generated AST, + * while we do get such an outer if node if the options is not set. + */ +static int test_ast_gen4(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_union_map *schedule; + isl_ast_build *build; + isl_ast_node *tree; + enum isl_ast_node_type type; + int enb; + + enb = isl_options_get_ast_build_exploit_nested_bounds(ctx); + str = "[N,M] -> { A[i,j] -> [i,j] : 0 <= i <= N and 0 <= j <= M }"; + + isl_options_set_ast_build_exploit_nested_bounds(ctx, 1); + + schedule = isl_union_map_read_from_str(ctx, str); + set = isl_set_universe(isl_space_params_alloc(ctx, 0)); + build = isl_ast_build_from_context(set); + tree = isl_ast_build_node_from_schedule_map(build, schedule); + isl_ast_build_free(build); + if (!tree) + return -1; + + type = isl_ast_node_get_type(tree); + isl_ast_node_free(tree); + + if (type == isl_ast_node_if) + isl_die(ctx, isl_error_unknown, + "not expecting if node", return -1); + + isl_options_set_ast_build_exploit_nested_bounds(ctx, 0); + + schedule = isl_union_map_read_from_str(ctx, str); + set = isl_set_universe(isl_space_params_alloc(ctx, 0)); + build = isl_ast_build_from_context(set); + tree = isl_ast_build_node_from_schedule_map(build, schedule); + isl_ast_build_free(build); + if (!tree) + return -1; + + type = isl_ast_node_get_type(tree); + isl_ast_node_free(tree); + + if (type != isl_ast_node_if) + isl_die(ctx, isl_error_unknown, + "expecting if node", return -1); + + isl_options_set_ast_build_exploit_nested_bounds(ctx, enb); + + return 0; +} + +/* This function is called for each leaf in the AST generated + * from test_ast_gen5. + * + * We finalize the AST generation by extending the outer schedule + * with a zero-dimensional schedule. If this results in any for loops, + * then this means that we did not pass along enough information + * about the outer schedule to the inner AST generation. + */ +static __isl_give isl_ast_node *create_leaf(__isl_take isl_ast_build *build, + void *user) +{ + isl_union_map *schedule, *extra; + isl_ast_node *tree; + + schedule = isl_ast_build_get_schedule(build); + extra = isl_union_map_copy(schedule); + extra = isl_union_map_from_domain(isl_union_map_domain(extra)); + schedule = isl_union_map_range_product(schedule, extra); + tree = isl_ast_build_node_from_schedule_map(build, schedule); + isl_ast_build_free(build); + + if (!tree) + return NULL; + + if (isl_ast_node_get_type(tree) == isl_ast_node_for) + isl_die(isl_ast_node_get_ctx(tree), isl_error_unknown, + "code should not contain any for loop", + return isl_ast_node_free(tree)); + + return tree; +} + +/* Check that we do not lose any information when going back and + * forth between internal and external schedule. + * + * In particular, we create an AST where we unroll the only + * non-constant dimension in the schedule. We therefore do + * not expect any for loops in the AST. However, older versions + * of isl would not pass along enough information about the outer + * schedule when performing an inner code generation from a create_leaf + * callback, resulting in the inner code generation producing a for loop. + */ +static int test_ast_gen5(isl_ctx *ctx) +{ + const char *str; + isl_set *set; + isl_union_map *schedule, *options; + isl_ast_build *build; + isl_ast_node *tree; + + str = "{ A[] -> [1, 1, 2]; B[i] -> [1, i, 0] : i >= 1 and i <= 2 }"; + schedule = isl_union_map_read_from_str(ctx, str); + + str = "{ [a, b, c] -> unroll[1] : exists (e0 = [(a)/4]: " + "4e0 >= -1 + a - b and 4e0 <= -2 + a + b) }"; + options = isl_union_map_read_from_str(ctx, str); + + set = isl_set_universe(isl_space_params_alloc(ctx, 0)); + build = isl_ast_build_from_context(set); + build = isl_ast_build_set_options(build, options); + build = isl_ast_build_set_create_leaf(build, &create_leaf, NULL); + tree = isl_ast_build_node_from_schedule_map(build, schedule); + isl_ast_build_free(build); + isl_ast_node_free(tree); + if (!tree) + return -1; + + return 0; +} + +/* Check that the expression + * + * [n] -> { [n/2] : n <= 0 and n % 2 = 0; [0] : n > 0 } + * + * is not combined into + * + * min(n/2, 0) + * + * as this would result in n/2 being evaluated in parts of + * the definition domain where n is not a multiple of 2. + */ +static int test_ast_expr(isl_ctx *ctx) +{ + const char *str; + isl_pw_aff *pa; + isl_ast_build *build; + isl_ast_expr *expr; + int min_max; + int is_min; + + min_max = isl_options_get_ast_build_detect_min_max(ctx); + isl_options_set_ast_build_detect_min_max(ctx, 1); + + str = "[n] -> { [n/2] : n <= 0 and n % 2 = 0; [0] : n > 0 }"; + pa = isl_pw_aff_read_from_str(ctx, str); + build = isl_ast_build_alloc(ctx); + expr = isl_ast_build_expr_from_pw_aff(build, pa); + is_min = isl_ast_expr_get_type(expr) == isl_ast_expr_op && + isl_ast_expr_get_op_type(expr) == isl_ast_op_min; + isl_ast_build_free(build); + isl_ast_expr_free(expr); + + isl_options_set_ast_build_detect_min_max(ctx, min_max); + + if (!expr) + return -1; + if (is_min) + isl_die(ctx, isl_error_unknown, + "expressions should not be combined", return -1); + + return 0; +} + +static int test_ast_gen(isl_ctx *ctx) +{ + if (test_ast_gen1(ctx) < 0) + return -1; + if (test_ast_gen2(ctx) < 0) + return -1; + if (test_ast_gen3(ctx) < 0) + return -1; + if (test_ast_gen4(ctx) < 0) + return -1; + if (test_ast_gen5(ctx) < 0) + return -1; + if (test_ast_expr(ctx) < 0) + return -1; + return 0; +} + +/* Check if dropping output dimensions from an isl_pw_multi_aff + * works properly. + */ +static int test_pw_multi_aff(isl_ctx *ctx) +{ + const char *str; + isl_pw_multi_aff *pma1, *pma2; + int equal; + + str = "{ [i,j] -> [i+j, 4i-j] }"; + pma1 = isl_pw_multi_aff_read_from_str(ctx, str); + str = "{ [i,j] -> [4i-j] }"; + pma2 = isl_pw_multi_aff_read_from_str(ctx, str); + + pma1 = isl_pw_multi_aff_drop_dims(pma1, isl_dim_out, 0, 1); + + equal = isl_pw_multi_aff_plain_is_equal(pma1, pma2); + + isl_pw_multi_aff_free(pma1); + isl_pw_multi_aff_free(pma2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "expressions not equal", return -1); + + return 0; +} + +/* Check that we can properly parse multi piecewise affine expressions + * where the piecewise affine expressions have different domains. + */ +static int test_multi_pw_aff(isl_ctx *ctx) +{ + const char *str; + isl_set *dom, *dom2; + isl_multi_pw_aff *mpa1, *mpa2; + isl_pw_aff *pa; + int equal; + int equal_domain; + + mpa1 = isl_multi_pw_aff_read_from_str(ctx, "{ [i] -> [i] }"); + dom = isl_set_read_from_str(ctx, "{ [i] : i > 0 }"); + mpa1 = isl_multi_pw_aff_intersect_domain(mpa1, dom); + mpa2 = isl_multi_pw_aff_read_from_str(ctx, "{ [i] -> [2i] }"); + mpa2 = isl_multi_pw_aff_flat_range_product(mpa1, mpa2); + str = "{ [i] -> [(i : i > 0), 2i] }"; + mpa1 = isl_multi_pw_aff_read_from_str(ctx, str); + + equal = isl_multi_pw_aff_plain_is_equal(mpa1, mpa2); + + pa = isl_multi_pw_aff_get_pw_aff(mpa1, 0); + dom = isl_pw_aff_domain(pa); + pa = isl_multi_pw_aff_get_pw_aff(mpa1, 1); + dom2 = isl_pw_aff_domain(pa); + equal_domain = isl_set_is_equal(dom, dom2); + + isl_set_free(dom); + isl_set_free(dom2); + isl_multi_pw_aff_free(mpa1); + isl_multi_pw_aff_free(mpa2); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "expressions not equal", return -1); + + if (equal_domain < 0) + return -1; + if (equal_domain) + isl_die(ctx, isl_error_unknown, + "domains unexpectedly equal", return -1); + + return 0; +} + +/* This is a regression test for a bug where isl_basic_map_simplify + * would end up in an infinite loop. In particular, we construct + * an empty basic set that is not obviously empty. + * isl_basic_set_is_empty marks the basic set as empty. + * After projecting out i3, the variable can be dropped completely, + * but isl_basic_map_simplify refrains from doing so if the basic set + * is empty and would end up in an infinite loop if it didn't test + * explicitly for empty basic maps in the outer loop. + */ +static int test_simplify_1(isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset; + int empty; + + str = "{ [i0, i1, i2, i3] : i0 >= -2 and 6i2 <= 4 + i0 + 5i1 and " + "i2 <= 22 and 75i2 <= 111 + 13i0 + 60i1 and " + "25i2 >= 38 + 6i0 + 20i1 and i0 <= -1 and i2 >= 20 and " + "i3 >= i2 }"; + bset = isl_basic_set_read_from_str(ctx, str); + empty = isl_basic_set_is_empty(bset); + bset = isl_basic_set_project_out(bset, isl_dim_set, 3, 1); + isl_basic_set_free(bset); + if (!bset) + return -1; + if (!empty) + isl_die(ctx, isl_error_unknown, + "basic set should be empty", return -1); + + return 0; +} + +/* Check that the equality in the set description below + * is simplified away. + */ +static int test_simplify_2(isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset; + isl_bool universe; + + str = "{ [a] : exists e0, e1: 32e1 = 31 + 31a + 31e0 }"; + bset = isl_basic_set_read_from_str(ctx, str); + universe = isl_basic_set_plain_is_universe(bset); + isl_basic_set_free(bset); + + if (universe < 0) + return -1; + if (!universe) + isl_die(ctx, isl_error_unknown, + "equality not simplified away", return -1); + return 0; +} + +/* Some simplification tests. + */ +static int test_simplify(isl_ctx *ctx) +{ + if (test_simplify_1(ctx) < 0) + return -1; + if (test_simplify_2(ctx) < 0) + return -1; + return 0; +} + +/* This is a regression test for a bug where isl_tab_basic_map_partial_lexopt + * with gbr context would fail to disable the use of the shifted tableau + * when transferring equalities for the input to the context, resulting + * in invalid sample values. + */ +static int test_partial_lexmin(isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset; + isl_basic_map *bmap; + isl_map *map; + + str = "{ [1, b, c, 1 - c] -> [e] : 2e <= -c and 2e >= -3 + c }"; + bmap = isl_basic_map_read_from_str(ctx, str); + str = "{ [a, b, c, d] : c <= 1 and 2d >= 6 - 4b - c }"; + bset = isl_basic_set_read_from_str(ctx, str); + map = isl_basic_map_partial_lexmin(bmap, bset, NULL); + isl_map_free(map); + + if (!map) + return -1; + + return 0; +} + +/* Check that the variable compression performed on the existentially + * quantified variables inside isl_basic_set_compute_divs is not confused + * by the implicit equalities among the parameters. + */ +static int test_compute_divs(isl_ctx *ctx) +{ + const char *str; + isl_basic_set *bset; + isl_set *set; + + str = "[a, b, c, d, e] -> { [] : exists (e0: 2d = b and a <= 124 and " + "b <= 2046 and b >= 0 and b <= 60 + 64a and 2e >= b + 2c and " + "2e >= b and 2e <= 1 + b and 2e <= 1 + b + 2c and " + "32768e0 >= -124 + a and 2097152e0 <= 60 + 64a - b) }"; + bset = isl_basic_set_read_from_str(ctx, str); + set = isl_basic_set_compute_divs(bset); + isl_set_free(set); + if (!set) + return -1; + + return 0; +} + +/* Check that the reaching domain elements and the prefix schedule + * at a leaf node are the same before and after grouping. + */ +static int test_schedule_tree_group_1(isl_ctx *ctx) +{ + int equal; + const char *str; + isl_id *id; + isl_union_set *uset; + isl_multi_union_pw_aff *mupa; + isl_union_pw_multi_aff *upma1, *upma2; + isl_union_set *domain1, *domain2; + isl_union_map *umap1, *umap2; + isl_schedule_node *node; + + str = "{ S1[i,j] : 0 <= i,j < 10; S2[i,j] : 0 <= i,j < 10 }"; + uset = isl_union_set_read_from_str(ctx, str); + node = isl_schedule_node_from_domain(uset); + node = isl_schedule_node_child(node, 0); + str = "[{ S1[i,j] -> [i]; S2[i,j] -> [9 - i] }]"; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + node = isl_schedule_node_insert_partial_schedule(node, mupa); + node = isl_schedule_node_child(node, 0); + str = "[{ S1[i,j] -> [j]; S2[i,j] -> [j] }]"; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + node = isl_schedule_node_insert_partial_schedule(node, mupa); + node = isl_schedule_node_child(node, 0); + umap1 = isl_schedule_node_get_prefix_schedule_union_map(node); + upma1 = isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(node); + domain1 = isl_schedule_node_get_domain(node); + id = isl_id_alloc(ctx, "group", NULL); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_group(node, id); + node = isl_schedule_node_child(node, 0); + umap2 = isl_schedule_node_get_prefix_schedule_union_map(node); + upma2 = isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(node); + domain2 = isl_schedule_node_get_domain(node); + equal = isl_union_pw_multi_aff_plain_is_equal(upma1, upma2); + if (equal >= 0 && equal) + equal = isl_union_set_is_equal(domain1, domain2); + if (equal >= 0 && equal) + equal = isl_union_map_is_equal(umap1, umap2); + isl_union_map_free(umap1); + isl_union_map_free(umap2); + isl_union_set_free(domain1); + isl_union_set_free(domain2); + isl_union_pw_multi_aff_free(upma1); + isl_union_pw_multi_aff_free(upma2); + isl_schedule_node_free(node); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "expressions not equal", return -1); + + return 0; +} + +/* Check that we can have nested groupings and that the union map + * schedule representation is the same before and after the grouping. + * Note that after the grouping, the union map representation contains + * the domain constraints from the ranges of the expansion nodes, + * while they are missing from the union map representation of + * the tree without expansion nodes. + * + * Also check that the global expansion is as expected. + */ +static int test_schedule_tree_group_2(isl_ctx *ctx) +{ + int equal, equal_expansion; + const char *str; + isl_id *id; + isl_union_set *uset; + isl_union_map *umap1, *umap2; + isl_union_map *expansion1, *expansion2; + isl_union_set_list *filters; + isl_multi_union_pw_aff *mupa; + isl_schedule *schedule; + isl_schedule_node *node; + + str = "{ S1[i,j] : 0 <= i,j < 10; S2[i,j] : 0 <= i,j < 10; " + "S3[i,j] : 0 <= i,j < 10 }"; + uset = isl_union_set_read_from_str(ctx, str); + node = isl_schedule_node_from_domain(uset); + node = isl_schedule_node_child(node, 0); + str = "[{ S1[i,j] -> [i]; S2[i,j] -> [i]; S3[i,j] -> [i] }]"; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + node = isl_schedule_node_insert_partial_schedule(node, mupa); + node = isl_schedule_node_child(node, 0); + str = "{ S1[i,j] }"; + uset = isl_union_set_read_from_str(ctx, str); + filters = isl_union_set_list_from_union_set(uset); + str = "{ S2[i,j]; S3[i,j] }"; + uset = isl_union_set_read_from_str(ctx, str); + filters = isl_union_set_list_add(filters, uset); + node = isl_schedule_node_insert_sequence(node, filters); + node = isl_schedule_node_child(node, 1); + node = isl_schedule_node_child(node, 0); + str = "{ S2[i,j] }"; + uset = isl_union_set_read_from_str(ctx, str); + filters = isl_union_set_list_from_union_set(uset); + str = "{ S3[i,j] }"; + uset = isl_union_set_read_from_str(ctx, str); + filters = isl_union_set_list_add(filters, uset); + node = isl_schedule_node_insert_sequence(node, filters); + + schedule = isl_schedule_node_get_schedule(node); + umap1 = isl_schedule_get_map(schedule); + uset = isl_schedule_get_domain(schedule); + umap1 = isl_union_map_intersect_domain(umap1, uset); + isl_schedule_free(schedule); + + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); + id = isl_id_alloc(ctx, "group1", NULL); + node = isl_schedule_node_group(node, id); + node = isl_schedule_node_child(node, 1); + node = isl_schedule_node_child(node, 0); + id = isl_id_alloc(ctx, "group2", NULL); + node = isl_schedule_node_group(node, id); + + schedule = isl_schedule_node_get_schedule(node); + umap2 = isl_schedule_get_map(schedule); + isl_schedule_free(schedule); + + node = isl_schedule_node_root(node); + node = isl_schedule_node_child(node, 0); + expansion1 = isl_schedule_node_get_subtree_expansion(node); + isl_schedule_node_free(node); + + str = "{ group1[i] -> S1[i,j] : 0 <= i,j < 10; " + "group1[i] -> S2[i,j] : 0 <= i,j < 10; " + "group1[i] -> S3[i,j] : 0 <= i,j < 10 }"; + + expansion2 = isl_union_map_read_from_str(ctx, str); + + equal = isl_union_map_is_equal(umap1, umap2); + equal_expansion = isl_union_map_is_equal(expansion1, expansion2); + + isl_union_map_free(umap1); + isl_union_map_free(umap2); + isl_union_map_free(expansion1); + isl_union_map_free(expansion2); + + if (equal < 0 || equal_expansion < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "expressions not equal", return -1); + if (!equal_expansion) + isl_die(ctx, isl_error_unknown, + "unexpected expansion", return -1); + + return 0; +} + +/* Some tests for the isl_schedule_node_group function. + */ +static int test_schedule_tree_group(isl_ctx *ctx) +{ + if (test_schedule_tree_group_1(ctx) < 0) + return -1; + if (test_schedule_tree_group_2(ctx) < 0) + return -1; + return 0; +} + +struct { + const char *set; + const char *dual; +} coef_tests[] = { + { "{ rat: [i] : 0 <= i <= 10 }", + "{ rat: coefficients[[cst] -> [a]] : cst >= 0 and 10a + cst >= 0 }" }, + { "{ rat: [i] : FALSE }", + "{ rat: coefficients[[cst] -> [a]] }" }, + { "{ rat: [i] : }", + "{ rat: coefficients[[cst] -> [0]] : cst >= 0 }" }, +}; + +struct { + const char *set; + const char *dual; +} sol_tests[] = { + { "{ rat: coefficients[[cst] -> [a]] : cst >= 0 and 10a + cst >= 0 }", + "{ rat: [i] : 0 <= i <= 10 }" }, + { "{ rat: coefficients[[cst] -> [a]] : FALSE }", + "{ rat: [i] }" }, + { "{ rat: coefficients[[cst] -> [a]] }", + "{ rat: [i] : FALSE }" }, +}; + +/* Test the basic functionality of isl_basic_set_coefficients and + * isl_basic_set_solutions. + */ +static int test_dual(isl_ctx *ctx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coef_tests); ++i) { + int equal; + isl_basic_set *bset1, *bset2; + + bset1 = isl_basic_set_read_from_str(ctx, coef_tests[i].set); + bset2 = isl_basic_set_read_from_str(ctx, coef_tests[i].dual); + bset1 = isl_basic_set_coefficients(bset1); + equal = isl_basic_set_is_equal(bset1, bset2); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "incorrect dual", return -1); + } + + for (i = 0; i < ARRAY_SIZE(sol_tests); ++i) { + int equal; + isl_basic_set *bset1, *bset2; + + bset1 = isl_basic_set_read_from_str(ctx, sol_tests[i].set); + bset2 = isl_basic_set_read_from_str(ctx, sol_tests[i].dual); + bset1 = isl_basic_set_solutions(bset1); + equal = isl_basic_set_is_equal(bset1, bset2); + isl_basic_set_free(bset1); + isl_basic_set_free(bset2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "incorrect dual", return -1); + } + + return 0; +} + +struct { + int scale_tile; + int shift_point; + const char *domain; + const char *schedule; + const char *sizes; + const char *tile; + const char *point; +} tile_tests[] = { + { 0, 0, "[n] -> { S[i,j] : 0 <= i,j < n }", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + "{ [32,32] }", + "[{ S[i,j] -> [floor(i/32)] }, { S[i,j] -> [floor(j/32)] }]", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + }, + { 1, 0, "[n] -> { S[i,j] : 0 <= i,j < n }", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + "{ [32,32] }", + "[{ S[i,j] -> [32*floor(i/32)] }, { S[i,j] -> [32*floor(j/32)] }]", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + }, + { 0, 1, "[n] -> { S[i,j] : 0 <= i,j < n }", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + "{ [32,32] }", + "[{ S[i,j] -> [floor(i/32)] }, { S[i,j] -> [floor(j/32)] }]", + "[{ S[i,j] -> [i%32] }, { S[i,j] -> [j%32] }]", + }, + { 1, 1, "[n] -> { S[i,j] : 0 <= i,j < n }", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + "{ [32,32] }", + "[{ S[i,j] -> [32*floor(i/32)] }, { S[i,j] -> [32*floor(j/32)] }]", + "[{ S[i,j] -> [i%32] }, { S[i,j] -> [j%32] }]", + }, +}; + +/* Basic tiling tests. Create a schedule tree with a domain and a band node, + * tile the band and then check if the tile and point bands have the + * expected partial schedule. + */ +static int test_tile(isl_ctx *ctx) +{ + int i; + int scale; + int shift; + + scale = isl_options_get_tile_scale_tile_loops(ctx); + shift = isl_options_get_tile_shift_point_loops(ctx); + + for (i = 0; i < ARRAY_SIZE(tile_tests); ++i) { + int opt; + int equal; + const char *str; + isl_union_set *domain; + isl_multi_union_pw_aff *mupa, *mupa2; + isl_schedule_node *node; + isl_multi_val *sizes; + + opt = tile_tests[i].scale_tile; + isl_options_set_tile_scale_tile_loops(ctx, opt); + opt = tile_tests[i].shift_point; + isl_options_set_tile_shift_point_loops(ctx, opt); + + str = tile_tests[i].domain; + domain = isl_union_set_read_from_str(ctx, str); + node = isl_schedule_node_from_domain(domain); + node = isl_schedule_node_child(node, 0); + str = tile_tests[i].schedule; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + node = isl_schedule_node_insert_partial_schedule(node, mupa); + str = tile_tests[i].sizes; + sizes = isl_multi_val_read_from_str(ctx, str); + node = isl_schedule_node_band_tile(node, sizes); + + str = tile_tests[i].tile; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + mupa2 = isl_schedule_node_band_get_partial_schedule(node); + equal = isl_multi_union_pw_aff_plain_is_equal(mupa, mupa2); + isl_multi_union_pw_aff_free(mupa); + isl_multi_union_pw_aff_free(mupa2); + + node = isl_schedule_node_child(node, 0); + + str = tile_tests[i].point; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + mupa2 = isl_schedule_node_band_get_partial_schedule(node); + if (equal >= 0 && equal) + equal = isl_multi_union_pw_aff_plain_is_equal(mupa, + mupa2); + isl_multi_union_pw_aff_free(mupa); + isl_multi_union_pw_aff_free(mupa2); + + isl_schedule_node_free(node); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + isl_options_set_tile_scale_tile_loops(ctx, scale); + isl_options_set_tile_shift_point_loops(ctx, shift); + + return 0; +} + +/* Check that the domain hash of a space is equal to the hash + * of the domain of the space. + */ +static int test_domain_hash(isl_ctx *ctx) +{ + isl_map *map; + isl_space *space; + uint32_t hash1, hash2; + + map = isl_map_read_from_str(ctx, "[n] -> { A[B[x] -> C[]] -> D[] }"); + space = isl_map_get_space(map); + isl_map_free(map); + hash1 = isl_space_get_domain_hash(space); + space = isl_space_domain(space); + hash2 = isl_space_get_hash(space); + isl_space_free(space); + + if (!space) + return -1; + if (hash1 != hash2) + isl_die(ctx, isl_error_unknown, + "domain hash not equal to hash of domain", return -1); + + return 0; +} + +/* Check that a universe basic set that is not obviously equal to the universe + * is still recognized as being equal to the universe. + */ +static int test_universe(isl_ctx *ctx) +{ + const char *s; + isl_basic_set *bset; + isl_bool is_univ; + + s = "{ [] : exists x, y : 3y <= 2x and y >= -3 + 2x and 2y >= 2 - x }"; + bset = isl_basic_set_read_from_str(ctx, s); + is_univ = isl_basic_set_is_universe(bset); + isl_basic_set_free(bset); + + if (is_univ < 0) + return -1; + if (!is_univ) + isl_die(ctx, isl_error_unknown, + "not recognized as universe set", return -1); + + return 0; +} + +/* Sets for which chambers are computed and checked. + */ +const char *chambers_tests[] = { + "[A, B, C] -> { [x, y, z] : x >= 0 and y >= 0 and y <= A - x and " + "z >= 0 and z <= C - y and z <= B - x - y }", +}; + +/* Add the domain of "cell" to "cells". + */ +static isl_stat add_cell(__isl_take isl_cell *cell, void *user) +{ + isl_basic_set_list **cells = user; + isl_basic_set *dom; + + dom = isl_cell_get_domain(cell); + isl_cell_free(cell); + *cells = isl_basic_set_list_add(*cells, dom); + + return *cells ? isl_stat_ok : isl_stat_error; +} + +/* Check that the elements of "list" are pairwise disjoint. + */ +static isl_stat check_pairwise_disjoint(__isl_keep isl_basic_set_list *list) +{ + int i, j, n; + + if (!list) + return isl_stat_error; + + n = isl_basic_set_list_n_basic_set(list); + for (i = 0; i < n; ++i) { + isl_basic_set *bset_i; + + bset_i = isl_basic_set_list_get_basic_set(list, i); + for (j = i + 1; j < n; ++j) { + isl_basic_set *bset_j; + isl_bool disjoint; + + bset_j = isl_basic_set_list_get_basic_set(list, j); + disjoint = isl_basic_set_is_disjoint(bset_i, bset_j); + isl_basic_set_free(bset_j); + if (!disjoint) + isl_die(isl_basic_set_list_get_ctx(list), + isl_error_unknown, "not disjoint", + break); + if (disjoint < 0 || !disjoint) + break; + } + isl_basic_set_free(bset_i); + if (j < n) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Check that the chambers computed by isl_vertices_foreach_disjoint_cell + * are pairwise disjoint. + */ +static int test_chambers(isl_ctx *ctx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(chambers_tests); ++i) { + isl_basic_set *bset; + isl_vertices *vertices; + isl_basic_set_list *cells; + isl_stat ok; + + bset = isl_basic_set_read_from_str(ctx, chambers_tests[i]); + vertices = isl_basic_set_compute_vertices(bset); + cells = isl_basic_set_list_alloc(ctx, 0); + if (isl_vertices_foreach_disjoint_cell(vertices, &add_cell, + &cells) < 0) + cells = isl_basic_set_list_free(cells); + ok = check_pairwise_disjoint(cells); + isl_basic_set_list_free(cells); + isl_vertices_free(vertices); + isl_basic_set_free(bset); + + if (ok < 0) + return -1; + } + + return 0; +} + +struct { + const char *name; + int (*fn)(isl_ctx *ctx); +} tests [] = { + { "universe", &test_universe }, + { "domain hash", &test_domain_hash }, + { "dual", &test_dual }, + { "dependence analysis", &test_flow }, + { "val", &test_val }, + { "compute divs", &test_compute_divs }, + { "partial lexmin", &test_partial_lexmin }, + { "simplify", &test_simplify }, + { "curry", &test_curry }, + { "piecewise multi affine expressions", &test_pw_multi_aff }, + { "multi piecewise affine expressions", &test_multi_pw_aff }, + { "conversion", &test_conversion }, + { "list", &test_list }, + { "align parameters", &test_align_parameters }, + { "preimage", &test_preimage }, + { "pullback", &test_pullback }, + { "AST", &test_ast }, + { "AST build", &test_ast_build }, + { "AST generation", &test_ast_gen }, + { "eliminate", &test_eliminate }, + { "residue class", &test_residue_class }, + { "div", &test_div }, + { "slice", &test_slice }, + { "fixed power", &test_fixed_power }, + { "sample", &test_sample }, + { "output", &test_output }, + { "vertices", &test_vertices }, + { "chambers", &test_chambers }, + { "fixed", &test_fixed }, + { "equal", &test_equal }, + { "disjoint", &test_disjoint }, + { "product", &test_product }, + { "dim_max", &test_dim_max }, + { "affine", &test_aff }, + { "injective", &test_injective }, + { "schedule (whole component)", &test_schedule_whole }, + { "schedule (incremental)", &test_schedule_incremental }, + { "schedule tree grouping", &test_schedule_tree_group }, + { "tile", &test_tile }, + { "union_pw", &test_union_pw }, + { "eval", &test_eval }, + { "parse", &test_parse }, + { "single-valued", &test_sv }, + { "affine hull", &test_affine_hull }, + { "simple_hull", &test_simple_hull }, + { "coalesce", &test_coalesce }, + { "factorize", &test_factorize }, + { "subset", &test_subset }, + { "subtract", &test_subtract }, + { "intersect", &test_intersect }, + { "lexmin", &test_lexmin }, + { "min", &test_min }, + { "gist", &test_gist }, + { "piecewise quasi-polynomials", &test_pwqp }, + { "lift", &test_lift }, + { "bound", &test_bound }, + { "union", &test_union }, + { "split periods", &test_split_periods }, + { "lexicographic order", &test_lex }, + { "bijectivity", &test_bijective }, + { "dataflow analysis", &test_dep }, + { "reading", &test_read }, + { "bounded", &test_bounded }, + { "construction", &test_construction }, + { "dimension manipulation", &test_dim }, + { "map application", &test_application }, + { "convex hull", &test_convex_hull }, + { "transitive closure", &test_closure }, +}; + +int main(int argc, char **argv) +{ + int i; + struct isl_ctx *ctx; + struct isl_options *options; + + options = isl_options_new_with_defaults(); + assert(options); + argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL); + + ctx = isl_ctx_alloc_with_options(&isl_options_args, options); + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + printf("%s\n", tests[i].name); + if (tests[i].fn(ctx) < 0) + goto error; + } + isl_ctx_free(ctx); + return 0; +error: + isl_ctx_free(ctx); + return -1; +} Index: contrib/isl/isl_test_imath.c =================================================================== --- /dev/null +++ contrib/isl/isl_test_imath.c @@ -0,0 +1,79 @@ +/* + * Copyright 2015 INRIA Paris-Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Michael Kruse, INRIA Paris-Rocquencourt, + * Domaine de Voluceau, Rocquenqourt, B.P. 105, + * 78153 Le Chesnay Cedex France + */ + +#include +#include +#include + +/* This constant is not defined in limits.h, but IMath uses it */ +#define ULONG_MIN 0ul + +/* Test the IMath internals assumed by the imath implementation of isl_int. + * + * In particular, we test the ranges of IMath-defined types. + * + * Also, isl uses the existence and function of imath's struct + * fields. The digits are stored with less significant digits at lower array + * indices. Where they are stored (on the heap or in the field 'single') does + * not matter. + */ +int test_imath_internals() +{ + mpz_t val; + mp_result retval; + + assert(sizeof(mp_small) == sizeof(long)); + assert(MP_SMALL_MIN == LONG_MIN); + assert(MP_SMALL_MAX == LONG_MAX); + + assert(sizeof(mp_usmall) == sizeof(unsigned long)); + assert(MP_USMALL_MIN == ULONG_MIN); + assert(MP_USMALL_MAX == ULONG_MAX); + + retval = mp_int_init_value(&val, 0); + assert(retval == MP_OK); + assert(val.alloc >= val.used); + assert(val.used == 1); + assert(val.sign == MP_ZPOS); + assert(val.digits[0] == 0); + + retval = mp_int_set_value(&val, -1); + assert(retval == MP_OK); + assert(val.alloc >= val.used); + assert(val.used == 1); + assert(val.sign == MP_NEG); + assert(val.digits[0] == 1); + + retval = mp_int_set_value(&val, 1); + assert(retval == MP_OK); + assert(val.alloc >= val.used); + assert(val.used == 1); + assert(val.sign == MP_ZPOS); + assert(val.digits[0] == 1); + + retval = mp_int_mul_pow2(&val, sizeof(mp_digit) * CHAR_BIT, &val); + assert(retval == MP_OK); + assert(val.alloc >= val.used); + assert(val.used == 2); + assert(val.sign == MP_ZPOS); + assert(val.digits[0] == 0); + assert(val.digits[1] == 1); + + mp_int_clear(&val); + return 0; +} + +int main() +{ + if (test_imath_internals() < 0) + return -1; + + return 0; +} Index: contrib/isl/isl_test_int.c =================================================================== --- /dev/null +++ contrib/isl/isl_test_int.c @@ -0,0 +1,669 @@ +/* + * Copyright 2015 INRIA Paris-Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Michael Kruse, INRIA Paris-Rocquencourt, + * Domaine de Voluceau, Rocquenqourt, B.P. 105, + * 78153 Le Chesnay Cedex France + */ + +#include +#include +#include + +#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array)) + +#ifdef USE_SMALL_INT_OPT +/* Test whether small and big representation of the same number have the same + * hash. + */ +static void int_test_hash(isl_int val) +{ + uint32_t demotedhash, promotedhash; + isl_int demoted, promoted; + + isl_int_init(demoted); + isl_int_set(demoted, val); + + isl_int_init(promoted); + isl_int_set(promoted, val); + + isl_sioimath_try_demote(demoted); + isl_sioimath_promote(promoted); + + assert(isl_int_eq(demoted, promoted)); + + demotedhash = isl_int_hash(demoted, 0); + promotedhash = isl_int_hash(promoted, 0); + assert(demotedhash == promotedhash); + + isl_int_clear(demoted); + isl_int_clear(promoted); +} + +struct { + void (*fn)(isl_int); + char *val; +} int_single_value_tests[] = { + { &int_test_hash, "0" }, + { &int_test_hash, "1" }, + { &int_test_hash, "-1" }, + { &int_test_hash, "23" }, + { &int_test_hash, "-23" }, + { &int_test_hash, "107" }, + { &int_test_hash, "32768" }, + { &int_test_hash, "2147483647" }, + { &int_test_hash, "-2147483647" }, + { &int_test_hash, "2147483648" }, + { &int_test_hash, "-2147483648" }, +}; + +static void int_test_single_value() +{ + int i; + + for (i = 0; i < ARRAY_SIZE(int_single_value_tests); i += 1) { + isl_int val; + + isl_int_init(val); + isl_int_read(val, int_single_value_tests[i].val); + + (*int_single_value_tests[i].fn)(val); + + isl_int_clear(val); + } +} + +static void invoke_alternate_representations_2args(char *arg1, char *arg2, + void (*fn)(isl_int, isl_int)) +{ + int j; + isl_int int1, int2; + + isl_int_init(int1); + isl_int_init(int2); + + for (j = 0; j < 4; ++j) { + isl_int_read(int1, arg1); + isl_int_read(int2, arg2); + + if (j & 1) + isl_sioimath_promote(int1); + else + isl_sioimath_try_demote(int1); + + if (j & 2) + isl_sioimath_promote(int2); + else + isl_sioimath_try_demote(int2); + + (*fn)(int1, int2); + } + + isl_int_clear(int1); + isl_int_clear(int2); +} + +static void invoke_alternate_representations_3args(char *arg1, char *arg2, + char *arg3, void (*fn)(isl_int, isl_int, isl_int)) +{ + int j; + isl_int int1, int2, int3; + + isl_int_init(int1); + isl_int_init(int2); + isl_int_init(int3); + + for (j = 0; j < 8; ++j) { + isl_int_read(int1, arg1); + isl_int_read(int2, arg2); + isl_int_read(int3, arg3); + + if (j & 1) + isl_sioimath_promote(int1); + else + isl_sioimath_try_demote(int1); + + if (j & 2) + isl_sioimath_promote(int2); + else + isl_sioimath_try_demote(int2); + + if (j & 4) + isl_sioimath_promote(int3); + else + isl_sioimath_try_demote(int3); + + (*fn)(int1, int2, int3); + } + + isl_int_clear(int1); + isl_int_clear(int2); + isl_int_clear(int3); +} +#else /* USE_SMALL_INT_OPT */ + +static void int_test_single_value() +{ +} + +static void invoke_alternate_representations_2args(char *arg1, char *arg2, + void (*fn)(isl_int, isl_int)) +{ + isl_int int1, int2; + + isl_int_init(int1); + isl_int_init(int2); + + isl_int_read(int1, arg1); + isl_int_read(int2, arg2); + + (*fn)(int1, int2); + + isl_int_clear(int1); + isl_int_clear(int2); +} + +static void invoke_alternate_representations_3args(char *arg1, char *arg2, + char *arg3, void (*fn)(isl_int, isl_int, isl_int)) +{ + isl_int int1, int2, int3; + + isl_int_init(int1); + isl_int_init(int2); + isl_int_init(int3); + + isl_int_read(int1, arg1); + isl_int_read(int2, arg2); + isl_int_read(int3, arg3); + + (*fn)(int1, int2, int3); + + isl_int_clear(int1); + isl_int_clear(int2); + isl_int_clear(int3); +} +#endif /* USE_SMALL_INT_OPT */ + +static void int_test_neg(isl_int expected, isl_int arg) +{ + isl_int result; + isl_int_init(result); + + isl_int_neg(result, arg); + assert(isl_int_eq(result, expected)); + + isl_int_neg(result, expected); + assert(isl_int_eq(result, arg)); + + isl_int_clear(result); +} + +static void int_test_abs(isl_int expected, isl_int arg) +{ + isl_int result; + isl_int_init(result); + + isl_int_abs(result, arg); + assert(isl_int_eq(result, expected)); + + isl_int_clear(result); +} + +struct { + void (*fn)(isl_int, isl_int); + char *expected, *arg; +} int_unary_tests[] = { + { &int_test_neg, "0", "0" }, + { &int_test_neg, "-1", "1" }, + { &int_test_neg, "-2147483647", "2147483647" }, + { &int_test_neg, "-2147483648", "2147483648" }, + { &int_test_neg, "-9223372036854775807", "9223372036854775807" }, + { &int_test_neg, "-9223372036854775808", "9223372036854775808" }, + + { &int_test_abs, "0", "0" }, + { &int_test_abs, "1", "1" }, + { &int_test_abs, "1", "-1" }, + { &int_test_abs, "2147483647", "2147483647" }, + { &int_test_abs, "2147483648", "-2147483648" }, + { &int_test_abs, "9223372036854775807", "9223372036854775807" }, + { &int_test_abs, "9223372036854775808", "-9223372036854775808" }, +}; + +static void int_test_divexact(isl_int expected, isl_int lhs, isl_int rhs) +{ + isl_int result; + unsigned long rhsulong; + + if (isl_int_sgn(rhs) == 0) + return; + + isl_int_init(result); + + isl_int_divexact(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_tdiv_q(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_fdiv_q(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_cdiv_q(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + if (isl_int_fits_ulong(rhs)) { + rhsulong = isl_int_get_ui(rhs); + + isl_int_divexact_ui(result, lhs, rhsulong); + assert(isl_int_eq(expected, result)); + + isl_int_fdiv_q_ui(result, lhs, rhsulong); + assert(isl_int_eq(expected, result)); + + isl_int_cdiv_q_ui(result, lhs, rhsulong); + assert(isl_int_eq(expected, result)); + } + + isl_int_clear(result); +} + +static void int_test_mul(isl_int expected, isl_int lhs, isl_int rhs) +{ + isl_int result; + isl_int_init(result); + + isl_int_mul(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + if (isl_int_fits_ulong(rhs)) { + unsigned long rhsulong = isl_int_get_ui(rhs); + + isl_int_mul_ui(result, lhs, rhsulong); + assert(isl_int_eq(expected, result)); + } + + if (isl_int_fits_slong(rhs)) { + unsigned long rhsslong = isl_int_get_si(rhs); + + isl_int_mul_si(result, lhs, rhsslong); + assert(isl_int_eq(expected, result)); + } + + isl_int_clear(result); +} + +/* Use a triple that satisfies 'product = factor1 * factor2' to check the + * operations mul, divexact, tdiv, fdiv and cdiv. + */ +static void int_test_product(isl_int product, isl_int factor1, isl_int factor2) +{ + int_test_divexact(factor1, product, factor2); + int_test_divexact(factor2, product, factor1); + + int_test_mul(product, factor1, factor2); + int_test_mul(product, factor2, factor1); +} + +static void int_test_add(isl_int expected, isl_int lhs, isl_int rhs) +{ + isl_int result; + isl_int_init(result); + + isl_int_add(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_clear(result); +} + +static void int_test_sub(isl_int expected, isl_int lhs, isl_int rhs) +{ + isl_int result; + isl_int_init(result); + + isl_int_sub(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_clear(result); +} + +/* Use a triple that satisfies 'sum = term1 + term2' to check the operations add + * and sub. + */ +static void int_test_sum(isl_int sum, isl_int term1, isl_int term2) +{ + int_test_sub(term1, sum, term2); + int_test_sub(term2, sum, term1); + + int_test_add(sum, term1, term2); + int_test_add(sum, term2, term1); +} + +static void int_test_fdiv(isl_int expected, isl_int lhs, isl_int rhs) +{ + unsigned long rhsulong; + isl_int result; + isl_int_init(result); + + isl_int_fdiv_q(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + if (isl_int_fits_ulong(rhs)) { + rhsulong = isl_int_get_ui(rhs); + + isl_int_fdiv_q_ui(result, lhs, rhsulong); + assert(isl_int_eq(expected, result)); + } + + isl_int_clear(result); +} + +static void int_test_cdiv(isl_int expected, isl_int lhs, isl_int rhs) +{ + unsigned long rhsulong; + isl_int result; + isl_int_init(result); + + isl_int_cdiv_q(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + if (isl_int_fits_ulong(rhs)) { + rhsulong = isl_int_get_ui(rhs); + + isl_int_cdiv_q_ui(result, lhs, rhsulong); + assert(isl_int_eq(expected, result)); + } + + isl_int_clear(result); +} + +static void int_test_tdiv(isl_int expected, isl_int lhs, isl_int rhs) +{ + isl_int result; + isl_int_init(result); + + isl_int_tdiv_q(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_clear(result); +} + +static void int_test_fdiv_r(isl_int expected, isl_int lhs, isl_int rhs) +{ + isl_int result; + isl_int_init(result); + + isl_int_fdiv_r(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_clear(result); +} + +static void int_test_gcd(isl_int expected, isl_int lhs, isl_int rhs) +{ + isl_int result; + isl_int_init(result); + + isl_int_gcd(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_gcd(result, rhs, lhs); + assert(isl_int_eq(expected, result)); + + isl_int_clear(result); +} + +static void int_test_lcm(isl_int expected, isl_int lhs, isl_int rhs) +{ + isl_int result; + isl_int_init(result); + + isl_int_lcm(result, lhs, rhs); + assert(isl_int_eq(expected, result)); + + isl_int_lcm(result, rhs, lhs); + assert(isl_int_eq(expected, result)); + + isl_int_clear(result); +} + +static int sgn(int val) +{ + if (val > 0) + return 1; + if (val < 0) + return -1; + return 0; +} + +static void int_test_cmp(int exp, isl_int lhs, isl_int rhs) +{ + long rhslong; + + assert(exp == sgn(isl_int_cmp(lhs, rhs))); + + if (isl_int_fits_slong(rhs)) { + rhslong = isl_int_get_si(rhs); + assert(exp == sgn(isl_int_cmp_si(lhs, rhslong))); + } +} + +/* Test the comparison relations over two numbers. + * expected is the sign (1, 0 or -1) of 'lhs - rhs'. + */ +static void int_test_cmps(isl_int expected, isl_int lhs, isl_int rhs) +{ + int exp; + isl_int diff; + + exp = isl_int_get_si(expected); + + isl_int_init(diff); + isl_int_sub(diff, lhs, rhs); + assert(exp == isl_int_sgn(diff)); + isl_int_clear(diff); + + int_test_cmp(exp, lhs, rhs); + int_test_cmp(-exp, rhs, lhs); +} + +static void int_test_abs_cmp(isl_int expected, isl_int lhs, isl_int rhs) +{ + int exp; + + exp = isl_int_get_si(expected); + assert(exp == sgn(isl_int_abs_cmp(lhs, rhs))); + assert(-exp == sgn(isl_int_abs_cmp(rhs, lhs))); +} + +/* If "expected" is equal to 1, then check that "rhs" divides "lhs". + * If "expected" is equal to 0, then check that "rhs" does not divide "lhs". + */ +static void int_test_divisible(isl_int expected, isl_int lhs, isl_int rhs) +{ + int exp; + + exp = isl_int_get_si(expected); + assert(isl_int_is_divisible_by(lhs, rhs) == exp); +} + +struct { + void (*fn)(isl_int, isl_int, isl_int); + char *expected, *lhs, *rhs; +} int_binary_tests[] = { + { &int_test_sum, "0", "0", "0" }, + { &int_test_sum, "1", "1", "0" }, + { &int_test_sum, "2", "1", "1" }, + { &int_test_sum, "-1", "0", "-1" }, + { &int_test_sum, "-2", "-1", "-1" }, + + { &int_test_sum, "2147483647", "1073741823", "1073741824" }, + { &int_test_sum, "-2147483648", "-1073741824", "-1073741824" }, + + { &int_test_sum, "2147483648", "2147483647", "1" }, + { &int_test_sum, "-2147483648", "-2147483647", "-1" }, + + { &int_test_product, "0", "0", "0" }, + { &int_test_product, "0", "0", "1" }, + { &int_test_product, "1", "1", "1" }, + + { &int_test_product, "6", "2", "3" }, + { &int_test_product, "-6", "2", "-3" }, + { &int_test_product, "-6", "-2", "3" }, + { &int_test_product, "6", "-2", "-3" }, + + { &int_test_product, "2147483648", "65536", "32768" }, + { &int_test_product, "-2147483648", "65536", "-32768" }, + + { &int_test_product, + "4611686014132420609", "2147483647", "2147483647" }, + { &int_test_product, + "-4611686014132420609", "-2147483647", "2147483647" }, + + { &int_test_product, + "4611686016279904256", "2147483647", "2147483648" }, + { &int_test_product, + "-4611686016279904256", "-2147483647", "2147483648" }, + { &int_test_product, + "-4611686016279904256", "2147483647", "-2147483648" }, + { &int_test_product, + "4611686016279904256", "-2147483647", "-2147483648" }, + + { &int_test_product, "85070591730234615847396907784232501249", + "9223372036854775807", "9223372036854775807" }, + { &int_test_product, "-85070591730234615847396907784232501249", + "-9223372036854775807", "9223372036854775807" }, + + { &int_test_product, "85070591730234615856620279821087277056", + "9223372036854775807", "9223372036854775808" }, + { &int_test_product, "-85070591730234615856620279821087277056", + "-9223372036854775807", "9223372036854775808" }, + { &int_test_product, "-85070591730234615856620279821087277056", + "9223372036854775807", "-9223372036854775808" }, + { &int_test_product, "85070591730234615856620279821087277056", + "-9223372036854775807", "-9223372036854775808" }, + + { &int_test_product, "340282366920938463426481119284349108225", + "18446744073709551615", "18446744073709551615" }, + { &int_test_product, "-340282366920938463426481119284349108225", + "-18446744073709551615", "18446744073709551615" }, + + { &int_test_product, "340282366920938463444927863358058659840", + "18446744073709551615", "18446744073709551616" }, + { &int_test_product, "-340282366920938463444927863358058659840", + "-18446744073709551615", "18446744073709551616" }, + { &int_test_product, "-340282366920938463444927863358058659840", + "18446744073709551615", "-18446744073709551616" }, + { &int_test_product, "340282366920938463444927863358058659840", + "-18446744073709551615", "-18446744073709551616" }, + + { &int_test_fdiv, "0", "1", "2" }, + { &int_test_fdiv_r, "1", "1", "3" }, + { &int_test_fdiv, "-1", "-1", "2" }, + { &int_test_fdiv_r, "2", "-1", "3" }, + { &int_test_fdiv, "-1", "1", "-2" }, + { &int_test_fdiv_r, "-2", "1", "-3" }, + { &int_test_fdiv, "0", "-1", "-2" }, + { &int_test_fdiv_r, "-1", "-1", "-3" }, + + { &int_test_cdiv, "1", "1", "2" }, + { &int_test_cdiv, "0", "-1", "2" }, + { &int_test_cdiv, "0", "1", "-2" }, + { &int_test_cdiv, "1", "-1", "-2" }, + + { &int_test_cdiv, "1073741824", "2147483647", "2" }, + { &int_test_cdiv, "1073741824", "2147483648", "2" }, + { &int_test_cdiv, "-1073741824", "-2147483648", "2" }, + { &int_test_cdiv, "-1073741823", "-2147483647", "2" }, + + { &int_test_tdiv, "0", "1", "2" }, + { &int_test_tdiv, "0", "-1", "2" }, + { &int_test_tdiv, "0", "1", "-2" }, + { &int_test_tdiv, "0", "-1", "-2" }, + + { &int_test_gcd, "0", "0", "0" }, + { &int_test_lcm, "0", "0", "0" }, + { &int_test_gcd, "7", "0", "7" }, + { &int_test_lcm, "0", "0", "7" }, + { &int_test_gcd, "1", "1", "1" }, + { &int_test_lcm, "1", "1", "1" }, + { &int_test_gcd, "1", "1", "-1" }, + { &int_test_lcm, "1", "1", "-1" }, + { &int_test_gcd, "1", "-1", "-1" }, + { &int_test_lcm, "1", "-1", "-1" }, + { &int_test_gcd, "3", "6", "9" }, + { &int_test_lcm, "18", "6", "9" }, + { &int_test_gcd, "1", "14", "2147483647" }, + { &int_test_lcm, "15032385529", "7", "2147483647" }, + { &int_test_gcd, "2", "6", "-2147483648" }, + { &int_test_lcm, "6442450944", "6", "-2147483648" }, + { &int_test_gcd, "1", "6", "9223372036854775807" }, + { &int_test_lcm, "55340232221128654842", "6", "9223372036854775807" }, + { &int_test_gcd, "2", "6", "-9223372036854775808" }, + { &int_test_lcm, "27670116110564327424", "6", "-9223372036854775808" }, + { &int_test_gcd, "1", "18446744073709551616", "18446744073709551615" }, + { &int_test_lcm, "340282366920938463444927863358058659840", + "18446744073709551616", "18446744073709551615" }, + + { &int_test_cmps, "0", "0", "0" }, + { &int_test_abs_cmp, "0", "0", "0" }, + { &int_test_cmps, "1", "1", "0" }, + { &int_test_abs_cmp, "1", "1", "0" }, + { &int_test_cmps, "-1", "-1", "0" }, + { &int_test_abs_cmp, "1", "-1", "0" }, + { &int_test_cmps, "-1", "-1", "1" }, + { &int_test_abs_cmp, "0", "-1", "1" }, + + { &int_test_cmps, "-1", "5", "2147483647" }, + { &int_test_abs_cmp, "-1", "5", "2147483647" }, + { &int_test_cmps, "1", "5", "-2147483648" }, + { &int_test_abs_cmp, "-1", "5", "-2147483648" }, + { &int_test_cmps, "-1", "5", "9223372036854775807" }, + { &int_test_abs_cmp, "-1", "5", "9223372036854775807" }, + { &int_test_cmps, "1", "5", "-9223372036854775809" }, + { &int_test_abs_cmp, "-1", "5", "-9223372036854775809" }, + + { &int_test_divisible, "1", "0", "0" }, + { &int_test_divisible, "0", "1", "0" }, + { &int_test_divisible, "0", "2", "0" }, + { &int_test_divisible, "0", "2147483647", "0" }, + { &int_test_divisible, "0", "9223372036854775807", "0" }, + { &int_test_divisible, "1", "0", "1" }, + { &int_test_divisible, "1", "1", "1" }, + { &int_test_divisible, "1", "2", "1" }, + { &int_test_divisible, "1", "2147483647", "1" }, + { &int_test_divisible, "1", "9223372036854775807", "1" }, + { &int_test_divisible, "1", "0", "2" }, + { &int_test_divisible, "0", "1", "2" }, + { &int_test_divisible, "1", "2", "2" }, + { &int_test_divisible, "0", "2147483647", "2" }, + { &int_test_divisible, "0", "9223372036854775807", "2" }, +}; + +/* Tests the isl_int_* function to give the expected results. Tests are + * grouped by the number of arguments they take. + * + * If small integer optimization is enabled, we also test whether the results + * are the same in small and big representation. + */ +int main() +{ + int i; + + int_test_single_value(); + + for (i = 0; i < ARRAY_SIZE(int_unary_tests); i += 1) { + invoke_alternate_representations_2args( + int_unary_tests[i].expected, int_unary_tests[i].arg, + int_unary_tests[i].fn); + } + + for (i = 0; i < ARRAY_SIZE(int_binary_tests); i += 1) { + invoke_alternate_representations_3args( + int_binary_tests[i].expected, int_binary_tests[i].lhs, + int_binary_tests[i].rhs, int_binary_tests[i].fn); + } + + return 0; +} Index: contrib/isl/isl_transitive_closure.c =================================================================== --- /dev/null +++ contrib/isl/isl_transitive_closure.c @@ -0,0 +1,2948 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int isl_map_is_transitively_closed(__isl_keep isl_map *map) +{ + isl_map *map2; + int closed; + + map2 = isl_map_apply_range(isl_map_copy(map), isl_map_copy(map)); + closed = isl_map_is_subset(map2, map); + isl_map_free(map2); + + return closed; +} + +int isl_union_map_is_transitively_closed(__isl_keep isl_union_map *umap) +{ + isl_union_map *umap2; + int closed; + + umap2 = isl_union_map_apply_range(isl_union_map_copy(umap), + isl_union_map_copy(umap)); + closed = isl_union_map_is_subset(umap2, umap); + isl_union_map_free(umap2); + + return closed; +} + +/* Given a map that represents a path with the length of the path + * encoded as the difference between the last output coordindate + * and the last input coordinate, set this length to either + * exactly "length" (if "exactly" is set) or at least "length" + * (if "exactly" is not set). + */ +static __isl_give isl_map *set_path_length(__isl_take isl_map *map, + int exactly, int length) +{ + isl_space *dim; + struct isl_basic_map *bmap; + unsigned d; + unsigned nparam; + int k; + isl_int *c; + + if (!map) + return NULL; + + dim = isl_map_get_space(map); + d = isl_space_dim(dim, isl_dim_in); + nparam = isl_space_dim(dim, isl_dim_param); + bmap = isl_basic_map_alloc_space(dim, 0, 1, 1); + if (exactly) { + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + c = bmap->eq[k]; + } else { + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + c = bmap->ineq[k]; + } + isl_seq_clr(c, 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(c[0], -length); + isl_int_set_si(c[1 + nparam + d - 1], -1); + isl_int_set_si(c[1 + nparam + d + d - 1], 1); + + bmap = isl_basic_map_finalize(bmap); + map = isl_map_intersect(map, isl_map_from_basic_map(bmap)); + + return map; +error: + isl_basic_map_free(bmap); + isl_map_free(map); + return NULL; +} + +/* Check whether the overapproximation of the power of "map" is exactly + * the power of "map". Let R be "map" and A_k the overapproximation. + * The approximation is exact if + * + * A_1 = R + * A_k = A_{k-1} \circ R k >= 2 + * + * Since A_k is known to be an overapproximation, we only need to check + * + * A_1 \subset R + * A_k \subset A_{k-1} \circ R k >= 2 + * + * In practice, "app" has an extra input and output coordinate + * to encode the length of the path. So, we first need to add + * this coordinate to "map" and set the length of the path to + * one. + */ +static int check_power_exactness(__isl_take isl_map *map, + __isl_take isl_map *app) +{ + int exact; + isl_map *app_1; + isl_map *app_2; + + map = isl_map_add_dims(map, isl_dim_in, 1); + map = isl_map_add_dims(map, isl_dim_out, 1); + map = set_path_length(map, 1, 1); + + app_1 = set_path_length(isl_map_copy(app), 1, 1); + + exact = isl_map_is_subset(app_1, map); + isl_map_free(app_1); + + if (!exact || exact < 0) { + isl_map_free(app); + isl_map_free(map); + return exact; + } + + app_1 = set_path_length(isl_map_copy(app), 0, 1); + app_2 = set_path_length(app, 0, 2); + app_1 = isl_map_apply_range(map, app_1); + + exact = isl_map_is_subset(app_2, app_1); + + isl_map_free(app_1); + isl_map_free(app_2); + + return exact; +} + +/* Check whether the overapproximation of the power of "map" is exactly + * the power of "map", possibly after projecting out the power (if "project" + * is set). + * + * If "project" is set and if "steps" can only result in acyclic paths, + * then we check + * + * A = R \cup (A \circ R) + * + * where A is the overapproximation with the power projected out, i.e., + * an overapproximation of the transitive closure. + * More specifically, since A is known to be an overapproximation, we check + * + * A \subset R \cup (A \circ R) + * + * Otherwise, we check if the power is exact. + * + * Note that "app" has an extra input and output coordinate to encode + * the length of the part. If we are only interested in the transitive + * closure, then we can simply project out these coordinates first. + */ +static int check_exactness(__isl_take isl_map *map, __isl_take isl_map *app, + int project) +{ + isl_map *test; + int exact; + unsigned d; + + if (!project) + return check_power_exactness(map, app); + + d = isl_map_dim(map, isl_dim_in); + app = set_path_length(app, 0, 1); + app = isl_map_project_out(app, isl_dim_in, d, 1); + app = isl_map_project_out(app, isl_dim_out, d, 1); + + app = isl_map_reset_space(app, isl_map_get_space(map)); + + test = isl_map_apply_range(isl_map_copy(map), isl_map_copy(app)); + test = isl_map_union(test, isl_map_copy(map)); + + exact = isl_map_is_subset(app, test); + + isl_map_free(app); + isl_map_free(test); + + isl_map_free(map); + + return exact; +} + +/* + * The transitive closure implementation is based on the paper + * "Computing the Transitive Closure of a Union of Affine Integer + * Tuple Relations" by Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and + * Albert Cohen. + */ + +/* Given a set of n offsets v_i (the rows of "steps"), construct a relation + * of the given dimension specification (Z^{n+1} -> Z^{n+1}) + * that maps an element x to any element that can be reached + * by taking a non-negative number of steps along any of + * the extended offsets v'_i = [v_i 1]. + * That is, construct + * + * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v'_i } + * + * For any element in this relation, the number of steps taken + * is equal to the difference in the final coordinates. + */ +static __isl_give isl_map *path_along_steps(__isl_take isl_space *dim, + __isl_keep isl_mat *steps) +{ + int i, j, k; + struct isl_basic_map *path = NULL; + unsigned d; + unsigned n; + unsigned nparam; + + if (!dim || !steps) + goto error; + + d = isl_space_dim(dim, isl_dim_in); + n = steps->n_row; + nparam = isl_space_dim(dim, isl_dim_param); + + path = isl_basic_map_alloc_space(isl_space_copy(dim), n, d, n); + + for (i = 0; i < n; ++i) { + k = isl_basic_map_alloc_div(path); + if (k < 0) + goto error; + isl_assert(steps->ctx, i == k, goto error); + isl_int_set_si(path->div[k][0], 0); + } + + for (i = 0; i < d; ++i) { + k = isl_basic_map_alloc_equality(path); + if (k < 0) + goto error; + isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path)); + isl_int_set_si(path->eq[k][1 + nparam + i], 1); + isl_int_set_si(path->eq[k][1 + nparam + d + i], -1); + if (i == d - 1) + for (j = 0; j < n; ++j) + isl_int_set_si(path->eq[k][1 + nparam + 2 * d + j], 1); + else + for (j = 0; j < n; ++j) + isl_int_set(path->eq[k][1 + nparam + 2 * d + j], + steps->row[j][i]); + } + + for (i = 0; i < n; ++i) { + k = isl_basic_map_alloc_inequality(path); + if (k < 0) + goto error; + isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path)); + isl_int_set_si(path->ineq[k][1 + nparam + 2 * d + i], 1); + } + + isl_space_free(dim); + + path = isl_basic_map_simplify(path); + path = isl_basic_map_finalize(path); + return isl_map_from_basic_map(path); +error: + isl_space_free(dim); + isl_basic_map_free(path); + return NULL; +} + +#define IMPURE 0 +#define PURE_PARAM 1 +#define PURE_VAR 2 +#define MIXED 3 + +/* Check whether the parametric constant term of constraint c is never + * positive in "bset". + */ +static isl_bool parametric_constant_never_positive( + __isl_keep isl_basic_set *bset, isl_int *c, int *div_purity) +{ + unsigned d; + unsigned n_div; + unsigned nparam; + int i; + int k; + isl_bool empty; + + n_div = isl_basic_set_dim(bset, isl_dim_div); + d = isl_basic_set_dim(bset, isl_dim_set); + nparam = isl_basic_set_dim(bset, isl_dim_param); + + bset = isl_basic_set_copy(bset); + bset = isl_basic_set_cow(bset); + bset = isl_basic_set_extend_constraints(bset, 0, 1); + k = isl_basic_set_alloc_inequality(bset); + if (k < 0) + goto error; + isl_seq_clr(bset->ineq[k], 1 + isl_basic_set_total_dim(bset)); + isl_seq_cpy(bset->ineq[k], c, 1 + nparam); + for (i = 0; i < n_div; ++i) { + if (div_purity[i] != PURE_PARAM) + continue; + isl_int_set(bset->ineq[k][1 + nparam + d + i], + c[1 + nparam + d + i]); + } + isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1); + empty = isl_basic_set_is_empty(bset); + isl_basic_set_free(bset); + + return empty; +error: + isl_basic_set_free(bset); + return isl_bool_error; +} + +/* Return PURE_PARAM if only the coefficients of the parameters are non-zero. + * Return PURE_VAR if only the coefficients of the set variables are non-zero. + * Return MIXED if only the coefficients of the parameters and the set + * variables are non-zero and if moreover the parametric constant + * can never attain positive values. + * Return IMPURE otherwise. + */ +static int purity(__isl_keep isl_basic_set *bset, isl_int *c, int *div_purity, + int eq) +{ + unsigned d; + unsigned n_div; + unsigned nparam; + isl_bool empty; + int i; + int p = 0, v = 0; + + n_div = isl_basic_set_dim(bset, isl_dim_div); + d = isl_basic_set_dim(bset, isl_dim_set); + nparam = isl_basic_set_dim(bset, isl_dim_param); + + for (i = 0; i < n_div; ++i) { + if (isl_int_is_zero(c[1 + nparam + d + i])) + continue; + switch (div_purity[i]) { + case PURE_PARAM: p = 1; break; + case PURE_VAR: v = 1; break; + default: return IMPURE; + } + } + if (!p && isl_seq_first_non_zero(c + 1, nparam) == -1) + return PURE_VAR; + if (!v && isl_seq_first_non_zero(c + 1 + nparam, d) == -1) + return PURE_PARAM; + + empty = parametric_constant_never_positive(bset, c, div_purity); + if (eq && empty >= 0 && !empty) { + isl_seq_neg(c, c, 1 + nparam + d + n_div); + empty = parametric_constant_never_positive(bset, c, div_purity); + } + + return empty < 0 ? -1 : empty ? MIXED : IMPURE; +} + +/* Return an array of integers indicating the type of each div in bset. + * If the div is (recursively) defined in terms of only the parameters, + * then the type is PURE_PARAM. + * If the div is (recursively) defined in terms of only the set variables, + * then the type is PURE_VAR. + * Otherwise, the type is IMPURE. + */ +static __isl_give int *get_div_purity(__isl_keep isl_basic_set *bset) +{ + int i, j; + int *div_purity; + unsigned d; + unsigned n_div; + unsigned nparam; + + if (!bset) + return NULL; + + n_div = isl_basic_set_dim(bset, isl_dim_div); + d = isl_basic_set_dim(bset, isl_dim_set); + nparam = isl_basic_set_dim(bset, isl_dim_param); + + div_purity = isl_alloc_array(bset->ctx, int, n_div); + if (n_div && !div_purity) + return NULL; + + for (i = 0; i < bset->n_div; ++i) { + int p = 0, v = 0; + if (isl_int_is_zero(bset->div[i][0])) { + div_purity[i] = IMPURE; + continue; + } + if (isl_seq_first_non_zero(bset->div[i] + 2, nparam) != -1) + p = 1; + if (isl_seq_first_non_zero(bset->div[i] + 2 + nparam, d) != -1) + v = 1; + for (j = 0; j < i; ++j) { + if (isl_int_is_zero(bset->div[i][2 + nparam + d + j])) + continue; + switch (div_purity[j]) { + case PURE_PARAM: p = 1; break; + case PURE_VAR: v = 1; break; + default: p = v = 1; break; + } + } + div_purity[i] = v ? p ? IMPURE : PURE_VAR : PURE_PARAM; + } + + return div_purity; +} + +/* Given a path with the as yet unconstrained length at position "pos", + * check if setting the length to zero results in only the identity + * mapping. + */ +static int empty_path_is_identity(__isl_keep isl_basic_map *path, unsigned pos) +{ + isl_basic_map *test = NULL; + isl_basic_map *id = NULL; + int k; + int is_id; + + test = isl_basic_map_copy(path); + test = isl_basic_map_extend_constraints(test, 1, 0); + k = isl_basic_map_alloc_equality(test); + if (k < 0) + goto error; + isl_seq_clr(test->eq[k], 1 + isl_basic_map_total_dim(test)); + isl_int_set_si(test->eq[k][pos], 1); + test = isl_basic_map_gauss(test, NULL); + id = isl_basic_map_identity(isl_basic_map_get_space(path)); + is_id = isl_basic_map_is_equal(test, id); + isl_basic_map_free(test); + isl_basic_map_free(id); + return is_id; +error: + isl_basic_map_free(test); + return -1; +} + +/* If any of the constraints is found to be impure then this function + * sets *impurity to 1. + * + * If impurity is NULL then we are dealing with a non-parametric set + * and so the constraints are obviously PURE_VAR. + */ +static __isl_give isl_basic_map *add_delta_constraints( + __isl_take isl_basic_map *path, + __isl_keep isl_basic_set *delta, unsigned off, unsigned nparam, + unsigned d, int *div_purity, int eq, int *impurity) +{ + int i, k; + int n = eq ? delta->n_eq : delta->n_ineq; + isl_int **delta_c = eq ? delta->eq : delta->ineq; + unsigned n_div; + + n_div = isl_basic_set_dim(delta, isl_dim_div); + + for (i = 0; i < n; ++i) { + isl_int *path_c; + int p = PURE_VAR; + if (impurity) + p = purity(delta, delta_c[i], div_purity, eq); + if (p < 0) + goto error; + if (p != PURE_VAR && p != PURE_PARAM && !*impurity) + *impurity = 1; + if (p == IMPURE) + continue; + if (eq && p != MIXED) { + k = isl_basic_map_alloc_equality(path); + if (k < 0) + goto error; + path_c = path->eq[k]; + } else { + k = isl_basic_map_alloc_inequality(path); + if (k < 0) + goto error; + path_c = path->ineq[k]; + } + isl_seq_clr(path_c, 1 + isl_basic_map_total_dim(path)); + if (p == PURE_VAR) { + isl_seq_cpy(path_c + off, + delta_c[i] + 1 + nparam, d); + isl_int_set(path_c[off + d], delta_c[i][0]); + } else if (p == PURE_PARAM) { + isl_seq_cpy(path_c, delta_c[i], 1 + nparam); + } else { + isl_seq_cpy(path_c + off, + delta_c[i] + 1 + nparam, d); + isl_seq_cpy(path_c, delta_c[i], 1 + nparam); + } + isl_seq_cpy(path_c + off - n_div, + delta_c[i] + 1 + nparam + d, n_div); + } + + return path; +error: + isl_basic_map_free(path); + return NULL; +} + +/* Given a set of offsets "delta", construct a relation of the + * given dimension specification (Z^{n+1} -> Z^{n+1}) that + * is an overapproximation of the relations that + * maps an element x to any element that can be reached + * by taking a non-negative number of steps along any of + * the elements in "delta". + * That is, construct an approximation of + * + * { [x] -> [y] : exists f \in \delta, k \in Z : + * y = x + k [f, 1] and k >= 0 } + * + * For any element in this relation, the number of steps taken + * is equal to the difference in the final coordinates. + * + * In particular, let delta be defined as + * + * \delta = [p] -> { [x] : A x + a >= 0 and B p + b >= 0 and + * C x + C'p + c >= 0 and + * D x + D'p + d >= 0 } + * + * where the constraints C x + C'p + c >= 0 are such that the parametric + * constant term of each constraint j, "C_j x + C'_j p + c_j", + * can never attain positive values, then the relation is constructed as + * + * { [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and + * A f + k a >= 0 and B p + b >= 0 and + * C f + C'p + c >= 0 and k >= 1 } + * union { [x] -> [x] } + * + * If the zero-length paths happen to correspond exactly to the identity + * mapping, then we return + * + * { [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and + * A f + k a >= 0 and B p + b >= 0 and + * C f + C'p + c >= 0 and k >= 0 } + * + * instead. + * + * Existentially quantified variables in \delta are handled by + * classifying them as independent of the parameters, purely + * parameter dependent and others. Constraints containing + * any of the other existentially quantified variables are removed. + * This is safe, but leads to an additional overapproximation. + * + * If there are any impure constraints, then we also eliminate + * the parameters from \delta, resulting in a set + * + * \delta' = { [x] : E x + e >= 0 } + * + * and add the constraints + * + * E f + k e >= 0 + * + * to the constructed relation. + */ +static __isl_give isl_map *path_along_delta(__isl_take isl_space *dim, + __isl_take isl_basic_set *delta) +{ + isl_basic_map *path = NULL; + unsigned d; + unsigned n_div; + unsigned nparam; + unsigned off; + int i, k; + int is_id; + int *div_purity = NULL; + int impurity = 0; + + if (!delta) + goto error; + n_div = isl_basic_set_dim(delta, isl_dim_div); + d = isl_basic_set_dim(delta, isl_dim_set); + nparam = isl_basic_set_dim(delta, isl_dim_param); + path = isl_basic_map_alloc_space(isl_space_copy(dim), n_div + d + 1, + d + 1 + delta->n_eq, delta->n_eq + delta->n_ineq + 1); + off = 1 + nparam + 2 * (d + 1) + n_div; + + for (i = 0; i < n_div + d + 1; ++i) { + k = isl_basic_map_alloc_div(path); + if (k < 0) + goto error; + isl_int_set_si(path->div[k][0], 0); + } + + for (i = 0; i < d + 1; ++i) { + k = isl_basic_map_alloc_equality(path); + if (k < 0) + goto error; + isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path)); + isl_int_set_si(path->eq[k][1 + nparam + i], 1); + isl_int_set_si(path->eq[k][1 + nparam + d + 1 + i], -1); + isl_int_set_si(path->eq[k][off + i], 1); + } + + div_purity = get_div_purity(delta); + if (n_div && !div_purity) + goto error; + + path = add_delta_constraints(path, delta, off, nparam, d, + div_purity, 1, &impurity); + path = add_delta_constraints(path, delta, off, nparam, d, + div_purity, 0, &impurity); + if (impurity) { + isl_space *dim = isl_basic_set_get_space(delta); + delta = isl_basic_set_project_out(delta, + isl_dim_param, 0, nparam); + delta = isl_basic_set_add_dims(delta, isl_dim_param, nparam); + delta = isl_basic_set_reset_space(delta, dim); + if (!delta) + goto error; + path = isl_basic_map_extend_constraints(path, delta->n_eq, + delta->n_ineq + 1); + path = add_delta_constraints(path, delta, off, nparam, d, + NULL, 1, NULL); + path = add_delta_constraints(path, delta, off, nparam, d, + NULL, 0, NULL); + path = isl_basic_map_gauss(path, NULL); + } + + is_id = empty_path_is_identity(path, off + d); + if (is_id < 0) + goto error; + + k = isl_basic_map_alloc_inequality(path); + if (k < 0) + goto error; + isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path)); + if (!is_id) + isl_int_set_si(path->ineq[k][0], -1); + isl_int_set_si(path->ineq[k][off + d], 1); + + free(div_purity); + isl_basic_set_free(delta); + path = isl_basic_map_finalize(path); + if (is_id) { + isl_space_free(dim); + return isl_map_from_basic_map(path); + } + return isl_basic_map_union(path, isl_basic_map_identity(dim)); +error: + free(div_purity); + isl_space_free(dim); + isl_basic_set_free(delta); + isl_basic_map_free(path); + return NULL; +} + +/* Given a dimension specification Z^{n+1} -> Z^{n+1} and a parameter "param", + * construct a map that equates the parameter to the difference + * in the final coordinates and imposes that this difference is positive. + * That is, construct + * + * { [x,x_s] -> [y,y_s] : k = y_s - x_s > 0 } + */ +static __isl_give isl_map *equate_parameter_to_length(__isl_take isl_space *dim, + unsigned param) +{ + struct isl_basic_map *bmap; + unsigned d; + unsigned nparam; + int k; + + d = isl_space_dim(dim, isl_dim_in); + nparam = isl_space_dim(dim, isl_dim_param); + bmap = isl_basic_map_alloc_space(dim, 0, 1, 1); + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->eq[k][1 + param], -1); + isl_int_set_si(bmap->eq[k][1 + nparam + d - 1], -1); + isl_int_set_si(bmap->eq[k][1 + nparam + d + d - 1], 1); + + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->ineq[k], 1 + isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->ineq[k][1 + param], 1); + isl_int_set_si(bmap->ineq[k][0], -1); + + bmap = isl_basic_map_finalize(bmap); + return isl_map_from_basic_map(bmap); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Check whether "path" is acyclic, where the last coordinates of domain + * and range of path encode the number of steps taken. + * That is, check whether + * + * { d | d = y - x and (x,y) in path } + * + * does not contain any element with positive last coordinate (positive length) + * and zero remaining coordinates (cycle). + */ +static int is_acyclic(__isl_take isl_map *path) +{ + int i; + int acyclic; + unsigned dim; + struct isl_set *delta; + + delta = isl_map_deltas(path); + dim = isl_set_dim(delta, isl_dim_set); + for (i = 0; i < dim; ++i) { + if (i == dim -1) + delta = isl_set_lower_bound_si(delta, isl_dim_set, i, 1); + else + delta = isl_set_fix_si(delta, isl_dim_set, i, 0); + } + + acyclic = isl_set_is_empty(delta); + isl_set_free(delta); + + return acyclic; +} + +/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D + * and a dimension specification (Z^{n+1} -> Z^{n+1}), + * construct a map that is an overapproximation of the map + * that takes an element from the space D \times Z to another + * element from the same space, such that the first n coordinates of the + * difference between them is a sum of differences between images + * and pre-images in one of the R_i and such that the last coordinate + * is equal to the number of steps taken. + * That is, let + * + * \Delta_i = { y - x | (x, y) in R_i } + * + * then the constructed map is an overapproximation of + * + * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i : + * d = (\sum_i k_i \delta_i, \sum_i k_i) } + * + * The elements of the singleton \Delta_i's are collected as the + * rows of the steps matrix. For all these \Delta_i's together, + * a single path is constructed. + * For each of the other \Delta_i's, we compute an overapproximation + * of the paths along elements of \Delta_i. + * Since each of these paths performs an addition, composition is + * symmetric and we can simply compose all resulting paths in any order. + */ +static __isl_give isl_map *construct_extended_path(__isl_take isl_space *dim, + __isl_keep isl_map *map, int *project) +{ + struct isl_mat *steps = NULL; + struct isl_map *path = NULL; + unsigned d; + int i, j, n; + + if (!map) + goto error; + + d = isl_map_dim(map, isl_dim_in); + + path = isl_map_identity(isl_space_copy(dim)); + + steps = isl_mat_alloc(map->ctx, map->n, d); + if (!steps) + goto error; + + n = 0; + for (i = 0; i < map->n; ++i) { + struct isl_basic_set *delta; + + delta = isl_basic_map_deltas(isl_basic_map_copy(map->p[i])); + + for (j = 0; j < d; ++j) { + isl_bool fixed; + + fixed = isl_basic_set_plain_dim_is_fixed(delta, j, + &steps->row[n][j]); + if (fixed < 0) { + isl_basic_set_free(delta); + goto error; + } + if (!fixed) + break; + } + + + if (j < d) { + path = isl_map_apply_range(path, + path_along_delta(isl_space_copy(dim), delta)); + path = isl_map_coalesce(path); + } else { + isl_basic_set_free(delta); + ++n; + } + } + + if (n > 0) { + steps->n_row = n; + path = isl_map_apply_range(path, + path_along_steps(isl_space_copy(dim), steps)); + } + + if (project && *project) { + *project = is_acyclic(isl_map_copy(path)); + if (*project < 0) + goto error; + } + + isl_space_free(dim); + isl_mat_free(steps); + return path; +error: + isl_space_free(dim); + isl_mat_free(steps); + isl_map_free(path); + return NULL; +} + +static isl_bool isl_set_overlaps(__isl_keep isl_set *set1, + __isl_keep isl_set *set2) +{ + isl_set *i; + isl_bool no_overlap; + + if (!set1 || !set2) + return isl_bool_error; + + if (!isl_space_tuple_is_equal(set1->dim, isl_dim_set, + set2->dim, isl_dim_set)) + return isl_bool_false; + + i = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2)); + no_overlap = isl_set_is_empty(i); + isl_set_free(i); + + return isl_bool_not(no_overlap); +} + +/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D + * and a dimension specification (Z^{n+1} -> Z^{n+1}), + * construct a map that is an overapproximation of the map + * that takes an element from the dom R \times Z to an + * element from ran R \times Z, such that the first n coordinates of the + * difference between them is a sum of differences between images + * and pre-images in one of the R_i and such that the last coordinate + * is equal to the number of steps taken. + * That is, let + * + * \Delta_i = { y - x | (x, y) in R_i } + * + * then the constructed map is an overapproximation of + * + * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i : + * d = (\sum_i k_i \delta_i, \sum_i k_i) and + * x in dom R and x + d in ran R and + * \sum_i k_i >= 1 } + */ +static __isl_give isl_map *construct_component(__isl_take isl_space *dim, + __isl_keep isl_map *map, int *exact, int project) +{ + struct isl_set *domain = NULL; + struct isl_set *range = NULL; + struct isl_map *app = NULL; + struct isl_map *path = NULL; + isl_bool overlaps; + + domain = isl_map_domain(isl_map_copy(map)); + domain = isl_set_coalesce(domain); + range = isl_map_range(isl_map_copy(map)); + range = isl_set_coalesce(range); + overlaps = isl_set_overlaps(domain, range); + if (overlaps < 0 || !overlaps) { + isl_set_free(domain); + isl_set_free(range); + isl_space_free(dim); + + if (overlaps < 0) + map = NULL; + map = isl_map_copy(map); + map = isl_map_add_dims(map, isl_dim_in, 1); + map = isl_map_add_dims(map, isl_dim_out, 1); + map = set_path_length(map, 1, 1); + return map; + } + app = isl_map_from_domain_and_range(domain, range); + app = isl_map_add_dims(app, isl_dim_in, 1); + app = isl_map_add_dims(app, isl_dim_out, 1); + + path = construct_extended_path(isl_space_copy(dim), map, + exact && *exact ? &project : NULL); + app = isl_map_intersect(app, path); + + if (exact && *exact && + (*exact = check_exactness(isl_map_copy(map), isl_map_copy(app), + project)) < 0) + goto error; + + isl_space_free(dim); + app = set_path_length(app, 0, 1); + return app; +error: + isl_space_free(dim); + isl_map_free(app); + return NULL; +} + +/* Call construct_component and, if "project" is set, project out + * the final coordinates. + */ +static __isl_give isl_map *construct_projected_component( + __isl_take isl_space *dim, + __isl_keep isl_map *map, int *exact, int project) +{ + isl_map *app; + unsigned d; + + if (!dim) + return NULL; + d = isl_space_dim(dim, isl_dim_in); + + app = construct_component(dim, map, exact, project); + if (project) { + app = isl_map_project_out(app, isl_dim_in, d - 1, 1); + app = isl_map_project_out(app, isl_dim_out, d - 1, 1); + } + return app; +} + +/* Compute an extended version, i.e., with path lengths, of + * an overapproximation of the transitive closure of "bmap" + * with path lengths greater than or equal to zero and with + * domain and range equal to "dom". + */ +static __isl_give isl_map *q_closure(__isl_take isl_space *dim, + __isl_take isl_set *dom, __isl_keep isl_basic_map *bmap, int *exact) +{ + int project = 1; + isl_map *path; + isl_map *map; + isl_map *app; + + dom = isl_set_add_dims(dom, isl_dim_set, 1); + app = isl_map_from_domain_and_range(dom, isl_set_copy(dom)); + map = isl_map_from_basic_map(isl_basic_map_copy(bmap)); + path = construct_extended_path(dim, map, &project); + app = isl_map_intersect(app, path); + + if ((*exact = check_exactness(map, isl_map_copy(app), project)) < 0) + goto error; + + return app; +error: + isl_map_free(app); + return NULL; +} + +/* Check whether qc has any elements of length at least one + * with domain and/or range outside of dom and ran. + */ +static int has_spurious_elements(__isl_keep isl_map *qc, + __isl_keep isl_set *dom, __isl_keep isl_set *ran) +{ + isl_set *s; + int subset; + unsigned d; + + if (!qc || !dom || !ran) + return -1; + + d = isl_map_dim(qc, isl_dim_in); + + qc = isl_map_copy(qc); + qc = set_path_length(qc, 0, 1); + qc = isl_map_project_out(qc, isl_dim_in, d - 1, 1); + qc = isl_map_project_out(qc, isl_dim_out, d - 1, 1); + + s = isl_map_domain(isl_map_copy(qc)); + subset = isl_set_is_subset(s, dom); + isl_set_free(s); + if (subset < 0) + goto error; + if (!subset) { + isl_map_free(qc); + return 1; + } + + s = isl_map_range(qc); + subset = isl_set_is_subset(s, ran); + isl_set_free(s); + + return subset < 0 ? -1 : !subset; +error: + isl_map_free(qc); + return -1; +} + +#define LEFT 2 +#define RIGHT 1 + +/* For each basic map in "map", except i, check whether it combines + * with the transitive closure that is reflexive on C combines + * to the left and to the right. + * + * In particular, if + * + * dom map_j \subseteq C + * + * then right[j] is set to 1. Otherwise, if + * + * ran map_i \cap dom map_j = \emptyset + * + * then right[j] is set to 0. Otherwise, composing to the right + * is impossible. + * + * Similar, for composing to the left, we have if + * + * ran map_j \subseteq C + * + * then left[j] is set to 1. Otherwise, if + * + * dom map_i \cap ran map_j = \emptyset + * + * then left[j] is set to 0. Otherwise, composing to the left + * is impossible. + * + * The return value is or'd with LEFT if composing to the left + * is possible and with RIGHT if composing to the right is possible. + */ +static int composability(__isl_keep isl_set *C, int i, + isl_set **dom, isl_set **ran, int *left, int *right, + __isl_keep isl_map *map) +{ + int j; + int ok; + + ok = LEFT | RIGHT; + for (j = 0; j < map->n && ok; ++j) { + isl_bool overlaps, subset; + if (j == i) + continue; + + if (ok & RIGHT) { + if (!dom[j]) + dom[j] = isl_set_from_basic_set( + isl_basic_map_domain( + isl_basic_map_copy(map->p[j]))); + if (!dom[j]) + return -1; + overlaps = isl_set_overlaps(ran[i], dom[j]); + if (overlaps < 0) + return -1; + if (!overlaps) + right[j] = 0; + else { + subset = isl_set_is_subset(dom[j], C); + if (subset < 0) + return -1; + if (subset) + right[j] = 1; + else + ok &= ~RIGHT; + } + } + + if (ok & LEFT) { + if (!ran[j]) + ran[j] = isl_set_from_basic_set( + isl_basic_map_range( + isl_basic_map_copy(map->p[j]))); + if (!ran[j]) + return -1; + overlaps = isl_set_overlaps(dom[i], ran[j]); + if (overlaps < 0) + return -1; + if (!overlaps) + left[j] = 0; + else { + subset = isl_set_is_subset(ran[j], C); + if (subset < 0) + return -1; + if (subset) + left[j] = 1; + else + ok &= ~LEFT; + } + } + } + + return ok; +} + +static __isl_give isl_map *anonymize(__isl_take isl_map *map) +{ + map = isl_map_reset(map, isl_dim_in); + map = isl_map_reset(map, isl_dim_out); + return map; +} + +/* Return a map that is a union of the basic maps in "map", except i, + * composed to left and right with qc based on the entries of "left" + * and "right". + */ +static __isl_give isl_map *compose(__isl_keep isl_map *map, int i, + __isl_take isl_map *qc, int *left, int *right) +{ + int j; + isl_map *comp; + + comp = isl_map_empty(isl_map_get_space(map)); + for (j = 0; j < map->n; ++j) { + isl_map *map_j; + + if (j == i) + continue; + + map_j = isl_map_from_basic_map(isl_basic_map_copy(map->p[j])); + map_j = anonymize(map_j); + if (left && left[j]) + map_j = isl_map_apply_range(map_j, isl_map_copy(qc)); + if (right && right[j]) + map_j = isl_map_apply_range(isl_map_copy(qc), map_j); + comp = isl_map_union(comp, map_j); + } + + comp = isl_map_compute_divs(comp); + comp = isl_map_coalesce(comp); + + isl_map_free(qc); + + return comp; +} + +/* Compute the transitive closure of "map" incrementally by + * computing + * + * map_i^+ \cup qc^+ + * + * or + * + * map_i^+ \cup ((id \cup map_i^) \circ qc^+) + * + * or + * + * map_i^+ \cup (qc^+ \circ (id \cup map_i^)) + * + * depending on whether left or right are NULL. + */ +static __isl_give isl_map *compute_incremental( + __isl_take isl_space *dim, __isl_keep isl_map *map, + int i, __isl_take isl_map *qc, int *left, int *right, int *exact) +{ + isl_map *map_i; + isl_map *tc; + isl_map *rtc = NULL; + + if (!map) + goto error; + isl_assert(map->ctx, left || right, goto error); + + map_i = isl_map_from_basic_map(isl_basic_map_copy(map->p[i])); + tc = construct_projected_component(isl_space_copy(dim), map_i, + exact, 1); + isl_map_free(map_i); + + if (*exact) + qc = isl_map_transitive_closure(qc, exact); + + if (!*exact) { + isl_space_free(dim); + isl_map_free(tc); + isl_map_free(qc); + return isl_map_universe(isl_map_get_space(map)); + } + + if (!left || !right) + rtc = isl_map_union(isl_map_copy(tc), + isl_map_identity(isl_map_get_space(tc))); + if (!right) + qc = isl_map_apply_range(rtc, qc); + if (!left) + qc = isl_map_apply_range(qc, rtc); + qc = isl_map_union(tc, qc); + + isl_space_free(dim); + + return qc; +error: + isl_space_free(dim); + isl_map_free(qc); + return NULL; +} + +/* Given a map "map", try to find a basic map such that + * map^+ can be computed as + * + * map^+ = map_i^+ \cup + * \bigcup_j ((map_i^+ \cup Id_C)^+ \circ map_j \circ (map_i^+ \cup Id_C))^+ + * + * with C the simple hull of the domain and range of the input map. + * map_i^ \cup Id_C is computed by allowing the path lengths to be zero + * and by intersecting domain and range with C. + * Of course, we need to check that this is actually equal to map_i^ \cup Id_C. + * Also, we only use the incremental computation if all the transitive + * closures are exact and if the number of basic maps in the union, + * after computing the integer divisions, is smaller than the number + * of basic maps in the input map. + */ +static int incemental_on_entire_domain(__isl_keep isl_space *dim, + __isl_keep isl_map *map, + isl_set **dom, isl_set **ran, int *left, int *right, + __isl_give isl_map **res) +{ + int i; + isl_set *C; + unsigned d; + + *res = NULL; + + C = isl_set_union(isl_map_domain(isl_map_copy(map)), + isl_map_range(isl_map_copy(map))); + C = isl_set_from_basic_set(isl_set_simple_hull(C)); + if (!C) + return -1; + if (C->n != 1) { + isl_set_free(C); + return 0; + } + + d = isl_map_dim(map, isl_dim_in); + + for (i = 0; i < map->n; ++i) { + isl_map *qc; + int exact_i, spurious; + int j; + dom[i] = isl_set_from_basic_set(isl_basic_map_domain( + isl_basic_map_copy(map->p[i]))); + ran[i] = isl_set_from_basic_set(isl_basic_map_range( + isl_basic_map_copy(map->p[i]))); + qc = q_closure(isl_space_copy(dim), isl_set_copy(C), + map->p[i], &exact_i); + if (!qc) + goto error; + if (!exact_i) { + isl_map_free(qc); + continue; + } + spurious = has_spurious_elements(qc, dom[i], ran[i]); + if (spurious) { + isl_map_free(qc); + if (spurious < 0) + goto error; + continue; + } + qc = isl_map_project_out(qc, isl_dim_in, d, 1); + qc = isl_map_project_out(qc, isl_dim_out, d, 1); + qc = isl_map_compute_divs(qc); + for (j = 0; j < map->n; ++j) + left[j] = right[j] = 1; + qc = compose(map, i, qc, left, right); + if (!qc) + goto error; + if (qc->n >= map->n) { + isl_map_free(qc); + continue; + } + *res = compute_incremental(isl_space_copy(dim), map, i, qc, + left, right, &exact_i); + if (!*res) + goto error; + if (exact_i) + break; + isl_map_free(*res); + *res = NULL; + } + + isl_set_free(C); + + return *res != NULL; +error: + isl_set_free(C); + return -1; +} + +/* Try and compute the transitive closure of "map" as + * + * map^+ = map_i^+ \cup + * \bigcup_j ((map_i^+ \cup Id_C)^+ \circ map_j \circ (map_i^+ \cup Id_C))^+ + * + * with C either the simple hull of the domain and range of the entire + * map or the simple hull of domain and range of map_i. + */ +static __isl_give isl_map *incremental_closure(__isl_take isl_space *dim, + __isl_keep isl_map *map, int *exact, int project) +{ + int i; + isl_set **dom = NULL; + isl_set **ran = NULL; + int *left = NULL; + int *right = NULL; + isl_set *C; + unsigned d; + isl_map *res = NULL; + + if (!project) + return construct_projected_component(dim, map, exact, project); + + if (!map) + goto error; + if (map->n <= 1) + return construct_projected_component(dim, map, exact, project); + + d = isl_map_dim(map, isl_dim_in); + + dom = isl_calloc_array(map->ctx, isl_set *, map->n); + ran = isl_calloc_array(map->ctx, isl_set *, map->n); + left = isl_calloc_array(map->ctx, int, map->n); + right = isl_calloc_array(map->ctx, int, map->n); + if (!ran || !dom || !left || !right) + goto error; + + if (incemental_on_entire_domain(dim, map, dom, ran, left, right, &res) < 0) + goto error; + + for (i = 0; !res && i < map->n; ++i) { + isl_map *qc; + int exact_i, spurious, comp; + if (!dom[i]) + dom[i] = isl_set_from_basic_set( + isl_basic_map_domain( + isl_basic_map_copy(map->p[i]))); + if (!dom[i]) + goto error; + if (!ran[i]) + ran[i] = isl_set_from_basic_set( + isl_basic_map_range( + isl_basic_map_copy(map->p[i]))); + if (!ran[i]) + goto error; + C = isl_set_union(isl_set_copy(dom[i]), + isl_set_copy(ran[i])); + C = isl_set_from_basic_set(isl_set_simple_hull(C)); + if (!C) + goto error; + if (C->n != 1) { + isl_set_free(C); + continue; + } + comp = composability(C, i, dom, ran, left, right, map); + if (!comp || comp < 0) { + isl_set_free(C); + if (comp < 0) + goto error; + continue; + } + qc = q_closure(isl_space_copy(dim), C, map->p[i], &exact_i); + if (!qc) + goto error; + if (!exact_i) { + isl_map_free(qc); + continue; + } + spurious = has_spurious_elements(qc, dom[i], ran[i]); + if (spurious) { + isl_map_free(qc); + if (spurious < 0) + goto error; + continue; + } + qc = isl_map_project_out(qc, isl_dim_in, d, 1); + qc = isl_map_project_out(qc, isl_dim_out, d, 1); + qc = isl_map_compute_divs(qc); + qc = compose(map, i, qc, (comp & LEFT) ? left : NULL, + (comp & RIGHT) ? right : NULL); + if (!qc) + goto error; + if (qc->n >= map->n) { + isl_map_free(qc); + continue; + } + res = compute_incremental(isl_space_copy(dim), map, i, qc, + (comp & LEFT) ? left : NULL, + (comp & RIGHT) ? right : NULL, &exact_i); + if (!res) + goto error; + if (exact_i) + break; + isl_map_free(res); + res = NULL; + } + + for (i = 0; i < map->n; ++i) { + isl_set_free(dom[i]); + isl_set_free(ran[i]); + } + free(dom); + free(ran); + free(left); + free(right); + + if (res) { + isl_space_free(dim); + return res; + } + + return construct_projected_component(dim, map, exact, project); +error: + if (dom) + for (i = 0; i < map->n; ++i) + isl_set_free(dom[i]); + free(dom); + if (ran) + for (i = 0; i < map->n; ++i) + isl_set_free(ran[i]); + free(ran); + free(left); + free(right); + isl_space_free(dim); + return NULL; +} + +/* Given an array of sets "set", add "dom" at position "pos" + * and search for elements at earlier positions that overlap with "dom". + * If any can be found, then merge all of them, together with "dom", into + * a single set and assign the union to the first in the array, + * which becomes the new group leader for all groups involved in the merge. + * During the search, we only consider group leaders, i.e., those with + * group[i] = i, as the other sets have already been combined + * with one of the group leaders. + */ +static int merge(isl_set **set, int *group, __isl_take isl_set *dom, int pos) +{ + int i; + + group[pos] = pos; + set[pos] = isl_set_copy(dom); + + for (i = pos - 1; i >= 0; --i) { + isl_bool o; + + if (group[i] != i) + continue; + + o = isl_set_overlaps(set[i], dom); + if (o < 0) + goto error; + if (!o) + continue; + + set[i] = isl_set_union(set[i], set[group[pos]]); + set[group[pos]] = NULL; + if (!set[i]) + goto error; + group[group[pos]] = i; + group[pos] = i; + } + + isl_set_free(dom); + return 0; +error: + isl_set_free(dom); + return -1; +} + +/* Replace each entry in the n by n grid of maps by the cross product + * with the relation { [i] -> [i + 1] }. + */ +static int add_length(__isl_keep isl_map *map, isl_map ***grid, int n) +{ + int i, j, k; + isl_space *dim; + isl_basic_map *bstep; + isl_map *step; + unsigned nparam; + + if (!map) + return -1; + + dim = isl_map_get_space(map); + nparam = isl_space_dim(dim, isl_dim_param); + dim = isl_space_drop_dims(dim, isl_dim_in, 0, isl_space_dim(dim, isl_dim_in)); + dim = isl_space_drop_dims(dim, isl_dim_out, 0, isl_space_dim(dim, isl_dim_out)); + dim = isl_space_add_dims(dim, isl_dim_in, 1); + dim = isl_space_add_dims(dim, isl_dim_out, 1); + bstep = isl_basic_map_alloc_space(dim, 0, 1, 0); + k = isl_basic_map_alloc_equality(bstep); + if (k < 0) { + isl_basic_map_free(bstep); + return -1; + } + isl_seq_clr(bstep->eq[k], 1 + isl_basic_map_total_dim(bstep)); + isl_int_set_si(bstep->eq[k][0], 1); + isl_int_set_si(bstep->eq[k][1 + nparam], 1); + isl_int_set_si(bstep->eq[k][1 + nparam + 1], -1); + bstep = isl_basic_map_finalize(bstep); + step = isl_map_from_basic_map(bstep); + + for (i = 0; i < n; ++i) + for (j = 0; j < n; ++j) + grid[i][j] = isl_map_product(grid[i][j], + isl_map_copy(step)); + + isl_map_free(step); + + return 0; +} + +/* The core of the Floyd-Warshall algorithm. + * Updates the given n x x matrix of relations in place. + * + * The algorithm iterates over all vertices. In each step, the whole + * matrix is updated to include all paths that go to the current vertex, + * possibly stay there a while (including passing through earlier vertices) + * and then come back. At the start of each iteration, the diagonal + * element corresponding to the current vertex is replaced by its + * transitive closure to account for all indirect paths that stay + * in the current vertex. + */ +static void floyd_warshall_iterate(isl_map ***grid, int n, int *exact) +{ + int r, p, q; + + for (r = 0; r < n; ++r) { + int r_exact; + grid[r][r] = isl_map_transitive_closure(grid[r][r], + (exact && *exact) ? &r_exact : NULL); + if (exact && *exact && !r_exact) + *exact = 0; + + for (p = 0; p < n; ++p) + for (q = 0; q < n; ++q) { + isl_map *loop; + if (p == r && q == r) + continue; + loop = isl_map_apply_range( + isl_map_copy(grid[p][r]), + isl_map_copy(grid[r][q])); + grid[p][q] = isl_map_union(grid[p][q], loop); + loop = isl_map_apply_range( + isl_map_copy(grid[p][r]), + isl_map_apply_range( + isl_map_copy(grid[r][r]), + isl_map_copy(grid[r][q]))); + grid[p][q] = isl_map_union(grid[p][q], loop); + grid[p][q] = isl_map_coalesce(grid[p][q]); + } + } +} + +/* Given a partition of the domains and ranges of the basic maps in "map", + * apply the Floyd-Warshall algorithm with the elements in the partition + * as vertices. + * + * In particular, there are "n" elements in the partition and "group" is + * an array of length 2 * map->n with entries in [0,n-1]. + * + * We first construct a matrix of relations based on the partition information, + * apply Floyd-Warshall on this matrix of relations and then take the + * union of all entries in the matrix as the final result. + * + * If we are actually computing the power instead of the transitive closure, + * i.e., when "project" is not set, then the result should have the + * path lengths encoded as the difference between an extra pair of + * coordinates. We therefore apply the nested transitive closures + * to relations that include these lengths. In particular, we replace + * the input relation by the cross product with the unit length relation + * { [i] -> [i + 1] }. + */ +static __isl_give isl_map *floyd_warshall_with_groups(__isl_take isl_space *dim, + __isl_keep isl_map *map, int *exact, int project, int *group, int n) +{ + int i, j, k; + isl_map ***grid = NULL; + isl_map *app; + + if (!map) + goto error; + + if (n == 1) { + free(group); + return incremental_closure(dim, map, exact, project); + } + + grid = isl_calloc_array(map->ctx, isl_map **, n); + if (!grid) + goto error; + for (i = 0; i < n; ++i) { + grid[i] = isl_calloc_array(map->ctx, isl_map *, n); + if (!grid[i]) + goto error; + for (j = 0; j < n; ++j) + grid[i][j] = isl_map_empty(isl_map_get_space(map)); + } + + for (k = 0; k < map->n; ++k) { + i = group[2 * k]; + j = group[2 * k + 1]; + grid[i][j] = isl_map_union(grid[i][j], + isl_map_from_basic_map( + isl_basic_map_copy(map->p[k]))); + } + + if (!project && add_length(map, grid, n) < 0) + goto error; + + floyd_warshall_iterate(grid, n, exact); + + app = isl_map_empty(isl_map_get_space(grid[0][0])); + + for (i = 0; i < n; ++i) { + for (j = 0; j < n; ++j) + app = isl_map_union(app, grid[i][j]); + free(grid[i]); + } + free(grid); + + free(group); + isl_space_free(dim); + + return app; +error: + if (grid) + for (i = 0; i < n; ++i) { + if (!grid[i]) + continue; + for (j = 0; j < n; ++j) + isl_map_free(grid[i][j]); + free(grid[i]); + } + free(grid); + free(group); + isl_space_free(dim); + return NULL; +} + +/* Partition the domains and ranges of the n basic relations in list + * into disjoint cells. + * + * To find the partition, we simply consider all of the domains + * and ranges in turn and combine those that overlap. + * "set" contains the partition elements and "group" indicates + * to which partition element a given domain or range belongs. + * The domain of basic map i corresponds to element 2 * i in these arrays, + * while the domain corresponds to element 2 * i + 1. + * During the construction group[k] is either equal to k, + * in which case set[k] contains the union of all the domains and + * ranges in the corresponding group, or is equal to some l < k, + * with l another domain or range in the same group. + */ +static int *setup_groups(isl_ctx *ctx, __isl_keep isl_basic_map **list, int n, + isl_set ***set, int *n_group) +{ + int i; + int *group = NULL; + int g; + + *set = isl_calloc_array(ctx, isl_set *, 2 * n); + group = isl_alloc_array(ctx, int, 2 * n); + + if (!*set || !group) + goto error; + + for (i = 0; i < n; ++i) { + isl_set *dom; + dom = isl_set_from_basic_set(isl_basic_map_domain( + isl_basic_map_copy(list[i]))); + if (merge(*set, group, dom, 2 * i) < 0) + goto error; + dom = isl_set_from_basic_set(isl_basic_map_range( + isl_basic_map_copy(list[i]))); + if (merge(*set, group, dom, 2 * i + 1) < 0) + goto error; + } + + g = 0; + for (i = 0; i < 2 * n; ++i) + if (group[i] == i) { + if (g != i) { + (*set)[g] = (*set)[i]; + (*set)[i] = NULL; + } + group[i] = g++; + } else + group[i] = group[group[i]]; + + *n_group = g; + + return group; +error: + if (*set) { + for (i = 0; i < 2 * n; ++i) + isl_set_free((*set)[i]); + free(*set); + *set = NULL; + } + free(group); + return NULL; +} + +/* Check if the domains and ranges of the basic maps in "map" can + * be partitioned, and if so, apply Floyd-Warshall on the elements + * of the partition. Note that we also apply this algorithm + * if we want to compute the power, i.e., when "project" is not set. + * However, the results are unlikely to be exact since the recursive + * calls inside the Floyd-Warshall algorithm typically result in + * non-linear path lengths quite quickly. + */ +static __isl_give isl_map *floyd_warshall(__isl_take isl_space *dim, + __isl_keep isl_map *map, int *exact, int project) +{ + int i; + isl_set **set = NULL; + int *group = NULL; + int n; + + if (!map) + goto error; + if (map->n <= 1) + return incremental_closure(dim, map, exact, project); + + group = setup_groups(map->ctx, map->p, map->n, &set, &n); + if (!group) + goto error; + + for (i = 0; i < 2 * map->n; ++i) + isl_set_free(set[i]); + + free(set); + + return floyd_warshall_with_groups(dim, map, exact, project, group, n); +error: + isl_space_free(dim); + return NULL; +} + +/* Structure for representing the nodes of the graph of which + * strongly connected components are being computed. + * + * list contains the actual nodes + * check_closed is set if we may have used the fact that + * a pair of basic maps can be interchanged + */ +struct isl_tc_follows_data { + isl_basic_map **list; + int check_closed; +}; + +/* Check whether in the computation of the transitive closure + * "list[i]" (R_1) should follow (or be part of the same component as) + * "list[j]" (R_2). + * + * That is check whether + * + * R_1 \circ R_2 + * + * is a subset of + * + * R_2 \circ R_1 + * + * If so, then there is no reason for R_1 to immediately follow R_2 + * in any path. + * + * *check_closed is set if the subset relation holds while + * R_1 \circ R_2 is not empty. + */ +static isl_bool basic_map_follows(int i, int j, void *user) +{ + struct isl_tc_follows_data *data = user; + struct isl_map *map12 = NULL; + struct isl_map *map21 = NULL; + isl_bool subset; + + if (!isl_space_tuple_is_equal(data->list[i]->dim, isl_dim_in, + data->list[j]->dim, isl_dim_out)) + return isl_bool_false; + + map21 = isl_map_from_basic_map( + isl_basic_map_apply_range( + isl_basic_map_copy(data->list[j]), + isl_basic_map_copy(data->list[i]))); + subset = isl_map_is_empty(map21); + if (subset < 0) + goto error; + if (subset) { + isl_map_free(map21); + return isl_bool_false; + } + + if (!isl_space_tuple_is_equal(data->list[i]->dim, isl_dim_in, + data->list[i]->dim, isl_dim_out) || + !isl_space_tuple_is_equal(data->list[j]->dim, isl_dim_in, + data->list[j]->dim, isl_dim_out)) { + isl_map_free(map21); + return isl_bool_true; + } + + map12 = isl_map_from_basic_map( + isl_basic_map_apply_range( + isl_basic_map_copy(data->list[i]), + isl_basic_map_copy(data->list[j]))); + + subset = isl_map_is_subset(map21, map12); + + isl_map_free(map12); + isl_map_free(map21); + + if (subset) + data->check_closed = 1; + + return subset < 0 ? isl_bool_error : !subset; +error: + isl_map_free(map21); + return isl_bool_error; +} + +/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D + * and a dimension specification (Z^{n+1} -> Z^{n+1}), + * construct a map that is an overapproximation of the map + * that takes an element from the dom R \times Z to an + * element from ran R \times Z, such that the first n coordinates of the + * difference between them is a sum of differences between images + * and pre-images in one of the R_i and such that the last coordinate + * is equal to the number of steps taken. + * If "project" is set, then these final coordinates are not included, + * i.e., a relation of type Z^n -> Z^n is returned. + * That is, let + * + * \Delta_i = { y - x | (x, y) in R_i } + * + * then the constructed map is an overapproximation of + * + * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i : + * d = (\sum_i k_i \delta_i, \sum_i k_i) and + * x in dom R and x + d in ran R } + * + * or + * + * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i : + * d = (\sum_i k_i \delta_i) and + * x in dom R and x + d in ran R } + * + * if "project" is set. + * + * We first split the map into strongly connected components, perform + * the above on each component and then join the results in the correct + * order, at each join also taking in the union of both arguments + * to allow for paths that do not go through one of the two arguments. + */ +static __isl_give isl_map *construct_power_components(__isl_take isl_space *dim, + __isl_keep isl_map *map, int *exact, int project) +{ + int i, n, c; + struct isl_map *path = NULL; + struct isl_tc_follows_data data; + struct isl_tarjan_graph *g = NULL; + int *orig_exact; + int local_exact; + + if (!map) + goto error; + if (map->n <= 1) + return floyd_warshall(dim, map, exact, project); + + data.list = map->p; + data.check_closed = 0; + g = isl_tarjan_graph_init(map->ctx, map->n, &basic_map_follows, &data); + if (!g) + goto error; + + orig_exact = exact; + if (data.check_closed && !exact) + exact = &local_exact; + + c = 0; + i = 0; + n = map->n; + if (project) + path = isl_map_empty(isl_map_get_space(map)); + else + path = isl_map_empty(isl_space_copy(dim)); + path = anonymize(path); + while (n) { + struct isl_map *comp; + isl_map *path_comp, *path_comb; + comp = isl_map_alloc_space(isl_map_get_space(map), n, 0); + while (g->order[i] != -1) { + comp = isl_map_add_basic_map(comp, + isl_basic_map_copy(map->p[g->order[i]])); + --n; + ++i; + } + path_comp = floyd_warshall(isl_space_copy(dim), + comp, exact, project); + path_comp = anonymize(path_comp); + path_comb = isl_map_apply_range(isl_map_copy(path), + isl_map_copy(path_comp)); + path = isl_map_union(path, path_comp); + path = isl_map_union(path, path_comb); + isl_map_free(comp); + ++i; + ++c; + } + + if (c > 1 && data.check_closed && !*exact) { + int closed; + + closed = isl_map_is_transitively_closed(path); + if (closed < 0) + goto error; + if (!closed) { + isl_tarjan_graph_free(g); + isl_map_free(path); + return floyd_warshall(dim, map, orig_exact, project); + } + } + + isl_tarjan_graph_free(g); + isl_space_free(dim); + + return path; +error: + isl_tarjan_graph_free(g); + isl_space_free(dim); + isl_map_free(path); + return NULL; +} + +/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D, + * construct a map that is an overapproximation of the map + * that takes an element from the space D to another + * element from the same space, such that the difference between + * them is a strictly positive sum of differences between images + * and pre-images in one of the R_i. + * The number of differences in the sum is equated to parameter "param". + * That is, let + * + * \Delta_i = { y - x | (x, y) in R_i } + * + * then the constructed map is an overapproximation of + * + * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i : + * d = \sum_i k_i \delta_i and k = \sum_i k_i > 0 } + * or + * + * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i : + * d = \sum_i k_i \delta_i and \sum_i k_i > 0 } + * + * if "project" is set. + * + * If "project" is not set, then + * we construct an extended mapping with an extra coordinate + * that indicates the number of steps taken. In particular, + * the difference in the last coordinate is equal to the number + * of steps taken to move from a domain element to the corresponding + * image element(s). + */ +static __isl_give isl_map *construct_power(__isl_keep isl_map *map, + int *exact, int project) +{ + struct isl_map *app = NULL; + isl_space *dim = NULL; + + if (!map) + return NULL; + + dim = isl_map_get_space(map); + + dim = isl_space_add_dims(dim, isl_dim_in, 1); + dim = isl_space_add_dims(dim, isl_dim_out, 1); + + app = construct_power_components(isl_space_copy(dim), map, + exact, project); + + isl_space_free(dim); + + return app; +} + +/* Compute the positive powers of "map", or an overapproximation. + * If the result is exact, then *exact is set to 1. + * + * If project is set, then we are actually interested in the transitive + * closure, so we can use a more relaxed exactness check. + * The lengths of the paths are also projected out instead of being + * encoded as the difference between an extra pair of final coordinates. + */ +static __isl_give isl_map *map_power(__isl_take isl_map *map, + int *exact, int project) +{ + struct isl_map *app = NULL; + + if (exact) + *exact = 1; + + if (!map) + return NULL; + + isl_assert(map->ctx, + isl_map_dim(map, isl_dim_in) == isl_map_dim(map, isl_dim_out), + goto error); + + app = construct_power(map, exact, project); + + isl_map_free(map); + return app; +error: + isl_map_free(map); + isl_map_free(app); + return NULL; +} + +/* Compute the positive powers of "map", or an overapproximation. + * The result maps the exponent to a nested copy of the corresponding power. + * If the result is exact, then *exact is set to 1. + * map_power constructs an extended relation with the path lengths + * encoded as the difference between the final coordinates. + * In the final step, this difference is equated to an extra parameter + * and made positive. The extra coordinates are subsequently projected out + * and the parameter is turned into the domain of the result. + */ +__isl_give isl_map *isl_map_power(__isl_take isl_map *map, int *exact) +{ + isl_space *target_dim; + isl_space *dim; + isl_map *diff; + unsigned d; + unsigned param; + + if (!map) + return NULL; + + d = isl_map_dim(map, isl_dim_in); + param = isl_map_dim(map, isl_dim_param); + + map = isl_map_compute_divs(map); + map = isl_map_coalesce(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"); + return map; + } + + target_dim = isl_map_get_space(map); + target_dim = isl_space_from_range(isl_space_wrap(target_dim)); + target_dim = isl_space_add_dims(target_dim, isl_dim_in, 1); + target_dim = isl_space_set_dim_name(target_dim, isl_dim_in, 0, "k"); + + map = map_power(map, exact, 0); + + map = isl_map_add_dims(map, isl_dim_param, 1); + dim = isl_map_get_space(map); + diff = equate_parameter_to_length(dim, param); + map = isl_map_intersect(map, diff); + map = isl_map_project_out(map, isl_dim_in, d, 1); + map = isl_map_project_out(map, isl_dim_out, d, 1); + map = isl_map_from_range(isl_map_wrap(map)); + map = isl_map_move_dims(map, isl_dim_in, 0, isl_dim_param, param, 1); + + map = isl_map_reset_space(map, target_dim); + + return map; +} + +/* Compute a relation that maps each element in the range of the input + * relation to the lengths of all paths composed of edges in the input + * relation that end up in the given range element. + * The result may be an overapproximation, in which case *exact is set to 0. + * The resulting relation is very similar to the power relation. + * The difference are that the domain has been projected out, the + * range has become the domain and the exponent is the range instead + * of a parameter. + */ +__isl_give isl_map *isl_map_reaching_path_lengths(__isl_take isl_map *map, + int *exact) +{ + isl_space *dim; + isl_map *diff; + unsigned d; + unsigned param; + + if (!map) + return NULL; + + d = isl_map_dim(map, isl_dim_in); + param = isl_map_dim(map, isl_dim_param); + + map = isl_map_compute_divs(map); + map = isl_map_coalesce(map); + + if (isl_map_plain_is_empty(map)) { + if (exact) + *exact = 1; + map = isl_map_project_out(map, isl_dim_out, 0, d); + map = isl_map_add_dims(map, isl_dim_out, 1); + return map; + } + + map = map_power(map, exact, 0); + + map = isl_map_add_dims(map, isl_dim_param, 1); + dim = isl_map_get_space(map); + diff = equate_parameter_to_length(dim, param); + map = isl_map_intersect(map, diff); + map = isl_map_project_out(map, isl_dim_in, 0, d + 1); + map = isl_map_project_out(map, isl_dim_out, d, 1); + map = isl_map_reverse(map); + map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_param, param, 1); + + return map; +} + +/* Given a map, compute the smallest superset of this map that is of the form + * + * { i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p } + * + * (where p ranges over the (non-parametric) dimensions), + * compute the transitive closure of this map, i.e., + * + * { i -> j : exists k > 0: + * k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p } + * + * and intersect domain and range of this transitive closure with + * the given domain and range. + * + * If with_id is set, then try to include as much of the identity mapping + * as possible, by computing + * + * { i -> j : exists k >= 0: + * k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p } + * + * instead (i.e., allow k = 0). + * + * In practice, we compute the difference set + * + * delta = { j - i | i -> j in map }, + * + * look for stride constraint on the individual dimensions and compute + * (constant) lower and upper bounds for each individual dimension, + * adding a constraint for each bound not equal to infinity. + */ +static __isl_give isl_map *box_closure_on_domain(__isl_take isl_map *map, + __isl_take isl_set *dom, __isl_take isl_set *ran, int with_id) +{ + int i; + int k; + unsigned d; + unsigned nparam; + unsigned total; + isl_space *dim; + isl_set *delta; + isl_map *app = NULL; + isl_basic_set *aff = NULL; + isl_basic_map *bmap = NULL; + isl_vec *obj = NULL; + isl_int opt; + + isl_int_init(opt); + + delta = isl_map_deltas(isl_map_copy(map)); + + aff = isl_set_affine_hull(isl_set_copy(delta)); + if (!aff) + goto error; + dim = isl_map_get_space(map); + d = isl_space_dim(dim, isl_dim_in); + nparam = isl_space_dim(dim, isl_dim_param); + total = isl_space_dim(dim, isl_dim_all); + bmap = isl_basic_map_alloc_space(dim, + aff->n_div + 1, aff->n_div, 2 * d + 1); + for (i = 0; i < aff->n_div + 1; ++i) { + k = isl_basic_map_alloc_div(bmap); + if (k < 0) + goto error; + isl_int_set_si(bmap->div[k][0], 0); + } + for (i = 0; i < aff->n_eq; ++i) { + if (!isl_basic_set_eq_is_stride(aff, i)) + continue; + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->eq[k], 1 + nparam); + isl_seq_cpy(bmap->eq[k] + 1 + nparam + d, + aff->eq[i] + 1 + nparam, d); + isl_seq_neg(bmap->eq[k] + 1 + nparam, + aff->eq[i] + 1 + nparam, d); + isl_seq_cpy(bmap->eq[k] + 1 + nparam + 2 * d, + aff->eq[i] + 1 + nparam + d, aff->n_div); + isl_int_set_si(bmap->eq[k][1 + total + aff->n_div], 0); + } + obj = isl_vec_alloc(map->ctx, 1 + nparam + d); + if (!obj) + goto error; + isl_seq_clr(obj->el, 1 + nparam + d); + for (i = 0; i < d; ++ i) { + enum isl_lp_result res; + + isl_int_set_si(obj->el[1 + nparam + i], 1); + + res = isl_set_solve_lp(delta, 0, obj->el, map->ctx->one, &opt, + NULL, NULL); + if (res == isl_lp_error) + goto error; + if (res == isl_lp_ok) { + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->ineq[k], + 1 + nparam + 2 * d + bmap->n_div); + isl_int_set_si(bmap->ineq[k][1 + nparam + i], -1); + isl_int_set_si(bmap->ineq[k][1 + nparam + d + i], 1); + isl_int_neg(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], opt); + } + + res = isl_set_solve_lp(delta, 1, obj->el, map->ctx->one, &opt, + NULL, NULL); + if (res == isl_lp_error) + goto error; + if (res == isl_lp_ok) { + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->ineq[k], + 1 + nparam + 2 * d + bmap->n_div); + isl_int_set_si(bmap->ineq[k][1 + nparam + i], 1); + isl_int_set_si(bmap->ineq[k][1 + nparam + d + i], -1); + isl_int_set(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], opt); + } + + isl_int_set_si(obj->el[1 + nparam + i], 0); + } + k = isl_basic_map_alloc_inequality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->ineq[k], + 1 + nparam + 2 * d + bmap->n_div); + if (!with_id) + isl_int_set_si(bmap->ineq[k][0], -1); + isl_int_set_si(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], 1); + + app = isl_map_from_domain_and_range(dom, ran); + + isl_vec_free(obj); + isl_basic_set_free(aff); + isl_map_free(map); + bmap = isl_basic_map_finalize(bmap); + isl_set_free(delta); + isl_int_clear(opt); + + map = isl_map_from_basic_map(bmap); + map = isl_map_intersect(map, app); + + return map; +error: + isl_vec_free(obj); + isl_basic_map_free(bmap); + isl_basic_set_free(aff); + isl_set_free(dom); + isl_set_free(ran); + isl_map_free(map); + isl_set_free(delta); + isl_int_clear(opt); + return NULL; +} + +/* Given a map, compute the smallest superset of this map that is of the form + * + * { i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p } + * + * (where p ranges over the (non-parametric) dimensions), + * compute the transitive closure of this map, i.e., + * + * { i -> j : exists k > 0: + * k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p } + * + * and intersect domain and range of this transitive closure with + * domain and range of the original map. + */ +static __isl_give isl_map *box_closure(__isl_take isl_map *map) +{ + isl_set *domain; + isl_set *range; + + domain = isl_map_domain(isl_map_copy(map)); + domain = isl_set_coalesce(domain); + range = isl_map_range(isl_map_copy(map)); + range = isl_set_coalesce(range); + + return box_closure_on_domain(map, domain, range, 0); +} + +/* Given a map, compute the smallest superset of this map that is of the form + * + * { i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p } + * + * (where p ranges over the (non-parametric) dimensions), + * compute the transitive and partially reflexive closure of this map, i.e., + * + * { i -> j : exists k >= 0: + * k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p } + * + * and intersect domain and range of this transitive closure with + * the given domain. + */ +static __isl_give isl_map *box_closure_with_identity(__isl_take isl_map *map, + __isl_take isl_set *dom) +{ + return box_closure_on_domain(map, dom, isl_set_copy(dom), 1); +} + +/* Check whether app is the transitive closure of map. + * In particular, check that app is acyclic and, if so, + * check that + * + * app \subset (map \cup (map \circ app)) + */ +static int check_exactness_omega(__isl_keep isl_map *map, + __isl_keep isl_map *app) +{ + isl_set *delta; + int i; + int is_empty, is_exact; + unsigned d; + isl_map *test; + + delta = isl_map_deltas(isl_map_copy(app)); + d = isl_set_dim(delta, isl_dim_set); + for (i = 0; i < d; ++i) + delta = isl_set_fix_si(delta, isl_dim_set, i, 0); + is_empty = isl_set_is_empty(delta); + isl_set_free(delta); + if (is_empty < 0) + return -1; + if (!is_empty) + return 0; + + test = isl_map_apply_range(isl_map_copy(app), isl_map_copy(map)); + test = isl_map_union(test, isl_map_copy(map)); + is_exact = isl_map_is_subset(app, test); + isl_map_free(test); + + return is_exact; +} + +/* Check if basic map M_i can be combined with all the other + * basic maps such that + * + * (\cup_j M_j)^+ + * + * can be computed as + * + * M_i \cup (\cup_{j \ne i} M_i^* \circ M_j \circ M_i^*)^+ + * + * In particular, check if we can compute a compact representation + * of + * + * M_i^* \circ M_j \circ M_i^* + * + * for each j != i. + * Let M_i^? be an extension of M_i^+ that allows paths + * of length zero, i.e., the result of box_closure(., 1). + * The criterion, as proposed by Kelly et al., is that + * id = M_i^? - M_i^+ can be represented as a basic map + * and that + * + * id \circ M_j \circ id = M_j + * + * for each j != i. + * + * If this function returns 1, then tc and qc are set to + * M_i^+ and M_i^?, respectively. + */ +static int can_be_split_off(__isl_keep isl_map *map, int i, + __isl_give isl_map **tc, __isl_give isl_map **qc) +{ + isl_map *map_i, *id = NULL; + int j = -1; + isl_set *C; + + *tc = NULL; + *qc = NULL; + + C = isl_set_union(isl_map_domain(isl_map_copy(map)), + isl_map_range(isl_map_copy(map))); + C = isl_set_from_basic_set(isl_set_simple_hull(C)); + if (!C) + goto error; + + map_i = isl_map_from_basic_map(isl_basic_map_copy(map->p[i])); + *tc = box_closure(isl_map_copy(map_i)); + *qc = box_closure_with_identity(map_i, C); + id = isl_map_subtract(isl_map_copy(*qc), isl_map_copy(*tc)); + + if (!id || !*qc) + goto error; + if (id->n != 1 || (*qc)->n != 1) + goto done; + + for (j = 0; j < map->n; ++j) { + isl_map *map_j, *test; + int is_ok; + + if (i == j) + continue; + map_j = isl_map_from_basic_map( + isl_basic_map_copy(map->p[j])); + test = isl_map_apply_range(isl_map_copy(id), + isl_map_copy(map_j)); + test = isl_map_apply_range(test, isl_map_copy(id)); + is_ok = isl_map_is_equal(test, map_j); + isl_map_free(map_j); + isl_map_free(test); + if (is_ok < 0) + goto error; + if (!is_ok) + break; + } + +done: + isl_map_free(id); + if (j == map->n) + return 1; + + isl_map_free(*qc); + isl_map_free(*tc); + *qc = NULL; + *tc = NULL; + + return 0; +error: + isl_map_free(id); + isl_map_free(*qc); + isl_map_free(*tc); + *qc = NULL; + *tc = NULL; + return -1; +} + +static __isl_give isl_map *box_closure_with_check(__isl_take isl_map *map, + int *exact) +{ + isl_map *app; + + app = box_closure(isl_map_copy(map)); + if (exact) + *exact = check_exactness_omega(map, app); + + isl_map_free(map); + return app; +} + +/* Compute an overapproximation of the transitive closure of "map" + * using a variation of the algorithm from + * "Transitive Closure of Infinite Graphs and its Applications" + * by Kelly et al. + * + * We first check whether we can can split of any basic map M_i and + * compute + * + * (\cup_j M_j)^+ + * + * as + * + * M_i \cup (\cup_{j \ne i} M_i^* \circ M_j \circ M_i^*)^+ + * + * using a recursive call on the remaining map. + * + * If not, we simply call box_closure on the whole map. + */ +static __isl_give isl_map *transitive_closure_omega(__isl_take isl_map *map, + int *exact) +{ + int i, j; + int exact_i; + isl_map *app; + + if (!map) + return NULL; + if (map->n == 1) + return box_closure_with_check(map, exact); + + for (i = 0; i < map->n; ++i) { + int ok; + isl_map *qc, *tc; + ok = can_be_split_off(map, i, &tc, &qc); + if (ok < 0) + goto error; + if (!ok) + continue; + + app = isl_map_alloc_space(isl_map_get_space(map), map->n - 1, 0); + + for (j = 0; j < map->n; ++j) { + if (j == i) + continue; + app = isl_map_add_basic_map(app, + isl_basic_map_copy(map->p[j])); + } + + app = isl_map_apply_range(isl_map_copy(qc), app); + app = isl_map_apply_range(app, qc); + + app = isl_map_union(tc, transitive_closure_omega(app, NULL)); + exact_i = check_exactness_omega(map, app); + if (exact_i == 1) { + if (exact) + *exact = exact_i; + isl_map_free(map); + return app; + } + isl_map_free(app); + if (exact_i < 0) + goto error; + } + + return box_closure_with_check(map, exact); +error: + isl_map_free(map); + return NULL; +} + +/* Compute the transitive closure of "map", or an overapproximation. + * If the result is exact, then *exact is set to 1. + * Simply use map_power to compute the powers of map, but tell + * it to project out the lengths of the paths instead of equating + * the length to a parameter. + */ +__isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map, + int *exact) +{ + isl_space *target_dim; + int closed; + + if (!map) + goto error; + + if (map->ctx->opt->closure == ISL_CLOSURE_BOX) + return transitive_closure_omega(map, exact); + + map = isl_map_compute_divs(map); + map = isl_map_coalesce(map); + closed = isl_map_is_transitively_closed(map); + if (closed < 0) + goto error; + if (closed) { + if (exact) + *exact = 1; + return map; + } + + target_dim = isl_map_get_space(map); + map = map_power(map, exact, 1); + map = isl_map_reset_space(map, target_dim); + + return map; +error: + isl_map_free(map); + return NULL; +} + +static isl_stat inc_count(__isl_take isl_map *map, void *user) +{ + int *n = user; + + *n += map->n; + + isl_map_free(map); + + return isl_stat_ok; +} + +static isl_stat collect_basic_map(__isl_take isl_map *map, void *user) +{ + int i; + isl_basic_map ***next = user; + + for (i = 0; i < map->n; ++i) { + **next = isl_basic_map_copy(map->p[i]); + if (!**next) + goto error; + (*next)++; + } + + isl_map_free(map); + return isl_stat_ok; +error: + isl_map_free(map); + return isl_stat_error; +} + +/* Perform Floyd-Warshall on the given list of basic relations. + * The basic relations may live in different dimensions, + * but basic relations that get assigned to the diagonal of the + * grid have domains and ranges of the same dimension and so + * the standard algorithm can be used because the nested transitive + * closures are only applied to diagonal elements and because all + * compositions are peformed on relations with compatible domains and ranges. + */ +static __isl_give isl_union_map *union_floyd_warshall_on_list(isl_ctx *ctx, + __isl_keep isl_basic_map **list, int n, int *exact) +{ + int i, j, k; + int n_group; + int *group = NULL; + isl_set **set = NULL; + isl_map ***grid = NULL; + isl_union_map *app; + + group = setup_groups(ctx, list, n, &set, &n_group); + if (!group) + goto error; + + grid = isl_calloc_array(ctx, isl_map **, n_group); + if (!grid) + goto error; + for (i = 0; i < n_group; ++i) { + grid[i] = isl_calloc_array(ctx, isl_map *, n_group); + if (!grid[i]) + goto error; + for (j = 0; j < n_group; ++j) { + isl_space *dim1, *dim2, *dim; + dim1 = isl_space_reverse(isl_set_get_space(set[i])); + dim2 = isl_set_get_space(set[j]); + dim = isl_space_join(dim1, dim2); + grid[i][j] = isl_map_empty(dim); + } + } + + for (k = 0; k < n; ++k) { + i = group[2 * k]; + j = group[2 * k + 1]; + grid[i][j] = isl_map_union(grid[i][j], + isl_map_from_basic_map( + isl_basic_map_copy(list[k]))); + } + + floyd_warshall_iterate(grid, n_group, exact); + + app = isl_union_map_empty(isl_map_get_space(grid[0][0])); + + for (i = 0; i < n_group; ++i) { + for (j = 0; j < n_group; ++j) + app = isl_union_map_add_map(app, grid[i][j]); + free(grid[i]); + } + free(grid); + + for (i = 0; i < 2 * n; ++i) + isl_set_free(set[i]); + free(set); + + free(group); + return app; +error: + if (grid) + for (i = 0; i < n_group; ++i) { + if (!grid[i]) + continue; + for (j = 0; j < n_group; ++j) + isl_map_free(grid[i][j]); + free(grid[i]); + } + free(grid); + if (set) { + for (i = 0; i < 2 * n; ++i) + isl_set_free(set[i]); + free(set); + } + free(group); + return NULL; +} + +/* Perform Floyd-Warshall on the given union relation. + * The implementation is very similar to that for non-unions. + * The main difference is that it is applied unconditionally. + * We first extract a list of basic maps from the union map + * and then perform the algorithm on this list. + */ +static __isl_give isl_union_map *union_floyd_warshall( + __isl_take isl_union_map *umap, int *exact) +{ + int i, n; + isl_ctx *ctx; + isl_basic_map **list = NULL; + isl_basic_map **next; + isl_union_map *res; + + n = 0; + if (isl_union_map_foreach_map(umap, inc_count, &n) < 0) + goto error; + + ctx = isl_union_map_get_ctx(umap); + list = isl_calloc_array(ctx, isl_basic_map *, n); + if (!list) + goto error; + + next = list; + if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0) + goto error; + + res = union_floyd_warshall_on_list(ctx, list, n, exact); + + if (list) { + for (i = 0; i < n; ++i) + isl_basic_map_free(list[i]); + free(list); + } + + isl_union_map_free(umap); + return res; +error: + if (list) { + for (i = 0; i < n; ++i) + isl_basic_map_free(list[i]); + free(list); + } + isl_union_map_free(umap); + return NULL; +} + +/* Decompose the give union relation into strongly connected components. + * The implementation is essentially the same as that of + * construct_power_components with the major difference that all + * operations are performed on union maps. + */ +static __isl_give isl_union_map *union_components( + __isl_take isl_union_map *umap, int *exact) +{ + int i; + int n; + isl_ctx *ctx; + isl_basic_map **list = NULL; + isl_basic_map **next; + isl_union_map *path = NULL; + struct isl_tc_follows_data data; + struct isl_tarjan_graph *g = NULL; + int c, l; + int recheck = 0; + + n = 0; + if (isl_union_map_foreach_map(umap, inc_count, &n) < 0) + goto error; + + if (n == 0) + return umap; + if (n <= 1) + return union_floyd_warshall(umap, exact); + + ctx = isl_union_map_get_ctx(umap); + list = isl_calloc_array(ctx, isl_basic_map *, n); + if (!list) + goto error; + + next = list; + if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0) + goto error; + + data.list = list; + data.check_closed = 0; + g = isl_tarjan_graph_init(ctx, n, &basic_map_follows, &data); + if (!g) + goto error; + + c = 0; + i = 0; + l = n; + path = isl_union_map_empty(isl_union_map_get_space(umap)); + while (l) { + isl_union_map *comp; + isl_union_map *path_comp, *path_comb; + comp = isl_union_map_empty(isl_union_map_get_space(umap)); + while (g->order[i] != -1) { + comp = isl_union_map_add_map(comp, + isl_map_from_basic_map( + isl_basic_map_copy(list[g->order[i]]))); + --l; + ++i; + } + path_comp = union_floyd_warshall(comp, exact); + path_comb = isl_union_map_apply_range(isl_union_map_copy(path), + isl_union_map_copy(path_comp)); + path = isl_union_map_union(path, path_comp); + path = isl_union_map_union(path, path_comb); + ++i; + ++c; + } + + if (c > 1 && data.check_closed && !*exact) { + int closed; + + closed = isl_union_map_is_transitively_closed(path); + if (closed < 0) + goto error; + recheck = !closed; + } + + isl_tarjan_graph_free(g); + + for (i = 0; i < n; ++i) + isl_basic_map_free(list[i]); + free(list); + + if (recheck) { + isl_union_map_free(path); + return union_floyd_warshall(umap, exact); + } + + isl_union_map_free(umap); + + return path; +error: + isl_tarjan_graph_free(g); + if (list) { + for (i = 0; i < n; ++i) + isl_basic_map_free(list[i]); + free(list); + } + isl_union_map_free(umap); + isl_union_map_free(path); + return NULL; +} + +/* Compute the transitive closure of "umap", or an overapproximation. + * If the result is exact, then *exact is set to 1. + */ +__isl_give isl_union_map *isl_union_map_transitive_closure( + __isl_take isl_union_map *umap, int *exact) +{ + int closed; + + if (!umap) + return NULL; + + if (exact) + *exact = 1; + + umap = isl_union_map_compute_divs(umap); + umap = isl_union_map_coalesce(umap); + closed = isl_union_map_is_transitively_closed(umap); + if (closed < 0) + goto error; + if (closed) + return umap; + umap = union_components(umap, exact); + return umap; +error: + isl_union_map_free(umap); + return NULL; +} + +struct isl_union_power { + isl_union_map *pow; + int *exact; +}; + +static isl_stat power(__isl_take isl_map *map, void *user) +{ + struct isl_union_power *up = user; + + map = isl_map_power(map, up->exact); + up->pow = isl_union_map_from_map(map); + + return isl_stat_error; +} + +/* Construct a map [x] -> [x+1], with parameters prescribed by "dim". + */ +static __isl_give isl_union_map *increment(__isl_take isl_space *dim) +{ + int k; + isl_basic_map *bmap; + + dim = isl_space_add_dims(dim, isl_dim_in, 1); + dim = isl_space_add_dims(dim, isl_dim_out, 1); + bmap = isl_basic_map_alloc_space(dim, 0, 1, 0); + k = isl_basic_map_alloc_equality(bmap); + if (k < 0) + goto error; + isl_seq_clr(bmap->eq[k], isl_basic_map_total_dim(bmap)); + isl_int_set_si(bmap->eq[k][0], 1); + isl_int_set_si(bmap->eq[k][isl_basic_map_offset(bmap, isl_dim_in)], 1); + isl_int_set_si(bmap->eq[k][isl_basic_map_offset(bmap, isl_dim_out)], -1); + return isl_union_map_from_map(isl_map_from_basic_map(bmap)); +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Construct a map [[x]->[y]] -> [y-x], with parameters prescribed by "dim". + */ +static __isl_give isl_union_map *deltas_map(__isl_take isl_space *dim) +{ + isl_basic_map *bmap; + + dim = isl_space_add_dims(dim, isl_dim_in, 1); + dim = isl_space_add_dims(dim, isl_dim_out, 1); + bmap = isl_basic_map_universe(dim); + bmap = isl_basic_map_deltas_map(bmap); + + return isl_union_map_from_map(isl_map_from_basic_map(bmap)); +} + +/* Compute the positive powers of "map", or an overapproximation. + * The result maps the exponent to a nested copy of the corresponding power. + * If the result is exact, then *exact is set to 1. + */ +__isl_give isl_union_map *isl_union_map_power(__isl_take isl_union_map *umap, + int *exact) +{ + int n; + isl_union_map *inc; + isl_union_map *dm; + + if (!umap) + return NULL; + n = isl_union_map_n_map(umap); + if (n == 0) + return umap; + if (n == 1) { + struct isl_union_power up = { NULL, exact }; + isl_union_map_foreach_map(umap, &power, &up); + isl_union_map_free(umap); + return up.pow; + } + inc = increment(isl_union_map_get_space(umap)); + umap = isl_union_map_product(inc, umap); + umap = isl_union_map_transitive_closure(umap, exact); + umap = isl_union_map_zip(umap); + dm = deltas_map(isl_union_map_get_space(umap)); + umap = isl_union_map_apply_domain(umap, dm); + + return umap; +} + +#undef TYPE +#define TYPE isl_map +#include "isl_power_templ.c" + +#undef TYPE +#define TYPE isl_union_map +#include "isl_power_templ.c" Index: contrib/isl/isl_union_eval.c =================================================================== --- /dev/null +++ contrib/isl/isl_union_eval.c @@ -0,0 +1,58 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#include + +/* Is the domain space of "entry" equal to "space"? + */ +static int FN(UNION,has_domain_space)(const void *entry, const void *val) +{ + PART *part = (PART *)entry; + isl_space *space = (isl_space *) val; + + if (isl_space_is_params(space)) + return isl_space_is_set(part->dim); + + return isl_space_tuple_is_equal(part->dim, isl_dim_in, + space, isl_dim_set); +} + +__isl_give isl_val *FN(UNION,eval)(__isl_take UNION *u, + __isl_take isl_point *pnt) +{ + uint32_t hash; + struct isl_hash_table_entry *entry; + isl_space *space; + isl_val *v; + + if (!u || !pnt) + goto error; + + space = isl_space_copy(pnt->dim); + if (!space) + goto error; + hash = isl_space_get_hash(space); + entry = isl_hash_table_find(u->space->ctx, &u->table, + hash, &FN(UNION,has_domain_space), + space, 0); + isl_space_free(space); + if (!entry) { + v = isl_val_zero(isl_point_get_ctx(pnt)); + isl_point_free(pnt); + } else { + v = FN(PART,eval)(FN(PART,copy)(entry->data), pnt); + } + FN(UNION,free)(u); + return v; +error: + FN(UNION,free)(u); + isl_point_free(pnt); + return NULL; +} Index: contrib/isl/isl_union_macro.h =================================================================== --- /dev/null +++ contrib/isl/isl_union_macro.h @@ -0,0 +1,4 @@ +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) +#define xS(TYPE,NAME) struct TYPE ## _ ## NAME +#define S(TYPE,NAME) xS(TYPE,NAME) Index: contrib/isl/isl_union_map.c =================================================================== --- /dev/null +++ contrib/isl/isl_union_map.c @@ -0,0 +1,4031 @@ +/* + * Copyright 2010-2011 INRIA Saclay + * Copyright 2013-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * Copyright 2016-2017 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + */ + +#define ISL_DIM_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Return the number of parameters of "umap", where "type" + * is required to be set to isl_dim_param. + */ +unsigned isl_union_map_dim(__isl_keep isl_union_map *umap, + enum isl_dim_type type) +{ + if (!umap) + return 0; + + if (type != isl_dim_param) + isl_die(isl_union_map_get_ctx(umap), isl_error_invalid, + "can only reference parameters", return 0); + + return isl_space_dim(umap->dim, type); +} + +/* Return the number of parameters of "uset", where "type" + * is required to be set to isl_dim_param. + */ +unsigned isl_union_set_dim(__isl_keep isl_union_set *uset, + enum isl_dim_type type) +{ + return isl_union_map_dim(uset, type); +} + +/* Return the id of the specified dimension. + */ +__isl_give isl_id *isl_union_map_get_dim_id(__isl_keep isl_union_map *umap, + enum isl_dim_type type, unsigned pos) +{ + if (!umap) + return NULL; + + if (type != isl_dim_param) + isl_die(isl_union_map_get_ctx(umap), isl_error_invalid, + "can only reference parameters", return NULL); + + return isl_space_get_dim_id(umap->dim, type, pos); +} + +/* Is this union set a parameter domain? + */ +isl_bool isl_union_set_is_params(__isl_keep isl_union_set *uset) +{ + isl_set *set; + isl_bool params; + + if (!uset) + return isl_bool_error; + if (uset->table.n != 1) + return isl_bool_false; + + set = isl_set_from_union_set(isl_union_set_copy(uset)); + params = isl_set_is_params(set); + isl_set_free(set); + return params; +} + +static __isl_give isl_union_map *isl_union_map_alloc( + __isl_take isl_space *space, int size) +{ + isl_union_map *umap; + + space = isl_space_params(space); + if (!space) + return NULL; + + umap = isl_calloc_type(space->ctx, isl_union_map); + if (!umap) { + isl_space_free(space); + return NULL; + } + + umap->ref = 1; + umap->dim = space; + if (isl_hash_table_init(space->ctx, &umap->table, size) < 0) + return isl_union_map_free(umap); + + return umap; +} + +__isl_give isl_union_map *isl_union_map_empty(__isl_take isl_space *space) +{ + return isl_union_map_alloc(space, 16); +} + +__isl_give isl_union_set *isl_union_set_empty(__isl_take isl_space *space) +{ + return isl_union_map_empty(space); +} + +isl_ctx *isl_union_map_get_ctx(__isl_keep isl_union_map *umap) +{ + return umap ? umap->dim->ctx : NULL; +} + +isl_ctx *isl_union_set_get_ctx(__isl_keep isl_union_set *uset) +{ + return uset ? uset->dim->ctx : NULL; +} + +/* Return the space of "umap". + */ +__isl_keep isl_space *isl_union_map_peek_space(__isl_keep isl_union_map *umap) +{ + return umap ? umap->dim : NULL; +} + +__isl_give isl_space *isl_union_map_get_space(__isl_keep isl_union_map *umap) +{ + return isl_space_copy(isl_union_map_peek_space(umap)); +} + +/* Return the position of the parameter with the given name + * in "umap". + * Return -1 if no such dimension can be found. + */ +int isl_union_map_find_dim_by_name(__isl_keep isl_union_map *umap, + enum isl_dim_type type, const char *name) +{ + if (!umap) + return -1; + return isl_space_find_dim_by_name(umap->dim, type, name); +} + +__isl_give isl_space *isl_union_set_get_space(__isl_keep isl_union_set *uset) +{ + return isl_union_map_get_space(uset); +} + +static isl_stat free_umap_entry(void **entry, void *user) +{ + isl_map *map = *entry; + isl_map_free(map); + return isl_stat_ok; +} + +static isl_stat add_map(__isl_take isl_map *map, void *user) +{ + isl_union_map **umap = (isl_union_map **)user; + + *umap = isl_union_map_add_map(*umap, map); + + return isl_stat_ok; +} + +__isl_give isl_union_map *isl_union_map_dup(__isl_keep isl_union_map *umap) +{ + isl_union_map *dup; + + if (!umap) + return NULL; + + dup = isl_union_map_empty(isl_space_copy(umap->dim)); + if (isl_union_map_foreach_map(umap, &add_map, &dup) < 0) + goto error; + return dup; +error: + isl_union_map_free(dup); + return NULL; +} + +__isl_give isl_union_map *isl_union_map_cow(__isl_take isl_union_map *umap) +{ + if (!umap) + return NULL; + + if (umap->ref == 1) + return umap; + umap->ref--; + return isl_union_map_dup(umap); +} + +struct isl_union_align { + isl_reordering *exp; + isl_union_map *res; +}; + +static isl_stat align_entry(void **entry, void *user) +{ + isl_map *map = *entry; + isl_reordering *exp; + struct isl_union_align *data = user; + + exp = isl_reordering_extend_space(isl_reordering_copy(data->exp), + isl_map_get_space(map)); + + data->res = isl_union_map_add_map(data->res, + isl_map_realign(isl_map_copy(map), exp)); + + return isl_stat_ok; +} + +/* Align the parameters of umap along those of model. + * The result has the parameters of model first, in the same order + * as they appear in model, followed by any remaining parameters of + * umap that do not appear in model. + */ +__isl_give isl_union_map *isl_union_map_align_params( + __isl_take isl_union_map *umap, __isl_take isl_space *model) +{ + struct isl_union_align data = { NULL, NULL }; + isl_bool equal_params; + + if (!umap || !model) + goto error; + + equal_params = isl_space_has_equal_params(umap->dim, model); + if (equal_params < 0) + goto error; + if (equal_params) { + isl_space_free(model); + return umap; + } + + model = isl_space_params(model); + data.exp = isl_parameter_alignment_reordering(umap->dim, model); + if (!data.exp) + goto error; + + data.res = isl_union_map_alloc(isl_space_copy(data.exp->dim), + umap->table.n); + if (isl_hash_table_foreach(umap->dim->ctx, &umap->table, + &align_entry, &data) < 0) + goto error; + + isl_reordering_free(data.exp); + isl_union_map_free(umap); + isl_space_free(model); + return data.res; +error: + isl_reordering_free(data.exp); + isl_union_map_free(umap); + isl_union_map_free(data.res); + isl_space_free(model); + return NULL; +} + +__isl_give isl_union_set *isl_union_set_align_params( + __isl_take isl_union_set *uset, __isl_take isl_space *model) +{ + return isl_union_map_align_params(uset, model); +} + +__isl_give isl_union_map *isl_union_map_union(__isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2) +{ + umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2)); + umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1)); + + umap1 = isl_union_map_cow(umap1); + + if (!umap1 || !umap2) + goto error; + + if (isl_union_map_foreach_map(umap2, &add_map, &umap1) < 0) + goto error; + + isl_union_map_free(umap2); + + return umap1; +error: + isl_union_map_free(umap1); + isl_union_map_free(umap2); + return NULL; +} + +__isl_give isl_union_set *isl_union_set_union(__isl_take isl_union_set *uset1, + __isl_take isl_union_set *uset2) +{ + return isl_union_map_union(uset1, uset2); +} + +__isl_give isl_union_map *isl_union_map_copy(__isl_keep isl_union_map *umap) +{ + if (!umap) + return NULL; + + umap->ref++; + return umap; +} + +__isl_give isl_union_set *isl_union_set_copy(__isl_keep isl_union_set *uset) +{ + return isl_union_map_copy(uset); +} + +__isl_null isl_union_map *isl_union_map_free(__isl_take isl_union_map *umap) +{ + if (!umap) + return NULL; + + if (--umap->ref > 0) + return NULL; + + isl_hash_table_foreach(umap->dim->ctx, &umap->table, + &free_umap_entry, NULL); + isl_hash_table_clear(&umap->table); + isl_space_free(umap->dim); + free(umap); + return NULL; +} + +__isl_null isl_union_set *isl_union_set_free(__isl_take isl_union_set *uset) +{ + return isl_union_map_free(uset); +} + +/* Do "umap" and "space" have the same parameters? + */ +isl_bool isl_union_map_space_has_equal_params(__isl_keep isl_union_map *umap, + __isl_keep isl_space *space) +{ + isl_space *umap_space; + + umap_space = isl_union_map_peek_space(umap); + return isl_space_has_equal_params(umap_space, space); +} + +static int has_space(const void *entry, const void *val) +{ + isl_map *map = (isl_map *)entry; + isl_space *space = (isl_space *) val; + + return isl_space_is_equal(map->dim, space); +} + +__isl_give isl_union_map *isl_union_map_add_map(__isl_take isl_union_map *umap, + __isl_take isl_map *map) +{ + uint32_t hash; + struct isl_hash_table_entry *entry; + isl_bool aligned; + + if (!map || !umap) + goto error; + + if (isl_map_plain_is_empty(map)) { + isl_map_free(map); + return umap; + } + + aligned = isl_map_space_has_equal_params(map, umap->dim); + if (aligned < 0) + goto error; + if (!aligned) { + umap = isl_union_map_align_params(umap, isl_map_get_space(map)); + map = isl_map_align_params(map, isl_union_map_get_space(umap)); + } + + umap = isl_union_map_cow(umap); + + if (!map || !umap) + goto error; + + hash = isl_space_get_hash(map->dim); + entry = isl_hash_table_find(umap->dim->ctx, &umap->table, hash, + &has_space, map->dim, 1); + if (!entry) + goto error; + + if (!entry->data) + entry->data = map; + else { + entry->data = isl_map_union(entry->data, isl_map_copy(map)); + if (!entry->data) + goto error; + isl_map_free(map); + } + + return umap; +error: + isl_map_free(map); + isl_union_map_free(umap); + return NULL; +} + +__isl_give isl_union_set *isl_union_set_add_set(__isl_take isl_union_set *uset, + __isl_take isl_set *set) +{ + return isl_union_map_add_map(uset, set_to_map(set)); +} + +__isl_give isl_union_map *isl_union_map_from_map(__isl_take isl_map *map) +{ + isl_space *dim; + isl_union_map *umap; + + if (!map) + return NULL; + + dim = isl_map_get_space(map); + dim = isl_space_params(dim); + umap = isl_union_map_empty(dim); + umap = isl_union_map_add_map(umap, map); + + return umap; +} + +__isl_give isl_union_set *isl_union_set_from_set(__isl_take isl_set *set) +{ + return isl_union_map_from_map(set_to_map(set)); +} + +__isl_give isl_union_map *isl_union_map_from_basic_map( + __isl_take isl_basic_map *bmap) +{ + return isl_union_map_from_map(isl_map_from_basic_map(bmap)); +} + +__isl_give isl_union_set *isl_union_set_from_basic_set( + __isl_take isl_basic_set *bset) +{ + return isl_union_map_from_basic_map(bset); +} + +struct isl_union_map_foreach_data +{ + isl_stat (*fn)(__isl_take isl_map *map, void *user); + void *user; +}; + +static isl_stat call_on_copy(void **entry, void *user) +{ + isl_map *map = *entry; + struct isl_union_map_foreach_data *data; + data = (struct isl_union_map_foreach_data *)user; + + return data->fn(isl_map_copy(map), data->user); +} + +int isl_union_map_n_map(__isl_keep isl_union_map *umap) +{ + return umap ? umap->table.n : 0; +} + +int isl_union_set_n_set(__isl_keep isl_union_set *uset) +{ + return uset ? uset->table.n : 0; +} + +isl_stat isl_union_map_foreach_map(__isl_keep isl_union_map *umap, + isl_stat (*fn)(__isl_take isl_map *map, void *user), void *user) +{ + struct isl_union_map_foreach_data data = { fn, user }; + + if (!umap) + return isl_stat_error; + + return isl_hash_table_foreach(umap->dim->ctx, &umap->table, + &call_on_copy, &data); +} + +/* Internal data structure for isl_union_map_every_map. + * + * "test" is the user-specified callback function. + * "user" is the user-specified callback function argument. + * + * "failed" is initialized to 0 and set to 1 if "test" fails + * on any map. + */ +struct isl_union_map_every_data { + isl_bool (*test)(__isl_keep isl_map *map, void *user); + void *user; + int failed; +}; + +/* Call data->test on "map". + * If this fails, then set data->failed and abort. + */ +static isl_stat call_every(void **entry, void *user) +{ + isl_map *map = *entry; + struct isl_union_map_every_data *data = user; + isl_bool r; + + r = data->test(map, data->user); + if (r < 0) + return isl_stat_error; + if (r) + return isl_stat_ok; + data->failed = 1; + return isl_stat_error; +} + +/* Does "test" succeed on every map in "umap"? + */ +isl_bool isl_union_map_every_map(__isl_keep isl_union_map *umap, + isl_bool (*test)(__isl_keep isl_map *map, void *user), void *user) +{ + struct isl_union_map_every_data data = { test, user, 0 }; + isl_stat r; + + if (!umap) + return isl_bool_error; + + r = isl_hash_table_foreach(isl_union_map_get_ctx(umap), &umap->table, + &call_every, &data); + if (r >= 0) + return isl_bool_true; + if (data.failed) + return isl_bool_false; + return isl_bool_error; +} + +static isl_stat copy_map(void **entry, void *user) +{ + isl_map *map = *entry; + isl_map **map_p = user; + + *map_p = isl_map_copy(map); + + return isl_stat_error; +} + +__isl_give isl_map *isl_map_from_union_map(__isl_take isl_union_map *umap) +{ + isl_ctx *ctx; + isl_map *map = NULL; + + if (!umap) + return NULL; + ctx = isl_union_map_get_ctx(umap); + if (umap->table.n != 1) + isl_die(ctx, isl_error_invalid, + "union map needs to contain elements in exactly " + "one space", goto error); + + isl_hash_table_foreach(ctx, &umap->table, ©_map, &map); + + isl_union_map_free(umap); + + return map; +error: + isl_union_map_free(umap); + return NULL; +} + +__isl_give isl_set *isl_set_from_union_set(__isl_take isl_union_set *uset) +{ + return isl_map_from_union_map(uset); +} + +/* Extract the map in "umap" that lives in the given space (ignoring + * parameters). + */ +__isl_give isl_map *isl_union_map_extract_map(__isl_keep isl_union_map *umap, + __isl_take isl_space *space) +{ + uint32_t hash; + struct isl_hash_table_entry *entry; + + space = isl_space_drop_dims(space, isl_dim_param, + 0, isl_space_dim(space, isl_dim_param)); + space = isl_space_align_params(space, isl_union_map_get_space(umap)); + if (!umap || !space) + goto error; + + hash = isl_space_get_hash(space); + entry = isl_hash_table_find(umap->dim->ctx, &umap->table, hash, + &has_space, space, 0); + if (!entry) + return isl_map_empty(space); + isl_space_free(space); + return isl_map_copy(entry->data); +error: + isl_space_free(space); + return NULL; +} + +__isl_give isl_set *isl_union_set_extract_set(__isl_keep isl_union_set *uset, + __isl_take isl_space *dim) +{ + return set_from_map(isl_union_map_extract_map(uset, dim)); +} + +/* Check if umap contains a map in the given space. + */ +isl_bool isl_union_map_contains(__isl_keep isl_union_map *umap, + __isl_keep isl_space *space) +{ + uint32_t hash; + struct isl_hash_table_entry *entry; + + if (!umap || !space) + return isl_bool_error; + + hash = isl_space_get_hash(space); + entry = isl_hash_table_find(umap->dim->ctx, &umap->table, hash, + &has_space, space, 0); + return !!entry; +} + +isl_bool isl_union_set_contains(__isl_keep isl_union_set *uset, + __isl_keep isl_space *space) +{ + return isl_union_map_contains(uset, space); +} + +isl_stat isl_union_set_foreach_set(__isl_keep isl_union_set *uset, + isl_stat (*fn)(__isl_take isl_set *set, void *user), void *user) +{ + return isl_union_map_foreach_map(uset, + (isl_stat(*)(__isl_take isl_map *, void*))fn, user); +} + +struct isl_union_set_foreach_point_data { + isl_stat (*fn)(__isl_take isl_point *pnt, void *user); + void *user; +}; + +static isl_stat foreach_point(__isl_take isl_set *set, void *user) +{ + struct isl_union_set_foreach_point_data *data = user; + isl_stat r; + + r = isl_set_foreach_point(set, data->fn, data->user); + isl_set_free(set); + + return r; +} + +isl_stat isl_union_set_foreach_point(__isl_keep isl_union_set *uset, + isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user) +{ + struct isl_union_set_foreach_point_data data = { fn, user }; + return isl_union_set_foreach_set(uset, &foreach_point, &data); +} + +/* Data structure that specifies how gen_bin_op should + * construct results from the inputs. + * + * If "subtract" is set, then a map in the first input is copied to the result + * if there is no corresponding map in the second input. + * Otherwise, a map in the first input with no corresponding map + * in the second input is ignored. + * If "filter" is not NULL, then it specifies which maps in the first + * input may have a matching map in the second input. + * In particular, it makes sure that "match_space" can be called + * on the space of the map. + * "match_space" specifies how to transform the space of a map + * in the first input to the space of the corresponding map + * in the second input. + * "fn_map" specifies how the matching maps, one from each input, + * should be combined to form a map in the result. + */ +struct isl_bin_op_control { + int subtract; + isl_bool (*filter)(__isl_keep isl_map *map); + __isl_give isl_space *(*match_space)(__isl_take isl_space *space); + __isl_give isl_map *(*fn_map)(__isl_take isl_map *map1, + __isl_take isl_map *map2); +}; + +/* Internal data structure for gen_bin_op. + * "control" specifies how the maps in the result should be constructed. + * "umap2" is a pointer to the second argument. + * "res" collects the results. + */ +struct isl_union_map_gen_bin_data { + struct isl_bin_op_control *control; + isl_union_map *umap2; + isl_union_map *res; +}; + +/* Add a copy of "map" to "res" and return the result. + */ +static __isl_give isl_union_map *bin_add_map(__isl_take isl_union_map *res, + __isl_keep isl_map *map) +{ + return isl_union_map_add_map(res, isl_map_copy(map)); +} + +/* Combine "map1" and "map2", add the result to "res" and return the result. + * Check whether the result is empty before adding it to "res". + */ +static __isl_give isl_union_map *bin_add_pair(__isl_take isl_union_map *res, + __isl_keep isl_map *map1, __isl_keep isl_map *map2, + struct isl_union_map_gen_bin_data *data) +{ + isl_bool empty; + isl_map *map; + + map = data->control->fn_map(isl_map_copy(map1), isl_map_copy(map2)); + empty = isl_map_is_empty(map); + if (empty < 0 || empty) { + isl_map_free(map); + if (empty < 0) + return isl_union_map_free(res); + return res; + } + return isl_union_map_add_map(res, map); +} + +/* Dummy match_space function that simply returns the input space. + */ +static __isl_give isl_space *identity(__isl_take isl_space *space) +{ + return space; +} + +/* Look for the map in data->umap2 that corresponds to "map", if any. + * Return (isl_bool_true, matching map) if there is one, + * (isl_bool_false, NULL) if there is no matching map and + * (isl_bool_error, NULL) on error. + * + * If not NULL, then data->control->filter specifies whether "map" + * can have any matching map. If so, + * data->control->match_space specifies which map in data->umap2 + * corresponds to "map". + */ +static __isl_keep isl_maybe_isl_map bin_try_get_match( + struct isl_union_map_gen_bin_data *data, __isl_keep isl_map *map) +{ + uint32_t hash; + struct isl_hash_table_entry *entry2; + isl_space *space; + isl_maybe_isl_map res = { isl_bool_error, NULL }; + + if (data->control->filter) { + res.valid = data->control->filter(map); + if (res.valid < 0 || !res.valid) + return res; + res.valid = isl_bool_error; + } + + space = isl_map_get_space(map); + if (data->control->match_space != &identity) + space = data->control->match_space(space); + if (!space) + return res; + hash = isl_space_get_hash(space); + entry2 = isl_hash_table_find(isl_union_map_get_ctx(data->umap2), + &data->umap2->table, hash, + &has_space, space, 0); + isl_space_free(space); + res.valid = entry2 != NULL; + if (entry2) + res.value = entry2->data; + + return res; +} + +/* isl_hash_table_foreach callback for gen_bin_op. + * Look for the map in data->umap2 that corresponds + * to the map that "entry" points to, apply the binary operation and + * add the result to data->res. + * + * If no corresponding map can be found, then the effect depends + * on data->control->subtract. If it is set, then the current map + * is added directly to the result. Otherwise, it is ignored. + */ +static isl_stat gen_bin_entry(void **entry, void *user) +{ + struct isl_union_map_gen_bin_data *data = user; + isl_map *map = *entry; + isl_maybe_isl_map m; + + m = bin_try_get_match(data, map); + if (m.valid < 0) + return isl_stat_error; + if (!m.valid && !data->control->subtract) + return isl_stat_ok; + + if (!m.valid) + data->res = bin_add_map(data->res, map); + else + data->res = bin_add_pair(data->res, map, m.value, data); + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Apply a binary operation to "umap1" and "umap2" based on "control". + * Run over all maps in "umap1" and look for the corresponding map in "umap2" + * in gen_bin_entry. + */ +static __isl_give isl_union_map *gen_bin_op(__isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2, struct isl_bin_op_control *control) +{ + struct isl_union_map_gen_bin_data data = { control, NULL, NULL }; + + umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2)); + umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1)); + + if (!umap1 || !umap2) + goto error; + + data.umap2 = umap2; + data.res = isl_union_map_alloc(isl_space_copy(umap1->dim), + umap1->table.n); + if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table, + &gen_bin_entry, &data) < 0) + goto error; + + isl_union_map_free(umap1); + isl_union_map_free(umap2); + return data.res; +error: + isl_union_map_free(umap1); + isl_union_map_free(umap2); + isl_union_map_free(data.res); + return NULL; +} + +__isl_give isl_union_map *isl_union_map_subtract( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + struct isl_bin_op_control control = { + .subtract = 1, + .match_space = &identity, + .fn_map = &isl_map_subtract, + }; + + return gen_bin_op(umap1, umap2, &control); +} + +__isl_give isl_union_set *isl_union_set_subtract( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2) +{ + return isl_union_map_subtract(uset1, uset2); +} + +struct isl_union_map_gen_bin_set_data { + isl_set *set; + isl_union_map *res; +}; + +static isl_stat intersect_params_entry(void **entry, void *user) +{ + struct isl_union_map_gen_bin_set_data *data = user; + isl_map *map = *entry; + int empty; + + map = isl_map_copy(map); + map = isl_map_intersect_params(map, isl_set_copy(data->set)); + + empty = isl_map_is_empty(map); + if (empty < 0) { + isl_map_free(map); + return isl_stat_error; + } + + data->res = isl_union_map_add_map(data->res, map); + + return isl_stat_ok; +} + +static __isl_give isl_union_map *gen_bin_set_op(__isl_take isl_union_map *umap, + __isl_take isl_set *set, isl_stat (*fn)(void **, void *)) +{ + struct isl_union_map_gen_bin_set_data data = { NULL, NULL }; + + umap = isl_union_map_align_params(umap, isl_set_get_space(set)); + set = isl_set_align_params(set, isl_union_map_get_space(umap)); + + if (!umap || !set) + goto error; + + data.set = set; + data.res = isl_union_map_alloc(isl_space_copy(umap->dim), + umap->table.n); + if (isl_hash_table_foreach(umap->dim->ctx, &umap->table, + fn, &data) < 0) + goto error; + + isl_union_map_free(umap); + isl_set_free(set); + return data.res; +error: + isl_union_map_free(umap); + isl_set_free(set); + isl_union_map_free(data.res); + return NULL; +} + +/* Intersect "umap" with the parameter domain "set". + * + * If "set" does not have any constraints, then we can return immediately. + */ +__isl_give isl_union_map *isl_union_map_intersect_params( + __isl_take isl_union_map *umap, __isl_take isl_set *set) +{ + int is_universe; + + is_universe = isl_set_plain_is_universe(set); + if (is_universe < 0) + goto error; + if (is_universe) { + isl_set_free(set); + return umap; + } + + return gen_bin_set_op(umap, set, &intersect_params_entry); +error: + isl_union_map_free(umap); + isl_set_free(set); + return NULL; +} + +__isl_give isl_union_set *isl_union_set_intersect_params( + __isl_take isl_union_set *uset, __isl_take isl_set *set) +{ + return isl_union_map_intersect_params(uset, set); +} + +static __isl_give isl_union_map *union_map_intersect_params( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset) +{ + return isl_union_map_intersect_params(umap, + isl_set_from_union_set(uset)); +} + +static __isl_give isl_union_map *union_map_gist_params( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset) +{ + return isl_union_map_gist_params(umap, isl_set_from_union_set(uset)); +} + +struct isl_union_map_match_bin_data { + isl_union_map *umap2; + isl_union_map *res; + __isl_give isl_map *(*fn)(__isl_take isl_map*, __isl_take isl_map*); +}; + +static isl_stat match_bin_entry(void **entry, void *user) +{ + struct isl_union_map_match_bin_data *data = user; + uint32_t hash; + struct isl_hash_table_entry *entry2; + isl_map *map = *entry; + int empty; + + hash = isl_space_get_hash(map->dim); + entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table, + hash, &has_space, map->dim, 0); + if (!entry2) + return isl_stat_ok; + + map = isl_map_copy(map); + map = data->fn(map, isl_map_copy(entry2->data)); + + empty = isl_map_is_empty(map); + if (empty < 0) { + isl_map_free(map); + return isl_stat_error; + } + if (empty) { + isl_map_free(map); + return isl_stat_ok; + } + + data->res = isl_union_map_add_map(data->res, map); + + return isl_stat_ok; +} + +static __isl_give isl_union_map *match_bin_op(__isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2, + __isl_give isl_map *(*fn)(__isl_take isl_map*, __isl_take isl_map*)) +{ + struct isl_union_map_match_bin_data data = { NULL, NULL, fn }; + + umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2)); + umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1)); + + if (!umap1 || !umap2) + goto error; + + data.umap2 = umap2; + data.res = isl_union_map_alloc(isl_space_copy(umap1->dim), + umap1->table.n); + if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table, + &match_bin_entry, &data) < 0) + goto error; + + isl_union_map_free(umap1); + isl_union_map_free(umap2); + return data.res; +error: + isl_union_map_free(umap1); + isl_union_map_free(umap2); + isl_union_map_free(data.res); + return NULL; +} + +__isl_give isl_union_map *isl_union_map_intersect( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return match_bin_op(umap1, umap2, &isl_map_intersect); +} + +/* Compute the intersection of the two union_sets. + * As a special case, if exactly one of the two union_sets + * is a parameter domain, then intersect the parameter domain + * of the other one with this set. + */ +__isl_give isl_union_set *isl_union_set_intersect( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2) +{ + int p1, p2; + + p1 = isl_union_set_is_params(uset1); + p2 = isl_union_set_is_params(uset2); + if (p1 < 0 || p2 < 0) + goto error; + if (!p1 && p2) + return union_map_intersect_params(uset1, uset2); + if (p1 && !p2) + return union_map_intersect_params(uset2, uset1); + return isl_union_map_intersect(uset1, uset2); +error: + isl_union_set_free(uset1); + isl_union_set_free(uset2); + return NULL; +} + +static isl_stat gist_params_entry(void **entry, void *user) +{ + struct isl_union_map_gen_bin_set_data *data = user; + isl_map *map = *entry; + int empty; + + map = isl_map_copy(map); + map = isl_map_gist_params(map, isl_set_copy(data->set)); + + empty = isl_map_is_empty(map); + if (empty < 0) { + isl_map_free(map); + return isl_stat_error; + } + + data->res = isl_union_map_add_map(data->res, map); + + return isl_stat_ok; +} + +__isl_give isl_union_map *isl_union_map_gist_params( + __isl_take isl_union_map *umap, __isl_take isl_set *set) +{ + return gen_bin_set_op(umap, set, &gist_params_entry); +} + +__isl_give isl_union_set *isl_union_set_gist_params( + __isl_take isl_union_set *uset, __isl_take isl_set *set) +{ + return isl_union_map_gist_params(uset, set); +} + +__isl_give isl_union_map *isl_union_map_gist(__isl_take isl_union_map *umap, + __isl_take isl_union_map *context) +{ + return match_bin_op(umap, context, &isl_map_gist); +} + +__isl_give isl_union_set *isl_union_set_gist(__isl_take isl_union_set *uset, + __isl_take isl_union_set *context) +{ + if (isl_union_set_is_params(context)) + return union_map_gist_params(uset, context); + return isl_union_map_gist(uset, context); +} + +/* For each map in "umap", remove the constraints in the corresponding map + * of "context". + * Each map in "context" is assumed to consist of a single disjunct and + * to have explicit representations for all local variables. + */ +__isl_give isl_union_map *isl_union_map_plain_gist( + __isl_take isl_union_map *umap, __isl_take isl_union_map *context) +{ + return match_bin_op(umap, context, &isl_map_plain_gist); +} + +/* For each set in "uset", remove the constraints in the corresponding set + * of "context". + * Each set in "context" is assumed to consist of a single disjunct and + * to have explicit representations for all local variables. + */ +__isl_give isl_union_set *isl_union_set_plain_gist( + __isl_take isl_union_set *uset, __isl_take isl_union_set *context) +{ + return isl_union_map_plain_gist(uset, context); +} + +static __isl_give isl_map *lex_le_set(__isl_take isl_map *set1, + __isl_take isl_map *set2) +{ + return isl_set_lex_le_set(set_from_map(set1), set_from_map(set2)); +} + +static __isl_give isl_map *lex_lt_set(__isl_take isl_map *set1, + __isl_take isl_map *set2) +{ + return isl_set_lex_lt_set(set_from_map(set1), set_from_map(set2)); +} + +__isl_give isl_union_map *isl_union_set_lex_lt_union_set( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2) +{ + return match_bin_op(uset1, uset2, &lex_lt_set); +} + +__isl_give isl_union_map *isl_union_set_lex_le_union_set( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2) +{ + return match_bin_op(uset1, uset2, &lex_le_set); +} + +__isl_give isl_union_map *isl_union_set_lex_gt_union_set( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2) +{ + return isl_union_map_reverse(isl_union_set_lex_lt_union_set(uset2, uset1)); +} + +__isl_give isl_union_map *isl_union_set_lex_ge_union_set( + __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2) +{ + return isl_union_map_reverse(isl_union_set_lex_le_union_set(uset2, uset1)); +} + +__isl_give isl_union_map *isl_union_map_lex_gt_union_map( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return isl_union_map_reverse(isl_union_map_lex_lt_union_map(umap2, umap1)); +} + +__isl_give isl_union_map *isl_union_map_lex_ge_union_map( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return isl_union_map_reverse(isl_union_map_lex_le_union_map(umap2, umap1)); +} + +/* Intersect the domain of "umap" with "uset". + */ +static __isl_give isl_union_map *union_map_intersect_domain( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset) +{ + struct isl_bin_op_control control = { + .match_space = &isl_space_domain, + .fn_map = &isl_map_intersect_domain, + }; + + return gen_bin_op(umap, uset, &control); +} + +/* Intersect the domain of "umap" with "uset". + * If "uset" is a parameters domain, then intersect the parameter + * domain of "umap" with this set. + */ +__isl_give isl_union_map *isl_union_map_intersect_domain( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset) +{ + if (isl_union_set_is_params(uset)) + return union_map_intersect_params(umap, uset); + else + return union_map_intersect_domain(umap, uset); +} + +/* Remove the elements of "uset" from the domain of "umap". + */ +__isl_give isl_union_map *isl_union_map_subtract_domain( + __isl_take isl_union_map *umap, __isl_take isl_union_set *dom) +{ + struct isl_bin_op_control control = { + .subtract = 1, + .match_space = &isl_space_domain, + .fn_map = &isl_map_subtract_domain, + }; + + return gen_bin_op(umap, dom, &control); +} + +/* Remove the elements of "uset" from the range of "umap". + */ +__isl_give isl_union_map *isl_union_map_subtract_range( + __isl_take isl_union_map *umap, __isl_take isl_union_set *dom) +{ + struct isl_bin_op_control control = { + .subtract = 1, + .match_space = &isl_space_range, + .fn_map = &isl_map_subtract_range, + }; + + return gen_bin_op(umap, dom, &control); +} + +/* Compute the gist of "umap" with respect to the domain "uset". + */ +static __isl_give isl_union_map *union_map_gist_domain( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset) +{ + struct isl_bin_op_control control = { + .match_space = &isl_space_domain, + .fn_map = &isl_map_gist_domain, + }; + + return gen_bin_op(umap, uset, &control); +} + +/* Compute the gist of "umap" with respect to the domain "uset". + * If "uset" is a parameters domain, then compute the gist + * with respect to this parameter domain. + */ +__isl_give isl_union_map *isl_union_map_gist_domain( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset) +{ + if (isl_union_set_is_params(uset)) + return union_map_gist_params(umap, uset); + else + return union_map_gist_domain(umap, uset); +} + +/* Compute the gist of "umap" with respect to the range "uset". + */ +__isl_give isl_union_map *isl_union_map_gist_range( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset) +{ + struct isl_bin_op_control control = { + .match_space = &isl_space_range, + .fn_map = &isl_map_gist_range, + }; + + return gen_bin_op(umap, uset, &control); +} + +__isl_give isl_union_map *isl_union_map_intersect_range( + __isl_take isl_union_map *umap, __isl_take isl_union_set *uset) +{ + struct isl_bin_op_control control = { + .match_space = &isl_space_range, + .fn_map = &isl_map_intersect_range, + }; + + return gen_bin_op(umap, uset, &control); +} + +/* Intersect each map in "umap" in a space A -> [B -> C] + * with the corresponding map in "factor" in the space A -> C and + * collect the results. + */ +__isl_give isl_union_map *isl_union_map_intersect_range_factor_range( + __isl_take isl_union_map *umap, __isl_take isl_union_map *factor) +{ + struct isl_bin_op_control control = { + .filter = &isl_map_range_is_wrapping, + .match_space = &isl_space_range_factor_range, + .fn_map = &isl_map_intersect_range_factor_range, + }; + + return gen_bin_op(umap, factor, &control); +} + +struct isl_union_map_bin_data { + isl_union_map *umap2; + isl_union_map *res; + isl_map *map; + isl_stat (*fn)(void **entry, void *user); +}; + +static isl_stat apply_range_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + isl_bool empty; + + if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out, + map2->dim, isl_dim_in)) + return isl_stat_ok; + + map2 = isl_map_apply_range(isl_map_copy(data->map), isl_map_copy(map2)); + + empty = isl_map_is_empty(map2); + if (empty < 0) { + isl_map_free(map2); + return isl_stat_error; + } + if (empty) { + isl_map_free(map2); + return isl_stat_ok; + } + + data->res = isl_union_map_add_map(data->res, map2); + + return isl_stat_ok; +} + +static isl_stat bin_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map = *entry; + + data->map = map; + if (isl_hash_table_foreach(data->umap2->dim->ctx, &data->umap2->table, + data->fn, data) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +static __isl_give isl_union_map *bin_op(__isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2, + isl_stat (*fn)(void **entry, void *user)) +{ + struct isl_union_map_bin_data data = { NULL, NULL, NULL, fn }; + + umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2)); + umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1)); + + if (!umap1 || !umap2) + goto error; + + data.umap2 = umap2; + data.res = isl_union_map_alloc(isl_space_copy(umap1->dim), + umap1->table.n); + if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table, + &bin_entry, &data) < 0) + goto error; + + isl_union_map_free(umap1); + isl_union_map_free(umap2); + return data.res; +error: + isl_union_map_free(umap1); + isl_union_map_free(umap2); + isl_union_map_free(data.res); + return NULL; +} + +__isl_give isl_union_map *isl_union_map_apply_range( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &apply_range_entry); +} + +__isl_give isl_union_map *isl_union_map_apply_domain( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + umap1 = isl_union_map_reverse(umap1); + umap1 = isl_union_map_apply_range(umap1, umap2); + return isl_union_map_reverse(umap1); +} + +__isl_give isl_union_set *isl_union_set_apply( + __isl_take isl_union_set *uset, __isl_take isl_union_map *umap) +{ + return isl_union_map_apply_range(uset, umap); +} + +static isl_stat map_lex_lt_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + + if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out, + map2->dim, isl_dim_out)) + return isl_stat_ok; + + map2 = isl_map_lex_lt_map(isl_map_copy(data->map), isl_map_copy(map2)); + + data->res = isl_union_map_add_map(data->res, map2); + + return isl_stat_ok; +} + +__isl_give isl_union_map *isl_union_map_lex_lt_union_map( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &map_lex_lt_entry); +} + +static isl_stat map_lex_le_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + + if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out, + map2->dim, isl_dim_out)) + return isl_stat_ok; + + map2 = isl_map_lex_le_map(isl_map_copy(data->map), isl_map_copy(map2)); + + data->res = isl_union_map_add_map(data->res, map2); + + return isl_stat_ok; +} + +__isl_give isl_union_map *isl_union_map_lex_le_union_map( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &map_lex_le_entry); +} + +static isl_stat product_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + + map2 = isl_map_product(isl_map_copy(data->map), isl_map_copy(map2)); + + data->res = isl_union_map_add_map(data->res, map2); + + return isl_stat_ok; +} + +__isl_give isl_union_map *isl_union_map_product(__isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &product_entry); +} + +static isl_stat set_product_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_set *set2 = *entry; + + set2 = isl_set_product(isl_set_copy(data->map), isl_set_copy(set2)); + + data->res = isl_union_set_add_set(data->res, set2); + + return isl_stat_ok; +} + +__isl_give isl_union_set *isl_union_set_product(__isl_take isl_union_set *uset1, + __isl_take isl_union_set *uset2) +{ + return bin_op(uset1, uset2, &set_product_entry); +} + +static isl_stat domain_product_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + + if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out, + map2->dim, isl_dim_out)) + return isl_stat_ok; + + map2 = isl_map_domain_product(isl_map_copy(data->map), + isl_map_copy(map2)); + + data->res = isl_union_map_add_map(data->res, map2); + + return isl_stat_ok; +} + +/* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D) + */ +__isl_give isl_union_map *isl_union_map_domain_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &domain_product_entry); +} + +static isl_stat range_product_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + + if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_in, + map2->dim, isl_dim_in)) + return isl_stat_ok; + + map2 = isl_map_range_product(isl_map_copy(data->map), + isl_map_copy(map2)); + + data->res = isl_union_map_add_map(data->res, map2); + + return isl_stat_ok; +} + +__isl_give isl_union_map *isl_union_map_range_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &range_product_entry); +} + +/* If data->map A -> B and "map2" C -> D have the same range space, + * then add (A, C) -> (B * D) to data->res. + */ +static isl_stat flat_domain_product_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + + if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out, + map2->dim, isl_dim_out)) + return isl_stat_ok; + + map2 = isl_map_flat_domain_product(isl_map_copy(data->map), + isl_map_copy(map2)); + + data->res = isl_union_map_add_map(data->res, map2); + + return isl_stat_ok; +} + +/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D). + */ +__isl_give isl_union_map *isl_union_map_flat_domain_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &flat_domain_product_entry); +} + +static isl_stat flat_range_product_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + + if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_in, + map2->dim, isl_dim_in)) + return isl_stat_ok; + + map2 = isl_map_flat_range_product(isl_map_copy(data->map), + isl_map_copy(map2)); + + data->res = isl_union_map_add_map(data->res, map2); + + return isl_stat_ok; +} + +__isl_give isl_union_map *isl_union_map_flat_range_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &flat_range_product_entry); +} + +/* Data structure that specifies how un_op should modify + * the maps in the union map. + * + * If "inplace" is set, then the maps in the input union map + * are modified in place. This means that "fn_map" should not + * change the meaning of the map or that the union map only + * has a single reference. + * If "total" is set, then all maps need to be modified and + * the results need to live in the same space. + * Otherwise, a new union map is constructed to store the results. + * If "filter" is not NULL, then only the input maps that satisfy "filter" + * are taken into account. "filter_user" is passed as the second argument + * to "filter". No filter can be set if "inplace" or + * "total" is set. + * "fn_map" specifies how the maps (selected by "filter") + * should be transformed. + */ +struct isl_un_op_control { + int inplace; + int total; + isl_bool (*filter)(__isl_keep isl_map *map, void *user); + void *filter_user; + __isl_give isl_map *(*fn_map)(__isl_take isl_map *map); +}; + +/* Data structure for wrapping the data for un_op_filter_drop_user. + * "filter" is the function that is being wrapped. + */ +struct isl_un_op_drop_user_data { + isl_bool (*filter)(__isl_keep isl_map *map); +}; + +/* Wrapper for isl_un_op_control filters that do not require + * a second argument. + * Simply call data->filter without the second argument. + */ +static isl_bool un_op_filter_drop_user(__isl_keep isl_map *map, void *user) +{ + struct isl_un_op_drop_user_data *data = user; + return data->filter(map); +} + +/* Internal data structure for "un_op". + * "control" specifies how the maps in the union map should be modified. + * "res" collects the results. + */ +struct isl_union_map_un_data { + struct isl_un_op_control *control; + isl_union_map *res; +}; + +/* isl_hash_table_foreach callback for un_op. + * Handle the map that "entry" points to. + * + * If control->filter is set, then check if this map satisfies the filter. + * If so (or if control->filter is not set), modify the map + * by calling control->fn_map and either add the result to data->res or + * replace the original entry by the result (if control->inplace is set). + */ +static isl_stat un_entry(void **entry, void *user) +{ + struct isl_union_map_un_data *data = user; + isl_map *map = *entry; + + if (data->control->filter) { + isl_bool ok; + + ok = data->control->filter(map, data->control->filter_user); + if (ok < 0) + return isl_stat_error; + if (!ok) + return isl_stat_ok; + } + + map = data->control->fn_map(isl_map_copy(map)); + if (!map) + return isl_stat_error; + if (data->control->inplace) { + isl_map_free(*entry); + *entry = map; + } else { + data->res = isl_union_map_add_map(data->res, map); + if (!data->res) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Modify the maps in "umap" based on "control". + * If control->inplace is set, then modify the maps in "umap" in-place. + * Otherwise, create a new union map to hold the results. + * If control->total is set, then perform an inplace computation + * if "umap" is only referenced once. Otherwise, create a new union map + * to store the results. + */ +static __isl_give isl_union_map *un_op(__isl_take isl_union_map *umap, + struct isl_un_op_control *control) +{ + struct isl_union_map_un_data data = { control }; + + if (!umap) + return NULL; + if ((control->inplace || control->total) && control->filter) + isl_die(isl_union_map_get_ctx(umap), isl_error_invalid, + "inplace/total modification cannot be filtered", + return isl_union_map_free(umap)); + + if (control->total && umap->ref == 1) + control->inplace = 1; + if (control->inplace) { + data.res = umap; + } else { + isl_space *space; + + space = isl_union_map_get_space(umap); + data.res = isl_union_map_alloc(space, umap->table.n); + } + if (isl_hash_table_foreach(isl_union_map_get_ctx(umap), + &umap->table, &un_entry, &data) < 0) + data.res = isl_union_map_free(data.res); + + if (control->inplace) + return data.res; + isl_union_map_free(umap); + return data.res; +} + +__isl_give isl_union_map *isl_union_map_from_range( + __isl_take isl_union_set *uset) +{ + struct isl_un_op_control control = { + .fn_map = &isl_map_from_range, + }; + return un_op(uset, &control); +} + +__isl_give isl_union_map *isl_union_map_from_domain( + __isl_take isl_union_set *uset) +{ + return isl_union_map_reverse(isl_union_map_from_range(uset)); +} + +__isl_give isl_union_map *isl_union_map_from_domain_and_range( + __isl_take isl_union_set *domain, __isl_take isl_union_set *range) +{ + return isl_union_map_apply_range(isl_union_map_from_domain(domain), + isl_union_map_from_range(range)); +} + +/* Modify the maps in "umap" by applying "fn" on them. + * "fn" should apply to all maps in "umap" and should not modify the space. + */ +static __isl_give isl_union_map *total(__isl_take isl_union_map *umap, + __isl_give isl_map *(*fn)(__isl_take isl_map *)) +{ + struct isl_un_op_control control = { + .total = 1, + .fn_map = fn, + }; + + return un_op(umap, &control); +} + +/* Compute the affine hull of "map" and return the result as an isl_map. + */ +static __isl_give isl_map *isl_map_affine_hull_map(__isl_take isl_map *map) +{ + return isl_map_from_basic_map(isl_map_affine_hull(map)); +} + +__isl_give isl_union_map *isl_union_map_affine_hull( + __isl_take isl_union_map *umap) +{ + return total(umap, &isl_map_affine_hull_map); +} + +__isl_give isl_union_set *isl_union_set_affine_hull( + __isl_take isl_union_set *uset) +{ + return isl_union_map_affine_hull(uset); +} + +/* Wrapper around isl_set_combined_lineality_space + * that returns the combined lineality space in the form of an isl_set + * instead of an isl_basic_set. + */ +static __isl_give isl_set *combined_lineality_space(__isl_take isl_set *set) +{ + return isl_set_from_basic_set(isl_set_combined_lineality_space(set)); +} + +/* For each set in "uset", compute the (linear) hull + * of the lineality spaces of its basic sets and + * collect and return the results. + */ +__isl_give isl_union_set *isl_union_set_combined_lineality_space( + __isl_take isl_union_set *uset) +{ + struct isl_un_op_control control = { + .fn_map = &combined_lineality_space, + }; + return un_op(uset, &control); +} + +/* Compute the polyhedral hull of "map" and return the result as an isl_map. + */ +static __isl_give isl_map *isl_map_polyhedral_hull_map(__isl_take isl_map *map) +{ + return isl_map_from_basic_map(isl_map_polyhedral_hull(map)); +} + +__isl_give isl_union_map *isl_union_map_polyhedral_hull( + __isl_take isl_union_map *umap) +{ + return total(umap, &isl_map_polyhedral_hull_map); +} + +__isl_give isl_union_set *isl_union_set_polyhedral_hull( + __isl_take isl_union_set *uset) +{ + return isl_union_map_polyhedral_hull(uset); +} + +/* Compute a superset of the convex hull of "map" that is described + * by only translates of the constraints in the constituents of "map" and + * return the result as an isl_map. + */ +static __isl_give isl_map *isl_map_simple_hull_map(__isl_take isl_map *map) +{ + return isl_map_from_basic_map(isl_map_simple_hull(map)); +} + +__isl_give isl_union_map *isl_union_map_simple_hull( + __isl_take isl_union_map *umap) +{ + return total(umap, &isl_map_simple_hull_map); +} + +__isl_give isl_union_set *isl_union_set_simple_hull( + __isl_take isl_union_set *uset) +{ + return isl_union_map_simple_hull(uset); +} + +static __isl_give isl_union_map *inplace(__isl_take isl_union_map *umap, + __isl_give isl_map *(*fn)(__isl_take isl_map *)) +{ + struct isl_un_op_control control = { + .inplace = 1, + .fn_map = fn, + }; + + return un_op(umap, &control); +} + +/* Remove redundant constraints in each of the basic maps of "umap". + * Since removing redundant constraints does not change the meaning + * or the space, the operation can be performed in-place. + */ +__isl_give isl_union_map *isl_union_map_remove_redundancies( + __isl_take isl_union_map *umap) +{ + return inplace(umap, &isl_map_remove_redundancies); +} + +/* Remove redundant constraints in each of the basic sets of "uset". + */ +__isl_give isl_union_set *isl_union_set_remove_redundancies( + __isl_take isl_union_set *uset) +{ + return isl_union_map_remove_redundancies(uset); +} + +__isl_give isl_union_map *isl_union_map_coalesce( + __isl_take isl_union_map *umap) +{ + return inplace(umap, &isl_map_coalesce); +} + +__isl_give isl_union_set *isl_union_set_coalesce( + __isl_take isl_union_set *uset) +{ + return isl_union_map_coalesce(uset); +} + +__isl_give isl_union_map *isl_union_map_detect_equalities( + __isl_take isl_union_map *umap) +{ + return inplace(umap, &isl_map_detect_equalities); +} + +__isl_give isl_union_set *isl_union_set_detect_equalities( + __isl_take isl_union_set *uset) +{ + return isl_union_map_detect_equalities(uset); +} + +__isl_give isl_union_map *isl_union_map_compute_divs( + __isl_take isl_union_map *umap) +{ + return inplace(umap, &isl_map_compute_divs); +} + +__isl_give isl_union_set *isl_union_set_compute_divs( + __isl_take isl_union_set *uset) +{ + return isl_union_map_compute_divs(uset); +} + +__isl_give isl_union_map *isl_union_map_lexmin( + __isl_take isl_union_map *umap) +{ + return total(umap, &isl_map_lexmin); +} + +__isl_give isl_union_set *isl_union_set_lexmin( + __isl_take isl_union_set *uset) +{ + return isl_union_map_lexmin(uset); +} + +__isl_give isl_union_map *isl_union_map_lexmax( + __isl_take isl_union_map *umap) +{ + return total(umap, &isl_map_lexmax); +} + +__isl_give isl_union_set *isl_union_set_lexmax( + __isl_take isl_union_set *uset) +{ + return isl_union_map_lexmax(uset); +} + +/* Return the universe in the space of "map". + */ +static __isl_give isl_map *universe(__isl_take isl_map *map) +{ + isl_space *space; + + space = isl_map_get_space(map); + isl_map_free(map); + return isl_map_universe(space); +} + +__isl_give isl_union_map *isl_union_map_universe(__isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .fn_map = &universe, + }; + return un_op(umap, &control); +} + +__isl_give isl_union_set *isl_union_set_universe(__isl_take isl_union_set *uset) +{ + return isl_union_map_universe(uset); +} + +__isl_give isl_union_map *isl_union_map_reverse(__isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .fn_map = &isl_map_reverse, + }; + return un_op(umap, &control); +} + +/* Compute the parameter domain of the given union map. + */ +__isl_give isl_set *isl_union_map_params(__isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .fn_map = &isl_map_params, + }; + int empty; + + empty = isl_union_map_is_empty(umap); + if (empty < 0) + goto error; + if (empty) { + isl_space *space; + space = isl_union_map_get_space(umap); + isl_union_map_free(umap); + return isl_set_empty(space); + } + return isl_set_from_union_set(un_op(umap, &control)); +error: + isl_union_map_free(umap); + return NULL; +} + +/* Compute the parameter domain of the given union set. + */ +__isl_give isl_set *isl_union_set_params(__isl_take isl_union_set *uset) +{ + return isl_union_map_params(uset); +} + +__isl_give isl_union_set *isl_union_map_domain(__isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .fn_map = &isl_map_domain, + }; + return un_op(umap, &control); +} + +__isl_give isl_union_set *isl_union_map_range(__isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .fn_map = &isl_map_range, + }; + return un_op(umap, &control); +} + +__isl_give isl_union_map *isl_union_map_domain_map( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .fn_map = &isl_map_domain_map, + }; + return un_op(umap, &control); +} + +/* Construct an isl_pw_multi_aff that maps "map" to its domain and + * add the result to "res". + */ +static isl_stat domain_map_upma(__isl_take isl_map *map, void *user) +{ + isl_union_pw_multi_aff **res = user; + isl_multi_aff *ma; + isl_pw_multi_aff *pma; + + ma = isl_multi_aff_domain_map(isl_map_get_space(map)); + pma = isl_pw_multi_aff_alloc(isl_map_wrap(map), ma); + *res = isl_union_pw_multi_aff_add_pw_multi_aff(*res, pma); + + return *res ? isl_stat_ok : isl_stat_error; + +} + +/* Return an isl_union_pw_multi_aff that maps a wrapped copy of "umap" + * to its domain. + */ +__isl_give isl_union_pw_multi_aff *isl_union_map_domain_map_union_pw_multi_aff( + __isl_take isl_union_map *umap) +{ + isl_union_pw_multi_aff *res; + + res = isl_union_pw_multi_aff_empty(isl_union_map_get_space(umap)); + if (isl_union_map_foreach_map(umap, &domain_map_upma, &res) < 0) + res = isl_union_pw_multi_aff_free(res); + + isl_union_map_free(umap); + return res; +} + +__isl_give isl_union_map *isl_union_map_range_map( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .fn_map = &isl_map_range_map, + }; + return un_op(umap, &control); +} + +/* Given a collection of wrapped maps of the form A[B -> C], + * return the collection of maps A[B -> C] -> B. + */ +__isl_give isl_union_map *isl_union_set_wrapped_domain_map( + __isl_take isl_union_set *uset) +{ + struct isl_un_op_drop_user_data data = { &isl_set_is_wrapping }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_set_wrapped_domain_map, + }; + return un_op(uset, &control); +} + +/* Does "map" relate elements from the same space? + */ +static isl_bool equal_tuples(__isl_keep isl_map *map, void *user) +{ + return isl_space_tuple_is_equal(map->dim, isl_dim_in, + map->dim, isl_dim_out); +} + +__isl_give isl_union_set *isl_union_map_deltas(__isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .filter = &equal_tuples, + .fn_map = &isl_map_deltas, + }; + return un_op(umap, &control); +} + +__isl_give isl_union_map *isl_union_map_deltas_map( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .filter = &equal_tuples, + .fn_map = &isl_map_deltas_map, + }; + return un_op(umap, &control); +} + +__isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset) +{ + struct isl_un_op_control control = { + .fn_map = &isl_set_identity, + }; + return un_op(uset, &control); +} + +/* Construct an identity isl_pw_multi_aff on "set" and add it to *res. + */ +static isl_stat identity_upma(__isl_take isl_set *set, void *user) +{ + isl_union_pw_multi_aff **res = user; + isl_space *space; + isl_pw_multi_aff *pma; + + space = isl_space_map_from_set(isl_set_get_space(set)); + pma = isl_pw_multi_aff_identity(space); + pma = isl_pw_multi_aff_intersect_domain(pma, set); + *res = isl_union_pw_multi_aff_add_pw_multi_aff(*res, pma); + + return *res ? isl_stat_ok : isl_stat_error; +} + +/* Return an identity function on "uset" in the form + * of an isl_union_pw_multi_aff. + */ +__isl_give isl_union_pw_multi_aff *isl_union_set_identity_union_pw_multi_aff( + __isl_take isl_union_set *uset) +{ + isl_union_pw_multi_aff *res; + + res = isl_union_pw_multi_aff_empty(isl_union_set_get_space(uset)); + if (isl_union_set_foreach_set(uset, &identity_upma, &res) < 0) + res = isl_union_pw_multi_aff_free(res); + + isl_union_set_free(uset); + return res; +} + +/* For each map in "umap" of the form [A -> B] -> C, + * construct the map A -> C and collect the results. + */ +__isl_give isl_union_map *isl_union_map_domain_factor_domain( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_domain_is_wrapping }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_domain_factor_domain, + }; + return un_op(umap, &control); +} + +/* For each map in "umap" of the form [A -> B] -> C, + * construct the map B -> C and collect the results. + */ +__isl_give isl_union_map *isl_union_map_domain_factor_range( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_domain_is_wrapping }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_domain_factor_range, + }; + return un_op(umap, &control); +} + +/* For each map in "umap" of the form A -> [B -> C], + * construct the map A -> B and collect the results. + */ +__isl_give isl_union_map *isl_union_map_range_factor_domain( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_range_is_wrapping }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_range_factor_domain, + }; + return un_op(umap, &control); +} + +/* For each map in "umap" of the form A -> [B -> C], + * construct the map A -> C and collect the results. + */ +__isl_give isl_union_map *isl_union_map_range_factor_range( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_range_is_wrapping }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_range_factor_range, + }; + return un_op(umap, &control); +} + +/* For each map in "umap" of the form [A -> B] -> [C -> D], + * construct the map A -> C and collect the results. + */ +__isl_give isl_union_map *isl_union_map_factor_domain( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_is_product }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_factor_domain, + }; + return un_op(umap, &control); +} + +/* For each map in "umap" of the form [A -> B] -> [C -> D], + * construct the map B -> D and collect the results. + */ +__isl_give isl_union_map *isl_union_map_factor_range( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_is_product }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_factor_range, + }; + return un_op(umap, &control); +} + +__isl_give isl_union_map *isl_union_set_unwrap(__isl_take isl_union_set *uset) +{ + struct isl_un_op_drop_user_data data = { &isl_set_is_wrapping }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_set_unwrap, + }; + return un_op(uset, &control); +} + +__isl_give isl_union_set *isl_union_map_wrap(__isl_take isl_union_map *umap) +{ + struct isl_un_op_control control = { + .fn_map = &isl_map_wrap, + }; + return un_op(umap, &control); +} + +struct isl_union_map_is_subset_data { + isl_union_map *umap2; + isl_bool is_subset; +}; + +static isl_stat is_subset_entry(void **entry, void *user) +{ + struct isl_union_map_is_subset_data *data = user; + uint32_t hash; + struct isl_hash_table_entry *entry2; + isl_map *map = *entry; + + hash = isl_space_get_hash(map->dim); + entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table, + hash, &has_space, map->dim, 0); + if (!entry2) { + int empty = isl_map_is_empty(map); + if (empty < 0) + return isl_stat_error; + if (empty) + return isl_stat_ok; + data->is_subset = 0; + return isl_stat_error; + } + + data->is_subset = isl_map_is_subset(map, entry2->data); + if (data->is_subset < 0 || !data->is_subset) + return isl_stat_error; + + return isl_stat_ok; +} + +isl_bool isl_union_map_is_subset(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2) +{ + struct isl_union_map_is_subset_data data = { NULL, isl_bool_true }; + + umap1 = isl_union_map_copy(umap1); + umap2 = isl_union_map_copy(umap2); + umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2)); + umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1)); + + if (!umap1 || !umap2) + goto error; + + data.umap2 = umap2; + if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table, + &is_subset_entry, &data) < 0 && + data.is_subset) + goto error; + + isl_union_map_free(umap1); + isl_union_map_free(umap2); + + return data.is_subset; +error: + isl_union_map_free(umap1); + isl_union_map_free(umap2); + return isl_bool_error; +} + +isl_bool isl_union_set_is_subset(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2) +{ + return isl_union_map_is_subset(uset1, uset2); +} + +isl_bool isl_union_map_is_equal(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2) +{ + isl_bool is_subset; + + if (!umap1 || !umap2) + return isl_bool_error; + is_subset = isl_union_map_is_subset(umap1, umap2); + if (is_subset != isl_bool_true) + return is_subset; + is_subset = isl_union_map_is_subset(umap2, umap1); + return is_subset; +} + +isl_bool isl_union_set_is_equal(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2) +{ + return isl_union_map_is_equal(uset1, uset2); +} + +isl_bool isl_union_map_is_strict_subset(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2) +{ + isl_bool is_subset; + + if (!umap1 || !umap2) + return isl_bool_error; + is_subset = isl_union_map_is_subset(umap1, umap2); + if (is_subset != isl_bool_true) + return is_subset; + is_subset = isl_union_map_is_subset(umap2, umap1); + if (is_subset == isl_bool_error) + return is_subset; + return !is_subset; +} + +isl_bool isl_union_set_is_strict_subset(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2) +{ + return isl_union_map_is_strict_subset(uset1, uset2); +} + +/* Internal data structure for isl_union_map_is_disjoint. + * umap2 is the union map with which we are comparing. + * is_disjoint is initialized to 1 and is set to 0 as soon + * as the union maps turn out not to be disjoint. + */ +struct isl_union_map_is_disjoint_data { + isl_union_map *umap2; + isl_bool is_disjoint; +}; + +/* Check if "map" is disjoint from data->umap2 and abort + * the search if it is not. + */ +static isl_stat is_disjoint_entry(void **entry, void *user) +{ + struct isl_union_map_is_disjoint_data *data = user; + uint32_t hash; + struct isl_hash_table_entry *entry2; + isl_map *map = *entry; + + hash = isl_space_get_hash(map->dim); + entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table, + hash, &has_space, map->dim, 0); + if (!entry2) + return isl_stat_ok; + + data->is_disjoint = isl_map_is_disjoint(map, entry2->data); + if (data->is_disjoint < 0 || !data->is_disjoint) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Are "umap1" and "umap2" disjoint? + */ +isl_bool isl_union_map_is_disjoint(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2) +{ + struct isl_union_map_is_disjoint_data data = { NULL, isl_bool_true }; + + umap1 = isl_union_map_copy(umap1); + umap2 = isl_union_map_copy(umap2); + umap1 = isl_union_map_align_params(umap1, + isl_union_map_get_space(umap2)); + umap2 = isl_union_map_align_params(umap2, + isl_union_map_get_space(umap1)); + + if (!umap1 || !umap2) + goto error; + + data.umap2 = umap2; + if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table, + &is_disjoint_entry, &data) < 0 && + data.is_disjoint) + goto error; + + isl_union_map_free(umap1); + isl_union_map_free(umap2); + + return data.is_disjoint; +error: + isl_union_map_free(umap1); + isl_union_map_free(umap2); + return isl_bool_error; +} + +/* Are "uset1" and "uset2" disjoint? + */ +isl_bool isl_union_set_is_disjoint(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2) +{ + return isl_union_map_is_disjoint(uset1, uset2); +} + +static isl_stat sample_entry(void **entry, void *user) +{ + isl_basic_map **sample = (isl_basic_map **)user; + isl_map *map = *entry; + + *sample = isl_map_sample(isl_map_copy(map)); + if (!*sample) + return isl_stat_error; + if (!isl_basic_map_plain_is_empty(*sample)) + return isl_stat_error; + return isl_stat_ok; +} + +__isl_give isl_basic_map *isl_union_map_sample(__isl_take isl_union_map *umap) +{ + isl_basic_map *sample = NULL; + + if (!umap) + return NULL; + + if (isl_hash_table_foreach(umap->dim->ctx, &umap->table, + &sample_entry, &sample) < 0 && + !sample) + goto error; + + if (!sample) + sample = isl_basic_map_empty(isl_union_map_get_space(umap)); + + isl_union_map_free(umap); + + return sample; +error: + isl_union_map_free(umap); + return NULL; +} + +__isl_give isl_basic_set *isl_union_set_sample(__isl_take isl_union_set *uset) +{ + return bset_from_bmap(isl_union_map_sample(uset)); +} + +/* Return an element in "uset" in the form of an isl_point. + * Return a void isl_point if "uset" is empty. + */ +__isl_give isl_point *isl_union_set_sample_point(__isl_take isl_union_set *uset) +{ + return isl_basic_set_sample_point(isl_union_set_sample(uset)); +} + +struct isl_forall_data { + isl_bool res; + isl_bool (*fn)(__isl_keep isl_map *map); +}; + +static isl_stat forall_entry(void **entry, void *user) +{ + struct isl_forall_data *data = user; + isl_map *map = *entry; + + data->res = data->fn(map); + if (data->res < 0) + return isl_stat_error; + + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +} + +static isl_bool union_map_forall(__isl_keep isl_union_map *umap, + isl_bool (*fn)(__isl_keep isl_map *map)) +{ + struct isl_forall_data data = { isl_bool_true, fn }; + + if (!umap) + return isl_bool_error; + + if (isl_hash_table_foreach(umap->dim->ctx, &umap->table, + &forall_entry, &data) < 0 && data.res) + return isl_bool_error; + + return data.res; +} + +struct isl_forall_user_data { + isl_bool res; + isl_bool (*fn)(__isl_keep isl_map *map, void *user); + void *user; +}; + +static isl_stat 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 isl_stat_error; + + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Check if fn(map, user) returns true for all maps "map" in umap. + */ +static isl_bool union_map_forall_user(__isl_keep isl_union_map *umap, + isl_bool (*fn)(__isl_keep isl_map *map, void *user), void *user) +{ + struct isl_forall_user_data data = { isl_bool_true, fn, user }; + + if (!umap) + return isl_bool_error; + + if (isl_hash_table_foreach(umap->dim->ctx, &umap->table, + &forall_user_entry, &data) < 0 && data.res) + return isl_bool_error; + + return data.res; +} + +/* Is "umap" obviously empty? + */ +isl_bool isl_union_map_plain_is_empty(__isl_keep isl_union_map *umap) +{ + if (!umap) + return isl_bool_error; + return isl_union_map_n_map(umap) == 0; +} + +isl_bool isl_union_map_is_empty(__isl_keep isl_union_map *umap) +{ + return union_map_forall(umap, &isl_map_is_empty); +} + +isl_bool isl_union_set_is_empty(__isl_keep isl_union_set *uset) +{ + return isl_union_map_is_empty(uset); +} + +static isl_bool is_subset_of_identity(__isl_keep isl_map *map) +{ + isl_bool is_subset; + isl_space *dim; + isl_map *id; + + if (!map) + return isl_bool_error; + + if (!isl_space_tuple_is_equal(map->dim, isl_dim_in, + map->dim, isl_dim_out)) + return isl_bool_false; + + dim = isl_map_get_space(map); + id = isl_map_identity(dim); + + is_subset = isl_map_is_subset(map, id); + + isl_map_free(id); + + return is_subset; +} + +/* Given an isl_union_map that consists of a single map, check + * if it is single-valued. + */ +static isl_bool single_map_is_single_valued(__isl_keep isl_union_map *umap) +{ + isl_map *map; + isl_bool sv; + + umap = isl_union_map_copy(umap); + map = isl_map_from_union_map(umap); + sv = isl_map_is_single_valued(map); + isl_map_free(map); + + return sv; +} + +/* Internal data structure for single_valued_on_domain. + * + * "umap" is the union map to be tested. + * "sv" is set to 1 as long as "umap" may still be single-valued. + */ +struct isl_union_map_is_sv_data { + isl_union_map *umap; + isl_bool sv; +}; + +/* Check if the data->umap is single-valued on "set". + * + * If data->umap consists of a single map on "set", then test it + * as an isl_map. + * + * Otherwise, compute + * + * M \circ M^-1 + * + * check if the result is a subset of the identity mapping and + * store the result in data->sv. + * + * Terminate as soon as data->umap has been determined not to + * be single-valued. + */ +static isl_stat single_valued_on_domain(__isl_take isl_set *set, void *user) +{ + struct isl_union_map_is_sv_data *data = user; + isl_union_map *umap, *test; + + umap = isl_union_map_copy(data->umap); + umap = isl_union_map_intersect_domain(umap, + isl_union_set_from_set(set)); + + if (isl_union_map_n_map(umap) == 1) { + data->sv = single_map_is_single_valued(umap); + isl_union_map_free(umap); + } else { + test = isl_union_map_reverse(isl_union_map_copy(umap)); + test = isl_union_map_apply_range(test, umap); + + data->sv = union_map_forall(test, &is_subset_of_identity); + + isl_union_map_free(test); + } + + if (data->sv < 0 || !data->sv) + return isl_stat_error; + return isl_stat_ok; +} + +/* Check if the given map is single-valued. + * + * If the union map consists of a single map, then test it as an isl_map. + * Otherwise, check if the union map is single-valued on each of its + * domain spaces. + */ +isl_bool isl_union_map_is_single_valued(__isl_keep isl_union_map *umap) +{ + isl_union_map *universe; + isl_union_set *domain; + struct isl_union_map_is_sv_data data; + + if (isl_union_map_n_map(umap) == 1) + return single_map_is_single_valued(umap); + + universe = isl_union_map_universe(isl_union_map_copy(umap)); + domain = isl_union_map_domain(universe); + + data.sv = isl_bool_true; + data.umap = umap; + if (isl_union_set_foreach_set(domain, + &single_valued_on_domain, &data) < 0 && data.sv) + data.sv = isl_bool_error; + isl_union_set_free(domain); + + return data.sv; +} + +isl_bool isl_union_map_is_injective(__isl_keep isl_union_map *umap) +{ + isl_bool 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; +} + +/* Is "map" obviously not an identity relation because + * it maps elements from one space to another space? + * Update *non_identity accordingly. + * + * In particular, if the domain and range spaces are the same, + * then the map is not considered to obviously not be an identity relation. + * Otherwise, the map is considered to obviously not be an identity relation + * if it is is non-empty. + * + * If "map" is determined to obviously not be an identity relation, + * then the search is aborted. + */ +static isl_stat map_plain_is_not_identity(__isl_take isl_map *map, void *user) +{ + isl_bool *non_identity = user; + isl_bool equal; + isl_space *space; + + space = isl_map_get_space(map); + equal = isl_space_tuple_is_equal(space, isl_dim_in, space, isl_dim_out); + if (equal >= 0 && !equal) + *non_identity = isl_bool_not(isl_map_is_empty(map)); + else + *non_identity = isl_bool_not(equal); + isl_space_free(space); + isl_map_free(map); + + if (*non_identity < 0 || *non_identity) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Is "umap" obviously not an identity relation because + * it maps elements from one space to another space? + * + * As soon as a map has been found that maps elements to a different space, + * non_identity is changed and the search is aborted. + */ +static isl_bool isl_union_map_plain_is_not_identity( + __isl_keep isl_union_map *umap) +{ + isl_bool non_identity; + + non_identity = isl_bool_false; + if (isl_union_map_foreach_map(umap, &map_plain_is_not_identity, + &non_identity) < 0 && + non_identity == isl_bool_false) + return isl_bool_error; + + return non_identity; +} + +/* Does "map" only map elements to themselves? + * Update *identity accordingly. + * + * If "map" is determined not to be an identity relation, + * then the search is aborted. + */ +static isl_stat map_is_identity(__isl_take isl_map *map, void *user) +{ + isl_bool *identity = user; + + *identity = isl_map_is_identity(map); + isl_map_free(map); + + if (*identity < 0 || !*identity) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Does "umap" only map elements to themselves? + * + * First check if there are any maps that map elements to different spaces. + * If not, then check that all the maps (between identical spaces) + * are identity relations. + */ +isl_bool isl_union_map_is_identity(__isl_keep isl_union_map *umap) +{ + isl_bool non_identity; + isl_bool identity; + + non_identity = isl_union_map_plain_is_not_identity(umap); + if (non_identity < 0 || non_identity) + return isl_bool_not(non_identity); + + identity = isl_bool_true; + if (isl_union_map_foreach_map(umap, &map_is_identity, &identity) < 0 && + identity == isl_bool_true) + return isl_bool_error; + + return identity; +} + +/* 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 isl_bool 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 isl_bool 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_space *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_space_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_space_free(dim); + free_isl_fixed_map_array(v, n); + return i + 1 >= n; +error: + isl_space_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 isl_bool 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); + + n = isl_union_map_n_map(umap); + if (!umap) + goto error; + + if (n <= 1) { + isl_union_map_free(umap); + return isl_bool_true; + } + + if (first >= n_range) { + isl_union_map_free(umap); + return isl_bool_false; + } + + data.v = alloc_isl_fixed_map_array(ctx, n); + if (!data.v) + goto error; + + for (data.pos = first; data.pos < n_range; ++data.pos) { + isl_bool fixed; + int injective; + isl_space *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_space(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 isl_bool_false; +error: + free_isl_fixed_map_array(data.v, n); + isl_union_map_free(umap); + return isl_bool_error; +} + +/* Check whether the maps in umap that map to subsets of "ran" + * have obviously distinct ranges. + */ +static isl_bool 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. + */ +isl_bool isl_union_map_plain_is_injective(__isl_keep isl_union_map *umap) +{ + isl_bool in; + isl_union_map *univ; + isl_union_set *ran; + + in = union_map_forall(umap, &isl_map_plain_is_injective); + if (in < 0) + return isl_bool_error; + if (!in) + return isl_bool_false; + + 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; +} + +isl_bool isl_union_map_is_bijective(__isl_keep isl_union_map *umap) +{ + isl_bool sv; + + sv = isl_union_map_is_single_valued(umap); + if (sv < 0 || !sv) + return sv; + + return isl_union_map_is_injective(umap); +} + +__isl_give isl_union_map *isl_union_map_zip(__isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_can_zip }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_zip, + }; + return un_op(umap, &control); +} + +/* Given a union map, take the maps of the form A -> (B -> C) and + * return the union of the corresponding maps (A -> B) -> C. + */ +__isl_give isl_union_map *isl_union_map_uncurry(__isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_can_uncurry }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_uncurry, + }; + return un_op(umap, &control); +} + +/* Given a union map, take the maps of the form (A -> B) -> C and + * return the union of the corresponding maps A -> (B -> C). + */ +__isl_give isl_union_map *isl_union_map_curry(__isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_can_curry }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_curry, + }; + return un_op(umap, &control); +} + +/* Given a union map, take the maps of the form A -> ((B -> C) -> D) and + * return the union of the corresponding maps A -> (B -> (C -> D)). + */ +__isl_give isl_union_map *isl_union_map_range_curry( + __isl_take isl_union_map *umap) +{ + struct isl_un_op_drop_user_data data = { &isl_map_can_range_curry }; + struct isl_un_op_control control = { + .filter = &un_op_filter_drop_user, + .filter_user = &data, + .fn_map = &isl_map_range_curry, + }; + return un_op(umap, &control); +} + +__isl_give isl_union_set *isl_union_set_lift(__isl_take isl_union_set *uset) +{ + struct isl_un_op_control control = { + .fn_map = &isl_set_lift, + }; + return un_op(uset, &control); +} + +static isl_stat 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 isl_stat_ok; +} + +__isl_give isl_union_set *isl_union_set_coefficients( + __isl_take isl_union_set *uset) +{ + isl_ctx *ctx; + isl_space *dim; + isl_union_set *res; + + if (!uset) + return NULL; + + ctx = isl_union_set_get_ctx(uset); + dim = isl_space_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 isl_stat 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 isl_stat_error; + + return isl_stat_ok; +} + +__isl_give isl_union_set *isl_union_set_solutions( + __isl_take isl_union_set *uset) +{ + isl_union_set *res = NULL; + + if (!uset) + return NULL; + + if (uset->table.n == 0) { + res = isl_union_set_empty(isl_union_set_get_space(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; +} + +/* Is the domain space of "map" equal to "space"? + */ +static int domain_match(__isl_keep isl_map *map, __isl_keep isl_space *space) +{ + return isl_space_tuple_is_equal(map->dim, isl_dim_in, + space, isl_dim_out); +} + +/* Is the range space of "map" equal to "space"? + */ +static int range_match(__isl_keep isl_map *map, __isl_keep isl_space *space) +{ + return isl_space_tuple_is_equal(map->dim, isl_dim_out, + space, isl_dim_out); +} + +/* Is the set space of "map" equal to "space"? + */ +static int set_match(__isl_keep isl_map *map, __isl_keep isl_space *space) +{ + return isl_space_tuple_is_equal(map->dim, isl_dim_set, + space, isl_dim_out); +} + +/* Internal data structure for preimage_pw_multi_aff. + * + * "pma" is the function under which the preimage should be taken. + * "space" is the space of "pma". + * "res" collects the results. + * "fn" computes the preimage for a given map. + * "match" returns true if "fn" can be called. + */ +struct isl_union_map_preimage_data { + isl_space *space; + isl_pw_multi_aff *pma; + isl_union_map *res; + int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space); + __isl_give isl_map *(*fn)(__isl_take isl_map *map, + __isl_take isl_pw_multi_aff *pma); +}; + +/* Call data->fn to compute the preimage of the domain or range of *entry + * under the function represented by data->pma, provided the domain/range + * space of *entry matches the target space of data->pma + * (as given by data->match), and add the result to data->res. + */ +static isl_stat preimage_entry(void **entry, void *user) +{ + int m; + isl_map *map = *entry; + struct isl_union_map_preimage_data *data = user; + isl_bool empty; + + m = data->match(map, data->space); + if (m < 0) + return isl_stat_error; + if (!m) + return isl_stat_ok; + + map = isl_map_copy(map); + map = data->fn(map, isl_pw_multi_aff_copy(data->pma)); + + empty = isl_map_is_empty(map); + if (empty < 0 || empty) { + isl_map_free(map); + return empty < 0 ? isl_stat_error : isl_stat_ok; + } + + data->res = isl_union_map_add_map(data->res, map); + + return isl_stat_ok; +} + +/* Compute the preimage of the domain or range of "umap" under the function + * represented by "pma". + * In other words, plug in "pma" in the domain or range of "umap". + * The function "fn" performs the actual preimage computation on a map, + * while "match" determines to which maps the function should be applied. + */ +static __isl_give isl_union_map *preimage_pw_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma, + int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space), + __isl_give isl_map *(*fn)(__isl_take isl_map *map, + __isl_take isl_pw_multi_aff *pma)) +{ + isl_ctx *ctx; + isl_space *space; + struct isl_union_map_preimage_data data; + + umap = isl_union_map_align_params(umap, + isl_pw_multi_aff_get_space(pma)); + pma = isl_pw_multi_aff_align_params(pma, isl_union_map_get_space(umap)); + + if (!umap || !pma) + goto error; + + ctx = isl_union_map_get_ctx(umap); + space = isl_union_map_get_space(umap); + data.space = isl_pw_multi_aff_get_space(pma); + data.pma = pma; + data.res = isl_union_map_alloc(space, umap->table.n); + data.match = match; + data.fn = fn; + if (isl_hash_table_foreach(ctx, &umap->table, &preimage_entry, + &data) < 0) + data.res = isl_union_map_free(data.res); + + isl_space_free(data.space); + isl_union_map_free(umap); + isl_pw_multi_aff_free(pma); + return data.res; +error: + isl_union_map_free(umap); + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* Compute the preimage of the domain of "umap" under the function + * represented by "pma". + * In other words, plug in "pma" in the domain of "umap". + * The result contains maps that live in the same spaces as the maps of "umap" + * with domain space equal to the target space of "pma", + * except that the domain has been replaced by the domain space of "pma". + */ +__isl_give isl_union_map *isl_union_map_preimage_domain_pw_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma) +{ + return preimage_pw_multi_aff(umap, pma, &domain_match, + &isl_map_preimage_domain_pw_multi_aff); +} + +/* Compute the preimage of the range of "umap" under the function + * represented by "pma". + * In other words, plug in "pma" in the range of "umap". + * The result contains maps that live in the same spaces as the maps of "umap" + * with range space equal to the target space of "pma", + * except that the range has been replaced by the domain space of "pma". + */ +__isl_give isl_union_map *isl_union_map_preimage_range_pw_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma) +{ + return preimage_pw_multi_aff(umap, pma, &range_match, + &isl_map_preimage_range_pw_multi_aff); +} + +/* Compute the preimage of "uset" under the function represented by "pma". + * In other words, plug in "pma" in "uset". + * The result contains sets that live in the same spaces as the sets of "uset" + * with space equal to the target space of "pma", + * except that the space has been replaced by the domain space of "pma". + */ +__isl_give isl_union_set *isl_union_set_preimage_pw_multi_aff( + __isl_take isl_union_set *uset, __isl_take isl_pw_multi_aff *pma) +{ + return preimage_pw_multi_aff(uset, pma, &set_match, + &isl_set_preimage_pw_multi_aff); +} + +/* Compute the preimage of the domain of "umap" under the function + * represented by "ma". + * In other words, plug in "ma" in the domain of "umap". + * The result contains maps that live in the same spaces as the maps of "umap" + * with domain space equal to the target space of "ma", + * except that the domain has been replaced by the domain space of "ma". + */ +__isl_give isl_union_map *isl_union_map_preimage_domain_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma) +{ + return isl_union_map_preimage_domain_pw_multi_aff(umap, + isl_pw_multi_aff_from_multi_aff(ma)); +} + +/* Compute the preimage of the range of "umap" under the function + * represented by "ma". + * In other words, plug in "ma" in the range of "umap". + * The result contains maps that live in the same spaces as the maps of "umap" + * with range space equal to the target space of "ma", + * except that the range has been replaced by the domain space of "ma". + */ +__isl_give isl_union_map *isl_union_map_preimage_range_multi_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma) +{ + return isl_union_map_preimage_range_pw_multi_aff(umap, + isl_pw_multi_aff_from_multi_aff(ma)); +} + +/* Compute the preimage of "uset" under the function represented by "ma". + * In other words, plug in "ma" in "uset". + * The result contains sets that live in the same spaces as the sets of "uset" + * with space equal to the target space of "ma", + * except that the space has been replaced by the domain space of "ma". + */ +__isl_give isl_union_map *isl_union_set_preimage_multi_aff( + __isl_take isl_union_set *uset, __isl_take isl_multi_aff *ma) +{ + return isl_union_set_preimage_pw_multi_aff(uset, + isl_pw_multi_aff_from_multi_aff(ma)); +} + +/* Internal data structure for preimage_multi_pw_aff. + * + * "mpa" is the function under which the preimage should be taken. + * "space" is the space of "mpa". + * "res" collects the results. + * "fn" computes the preimage for a given map. + * "match" returns true if "fn" can be called. + */ +struct isl_union_map_preimage_mpa_data { + isl_space *space; + isl_multi_pw_aff *mpa; + isl_union_map *res; + int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space); + __isl_give isl_map *(*fn)(__isl_take isl_map *map, + __isl_take isl_multi_pw_aff *mpa); +}; + +/* Call data->fn to compute the preimage of the domain or range of *entry + * under the function represented by data->mpa, provided the domain/range + * space of *entry matches the target space of data->mpa + * (as given by data->match), and add the result to data->res. + */ +static isl_stat preimage_mpa_entry(void **entry, void *user) +{ + int m; + isl_map *map = *entry; + struct isl_union_map_preimage_mpa_data *data = user; + isl_bool empty; + + m = data->match(map, data->space); + if (m < 0) + return isl_stat_error; + if (!m) + return isl_stat_ok; + + map = isl_map_copy(map); + map = data->fn(map, isl_multi_pw_aff_copy(data->mpa)); + + empty = isl_map_is_empty(map); + if (empty < 0 || empty) { + isl_map_free(map); + return empty < 0 ? isl_stat_error : isl_stat_ok; + } + + data->res = isl_union_map_add_map(data->res, map); + + return isl_stat_ok; +} + +/* Compute the preimage of the domain or range of "umap" under the function + * represented by "mpa". + * In other words, plug in "mpa" in the domain or range of "umap". + * The function "fn" performs the actual preimage computation on a map, + * while "match" determines to which maps the function should be applied. + */ +static __isl_give isl_union_map *preimage_multi_pw_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_pw_aff *mpa, + int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space), + __isl_give isl_map *(*fn)(__isl_take isl_map *map, + __isl_take isl_multi_pw_aff *mpa)) +{ + isl_ctx *ctx; + isl_space *space; + struct isl_union_map_preimage_mpa_data data; + + umap = isl_union_map_align_params(umap, + isl_multi_pw_aff_get_space(mpa)); + mpa = isl_multi_pw_aff_align_params(mpa, isl_union_map_get_space(umap)); + + if (!umap || !mpa) + goto error; + + ctx = isl_union_map_get_ctx(umap); + space = isl_union_map_get_space(umap); + data.space = isl_multi_pw_aff_get_space(mpa); + data.mpa = mpa; + data.res = isl_union_map_alloc(space, umap->table.n); + data.match = match; + data.fn = fn; + if (isl_hash_table_foreach(ctx, &umap->table, &preimage_mpa_entry, + &data) < 0) + data.res = isl_union_map_free(data.res); + + isl_space_free(data.space); + isl_union_map_free(umap); + isl_multi_pw_aff_free(mpa); + return data.res; +error: + isl_union_map_free(umap); + isl_multi_pw_aff_free(mpa); + return NULL; +} + +/* Compute the preimage of the domain of "umap" under the function + * represented by "mpa". + * In other words, plug in "mpa" in the domain of "umap". + * The result contains maps that live in the same spaces as the maps of "umap" + * with domain space equal to the target space of "mpa", + * except that the domain has been replaced by the domain space of "mpa". + */ +__isl_give isl_union_map *isl_union_map_preimage_domain_multi_pw_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_pw_aff *mpa) +{ + return preimage_multi_pw_aff(umap, mpa, &domain_match, + &isl_map_preimage_domain_multi_pw_aff); +} + +/* Internal data structure for preimage_upma. + * + * "umap" is the map of which the preimage should be computed. + * "res" collects the results. + * "fn" computes the preimage for a given piecewise multi-affine function. + */ +struct isl_union_map_preimage_upma_data { + isl_union_map *umap; + isl_union_map *res; + __isl_give isl_union_map *(*fn)(__isl_take isl_union_map *umap, + __isl_take isl_pw_multi_aff *pma); +}; + +/* Call data->fn to compute the preimage of the domain or range of data->umap + * under the function represented by pma and add the result to data->res. + */ +static isl_stat preimage_upma(__isl_take isl_pw_multi_aff *pma, void *user) +{ + struct isl_union_map_preimage_upma_data *data = user; + isl_union_map *umap; + + umap = isl_union_map_copy(data->umap); + umap = data->fn(umap, pma); + data->res = isl_union_map_union(data->res, umap); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Compute the preimage of the domain or range of "umap" under the function + * represented by "upma". + * In other words, plug in "upma" in the domain or range of "umap". + * The function "fn" performs the actual preimage computation + * on a piecewise multi-affine function. + */ +static __isl_give isl_union_map *preimage_union_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_multi_aff *upma, + __isl_give isl_union_map *(*fn)(__isl_take isl_union_map *umap, + __isl_take isl_pw_multi_aff *pma)) +{ + struct isl_union_map_preimage_upma_data data; + + data.umap = umap; + data.res = isl_union_map_empty(isl_union_map_get_space(umap)); + data.fn = fn; + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, + &preimage_upma, &data) < 0) + data.res = isl_union_map_free(data.res); + + isl_union_map_free(umap); + isl_union_pw_multi_aff_free(upma); + + return data.res; +} + +/* Compute the preimage of the domain of "umap" under the function + * represented by "upma". + * In other words, plug in "upma" in the domain of "umap". + * The result contains maps that live in the same spaces as the maps of "umap" + * with domain space equal to one of the target spaces of "upma", + * except that the domain has been replaced by one of the domain spaces that + * correspond to that target space of "upma". + */ +__isl_give isl_union_map *isl_union_map_preimage_domain_union_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_multi_aff *upma) +{ + return preimage_union_pw_multi_aff(umap, upma, + &isl_union_map_preimage_domain_pw_multi_aff); +} + +/* Compute the preimage of the range of "umap" under the function + * represented by "upma". + * In other words, plug in "upma" in the range of "umap". + * The result contains maps that live in the same spaces as the maps of "umap" + * with range space equal to one of the target spaces of "upma", + * except that the range has been replaced by one of the domain spaces that + * correspond to that target space of "upma". + */ +__isl_give isl_union_map *isl_union_map_preimage_range_union_pw_multi_aff( + __isl_take isl_union_map *umap, + __isl_take isl_union_pw_multi_aff *upma) +{ + return preimage_union_pw_multi_aff(umap, upma, + &isl_union_map_preimage_range_pw_multi_aff); +} + +/* Compute the preimage of "uset" under the function represented by "upma". + * In other words, plug in "upma" in the range of "uset". + * The result contains sets that live in the same spaces as the sets of "uset" + * with space equal to one of the target spaces of "upma", + * except that the space has been replaced by one of the domain spaces that + * correspond to that target space of "upma". + */ +__isl_give isl_union_set *isl_union_set_preimage_union_pw_multi_aff( + __isl_take isl_union_set *uset, + __isl_take isl_union_pw_multi_aff *upma) +{ + return preimage_union_pw_multi_aff(uset, upma, + &isl_union_set_preimage_pw_multi_aff); +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the spaces of "umap". + */ +__isl_give isl_union_map *isl_union_map_reset_user( + __isl_take isl_union_map *umap) +{ + umap = isl_union_map_cow(umap); + if (!umap) + return NULL; + umap->dim = isl_space_reset_user(umap->dim); + if (!umap->dim) + return isl_union_map_free(umap); + return total(umap, &isl_map_reset_user); +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the spaces of "uset". + */ +__isl_give isl_union_set *isl_union_set_reset_user( + __isl_take isl_union_set *uset) +{ + return isl_union_map_reset_user(uset); +} + +/* Remove all existentially quantified variables and integer divisions + * from "umap" using Fourier-Motzkin elimination. + */ +__isl_give isl_union_map *isl_union_map_remove_divs( + __isl_take isl_union_map *umap) +{ + return total(umap, &isl_map_remove_divs); +} + +/* Remove all existentially quantified variables and integer divisions + * from "uset" using Fourier-Motzkin elimination. + */ +__isl_give isl_union_set *isl_union_set_remove_divs( + __isl_take isl_union_set *uset) +{ + return isl_union_map_remove_divs(uset); +} + +/* Internal data structure for isl_union_map_project_out. + * "type", "first" and "n" are the arguments for the isl_map_project_out + * call. + * "res" collects the results. + */ +struct isl_union_map_project_out_data { + enum isl_dim_type type; + unsigned first; + unsigned n; + + isl_union_map *res; +}; + +/* Turn the data->n dimensions of type data->type, starting at data->first + * into existentially quantified variables and add the result to data->res. + */ +static isl_stat project_out(__isl_take isl_map *map, void *user) +{ + struct isl_union_map_project_out_data *data = user; + + map = isl_map_project_out(map, data->type, data->first, data->n); + data->res = isl_union_map_add_map(data->res, map); + + return isl_stat_ok; +} + +/* Turn the "n" dimensions of type "type", starting at "first" + * into existentially quantified variables. + * Since the space of an isl_union_map only contains parameters, + * type is required to be equal to isl_dim_param. + */ +__isl_give isl_union_map *isl_union_map_project_out( + __isl_take isl_union_map *umap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_space *space; + struct isl_union_map_project_out_data data = { type, first, n }; + + if (!umap) + return NULL; + + if (type != isl_dim_param) + isl_die(isl_union_map_get_ctx(umap), isl_error_invalid, + "can only project out parameters", + return isl_union_map_free(umap)); + + space = isl_union_map_get_space(umap); + space = isl_space_drop_dims(space, type, first, n); + data.res = isl_union_map_empty(space); + if (isl_union_map_foreach_map(umap, &project_out, &data) < 0) + data.res = isl_union_map_free(data.res); + + isl_union_map_free(umap); + + return data.res; +} + +/* Turn the "n" dimensions of type "type", starting at "first" + * into existentially quantified variables. + * Since the space of an isl_union_set only contains parameters, + * "type" is required to be equal to isl_dim_param. + */ +__isl_give isl_union_set *isl_union_set_project_out( + __isl_take isl_union_set *uset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_union_map_project_out(uset, type, first, n); +} + +/* Internal data structure for isl_union_map_involves_dims. + * "first" and "n" are the arguments for the isl_map_involves_dims calls. + */ +struct isl_union_map_involves_dims_data { + unsigned first; + unsigned n; +}; + +/* Does "map" _not_ involve the data->n parameters starting at data->first? + */ +static isl_bool map_excludes(__isl_keep isl_map *map, void *user) +{ + struct isl_union_map_involves_dims_data *data = user; + isl_bool involves; + + involves = isl_map_involves_dims(map, + isl_dim_param, data->first, data->n); + if (involves < 0) + return isl_bool_error; + return !involves; +} + +/* Does "umap" involve any of the n parameters starting at first? + * "type" is required to be set to isl_dim_param. + * + * "umap" involves any of those parameters if any of its maps + * involve the parameters. In other words, "umap" does not + * involve any of the parameters if all its maps to not + * involve the parameters. + */ +isl_bool isl_union_map_involves_dims(__isl_keep isl_union_map *umap, + enum isl_dim_type type, unsigned first, unsigned n) +{ + struct isl_union_map_involves_dims_data data = { first, n }; + isl_bool excludes; + + if (type != isl_dim_param) + isl_die(isl_union_map_get_ctx(umap), isl_error_invalid, + "can only reference parameters", return isl_bool_error); + + excludes = union_map_forall_user(umap, &map_excludes, &data); + + if (excludes < 0) + return isl_bool_error; + + return !excludes; +} + +/* Internal data structure for isl_union_map_reset_range_space. + * "range" is the space from which to set the range space. + * "res" collects the results. + */ +struct isl_union_map_reset_range_space_data { + isl_space *range; + isl_union_map *res; +}; + +/* Replace the range space of "map" by the range space of data->range and + * add the result to data->res. + */ +static isl_stat reset_range_space(__isl_take isl_map *map, void *user) +{ + struct isl_union_map_reset_range_space_data *data = user; + isl_space *space; + + space = isl_map_get_space(map); + space = isl_space_domain(space); + space = isl_space_extend_domain_with_range(space, + isl_space_copy(data->range)); + map = isl_map_reset_space(map, space); + data->res = isl_union_map_add_map(data->res, map); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Replace the range space of all the maps in "umap" by + * the range space of "space". + * + * This assumes that all maps have the same output dimension. + * This function should therefore not be made publicly available. + * + * Since the spaces of the maps change, so do their hash value. + * We therefore need to create a new isl_union_map. + */ +__isl_give isl_union_map *isl_union_map_reset_range_space( + __isl_take isl_union_map *umap, __isl_take isl_space *space) +{ + struct isl_union_map_reset_range_space_data data = { space }; + + data.res = isl_union_map_empty(isl_union_map_get_space(umap)); + if (isl_union_map_foreach_map(umap, &reset_range_space, &data) < 0) + data.res = isl_union_map_free(data.res); + + isl_space_free(space); + isl_union_map_free(umap); + return data.res; +} + +/* Internal data structure for isl_union_map_order_at_multi_union_pw_aff. + * "mupa" is the function from which the isl_multi_pw_affs are extracted. + * "order" is applied to the extracted isl_multi_pw_affs that correspond + * to the domain and the range of each map. + * "res" collects the results. + */ +struct isl_union_order_at_data { + isl_multi_union_pw_aff *mupa; + __isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + isl_union_map *res; +}; + +/* Intersect "map" with the result of applying data->order to + * the functions in data->mupa that apply to the domain and the range + * of "map" and add the result to data->res. + */ +static isl_stat order_at(__isl_take isl_map *map, void *user) +{ + struct isl_union_order_at_data *data = user; + isl_space *space; + isl_multi_pw_aff *mpa1, *mpa2; + isl_map *order; + + space = isl_space_domain(isl_map_get_space(map)); + mpa1 = isl_multi_union_pw_aff_extract_multi_pw_aff(data->mupa, space); + space = isl_space_range(isl_map_get_space(map)); + mpa2 = isl_multi_union_pw_aff_extract_multi_pw_aff(data->mupa, space); + order = data->order(mpa1, mpa2); + map = isl_map_intersect(map, order); + data->res = isl_union_map_add_map(data->res, map); + + return data->res ? isl_stat_ok : isl_stat_error; +} + +/* Intersect each map in "umap" with the result of calling "order" + * on the functions is "mupa" that apply to the domain and the range + * of the map. + */ +static __isl_give isl_union_map *isl_union_map_order_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_union_pw_aff *mupa, + __isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2)) +{ + struct isl_union_order_at_data data; + + umap = isl_union_map_align_params(umap, + isl_multi_union_pw_aff_get_space(mupa)); + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_union_map_get_space(umap)); + data.mupa = mupa; + data.order = order; + data.res = isl_union_map_empty(isl_union_map_get_space(umap)); + if (isl_union_map_foreach_map(umap, &order_at, &data) < 0) + data.res = isl_union_map_free(data.res); + + isl_multi_union_pw_aff_free(mupa); + isl_union_map_free(umap); + return data.res; +} + +/* Return the subset of "umap" where the domain and the range + * have equal "mupa" values. + */ +__isl_give isl_union_map *isl_union_map_eq_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa) +{ + return isl_union_map_order_at_multi_union_pw_aff(umap, mupa, + &isl_multi_pw_aff_eq_map); +} + +/* Return the subset of "umap" where the domain has a lexicographically + * smaller "mupa" value than the range. + */ +__isl_give isl_union_map *isl_union_map_lex_lt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa) +{ + return isl_union_map_order_at_multi_union_pw_aff(umap, mupa, + &isl_multi_pw_aff_lex_lt_map); +} + +/* Return the subset of "umap" where the domain has a lexicographically + * greater "mupa" value than the range. + */ +__isl_give isl_union_map *isl_union_map_lex_gt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa) +{ + return isl_union_map_order_at_multi_union_pw_aff(umap, mupa, + &isl_multi_pw_aff_lex_gt_map); +} + +/* Return the union of the elements in the list "list". + */ +__isl_give isl_union_set *isl_union_set_list_union( + __isl_take isl_union_set_list *list) +{ + int i, n; + isl_ctx *ctx; + isl_space *space; + isl_union_set *res; + + if (!list) + return NULL; + + ctx = isl_union_set_list_get_ctx(list); + space = isl_space_params_alloc(ctx, 0); + res = isl_union_set_empty(space); + + n = isl_union_set_list_n_union_set(list); + for (i = 0; i < n; ++i) { + isl_union_set *uset_i; + + uset_i = isl_union_set_list_get_union_set(list, i); + res = isl_union_set_union(res, uset_i); + } + + isl_union_set_list_free(list); + return res; +} + +/* Update *hash with the hash value of "map". + */ +static isl_stat add_hash(__isl_take isl_map *map, void *user) +{ + uint32_t *hash = user; + uint32_t map_hash; + + map_hash = isl_map_get_hash(map); + isl_hash_hash(*hash, map_hash); + + isl_map_free(map); + return isl_stat_ok; +} + +/* Return a hash value that digests "umap". + */ +uint32_t isl_union_map_get_hash(__isl_keep isl_union_map *umap) +{ + uint32_t hash; + + if (!umap) + return 0; + + hash = isl_hash_init(); + if (isl_union_map_foreach_map(umap, &add_hash, &hash) < 0) + return 0; + + return hash; +} + +/* Return a hash value that digests "uset". + */ +uint32_t isl_union_set_get_hash(__isl_keep isl_union_set *uset) +{ + return isl_union_map_get_hash(uset); +} + +/* Add the number of basic sets in "set" to "n". + */ +static isl_stat add_n(__isl_take isl_set *set, void *user) +{ + int *n = user; + + *n += isl_set_n_basic_set(set); + isl_set_free(set); + + return isl_stat_ok; +} + +/* Return the total number of basic sets in "uset". + */ +int isl_union_set_n_basic_set(__isl_keep isl_union_set *uset) +{ + int n = 0; + + if (isl_union_set_foreach_set(uset, &add_n, &n) < 0) + return -1; + + return n; +} + +/* Add the basic sets in "set" to "list". + */ +static isl_stat add_list(__isl_take isl_set *set, void *user) +{ + isl_basic_set_list **list = user; + isl_basic_set_list *list_i; + + list_i = isl_set_get_basic_set_list(set); + *list = isl_basic_set_list_concat(*list, list_i); + isl_set_free(set); + + if (!*list) + return isl_stat_error; + return isl_stat_ok; +} + +/* Return a list containing all the basic sets in "uset". + * + * First construct a list of the appropriate size and + * then add all the elements. + */ +__isl_give isl_basic_set_list *isl_union_set_get_basic_set_list( + __isl_keep isl_union_set *uset) +{ + int n; + isl_ctx *ctx; + isl_basic_set_list *list; + + if (!uset) + return NULL; + ctx = isl_union_set_get_ctx(uset); + n = isl_union_set_n_basic_set(uset); + if (n < 0) + return NULL; + list = isl_basic_set_list_alloc(ctx, n); + if (isl_union_set_foreach_set(uset, &add_list, &list) < 0) + list = isl_basic_set_list_free(list); + + return list; +} + +/* Internal data structure for isl_union_map_remove_map_if. + * "fn" and "user" are the arguments to isl_union_map_remove_map_if. + */ +struct isl_union_map_remove_map_if_data { + isl_bool (*fn)(__isl_keep isl_map *map, void *user); + void *user; +}; + +/* isl_un_op_control filter that negates the result of data->fn + * called on "map". + */ +static isl_bool not(__isl_keep isl_map *map, void *user) +{ + struct isl_union_map_remove_map_if_data *data = user; + + return isl_bool_not(data->fn(map, data->user)); +} + +/* Dummy isl_un_op_control transformation callback that + * simply returns the input. + */ +static __isl_give isl_map *map_id(__isl_take isl_map *map) +{ + return map; +} + +/* Call "fn" on every map in "umap" and remove those maps + * for which the callback returns true. + * + * Use un_op to keep only those maps that are not filtered out, + * applying an identity transformation on them. + */ +__isl_give isl_union_map *isl_union_map_remove_map_if( + __isl_take isl_union_map *umap, + isl_bool (*fn)(__isl_keep isl_map *map, void *user), void *user) +{ + struct isl_union_map_remove_map_if_data data = { fn, user }; + struct isl_un_op_control control = { + .filter = ¬, + .filter_user = &data, + .fn_map = &map_id, + }; + return un_op(umap, &control); +} Index: contrib/isl/isl_union_map_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_union_map_private.h @@ -0,0 +1,16 @@ +#define isl_union_set_list isl_union_map_list +#define isl_union_set isl_union_map +#include +#include + +struct isl_union_map { + int ref; + isl_space *dim; + + struct isl_hash_table table; +}; + +isl_bool isl_union_map_space_has_equal_params(__isl_keep isl_union_map *umap, + __isl_keep isl_space *space); +__isl_give isl_union_map *isl_union_map_reset_range_space( + __isl_take isl_union_map *umap, __isl_take isl_space *space); Index: contrib/isl/isl_union_multi.c =================================================================== --- /dev/null +++ contrib/isl/isl_union_multi.c @@ -0,0 +1,465 @@ +/* + * Copyright 2010 INRIA Saclay + * Copyright 2013 Ecole Normale Superieure + * Copyright 2015 INRIA Paris-Rocquencourt + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and INRIA Paris-Rocquencourt, Domaine de Voluceau, Rocquenqourt, B.P. 105, + * 78153 Le Chesnay Cedex France + */ + +#include +#include + +/* A group of expressions defined over the same domain space "domain_space". + * The entries of "part_table" are the individual expressions, + * keyed on the entire space of the expression. + * + * Each UNION has its own groups, so there can only ever be a single + * reference to each group. + */ +S(UNION,group) { + isl_space *domain_space; + struct isl_hash_table part_table; +}; + +/* A union of expressions defined over different disjoint domains. + * "space" describes the parameters. + * The entries of "table" are keyed on the domain space of the entry and + * contain groups of expressions that are defined over the same domain space. + */ +struct UNION { + int ref; + isl_space *space; + + struct isl_hash_table table; +}; + +/* Internal data structure for isl_union_*_foreach_group. + * "fn" is the function that needs to be called on each group. + */ +S(UNION,foreach_group_data) +{ + isl_stat (*fn)(__isl_keep S(UNION,group) *group, void *user); + void *user; +}; + +/* Call data->fn on the group stored at *entry. + */ +static isl_stat FN(UNION,call_on_group)(void **entry, void *user) +{ + S(UNION,group) *group = *entry; + S(UNION,foreach_group_data) *data; + + data = (S(UNION,foreach_group_data) *) user; + return data->fn(group, data->user); +} + +/* Call "fn" on each group of expressions in "u". + */ +static isl_stat FN(UNION,foreach_group)(__isl_keep UNION *u, + isl_stat (*fn)(__isl_keep S(UNION,group) *group, void *user), + void *user) +{ + S(UNION,foreach_group_data) data = { fn, user }; + + if (!u) + return isl_stat_error; + + return isl_hash_table_foreach(u->space->ctx, &u->table, + &FN(UNION,call_on_group), &data); +} + +/* A isl_union_*_foreach_group callback for counting the total number + * of expressions in a UNION. Add the number of expressions in "group" + * to *n. + */ +static isl_stat FN(UNION,count_part)(__isl_keep S(UNION,group) *group, + void *user) +{ + int *n = user; + + if (!group) + return isl_stat_error; + + *n += group->part_table.n; + return isl_stat_ok; +} + +/* Return the number of base expressions in "u". + */ +int FN(FN(UNION,n),PARTS)(__isl_keep UNION *u) +{ + int n; + + n = 0; + if (FN(UNION,foreach_group)(u, &FN(UNION,count_part), &n) < 0) + n = -1; + return n; +} + +/* Free an entry in a group of expressions. + * Each entry in such a group is a single expression. + */ +static isl_stat FN(UNION,free_group_entry)(void **entry, void *user) +{ + PART *part = *entry; + + FN(PART,free)(part); + return isl_stat_ok; +} + +/* Free all memory allocated for "group" and return NULL. + */ +static __isl_null S(UNION,group) *FN(UNION,group_free)( + __isl_take S(UNION,group) *group) +{ + isl_ctx *ctx; + + if (!group) + return NULL; + + ctx = isl_space_get_ctx(group->domain_space); + isl_hash_table_foreach(ctx, &group->part_table, + &FN(UNION,free_group_entry), NULL); + isl_hash_table_clear(&group->part_table); + isl_space_free(group->domain_space); + free(group); + return NULL; +} + +/* Allocate a group of expressions defined over the same domain space + * with domain space "domain_space" and initial size "size". + */ +static __isl_give S(UNION,group) *FN(UNION,group_alloc)( + __isl_take isl_space *domain_space, int size) +{ + isl_ctx *ctx; + S(UNION,group) *group; + + if (!domain_space) + return NULL; + ctx = isl_space_get_ctx(domain_space); + group = isl_calloc_type(ctx, S(UNION,group)); + if (!group) + goto error; + group->domain_space = domain_space; + if (isl_hash_table_init(ctx, &group->part_table, size) < 0) + return FN(UNION,group_free)(group); + + return group; +error: + isl_space_free(domain_space); + return NULL; +} + +/* Is the space of "entry" equal to "space"? + */ +static int FN(UNION,has_space)(const void *entry, const void *val) +{ + PART *part = (PART *) entry; + isl_space *space = (isl_space *) val; + + return isl_space_is_equal(part->dim, space); +} + +/* Return a group equal to "group", but with a single reference. + * Since all groups have only a single reference, simply return "group". + */ +static __isl_give S(UNION,group) *FN(UNION,group_cow)( + __isl_take S(UNION,group) *group) +{ + return group; +} + +S(UNION,foreach_data) +{ + isl_stat (*fn)(__isl_take PART *part, void *user); + void *user; +}; + +static isl_stat FN(UNION,call_on_copy)(void **entry, void *user) +{ + PART *part = *entry; + S(UNION,foreach_data) *data = (S(UNION,foreach_data) *) user; + + part = FN(PART,copy)(part); + if (!part) + return isl_stat_error; + return data->fn(part, data->user); +} + +/* Call data->fn on a copy of each expression in "group". + */ +static isl_stat FN(UNION,group_call_on_copy)(__isl_keep S(UNION,group) *group, + void *user) +{ + isl_ctx *ctx; + + if (!group) + return isl_stat_error; + + ctx = isl_space_get_ctx(group->domain_space); + return isl_hash_table_foreach(ctx, &group->part_table, + &FN(UNION,call_on_copy), user); +} + +isl_stat FN(FN(UNION,foreach),PARTS)(__isl_keep UNION *u, + isl_stat (*fn)(__isl_take PART *part, void *user), void *user) +{ + S(UNION,foreach_data) data = { fn, user }; + + if (!u) + return isl_stat_error; + + return FN(UNION,foreach_group)(u, &FN(UNION,group_call_on_copy), &data); +} + +/* Is the domain space of the group of expressions at "entry" + * equal to "space"? + */ +static int FN(UNION,group_has_domain_space)(const void *entry, const void *val) +{ + S(UNION,group) *group = (S(UNION,group) *) entry; + isl_space *space = (isl_space *) val; + + return isl_space_is_domain_internal(group->domain_space, space); +} + +/* Return the entry, if any, in "u" that lives in "space". + * If "reserve" is set, then an entry is created if it does not exist yet. + * Return NULL on error and isl_hash_table_entry_none if no entry was found. + * Note that when "reserve" is set, the function will never return + * isl_hash_table_entry_none. + * + * First look for the group of expressions with the same domain space, + * creating one if needed. + * Then look for the expression living in the specified space in that group. + */ +static struct isl_hash_table_entry *FN(UNION,find_part_entry)( + __isl_keep UNION *u, __isl_keep isl_space *space, int reserve) +{ + isl_ctx *ctx; + uint32_t hash; + struct isl_hash_table_entry *group_entry, *part_entry; + S(UNION,group) *group; + + if (!u || !space) + return NULL; + + ctx = FN(UNION,get_ctx)(u); + hash = isl_space_get_domain_hash(space); + group_entry = isl_hash_table_find(ctx, &u->table, hash, + &FN(UNION,group_has_domain_space), space, reserve); + if (!group_entry) + return reserve ? NULL : isl_hash_table_entry_none; + if (reserve && !group_entry->data) { + isl_space *domain = isl_space_domain(isl_space_copy(space)); + group = FN(UNION,group_alloc)(domain, 1); + group_entry->data = group; + } else { + group = group_entry->data; + if (reserve) + group = FN(UNION,group_cow)(group); + } + if (!group) + return NULL; + hash = isl_space_get_hash(space); + part_entry = isl_hash_table_find(ctx, &group->part_table, hash, + &FN(UNION,has_space), space, reserve); + if (!reserve && !part_entry) + return isl_hash_table_entry_none; + return part_entry; +} + +/* Remove "part_entry" from the hash table of "u". + * + * First look the group_entry in "u" holding the group that + * contains "part_entry". Remove "part_entry" from that group. + * If the group becomes empty, then also remove the group_entry from "u". + */ +static __isl_give UNION *FN(UNION,remove_part_entry)(__isl_take UNION *u, + struct isl_hash_table_entry *part_entry) +{ + isl_ctx *ctx; + uint32_t hash; + PART *part; + struct isl_hash_table_entry *group_entry; + S(UNION,group) *group; + + if (!u || !part_entry) + return FN(UNION,free)(u); + + part = part_entry->data; + ctx = FN(UNION,get_ctx)(u); + hash = isl_space_get_domain_hash(part->dim); + group_entry = isl_hash_table_find(ctx, &u->table, hash, + &FN(UNION,group_has_domain_space), part->dim, 0); + if (!group_entry) + isl_die(ctx, isl_error_internal, "missing group", + return FN(UNION,free)(u)); + group = group_entry->data; + isl_hash_table_remove(ctx, &group->part_table, part_entry); + FN(PART,free)(part); + + if (group->part_table.n != 0) + return u; + + isl_hash_table_remove(ctx, &u->table, group_entry); + FN(UNION,group_free)(group); + + return u; +} + +/* Are the domains of "part1" and "part2" disjoint? + */ +static isl_bool FN(UNION,disjoint_domain)(__isl_keep PART *part1, + __isl_keep PART *part2) +{ + isl_set *dom1, *dom2; + isl_bool disjoint; + + if (!part1 || !part2) + return isl_bool_error; + dom1 = FN(PART,domain)(FN(PART,copy)(part1)); + dom2 = FN(PART,domain)(FN(PART,copy)(part2)); + disjoint = isl_set_is_disjoint(dom1, dom2); + isl_set_free(dom1); + isl_set_free(dom2); + + return disjoint; +} + +/* Check that the expression at *entry has a domain that is disjoint + * from that of "part", unless they also have the same target space. + */ +static isl_stat FN(UNION,check_disjoint_domain_entry)(void **entry, void *user) +{ + PART *part = user; + PART *other = *entry; + isl_bool equal; + isl_bool disjoint; + + equal = isl_space_is_equal(part->dim, other->dim); + if (equal < 0) + return isl_stat_error; + if (equal) + return isl_stat_ok; + + disjoint = FN(UNION,disjoint_domain)(part, other); + if (disjoint < 0) + return isl_stat_error; + if (!disjoint) + isl_die(FN(PART,get_ctx)(part), isl_error_invalid, + "overlapping domain with other part", + return isl_stat_error); + return isl_stat_ok; +} + +/* Check that the domain of "part" is disjoint from the domain of the entries + * in "u" that are defined on the same domain space, but have a different + * target space. + * If there is no group of expressions in "u" with the same domain space, + * then everything is fine. Otherwise, check the individual expressions + * in that group. + */ +static isl_stat FN(UNION,check_disjoint_domain_other)(__isl_keep UNION *u, + __isl_keep PART *part) +{ + isl_ctx *ctx; + uint32_t hash; + struct isl_hash_table_entry *group_entry; + S(UNION,group) *group; + + if (!u || !part) + return isl_stat_error; + ctx = FN(UNION,get_ctx)(u); + hash = isl_space_get_domain_hash(part->dim); + group_entry = isl_hash_table_find(ctx, &u->table, hash, + &FN(UNION,group_has_domain_space), part->dim, 0); + if (!group_entry) + return isl_stat_ok; + group = group_entry->data; + return isl_hash_table_foreach(ctx, &group->part_table, + &FN(UNION,check_disjoint_domain_entry), part); +} + +/* Check that the domain of "part1" is disjoint from the domain of "part2". + * This check is performed before "part2" is added to a UNION to ensure + * that the UNION expression remains a function. + */ +static isl_stat FN(UNION,check_disjoint_domain)(__isl_keep PART *part1, + __isl_keep PART *part2) +{ + isl_bool disjoint; + + disjoint = FN(UNION,disjoint_domain)(part1, part2); + if (disjoint < 0) + return isl_stat_error; + if (!disjoint) + isl_die(FN(PART,get_ctx)(part1), isl_error_invalid, + "domain of additional part should be disjoint", + return isl_stat_error); + return isl_stat_ok; +} + +/* Internal data structure for isl_union_*_foreach_inplace. + * "fn" is the function that needs to be called on each entry. + */ +S(UNION,foreach_inplace_data) +{ + isl_stat (*fn)(void **entry, void *user); + void *user; +}; + +/* isl_union_*_foreach_group callback for calling data->fn on + * each part entry in the group. + */ +static isl_stat FN(UNION,group_call_inplace)(__isl_keep S(UNION,group) *group, + void *user) +{ + isl_ctx *ctx; + S(UNION,foreach_inplace_data) *data; + + if (!group) + return isl_stat_error; + + data = (S(UNION,foreach_inplace_data) *) user; + ctx = isl_space_get_ctx(group->domain_space); + return isl_hash_table_foreach(ctx, &group->part_table, + data->fn, data->user); +} + +/* Call "fn" on each part entry of "u". + */ +static isl_stat FN(UNION,foreach_inplace)(__isl_keep UNION *u, + isl_stat (*fn)(void **part, void *user), void *user) +{ + S(UNION,foreach_inplace_data) data = { fn, user }; + + return FN(UNION,foreach_group)(u, &FN(UNION,group_call_inplace), &data); +} + +/* Does "u" have a single reference? + * That is, can we change "u" inplace? + */ +static isl_bool FN(UNION,has_single_reference)(__isl_keep UNION *u) +{ + if (!u) + return isl_bool_error; + return u->ref == 1; +} + +static isl_stat FN(UNION,free_u_entry)(void **entry, void *user) +{ + S(UNION,group) *group = *entry; + FN(UNION,group_free)(group); + return isl_stat_ok; +} + +#include Index: contrib/isl/isl_union_neg.c =================================================================== --- /dev/null +++ contrib/isl/isl_union_neg.c @@ -0,0 +1,25 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#include + +/* Return the opposite of "part". + */ +static __isl_give PART *FN(UNION,neg_entry)(__isl_take PART *part, void *user) +{ + return FN(PART,neg)(part); +} + +/* Return the opposite of "u". + */ +__isl_give UNION *FN(UNION,neg)(__isl_take UNION *u) +{ + return FN(UNION,transform_inplace)(u, &FN(UNION,neg_entry), NULL); +} Index: contrib/isl/isl_union_set_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_union_set_private.h @@ -0,0 +1,11 @@ +#ifndef ISL_UNION_SET_PRIVATE_H +#define ISL_UNION_SET_PRIVATE_H + +#include + +__isl_give isl_union_set *isl_union_set_combined_lineality_space( + __isl_take isl_union_set *uset); +__isl_give isl_union_set *isl_union_set_plain_gist( + __isl_take isl_union_set *uset, __isl_take isl_union_set *context); + +#endif Index: contrib/isl/isl_union_single.c =================================================================== --- /dev/null +++ contrib/isl/isl_union_single.c @@ -0,0 +1,197 @@ +/* + * Copyright 2010 INRIA Saclay + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include + +/* A union of expressions defined over different domain spaces. + * "space" describes the parameters. + * The entries of "table" are keyed on the domain space of the entry. + */ +struct UNION { + int ref; +#ifdef HAS_TYPE + enum isl_fold type; +#endif + isl_space *space; + + struct isl_hash_table table; +}; + +/* Return the number of base expressions in "u". + */ +int FN(FN(UNION,n),PARTS)(__isl_keep UNION *u) +{ + return u ? u->table.n : 0; +} + +S(UNION,foreach_data) +{ + isl_stat (*fn)(__isl_take PART *part, void *user); + void *user; +}; + +static isl_stat FN(UNION,call_on_copy)(void **entry, void *user) +{ + PART *part = *entry; + S(UNION,foreach_data) *data = (S(UNION,foreach_data) *)user; + + part = FN(PART,copy)(part); + if (!part) + return isl_stat_error; + return data->fn(part, data->user); +} + +isl_stat FN(FN(UNION,foreach),PARTS)(__isl_keep UNION *u, + isl_stat (*fn)(__isl_take PART *part, void *user), void *user) +{ + S(UNION,foreach_data) data = { fn, user }; + + if (!u) + return isl_stat_error; + + return isl_hash_table_foreach(u->space->ctx, &u->table, + &FN(UNION,call_on_copy), &data); +} + +/* Is the domain space of "entry" equal to the domain of "space"? + */ +static int FN(UNION,has_same_domain_space)(const void *entry, const void *val) +{ + PART *part = (PART *)entry; + isl_space *space = (isl_space *) val; + + if (isl_space_is_set(space)) + return isl_space_is_set(part->dim); + + return isl_space_tuple_is_equal(part->dim, isl_dim_in, + space, isl_dim_in); +} + +/* Return the entry, if any, in "u" that lives in "space". + * If "reserve" is set, then an entry is created if it does not exist yet. + * Return NULL on error and isl_hash_table_entry_none if no entry was found. + * Note that when "reserve" is set, the function will never return + * isl_hash_table_entry_none. + * + * First look for the entry (if any) with the same domain space. + * If it exists, then check if the range space also matches. + */ +static struct isl_hash_table_entry *FN(UNION,find_part_entry)( + __isl_keep UNION *u, __isl_keep isl_space *space, int reserve) +{ + isl_ctx *ctx; + uint32_t hash; + struct isl_hash_table_entry *entry; + isl_bool equal; + PART *part; + + if (!u || !space) + return NULL; + + ctx = FN(UNION,get_ctx)(u); + hash = isl_space_get_domain_hash(space); + entry = isl_hash_table_find(ctx, &u->table, hash, + &FN(UNION,has_same_domain_space), space, reserve); + if (!entry) + return reserve ? NULL : isl_hash_table_entry_none; + if (reserve && !entry->data) + return entry; + part = entry->data; + equal = isl_space_tuple_is_equal(part->dim, isl_dim_out, + space, isl_dim_out); + if (equal < 0) + return NULL; + if (equal) + return entry; + if (!reserve) + return isl_hash_table_entry_none; + isl_die(FN(UNION,get_ctx)(u), isl_error_invalid, + "union expression can only contain a single " + "expression over a given domain", return NULL); +} + +/* Remove "part_entry" from the hash table of "u". + */ +static __isl_give UNION *FN(UNION,remove_part_entry)(__isl_take UNION *u, + struct isl_hash_table_entry *part_entry) +{ + isl_ctx *ctx; + + if (!u || !part_entry) + return FN(UNION,free)(u); + + ctx = FN(UNION,get_ctx)(u); + isl_hash_table_remove(ctx, &u->table, part_entry); + FN(PART,free)(part_entry->data); + + return u; +} + +/* Check that the domain of "part" is disjoint from the domain of the entries + * in "u" that are defined on the same domain space, but have a different + * target space. + * Since a UNION with a single entry per domain space is not allowed + * to contain two entries with the same domain space, there cannot be + * any such other entry. + */ +static isl_stat FN(UNION,check_disjoint_domain_other)(__isl_keep UNION *u, + __isl_keep PART *part) +{ + return isl_stat_ok; +} + +/* Check that the domain of "part1" is disjoint from the domain of "part2". + * This check is performed before "part2" is added to a UNION to ensure + * that the UNION expression remains a function. + * Since a UNION with a single entry per domain space is not allowed + * to contain two entries with the same domain space, fail unconditionally. + */ +static isl_stat FN(UNION,check_disjoint_domain)(__isl_keep PART *part1, + __isl_keep PART *part2) +{ + isl_die(FN(PART,get_ctx)(part1), isl_error_invalid, + "additional part should live on separate space", + return isl_stat_error); +} + +/* Call "fn" on each part entry of "u". + */ +static isl_stat FN(UNION,foreach_inplace)(__isl_keep UNION *u, + isl_stat (*fn)(void **part, void *user), void *user) +{ + isl_ctx *ctx; + + if (!u) + return isl_stat_error; + ctx = FN(UNION,get_ctx)(u); + return isl_hash_table_foreach(ctx, &u->table, fn, user); +} + +/* Does "u" have a single reference? + * That is, can we change "u" inplace? + */ +static isl_bool FN(UNION,has_single_reference)(__isl_keep UNION *u) +{ + if (!u) + return isl_bool_error; + return u->ref == 1; +} + +static isl_stat FN(UNION,free_u_entry)(void **entry, void *user) +{ + PART *part = *entry; + FN(PART,free)(part); + return isl_stat_ok; +} + +#include Index: contrib/isl/isl_union_templ.c =================================================================== --- /dev/null +++ contrib/isl/isl_union_templ.c @@ -0,0 +1,1172 @@ +/* + * Copyright 2010 INRIA Saclay + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +__isl_give UNION *FN(UNION,cow)(__isl_take UNION *u); + +isl_ctx *FN(UNION,get_ctx)(__isl_keep UNION *u) +{ + return u ? u->space->ctx : NULL; +} + +__isl_give isl_space *FN(UNION,get_space)(__isl_keep UNION *u) +{ + if (!u) + return NULL; + return isl_space_copy(u->space); +} + +/* Return the number of parameters of "u", where "type" + * is required to be set to isl_dim_param. + */ +unsigned FN(UNION,dim)(__isl_keep UNION *u, enum isl_dim_type type) +{ + if (!u) + return 0; + + if (type != isl_dim_param) + isl_die(FN(UNION,get_ctx)(u), isl_error_invalid, + "can only reference parameters", return 0); + + return isl_space_dim(u->space, type); +} + +/* Return the position of the parameter with the given name + * in "u". + * Return -1 if no such dimension can be found. + */ +int FN(UNION,find_dim_by_name)(__isl_keep UNION *u, enum isl_dim_type type, + const char *name) +{ + if (!u) + return -1; + return isl_space_find_dim_by_name(u->space, type, name); +} + +#ifdef HAS_TYPE +static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim, + enum isl_fold type, int size) +#else +static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim, int size) +#endif +{ + UNION *u; + + dim = isl_space_params(dim); + if (!dim) + return NULL; + + u = isl_calloc_type(dim->ctx, UNION); + if (!u) + goto error; + + u->ref = 1; +#ifdef HAS_TYPE + u->type = type; +#endif + u->space = dim; + if (isl_hash_table_init(dim->ctx, &u->table, size) < 0) + return FN(UNION,free)(u); + + return u; +error: + isl_space_free(dim); + return NULL; +} + +#ifdef HAS_TYPE +__isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim, enum isl_fold type) +{ + return FN(UNION,alloc)(dim, type, 16); +} +#else +__isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim) +{ + return FN(UNION,alloc)(dim, 16); +} +#endif + +__isl_give UNION *FN(UNION,copy)(__isl_keep UNION *u) +{ + if (!u) + return NULL; + + u->ref++; + return u; +} + +/* Extract the element of "u" living in "space" (ignoring parameters). + * + * Return the ZERO element if "u" does not contain any element + * living in "space". + */ +__isl_give PART *FN(FN(UNION,extract),PARTS)(__isl_keep UNION *u, + __isl_take isl_space *space) +{ + struct isl_hash_table_entry *entry; + isl_bool equal_params; + + if (!u || !space) + goto error; + equal_params = isl_space_has_equal_params(u->space, space); + if (equal_params < 0) + goto error; + if (!equal_params) { + space = isl_space_drop_dims(space, isl_dim_param, + 0, isl_space_dim(space, isl_dim_param)); + space = isl_space_align_params(space, + FN(UNION,get_space)(u)); + if (!space) + goto error; + } + + entry = FN(UNION,find_part_entry)(u, space, 0); + if (!entry) + goto error; + if (entry == isl_hash_table_entry_none) +#ifdef HAS_TYPE + return FN(PART,ZERO)(space, u->type); +#else + return FN(PART,ZERO)(space); +#endif + isl_space_free(space); + return FN(PART,copy)(entry->data); +error: + isl_space_free(space); + return NULL; +} + +/* Add "part" to "u". + * If "disjoint" is set, then "u" is not allowed to already have + * a part that is defined over a domain that overlaps with the domain + * of "part". + * Otherwise, compute the union sum of "part" and the part in "u" + * defined on the same space. + */ +static __isl_give UNION *FN(UNION,add_part_generic)(__isl_take UNION *u, + __isl_take PART *part, int disjoint) +{ + int empty; + struct isl_hash_table_entry *entry; + + if (!part) + goto error; + + empty = FN(PART,IS_ZERO)(part); + if (empty < 0) + goto error; + if (empty) { + FN(PART,free)(part); + return u; + } + + u = FN(UNION,align_params)(u, FN(PART,get_space)(part)); + part = FN(PART,align_params)(part, FN(UNION,get_space)(u)); + + u = FN(UNION,cow)(u); + + if (!u) + goto error; + + if (FN(UNION,check_disjoint_domain_other)(u, part) < 0) + goto error; + entry = FN(UNION,find_part_entry)(u, part->dim, 1); + if (!entry) + goto error; + + if (!entry->data) + entry->data = part; + else { + if (disjoint && + FN(UNION,check_disjoint_domain)(entry->data, part) < 0) + goto error; + entry->data = FN(PART,union_add_)(entry->data, + FN(PART,copy)(part)); + if (!entry->data) + goto error; + empty = FN(PART,IS_ZERO)(part); + if (empty < 0) + goto error; + if (empty) + u = FN(UNION,remove_part_entry)(u, entry); + FN(PART,free)(part); + } + + return u; +error: + FN(PART,free)(part); + FN(UNION,free)(u); + return NULL; +} + +/* Add "part" to "u", where "u" is assumed not to already have + * a part that is defined on the same space as "part". + */ +__isl_give UNION *FN(FN(UNION,add),PARTS)(__isl_take UNION *u, + __isl_take PART *part) +{ + return FN(UNION,add_part_generic)(u, part, 1); +} + +#ifdef HAS_TYPE +/* Allocate a UNION with the same type and the same size as "u" and + * with space "space". + */ +static __isl_give UNION *FN(UNION,alloc_same_size_on_space)(__isl_keep UNION *u, + __isl_take isl_space *space) +{ + if (!u) + goto error; + return FN(UNION,alloc)(space, u->type, u->table.n); +error: + isl_space_free(space); + return NULL; +} +#else +/* Allocate a UNION with the same size as "u" and with space "space". + */ +static __isl_give UNION *FN(UNION,alloc_same_size_on_space)(__isl_keep UNION *u, + __isl_take isl_space *space) +{ + if (!u) + goto error; + return FN(UNION,alloc)(space, u->table.n); +error: + isl_space_free(space); + return NULL; +} +#endif + +/* Allocate a UNION with the same space, the same type (if any) and + * the same size as "u". + */ +static __isl_give UNION *FN(UNION,alloc_same_size)(__isl_keep UNION *u) +{ + return FN(UNION,alloc_same_size_on_space)(u, FN(UNION,get_space)(u)); +} + +/* Internal data structure for isl_union_*_transform_space. + * "fn' is applied to each entry in the input. + * "res" collects the results. + */ +S(UNION,transform_data) +{ + __isl_give PART *(*fn)(__isl_take PART *part, void *user); + void *user; + + UNION *res; +}; + +/* Apply data->fn to "part" and add the result to data->res. + */ +static isl_stat FN(UNION,transform_entry)(__isl_take PART *part, void *user) +{ + S(UNION,transform_data) *data = (S(UNION,transform_data) *)user; + + part = data->fn(part, data->user); + data->res = FN(FN(UNION,add),PARTS)(data->res, part); + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Return a UNION living in "space" that is obtained by applying "fn" + * to each of the entries in "u". + */ +static __isl_give UNION *FN(UNION,transform_space)(__isl_take UNION *u, + isl_space *space, + __isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user) +{ + S(UNION,transform_data) data = { fn, user }; + + data.res = FN(UNION,alloc_same_size_on_space)(u, space); + if (FN(FN(UNION,foreach),PARTS)(u, + &FN(UNION,transform_entry), &data) < 0) + data.res = FN(UNION,free)(data.res); + FN(UNION,free)(u); + return data.res; +} + +/* Return a UNION that lives in the same space as "u" and that is obtained + * by applying "fn" to each of the entries in "u". + */ +static __isl_give UNION *FN(UNION,transform)(__isl_take UNION *u, + __isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user) +{ + return FN(UNION,transform_space)(u, FN(UNION,get_space)(u), fn, user); +} + +/* Apply data->fn to *part and store the result back into *part. + */ +static isl_stat FN(UNION,transform_inplace_entry)(void **part, void *user) +{ + S(UNION,transform_data) *data = (S(UNION,transform_data) *) user; + + *part = data->fn(*part, data->user); + if (!*part) + return isl_stat_error; + return isl_stat_ok; +} + +/* Update "u" by applying "fn" to each entry. + * This operation is assumed not to change the number of entries nor + * the spaces of the entries. + * + * If there is only one reference to "u", then change "u" inplace. + * Otherwise, create a new UNION from "u" and discard the original. + */ +static __isl_give UNION *FN(UNION,transform_inplace)(__isl_take UNION *u, + __isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user) +{ + isl_bool single_ref; + + single_ref = FN(UNION,has_single_reference)(u); + if (single_ref < 0) + return FN(UNION,free)(u); + if (single_ref) { + S(UNION,transform_data) data = { fn, user }; + if (FN(UNION,foreach_inplace)(u, + &FN(UNION,transform_inplace_entry), &data) < 0) + return FN(UNION,free)(u); + return u; + } + return FN(UNION,transform)(u, fn, user); +} + +/* An isl_union_*_transform callback for use in isl_union_*_dup + * that simply returns "part". + */ +static __isl_give PART *FN(UNION,copy_part)(__isl_take PART *part, void *user) +{ + return part; +} + +__isl_give UNION *FN(UNION,dup)(__isl_keep UNION *u) +{ + u = FN(UNION,copy)(u); + return FN(UNION,transform)(u, &FN(UNION,copy_part), NULL); +} + +__isl_give UNION *FN(UNION,cow)(__isl_take UNION *u) +{ + if (!u) + return NULL; + + if (u->ref == 1) + return u; + u->ref--; + return FN(UNION,dup)(u); +} + +__isl_null UNION *FN(UNION,free)(__isl_take UNION *u) +{ + if (!u) + return NULL; + + if (--u->ref > 0) + return NULL; + + isl_hash_table_foreach(u->space->ctx, &u->table, + &FN(UNION,free_u_entry), NULL); + isl_hash_table_clear(&u->table); + isl_space_free(u->space); + free(u); + return NULL; +} + +static __isl_give PART *FN(UNION,align_entry)(__isl_take PART *part, void *user) +{ + isl_reordering *exp = user; + + exp = isl_reordering_extend_space(isl_reordering_copy(exp), + FN(PART,get_domain_space)(part)); + return FN(PART,realign_domain)(part, exp); +} + +/* Reorder the parameters of "u" according to the given reordering. + */ +static __isl_give UNION *FN(UNION,realign_domain)(__isl_take UNION *u, + __isl_take isl_reordering *r) +{ + isl_space *space; + + if (!u || !r) + goto error; + + space = isl_space_copy(r->dim); + u = FN(UNION,transform_space)(u, space, &FN(UNION,align_entry), r); + isl_reordering_free(r); + return u; +error: + FN(UNION,free)(u); + isl_reordering_free(r); + return NULL; +} + +/* Align the parameters of "u" to those of "model". + */ +__isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u, + __isl_take isl_space *model) +{ + isl_bool equal_params; + isl_reordering *r; + + if (!u || !model) + goto error; + + equal_params = isl_space_has_equal_params(u->space, model); + if (equal_params < 0) + goto error; + if (equal_params) { + isl_space_free(model); + return u; + } + + model = isl_space_params(model); + r = isl_parameter_alignment_reordering(u->space, model); + isl_space_free(model); + + return FN(UNION,realign_domain)(u, r); +error: + isl_space_free(model); + FN(UNION,free)(u); + return NULL; +} + +/* Add "part" to *u, taking the union sum if "u" already has + * a part defined on the same space as "part". + */ +static isl_stat FN(UNION,union_add_part)(__isl_take PART *part, void *user) +{ + UNION **u = (UNION **)user; + + *u = FN(UNION,add_part_generic)(*u, part, 0); + + return isl_stat_ok; +} + +/* Compute the sum of "u1" and "u2" on the union of their domains, + * with the actual sum on the shared domain and + * the defined expression on the symmetric difference of the domains. + * + * This is an internal function that is exposed under different + * names depending on whether the base expressions have a zero default + * value. + * If they do, then this function is called "add". + * Otherwise, it is called "union_add". + */ +static __isl_give UNION *FN(UNION,union_add_)(__isl_take UNION *u1, + __isl_take UNION *u2) +{ + u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2)); + u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1)); + + u1 = FN(UNION,cow)(u1); + + if (!u1 || !u2) + goto error; + + if (FN(FN(UNION,foreach),PARTS)(u2, &FN(UNION,union_add_part), &u1) < 0) + goto error; + + FN(UNION,free)(u2); + + return u1; +error: + FN(UNION,free)(u1); + FN(UNION,free)(u2); + return NULL; +} + +__isl_give UNION *FN(FN(UNION,from),PARTS)(__isl_take PART *part) +{ + isl_space *dim; + UNION *u; + + if (!part) + return NULL; + + dim = FN(PART,get_space)(part); + dim = isl_space_drop_dims(dim, isl_dim_in, 0, isl_space_dim(dim, isl_dim_in)); + dim = isl_space_drop_dims(dim, isl_dim_out, 0, isl_space_dim(dim, isl_dim_out)); +#ifdef HAS_TYPE + u = FN(UNION,ZERO)(dim, part->type); +#else + u = FN(UNION,ZERO)(dim); +#endif + u = FN(FN(UNION,add),PARTS)(u, part); + + return u; +} + +S(UNION,match_bin_data) { + UNION *u2; + UNION *res; + __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *); +}; + +/* Check if data->u2 has an element living in the same space as "part". + * If so, call data->fn on the two elements and add the result to + * data->res. + */ +static isl_stat FN(UNION,match_bin_entry)(__isl_take PART *part, void *user) +{ + S(UNION,match_bin_data) *data = user; + struct isl_hash_table_entry *entry2; + isl_space *space; + PART *part2; + + space = FN(PART,get_space)(part); + entry2 = FN(UNION,find_part_entry)(data->u2, space, 0); + isl_space_free(space); + if (!entry2) + goto error; + if (entry2 == isl_hash_table_entry_none) { + FN(PART,free)(part); + return isl_stat_ok; + } + + part2 = entry2->data; + if (!isl_space_tuple_is_equal(part->dim, isl_dim_out, + part2->dim, isl_dim_out)) + isl_die(FN(UNION,get_ctx)(data->u2), isl_error_invalid, + "entries should have the same range space", + goto error); + + part = data->fn(part, FN(PART, copy)(entry2->data)); + + data->res = FN(FN(UNION,add),PARTS)(data->res, part); + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +error: + FN(PART,free)(part); + return isl_stat_error; +} + +/* This function is currently only used from isl_polynomial.c + * and not from isl_fold.c. + */ +static __isl_give UNION *FN(UNION,match_bin_op)(__isl_take UNION *u1, + __isl_take UNION *u2, + __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *)) + __attribute__ ((unused)); +/* For each pair of elements in "u1" and "u2" living in the same space, + * call "fn" and collect the results. + */ +static __isl_give UNION *FN(UNION,match_bin_op)(__isl_take UNION *u1, + __isl_take UNION *u2, + __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *)) +{ + S(UNION,match_bin_data) data = { NULL, NULL, fn }; + + u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2)); + u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1)); + + if (!u1 || !u2) + goto error; + + data.u2 = u2; + data.res = FN(UNION,alloc_same_size)(u1); + if (FN(FN(UNION,foreach),PARTS)(u1, + &FN(UNION,match_bin_entry), &data) < 0) + goto error; + + FN(UNION,free)(u1); + FN(UNION,free)(u2); + return data.res; +error: + FN(UNION,free)(u1); + FN(UNION,free)(u2); + FN(UNION,free)(data.res); + return NULL; +} + +/* Compute the sum of "u1" and "u2". + * + * If the base expressions have a default zero value, then the sum + * is computed on the union of the domains of "u1" and "u2". + * Otherwise, it is computed on their shared domains. + */ +__isl_give UNION *FN(UNION,add)(__isl_take UNION *u1, __isl_take UNION *u2) +{ +#if DEFAULT_IS_ZERO + return FN(UNION,union_add_)(u1, u2); +#else + return FN(UNION,match_bin_op)(u1, u2, &FN(PART,add)); +#endif +} + +#ifndef NO_SUB +/* Subtract "u2" from "u1" and return the result. + */ +__isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2) +{ + return FN(UNION,match_bin_op)(u1, u2, &FN(PART,sub)); +} +#endif + +S(UNION,any_set_data) { + isl_set *set; + __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*); +}; + +static __isl_give PART *FN(UNION,any_set_entry)(__isl_take PART *part, + void *user) +{ + S(UNION,any_set_data) *data = user; + + return data->fn(part, isl_set_copy(data->set)); +} + +/* Update each element of "u" by calling "fn" on the element and "set". + */ +static __isl_give UNION *FN(UNION,any_set_op)(__isl_take UNION *u, + __isl_take isl_set *set, + __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*)) +{ + S(UNION,any_set_data) data = { NULL, fn }; + + u = FN(UNION,align_params)(u, isl_set_get_space(set)); + set = isl_set_align_params(set, FN(UNION,get_space)(u)); + + if (!u || !set) + goto error; + + data.set = set; + u = FN(UNION,transform)(u, &FN(UNION,any_set_entry), &data); + isl_set_free(set); + return u; +error: + FN(UNION,free)(u); + isl_set_free(set); + return NULL; +} + +/* Intersect the domain of "u" with the parameter domain "context". + */ +__isl_give UNION *FN(UNION,intersect_params)(__isl_take UNION *u, + __isl_take isl_set *set) +{ + return FN(UNION,any_set_op)(u, set, &FN(PW,intersect_params)); +} + +/* Compute the gist of the domain of "u" with respect to + * the parameter domain "context". + */ +__isl_give UNION *FN(UNION,gist_params)(__isl_take UNION *u, + __isl_take isl_set *set) +{ + return FN(UNION,any_set_op)(u, set, &FN(PW,gist_params)); +} + +S(UNION,match_domain_data) { + isl_union_set *uset; + UNION *res; + __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*); +}; + +static int FN(UNION,set_has_dim)(const void *entry, const void *val) +{ + isl_set *set = (isl_set *)entry; + isl_space *dim = (isl_space *)val; + + return isl_space_is_equal(set->dim, dim); +} + +/* Find the set in data->uset that lives in the same space as the domain + * of "part", apply data->fn to *entry and this set (if any), and add + * the result to data->res. + */ +static isl_stat FN(UNION,match_domain_entry)(__isl_take PART *part, void *user) +{ + S(UNION,match_domain_data) *data = user; + uint32_t hash; + struct isl_hash_table_entry *entry2; + isl_space *space; + + space = FN(PART,get_domain_space)(part); + hash = isl_space_get_hash(space); + entry2 = isl_hash_table_find(data->uset->dim->ctx, &data->uset->table, + hash, &FN(UNION,set_has_dim), space, 0); + isl_space_free(space); + if (!entry2) { + FN(PART,free)(part); + return isl_stat_ok; + } + + part = data->fn(part, isl_set_copy(entry2->data)); + + data->res = FN(FN(UNION,add),PARTS)(data->res, part); + if (!data->res) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Apply fn to each pair of PW in u and set in uset such that + * the set lives in the same space as the domain of PW + * and collect the results. + */ +static __isl_give UNION *FN(UNION,match_domain_op)(__isl_take UNION *u, + __isl_take isl_union_set *uset, + __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*)) +{ + S(UNION,match_domain_data) data = { NULL, NULL, fn }; + + u = FN(UNION,align_params)(u, isl_union_set_get_space(uset)); + uset = isl_union_set_align_params(uset, FN(UNION,get_space)(u)); + + if (!u || !uset) + goto error; + + data.uset = uset; + data.res = FN(UNION,alloc_same_size)(u); + if (FN(FN(UNION,foreach),PARTS)(u, + &FN(UNION,match_domain_entry), &data) < 0) + goto error; + + FN(UNION,free)(u); + isl_union_set_free(uset); + return data.res; +error: + FN(UNION,free)(u); + isl_union_set_free(uset); + FN(UNION,free)(data.res); + return NULL; +} + +/* Intersect the domain of "u" with "uset". + * If "uset" is a parameters domain, then intersect the parameter + * domain of "u" with this set. + */ +__isl_give UNION *FN(UNION,intersect_domain)(__isl_take UNION *u, + __isl_take isl_union_set *uset) +{ + if (isl_union_set_is_params(uset)) + return FN(UNION,intersect_params)(u, + isl_set_from_union_set(uset)); + return FN(UNION,match_domain_op)(u, uset, &FN(PW,intersect_domain)); +} + +/* Take the set (which may be empty) in data->uset that lives + * in the same space as the domain of "pw", subtract it from the domain + * of "part" and return the result. + */ +static __isl_give PART *FN(UNION,subtract_domain_entry)(__isl_take PART *part, + void *user) +{ + isl_union_set *uset = user; + isl_space *space; + isl_set *set; + + space = FN(PART,get_domain_space)(part); + set = isl_union_set_extract_set(uset, space); + return FN(PART,subtract_domain)(part, set); +} + +/* Subtract "uset' from the domain of "u". + */ +__isl_give UNION *FN(UNION,subtract_domain)(__isl_take UNION *u, + __isl_take isl_union_set *uset) +{ + u = FN(UNION,transform)(u, &FN(UNION,subtract_domain_entry), uset); + isl_union_set_free(uset); + return u; +} + +__isl_give UNION *FN(UNION,gist)(__isl_take UNION *u, + __isl_take isl_union_set *uset) +{ + if (isl_union_set_is_params(uset)) + return FN(UNION,gist_params)(u, isl_set_from_union_set(uset)); + return FN(UNION,match_domain_op)(u, uset, &FN(PW,gist)); +} + +/* Coalesce an entry in a UNION. Coalescing is performed in-place. + * Since the UNION may have several references, the entry is only + * replaced if the coalescing is successful. + */ +static isl_stat FN(UNION,coalesce_entry)(void **entry, void *user) +{ + PART **part_p = (PART **) entry; + PART *part; + + part = FN(PART,copy)(*part_p); + part = FN(PW,coalesce)(part); + if (!part) + return isl_stat_error; + FN(PART,free)(*part_p); + *part_p = part; + + return isl_stat_ok; +} + +__isl_give UNION *FN(UNION,coalesce)(__isl_take UNION *u) +{ + if (FN(UNION,foreach_inplace)(u, &FN(UNION,coalesce_entry), NULL) < 0) + goto error; + + return u; +error: + FN(UNION,free)(u); + return NULL; +} + +static isl_stat FN(UNION,domain_entry)(__isl_take PART *part, void *user) +{ + isl_union_set **uset = (isl_union_set **)user; + + *uset = isl_union_set_add_set(*uset, FN(PART,domain)(part)); + + return isl_stat_ok; +} + +__isl_give isl_union_set *FN(UNION,domain)(__isl_take UNION *u) +{ + isl_union_set *uset; + + uset = isl_union_set_empty(FN(UNION,get_space)(u)); + if (FN(FN(UNION,foreach),PARTS)(u, &FN(UNION,domain_entry), &uset) < 0) + goto error; + + FN(UNION,free)(u); + + return uset; +error: + isl_union_set_free(uset); + FN(UNION,free)(u); + return NULL; +} + +#ifdef HAS_TYPE +/* Negate the type of "u". + */ +static __isl_give UNION *FN(UNION,negate_type)(__isl_take UNION *u) +{ + u = FN(UNION,cow)(u); + if (!u) + return NULL; + u->type = isl_fold_type_negate(u->type); + return u; +} +#else +/* Negate the type of "u". + * Since "u" does not have a type, do nothing. + */ +static __isl_give UNION *FN(UNION,negate_type)(__isl_take UNION *u) +{ + return u; +} +#endif + +/* Multiply "part" by the isl_val "user" and return the result. + */ +static __isl_give PART *FN(UNION,scale_val_entry)(__isl_take PART *part, + void *user) +{ + isl_val *v = user; + + return FN(PART,scale_val)(part, isl_val_copy(v)); +} + +/* Multiply "u" by "v" and return the result. + */ +__isl_give UNION *FN(UNION,scale_val)(__isl_take UNION *u, + __isl_take isl_val *v) +{ + if (!u || !v) + goto error; + if (isl_val_is_one(v)) { + isl_val_free(v); + return u; + } + + if (DEFAULT_IS_ZERO && u && isl_val_is_zero(v)) { + UNION *zero; + isl_space *space = FN(UNION,get_space)(u); +#ifdef HAS_TYPE + zero = FN(UNION,ZERO)(space, u->type); +#else + zero = FN(UNION,ZERO)(space); +#endif + FN(UNION,free)(u); + isl_val_free(v); + return zero; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational factor", goto error); + + u = FN(UNION,transform_inplace)(u, &FN(UNION,scale_val_entry), v); + if (isl_val_is_neg(v)) + u = FN(UNION,negate_type)(u); + + isl_val_free(v); + return u; +error: + isl_val_free(v); + FN(UNION,free)(u); + return NULL; +} + +/* Divide "part" by the isl_val "user" and return the result. + */ +static __isl_give PART *FN(UNION,scale_down_val_entry)(__isl_take PART *part, + void *user) +{ + isl_val *v = user; + + return FN(PART,scale_down_val)(part, isl_val_copy(v)); +} + +/* Divide "u" by "v" and return the result. + */ +__isl_give UNION *FN(UNION,scale_down_val)(__isl_take UNION *u, + __isl_take isl_val *v) +{ + if (!u || !v) + goto error; + if (isl_val_is_one(v)) { + isl_val_free(v); + return u; + } + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational factor", goto error); + if (isl_val_is_zero(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "cannot scale down by zero", goto error); + + u = FN(UNION,transform_inplace)(u, &FN(UNION,scale_down_val_entry), v); + if (isl_val_is_neg(v)) + u = FN(UNION,negate_type)(u); + + isl_val_free(v); + return u; +error: + isl_val_free(v); + FN(UNION,free)(u); + return NULL; +} + +S(UNION,plain_is_equal_data) +{ + UNION *u2; + isl_bool is_equal; +}; + +static isl_stat FN(UNION,plain_is_equal_entry)(void **entry, void *user) +{ + S(UNION,plain_is_equal_data) *data = user; + struct isl_hash_table_entry *entry2; + PW *pw = *entry; + + entry2 = FN(UNION,find_part_entry)(data->u2, pw->dim, 0); + if (!entry2 || entry2 == isl_hash_table_entry_none) { + if (!entry2) + data->is_equal = isl_bool_error; + else + data->is_equal = isl_bool_false; + return isl_stat_error; + } + + data->is_equal = FN(PW,plain_is_equal)(pw, entry2->data); + if (data->is_equal < 0 || !data->is_equal) + return isl_stat_error; + + return isl_stat_ok; +} + +isl_bool FN(UNION,plain_is_equal)(__isl_keep UNION *u1, __isl_keep UNION *u2) +{ + S(UNION,plain_is_equal_data) data = { NULL, isl_bool_true }; + int n1, n2; + + if (!u1 || !u2) + return isl_bool_error; + if (u1 == u2) + return isl_bool_true; + if (u1->table.n != u2->table.n) + return isl_bool_false; + n1 = FN(FN(UNION,n),PARTS)(u1); + n2 = FN(FN(UNION,n),PARTS)(u2); + if (n1 < 0 || n2 < 0) + return isl_bool_error; + if (n1 != n2) + return isl_bool_false; + + u1 = FN(UNION,copy)(u1); + u2 = FN(UNION,copy)(u2); + u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2)); + u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1)); + if (!u1 || !u2) + goto error; + + data.u2 = u2; + if (FN(UNION,foreach_inplace)(u1, + &FN(UNION,plain_is_equal_entry), &data) < 0 && + data.is_equal) + goto error; + + FN(UNION,free)(u1); + FN(UNION,free)(u2); + + return data.is_equal; +error: + FN(UNION,free)(u1); + FN(UNION,free)(u2); + return isl_bool_error; +} + +/* Check whether the element that "entry" points to involves any NaNs and + * store the result in *nan. + * Abort as soon as one such element has been found. + */ +static isl_stat FN(UNION,involves_nan_entry)(void **entry, void *user) +{ + isl_bool *nan = user; + PW *pw = *entry; + + *nan = FN(PW,involves_nan)(pw); + if (*nan < 0 || !nan) + return isl_stat_error; + + return isl_stat_ok; +} + +/* Does "u" involve any NaNs? + */ +isl_bool FN(UNION,involves_nan)(__isl_keep UNION *u) +{ + isl_bool nan = isl_bool_false; + + if (!u) + return isl_bool_error; + + if (FN(UNION,foreach_inplace)(u, + &FN(UNION,involves_nan_entry), &nan) < 0 && + !nan) + return isl_bool_error; + + return nan; +} + +/* Internal data structure for isl_union_*_drop_dims. + * type, first and n are passed to isl_*_drop_dims. + */ +S(UNION,drop_dims_data) { + enum isl_dim_type type; + unsigned first; + unsigned n; +}; + +/* Drop the parameters specified by "data" from "part" and return the result. + */ +static __isl_give PART *FN(UNION,drop_dims_entry)(__isl_take PART *part, + void *user) +{ + S(UNION,drop_dims_data) *data = user; + + return FN(PART,drop_dims)(part, data->type, data->first, data->n); +} + +/* Drop the specified parameters from "u". + * That is, type is required to be isl_dim_param. + */ +__isl_give UNION *FN(UNION,drop_dims)( __isl_take UNION *u, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_space *space; + S(UNION,drop_dims_data) data = { type, first, n }; + + if (!u) + return NULL; + + if (type != isl_dim_param) + isl_die(FN(UNION,get_ctx)(u), isl_error_invalid, + "can only project out parameters", + return FN(UNION,free)(u)); + + space = FN(UNION,get_space)(u); + space = isl_space_drop_dims(space, type, first, n); + return FN(UNION,transform_space)(u, space, &FN(UNION,drop_dims_entry), + &data); +} + +/* Internal data structure for isl_union_*_set_dim_name. + * pos is the position of the parameter that needs to be renamed. + * s is the new name. + */ +S(UNION,set_dim_name_data) { + unsigned pos; + const char *s; +}; + +/* Change the name of the parameter at position data->pos of "part" to data->s + * and return the result. + */ +static __isl_give PART *FN(UNION,set_dim_name_entry)(__isl_take PART *part, + void *user) +{ + S(UNION,set_dim_name_data) *data = user; + + return FN(PART,set_dim_name)(part, isl_dim_param, data->pos, data->s); +} + +/* Change the name of the parameter at position "pos" to "s". + * That is, type is required to be isl_dim_param. + */ +__isl_give UNION *FN(UNION,set_dim_name)(__isl_take UNION *u, + enum isl_dim_type type, unsigned pos, const char *s) +{ + S(UNION,set_dim_name_data) data = { pos, s }; + isl_space *space; + + if (!u) + return NULL; + + if (type != isl_dim_param) + isl_die(FN(UNION,get_ctx)(u), isl_error_invalid, + "can only set parameter names", + return FN(UNION,free)(u)); + + space = FN(UNION,get_space)(u); + space = isl_space_set_dim_name(space, type, pos, s); + return FN(UNION,transform_space)(u, space, + &FN(UNION,set_dim_name_entry), &data); +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the space of "part" and return the result. + */ +static __isl_give PART *FN(UNION,reset_user_entry)(__isl_take PART *part, + void *user) +{ + return FN(PART,reset_user)(part); +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the spaces of "u". + */ +__isl_give UNION *FN(UNION,reset_user)(__isl_take UNION *u) +{ + isl_space *space; + + space = FN(UNION,get_space)(u); + space = isl_space_reset_user(space); + return FN(UNION,transform_space)(u, space, &FN(UNION,reset_user_entry), + NULL); +} Index: contrib/isl/isl_val.c =================================================================== --- /dev/null +++ contrib/isl/isl_val.c @@ -0,0 +1,1693 @@ +/* + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include +#include +#include + +#undef BASE +#define BASE val + +#include + +/* Allocate an isl_val object with indeterminate value. + */ +__isl_give isl_val *isl_val_alloc(isl_ctx *ctx) +{ + isl_val *v; + + v = isl_alloc_type(ctx, struct isl_val); + if (!v) + return NULL; + + v->ctx = ctx; + isl_ctx_ref(ctx); + v->ref = 1; + isl_int_init(v->n); + isl_int_init(v->d); + + return v; +} + +/* Return a reference to an isl_val representing zero. + */ +__isl_give isl_val *isl_val_zero(isl_ctx *ctx) +{ + return isl_val_int_from_si(ctx, 0); +} + +/* Return a reference to an isl_val representing one. + */ +__isl_give isl_val *isl_val_one(isl_ctx *ctx) +{ + return isl_val_int_from_si(ctx, 1); +} + +/* Return a reference to an isl_val representing negative one. + */ +__isl_give isl_val *isl_val_negone(isl_ctx *ctx) +{ + return isl_val_int_from_si(ctx, -1); +} + +/* Return a reference to an isl_val representing NaN. + */ +__isl_give isl_val *isl_val_nan(isl_ctx *ctx) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set_si(v->n, 0); + isl_int_set_si(v->d, 0); + + return v; +} + +/* Change "v" into a NaN. + */ +__isl_give isl_val *isl_val_set_nan(__isl_take isl_val *v) +{ + if (!v) + return NULL; + if (isl_val_is_nan(v)) + return v; + v = isl_val_cow(v); + if (!v) + return NULL; + + isl_int_set_si(v->n, 0); + isl_int_set_si(v->d, 0); + + return v; +} + +/* Return a reference to an isl_val representing +infinity. + */ +__isl_give isl_val *isl_val_infty(isl_ctx *ctx) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set_si(v->n, 1); + isl_int_set_si(v->d, 0); + + return v; +} + +/* Return a reference to an isl_val representing -infinity. + */ +__isl_give isl_val *isl_val_neginfty(isl_ctx *ctx) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set_si(v->n, -1); + isl_int_set_si(v->d, 0); + + return v; +} + +/* Return a reference to an isl_val representing the integer "i". + */ +__isl_give isl_val *isl_val_int_from_si(isl_ctx *ctx, long i) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set_si(v->n, i); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Change the value of "v" to be equal to the integer "i". + */ +__isl_give isl_val *isl_val_set_si(__isl_take isl_val *v, long i) +{ + if (!v) + return NULL; + if (isl_val_is_int(v) && isl_int_cmp_si(v->n, i) == 0) + return v; + v = isl_val_cow(v); + if (!v) + return NULL; + + isl_int_set_si(v->n, i); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Change the value of "v" to be equal to zero. + */ +__isl_give isl_val *isl_val_set_zero(__isl_take isl_val *v) +{ + return isl_val_set_si(v, 0); +} + +/* Return a reference to an isl_val representing the unsigned integer "u". + */ +__isl_give isl_val *isl_val_int_from_ui(isl_ctx *ctx, unsigned long u) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set_ui(v->n, u); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Return a reference to an isl_val representing the integer "n". + */ +__isl_give isl_val *isl_val_int_from_isl_int(isl_ctx *ctx, isl_int n) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set(v->n, n); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Return a reference to an isl_val representing the rational value "n"/"d". + * Normalizing the isl_val (if needed) is left to the caller. + */ +__isl_give isl_val *isl_val_rat_from_isl_int(isl_ctx *ctx, + isl_int n, isl_int d) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set(v->n, n); + isl_int_set(v->d, d); + + return v; +} + +/* Return a new reference to "v". + */ +__isl_give isl_val *isl_val_copy(__isl_keep isl_val *v) +{ + if (!v) + return NULL; + + v->ref++; + return v; +} + +/* Return a fresh copy of "val". + */ +__isl_give isl_val *isl_val_dup(__isl_keep isl_val *val) +{ + isl_val *dup; + + if (!val) + return NULL; + + dup = isl_val_alloc(isl_val_get_ctx(val)); + if (!dup) + return NULL; + + isl_int_set(dup->n, val->n); + isl_int_set(dup->d, val->d); + + return dup; +} + +/* Return an isl_val that is equal to "val" and that has only + * a single reference. + */ +__isl_give isl_val *isl_val_cow(__isl_take isl_val *val) +{ + if (!val) + return NULL; + + if (val->ref == 1) + return val; + val->ref--; + return isl_val_dup(val); +} + +/* Free "v" and return NULL. + */ +__isl_null isl_val *isl_val_free(__isl_take isl_val *v) +{ + if (!v) + return NULL; + + if (--v->ref > 0) + return NULL; + + isl_ctx_deref(v->ctx); + isl_int_clear(v->n); + isl_int_clear(v->d); + free(v); + return NULL; +} + +/* Extract the numerator of a rational value "v" as an integer. + * + * If "v" is not a rational value, then the result is undefined. + */ +long isl_val_get_num_si(__isl_keep isl_val *v) +{ + if (!v) + return 0; + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return 0); + if (!isl_int_fits_slong(v->n)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "numerator too large", return 0); + return isl_int_get_si(v->n); +} + +/* Extract the numerator of a rational value "v" as an isl_int. + * + * If "v" is not a rational value, then the result is undefined. + */ +int isl_val_get_num_isl_int(__isl_keep isl_val *v, isl_int *n) +{ + if (!v) + return -1; + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return -1); + isl_int_set(*n, v->n); + return 0; +} + +/* Extract the denominator of a rational value "v" as an integer. + * + * If "v" is not a rational value, then the result is undefined. + */ +long isl_val_get_den_si(__isl_keep isl_val *v) +{ + if (!v) + return 0; + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return 0); + if (!isl_int_fits_slong(v->d)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "denominator too large", return 0); + return isl_int_get_si(v->d); +} + +/* Extract the denominator of a rational value "v" as an isl_val. + * + * If "v" is not a rational value, then the result is undefined. + */ +__isl_give isl_val *isl_val_get_den_val(__isl_keep isl_val *v) +{ + if (!v) + return NULL; + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return NULL); + return isl_val_int_from_isl_int(isl_val_get_ctx(v), v->d); +} + +/* Return an approximation of "v" as a double. + */ +double isl_val_get_d(__isl_keep isl_val *v) +{ + if (!v) + return 0; + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return 0); + return isl_int_get_d(v->n) / isl_int_get_d(v->d); +} + +/* Return the isl_ctx to which "val" belongs. + */ +isl_ctx *isl_val_get_ctx(__isl_keep isl_val *val) +{ + return val ? val->ctx : NULL; +} + +/* Return a hash value that digests "val". + */ +uint32_t isl_val_get_hash(__isl_keep isl_val *val) +{ + uint32_t hash; + + if (!val) + return 0; + + hash = isl_hash_init(); + hash = isl_int_hash(val->n, hash); + hash = isl_int_hash(val->d, hash); + + return hash; +} + +/* Normalize "v". + * + * In particular, make sure that the denominator of a rational value + * is positive and the numerator and denominator do not have any + * common divisors. + * + * This function should not be called by an external user + * since it will only be given normalized values. + */ +__isl_give isl_val *isl_val_normalize(__isl_take isl_val *v) +{ + isl_ctx *ctx; + + if (!v) + return NULL; + if (isl_val_is_int(v)) + return v; + if (!isl_val_is_rat(v)) + return v; + if (isl_int_is_neg(v->d)) { + isl_int_neg(v->d, v->d); + isl_int_neg(v->n, v->n); + } + ctx = isl_val_get_ctx(v); + isl_int_gcd(ctx->normalize_gcd, v->n, v->d); + if (isl_int_is_one(ctx->normalize_gcd)) + return v; + isl_int_divexact(v->n, v->n, ctx->normalize_gcd); + isl_int_divexact(v->d, v->d, ctx->normalize_gcd); + return v; +} + +/* Return the opposite of "v". + */ +__isl_give isl_val *isl_val_neg(__isl_take isl_val *v) +{ + if (!v) + return NULL; + if (isl_val_is_nan(v)) + return v; + if (isl_val_is_zero(v)) + return v; + + v = isl_val_cow(v); + if (!v) + return NULL; + isl_int_neg(v->n, v->n); + + return v; +} + +/* Return the inverse of "v". + */ +__isl_give isl_val *isl_val_inv(__isl_take isl_val *v) +{ + if (!v) + return NULL; + if (isl_val_is_nan(v)) + return v; + if (isl_val_is_zero(v)) { + isl_ctx *ctx = isl_val_get_ctx(v); + isl_val_free(v); + return isl_val_nan(ctx); + } + if (isl_val_is_infty(v) || isl_val_is_neginfty(v)) { + isl_ctx *ctx = isl_val_get_ctx(v); + isl_val_free(v); + return isl_val_zero(ctx); + } + + v = isl_val_cow(v); + if (!v) + return NULL; + isl_int_swap(v->n, v->d); + + return isl_val_normalize(v); +} + +/* Return the absolute value of "v". + */ +__isl_give isl_val *isl_val_abs(__isl_take isl_val *v) +{ + if (!v) + return NULL; + if (isl_val_is_nan(v)) + return v; + if (isl_val_is_nonneg(v)) + return v; + return isl_val_neg(v); +} + +/* Return the "floor" (greatest integer part) of "v". + * That is, return the result of rounding towards -infinity. + */ +__isl_give isl_val *isl_val_floor(__isl_take isl_val *v) +{ + if (!v) + return NULL; + if (isl_val_is_int(v)) + return v; + if (!isl_val_is_rat(v)) + return v; + + v = isl_val_cow(v); + if (!v) + return NULL; + isl_int_fdiv_q(v->n, v->n, v->d); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Return the "ceiling" of "v". + * That is, return the result of rounding towards +infinity. + */ +__isl_give isl_val *isl_val_ceil(__isl_take isl_val *v) +{ + if (!v) + return NULL; + if (isl_val_is_int(v)) + return v; + if (!isl_val_is_rat(v)) + return v; + + v = isl_val_cow(v); + if (!v) + return NULL; + isl_int_cdiv_q(v->n, v->n, v->d); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Truncate "v". + * That is, return the result of rounding towards zero. + */ +__isl_give isl_val *isl_val_trunc(__isl_take isl_val *v) +{ + if (!v) + return NULL; + if (isl_val_is_int(v)) + return v; + if (!isl_val_is_rat(v)) + return v; + + v = isl_val_cow(v); + if (!v) + return NULL; + isl_int_tdiv_q(v->n, v->n, v->d); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Return 2^v, where v is an integer (that is not too large). + */ +__isl_give isl_val *isl_val_2exp(__isl_take isl_val *v) +{ + unsigned long exp; + int neg; + + v = isl_val_cow(v); + if (!v) + return NULL; + if (!isl_val_is_int(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "can only compute integer powers", + return isl_val_free(v)); + neg = isl_val_is_neg(v); + if (neg) + isl_int_neg(v->n, v->n); + if (!isl_int_fits_ulong(v->n)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "exponent too large", return isl_val_free(v)); + exp = isl_int_get_ui(v->n); + if (neg) { + isl_int_mul_2exp(v->d, v->d, exp); + isl_int_set_si(v->n, 1); + } else { + isl_int_mul_2exp(v->n, v->d, exp); + } + + return v; +} + +/* Return the minimum of "v1" and "v2". + */ +__isl_give isl_val *isl_val_min(__isl_take isl_val *v1, __isl_take isl_val *v2) +{ + if (!v1 || !v2) + goto error; + + if (isl_val_is_nan(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_nan(v2)) { + isl_val_free(v1); + return v2; + } + if (isl_val_le(v1, v2)) { + isl_val_free(v2); + return v1; + } else { + isl_val_free(v1); + return v2; + } +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Return the maximum of "v1" and "v2". + */ +__isl_give isl_val *isl_val_max(__isl_take isl_val *v1, __isl_take isl_val *v2) +{ + if (!v1 || !v2) + goto error; + + if (isl_val_is_nan(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_nan(v2)) { + isl_val_free(v1); + return v2; + } + if (isl_val_ge(v1, v2)) { + isl_val_free(v2); + return v1; + } else { + isl_val_free(v1); + return v2; + } +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Return the sum of "v1" and "v2". + */ +__isl_give isl_val *isl_val_add(__isl_take isl_val *v1, __isl_take isl_val *v2) +{ + if (!v1 || !v2) + goto error; + if (isl_val_is_nan(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_nan(v2)) { + isl_val_free(v1); + return v2; + } + if ((isl_val_is_infty(v1) && isl_val_is_neginfty(v2)) || + (isl_val_is_neginfty(v1) && isl_val_is_infty(v2))) { + isl_val_free(v2); + return isl_val_set_nan(v1); + } + if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_infty(v2) || isl_val_is_neginfty(v2)) { + isl_val_free(v1); + return v2; + } + if (isl_val_is_zero(v1)) { + isl_val_free(v1); + return v2; + } + if (isl_val_is_zero(v2)) { + isl_val_free(v2); + return v1; + } + + v1 = isl_val_cow(v1); + if (!v1) + goto error; + if (isl_val_is_int(v1) && isl_val_is_int(v2)) + isl_int_add(v1->n, v1->n, v2->n); + else { + if (isl_int_eq(v1->d, v2->d)) + isl_int_add(v1->n, v1->n, v2->n); + else { + isl_int_mul(v1->n, v1->n, v2->d); + isl_int_addmul(v1->n, v2->n, v1->d); + isl_int_mul(v1->d, v1->d, v2->d); + } + v1 = isl_val_normalize(v1); + } + isl_val_free(v2); + return v1; +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Return the sum of "v1" and "v2". + */ +__isl_give isl_val *isl_val_add_ui(__isl_take isl_val *v1, unsigned long v2) +{ + if (!v1) + return NULL; + if (!isl_val_is_rat(v1)) + return v1; + if (v2 == 0) + return v1; + v1 = isl_val_cow(v1); + if (!v1) + return NULL; + + isl_int_addmul_ui(v1->n, v1->d, v2); + + return v1; +} + +/* Subtract "v2" from "v1". + */ +__isl_give isl_val *isl_val_sub(__isl_take isl_val *v1, __isl_take isl_val *v2) +{ + if (!v1 || !v2) + goto error; + if (isl_val_is_nan(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_nan(v2)) { + isl_val_free(v1); + return v2; + } + if ((isl_val_is_infty(v1) && isl_val_is_infty(v2)) || + (isl_val_is_neginfty(v1) && isl_val_is_neginfty(v2))) { + isl_val_free(v2); + return isl_val_set_nan(v1); + } + if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_infty(v2) || isl_val_is_neginfty(v2)) { + isl_val_free(v1); + return isl_val_neg(v2); + } + if (isl_val_is_zero(v2)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_zero(v1)) { + isl_val_free(v1); + return isl_val_neg(v2); + } + + v1 = isl_val_cow(v1); + if (!v1) + goto error; + if (isl_val_is_int(v1) && isl_val_is_int(v2)) + isl_int_sub(v1->n, v1->n, v2->n); + else { + if (isl_int_eq(v1->d, v2->d)) + isl_int_sub(v1->n, v1->n, v2->n); + else { + isl_int_mul(v1->n, v1->n, v2->d); + isl_int_submul(v1->n, v2->n, v1->d); + isl_int_mul(v1->d, v1->d, v2->d); + } + v1 = isl_val_normalize(v1); + } + isl_val_free(v2); + return v1; +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Subtract "v2" from "v1". + */ +__isl_give isl_val *isl_val_sub_ui(__isl_take isl_val *v1, unsigned long v2) +{ + if (!v1) + return NULL; + if (!isl_val_is_rat(v1)) + return v1; + if (v2 == 0) + return v1; + v1 = isl_val_cow(v1); + if (!v1) + return NULL; + + isl_int_submul_ui(v1->n, v1->d, v2); + + return v1; +} + +/* Return the product of "v1" and "v2". + */ +__isl_give isl_val *isl_val_mul(__isl_take isl_val *v1, __isl_take isl_val *v2) +{ + if (!v1 || !v2) + goto error; + if (isl_val_is_nan(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_nan(v2)) { + isl_val_free(v1); + return v2; + } + if ((!isl_val_is_rat(v1) && isl_val_is_zero(v2)) || + (isl_val_is_zero(v1) && !isl_val_is_rat(v2))) { + isl_val_free(v2); + return isl_val_set_nan(v1); + } + if (isl_val_is_zero(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_zero(v2)) { + isl_val_free(v1); + return v2; + } + if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) { + if (isl_val_is_neg(v2)) + v1 = isl_val_neg(v1); + isl_val_free(v2); + return v1; + } + if (isl_val_is_infty(v2) || isl_val_is_neginfty(v2)) { + if (isl_val_is_neg(v1)) + v2 = isl_val_neg(v2); + isl_val_free(v1); + return v2; + } + + v1 = isl_val_cow(v1); + if (!v1) + goto error; + if (isl_val_is_int(v1) && isl_val_is_int(v2)) + isl_int_mul(v1->n, v1->n, v2->n); + else { + isl_int_mul(v1->n, v1->n, v2->n); + isl_int_mul(v1->d, v1->d, v2->d); + v1 = isl_val_normalize(v1); + } + isl_val_free(v2); + return v1; +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Return the product of "v1" and "v2". + * + * This is a private copy of isl_val_mul for use in the generic + * isl_multi_*_scale_val instantiated for isl_val. + */ +__isl_give isl_val *isl_val_scale_val(__isl_take isl_val *v1, + __isl_take isl_val *v2) +{ + return isl_val_mul(v1, v2); +} + +/* Return the product of "v1" and "v2". + */ +__isl_give isl_val *isl_val_mul_ui(__isl_take isl_val *v1, unsigned long v2) +{ + if (!v1) + return NULL; + if (isl_val_is_nan(v1)) + return v1; + if (!isl_val_is_rat(v1)) { + if (v2 == 0) + v1 = isl_val_set_nan(v1); + return v1; + } + if (v2 == 1) + return v1; + v1 = isl_val_cow(v1); + if (!v1) + return NULL; + + isl_int_mul_ui(v1->n, v1->n, v2); + + return isl_val_normalize(v1); +} + +/* Divide "v1" by "v2". + */ +__isl_give isl_val *isl_val_div(__isl_take isl_val *v1, __isl_take isl_val *v2) +{ + if (!v1 || !v2) + goto error; + if (isl_val_is_nan(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_nan(v2)) { + isl_val_free(v1); + return v2; + } + if (isl_val_is_zero(v2) || + (!isl_val_is_rat(v1) && !isl_val_is_rat(v2))) { + isl_val_free(v2); + return isl_val_set_nan(v1); + } + if (isl_val_is_zero(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) { + if (isl_val_is_neg(v2)) + v1 = isl_val_neg(v1); + isl_val_free(v2); + return v1; + } + if (isl_val_is_infty(v2) || isl_val_is_neginfty(v2)) { + isl_val_free(v2); + return isl_val_set_zero(v1); + } + + v1 = isl_val_cow(v1); + if (!v1) + goto error; + if (isl_val_is_int(v2)) { + isl_int_mul(v1->d, v1->d, v2->n); + v1 = isl_val_normalize(v1); + } else { + isl_int_mul(v1->d, v1->d, v2->n); + isl_int_mul(v1->n, v1->n, v2->d); + v1 = isl_val_normalize(v1); + } + isl_val_free(v2); + return v1; +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Divide "v1" by "v2". + */ +__isl_give isl_val *isl_val_div_ui(__isl_take isl_val *v1, unsigned long v2) +{ + if (!v1) + return NULL; + if (isl_val_is_nan(v1)) + return v1; + if (v2 == 0) + return isl_val_set_nan(v1); + if (v2 == 1) + return v1; + if (isl_val_is_zero(v1)) + return v1; + if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) + return v1; + v1 = isl_val_cow(v1); + if (!v1) + return NULL; + + isl_int_mul_ui(v1->d, v1->d, v2); + + return isl_val_normalize(v1); +} + +/* Divide "v1" by "v2". + * + * This is a private copy of isl_val_div for use in the generic + * isl_multi_*_scale_down_val instantiated for isl_val. + */ +__isl_give isl_val *isl_val_scale_down_val(__isl_take isl_val *v1, + __isl_take isl_val *v2) +{ + return isl_val_div(v1, v2); +} + +/* Given two integer values "v1" and "v2", check if "v1" is divisible by "v2". + */ +isl_bool isl_val_is_divisible_by(__isl_keep isl_val *v1, __isl_keep isl_val *v2) +{ + if (!v1 || !v2) + return isl_bool_error; + + if (!isl_val_is_int(v1) || !isl_val_is_int(v2)) + isl_die(isl_val_get_ctx(v1), isl_error_invalid, + "expecting two integers", return isl_bool_error); + + return isl_int_is_divisible_by(v1->n, v2->n); +} + +/* Given two integer values "v1" and "v2", return the residue of "v1" + * modulo "v2". + */ +__isl_give isl_val *isl_val_mod(__isl_take isl_val *v1, __isl_take isl_val *v2) +{ + if (!v1 || !v2) + goto error; + if (!isl_val_is_int(v1) || !isl_val_is_int(v2)) + isl_die(isl_val_get_ctx(v1), isl_error_invalid, + "expecting two integers", goto error); + if (isl_val_is_nonneg(v1) && isl_val_lt(v1, v2)) { + isl_val_free(v2); + return v1; + } + v1 = isl_val_cow(v1); + if (!v1) + goto error; + isl_int_fdiv_r(v1->n, v1->n, v2->n); + isl_val_free(v2); + return v1; +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Given two integer values "v1" and "v2", return the residue of "v1" + * modulo "v2". + * + * This is a private copy of isl_val_mod for use in the generic + * isl_multi_*_mod_multi_val instantiated for isl_val. + */ +__isl_give isl_val *isl_val_mod_val(__isl_take isl_val *v1, + __isl_take isl_val *v2) +{ + return isl_val_mod(v1, v2); +} + +/* Given two integer values, return their greatest common divisor. + */ +__isl_give isl_val *isl_val_gcd(__isl_take isl_val *v1, __isl_take isl_val *v2) +{ + if (!v1 || !v2) + goto error; + if (!isl_val_is_int(v1) || !isl_val_is_int(v2)) + isl_die(isl_val_get_ctx(v1), isl_error_invalid, + "expecting two integers", goto error); + if (isl_val_eq(v1, v2)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_one(v1)) { + isl_val_free(v2); + return v1; + } + if (isl_val_is_one(v2)) { + isl_val_free(v1); + return v2; + } + v1 = isl_val_cow(v1); + if (!v1) + goto error; + isl_int_gcd(v1->n, v1->n, v2->n); + isl_val_free(v2); + return v1; +error: + isl_val_free(v1); + isl_val_free(v2); + return NULL; +} + +/* Compute x, y and g such that g = gcd(a,b) and a*x+b*y = g. + */ +static void isl_int_gcdext(isl_int *g, isl_int *x, isl_int *y, + isl_int a, isl_int b) +{ + isl_int d, tmp; + isl_int a_copy, b_copy; + + isl_int_init(a_copy); + isl_int_init(b_copy); + isl_int_init(d); + isl_int_init(tmp); + isl_int_set(a_copy, a); + isl_int_set(b_copy, b); + isl_int_abs(*g, a_copy); + isl_int_abs(d, b_copy); + isl_int_set_si(*x, 1); + isl_int_set_si(*y, 0); + while (isl_int_is_pos(d)) { + isl_int_fdiv_q(tmp, *g, d); + isl_int_submul(*x, tmp, *y); + isl_int_submul(*g, tmp, d); + isl_int_swap(*g, d); + isl_int_swap(*x, *y); + } + if (isl_int_is_zero(a_copy)) + isl_int_set_si(*x, 0); + else if (isl_int_is_neg(a_copy)) + isl_int_neg(*x, *x); + if (isl_int_is_zero(b_copy)) + isl_int_set_si(*y, 0); + else { + isl_int_mul(tmp, a_copy, *x); + isl_int_sub(tmp, *g, tmp); + isl_int_divexact(*y, tmp, b_copy); + } + isl_int_clear(d); + isl_int_clear(tmp); + isl_int_clear(a_copy); + isl_int_clear(b_copy); +} + +/* Given two integer values v1 and v2, return their greatest common divisor g, + * as well as two integers x and y such that x * v1 + y * v2 = g. + */ +__isl_give isl_val *isl_val_gcdext(__isl_take isl_val *v1, + __isl_take isl_val *v2, __isl_give isl_val **x, __isl_give isl_val **y) +{ + isl_ctx *ctx; + isl_val *a = NULL, *b = NULL; + + if (!x && !y) + return isl_val_gcd(v1, v2); + + if (!v1 || !v2) + goto error; + + ctx = isl_val_get_ctx(v1); + if (!isl_val_is_int(v1) || !isl_val_is_int(v2)) + isl_die(ctx, isl_error_invalid, + "expecting two integers", goto error); + + v1 = isl_val_cow(v1); + a = isl_val_alloc(ctx); + b = isl_val_alloc(ctx); + if (!v1 || !a || !b) + goto error; + isl_int_gcdext(&v1->n, &a->n, &b->n, v1->n, v2->n); + if (x) { + isl_int_set_si(a->d, 1); + *x = a; + } else + isl_val_free(a); + if (y) { + isl_int_set_si(b->d, 1); + *y = b; + } else + isl_val_free(b); + isl_val_free(v2); + return v1; +error: + isl_val_free(v1); + isl_val_free(v2); + isl_val_free(a); + isl_val_free(b); + if (x) + *x = NULL; + if (y) + *y = NULL; + return NULL; +} + +/* Does "v" represent an integer value? + */ +isl_bool isl_val_is_int(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return isl_int_is_one(v->d); +} + +/* Does "v" represent a rational value? + */ +isl_bool isl_val_is_rat(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return !isl_int_is_zero(v->d); +} + +/* Does "v" represent NaN? + */ +isl_bool isl_val_is_nan(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return isl_int_is_zero(v->n) && isl_int_is_zero(v->d); +} + +/* Does "v" represent +infinity? + */ +isl_bool isl_val_is_infty(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return isl_int_is_pos(v->n) && isl_int_is_zero(v->d); +} + +/* Does "v" represent -infinity? + */ +isl_bool isl_val_is_neginfty(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return isl_int_is_neg(v->n) && isl_int_is_zero(v->d); +} + +/* Does "v" represent the integer zero? + */ +isl_bool isl_val_is_zero(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return isl_int_is_zero(v->n) && !isl_int_is_zero(v->d); +} + +/* Does "v" represent the integer one? + */ +isl_bool isl_val_is_one(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + if (isl_val_is_nan(v)) + return isl_bool_false; + + return isl_int_eq(v->n, v->d); +} + +/* Does "v" represent the integer negative one? + */ +isl_bool isl_val_is_negone(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return isl_int_is_neg(v->n) && isl_int_abs_eq(v->n, v->d); +} + +/* Is "v" (strictly) positive? + */ +isl_bool isl_val_is_pos(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return isl_int_is_pos(v->n); +} + +/* Is "v" (strictly) negative? + */ +isl_bool isl_val_is_neg(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + return isl_int_is_neg(v->n); +} + +/* Is "v" non-negative? + */ +isl_bool isl_val_is_nonneg(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + if (isl_val_is_nan(v)) + return isl_bool_false; + + return isl_int_is_nonneg(v->n); +} + +/* Is "v" non-positive? + */ +isl_bool isl_val_is_nonpos(__isl_keep isl_val *v) +{ + if (!v) + return isl_bool_error; + + if (isl_val_is_nan(v)) + return isl_bool_false; + + return isl_int_is_nonpos(v->n); +} + +/* Return the sign of "v". + * + * The sign of NaN is undefined. + */ +int isl_val_sgn(__isl_keep isl_val *v) +{ + if (!v) + return 0; + if (isl_val_is_zero(v)) + return 0; + if (isl_val_is_pos(v)) + return 1; + return -1; +} + +/* Is "v1" (strictly) less than "v2"? + */ +isl_bool isl_val_lt(__isl_keep isl_val *v1, __isl_keep isl_val *v2) +{ + isl_int t; + isl_bool lt; + + if (!v1 || !v2) + return isl_bool_error; + if (isl_val_is_int(v1) && isl_val_is_int(v2)) + return isl_int_lt(v1->n, v2->n); + if (isl_val_is_nan(v1) || isl_val_is_nan(v2)) + return isl_bool_false; + if (isl_val_eq(v1, v2)) + return isl_bool_false; + if (isl_val_is_infty(v2)) + return isl_bool_true; + if (isl_val_is_infty(v1)) + return isl_bool_false; + if (isl_val_is_neginfty(v1)) + return isl_bool_true; + if (isl_val_is_neginfty(v2)) + return isl_bool_false; + + isl_int_init(t); + isl_int_mul(t, v1->n, v2->d); + isl_int_submul(t, v2->n, v1->d); + lt = isl_int_is_neg(t); + isl_int_clear(t); + + return lt; +} + +/* Is "v1" (strictly) greater than "v2"? + */ +isl_bool isl_val_gt(__isl_keep isl_val *v1, __isl_keep isl_val *v2) +{ + return isl_val_lt(v2, v1); +} + +/* Is "v1" less than or equal to "v2"? + */ +isl_bool isl_val_le(__isl_keep isl_val *v1, __isl_keep isl_val *v2) +{ + isl_int t; + isl_bool le; + + if (!v1 || !v2) + return isl_bool_error; + if (isl_val_is_int(v1) && isl_val_is_int(v2)) + return isl_int_le(v1->n, v2->n); + if (isl_val_is_nan(v1) || isl_val_is_nan(v2)) + return isl_bool_false; + if (isl_val_eq(v1, v2)) + return isl_bool_true; + if (isl_val_is_infty(v2)) + return isl_bool_true; + if (isl_val_is_infty(v1)) + return isl_bool_false; + if (isl_val_is_neginfty(v1)) + return isl_bool_true; + if (isl_val_is_neginfty(v2)) + return isl_bool_false; + + isl_int_init(t); + isl_int_mul(t, v1->n, v2->d); + isl_int_submul(t, v2->n, v1->d); + le = isl_int_is_nonpos(t); + isl_int_clear(t); + + return le; +} + +/* Is "v1" greater than or equal to "v2"? + */ +isl_bool isl_val_ge(__isl_keep isl_val *v1, __isl_keep isl_val *v2) +{ + return isl_val_le(v2, v1); +} + +/* How does "v" compare to "i"? + * + * Return 1 if v is greater, -1 if v is smaller and 0 if v is equal to i. + * + * If v is NaN (or NULL), then the result is undefined. + */ +int isl_val_cmp_si(__isl_keep isl_val *v, long i) +{ + isl_int t; + int cmp; + + if (!v) + return 0; + if (isl_val_is_int(v)) + return isl_int_cmp_si(v->n, i); + if (isl_val_is_nan(v)) + return 0; + if (isl_val_is_infty(v)) + return 1; + if (isl_val_is_neginfty(v)) + return -1; + + isl_int_init(t); + isl_int_mul_si(t, v->d, i); + isl_int_sub(t, v->n, t); + cmp = isl_int_sgn(t); + isl_int_clear(t); + + return cmp; +} + +/* Is "v1" equal to "v2"? + */ +isl_bool isl_val_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2) +{ + if (!v1 || !v2) + return isl_bool_error; + if (isl_val_is_nan(v1) || isl_val_is_nan(v2)) + return isl_bool_false; + + return isl_int_eq(v1->n, v2->n) && isl_int_eq(v1->d, v2->d); +} + +/* Is "v1" equal to "v2" in absolute value? + */ +isl_bool isl_val_abs_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2) +{ + if (!v1 || !v2) + return isl_bool_error; + if (isl_val_is_nan(v1) || isl_val_is_nan(v2)) + return isl_bool_false; + + return isl_int_abs_eq(v1->n, v2->n) && isl_int_eq(v1->d, v2->d); +} + +/* Is "v1" different from "v2"? + */ +isl_bool isl_val_ne(__isl_keep isl_val *v1, __isl_keep isl_val *v2) +{ + if (!v1 || !v2) + return isl_bool_error; + if (isl_val_is_nan(v1) || isl_val_is_nan(v2)) + return isl_bool_false; + + return isl_int_ne(v1->n, v2->n) || isl_int_ne(v1->d, v2->d); +} + +/* Print a textual representation of "v" onto "p". + */ +__isl_give isl_printer *isl_printer_print_val(__isl_take isl_printer *p, + __isl_keep isl_val *v) +{ + int neg; + + if (!p || !v) + return isl_printer_free(p); + + neg = isl_int_is_neg(v->n); + if (neg) { + p = isl_printer_print_str(p, "-"); + isl_int_neg(v->n, v->n); + } + if (isl_int_is_zero(v->d)) { + int sgn = isl_int_sgn(v->n); + p = isl_printer_print_str(p, sgn < 0 ? "-infty" : + sgn == 0 ? "NaN" : "infty"); + } else + p = isl_printer_print_isl_int(p, v->n); + if (neg) + isl_int_neg(v->n, v->n); + if (!isl_int_is_zero(v->d) && !isl_int_is_one(v->d)) { + p = isl_printer_print_str(p, "/"); + p = isl_printer_print_isl_int(p, v->d); + } + + return p; +} + +/* Is "val1" (obviously) equal to "val2"? + * + * This is a private copy of isl_val_eq for use in the generic + * isl_multi_*_plain_is_equal instantiated for isl_val. + */ +int isl_val_plain_is_equal(__isl_keep isl_val *val1, __isl_keep isl_val *val2) +{ + return isl_val_eq(val1, val2); +} + +/* Does "v" have any non-zero coefficients + * for any dimension in the given range? + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have any coefficients, this function + * always return 0. + */ +int isl_val_involves_dims(__isl_keep isl_val *v, enum isl_dim_type type, + unsigned first, unsigned n) +{ + if (!v) + return -1; + + return 0; +} + +/* Insert "n" dimensions of type "type" at position "first". + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * does not do anything. + */ +__isl_give isl_val *isl_val_insert_dims(__isl_take isl_val *v, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return v; +} + +/* Drop the "n" first dimensions of type "type" at position "first". + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * does not do anything. + */ +__isl_give isl_val *isl_val_drop_dims(__isl_take isl_val *v, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return v; +} + +/* Change the name of the dimension of type "type" at position "pos" to "s". + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * does not do anything. + */ +__isl_give isl_val *isl_val_set_dim_name(__isl_take isl_val *v, + enum isl_dim_type type, unsigned pos, const char *s) +{ + return v; +} + +/* Return the space of "v". + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. The conditions surrounding the call to this function make sure + * that this function will never actually get called. We return a valid + * space anyway, just in case. + */ +__isl_give isl_space *isl_val_get_space(__isl_keep isl_val *v) +{ + if (!v) + return NULL; + + return isl_space_params_alloc(isl_val_get_ctx(v), 0); +} + +/* Reset the domain space of "v" to "space". + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * does not do anything, apart from error handling and cleaning up memory. + */ +__isl_give isl_val *isl_val_reset_domain_space(__isl_take isl_val *v, + __isl_take isl_space *space) +{ + if (!space) + return isl_val_free(v); + isl_space_free(space); + return v; +} + +/* Align the parameters of "v" to those of "space". + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * does not do anything, apart from error handling and cleaning up memory. + * Note that the conditions surrounding the call to this function make sure + * that this function will never actually get called. + */ +__isl_give isl_val *isl_val_align_params(__isl_take isl_val *v, + __isl_take isl_space *space) +{ + if (!space) + return isl_val_free(v); + isl_space_free(space); + return v; +} + +/* Reorder the dimensions of the domain of "v" according + * to the given reordering. + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * does not do anything, apart from error handling and cleaning up memory. + */ +__isl_give isl_val *isl_val_realign_domain(__isl_take isl_val *v, + __isl_take isl_reordering *r) +{ + if (!r) + return isl_val_free(v); + isl_reordering_free(r); + return v; +} + +/* Return an isl_val that is zero on "ls". + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * simply returns a zero isl_val in the same context as "ls". + */ +__isl_give isl_val *isl_val_zero_on_domain(__isl_take isl_local_space *ls) +{ + isl_ctx *ctx; + + if (!ls) + return NULL; + ctx = isl_local_space_get_ctx(ls); + isl_local_space_free(ls); + return isl_val_zero(ctx); +} + +/* Do the parameters of "v" match those of "space"? + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * simply returns true, except if "v" or "space" are NULL. + */ +isl_bool isl_val_matching_params(__isl_keep isl_val *v, + __isl_keep isl_space *space) +{ + if (!v || !space) + return isl_bool_error; + return isl_bool_true; +} + +/* Check that the domain space of "v" matches "space". + * + * This function is only meant to be used in the generic isl_multi_* + * functions which have to deal with base objects that have an associated + * space. Since an isl_val does not have an associated space, this function + * simply returns 0, except if "v" or "space" are NULL. + */ +isl_stat isl_val_check_match_domain_space(__isl_keep isl_val *v, + __isl_keep isl_space *space) +{ + if (!v || !space) + return isl_stat_error; + return isl_stat_ok; +} + +#define isl_val_involves_nan isl_val_is_nan + +#undef BASE +#define BASE val + +#define NO_DOMAIN +#define NO_IDENTITY +#define NO_FROM_BASE +#define NO_MOVE_DIMS +#include + +/* Apply "fn" to each of the elements of "mv" with as second argument "v". + */ +static __isl_give isl_multi_val *isl_multi_val_fn_val( + __isl_take isl_multi_val *mv, + __isl_give isl_val *(*fn)(__isl_take isl_val *v1, + __isl_take isl_val *v2), + __isl_take isl_val *v) +{ + int i; + + mv = isl_multi_val_cow(mv); + if (!mv || !v) + goto error; + + for (i = 0; i < mv->n; ++i) { + mv->p[i] = fn(mv->p[i], isl_val_copy(v)); + if (!mv->p[i]) + goto error; + } + + isl_val_free(v); + return mv; +error: + isl_val_free(v); + isl_multi_val_free(mv); + return NULL; +} + +/* Add "v" to each of the elements of "mv". + */ +__isl_give isl_multi_val *isl_multi_val_add_val(__isl_take isl_multi_val *mv, + __isl_take isl_val *v) +{ + if (!v) + return isl_multi_val_free(mv); + if (isl_val_is_zero(v)) { + isl_val_free(v); + return mv; + } + return isl_multi_val_fn_val(mv, &isl_val_add, v); +} + +/* Reduce the elements of "mv" modulo "v". + */ +__isl_give isl_multi_val *isl_multi_val_mod_val(__isl_take isl_multi_val *mv, + __isl_take isl_val *v) +{ + return isl_multi_val_fn_val(mv, &isl_val_mod, v); +} Index: contrib/isl/isl_val_gmp.c =================================================================== --- /dev/null +++ contrib/isl/isl_val_gmp.c @@ -0,0 +1,128 @@ +#include +#include +#include + +/* Return a reference to an isl_val representing the integer "z". + */ +__isl_give isl_val *isl_val_int_from_gmp(isl_ctx *ctx, mpz_t z) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set(v->n, z); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Return a reference to an isl_val representing the rational value "n"/"d". + */ +__isl_give isl_val *isl_val_from_gmp(isl_ctx *ctx, const mpz_t n, const mpz_t d) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + isl_int_set(v->n, n); + isl_int_set(v->d, d); + + return isl_val_normalize(v); +} + +/* Extract the numerator of a rational value "v" in "z". + * + * If "v" is not a rational value, then the result is undefined. + */ +int isl_val_get_num_gmp(__isl_keep isl_val *v, mpz_t z) +{ + if (!v) + return -1; + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return -1); + mpz_set(z, v->n); + return 0; +} + +/* Extract the denominator of a rational value "v" in "z". + * + * If "v" is not a rational value, then the result is undefined. + */ +int isl_val_get_den_gmp(__isl_keep isl_val *v, mpz_t z) +{ + if (!v) + return -1; + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return -1); + mpz_set(z, v->d); + return 0; +} + +/* Return a reference to an isl_val representing the unsigned + * integer value stored in the "n" chunks of size "size" at "chunks". + * The least significant chunk is assumed to be stored first. + */ +__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, size_t n, + size_t size, const void *chunks) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + mpz_import(v->n, n, -1, size, 0, 0, chunks); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Return the number of chunks of size "size" required to + * store the absolute value of the numerator of "v". + */ +size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, size_t size) +{ + if (!v) + return 0; + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return 0); + + size *= 8; + return (mpz_sizeinbase(v->n, 2) + size - 1) / size; +} + +/* Store a representation of the absolute value of the numerator of "v" + * in terms of chunks of size "size" at "chunks". + * The least significant chunk is stored first. + * The number of chunks in the result can be obtained by calling + * isl_val_n_abs_num_chunks. The user is responsible for allocating + * enough memory to store the results. + * + * In the special case of a zero value, isl_val_n_abs_num_chunks will + * return one, while mpz_export will not fill in any chunks. We therefore + * do it ourselves. + */ +int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, size_t size, + void *chunks) +{ + if (!v || !chunks) + return -1; + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return -1); + + mpz_export(chunks, NULL, -1, size, 0, 0, v->n); + if (isl_val_is_zero(v)) + memset(chunks, 0, size); + + return 0; +} Index: contrib/isl/isl_val_imath.c =================================================================== --- /dev/null +++ contrib/isl/isl_val_imath.c @@ -0,0 +1,64 @@ +#include + +/* Return a reference to an isl_val representing the unsigned + * integer value stored in the "n" chunks of size "size" at "chunks". + * The least significant chunk is assumed to be stored first. + */ +__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, size_t n, + size_t size, const void *chunks) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + impz_import(v->n, n, -1, size, 0, 0, chunks); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Store a representation of the absolute value of the numerator of "v" + * in terms of chunks of size "size" at "chunks". + * The least significant chunk is stored first. + * The number of chunks in the result can be obtained by calling + * isl_val_n_abs_num_chunks. The user is responsible for allocating + * enough memory to store the results. + * + * In the special case of a zero value, isl_val_n_abs_num_chunks will + * return one, while impz_export will not fill in any chunks. We therefore + * do it ourselves. + */ +int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, size_t size, + void *chunks) +{ + if (!v || !chunks) + return -1; + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return -1); + + impz_export(chunks, NULL, -1, size, 0, 0, v->n); + if (isl_val_is_zero(v)) + memset(chunks, 0, size); + + return 0; +} + +/* Return the number of chunks of size "size" required to + * store the absolute value of the numerator of "v". + */ +size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, size_t size) +{ + if (!v) + return 0; + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return 0); + + size *= 8; + return (impz_sizeinbase(v->n, 2) + size - 1) / size; +} Index: contrib/isl/isl_val_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_val_private.h @@ -0,0 +1,75 @@ +#ifndef ISL_VAL_PRIVATE_H +#define ISL_VAL_PRIVATE_H + +#include +#include +#include +#include + +/* Represents a "value", which may be an integer value, a rational value, + * plus or minus infinity or "not a number". + * + * Internally, +infinity is represented as 1/0, + * -infinity as -1/0 and NaN as 0/0. + * + * A rational value is always normalized before it is passed to the user. + */ +struct isl_val { + int ref; + isl_ctx *ctx; + + isl_int n; + isl_int d; +}; + +#undef EL +#define EL isl_val + +#include + +__isl_give isl_val *isl_val_alloc(isl_ctx *ctx); +__isl_give isl_val *isl_val_normalize(__isl_take isl_val *v); +__isl_give isl_val *isl_val_int_from_isl_int(isl_ctx *ctx, isl_int n); +__isl_give isl_val *isl_val_rat_from_isl_int(isl_ctx *ctx, + isl_int n, isl_int d); +__isl_give isl_val *isl_val_cow(__isl_take isl_val *val); + +int isl_val_get_num_isl_int(__isl_keep isl_val *v, isl_int *n); + +int isl_val_involves_dims(__isl_keep isl_val *v, enum isl_dim_type type, + unsigned first, unsigned n); +__isl_give isl_val *isl_val_insert_dims(__isl_take isl_val *v, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_val *isl_val_drop_dims(__isl_take isl_val *v, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_val *isl_val_set_dim_name(__isl_take isl_val *v, + enum isl_dim_type type, unsigned pos, const char *s); +__isl_give isl_space *isl_val_get_space(__isl_keep isl_val *v); +__isl_give isl_val *isl_val_reset_domain_space(__isl_take isl_val *v, + __isl_take isl_space *space); +__isl_give isl_val *isl_val_align_params(__isl_take isl_val *v, + __isl_take isl_space *space); +__isl_give isl_val *isl_val_realign_domain(__isl_take isl_val *v, + __isl_take isl_reordering *r); +__isl_give isl_val *isl_val_zero_on_domain(__isl_take isl_local_space *ls); + +__isl_give isl_val *isl_val_scale_val(__isl_take isl_val *v1, + __isl_take isl_val *v2); +__isl_give isl_val *isl_val_scale_down_val(__isl_take isl_val *v1, + __isl_take isl_val *v2); +__isl_give isl_val *isl_val_mod_val(__isl_take isl_val *v1, + __isl_take isl_val *v2); + +int isl_val_plain_is_equal(__isl_keep isl_val *val1, __isl_keep isl_val *val2); + +isl_bool isl_val_matching_params(__isl_keep isl_val *v, + __isl_keep isl_space *space); +isl_stat isl_val_check_match_domain_space(__isl_keep isl_val *v, + __isl_keep isl_space *space); + +#undef BASE +#define BASE val + +#include + +#endif Index: contrib/isl/isl_val_sioimath.c =================================================================== --- /dev/null +++ contrib/isl/isl_val_sioimath.c @@ -0,0 +1,68 @@ +#include + +/* Return a reference to an isl_val representing the unsigned + * integer value stored in the "n" chunks of size "size" at "chunks". + * The least significant chunk is assumed to be stored first. + */ +__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, size_t n, + size_t size, const void *chunks) +{ + isl_val *v; + + v = isl_val_alloc(ctx); + if (!v) + return NULL; + + impz_import(isl_sioimath_reinit_big(v->n), n, -1, size, 0, 0, chunks); + isl_sioimath_try_demote(v->n); + isl_int_set_si(v->d, 1); + + return v; +} + +/* Store a representation of the absolute value of the numerator of "v" + * in terms of chunks of size "size" at "chunks". + * The least significant chunk is stored first. + * The number of chunks in the result can be obtained by calling + * isl_val_n_abs_num_chunks. The user is responsible for allocating + * enough memory to store the results. + * + * In the special case of a zero value, isl_val_n_abs_num_chunks will + * return one, while impz_export will not fill in any chunks. We therefore + * do it ourselves. + */ +int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, size_t size, + void *chunks) +{ + isl_sioimath_scratchspace_t scratch; + + if (!v || !chunks) + return -1; + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return -1); + + impz_export(chunks, NULL, -1, size, 0, 0, + isl_sioimath_bigarg_src(*v->n, &scratch)); + if (isl_val_is_zero(v)) + memset(chunks, 0, size); + + return 0; +} + +/* Return the number of chunks of size "size" required to + * store the absolute value of the numerator of "v". + */ +size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, size_t size) +{ + if (!v) + return 0; + + if (!isl_val_is_rat(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting rational value", return 0); + + size *= 8; + return (isl_sioimath_sizeinbase(*v->n, 2) + size - 1) / size; +} Index: contrib/isl/isl_vec.c =================================================================== --- /dev/null +++ contrib/isl/isl_vec.c @@ -0,0 +1,646 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include +#include +#include +#include + +isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec) +{ + return vec ? vec->ctx : NULL; +} + +/* Return a hash value that digests "vec". + */ +uint32_t isl_vec_get_hash(__isl_keep isl_vec *vec) +{ + if (!vec) + return 0; + + return isl_seq_get_hash(vec->el, vec->size); +} + +__isl_give isl_vec *isl_vec_alloc(struct isl_ctx *ctx, unsigned size) +{ + struct isl_vec *vec; + + vec = isl_alloc_type(ctx, struct isl_vec); + if (!vec) + return NULL; + + vec->block = isl_blk_alloc(ctx, size); + if (isl_blk_is_error(vec->block)) + goto error; + + vec->ctx = ctx; + isl_ctx_ref(ctx); + vec->ref = 1; + vec->size = size; + vec->el = vec->block.data; + + return vec; +error: + isl_blk_free(ctx, vec->block); + free(vec); + return NULL; +} + +__isl_give isl_vec *isl_vec_extend(__isl_take isl_vec *vec, unsigned size) +{ + if (!vec) + return NULL; + if (size <= vec->size) + return vec; + + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + + vec->block = isl_blk_extend(vec->ctx, vec->block, size); + if (!vec->block.data) + goto error; + + vec->size = size; + vec->el = vec->block.data; + + return vec; +error: + isl_vec_free(vec); + return NULL; +} + +/* Apply the expansion specified by "exp" to the "n" elements starting at "pos". + * "expanded" it the number of elements that need to replace those "n" + * elements. The entries in "exp" have increasing values between + * 0 and "expanded". + */ +__isl_give isl_vec *isl_vec_expand(__isl_take isl_vec *vec, int pos, int n, + int *exp, int expanded) +{ + int i, j; + int old_size, extra; + + if (!vec) + return NULL; + if (expanded < n) + isl_die(isl_vec_get_ctx(vec), isl_error_invalid, + "not an expansion", return isl_vec_free(vec)); + if (expanded == n) + return vec; + if (pos < 0 || n < 0 || pos + n > vec->size) + isl_die(isl_vec_get_ctx(vec), isl_error_invalid, + "position out of bounds", return isl_vec_free(vec)); + + old_size = vec->size; + extra = expanded - n; + vec = isl_vec_extend(vec, old_size + extra); + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + + for (i = old_size - 1; i >= pos + n; --i) + isl_int_set(vec->el[i + extra], vec->el[i]); + + j = n - 1; + for (i = expanded - 1; i >= 0; --i) { + if (j >= 0 && exp[j] == i) { + if (i != j) + isl_int_swap(vec->el[pos + i], + vec->el[pos + j]); + j--; + } else { + isl_int_set_si(vec->el[pos + i], 0); + } + } + + return vec; +} + +/* Create a vector of size "size" with zero-valued elements. + */ +__isl_give isl_vec *isl_vec_zero(isl_ctx *ctx, unsigned size) +{ + isl_vec *vec; + + vec = isl_vec_alloc(ctx, size); + if (!vec) + return NULL; + isl_seq_clr(vec->el, size); + return vec; +} + +__isl_give isl_vec *isl_vec_zero_extend(__isl_take isl_vec *vec, unsigned size) +{ + int extra; + + if (!vec) + return NULL; + if (size <= vec->size) + return vec; + + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + + extra = size - vec->size; + vec = isl_vec_extend(vec, size); + if (!vec) + return NULL; + + isl_seq_clr(vec->el + size - extra, extra); + + return vec; +} + +/* Return a vector containing the elements of "vec1" followed by + * those of "vec2". + */ +__isl_give isl_vec *isl_vec_concat(__isl_take isl_vec *vec1, + __isl_take isl_vec *vec2) +{ + if (!vec1 || !vec2) + goto error; + + if (vec2->size == 0) { + isl_vec_free(vec2); + return vec1; + } + + if (vec1->size == 0) { + isl_vec_free(vec1); + return vec2; + } + + vec1 = isl_vec_extend(vec1, vec1->size + vec2->size); + if (!vec1) + goto error; + + isl_seq_cpy(vec1->el + vec1->size - vec2->size, vec2->el, vec2->size); + + isl_vec_free(vec2); + return vec1; +error: + isl_vec_free(vec1); + isl_vec_free(vec2); + return NULL; +} + +struct isl_vec *isl_vec_copy(struct isl_vec *vec) +{ + if (!vec) + return NULL; + + vec->ref++; + return vec; +} + +struct isl_vec *isl_vec_dup(struct isl_vec *vec) +{ + struct isl_vec *vec2; + + if (!vec) + return NULL; + vec2 = isl_vec_alloc(vec->ctx, vec->size); + if (!vec2) + return NULL; + isl_seq_cpy(vec2->el, vec->el, vec->size); + return vec2; +} + +struct isl_vec *isl_vec_cow(struct isl_vec *vec) +{ + struct isl_vec *vec2; + if (!vec) + return NULL; + + if (vec->ref == 1) + return vec; + + vec2 = isl_vec_dup(vec); + isl_vec_free(vec); + return vec2; +} + +__isl_null isl_vec *isl_vec_free(__isl_take isl_vec *vec) +{ + if (!vec) + return NULL; + + if (--vec->ref > 0) + return NULL; + + isl_ctx_deref(vec->ctx); + isl_blk_free(vec->ctx, vec->block); + free(vec); + + return NULL; +} + +int isl_vec_size(__isl_keep isl_vec *vec) +{ + return vec ? vec->size : -1; +} + +/* Extract the element at position "pos" of "vec". + */ +__isl_give isl_val *isl_vec_get_element_val(__isl_keep isl_vec *vec, int pos) +{ + isl_ctx *ctx; + + if (!vec) + return NULL; + ctx = isl_vec_get_ctx(vec); + if (pos < 0 || pos >= vec->size) + isl_die(ctx, isl_error_invalid, "position out of range", + return NULL); + return isl_val_int_from_isl_int(ctx, vec->el[pos]); +} + +__isl_give isl_vec *isl_vec_set_element(__isl_take isl_vec *vec, + int pos, isl_int v) +{ + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + if (pos < 0 || pos >= vec->size) + isl_die(vec->ctx, isl_error_invalid, "position out of range", + goto error); + isl_int_set(vec->el[pos], v); + return vec; +error: + isl_vec_free(vec); + return NULL; +} + +__isl_give isl_vec *isl_vec_set_element_si(__isl_take isl_vec *vec, + int pos, int v) +{ + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + if (pos < 0 || pos >= vec->size) + isl_die(vec->ctx, isl_error_invalid, "position out of range", + goto error); + isl_int_set_si(vec->el[pos], v); + return vec; +error: + isl_vec_free(vec); + return NULL; +} + +/* Replace the element at position "pos" of "vec" by "v". + */ +__isl_give isl_vec *isl_vec_set_element_val(__isl_take isl_vec *vec, + int pos, __isl_take isl_val *v) +{ + if (!v) + return isl_vec_free(vec); + if (!isl_val_is_int(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting integer value", goto error); + vec = isl_vec_set_element(vec, pos, v->n); + isl_val_free(v); + return vec; +error: + isl_val_free(v); + return isl_vec_free(vec); +} + +/* Compare the elements of "vec1" and "vec2" at position "pos". + */ +int isl_vec_cmp_element(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2, + int pos) +{ + if (!vec1 || !vec2) + return 0; + if (pos < 0 || pos >= vec1->size || pos >= vec2->size) + isl_die(isl_vec_get_ctx(vec1), isl_error_invalid, + "position out of range", return 0); + return isl_int_cmp(vec1->el[pos], vec2->el[pos]); +} + +/* Does "vec" contain only zero elements? + */ +isl_bool isl_vec_is_zero(__isl_keep isl_vec *vec) +{ + if (!vec) + return isl_bool_error; + return isl_seq_first_non_zero(vec->el, vec->size) < 0; +} + +isl_bool isl_vec_is_equal(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2) +{ + if (!vec1 || !vec2) + return isl_bool_error; + + if (vec1->size != vec2->size) + return isl_bool_false; + + return isl_seq_eq(vec1->el, vec2->el, vec1->size); +} + +__isl_give isl_printer *isl_printer_print_vec(__isl_take isl_printer *printer, + __isl_keep isl_vec *vec) +{ + int i; + + if (!printer || !vec) + goto error; + + printer = isl_printer_print_str(printer, "["); + for (i = 0; i < vec->size; ++i) { + if (i) + printer = isl_printer_print_str(printer, ","); + printer = isl_printer_print_isl_int(printer, vec->el[i]); + } + printer = isl_printer_print_str(printer, "]"); + + return printer; +error: + isl_printer_free(printer); + return NULL; +} + +void isl_vec_dump(struct isl_vec *vec) +{ + isl_printer *printer; + + if (!vec) + return; + + printer = isl_printer_to_file(vec->ctx, stderr); + printer = isl_printer_print_vec(printer, vec); + printer = isl_printer_end_line(printer); + + isl_printer_free(printer); +} + +__isl_give isl_vec *isl_vec_set(__isl_take isl_vec *vec, isl_int v) +{ + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + isl_seq_set(vec->el, v, vec->size); + return vec; +} + +__isl_give isl_vec *isl_vec_set_si(__isl_take isl_vec *vec, int v) +{ + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + isl_seq_set_si(vec->el, v, vec->size); + return vec; +} + +/* Replace all elements of "vec" by "v". + */ +__isl_give isl_vec *isl_vec_set_val(__isl_take isl_vec *vec, + __isl_take isl_val *v) +{ + vec = isl_vec_cow(vec); + if (!vec || !v) + goto error; + if (!isl_val_is_int(v)) + isl_die(isl_val_get_ctx(v), isl_error_invalid, + "expecting integer value", goto error); + isl_seq_set(vec->el, v->n, vec->size); + isl_val_free(v); + return vec; +error: + isl_vec_free(vec); + isl_val_free(v); + return NULL; +} + +__isl_give isl_vec *isl_vec_clr(__isl_take isl_vec *vec) +{ + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + isl_seq_clr(vec->el, vec->size); + return vec; +} + +void isl_vec_lcm(struct isl_vec *vec, isl_int *lcm) +{ + isl_seq_lcm(vec->block.data, vec->size, lcm); +} + +/* Given a rational vector, with the denominator in the first element + * of the vector, round up all coordinates. + */ +__isl_give isl_vec *isl_vec_ceil(__isl_take isl_vec *vec) +{ + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + + isl_seq_cdiv_q(vec->el + 1, vec->el + 1, vec->el[0], vec->size - 1); + + isl_int_set_si(vec->el[0], 1); + + return vec; +} + +struct isl_vec *isl_vec_normalize(struct isl_vec *vec) +{ + if (!vec) + return NULL; + isl_seq_normalize(vec->ctx, vec->el, vec->size); + return vec; +} + +__isl_give isl_vec *isl_vec_neg(__isl_take isl_vec *vec) +{ + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + isl_seq_neg(vec->el, vec->el, vec->size); + return vec; +} + +__isl_give isl_vec *isl_vec_scale(__isl_take isl_vec *vec, isl_int m) +{ + if (isl_int_is_one(m)) + return vec; + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + isl_seq_scale(vec->el, vec->el, m, vec->size); + return vec; +} + +/* Reduce the elements of "vec" modulo "m". + */ +__isl_give isl_vec *isl_vec_fdiv_r(__isl_take isl_vec *vec, isl_int m) +{ + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + + isl_seq_fdiv_r(vec->el, vec->el, m, vec->size); + + return vec; +} + +__isl_give isl_vec *isl_vec_add(__isl_take isl_vec *vec1, + __isl_take isl_vec *vec2) +{ + vec1 = isl_vec_cow(vec1); + if (!vec1 || !vec2) + goto error; + + isl_assert(vec1->ctx, vec1->size == vec2->size, goto error); + + isl_seq_combine(vec1->el, vec1->ctx->one, vec1->el, + vec1->ctx->one, vec2->el, vec1->size); + + isl_vec_free(vec2); + return vec1; +error: + isl_vec_free(vec1); + 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; +} + +__isl_give isl_vec *isl_vec_drop_els(__isl_take isl_vec *vec, + unsigned pos, unsigned n) +{ + if (n == 0) + return vec; + vec = isl_vec_cow(vec); + if (!vec) + return NULL; + + if (pos + n > vec->size) + isl_die(vec->ctx, isl_error_invalid, + "range out of bounds", goto error); + + if (pos + n != vec->size) + isl_seq_cpy(vec->el + pos, vec->el + pos + n, + vec->size - pos - n); + + vec->size -= n; + + return vec; +error: + isl_vec_free(vec); + return NULL; +} + +__isl_give isl_vec *isl_vec_insert_els(__isl_take isl_vec *vec, + unsigned pos, unsigned n) +{ + isl_vec *ext = NULL; + + if (n == 0) + return vec; + if (!vec) + return NULL; + + if (pos > vec->size) + isl_die(vec->ctx, isl_error_invalid, + "position out of bounds", goto error); + + ext = isl_vec_alloc(vec->ctx, vec->size + n); + if (!ext) + goto error; + + isl_seq_cpy(ext->el, vec->el, pos); + isl_seq_cpy(ext->el + pos + n, vec->el + pos, vec->size - pos); + + isl_vec_free(vec); + return ext; +error: + isl_vec_free(vec); + isl_vec_free(ext); + return NULL; +} + +__isl_give isl_vec *isl_vec_insert_zero_els(__isl_take isl_vec *vec, + unsigned pos, unsigned n) +{ + vec = isl_vec_insert_els(vec, pos, n); + if (!vec) + return NULL; + + isl_seq_clr(vec->el + pos, n); + + return vec; +} + +/* Move the "n" elements starting as "src_pos" of "vec" + * to "dst_pos". The elements originally at "dst_pos" are moved + * up or down depending on whether "dst_pos" is smaller or greater + * than "src_pos". + */ +__isl_give isl_vec *isl_vec_move_els(__isl_take isl_vec *vec, + unsigned dst_pos, unsigned src_pos, unsigned n) +{ + isl_vec *res; + + if (!vec) + return NULL; + + if (src_pos + n > vec->size) + isl_die(vec->ctx, isl_error_invalid, + "source range out of bounds", return isl_vec_free(vec)); + if (dst_pos + n > vec->size) + isl_die(vec->ctx, isl_error_invalid, + "destination range out of bounds", + return isl_vec_free(vec)); + + if (n == 0 || dst_pos == src_pos) + return vec; + + res = isl_vec_alloc(vec->ctx, vec->size); + if (!res) + return isl_vec_free(vec); + + if (dst_pos < src_pos) { + isl_seq_cpy(res->el, vec->el, dst_pos); + isl_seq_cpy(res->el + dst_pos, vec->el + src_pos, n); + isl_seq_cpy(res->el + dst_pos + n, + vec->el + dst_pos, src_pos - dst_pos); + isl_seq_cpy(res->el + src_pos + n, + vec->el + src_pos + n, res->size - src_pos - n); + } else { + isl_seq_cpy(res->el, vec->el, src_pos); + isl_seq_cpy(res->el + src_pos, + vec->el + src_pos + n, dst_pos - src_pos); + isl_seq_cpy(res->el + dst_pos, vec->el + src_pos, n); + isl_seq_cpy(res->el + dst_pos + n, + vec->el + dst_pos + n, res->size - dst_pos - n); + } + + isl_vec_free(vec); + return res; +} Index: contrib/isl/isl_vec_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_vec_private.h @@ -0,0 +1,31 @@ +#ifndef ISL_VEC_PRIVATE_H +#define ISL_VEC_PRIVATE_H + +#include +#include + +struct isl_vec { + int ref; + + struct isl_ctx *ctx; + + unsigned size; + isl_int *el; + + struct isl_blk block; +}; + +uint32_t isl_vec_get_hash(__isl_keep isl_vec *vec); + +__isl_give isl_vec *isl_vec_cow(__isl_take isl_vec *vec); + +void isl_vec_lcm(struct isl_vec *vec, isl_int *lcm); +int isl_vec_get_element(__isl_keep isl_vec *vec, int pos, isl_int *v); +__isl_give isl_vec *isl_vec_set(__isl_take isl_vec *vec, isl_int v); + +isl_bool isl_vec_is_zero(__isl_keep isl_vec *vec); + +__isl_give isl_vec *isl_vec_expand(__isl_take isl_vec *vec, int pos, int n, + int *exp, int expanded); + +#endif Index: contrib/isl/isl_version.c =================================================================== --- /dev/null +++ contrib/isl/isl_version.c @@ -0,0 +1,17 @@ +#include "isl_config.h" +#include "gitversion.h" + +const char *isl_version(void) +{ + return GIT_HEAD_ID +#ifdef USE_GMP_FOR_MP + "-GMP" +#endif +#ifdef USE_IMATH_FOR_MP + "-IMath" +#ifdef USE_SMALL_INT_OPT + "-32" +#endif +#endif + "\n"; +} Index: contrib/isl/isl_vertices.c =================================================================== --- /dev/null +++ contrib/isl/isl_vertices.c @@ -0,0 +1,1547 @@ +/* + * Copyright 2010 INRIA Saclay + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, + * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, + * 91893 Orsay, France + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SELECTED 1 +#define DESELECTED -1 +#define UNSELECTED 0 + +static __isl_give isl_vertices *compute_chambers(__isl_take isl_basic_set *bset, + __isl_take isl_vertices *vertices); + +__isl_give isl_vertices *isl_vertices_copy(__isl_keep isl_vertices *vertices) +{ + if (!vertices) + return NULL; + + vertices->ref++; + return vertices; +} + +__isl_null isl_vertices *isl_vertices_free(__isl_take isl_vertices *vertices) +{ + int i; + + if (!vertices) + return NULL; + + if (--vertices->ref > 0) + return NULL; + + for (i = 0; i < vertices->n_vertices; ++i) { + isl_basic_set_free(vertices->v[i].vertex); + isl_basic_set_free(vertices->v[i].dom); + } + free(vertices->v); + + for (i = 0; i < vertices->n_chambers; ++i) { + free(vertices->c[i].vertices); + isl_basic_set_free(vertices->c[i].dom); + } + free(vertices->c); + + isl_basic_set_free(vertices->bset); + free(vertices); + + return NULL; +} + +struct isl_vertex_list { + struct isl_vertex v; + struct isl_vertex_list *next; +}; + +static struct isl_vertex_list *free_vertex_list(struct isl_vertex_list *list) +{ + struct isl_vertex_list *next; + + for (; list; list = next) { + next = list->next; + isl_basic_set_free(list->v.vertex); + isl_basic_set_free(list->v.dom); + free(list); + } + + return NULL; +} + +static __isl_give isl_vertices *vertices_from_list(__isl_keep isl_basic_set *bset, + int n_vertices, struct isl_vertex_list *list) +{ + int i; + struct isl_vertex_list *next; + isl_vertices *vertices; + + vertices = isl_calloc_type(bset->ctx, isl_vertices); + if (!vertices) + goto error; + vertices->ref = 1; + vertices->bset = isl_basic_set_copy(bset); + vertices->v = isl_alloc_array(bset->ctx, struct isl_vertex, n_vertices); + if (n_vertices && !vertices->v) + goto error; + vertices->n_vertices = n_vertices; + + for (i = 0; list; list = next, i++) { + next = list->next; + vertices->v[i] = list->v; + free(list); + } + + return vertices; +error: + isl_vertices_free(vertices); + free_vertex_list(list); + return NULL; +} + +/* Prepend a vertex to the linked list "list" based on the equalities in "tab". + * Return isl_bool_true if the vertex was actually added and + * isl_bool_false otherwise. + * In particular, vertices with a lower-dimensional activity domain are + * not added to the list because they would not be included in any chamber. + * Return isl_bool_error on error. + */ +static isl_bool add_vertex(struct isl_vertex_list **list, + __isl_keep isl_basic_set *bset, struct isl_tab *tab) +{ + unsigned nvar; + struct isl_vertex_list *v = NULL; + + if (isl_tab_detect_implicit_equalities(tab) < 0) + return isl_bool_error; + + nvar = isl_basic_set_dim(bset, isl_dim_set); + + v = isl_calloc_type(tab->mat->ctx, struct isl_vertex_list); + if (!v) + goto error; + + v->v.vertex = isl_basic_set_copy(bset); + v->v.vertex = isl_basic_set_cow(v->v.vertex); + v->v.vertex = isl_basic_set_update_from_tab(v->v.vertex, tab); + v->v.vertex = isl_basic_set_simplify(v->v.vertex); + v->v.vertex = isl_basic_set_finalize(v->v.vertex); + if (!v->v.vertex) + goto error; + isl_assert(bset->ctx, v->v.vertex->n_eq >= nvar, goto error); + v->v.dom = isl_basic_set_copy(v->v.vertex); + v->v.dom = isl_basic_set_params(v->v.dom); + if (!v->v.dom) + goto error; + + if (v->v.dom->n_eq > 0) { + free_vertex_list(v); + return isl_bool_false; + } + + v->next = *list; + *list = v; + + return isl_bool_true; +error: + free_vertex_list(v); + return isl_bool_error; +} + +/* Compute the parametric vertices and the chamber decomposition + * of an empty parametric polytope. + */ +static __isl_give isl_vertices *vertices_empty(__isl_keep isl_basic_set *bset) +{ + isl_vertices *vertices; + + if (!bset) + return NULL; + + vertices = isl_calloc_type(bset->ctx, isl_vertices); + if (!vertices) + return NULL; + vertices->bset = isl_basic_set_copy(bset); + vertices->ref = 1; + + vertices->n_vertices = 0; + vertices->n_chambers = 0; + + return vertices; +} + +/* Compute the parametric vertices and the chamber decomposition + * of the parametric polytope defined using the same constraints + * as "bset" in the 0D case. + * There is exactly one 0D vertex and a single chamber containing + * the vertex. + */ +static __isl_give isl_vertices *vertices_0D(__isl_keep isl_basic_set *bset) +{ + isl_vertices *vertices; + + if (!bset) + return NULL; + + vertices = isl_calloc_type(bset->ctx, isl_vertices); + if (!vertices) + return NULL; + vertices->ref = 1; + vertices->bset = isl_basic_set_copy(bset); + + vertices->v = isl_calloc_array(bset->ctx, struct isl_vertex, 1); + if (!vertices->v) + goto error; + vertices->n_vertices = 1; + vertices->v[0].vertex = isl_basic_set_copy(bset); + vertices->v[0].dom = isl_basic_set_params(isl_basic_set_copy(bset)); + if (!vertices->v[0].vertex || !vertices->v[0].dom) + goto error; + + vertices->c = isl_calloc_array(bset->ctx, struct isl_chamber, 1); + if (!vertices->c) + goto error; + vertices->n_chambers = 1; + vertices->c[0].n_vertices = 1; + vertices->c[0].vertices = isl_calloc_array(bset->ctx, int, 1); + if (!vertices->c[0].vertices) + goto error; + vertices->c[0].dom = isl_basic_set_copy(vertices->v[0].dom); + if (!vertices->c[0].dom) + goto error; + + return vertices; +error: + isl_vertices_free(vertices); + return NULL; +} + +/* Is the row pointed to by "f" linearly independent of the "n" first + * rows in "facets"? + */ +static int is_independent(__isl_keep isl_mat *facets, int n, isl_int *f) +{ + int rank; + + if (isl_seq_first_non_zero(f, facets->n_col) < 0) + return 0; + + isl_seq_cpy(facets->row[n], f, facets->n_col); + facets->n_row = n + 1; + rank = isl_mat_rank(facets); + if (rank < 0) + return -1; + + return rank == n + 1; +} + +/* Check whether we can select constraint "level", given the current selection + * reflected by facets in "tab", the rows of "facets" and the earlier + * "selected" elements of "selection". + * + * If the constraint is (strictly) redundant in the tableau, selecting it would + * result in an empty tableau, so it can't be selected. + * If the set variable part of the constraint is not linearly independent + * of the set variable parts of the already selected constraints, + * the constraint cannot be selected. + * If selecting the constraint results in an empty tableau, the constraint + * cannot be selected. + * Finally, if selecting the constraint results in some explicitly + * deselected constraints turning into equalities, then the corresponding + * vertices have already been generated, so the constraint cannot be selected. + */ +static int can_select(__isl_keep isl_basic_set *bset, int level, + struct isl_tab *tab, __isl_keep isl_mat *facets, int selected, + int *selection) +{ + int i; + int indep; + unsigned ovar; + struct isl_tab_undo *snap; + + if (isl_tab_is_redundant(tab, level)) + return 0; + + ovar = isl_space_offset(bset->dim, isl_dim_set); + + indep = is_independent(facets, selected, bset->ineq[level] + 1 + ovar); + if (indep < 0) + return -1; + if (!indep) + return 0; + + snap = isl_tab_snap(tab); + if (isl_tab_select_facet(tab, level) < 0) + return -1; + + if (tab->empty) { + if (isl_tab_rollback(tab, snap) < 0) + return -1; + return 0; + } + + for (i = 0; i < level; ++i) { + int sgn; + + if (selection[i] != DESELECTED) + continue; + + if (isl_tab_is_equality(tab, i)) + sgn = 0; + else if (isl_tab_is_redundant(tab, i)) + sgn = 1; + else + sgn = isl_tab_sign_of_max(tab, i); + if (sgn < -1) + return -1; + if (sgn <= 0) { + if (isl_tab_rollback(tab, snap) < 0) + return -1; + return 0; + } + } + + return 1; +} + +/* Compute the parametric vertices and the chamber decomposition + * of a parametric polytope that is not full-dimensional. + * + * Simply map the parametric polytope to a lower dimensional space + * and map the resulting vertices back. + */ +static __isl_give isl_vertices *lower_dim_vertices( + __isl_keep isl_basic_set *bset) +{ + isl_morph *morph; + isl_vertices *vertices; + + bset = isl_basic_set_copy(bset); + morph = isl_basic_set_full_compression(bset); + bset = isl_morph_basic_set(isl_morph_copy(morph), bset); + + vertices = isl_basic_set_compute_vertices(bset); + isl_basic_set_free(bset); + + morph = isl_morph_inverse(morph); + + vertices = isl_morph_vertices(morph, vertices); + + return vertices; +} + +/* Compute the parametric vertices and the chamber decomposition + * of the parametric polytope defined using the same constraints + * as "bset". "bset" is assumed to have no existentially quantified + * variables. + * + * The vertices themselves are computed in a fairly simplistic way. + * We simply run through all combinations of d constraints, + * with d the number of set variables, and check if those d constraints + * define a vertex. To avoid the generation of duplicate vertices, + * which we may happen if a vertex is defined by more that d constraints, + * we make sure we only generate the vertex for the d constraints with + * smallest index. + * + * We set up a tableau and keep track of which facets have been + * selected. The tableau is marked strict_redundant so that we can be + * sure that any constraint that is marked redundant (and that is not + * also marked zero) is not an equality. + * If a constraint is marked DESELECTED, it means the constraint was + * SELECTED before (in combination with the same selection of earlier + * constraints). If such a deselected constraint turns out to be an + * equality, then any vertex that may still be found with the current + * selection has already been generated when the constraint was selected. + * A constraint is marked UNSELECTED when there is no way selecting + * the constraint could lead to a vertex (in combination with the current + * selection of earlier constraints). + * + * The set variable coefficients of the selected constraints are stored + * in the facets matrix. + */ +__isl_give isl_vertices *isl_basic_set_compute_vertices( + __isl_keep isl_basic_set *bset) +{ + struct isl_tab *tab; + int level; + int init; + unsigned nvar; + int *selection = NULL; + int selected; + struct isl_tab_undo **snap = NULL; + isl_mat *facets = NULL; + struct isl_vertex_list *list = NULL; + int n_vertices = 0; + isl_vertices *vertices; + + if (!bset) + return NULL; + + if (isl_basic_set_plain_is_empty(bset)) + return vertices_empty(bset); + + if (bset->n_eq != 0) + return lower_dim_vertices(bset); + + isl_assert(bset->ctx, isl_basic_set_dim(bset, isl_dim_div) == 0, + return NULL); + + if (isl_basic_set_dim(bset, isl_dim_set) == 0) + return vertices_0D(bset); + + nvar = isl_basic_set_dim(bset, isl_dim_set); + + bset = isl_basic_set_copy(bset); + bset = isl_basic_set_set_rational(bset); + if (!bset) + return NULL; + + tab = isl_tab_from_basic_set(bset, 0); + if (!tab) + goto error; + tab->strict_redundant = 1; + + if (tab->empty) { + vertices = vertices_empty(bset); + isl_basic_set_free(bset); + isl_tab_free(tab); + return vertices; + } + + selection = isl_alloc_array(bset->ctx, int, bset->n_ineq); + snap = isl_alloc_array(bset->ctx, struct isl_tab_undo *, bset->n_ineq); + facets = isl_mat_alloc(bset->ctx, nvar, nvar); + if ((bset->n_ineq && (!selection || !snap)) || !facets) + goto error; + + level = 0; + init = 1; + selected = 0; + + while (level >= 0) { + if (level >= bset->n_ineq || + (!init && selection[level] != SELECTED)) { + --level; + init = 0; + continue; + } + if (init) { + int ok; + snap[level] = isl_tab_snap(tab); + ok = can_select(bset, level, tab, facets, selected, + selection); + if (ok < 0) + goto error; + if (ok) { + selection[level] = SELECTED; + selected++; + } else + selection[level] = UNSELECTED; + } else { + selection[level] = DESELECTED; + selected--; + if (isl_tab_rollback(tab, snap[level]) < 0) + goto error; + } + if (selected == nvar) { + if (tab->n_dead == nvar) { + isl_bool added = add_vertex(&list, bset, tab); + if (added < 0) + goto error; + if (added) + n_vertices++; + } + init = 0; + continue; + } + ++level; + init = 1; + } + + isl_mat_free(facets); + free(selection); + free(snap); + + isl_tab_free(tab); + + vertices = vertices_from_list(bset, n_vertices, list); + + vertices = compute_chambers(bset, vertices); + + return vertices; +error: + free_vertex_list(list); + isl_mat_free(facets); + free(selection); + free(snap); + isl_tab_free(tab); + isl_basic_set_free(bset); + return NULL; +} + +struct isl_chamber_list { + struct isl_chamber c; + struct isl_chamber_list *next; +}; + +static void free_chamber_list(struct isl_chamber_list *list) +{ + struct isl_chamber_list *next; + + for (; list; list = next) { + next = list->next; + isl_basic_set_free(list->c.dom); + free(list->c.vertices); + free(list); + } +} + +/* Check whether the basic set "bset" is a superset of the basic set described + * by "tab", i.e., check whether all constraints of "bset" are redundant. + */ +static isl_bool bset_covers_tab(__isl_keep isl_basic_set *bset, + struct isl_tab *tab) +{ + int i; + + if (!bset || !tab) + return isl_bool_error; + + for (i = 0; i < bset->n_ineq; ++i) { + enum isl_ineq_type type = isl_tab_ineq_type(tab, bset->ineq[i]); + switch (type) { + case isl_ineq_error: return isl_bool_error; + case isl_ineq_redundant: continue; + default: return isl_bool_false; + } + } + + return isl_bool_true; +} + +static __isl_give isl_vertices *vertices_add_chambers( + __isl_take isl_vertices *vertices, int n_chambers, + struct isl_chamber_list *list) +{ + int i; + isl_ctx *ctx; + struct isl_chamber_list *next; + + ctx = isl_vertices_get_ctx(vertices); + vertices->c = isl_alloc_array(ctx, struct isl_chamber, n_chambers); + if (!vertices->c) + goto error; + vertices->n_chambers = n_chambers; + + for (i = 0; list; list = next, i++) { + next = list->next; + vertices->c[i] = list->c; + free(list); + } + + return vertices; +error: + isl_vertices_free(vertices); + free_chamber_list(list); + return NULL; +} + +/* Can "tab" be intersected with "bset" without resulting in + * a lower-dimensional set. + * "bset" itself is assumed to be full-dimensional. + */ +static isl_bool can_intersect(struct isl_tab *tab, + __isl_keep isl_basic_set *bset) +{ + int i; + struct isl_tab_undo *snap; + + if (bset->n_eq > 0) + isl_die(isl_basic_set_get_ctx(bset), isl_error_internal, + "expecting full-dimensional input", + return isl_bool_error); + + if (isl_tab_extend_cons(tab, bset->n_ineq) < 0) + return isl_bool_error; + + snap = isl_tab_snap(tab); + + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_tab_ineq_type(tab, bset->ineq[i]) == isl_ineq_redundant) + continue; + if (isl_tab_add_ineq(tab, bset->ineq[i]) < 0) + return isl_bool_error; + } + + if (isl_tab_detect_implicit_equalities(tab) < 0) + return isl_bool_error; + if (tab->n_dead) { + if (isl_tab_rollback(tab, snap) < 0) + return isl_bool_error; + return isl_bool_false; + } + + return isl_bool_true; +} + +static int add_chamber(struct isl_chamber_list **list, + __isl_keep isl_vertices *vertices, struct isl_tab *tab, int *selection) +{ + int n_frozen; + int i, j; + int n_vertices = 0; + struct isl_tab_undo *snap; + struct isl_chamber_list *c = NULL; + + for (i = 0; i < vertices->n_vertices; ++i) + if (selection[i]) + n_vertices++; + + snap = isl_tab_snap(tab); + + for (i = 0; i < tab->n_con && tab->con[i].frozen; ++i) + tab->con[i].frozen = 0; + n_frozen = i; + + if (isl_tab_detect_redundant(tab) < 0) + return -1; + + c = isl_calloc_type(tab->mat->ctx, struct isl_chamber_list); + if (!c) + goto error; + c->c.vertices = isl_alloc_array(tab->mat->ctx, int, n_vertices); + if (n_vertices && !c->c.vertices) + goto error; + c->c.dom = isl_basic_set_copy(isl_tab_peek_bset(tab)); + c->c.dom = isl_basic_set_set_rational(c->c.dom); + c->c.dom = isl_basic_set_cow(c->c.dom); + c->c.dom = isl_basic_set_update_from_tab(c->c.dom, tab); + c->c.dom = isl_basic_set_simplify(c->c.dom); + c->c.dom = isl_basic_set_finalize(c->c.dom); + if (!c->c.dom) + goto error; + + c->c.n_vertices = n_vertices; + + for (i = 0, j = 0; i < vertices->n_vertices; ++i) + if (selection[i]) { + c->c.vertices[j] = i; + j++; + } + + c->next = *list; + *list = c; + + for (i = 0; i < n_frozen; ++i) + tab->con[i].frozen = 1; + + if (isl_tab_rollback(tab, snap) < 0) + return -1; + + return 0; +error: + free_chamber_list(c); + return -1; +} + +struct isl_facet_todo { + struct isl_tab *tab; /* A tableau representation of the facet */ + isl_basic_set *bset; /* A normalized basic set representation */ + isl_vec *constraint; /* Constraint pointing to the other side */ + struct isl_facet_todo *next; +}; + +static void free_todo(struct isl_facet_todo *todo) +{ + while (todo) { + struct isl_facet_todo *next = todo->next; + + isl_tab_free(todo->tab); + isl_basic_set_free(todo->bset); + isl_vec_free(todo->constraint); + free(todo); + + todo = next; + } +} + +static struct isl_facet_todo *create_todo(struct isl_tab *tab, int con) +{ + int i; + int n_frozen; + struct isl_tab_undo *snap; + struct isl_facet_todo *todo; + + snap = isl_tab_snap(tab); + + for (i = 0; i < tab->n_con && tab->con[i].frozen; ++i) + tab->con[i].frozen = 0; + n_frozen = i; + + if (isl_tab_detect_redundant(tab) < 0) + return NULL; + + todo = isl_calloc_type(tab->mat->ctx, struct isl_facet_todo); + if (!todo) + return NULL; + + todo->constraint = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var); + if (!todo->constraint) + goto error; + isl_seq_neg(todo->constraint->el, tab->bmap->ineq[con], 1 + tab->n_var); + todo->bset = isl_basic_set_copy(isl_tab_peek_bset(tab)); + todo->bset = isl_basic_set_set_rational(todo->bset); + todo->bset = isl_basic_set_cow(todo->bset); + todo->bset = isl_basic_set_update_from_tab(todo->bset, tab); + todo->bset = isl_basic_set_simplify(todo->bset); + todo->bset = isl_basic_set_sort_constraints(todo->bset); + if (!todo->bset) + goto error; + ISL_F_SET(todo->bset, ISL_BASIC_SET_NORMALIZED); + todo->tab = isl_tab_dup(tab); + if (!todo->tab) + goto error; + + for (i = 0; i < n_frozen; ++i) + tab->con[i].frozen = 1; + + if (isl_tab_rollback(tab, snap) < 0) + goto error; + + return todo; +error: + free_todo(todo); + return NULL; +} + +/* Create todo items for all interior facets of the chamber represented + * by "tab" and collect them in "next". + */ +static int init_todo(struct isl_facet_todo **next, struct isl_tab *tab) +{ + int i; + struct isl_tab_undo *snap; + struct isl_facet_todo *todo; + + snap = isl_tab_snap(tab); + + for (i = 0; i < tab->n_con; ++i) { + if (tab->con[i].frozen) + continue; + if (tab->con[i].is_redundant) + continue; + + if (isl_tab_select_facet(tab, i) < 0) + return -1; + + todo = create_todo(tab, i); + if (!todo) + return -1; + + todo->next = *next; + *next = todo; + + if (isl_tab_rollback(tab, snap) < 0) + return -1; + } + + return 0; +} + +/* Does the linked list contain a todo item that is the opposite of "todo". + * If so, return 1 and remove the opposite todo item. + */ +static int has_opposite(struct isl_facet_todo *todo, + struct isl_facet_todo **list) +{ + for (; *list; list = &(*list)->next) { + int eq; + eq = isl_basic_set_plain_is_equal(todo->bset, (*list)->bset); + if (eq < 0) + return -1; + if (!eq) + continue; + todo = *list; + *list = todo->next; + todo->next = NULL; + free_todo(todo); + return 1; + } + + return 0; +} + +/* Create todo items for all interior facets of the chamber represented + * by "tab" and collect them in first->next, taking care to cancel + * opposite todo items. + */ +static int update_todo(struct isl_facet_todo *first, struct isl_tab *tab) +{ + int i; + struct isl_tab_undo *snap; + struct isl_facet_todo *todo; + + snap = isl_tab_snap(tab); + + for (i = 0; i < tab->n_con; ++i) { + int drop; + + if (tab->con[i].frozen) + continue; + if (tab->con[i].is_redundant) + continue; + + if (isl_tab_select_facet(tab, i) < 0) + return -1; + + todo = create_todo(tab, i); + if (!todo) + return -1; + + drop = has_opposite(todo, &first->next); + if (drop < 0) + return -1; + + if (drop) + free_todo(todo); + else { + todo->next = first->next; + first->next = todo; + } + + if (isl_tab_rollback(tab, snap) < 0) + return -1; + } + + return 0; +} + +/* Compute the chamber decomposition of the parametric polytope respresented + * by "bset" given the parametric vertices and their activity domains. + * + * We are only interested in full-dimensional chambers. + * Each of these chambers is the intersection of the activity domains of + * one or more vertices and the union of all chambers is equal to the + * projection of the entire parametric polytope onto the parameter space. + * + * We first create an initial chamber by intersecting as many activity + * domains as possible without ending up with an empty or lower-dimensional + * set. As a minor optimization, we only consider those activity domains + * that contain some arbitrary point. + * + * For each of the interior facets of the chamber, we construct a todo item, + * containing the facet and a constraint containing the other side of the facet, + * for constructing the chamber on the other side. + * While their are any todo items left, we pick a todo item and + * create the required chamber by intersecting all activity domains + * that contain the facet and have a full-dimensional intersection with + * the other side of the facet. For each of the interior facets, we + * again create todo items, taking care to cancel opposite todo items. + */ +static __isl_give isl_vertices *compute_chambers(__isl_take isl_basic_set *bset, + __isl_take isl_vertices *vertices) +{ + int i; + isl_ctx *ctx; + isl_vec *sample = NULL; + struct isl_tab *tab = NULL; + struct isl_tab_undo *snap; + int *selection = NULL; + int n_chambers = 0; + struct isl_chamber_list *list = NULL; + struct isl_facet_todo *todo = NULL; + + if (!bset || !vertices) + goto error; + + ctx = isl_vertices_get_ctx(vertices); + selection = isl_alloc_array(ctx, int, vertices->n_vertices); + if (vertices->n_vertices && !selection) + goto error; + + bset = isl_basic_set_params(bset); + + tab = isl_tab_from_basic_set(bset, 1); + if (!tab) + goto error; + for (i = 0; i < bset->n_ineq; ++i) + if (isl_tab_freeze_constraint(tab, i) < 0) + goto error; + isl_basic_set_free(bset); + + snap = isl_tab_snap(tab); + + sample = isl_tab_get_sample_value(tab); + + for (i = 0; i < vertices->n_vertices; ++i) { + selection[i] = isl_basic_set_contains(vertices->v[i].dom, sample); + if (selection[i] < 0) + goto error; + if (!selection[i]) + continue; + selection[i] = can_intersect(tab, vertices->v[i].dom); + if (selection[i] < 0) + goto error; + } + + if (isl_tab_detect_redundant(tab) < 0) + goto error; + + if (add_chamber(&list, vertices, tab, selection) < 0) + goto error; + n_chambers++; + + if (init_todo(&todo, tab) < 0) + goto error; + + while (todo) { + struct isl_facet_todo *next; + + if (isl_tab_rollback(tab, snap) < 0) + goto error; + + if (isl_tab_add_ineq(tab, todo->constraint->el) < 0) + goto error; + if (isl_tab_freeze_constraint(tab, tab->n_con - 1) < 0) + goto error; + + for (i = 0; i < vertices->n_vertices; ++i) { + selection[i] = bset_covers_tab(vertices->v[i].dom, + todo->tab); + if (selection[i] < 0) + goto error; + if (!selection[i]) + continue; + selection[i] = can_intersect(tab, vertices->v[i].dom); + if (selection[i] < 0) + goto error; + } + + if (isl_tab_detect_redundant(tab) < 0) + goto error; + + if (add_chamber(&list, vertices, tab, selection) < 0) + goto error; + n_chambers++; + + if (update_todo(todo, tab) < 0) + goto error; + + next = todo->next; + todo->next = NULL; + free_todo(todo); + todo = next; + } + + isl_vec_free(sample); + + isl_tab_free(tab); + free(selection); + + vertices = vertices_add_chambers(vertices, n_chambers, list); + + for (i = 0; vertices && i < vertices->n_vertices; ++i) { + isl_basic_set_free(vertices->v[i].dom); + vertices->v[i].dom = NULL; + } + + return vertices; +error: + free_chamber_list(list); + free_todo(todo); + isl_vec_free(sample); + isl_tab_free(tab); + free(selection); + if (!tab) + isl_basic_set_free(bset); + isl_vertices_free(vertices); + return NULL; +} + +isl_ctx *isl_vertex_get_ctx(__isl_keep isl_vertex *vertex) +{ + return vertex ? isl_vertices_get_ctx(vertex->vertices) : NULL; +} + +int isl_vertex_get_id(__isl_keep isl_vertex *vertex) +{ + return vertex ? vertex->id : -1; +} + +/* Return the activity domain of the vertex "vertex". + */ +__isl_give isl_basic_set *isl_vertex_get_domain(__isl_keep isl_vertex *vertex) +{ + struct isl_vertex *v; + + if (!vertex) + return NULL; + + v = &vertex->vertices->v[vertex->id]; + if (!v->dom) { + v->dom = isl_basic_set_copy(v->vertex); + v->dom = isl_basic_set_params(v->dom); + v->dom = isl_basic_set_set_integral(v->dom); + } + + return isl_basic_set_copy(v->dom); +} + +/* Return a multiple quasi-affine expression describing the vertex "vertex" + * in terms of the parameters, + */ +__isl_give isl_multi_aff *isl_vertex_get_expr(__isl_keep isl_vertex *vertex) +{ + struct isl_vertex *v; + isl_basic_set *bset; + + if (!vertex) + return NULL; + + v = &vertex->vertices->v[vertex->id]; + + bset = isl_basic_set_copy(v->vertex); + return isl_multi_aff_from_basic_set_equalities(bset); +} + +static __isl_give isl_vertex *isl_vertex_alloc(__isl_take isl_vertices *vertices, + int id) +{ + isl_ctx *ctx; + isl_vertex *vertex; + + if (!vertices) + return NULL; + + ctx = isl_vertices_get_ctx(vertices); + vertex = isl_alloc_type(ctx, isl_vertex); + if (!vertex) + goto error; + + vertex->vertices = vertices; + vertex->id = id; + + return vertex; +error: + isl_vertices_free(vertices); + return NULL; +} + +void isl_vertex_free(__isl_take isl_vertex *vertex) +{ + if (!vertex) + return; + isl_vertices_free(vertex->vertices); + free(vertex); +} + +isl_ctx *isl_cell_get_ctx(__isl_keep isl_cell *cell) +{ + return cell ? cell->dom->ctx : NULL; +} + +__isl_give isl_basic_set *isl_cell_get_domain(__isl_keep isl_cell *cell) +{ + return cell ? isl_basic_set_copy(cell->dom) : NULL; +} + +static __isl_give isl_cell *isl_cell_alloc(__isl_take isl_vertices *vertices, + __isl_take isl_basic_set *dom, int id) +{ + int i; + isl_cell *cell = NULL; + + if (!vertices || !dom) + goto error; + + cell = isl_calloc_type(dom->ctx, isl_cell); + if (!cell) + goto error; + + cell->n_vertices = vertices->c[id].n_vertices; + cell->ids = isl_alloc_array(dom->ctx, int, cell->n_vertices); + if (cell->n_vertices && !cell->ids) + goto error; + for (i = 0; i < cell->n_vertices; ++i) + cell->ids[i] = vertices->c[id].vertices[i]; + cell->vertices = vertices; + cell->dom = dom; + + return cell; +error: + isl_cell_free(cell); + isl_vertices_free(vertices); + isl_basic_set_free(dom); + return NULL; +} + +void isl_cell_free(__isl_take isl_cell *cell) +{ + if (!cell) + return; + + isl_vertices_free(cell->vertices); + free(cell->ids); + isl_basic_set_free(cell->dom); + free(cell); +} + +/* Create a tableau of the cone obtained by first homogenizing the given + * polytope and then making all inequalities strict by setting the + * constant term to -1. + */ +static struct isl_tab *tab_for_shifted_cone(__isl_keep isl_basic_set *bset) +{ + int i; + isl_vec *c = NULL; + struct isl_tab *tab; + + if (!bset) + return NULL; + tab = isl_tab_alloc(bset->ctx, bset->n_eq + bset->n_ineq + 1, + 1 + isl_basic_set_total_dim(bset), 0); + if (!tab) + return NULL; + tab->rational = ISL_F_ISSET(bset, ISL_BASIC_SET_RATIONAL); + if (ISL_F_ISSET(bset, ISL_BASIC_MAP_EMPTY)) { + if (isl_tab_mark_empty(tab) < 0) + goto error; + return tab; + } + + c = isl_vec_alloc(bset->ctx, 1 + 1 + isl_basic_set_total_dim(bset)); + if (!c) + goto error; + + isl_int_set_si(c->el[0], 0); + for (i = 0; i < bset->n_eq; ++i) { + isl_seq_cpy(c->el + 1, bset->eq[i], c->size - 1); + if (isl_tab_add_eq(tab, c->el) < 0) + goto error; + } + + isl_int_set_si(c->el[0], -1); + for (i = 0; i < bset->n_ineq; ++i) { + isl_seq_cpy(c->el + 1, bset->ineq[i], c->size - 1); + if (isl_tab_add_ineq(tab, c->el) < 0) + goto error; + if (tab->empty) { + isl_vec_free(c); + return tab; + } + } + + isl_seq_clr(c->el + 1, c->size - 1); + isl_int_set_si(c->el[1], 1); + if (isl_tab_add_ineq(tab, c->el) < 0) + goto error; + + isl_vec_free(c); + return tab; +error: + isl_vec_free(c); + isl_tab_free(tab); + return NULL; +} + +/* Compute an interior point of "bset" by selecting an interior + * point in homogeneous space and projecting the point back down. + */ +static __isl_give isl_vec *isl_basic_set_interior_point( + __isl_keep isl_basic_set *bset) +{ + isl_vec *vec; + struct isl_tab *tab; + + tab = tab_for_shifted_cone(bset); + vec = isl_tab_get_sample_value(tab); + isl_tab_free(tab); + if (!vec) + return NULL; + + isl_seq_cpy(vec->el, vec->el + 1, vec->size - 1); + vec->size--; + + return vec; +} + +/* Call "fn" on all chambers of the parametric polytope with the shared + * facets of neighboring chambers only appearing in one of the chambers. + * + * We pick an interior point from one of the chambers and then make + * all constraints that do not satisfy this point strict. + * For constraints that saturate the interior point, the sign + * of the first non-zero coefficient is used to determine which + * of the two (internal) constraints should be tightened. + */ +isl_stat isl_vertices_foreach_disjoint_cell(__isl_keep isl_vertices *vertices, + isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user) +{ + int i; + isl_vec *vec; + isl_cell *cell; + + if (!vertices) + return isl_stat_error; + + if (vertices->n_chambers == 0) + return isl_stat_ok; + + if (vertices->n_chambers == 1) { + isl_basic_set *dom = isl_basic_set_copy(vertices->c[0].dom); + dom = isl_basic_set_set_integral(dom); + cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, 0); + if (!cell) + return isl_stat_error; + return fn(cell, user); + } + + vec = isl_basic_set_interior_point(vertices->c[0].dom); + if (!vec) + return isl_stat_error; + + for (i = 0; i < vertices->n_chambers; ++i) { + int r; + isl_basic_set *dom = isl_basic_set_copy(vertices->c[i].dom); + if (i) + dom = isl_basic_set_tighten_outward(dom, vec); + dom = isl_basic_set_set_integral(dom); + cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, i); + if (!cell) + goto error; + r = fn(cell, user); + if (r < 0) + goto error; + } + + isl_vec_free(vec); + + return isl_stat_ok; +error: + isl_vec_free(vec); + return isl_stat_error; +} + +isl_stat isl_vertices_foreach_cell(__isl_keep isl_vertices *vertices, + isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user) +{ + int i; + isl_cell *cell; + + if (!vertices) + return isl_stat_error; + + if (vertices->n_chambers == 0) + return isl_stat_ok; + + for (i = 0; i < vertices->n_chambers; ++i) { + isl_stat r; + isl_basic_set *dom = isl_basic_set_copy(vertices->c[i].dom); + + cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, i); + if (!cell) + return isl_stat_error; + + r = fn(cell, user); + if (r < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +isl_stat isl_vertices_foreach_vertex(__isl_keep isl_vertices *vertices, + isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user) +{ + int i; + isl_vertex *vertex; + + if (!vertices) + return isl_stat_error; + + if (vertices->n_vertices == 0) + return isl_stat_ok; + + for (i = 0; i < vertices->n_vertices; ++i) { + isl_stat r; + + vertex = isl_vertex_alloc(isl_vertices_copy(vertices), i); + if (!vertex) + return isl_stat_error; + + r = fn(vertex, user); + if (r < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +isl_stat isl_cell_foreach_vertex(__isl_keep isl_cell *cell, + isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user) +{ + int i; + isl_vertex *vertex; + + if (!cell) + return isl_stat_error; + + if (cell->n_vertices == 0) + return isl_stat_ok; + + for (i = 0; i < cell->n_vertices; ++i) { + isl_stat r; + + vertex = isl_vertex_alloc(isl_vertices_copy(cell->vertices), + cell->ids[i]); + if (!vertex) + return isl_stat_error; + + r = fn(vertex, user); + if (r < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +isl_ctx *isl_vertices_get_ctx(__isl_keep isl_vertices *vertices) +{ + return vertices ? vertices->bset->ctx : NULL; +} + +int isl_vertices_get_n_vertices(__isl_keep isl_vertices *vertices) +{ + return vertices ? vertices->n_vertices : -1; +} + +__isl_give isl_vertices *isl_morph_vertices(__isl_take isl_morph *morph, + __isl_take isl_vertices *vertices) +{ + int i; + isl_morph *param_morph = NULL; + + if (!morph || !vertices) + goto error; + + isl_assert(vertices->bset->ctx, vertices->ref == 1, goto error); + + param_morph = isl_morph_copy(morph); + param_morph = isl_morph_dom_params(param_morph); + param_morph = isl_morph_ran_params(param_morph); + + for (i = 0; i < vertices->n_vertices; ++i) { + vertices->v[i].dom = isl_morph_basic_set( + isl_morph_copy(param_morph), vertices->v[i].dom); + vertices->v[i].vertex = isl_morph_basic_set( + isl_morph_copy(morph), vertices->v[i].vertex); + if (!vertices->v[i].vertex) + goto error; + } + + for (i = 0; i < vertices->n_chambers; ++i) { + vertices->c[i].dom = isl_morph_basic_set( + isl_morph_copy(param_morph), vertices->c[i].dom); + if (!vertices->c[i].dom) + goto error; + } + + isl_morph_free(param_morph); + isl_morph_free(morph); + return vertices; +error: + isl_morph_free(param_morph); + isl_morph_free(morph); + isl_vertices_free(vertices); + return NULL; +} + +/* Construct a simplex isl_cell spanned by the vertices with indices in + * "simplex_ids" and "other_ids" and call "fn" on this isl_cell. + */ +static isl_stat call_on_simplex(__isl_keep isl_cell *cell, + int *simplex_ids, int n_simplex, int *other_ids, int n_other, + isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user) +{ + int i; + isl_ctx *ctx; + struct isl_cell *simplex; + + ctx = isl_cell_get_ctx(cell); + + simplex = isl_calloc_type(ctx, struct isl_cell); + if (!simplex) + return isl_stat_error; + simplex->vertices = isl_vertices_copy(cell->vertices); + if (!simplex->vertices) + goto error; + simplex->dom = isl_basic_set_copy(cell->dom); + if (!simplex->dom) + goto error; + simplex->n_vertices = n_simplex + n_other; + simplex->ids = isl_alloc_array(ctx, int, simplex->n_vertices); + if (!simplex->ids) + goto error; + + for (i = 0; i < n_simplex; ++i) + simplex->ids[i] = simplex_ids[i]; + for (i = 0; i < n_other; ++i) + simplex->ids[n_simplex + i] = other_ids[i]; + + return fn(simplex, user); +error: + isl_cell_free(simplex); + return isl_stat_error; +} + +/* Check whether the parametric vertex described by "vertex" + * lies on the facet corresponding to constraint "facet" of "bset". + * The isl_vec "v" is a temporary vector than can be used by this function. + * + * We eliminate the variables from the facet constraint using the + * equalities defining the vertex and check if the result is identical + * to zero. + * + * It would probably be better to keep track of the constraints defining + * a vertex during the vertex construction so that we could simply look + * it up here. + */ +static int vertex_on_facet(__isl_keep isl_basic_set *vertex, + __isl_keep isl_basic_set *bset, int facet, __isl_keep isl_vec *v) +{ + int i; + isl_int m; + + isl_seq_cpy(v->el, bset->ineq[facet], v->size); + + isl_int_init(m); + for (i = 0; i < vertex->n_eq; ++i) { + int k = isl_seq_last_non_zero(vertex->eq[i], v->size); + isl_seq_elim(v->el, vertex->eq[i], k, v->size, &m); + } + isl_int_clear(m); + + return isl_seq_first_non_zero(v->el, v->size) == -1; +} + +/* Triangulate the polytope spanned by the vertices with ids + * in "simplex_ids" and "other_ids" and call "fn" on each of + * the resulting simplices. + * If the input polytope is already a simplex, we simply call "fn". + * Otherwise, we pick a point from "other_ids" and add it to "simplex_ids". + * Then we consider each facet of "bset" that does not contain the point + * we just picked, but does contain some of the other points in "other_ids" + * and call ourselves recursively on the polytope spanned by the new + * "simplex_ids" and those points in "other_ids" that lie on the facet. + */ +static isl_stat triangulate(__isl_keep isl_cell *cell, __isl_keep isl_vec *v, + int *simplex_ids, int n_simplex, int *other_ids, int n_other, + isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user) +{ + int i, j, k; + int d, nparam; + int *ids; + isl_ctx *ctx; + isl_basic_set *vertex; + isl_basic_set *bset; + + ctx = isl_cell_get_ctx(cell); + d = isl_basic_set_dim(cell->vertices->bset, isl_dim_set); + nparam = isl_basic_set_dim(cell->vertices->bset, isl_dim_param); + + if (n_simplex + n_other == d + 1) + return call_on_simplex(cell, simplex_ids, n_simplex, + other_ids, n_other, fn, user); + + simplex_ids[n_simplex] = other_ids[0]; + vertex = cell->vertices->v[other_ids[0]].vertex; + bset = cell->vertices->bset; + + ids = isl_alloc_array(ctx, int, n_other - 1); + if (!ids) + goto error; + for (i = 0; i < bset->n_ineq; ++i) { + if (isl_seq_first_non_zero(bset->ineq[i] + 1 + nparam, d) == -1) + continue; + if (vertex_on_facet(vertex, bset, i, v)) + continue; + + for (j = 1, k = 0; j < n_other; ++j) { + isl_basic_set *ov; + ov = cell->vertices->v[other_ids[j]].vertex; + if (vertex_on_facet(ov, bset, i, v)) + ids[k++] = other_ids[j]; + } + if (k == 0) + continue; + + if (triangulate(cell, v, simplex_ids, n_simplex + 1, + ids, k, fn, user) < 0) + goto error; + } + free(ids); + + return isl_stat_ok; +error: + free(ids); + return isl_stat_error; +} + +/* Triangulate the given cell and call "fn" on each of the resulting + * simplices. + */ +isl_stat isl_cell_foreach_simplex(__isl_take isl_cell *cell, + isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user) +{ + int d, total; + int r; + isl_ctx *ctx; + isl_vec *v = NULL; + int *simplex_ids = NULL; + + if (!cell) + return isl_stat_error; + + d = isl_basic_set_dim(cell->vertices->bset, isl_dim_set); + total = isl_basic_set_total_dim(cell->vertices->bset); + + if (cell->n_vertices == d + 1) + return fn(cell, user); + + ctx = isl_cell_get_ctx(cell); + simplex_ids = isl_alloc_array(ctx, int, d + 1); + if (!simplex_ids) + goto error; + + v = isl_vec_alloc(ctx, 1 + total); + if (!v) + goto error; + + r = triangulate(cell, v, simplex_ids, 0, + cell->ids, cell->n_vertices, fn, user); + + isl_vec_free(v); + free(simplex_ids); + + isl_cell_free(cell); + + return r; +error: + free(simplex_ids); + isl_vec_free(v); + isl_cell_free(cell); + return isl_stat_error; +} Index: contrib/isl/isl_vertices_private.h =================================================================== --- /dev/null +++ contrib/isl/isl_vertices_private.h @@ -0,0 +1,71 @@ +#ifndef ISL_VERTICES_PRIVATE_H +#define ISL_VERTICES_PRIVATE_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct isl_morph; + +/* A parametric vertex. "vertex" contains the actual description + * of the vertex as a singleton parametric set. "dom" is the projection + * of "vertex" onto the parameter space, i.e., the activity domain + * of the vertex. + * During the construction of vertices and chambers, the activity domain + * of every parametric vertex is full-dimensional. + */ +struct isl_vertex { + isl_basic_set *dom; + isl_basic_set *vertex; +}; + +/* A chamber in the chamber decomposition. The indices of the "n_vertices" + * active vertices are stored in "vertices". + */ +struct isl_chamber { + int n_vertices; + int *vertices; + isl_basic_set *dom; +}; + +struct isl_vertices { + int ref; + + /* The rational basic set spanned by the vertices. */ + isl_basic_set *bset; + + int n_vertices; + struct isl_vertex *v; + + int n_chambers; + struct isl_chamber *c; +}; + +struct isl_cell { + int n_vertices; + int *ids; + isl_vertices *vertices; + isl_basic_set *dom; +}; + +struct isl_external_vertex { + isl_vertices *vertices; + int id; +}; + +isl_stat isl_vertices_foreach_disjoint_cell(__isl_keep isl_vertices *vertices, + isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user); +isl_stat isl_cell_foreach_simplex(__isl_take isl_cell *cell, + isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user); + +__isl_give isl_vertices *isl_morph_vertices(__isl_take struct isl_morph *morph, + __isl_take isl_vertices *vertices); + +#if defined(__cplusplus) +} +#endif + +#endif Index: contrib/isl/isl_yaml.h =================================================================== --- /dev/null +++ contrib/isl/isl_yaml.h @@ -0,0 +1,18 @@ +#ifndef ISL_YAML_H +#define ISL_YAML_H + +#define ISL_YAML_INDENT_FLOW -1 + +enum isl_yaml_state { + isl_yaml_none, + isl_yaml_mapping_first_key_start, + isl_yaml_mapping_key_start, + isl_yaml_mapping_key, + isl_yaml_mapping_val_start, + isl_yaml_mapping_val, + isl_yaml_sequence_first_start, + isl_yaml_sequence_start, + isl_yaml_sequence +}; + +#endif Index: contrib/isl/m4/ax_c___attribute__.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_c___attribute__.m4 @@ -0,0 +1,66 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_c___attribute__.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_C___ATTRIBUTE__ +# +# DESCRIPTION +# +# Provides a test for the compiler support of __attribute__ extensions. +# Defines HAVE___ATTRIBUTE__ if it is found. +# +# LICENSE +# +# Copyright (c) 2008 Stepan Kasal +# Copyright (c) 2008 Christian Haggstrom +# Copyright (c) 2008 Ryan McCabe +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 8 + +AC_DEFUN([AX_C___ATTRIBUTE__], [ + AC_CACHE_CHECK([for __attribute__], [ax_cv___attribute__], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + static void foo(void) __attribute__ ((unused)); + static void + foo(void) { + exit(1); + } + ]], [])], + [ax_cv___attribute__=yes], + [ax_cv___attribute__=no] + ) + ]) + if test "$ax_cv___attribute__" = "yes"; then + AC_DEFINE([HAVE___ATTRIBUTE__], 1, [define if your compiler has __attribute__]) + fi +]) Index: contrib/isl/m4/ax_cc_maxopt.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_cc_maxopt.m4 @@ -0,0 +1,188 @@ +# =========================================================================== +# http://www.nongnu.org/autoconf-archive/ax_cc_maxopt.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CC_MAXOPT +# +# DESCRIPTION +# +# Try to turn on "good" C optimization flags for various compilers and +# architectures, for some definition of "good". (In our case, good for +# FFTW and hopefully for other scientific codes. Modify as needed.) +# +# The user can override the flags by setting the CFLAGS environment +# variable. The user can also specify --enable-portable-binary in order to +# disable any optimization flags that might result in a binary that only +# runs on the host architecture. +# +# Note also that the flags assume that ANSI C aliasing rules are followed +# by the code (e.g. for gcc's -fstrict-aliasing), and that floating-point +# computations can be re-ordered as needed. +# +# Requires macros: AX_CHECK_COMPILER_FLAGS, AX_COMPILER_VENDOR, +# AX_GCC_ARCHFLAG, AX_GCC_X86_CPUID. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_CC_MAXOPT], +[ +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AX_COMPILER_VENDOR]) +AC_REQUIRE([AC_CANONICAL_HOST]) + +AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disable compiler optimizations that would produce unportable binaries])], + acx_maxopt_portable=$withval, acx_maxopt_portable=no) + +# Try to determine "good" native compiler flags if none specified via CFLAGS +if test "$ac_test_CFLAGS" != "set"; then + CFLAGS="" + case $ax_cv_c_compiler_vendor in + dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host" + if test "x$acx_maxopt_portable" = xno; then + CFLAGS="$CFLAGS -arch host" + fi;; + + sun) CFLAGS="-native -fast -xO5 -dalign" + if test "x$acx_maxopt_portable" = xyes; then + CFLAGS="$CFLAGS -xarch=generic" + fi;; + + hp) CFLAGS="+Oall +Optrs_ansi +DSnative" + if test "x$acx_maxopt_portable" = xyes; then + CFLAGS="$CFLAGS +DAportable" + fi;; + + ibm) if test "x$acx_maxopt_portable" = xno; then + xlc_opt="-qarch=auto -qtune=auto" + else + xlc_opt="-qtune=auto" + fi + AX_CHECK_COMPILER_FLAGS($xlc_opt, + CFLAGS="-O3 -qansialias -w $xlc_opt", + [CFLAGS="-O3 -qansialias -w" + echo "******************************************************" + echo "* You seem to have the IBM C compiler. It is *" + echo "* recommended for best performance that you use: *" + echo "* *" + echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *" + echo "* ^^^ ^^^ *" + echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" + echo "* CPU you have. (Set the CFLAGS environment var. *" + echo "* and re-run configure.) For more info, man cc. *" + echo "******************************************************"]) + ;; + + intel) CFLAGS="-O3 -ansi_alias" + if test "x$acx_maxopt_portable" = xno; then + icc_archflag=unknown + icc_flags="" + case $host_cpu in + i686*|x86_64*) + # icc accepts gcc assembly syntax, so these should work: + AX_GCC_X86_CPUID(0) + AX_GCC_X86_CPUID(1) + case $ax_cv_gcc_x86_cpuid_0 in # see AX_GCC_ARCHFLAG + *:756e6547:*:*) # Intel + case $ax_cv_gcc_x86_cpuid_1 in + *6a?:*[[234]]:*:*|*6[[789b]]?:*:*:*) icc_flags="-xK";; + *f3[[347]]:*:*:*|*f4[1347]:*:*:*) icc_flags="-xP -xN -xW -xK";; + *f??:*:*:*) icc_flags="-xN -xW -xK";; + esac ;; + esac ;; + esac + if test "x$icc_flags" != x; then + for flag in $icc_flags; do + AX_CHECK_COMPILER_FLAGS($flag, [icc_archflag=$flag; break]) + done + fi + AC_MSG_CHECKING([for icc architecture flag]) + AC_MSG_RESULT($icc_archflag) + if test "x$icc_archflag" != xunknown; then + CFLAGS="$CFLAGS $icc_archflag" + fi + fi + ;; + + gnu) + # default optimization flags for gcc on all systems + CFLAGS="-O3 -fomit-frame-pointer" + + # -malign-double for x86 systems + AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double") + + # -fstrict-aliasing for gcc-2.95+ + AX_CHECK_COMPILER_FLAGS(-fstrict-aliasing, + CFLAGS="$CFLAGS -fstrict-aliasing") + + # note that we enable "unsafe" fp optimization with other compilers, too + AX_CHECK_COMPILER_FLAGS(-ffast-math, CFLAGS="$CFLAGS -ffast-math") + + AX_GCC_ARCHFLAG($acx_maxopt_portable) + + # drop to -O1 for gcc 4.2 + $CC --version | + sed -e 's/.* \(@<:@0-9@:>@@<:@0-9@:>@*\)\.\(@<:@0-9@:>@@<:@0-9@:>@*\).*/\1 \2/' | + (read major minor + if test $major -eq 4 -a $minor -eq 2; then + exit 0 + fi + exit 1 + ) && CFLAGS="-O1" + ;; + esac + + if test -z "$CFLAGS"; then + echo "" + echo "********************************************************" + echo "* WARNING: Don't know the best CFLAGS for this system *" + echo "* Use ./configure CFLAGS=... to specify your own flags *" + echo "* (otherwise, a default of CFLAGS=-O3 will be used) *" + echo "********************************************************" + echo "" + CFLAGS="-O3" + fi + + AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [ + echo "" + echo "********************************************************" + echo "* WARNING: The guessed CFLAGS don't seem to work with *" + echo "* your compiler. *" + echo "* Use ./configure CFLAGS=... to specify your own flags *" + echo "********************************************************" + echo "" + CFLAGS="" + ]) + +fi +]) Index: contrib/isl/m4/ax_cflags_warn_all.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_cflags_warn_all.m4 @@ -0,0 +1,149 @@ +# =========================================================================== +# http://www.nongnu.org/autoconf-archive/ax_cflags_warn_all.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# +# DESCRIPTION +# +# Try to find a compiler option that enables most reasonable warnings. +# +# For the GNU CC compiler it will be -Wall (and -ansi -pedantic) The +# result is added to the shellvar being CFLAGS by default. +# +# Currently this macro knows about GCC, Solaris C compiler, Digital Unix C +# compiler, C for AIX Compiler, HP-UX C compiler, IRIX C compiler, NEC +# SX-5 (Super-UX 10) C compiler, and Cray J90 (Unicos 10.0.0.8) C +# compiler. +# +# - $1 shell-variable-to-add-to : CFLAGS +# - $2 add-value-if-not-found : nothing +# - $3 action-if-found : add value to shellvariable +# - $4 action-if-not-found : nothing +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl +AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], +VAR,[VAR="no, unknown" + AC_LANG_SAVE + AC_LANG_C + ac_save_[]FLAGS="$[]FLAGS" +for ac_arg dnl +in "-pedantic % -Wall" dnl GCC + "-xstrconst % -v" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix + "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + "-ansi -ansiE % -fullwarn" dnl IRIX + "+ESlit % +w1" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_TRY_COMPILE([],[return 0;], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done + FLAGS="$ac_save_[]FLAGS" + AC_LANG_RESTORE +]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ + AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; + *) m4_ifvaln($3,$3,[ + if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null + then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) + else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" + fi ]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +AS_VAR_POPDEF([FLAGS])dnl +]) + +dnl the only difference - the LANG selection... and the default FLAGS + +AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl +AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ax_cv_cxxflags_warn_all])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], +VAR,[VAR="no, unknown" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_[]FLAGS="$[]FLAGS" +for ac_arg dnl +in "-pedantic % -Wall" dnl GCC + "-xstrconst % -v" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix + "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + "-ansi -ansiE % -fullwarn" dnl IRIX + "+ESlit % +w1" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_TRY_COMPILE([],[return 0;], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done + FLAGS="$ac_save_[]FLAGS" + AC_LANG_RESTORE +]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ + AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; + *) m4_ifvaln($3,$3,[ + if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null + then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) + else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" + fi ]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +AS_VAR_POPDEF([FLAGS])dnl +]) + +dnl implementation tactics: +dnl the for-argument contains a list of options. The first part of +dnl these does only exist to detect the compiler - usually it is +dnl a global option to enable -ansi or -extrawarnings. All other +dnl compilers will fail about it. That was needed since a lot of +dnl compilers will give false positives for some option-syntax +dnl like -Woption or -Xoption as they think of it is a pass-through +dnl to later compile stages or something. The "%" is used as a +dnl delimimiter. A non-option comment can be given after "%%" marks +dnl which will be shown but not added to the respective C/CXXFLAGS. Index: contrib/isl/m4/ax_check_compiler_flags.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_check_compiler_flags.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.nongnu.org/autoconf-archive/ax_check_compiler_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE]) +# +# DESCRIPTION +# +# Check whether the given compiler FLAGS work with the current language's +# compiler, or whether they give an error. (Warnings, however, are +# ignored.) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# LICENSE +# +# Copyright (c) 2009 Steven G. Johnson +# Copyright (c) 2009 Matteo Frigo +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_CHECK_COMPILER_FLAGS], +[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX +AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1]) +dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname: +AS_LITERAL_IF([$1], + [AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1]), [ + ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=yes, + AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=no) + _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])], + [ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=yes, + eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=no) + _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS]) +eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1]) +AC_MSG_RESULT($ax_check_compiler_flags) +if test "x$ax_check_compiler_flags" = xyes; then + m4_default([$2], :) +else + m4_default([$3], :) +fi +])dnl AX_CHECK_COMPILER_FLAGS Index: contrib/isl/m4/ax_compiler_vendor.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_compiler_vendor.m4 @@ -0,0 +1,63 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_VENDOR +# +# DESCRIPTION +# +# Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, +# hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, +# watcom, etc. The vendor is returned in the cache variable +# $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 9 + +AC_DEFUN([AX_COMPILER_VENDOR], +[ +AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, + [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown + # note: don't check for gcc first since some other compilers define __GNUC__ + for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale:__PATHCC__,__PATHSCALE__ clang:__clang__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do + vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ +#if !($vencpp) + thisisanerror; +#endif +])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break]) + done + ]) +]) Index: contrib/isl/m4/ax_create_pkgconfig_info.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_create_pkgconfig_info.m4 @@ -0,0 +1,351 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_create_pkgconfig_info.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CREATE_PKGCONFIG_INFO [(outputfile, [requires [,libs [,summary [,cflags [, ldflags]]]]])] +# +# DESCRIPTION +# +# Defaults: +# +# $1 = $PACKAGE_NAME.pc +# $2 = (empty) +# $3 = $PACKAGE_LIBS $LIBS (as set at that point in configure.ac) +# $4 = $PACKAGE_SUMMARY (or $1 Library) +# $5 = $PACKAGE_CFLAGS (as set at the point in configure.ac) +# $6 = $PACKAGE_LDFLAGS (as set at the point in configure.ac) +# +# PACKAGE_NAME defaults to $PACKAGE if not set. +# PACKAGE_LIBS defaults to -l$PACKAGE_NAME if not set. +# +# The resulting file is called $PACKAGE.pc.in / $PACKAGE.pc +# +# You will find this macro most useful in conjunction with +# ax_spec_defaults that can read good initializers from the .spec file. In +# consequencd, most of the generatable installable stuff can be made from +# information being updated in a single place for the whole project. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2008 Sven Verdoolaege +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 12 + +AC_DEFUN([AX_CREATE_PKGCONFIG_INFO],[dnl +AS_VAR_PUSHDEF([PKGCONFIG_suffix],[ax_create_pkgconfig_suffix])dnl +AS_VAR_PUSHDEF([PKGCONFIG_libdir],[ax_create_pkgconfig_libdir])dnl +AS_VAR_PUSHDEF([PKGCONFIG_libfile],[ax_create_pkgconfig_libfile])dnl +AS_VAR_PUSHDEF([PKGCONFIG_libname],[ax_create_pkgconfig_libname])dnl +AS_VAR_PUSHDEF([PKGCONFIG_version],[ax_create_pkgconfig_version])dnl +AS_VAR_PUSHDEF([PKGCONFIG_description],[ax_create_pkgconfig_description])dnl +AS_VAR_PUSHDEF([PKGCONFIG_requires],[ax_create_pkgconfig_requires])dnl +AS_VAR_PUSHDEF([PKGCONFIG_pkglibs],[ax_create_pkgconfig_pkglibs])dnl +AS_VAR_PUSHDEF([PKGCONFIG_libs],[ax_create_pkgconfig_libs])dnl +AS_VAR_PUSHDEF([PKGCONFIG_ldflags],[ax_create_pkgconfig_ldflags])dnl +AS_VAR_PUSHDEF([PKGCONFIG_cppflags],[ax_create_pkgconfig_cppflags])dnl +AS_VAR_PUSHDEF([PKGCONFIG_generate],[ax_create_pkgconfig_generate])dnl +AS_VAR_PUSHDEF([PKGCONFIG_src_libdir],[ax_create_pkgconfig_src_libdir])dnl +AS_VAR_PUSHDEF([PKGCONFIG_src_headers],[ax_create_pkgconfig_src_headers])dnl + +# we need the expanded forms... +test "x$prefix" = xNONE && prefix=$ac_default_prefix +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +AC_MSG_CHECKING(our pkgconfig libname) +test ".$PKGCONFIG_libname" != "." || \ +PKGCONFIG_libname="ifelse($1,,${PACKAGE_NAME},`basename $1 .pc`)" +test ".$PKGCONFIG_libname" != "." || \ +PKGCONFIG_libname="$PACKAGE" +PKGCONFIG_libname=`eval echo "$PKGCONFIG_libname"` +PKGCONFIG_libname=`eval echo "$PKGCONFIG_libname"` +AC_MSG_RESULT($PKGCONFIG_libname) + +AC_MSG_CHECKING(our pkgconfig version) +test ".$PKGCONFIG_version" != "." || \ +PKGCONFIG_version="${PACKAGE_VERSION}" +test ".$PKGCONFIG_version" != "." || \ +PKGCONFIG_version="$VERSION" +PKGCONFIG_version=`eval echo "$PKGCONFIG_version"` +PKGCONFIG_version=`eval echo "$PKGCONFIG_version"` +AC_MSG_RESULT($PKGCONFIG_version) + +AC_MSG_CHECKING(our pkgconfig_libdir) +test ".$pkgconfig_libdir" = "." && \ +pkgconfig_libdir='${libdir}/pkgconfig' +PKGCONFIG_libdir=`eval echo "$pkgconfig_libdir"` +PKGCONFIG_libdir=`eval echo "$PKGCONFIG_libdir"` +PKGCONFIG_libdir=`eval echo "$PKGCONFIG_libdir"` +AC_MSG_RESULT($pkgconfig_libdir) +test "$pkgconfig_libdir" != "$PKGCONFIG_libdir" && ( +AC_MSG_RESULT(expanded our pkgconfig_libdir... $PKGCONFIG_libdir)) +AC_SUBST([pkgconfig_libdir]) + +AC_MSG_CHECKING(our pkgconfig_libfile) +test ".$pkgconfig_libfile" != "." || \ +pkgconfig_libfile="ifelse($1,,$PKGCONFIG_libname.pc,`basename $1`)" +PKGCONFIG_libfile=`eval echo "$pkgconfig_libfile"` +PKGCONFIG_libfile=`eval echo "$PKGCONFIG_libfile"` +AC_MSG_RESULT($pkgconfig_libfile) +test "$pkgconfig_libfile" != "$PKGCONFIG_libfile" && ( +AC_MSG_RESULT(expanded our pkgconfig_libfile... $PKGCONFIG_libfile)) +AC_SUBST([pkgconfig_libfile]) + +AC_MSG_CHECKING(our package / suffix) +PKGCONFIG_suffix="$program_suffix" +test ".$PKGCONFIG_suffix" != .NONE || PKGCONFIG_suffix="" +AC_MSG_RESULT(${PACKAGE_NAME} / ${PKGCONFIG_suffix}) + +AC_MSG_CHECKING(our pkgconfig description) +PKGCONFIG_description="ifelse($4,,$PACKAGE_SUMMARY,$4)" +test ".$PKGCONFIG_description" != "." || \ +PKGCONFIG_description="$PKGCONFIG_libname Library" +PKGCONFIG_description=`eval echo "$PKGCONFIG_description"` +PKGCONFIG_description=`eval echo "$PKGCONFIG_description"` +AC_MSG_RESULT($PKGCONFIG_description) + +AC_MSG_CHECKING(our pkgconfig requires) +PKGCONFIG_requires="ifelse($2,,$PACKAGE_REQUIRES,$2)" +PKGCONFIG_requires=`eval echo "$PKGCONFIG_requires"` +PKGCONFIG_requires=`eval echo "$PKGCONFIG_requires"` +AC_MSG_RESULT($PKGCONFIG_requires) + +AC_MSG_CHECKING(our pkgconfig ext libs) +PKGCONFIG_pkglibs="$PACKAGE_LIBS" +test ".$PKGCONFIG_pkglibs" != "." || PKGCONFIG_pkglibs="-l$PKGCONFIG_libname" +PKGCONFIG_libs="ifelse($3,,$PKGCONFIG_pkglibs $LIBS,$3)" +PKGCONFIG_libs=`eval echo "$PKGCONFIG_libs"` +PKGCONFIG_libs=`eval echo "$PKGCONFIG_libs"` +AC_MSG_RESULT($PKGCONFIG_libs) + +AC_MSG_CHECKING(our pkgconfig cppflags) +PKGCONFIG_cppflags="ifelse($5,,$PACKAGE_CFLAGS,$5)" +PKGCONFIG_cppflags=`eval echo "$PKGCONFIG_cppflags"` +PKGCONFIG_cppflags=`eval echo "$PKGCONFIG_cppflags"` +AC_MSG_RESULT($PKGCONFIG_cppflags) + +AC_MSG_CHECKING(our pkgconfig ldflags) +PKGCONFIG_ldflags="ifelse($6,,$PACKAGE_LDFLAGS,$5)" +PKGCONFIG_ldflags=`eval echo "$PKGCONFIG_ldflags"` +PKGCONFIG_ldflags=`eval echo "$PKGCONFIG_ldflags"` +AC_MSG_RESULT($PKGCONFIG_ldflags) + +test ".$PKGCONFIG_generate" != "." || \ +PKGCONFIG_generate="ifelse($1,,$PKGCONFIG_libname.pc,$1)" +PKGCONFIG_generate=`eval echo "$PKGCONFIG_generate"` +PKGCONFIG_generate=`eval echo "$PKGCONFIG_generate"` +test "$pkgconfig_libfile" != "$PKGCONFIG_generate" && ( +AC_MSG_RESULT(generate the pkgconfig later... $PKGCONFIG_generate)) + +if test ".$PKGCONFIG_src_libdir" = "." ; then +PKGCONFIG_src_libdir=`pwd` +PKGCONFIG_src_libdir=`AS_DIRNAME("$PKGCONFIG_src_libdir/$PKGCONFIG_generate")` +test ! -d $PKGCONFIG_src_libdir/src || \ +PKGCONFIG_src_libdir="$PKGCONFIG_src_libdir/src" +case ".$objdir" in +*libs) PKGCONFIG_src_libdir="$PKGCONFIG_src_libdir/$objdir" ;; esac +AC_MSG_RESULT(noninstalled pkgconfig -L $PKGCONFIG_src_libdir) +fi + +if test ".$PKGCONFIG_src_headers" = "." ; then +PKGCONFIG_src_headers=`pwd` +v="$ac_top_srcdir" ; +test ".$v" != "." || v="$ax_spec_dir" +test ".$v" != "." || v="$srcdir" +case "$v" in /*) PKGCONFIG_src_headers="" ;; esac +PKGCONFIG_src_headers=`AS_DIRNAME("$PKGCONFIG_src_headers/$v/x")` +test ! -d $PKGCONFIG_src_headers/incl[]ude || \ +PKGCONFIG_src_headers="$PKGCONFIG_src_headers/incl[]ude" +AC_MSG_RESULT(noninstalled pkgconfig -I $PKGCONFIG_src_headers) +fi + + +dnl AC_CONFIG_COMMANDS crap disallows to use $PKGCONFIG_libfile here... +AC_CONFIG_COMMANDS([$ax_create_pkgconfig_generate],[ +pkgconfig_generate="$ax_create_pkgconfig_generate" +if test ! -f "$pkgconfig_generate.in" +then generate="true" +elif grep ' generated by configure ' $pkgconfig_generate.in >/dev/null +then generate="true" +else generate="false"; +fi +if $generate ; then +AC_MSG_NOTICE(creating $pkgconfig_generate.in) +cat > $pkgconfig_generate.in <conftest.sed < $pkgconfig_generate +if test ! -s $pkgconfig_generate ; then + AC_MSG_ERROR([$pkgconfig_generate is empty]) +fi ; rm conftest.sed # DONE generate $pkgconfig_generate +pkgconfig_uninstalled=`echo $pkgconfig_generate |sed 's/.pc$/-uninstalled.pc/'` +AC_MSG_NOTICE(creating $pkgconfig_uninstalled) +cat >conftest.sed < $pkgconfig_uninstalled +if test ! -s $pkgconfig_uninstalled ; then + AC_MSG_ERROR([$pkgconfig_uninstalled is empty]) +fi ; rm conftest.sed # DONE generate $pkgconfig_uninstalled + pkgconfig_requires_add=`echo ${pkgconfig_requires}` +if test ".$pkgconfig_requires_add" != "." ; then + pkgconfig_requires_add="pkg-config $pkgconfig_requires_add" + else pkgconfig_requires_add=":" ; fi +pkgconfig_uninstalled=`echo $pkgconfig_generate |sed 's/.pc$/-uninstalled.sh/'` +AC_MSG_NOTICE(creating $pkgconfig_uninstalled) +cat >conftest.sed <Name:>for option\\; do case \"\$option\" in --list-all|--name) echo > +s>Description: *>\\;\\; --help) pkg-config --help \\; echo Buildscript Of > +s>Version: *>\\;\\; --modversion|--version) echo > +s>Requires:>\\;\\; --requires) echo $pkgconfig_requires_add> +s>Libs: *>\\;\\; --libs) echo > +s>Cflags: *>\\;\\; --cflags) echo > +/--libs)/a\\ + $pkgconfig_requires_add +/--cflags)/a\\ + $pkgconfig_requires_add\\ +;; --variable=*) eval echo '\$'\`echo \$option | sed -e 's/.*=//'\`\\ +;; --uninstalled) exit 0 \\ +;; *) ;; esac done +AXEOF +sed -f conftest.sed $pkgconfig_generate.in > $pkgconfig_uninstalled +if test ! -s $pkgconfig_uninstalled ; then + AC_MSG_ERROR([$pkgconfig_uninstalled is empty]) +fi ; rm conftest.sed # DONE generate $pkgconfig_uninstalled +],[ +dnl AC_CONFIG_COMMANDS crap, the AS_PUSHVAR defines are invalid here... +ax_create_pkgconfig_generate="$ax_create_pkgconfig_generate" +pkgconfig_prefix='$prefix' +pkgconfig_execprefix='$exec_prefix' +pkgconfig_bindir='$bindir' +pkgconfig_libdir='$libdir' +pkgconfig_includedir='$includedir' +pkgconfig_datarootdir='$datarootdir' +pkgconfig_datadir='$datadir' +pkgconfig_sysconfdir='$sysconfdir' +pkgconfig_suffix='$ax_create_pkgconfig_suffix' +pkgconfig_package='$PACKAGE_NAME' +pkgconfig_libname='$ax_create_pkgconfig_libname' +pkgconfig_description='$ax_create_pkgconfig_description' +pkgconfig_version='$ax_create_pkgconfig_version' +pkgconfig_requires='$ax_create_pkgconfig_requires' +pkgconfig_libs='$ax_create_pkgconfig_libs' +pkgconfig_ldflags='$ax_create_pkgconfig_ldflags' +pkgconfig_cppflags='$ax_create_pkgconfig_cppflags' +pkgconfig_src_libdir='$ax_create_pkgconfig_src_libdir' +pkgconfig_src_headers='$ax_create_pkgconfig_src_headers' +])dnl +AS_VAR_POPDEF([PKGCONFIG_suffix])dnl +AS_VAR_POPDEF([PKGCONFIG_libdir])dnl +AS_VAR_POPDEF([PKGCONFIG_libfile])dnl +AS_VAR_POPDEF([PKGCONFIG_libname])dnl +AS_VAR_POPDEF([PKGCONFIG_version])dnl +AS_VAR_POPDEF([PKGCONFIG_description])dnl +AS_VAR_POPDEF([PKGCONFIG_requires])dnl +AS_VAR_POPDEF([PKGCONFIG_pkglibs])dnl +AS_VAR_POPDEF([PKGCONFIG_libs])dnl +AS_VAR_POPDEF([PKGCONFIG_ldflags])dnl +AS_VAR_POPDEF([PKGCONFIG_cppflags])dnl +AS_VAR_POPDEF([PKGCONFIG_generate])dnl +AS_VAR_POPDEF([PKGCONFIG_src_libdir])dnl +AS_VAR_POPDEF([PKGCONFIG_src_headers])dnl +]) Index: contrib/isl/m4/ax_create_stdint_h.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_create_stdint_h.m4 @@ -0,0 +1,739 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_create_stdint_h.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] +# +# DESCRIPTION +# +# the "ISO C9X: 7.18 Integer types " section requires the +# existence of an include file that defines a set of typedefs, +# especially uint8_t,int32_t,uintptr_t. Many older installations will not +# provide this file, but some will have the very same definitions in +# . In other enviroments we can use the inet-types in +# which would define the typedefs int8_t and u_int8_t +# respectivly. +# +# This macros will create a local "_stdint.h" or the headerfile given as +# an argument. In many cases that file will just "#include " or +# "#include ", while in other environments it will provide the +# set of basic 'stdint's definitions/typedefs: +# +# int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t +# int_least32_t.. int_fast32_t.. intmax_t +# +# which may or may not rely on the definitions of other files, or using +# the AC_CHECK_SIZEOF macro to determine the actual sizeof each type. +# +# if your header files require the stdint-types you will want to create an +# installable file mylib-int.h that all your other installable header may +# include. So if you have a library package named "mylib", just use +# +# AX_CREATE_STDINT_H(mylib-int.h) +# +# in configure.ac and go to install that very header file in Makefile.am +# along with the other headers (mylib.h) - and the mylib-specific headers +# can simply use "#include " to obtain the stdint-types. +# +# Remember, if the system already had a valid , the generated +# file will include it directly. No need for fuzzy HAVE_STDINT_H things... +# (oops, GCC 4.2.x has deliberatly disabled its stdint.h for non-c99 +# compilation and the c99-mode is not the default. Therefore this macro +# will not use the compiler's stdint.h - please complain to the GCC +# developers). +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_CHECK_DATA_MODEL],[ + AC_CHECK_SIZEOF(char) + AC_CHECK_SIZEOF(short) + AC_CHECK_SIZEOF(int) + AC_CHECK_SIZEOF(long) + AC_CHECK_SIZEOF(void*) + ac_cv_char_data_model="" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_char" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_short" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_int" + ac_cv_long_data_model="" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_int" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_long" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_voidp" + AC_MSG_CHECKING([data model]) + case "$ac_cv_char_data_model/$ac_cv_long_data_model" in + 122/242) ac_cv_data_model="IP16" ; n="standard 16bit machine" ;; + 122/244) ac_cv_data_model="LP32" ; n="standard 32bit machine" ;; + 122/*) ac_cv_data_model="i16" ; n="unusual int16 model" ;; + 124/444) ac_cv_data_model="ILP32" ; n="standard 32bit unixish" ;; + 124/488) ac_cv_data_model="LP64" ; n="standard 64bit unixish" ;; + 124/448) ac_cv_data_model="LLP64" ; n="unusual 64bit unixish" ;; + 124/*) ac_cv_data_model="i32" ; n="unusual int32 model" ;; + 128/888) ac_cv_data_model="ILP64" ; n="unusual 64bit numeric" ;; + 128/*) ac_cv_data_model="i64" ; n="unusual int64 model" ;; + 222/*2) ac_cv_data_model="DSP16" ; n="strict 16bit dsptype" ;; + 333/*3) ac_cv_data_model="DSP24" ; n="strict 24bit dsptype" ;; + 444/*4) ac_cv_data_model="DSP32" ; n="strict 32bit dsptype" ;; + 666/*6) ac_cv_data_model="DSP48" ; n="strict 48bit dsptype" ;; + 888/*8) ac_cv_data_model="DSP64" ; n="strict 64bit dsptype" ;; + 222/*|333/*|444/*|666/*|888/*) : + ac_cv_data_model="iDSP" ; n="unusual dsptype" ;; + *) ac_cv_data_model="none" ; n="very unusual model" ;; + esac + AC_MSG_RESULT([$ac_cv_data_model ($ac_cv_long_data_model, $n)]) +]) + +dnl AX_CHECK_HEADER_STDINT_X([HEADERLIST][,ACTION-IF]) +AC_DEFUN([AX_CHECK_HEADER_STDINT_X],[ +AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[ + ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[stdint.h inttypes.h sys/inttypes.h sys/types.h]) + do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uintptr_t,[ac_cv_header_stdint_x=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + done + AC_MSG_CHECKING([for stdint uintptr_t]) + ]) +]) + +AC_DEFUN([AX_CHECK_HEADER_STDINT_O],[ +AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[ + ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[inttypes.h sys/inttypes.h sys/types.h stdint.h]) + do + unset ac_cv_type_uint32_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + break; + done + AC_MSG_CHECKING([for stdint uint32_t]) + ]) +]) + +AC_DEFUN([AX_CHECK_HEADER_STDINT_U],[ +AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[ + ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[sys/types.h inttypes.h sys/inttypes.h]) ; do + unset ac_cv_type_u_int32_t + unset ac_cv_type_u_int64_t + AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + break; + done + AC_MSG_CHECKING([for stdint u_int32_t]) + ]) +]) + +AC_DEFUN([AX_CREATE_STDINT_H], +[# ------ AX CREATE STDINT H ------------------------------------- +AC_MSG_CHECKING([for stdint types]) +ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` +# try to shortcircuit - if the default include path of the compiler +# can find a "stdint.h" header then we assume that all compilers can. +AC_CACHE_VAL([ac_cv_header_stdint_t],[ +old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS="" +old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="" +old_CFLAGS="$CFLAGS" ; CFLAGS="" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[ac_cv_stdint_result="(assuming C99 compatible system)" + ac_cv_header_stdint_t="stdint.h"; ], +[ac_cv_header_stdint_t=""]) +if test "$GCC" = "yes" && test ".$ac_cv_header_stdint_t" = "."; then +CFLAGS="-std=c99" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[AC_MSG_WARN(your GCC compiler has a defunct stdint.h for its default-mode)]) +fi +CXXFLAGS="$old_CXXFLAGS" +CPPFLAGS="$old_CPPFLAGS" +CFLAGS="$old_CFLAGS" ]) + +v="... $ac_cv_header_stdint_h" +if test "$ac_stdint_h" = "stdint.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)]) +elif test "$ac_stdint_h" = "inttypes.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)]) +elif test "_$ac_cv_header_stdint_t" = "_" ; then + AC_MSG_RESULT([(putting them into $ac_stdint_h)$v]) +else + ac_cv_header_stdint="$ac_cv_header_stdint_t" + AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)]) +fi + +if test "_$ac_cv_header_stdint_t" = "_" ; then # can not shortcircuit.. + +dnl .....intro message done, now do a few system checks..... +dnl btw, all old CHECK_TYPE macros do automatically "DEFINE" a type, +dnl therefore we use the autoconf implementation detail CHECK_TYPE_NEW +dnl instead that is triggered with 3 or more arguments (see types.m4) + +inttype_headers=`echo $2 | sed -e 's/,/ /g'` + +ac_cv_stdint_result="(no helpful system typedefs seen)" +AX_CHECK_HEADER_STDINT_X(dnl + stdint.h inttypes.h sys/inttypes.h $inttype_headers, + ac_cv_stdint_result="(seen uintptr_t$and64 in $i)") + +if test "_$ac_cv_header_stdint_x" = "_" ; then +AX_CHECK_HEADER_STDINT_O(dnl, + inttypes.h sys/inttypes.h stdint.h $inttype_headers, + ac_cv_stdint_result="(seen uint32_t$and64 in $i)") +fi + +if test "_$ac_cv_header_stdint_x" = "_" ; then +if test "_$ac_cv_header_stdint_o" = "_" ; then +AX_CHECK_HEADER_STDINT_U(dnl, + sys/types.h inttypes.h sys/inttypes.h $inttype_headers, + ac_cv_stdint_result="(seen u_int32_t$and64 in $i)") +fi fi + +dnl if there was no good C99 header file, do some typedef checks... +if test "_$ac_cv_header_stdint_x" = "_" ; then + AC_MSG_CHECKING([for stdint datatype model]) + AC_MSG_RESULT([(..)]) + AX_CHECK_DATA_MODEL +fi + +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_x" +elif test "_$ac_cv_header_stdint_o" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_o" +elif test "_$ac_cv_header_stdint_u" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_u" +else + ac_cv_header_stdint="stddef.h" +fi + +AC_MSG_CHECKING([for extra inttypes in chosen header]) +AC_MSG_RESULT([($ac_cv_header_stdint)]) +dnl see if int_least and int_fast types are present in _this_ header. +unset ac_cv_type_int_least32_t +unset ac_cv_type_int_fast32_t +AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) +AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) +AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>]) + +fi # shortcircut to system "stdint.h" +# ------------------ PREPARE VARIABLES ------------------------------ +if test "$GCC" = "yes" ; then +ac_cv_stdint_message="using gnu compiler "`$CC --version | head -1` +else +ac_cv_stdint_message="using $CC" +fi + +AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl +$ac_cv_stdint_result]) + +dnl ----------------------------------------------------------------- +# ----------------- DONE inttypes.h checks START header ------------- +AC_CONFIG_COMMANDS([$ac_stdint_h],[ +AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h) +ac_stdint=$tmp/_stdint.h + +echo "#ifndef" $_ac_stdint_h >$ac_stdint +echo "#define" $_ac_stdint_h "1" >>$ac_stdint +echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint +echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint +echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint +if test "_$ac_cv_header_stdint_t" != "_" ; then +echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint +echo "#include " >>$ac_stdint +echo "#endif" >>$ac_stdint +echo "#endif" >>$ac_stdint +else + +cat >>$ac_stdint < +#else +#include + +/* .................... configured part ............................ */ + +STDINT_EOF + +echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_header="$ac_cv_header_stdint_x" + echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint +fi + +echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_o" != "_" ; then + ac_header="$ac_cv_header_stdint_o" + echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint +fi + +echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint +if test "_$ac_cv_header_stdint_u" != "_" ; then + ac_header="$ac_cv_header_stdint_u" + echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint +fi + +echo "" >>$ac_stdint + +if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then + echo "#include <$ac_header>" >>$ac_stdint + echo "" >>$ac_stdint +fi fi + +echo "/* which 64bit typedef has been found */" >>$ac_stdint +if test "$ac_cv_type_uint64_t" = "yes" ; then +echo "#define _STDINT_HAVE_UINT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint +fi +if test "$ac_cv_type_u_int64_t" = "yes" ; then +echo "#define _STDINT_HAVE_U_INT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* which type model has been detected */" >>$ac_stdint +if test "_$ac_cv_char_data_model" != "_" ; then +echo "#define _STDINT_CHAR_MODEL" "$ac_cv_char_data_model" >>$ac_stdint +echo "#define _STDINT_LONG_MODEL" "$ac_cv_long_data_model" >>$ac_stdint +else +echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint +echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* whether int_least types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_least32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_LEAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint +fi +echo "/* whether int_fast types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_fast32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint +fi +echo "/* whether intmax_t type was detected */" >>$ac_stdint +if test "$ac_cv_type_intmax_t" = "yes"; then +echo "#define _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + + cat >>$ac_stdint <= 199901L +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#elif !defined __STRICT_ANSI__ +#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ +#define _HAVE_UINT64_T +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ +/* note: all ELF-systems seem to have loff-support which needs 64-bit */ +#if !defined _NO_LONGLONG +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +#elif defined __alpha || (defined __mips && defined _ABIN32) +#if !defined _NO_LONGLONG +typedef long int64_t; +typedef unsigned long uint64_t; +#endif + /* compiler/cpu type to define int64_t */ +#endif +#endif +#endif + +#if defined _STDINT_HAVE_U_INT_TYPES +/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ +typedef u_int8_t uint8_t; +typedef u_int16_t uint16_t; +typedef u_int32_t uint32_t; + +/* glibc compatibility */ +#ifndef __int8_t_defined +#define __int8_t_defined +#endif +#endif + +#ifdef _STDINT_NEED_INT_MODEL_T +/* we must guess all the basic types. Apart from byte-adressable system, */ +/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ +/* (btw, those nibble-addressable systems are way off, or so we assume) */ + +dnl /* have a look at "64bit and data size neutrality" at */ +dnl /* http://unix.org/version2/whatsnew/login_64bit.html */ +dnl /* (the shorthand "ILP" types always have a "P" part) */ + +#if defined _STDINT_BYTE_MODEL +#if _STDINT_LONG_MODEL+0 == 242 +/* 2:4:2 = IP16 = a normal 16-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 +/* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ +/* 4:4:4 = ILP32 = a normal 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 +/* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ +/* 4:8:8 = LP64 = a normal 64-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* this system has a "long" of 64bit */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +typedef unsigned long uint64_t; +typedef long int64_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 448 +/* LLP64 a 64-bit system derived from a 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* assuming the system has a "long long" */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef unsigned long long uint64_t; +typedef long long int64_t; +#endif +#else +#define _STDINT_NO_INT32_T +#endif +#else +#define _STDINT_NO_INT8_T +#define _STDINT_NO_INT32_T +#endif +#endif + +/* + * quote from SunOS-5.8 sys/inttypes.h: + * Use at your own risk. As of February 1996, the committee is squarely + * behind the fixed sized types; the "least" and "fast" types are still being + * discussed. The probability that the "fast" types may be removed before + * the standard is finalized is high enough that they are not currently + * implemented. + */ + +#if defined _STDINT_NEED_INT_LEAST_T +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_least64_t; +#endif + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_least64_t; +#endif + /* least types */ +#endif + +#if defined _STDINT_NEED_INT_FAST_T +typedef int8_t int_fast8_t; +typedef int int_fast16_t; +typedef int32_t int_fast32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_fast64_t; +#endif + +typedef uint8_t uint_fast8_t; +typedef unsigned uint_fast16_t; +typedef uint32_t uint_fast32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_fast64_t; +#endif + /* fast types */ +#endif + +#ifdef _STDINT_NEED_INTMAX_T +#ifdef _HAVE_UINT64_T +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; +#else +typedef long intmax_t; +typedef unsigned long uintmax_t; +#endif +#endif + +#ifdef _STDINT_NEED_INTPTR_T +#ifndef __intptr_t_defined +#define __intptr_t_defined +/* we encourage using "long" to store pointer values, never use "int" ! */ +#if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 +typedef unsigned int uintptr_t; +typedef int intptr_t; +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 +typedef unsigned long uintptr_t; +typedef long intptr_t; +#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T +typedef uint64_t uintptr_t; +typedef int64_t intptr_t; +#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ +typedef unsigned long uintptr_t; +typedef long intptr_t; +#endif +#endif +#endif + +/* The ISO C99 standard specifies that in C++ implementations these + should only be defined if explicitly requested. */ +#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS +#ifndef UINT32_C + +/* Signed. */ +# define INT8_C(c) c +# define INT16_C(c) c +# define INT32_C(c) c +# ifdef _HAVE_LONGLONG_UINT64_T +# define INT64_C(c) c ## L +# else +# define INT64_C(c) c ## LL +# endif + +/* Unsigned. */ +# define UINT8_C(c) c ## U +# define UINT16_C(c) c ## U +# define UINT32_C(c) c ## U +# ifdef _HAVE_LONGLONG_UINT64_T +# define UINT64_C(c) c ## UL +# else +# define UINT64_C(c) c ## ULL +# endif + +/* Maximal type. */ +# ifdef _HAVE_LONGLONG_UINT64_T +# define INTMAX_C(c) c ## L +# define UINTMAX_C(c) c ## UL +# else +# define INTMAX_C(c) c ## LL +# define UINTMAX_C(c) c ## ULL +# endif + + /* literalnumbers */ +#endif +#endif + +/* These limits are merily those of a two complement byte-oriented system */ + +/* Minimum of signed integral types. */ +# define INT8_MIN (-128) +# define INT16_MIN (-32767-1) +# define INT32_MIN (-2147483647-1) +#ifndef INT64_MIN +# define INT64_MIN (-__INT64_C(9223372036854775807)-1) +#endif +/* Maximum of signed integral types. */ +# define INT8_MAX (127) +# define INT16_MAX (32767) +# define INT32_MAX (2147483647) +#ifndef INT64_MAX +# define INT64_MAX (__INT64_C(9223372036854775807)) +#endif + +/* Maximum of unsigned integral types. */ +#ifndef UINT8_MAX +# define UINT8_MAX (255) +#endif +#ifndef UINT16_MAX +# define UINT16_MAX (65535) +#endif +# define UINT32_MAX (4294967295U) +#ifndef UINT64_MAX +# define UINT64_MAX (__UINT64_C(18446744073709551615)) +#endif + +/* Minimum of signed integral types having a minimum size. */ +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST32_MIN INT32_MIN +# define INT_LEAST64_MIN INT64_MIN +/* Maximum of signed integral types having a minimum size. */ +# define INT_LEAST8_MAX INT8_MAX +# define INT_LEAST16_MAX INT16_MAX +# define INT_LEAST32_MAX INT32_MAX +# define INT_LEAST64_MAX INT64_MAX + +/* Maximum of unsigned integral types having a minimum size. */ +# define UINT_LEAST8_MAX UINT8_MAX +# define UINT_LEAST16_MAX UINT16_MAX +# define UINT_LEAST32_MAX UINT32_MAX +# define UINT_LEAST64_MAX UINT64_MAX + + /* shortcircuit*/ +#endif + /* once */ +#endif +#endif +STDINT_EOF +fi + if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then + AC_MSG_NOTICE([$ac_stdint_h is unchanged]) + else + ac_dir=`AS_DIRNAME(["$ac_stdint_h"])` + AS_MKDIR_P(["$ac_dir"]) + rm -f $ac_stdint_h + mv $ac_stdint $ac_stdint_h + fi +],[# variables for create stdint.h replacement +PACKAGE="$PACKAGE" +VERSION="$VERSION" +ac_stdint_h="$ac_stdint_h" +_ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h) +ac_cv_stdint_message="$ac_cv_stdint_message" +ac_cv_header_stdint_t="$ac_cv_header_stdint_t" +ac_cv_header_stdint_x="$ac_cv_header_stdint_x" +ac_cv_header_stdint_o="$ac_cv_header_stdint_o" +ac_cv_header_stdint_u="$ac_cv_header_stdint_u" +ac_cv_type_uint64_t="$ac_cv_type_uint64_t" +ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" +ac_cv_char_data_model="$ac_cv_char_data_model" +ac_cv_long_data_model="$ac_cv_long_data_model" +ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" +ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" +ac_cv_type_intmax_t="$ac_cv_type_intmax_t" +]) +]) Index: contrib/isl/m4/ax_cxx_compile_stdcxx.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,982 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# Copyright (c) 2016 Krzesimir Nowak +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AX_REQUIRE_DEFINED([AC_MSG_WARN]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) + m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])]) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 +) + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus <= 201402L + +#error "This is not a C++17 compiler" + +#else + +#if defined(__clang__) + #define REALLY_CLANG +#else + #if defined(__GNUC__) + #define REALLY_GCC + #endif +#endif + +#include +#include +#include + +namespace cxx17 +{ + +#if !defined(REALLY_CLANG) + namespace test_constexpr_lambdas + { + + // TODO: test it with clang++ from git + + constexpr int foo = [](){return 42;}(); + + } +#endif // !defined(REALLY_CLANG) + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + +#if !defined(REALLY_CLANG) + namespace test_template_argument_deduction_for_class_templates + { + + // TODO: test it with clang++ from git + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } +#endif // !defined(REALLY_CLANG) + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + +#if !defined(REALLY_CLANG) + namespace test_structured_bindings + { + + // TODO: test it with clang++ from git + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } +#endif // !defined(REALLY_CLANG) + +#if !defined(REALLY_CLANG) + namespace test_exception_spec_type_system + { + + // TODO: test it with clang++ from git + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } +#endif // !defined(REALLY_CLANG) + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus <= 201402L + +]]) Index: contrib/isl/m4/ax_cxx_compile_stdcxx_11.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,39 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXX and CXXCPP to enable +# support. +# +# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX +# macro with the version set to C++11. The two optional arguments are +# forwarded literally as the second and third argument respectively. +# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for +# more information. If you want to use this macro, you also need to +# download the ax_cxx_compile_stdcxx.m4 file. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 17 + +AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) Index: contrib/isl/m4/ax_detect_clang.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_detect_clang.m4 @@ -0,0 +1,168 @@ +AC_DEFUN([AX_DETECT_CLANG], [ +AC_SUBST(CLANG_CXXFLAGS) +AC_SUBST(CLANG_LDFLAGS) +AC_SUBST(CLANG_LIBS) +AC_PROG_GREP +AC_PROG_SED +llvm_config="llvm-config" +AC_CHECK_PROG([llvm_config_found], ["$llvm_config"], [yes]) +if test "x$with_clang_prefix" != "x"; then + llvm_config="$with_clang_prefix/bin/llvm-config" + if test -x "$llvm_config"; then + llvm_config_found=yes + fi +fi +if test "$llvm_config_found" != yes; then + AC_MSG_ERROR([llvm-config not found]) +fi +CLANG_CXXFLAGS=`$llvm_config --cxxflags | \ + $SED -e 's/-Wcovered-switch-default//;s/-gsplit-dwarf//'` +CLANG_LDFLAGS=`$llvm_config --ldflags` +targets=`$llvm_config --targets-built` +components="$targets asmparser bitreader support mc" +$llvm_config --components | $GREP option > /dev/null 2> /dev/null +if test $? -eq 0; then + components="$components option" +fi +CLANG_LIBS=`$llvm_config --libs $components` +systemlibs=`$llvm_config --system-libs 2> /dev/null | tail -1` +if test $? -eq 0; then + CLANG_LIBS="$CLANG_LIBS $systemlibs" +fi +CLANG_PREFIX=`$llvm_config --prefix` +AC_DEFINE_UNQUOTED(CLANG_PREFIX, ["$CLANG_PREFIX"], [Clang installation prefix]) + +SAVE_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CLANG_CXXFLAGS $CPPFLAGS" +AC_LANG_PUSH(C++) +AC_CHECK_HEADER([clang/Basic/SourceLocation.h], [], + [AC_ERROR([clang header file not found])]) +AC_EGREP_HEADER([getDefaultTargetTriple], [llvm/Support/Host.h], [], + [AC_DEFINE([getDefaultTargetTriple], [getHostTriple], + [Define to getHostTriple for older versions of clang])]) +AC_EGREP_HEADER([getExpansionLineNumber], [clang/Basic/SourceLocation.h], [], + [AC_DEFINE([getExpansionLineNumber], [getInstantiationLineNumber], + [Define to getInstantiationLineNumber for older versions of clang])]) +AC_EGREP_HEADER([DiagnosticsEngine], [clang/Basic/Diagnostic.h], [], + [AC_DEFINE([DiagnosticsEngine], [Diagnostic], + [Define to Diagnostic for older versions of clang])]) +AC_EGREP_HEADER([ArrayRef], [clang/Driver/Driver.h], + [AC_DEFINE([USE_ARRAYREF], [], + [Define if Driver::BuildCompilation takes ArrayRef])]) +AC_EGREP_HEADER([CXXIsProduction], [clang/Driver/Driver.h], + [AC_DEFINE([HAVE_CXXISPRODUCTION], [], + [Define if Driver constructor takes CXXIsProduction argument])]) +AC_EGREP_HEADER([ IsProduction], [clang/Driver/Driver.h], + [AC_DEFINE([HAVE_ISPRODUCTION], [], + [Define if Driver constructor takes IsProduction argument])]) +AC_TRY_COMPILE([#include ], [ + using namespace clang; + DiagnosticsEngine *Diags; + new driver::Driver("", "", "", *Diags); +], [AC_DEFINE([DRIVER_CTOR_TAKES_DEFAULTIMAGENAME], [], + [Define if Driver constructor takes default image name])]) +AC_EGREP_HEADER([void HandleTopLevelDecl\(], [clang/AST/ASTConsumer.h], + [AC_DEFINE([HandleTopLevelDeclReturn], [void], + [Return type of HandleTopLevelDeclReturn]) + AC_DEFINE([HandleTopLevelDeclContinue], [], + [Return type of HandleTopLevelDeclReturn])], + [AC_DEFINE([HandleTopLevelDeclReturn], [bool], + [Return type of HandleTopLevelDeclReturn]) + AC_DEFINE([HandleTopLevelDeclContinue], [true], + [Return type of HandleTopLevelDeclReturn])]) +AC_CHECK_HEADER([clang/Basic/DiagnosticOptions.h], + [AC_DEFINE([HAVE_BASIC_DIAGNOSTICOPTIONS_H], [], + [Define if clang/Basic/DiagnosticOptions.h exists])]) +AC_CHECK_HEADER([clang/Lex/PreprocessorOptions.h], + [AC_DEFINE([HAVE_LEX_PREPROCESSOROPTIONS_H], [], + [Define if clang/Lex/PreprocessorOptions.h exists])], [], + [#include ]) +AC_TRY_COMPILE([#include ], [ + using namespace clang; + std::shared_ptr TO; + DiagnosticsEngine *Diags; + TargetInfo::CreateTargetInfo(*Diags, TO); +], [AC_DEFINE([CREATETARGETINFO_TAKES_SHARED_PTR], [], + [Define if TargetInfo::CreateTargetInfo takes shared_ptr])]) +AC_TRY_COMPILE([#include ], [ + using namespace clang; + TargetOptions *TO; + DiagnosticsEngine *Diags; + TargetInfo::CreateTargetInfo(*Diags, TO); +], [AC_DEFINE([CREATETARGETINFO_TAKES_POINTER], [], + [Define if TargetInfo::CreateTargetInfo takes pointer])]) +AC_TRY_COMPILE([#include ], [ + using namespace clang; + DiagnosticConsumer *client; + CompilerInstance *Clang; + Clang->createDiagnostics(client); +], [], [AC_DEFINE([CREATEDIAGNOSTICS_TAKES_ARG], [], + [Define if CompilerInstance::createDiagnostics takes argc and argv])]) +AC_TRY_COMPILE([#include ], [ + using namespace clang; + HeaderSearchOptions HSO; + HSO.AddPath("", frontend::Angled, false, false); +], [AC_DEFINE([ADDPATH_TAKES_4_ARGUMENTS], [], + [Define if HeaderSearchOptions::AddPath takes 4 arguments])]) +AC_EGREP_HEADER([getNumParams], + [clang/AST/CanonicalType.h], + [AC_DEFINE([getNumArgs], [getNumParams], + [Define to getNumParams for newer versions of clang]) + AC_DEFINE([getArgType], [getParamType], + [Define to getParamType for newer versions of clang])]) +AC_EGREP_HEADER([getReturnType], + [clang/AST/CanonicalType.h], [], + [AC_DEFINE([getReturnType], [getResultType], + [Define to getResultType for older versions of clang])]) +AC_TRY_COMPILE([#include ], [ + using namespace clang; + CompilerInstance *Clang; + Clang->createPreprocessor(TU_Complete); +], [AC_DEFINE([CREATEPREPROCESSOR_TAKES_TUKIND], [], +[Define if CompilerInstance::createPreprocessor takes TranslationUnitKind])]) +AC_EGREP_HEADER([setMainFileID], [clang/Basic/SourceManager.h], + [AC_DEFINE([HAVE_SETMAINFILEID], [], + [Define if SourceManager has a setMainFileID method])]) +AC_CHECK_HEADER([llvm/ADT/OwningPtr.h], + [AC_DEFINE([HAVE_ADT_OWNINGPTR_H], [], + [Define if llvm/ADT/OwningPtr.h exists])]) +AC_EGREP_HEADER([initializeBuiltins], + [clang/Basic/Builtins.h], [], + [AC_DEFINE([initializeBuiltins], [InitializeBuiltins], + [Define to InitializeBuiltins for older versions of clang])]) +AC_EGREP_HEADER([IK_C], [clang/Frontend/FrontendOptions.h], [], + [AC_DEFINE([IK_C], [InputKind::C], + [Define to InputKind::C for newer versions of clang])]) +AC_TRY_COMPILE([ + #include + #include + #include +], [ + using namespace clang; + CompilerInstance *Clang; + TargetOptions TO; + llvm::Triple T(TO.Triple); + PreprocessorOptions PO; + CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, + T, PO, LangStandard::lang_unspecified); +], [AC_DEFINE([SETLANGDEFAULTS_TAKES_5_ARGUMENTS], [], + [Define if CompilerInvocation::setLangDefaults takes 5 arguments])]) +AC_TRY_COMPILE([ + #include + #include +], [ + using namespace clang; + CompilerInvocation *invocation; + CompilerInstance *Clang; + Clang->setInvocation(std::make_shared(*invocation)); +], [AC_DEFINE([SETINVOCATION_TAKES_SHARED_PTR], [], + [Defined if CompilerInstance::setInvocation takes a shared_ptr])]) +AC_LANG_POP +CPPFLAGS="$SAVE_CPPFLAGS" + +SAVE_LDFLAGS="$LDFLAGS" +LDFLAGS="$CLANG_LDFLAGS $LDFLAGS" +AC_SUBST(LIB_CLANG_EDIT) +AC_CHECK_LIB([clangEdit], [main], [LIB_CLANG_EDIT=-lclangEdit], []) +LDFLAGS="$SAVE_LDFLAGS" +]) Index: contrib/isl/m4/ax_detect_git_head.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_detect_git_head.m4 @@ -0,0 +1,32 @@ +AC_DEFUN([AX_DETECT_GIT_HEAD], [ + AC_SUBST(GIT_HEAD_ID) + AC_SUBST(GIT_HEAD) + AC_SUBST(GIT_HEAD_VERSION) + if test -f $srcdir/.git; then + gitdir=`GIT_DIR=$srcdir/.git git rev-parse --git-dir` + GIT_HEAD="$gitdir/index" + GIT_REPO="$gitdir" + GIT_HEAD_ID=`GIT_DIR=$GIT_REPO git describe --always` + elif test -f $srcdir/.git/HEAD; then + GIT_HEAD="$srcdir/.git/index" + GIT_REPO="$srcdir/.git" + GIT_HEAD_ID=`GIT_DIR=$GIT_REPO git describe --always` + elif test -f $srcdir/GIT_HEAD_ID; then + GIT_HEAD_ID=`cat $srcdir/GIT_HEAD_ID` + else + mysrcdir=`(cd $srcdir; pwd)` + head=`basename $mysrcdir | sed -e 's/.*-//'` + head2=`echo $head | sed -e 's/[^0-9a-f]//'` + head3=`echo $head2 | sed -e 's/........................................//'` + if test "x$head3" = "x" -a "x$head" = "x$head2"; then + GIT_HEAD_ID="$head" + else + GIT_HEAD_ID="UNKNOWN" + fi + fi + if test -z "$GIT_REPO" ; then + GIT_HEAD_VERSION="$GIT_HEAD_ID" + else + GIT_HEAD_VERSION="\`GIT_DIR=$GIT_REPO git describe --always\`" + fi +]) Index: contrib/isl/m4/ax_detect_gmp.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_detect_gmp.m4 @@ -0,0 +1,48 @@ +AC_DEFUN([AX_DETECT_GMP], [ +AC_DEFINE([USE_GMP_FOR_MP], [], [use gmp to implement isl_int]) +AX_SUBMODULE(gmp,system|build,system) +case "$with_gmp" in +system) + if test "x$with_gmp_prefix" != "x"; then + isl_configure_args="$isl_configure_args --with-gmp=$with_gmp_prefix" + MP_CPPFLAGS="-I$with_gmp_prefix/include" + MP_LDFLAGS="-L$with_gmp_prefix/lib" + fi + MP_LIBS=-lgmp + SAVE_CPPFLAGS="$CPPFLAGS" + SAVE_LDFLAGS="$LDFLAGS" + SAVE_LIBS="$LIBS" + CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS" + LDFLAGS="$MP_LDFLAGS $LDFLAGS" + LIBS="$MP_LIBS $LIBS" + AC_CHECK_HEADER([gmp.h], [], [AC_ERROR([gmp.h header not found])]) + AC_CHECK_LIB([gmp], [main], [], [AC_ERROR([gmp library not found])]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ + mpz_t n, d; + if (mpz_divisible_p(n, d)) + mpz_divexact_ui(n, n, 4); + ]])], [], [AC_ERROR([gmp library too old])]) + CPPFLAGS="$SAVE_CPPFLAGS" + LDFLAGS="$SAVE_LDFLAGS" + LIBS="$SAVE_LIBS" + ;; +build) + MP_CPPFLAGS="-I$gmp_srcdir -I$with_gmp_builddir" + MP_LIBS="$with_gmp_builddir/libgmp.la" + ;; +esac +SAVE_CPPFLAGS="$CPPFLAGS" +SAVE_LDFLAGS="$LDFLAGS" +SAVE_LIBS="$LIBS" +CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS" +LDFLAGS="$MP_LDFLAGS $LDFLAGS" +LIBS="$MP_LIBS $LIBS" +need_get_memory_functions=false +AC_CHECK_DECLS(mp_get_memory_functions,[],[ + need_get_memory_functions=true +],[#include ]) +CPPFLAGS="$SAVE_CPPFLAGS" +LDFLAGS="$SAVE_LDFLAGS" +LIBS="$SAVE_LIBS" +AM_CONDITIONAL(NEED_GET_MEMORY_FUNCTIONS, test x$need_get_memory_functions = xtrue) +]) Index: contrib/isl/m4/ax_detect_imath.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_detect_imath.m4 @@ -0,0 +1,15 @@ +AC_DEFUN([AX_DETECT_IMATH], [ +AC_DEFINE([USE_IMATH_FOR_MP], [], [use imath to implement isl_int]) + +MP_CPPFLAGS="-I$srcdir/imath_wrap" +MP_LDFLAGS="" +MP_LIBS="" + +SAVE_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS" +AC_CHECK_HEADER([imath.h], [], [AC_ERROR([imath.h header not found])]) +AC_CHECK_HEADER([gmp_compat.h], [], [AC_ERROR([gmp_compat.h header not found])]) +CPPFLAGS="$SAVE_CPPFLAGS" + +AM_CONDITIONAL(NEED_GET_MEMORY_FUNCTIONS, test x = xfalse) +]) Index: contrib/isl/m4/ax_gcc_archflag.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_gcc_archflag.m4 @@ -0,0 +1,213 @@ +# =========================================================================== +# http://www.nongnu.org/autoconf-archive/ax_gcc_archflag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_ARCHFLAG([PORTABLE?], [ACTION-SUCCESS], [ACTION-FAILURE]) +# +# DESCRIPTION +# +# This macro tries to guess the "native" arch corresponding to the target +# architecture for use with gcc's -march=arch or -mtune=arch flags. If +# found, the cache variable $ax_cv_gcc_archflag is set to this flag and +# ACTION-SUCCESS is executed; otherwise $ax_cv_gcc_archflag is is set to +# "unknown" and ACTION-FAILURE is executed. The default ACTION-SUCCESS is +# to add $ax_cv_gcc_archflag to the end of $CFLAGS. +# +# PORTABLE? should be either [yes] (default) or [no]. In the former case, +# the flag is set to -mtune (or equivalent) so that the architecture is +# only used for tuning, but the instruction set used is still portable. In +# the latter case, the flag is set to -march (or equivalent) so that +# architecture-specific instructions are enabled. +# +# The user can specify --with-gcc-arch= in order to override the +# macro's choice of architecture, or --without-gcc-arch to disable this. +# +# When cross-compiling, or if $CC is not gcc, then ACTION-FAILURE is +# called unless the user specified --with-gcc-arch manually. +# +# Requires macros: AX_CHECK_COMPILER_FLAGS, AX_GCC_X86_CPUID +# +# (The main emphasis here is on recent CPUs, on the principle that doing +# high-performance computing on old hardware is uncommon.) +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_GCC_ARCHFLAG], +[AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_CANONICAL_HOST]) + +AC_ARG_WITH(gcc-arch, [AC_HELP_STRING([--with-gcc-arch=], [use architecture for gcc -march/-mtune, instead of guessing])], + ax_gcc_arch=$withval, ax_gcc_arch=yes) + +AC_MSG_CHECKING([for gcc architecture flag]) +AC_MSG_RESULT([]) +AC_CACHE_VAL(ax_cv_gcc_archflag, +[ +ax_cv_gcc_archflag="unknown" + +if test "$GCC" = yes; then + +if test "x$ax_gcc_arch" = xyes; then +ax_gcc_arch="" +if test "$cross_compiling" = no; then +case $host_cpu in + i[[3456]]86*|x86_64*) # use cpuid codes, in part from x86info-1.7 by D. Jones + AX_GCC_X86_CPUID(0) + AX_GCC_X86_CPUID(1) + case $ax_cv_gcc_x86_cpuid_0 in + *:756e6547:*:*) # Intel + case $ax_cv_gcc_x86_cpuid_1 in + *5[[48]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;; + *5??:*:*:*) ax_gcc_arch=pentium ;; + *6[[3456]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; + *6a?:*[[01]]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; + *6a?:*[[234]]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; + *6[[9d]]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;; + *6[[78b]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; + *6??:*:*:*) ax_gcc_arch=pentiumpro ;; + *f3[[347]]:*:*:*|*f4[1347]:*:*:*) + case $host_cpu in + x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;; + *) ax_gcc_arch="prescott pentium4 pentiumpro" ;; + esac ;; + *f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";; + esac ;; + *:68747541:*:*) # AMD + case $ax_cv_gcc_x86_cpuid_1 in + *5[[67]]?:*:*:*) ax_gcc_arch=k6 ;; + *5[[8d]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;; + *5[[9]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;; + *60?:*:*:*) ax_gcc_arch=k7 ;; + *6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;; + *6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;; + *67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;; + *6[[68a]]?:*:*:*) + AX_GCC_X86_CPUID(0x80000006) # L2 cache size + case $ax_cv_gcc_x86_cpuid_0x80000006 in + *:*:*[[1-9a-f]]??????:*) # (L2 = ecx >> 16) >= 256 + ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;; + *) ax_gcc_arch="athlon-4 athlon k7" ;; + esac ;; + *f[[4cef8b]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;; + *f5?:*:*:*) ax_gcc_arch="opteron k8" ;; + *f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;; + *f??:*:*:*) ax_gcc_arch="k8" ;; + esac ;; + *:746e6543:*:*) # IDT + case $ax_cv_gcc_x86_cpuid_1 in + *54?:*:*:*) ax_gcc_arch=winchip-c6 ;; + *58?:*:*:*) ax_gcc_arch=winchip2 ;; + *6[[78]]?:*:*:*) ax_gcc_arch=c3 ;; + *69?:*:*:*) ax_gcc_arch="c3-2 c3" ;; + esac ;; + esac + if test x"$ax_gcc_arch" = x; then # fallback + case $host_cpu in + i586*) ax_gcc_arch=pentium ;; + i686*) ax_gcc_arch=pentiumpro ;; + esac + fi + ;; + + sparc*) + AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/]) + cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null` + cputype=`echo "$cputype" | tr -d ' -' |tr $as_cr_LETTERS $as_cr_letters` + case $cputype in + *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;; + *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;; + *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;; + *supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;; + *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;; + *cypress*) ax_gcc_arch=cypress ;; + esac ;; + + alphaev5) ax_gcc_arch=ev5 ;; + alphaev56) ax_gcc_arch=ev56 ;; + alphapca56) ax_gcc_arch="pca56 ev56" ;; + alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;; + alphaev6) ax_gcc_arch=ev6 ;; + alphaev67) ax_gcc_arch=ev67 ;; + alphaev68) ax_gcc_arch="ev68 ev67" ;; + alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;; + alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;; + alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;; + + powerpc*) + cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null` + cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'` + case $cputype in + *750*) ax_gcc_arch="750 G3" ;; + *740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;; + *74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;; + *74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;; + *970*) ax_gcc_arch="970 G5 power4";; + *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";; + *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";; + 603ev|8240) ax_gcc_arch="$cputype 603e 603";; + *) ax_gcc_arch=$cputype ;; + esac + ax_gcc_arch="$ax_gcc_arch powerpc" + ;; +esac +fi # not cross-compiling +fi # guess arch + +if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then +for arch in $ax_gcc_arch; do + if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code + flags="-mtune=$arch" + # -mcpu=$arch and m$arch generate nonportable code on every arch except + # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr. + case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac + else + flags="-march=$arch -mcpu=$arch -m$arch" + fi + for flag in $flags; do + AX_CHECK_COMPILER_FLAGS($flag, [ax_cv_gcc_archflag=$flag; break]) + done + test "x$ax_cv_gcc_archflag" = xunknown || break +done +fi + +fi # $GCC=yes +]) +AC_MSG_CHECKING([for gcc architecture flag]) +AC_MSG_RESULT($ax_cv_gcc_archflag) +if test "x$ax_cv_gcc_archflag" = xunknown; then + m4_default([$3],:) +else + m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"]) +fi +]) Index: contrib/isl/m4/ax_gcc_warn_unused_result.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_gcc_warn_unused_result.m4 @@ -0,0 +1,56 @@ +# =========================================================================== +# http://www.nongnu.org/autoconf-archive/ax_gcc_warn_unused_result.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_WARN_UNUSED_RESULT +# +# DESCRIPTION +# +# The macro will compile a test program to see whether the compiler does +# understand the per-function postfix pragma. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_GCC_WARN_UNUSED_RESULT],[dnl +AC_CACHE_CHECK( + [whether the compiler supports function __attribute__((__warn_unused_result__))], + ax_cv_gcc_warn_unused_result,[ + AC_TRY_COMPILE([__attribute__((__warn_unused_result__)) + int f(int i) { return i; }], + [], + ax_cv_gcc_warn_unused_result=yes, ax_cv_gcc_warn_unused_result=no)]) + if test "$ax_cv_gcc_warn_unused_result" = yes; then + AC_DEFINE([GCC_WARN_UNUSED_RESULT],[__attribute__((__warn_unused_result__))], + [most gcc compilers know a function __attribute__((__warn_unused_result__))]) + fi +]) Index: contrib/isl/m4/ax_gcc_x86_cpuid.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_gcc_x86_cpuid.m4 @@ -0,0 +1,77 @@ +# =========================================================================== +# http://www.nongnu.org/autoconf-archive/ax_gcc_x86_cpuid.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_X86_CPUID(OP) +# +# DESCRIPTION +# +# On Pentium and later x86 processors, with gcc or a compiler that has a +# compatible syntax for inline assembly instructions, run a small program +# that executes the cpuid instruction with input OP. This can be used to +# detect the CPU type. +# +# On output, the values of the eax, ebx, ecx, and edx registers are stored +# as hexadecimal strings as "eax:ebx:ecx:edx" in the cache variable +# ax_cv_gcc_x86_cpuid_OP. +# +# If the cpuid instruction fails (because you are running a +# cross-compiler, or because you are not using gcc, or because you are on +# a processor that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP +# is set to the string "unknown". +# +# This macro mainly exists to be used in AX_GCC_ARCHFLAG. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_GCC_X86_CPUID], +[AC_REQUIRE([AC_PROG_CC]) +AC_LANG_PUSH([C]) +AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1, + [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [ + int op = $1, eax, ebx, ecx, edx; + FILE *f; + __asm__("cpuid" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op)); + f = fopen("conftest_cpuid", "w"); if (!f) return 1; + fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); + fclose(f); + return 0; +])], + [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid], + [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid], + [ax_cv_gcc_x86_cpuid_$1=unknown])]) +AC_LANG_POP([C]) +]) Index: contrib/isl/m4/ax_set_warning_flags.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_set_warning_flags.m4 @@ -0,0 +1,17 @@ +dnl Add a set of flags to WARNING_FLAGS, that enable compiler warnings for +dnl isl. The warnings that are enabled vary with the compiler and only include +dnl warnings that did not trigger at the time of adding these flags. +AC_DEFUN([AX_SET_WARNING_FLAGS],[dnl + AX_COMPILER_VENDOR + + WARNING_FLAGS="" + + if test "${ax_cv_c_compiler_vendor}" = "clang"; then + dnl isl is at the moment clean of -Wall warnings. If clang adds + dnl new warnings to -Wall which cause false positives, the + dnl specific warning types will be disabled explicitally (by + dnl adding for example -Wno-return-type). To temporarily disable + dnl all warnings run configure with CFLAGS=-Wno-all. + WARNING_FLAGS="-Wall" + fi +]) Index: contrib/isl/m4/ax_submodule.m4 =================================================================== --- /dev/null +++ contrib/isl/m4/ax_submodule.m4 @@ -0,0 +1,71 @@ +AC_DEFUN([AX_SUBMODULE], +[ + +m4_if(m4_bregexp($2,|,choice),choice, + [AC_ARG_WITH($1, + [AS_HELP_STRING([--with-$1=$2], + [Which $1 to use [default=$3]])])]) +case "system" in +$2) + AC_ARG_WITH($1_prefix, + [AS_HELP_STRING([--with-$1-prefix=DIR], + [Prefix of $1 installation])]) + AC_ARG_WITH($1_exec_prefix, + [AS_HELP_STRING([--with-$1-exec-prefix=DIR], + [Exec prefix of $1 installation])]) +esac +m4_if(m4_bregexp($2,build,build),build, + [AC_ARG_WITH($1_builddir, + [AS_HELP_STRING([--with-$1-builddir=DIR], + [Location of $1 builddir])])]) +if test "x$with_$1_prefix" != "x" -a "x$with_$1_exec_prefix" = "x"; then + with_$1_exec_prefix=$with_$1_prefix +fi +if test "x$with_$1_prefix" != "x" -o "x$with_$1_exec_prefix" != "x"; then + if test "x$with_$1" != "x" -a "x$with_$1" != "xyes" -a "x$with_$1" != "xsystem"; then + AC_MSG_ERROR([Setting $with_$1_prefix implies use of system $1]) + fi + with_$1="system" +fi +if test "x$with_$1_builddir" != "x"; then + if test "x$with_$1" != "x" -a "x$with_$1" != "xyes" -a "x$with_$1" != "xbuild"; then + AC_MSG_ERROR([Setting $with_$1_builddir implies use of build $1]) + fi + with_$1="build" + $1_srcdir=`echo @abs_srcdir@ | $with_$1_builddir/config.status --file=-` + AC_MSG_NOTICE($1 sources in $$1_srcdir) +fi +if test "x$with_$1_exec_prefix" != "x"; then + export PKG_CONFIG_PATH="$with_$1_exec_prefix/lib/pkgconfig${PKG_CONFIG_PATH+:$PKG_CONFIG_PATH}" +fi +case "$with_$1" in +$2) + ;; +*) + case "$3" in + bundled) + if test -d $srcdir/.git -a \ + -d $srcdir/$1 -a \ + ! -d $srcdir/$1/.git; then + AC_MSG_WARN([git repo detected, but submodule $1 not initialized]) + AC_MSG_WARN([You may want to run]) + AC_MSG_WARN([ git submodule init]) + AC_MSG_WARN([ git submodule update]) + AC_MSG_WARN([ sh autogen.sh]) + fi + if test -f $srcdir/$1/configure; then + with_$1="bundled" + else + with_$1="no" + fi + ;; + *) + with_$1="$3" + ;; + esac + ;; +esac +AC_MSG_CHECKING([which $1 to use]) +AC_MSG_RESULT($with_$1) + +]) Index: contrib/isl/mp_get_memory_functions.c =================================================================== --- /dev/null +++ contrib/isl/mp_get_memory_functions.c @@ -0,0 +1,14 @@ +#include + +void mp_get_memory_functions( + void *(**alloc_func_ptr) (size_t), + void *(**realloc_func_ptr) (void *, size_t, size_t), + void (**free_func_ptr) (void *, size_t)) +{ + if (alloc_func_ptr) + *alloc_func_ptr = __gmp_allocate_func; + if (realloc_func_ptr) + *realloc_func_ptr = __gmp_reallocate_func; + if (free_func_ptr) + *free_func_ptr = __gmp_free_func; +} Index: contrib/isl/pip.c =================================================================== --- /dev/null +++ contrib/isl/pip.c @@ -0,0 +1,397 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include +#include +#include "isl_tab.h" +#include "isl_sample.h" +#include "isl_scan.h" +#include +#include +#include +#include +#include +#include +#include + +/* The input of this program is the same as that of the "example" program + * from the PipLib distribution, except that the "big parameter column" + * should always be -1. + * + * Context constraints in PolyLib format + * -1 + * Problem constraints in PolyLib format + * Optional list of options + * + * The options are + * Maximize compute maximum instead of minimum + * Rational compute rational optimum instead of integer optimum + * Urs_parms don't assume parameters are non-negative + * Urs_unknowns don't assume unknowns are non-negative + */ + +struct options { + struct isl_options *isl; + unsigned verify; + unsigned format; +}; + +#define FORMAT_SET 0 +#define FORMAT_AFF 1 + +struct isl_arg_choice pip_format[] = { + {"set", FORMAT_SET}, + {"affine", FORMAT_AFF}, + {0} +}; + +ISL_ARGS_START(struct options, options_args) +ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options") +ISL_ARG_BOOL(struct options, verify, 'T', "verify", 0, NULL) +ISL_ARG_CHOICE(struct options, format, 0, "format", + pip_format, FORMAT_SET, "output format") +ISL_ARGS_END + +ISL_ARG_DEF(options, struct options, options_args) + +static __isl_give isl_basic_set *set_bounds(__isl_take isl_basic_set *bset) +{ + unsigned nparam; + int i, r; + isl_point *pt, *pt2; + isl_basic_set *box; + + nparam = isl_basic_set_dim(bset, isl_dim_param); + r = nparam >= 8 ? 4 : nparam >= 5 ? 6 : 30; + + pt = isl_basic_set_sample_point(isl_basic_set_copy(bset)); + pt2 = isl_point_copy(pt); + + for (i = 0; i < nparam; ++i) { + pt = isl_point_add_ui(pt, isl_dim_param, i, r); + pt2 = isl_point_sub_ui(pt2, isl_dim_param, i, r); + } + + box = isl_basic_set_box_from_points(pt, pt2); + + return isl_basic_set_intersect(bset, box); +} + +static struct isl_basic_set *to_parameter_domain(struct isl_basic_set *context) +{ + context = isl_basic_set_move_dims(context, isl_dim_param, 0, + isl_dim_set, 0, isl_basic_set_dim(context, isl_dim_set)); + context = isl_basic_set_params(context); + return context; +} + +/* Plug in the initial values of "params" for the parameters in "bset" and + * return the result. The remaining entries in "params", if any, + * correspond to the existentially quantified variables in the description + * of the original context and can be ignored. + */ +static __isl_give isl_basic_set *plug_in_parameters( + __isl_take isl_basic_set *bset, __isl_take isl_vec *params) +{ + int i, n; + + n = isl_basic_set_dim(bset, isl_dim_param); + for (i = 0; i < n; ++i) + bset = isl_basic_set_fix(bset, + isl_dim_param, i, params->el[1 + i]); + + bset = isl_basic_set_remove_dims(bset, isl_dim_param, 0, n); + + isl_vec_free(params); + + return bset; +} + +/* Plug in the initial values of "params" for the parameters in "set" and + * return the result. The remaining entries in "params", if any, + * correspond to the existentially quantified variables in the description + * of the original context and can be ignored. + */ +static __isl_give isl_set *set_plug_in_parameters(__isl_take isl_set *set, + __isl_take isl_vec *params) +{ + int i, n; + + n = isl_set_dim(set, isl_dim_param); + for (i = 0; i < n; ++i) + set = isl_set_fix(set, isl_dim_param, i, params->el[1 + i]); + + set = isl_set_remove_dims(set, isl_dim_param, 0, n); + + isl_vec_free(params); + + return set; +} + +/* Compute the lexicographically minimal (or maximal if max is set) + * element of bset for the given values of the parameters, by + * successively solving an ilp problem in each direction. + */ +static __isl_give isl_vec *opt_at(__isl_take isl_basic_set *bset, + __isl_take isl_vec *params, int max) +{ + unsigned dim; + isl_ctx *ctx; + struct isl_vec *opt; + struct isl_vec *obj; + int i; + + dim = isl_basic_set_dim(bset, isl_dim_set); + + bset = plug_in_parameters(bset, params); + + ctx = isl_basic_set_get_ctx(bset); + if (isl_basic_set_plain_is_empty(bset)) { + opt = isl_vec_alloc(ctx, 0); + isl_basic_set_free(bset); + return opt; + } + + opt = isl_vec_alloc(ctx, 1 + dim); + assert(opt); + + obj = isl_vec_alloc(ctx, 1 + dim); + assert(obj); + + isl_int_set_si(opt->el[0], 1); + isl_int_set_si(obj->el[0], 0); + + for (i = 0; i < dim; ++i) { + enum isl_lp_result res; + + isl_seq_clr(obj->el + 1, dim); + isl_int_set_si(obj->el[1 + i], 1); + res = isl_basic_set_solve_ilp(bset, max, obj->el, + &opt->el[1 + i], NULL); + if (res == isl_lp_empty) + goto empty; + assert(res == isl_lp_ok); + bset = isl_basic_set_fix(bset, isl_dim_set, i, opt->el[1 + i]); + } + + isl_basic_set_free(bset); + isl_vec_free(obj); + + return opt; +empty: + isl_vec_free(opt); + opt = isl_vec_alloc(ctx, 0); + isl_basic_set_free(bset); + isl_vec_free(obj); + + return opt; +} + +struct isl_scan_pip { + struct isl_scan_callback callback; + isl_basic_set *bset; + isl_set *sol; + isl_set *empty; + int stride; + int n; + int max; +}; + +/* Check if the "manually" computed optimum of bset at the "sample" + * values of the parameters agrees with the solution of pilp problem + * represented by the pair (sol, empty). + * In particular, if there is no solution for this value of the parameters, + * then it should be an element of the parameter domain "empty". + * Otherwise, the optimal solution, should be equal to the result of + * plugging in the value of the parameters in "sol". + */ +static isl_stat scan_one(struct isl_scan_callback *callback, + __isl_take isl_vec *sample) +{ + struct isl_scan_pip *sp = (struct isl_scan_pip *)callback; + struct isl_vec *opt; + + sp->n--; + + opt = opt_at(isl_basic_set_copy(sp->bset), isl_vec_copy(sample), sp->max); + assert(opt); + + if (opt->size == 0) { + isl_point *sample_pnt; + sample_pnt = isl_point_alloc(isl_set_get_space(sp->empty), sample); + assert(isl_set_contains_point(sp->empty, sample_pnt)); + isl_point_free(sample_pnt); + isl_vec_free(opt); + } else { + isl_set *sol; + isl_set *opt_set; + opt_set = isl_set_from_basic_set(isl_basic_set_from_vec(opt)); + sol = set_plug_in_parameters(isl_set_copy(sp->sol), sample); + assert(isl_set_is_equal(opt_set, sol)); + isl_set_free(sol); + isl_set_free(opt_set); + } + + if (!(sp->n % sp->stride)) { + printf("o"); + fflush(stdout); + } + + return sp->n >= 1 ? isl_stat_ok : isl_stat_error; +} + +static void check_solution(isl_basic_set *bset, isl_basic_set *context, + isl_set *sol, isl_set *empty, int max) +{ + struct isl_scan_pip sp; + isl_int count, count_max; + int i, n; + int r; + + context = set_bounds(context); + context = isl_basic_set_underlying_set(context); + + isl_int_init(count); + isl_int_init(count_max); + + isl_int_set_si(count_max, 2000); + r = isl_basic_set_count_upto(context, count_max, &count); + assert(r >= 0); + n = isl_int_get_si(count); + + isl_int_clear(count_max); + isl_int_clear(count); + + sp.callback.add = scan_one; + sp.bset = bset; + sp.sol = sol; + sp.empty = empty; + sp.n = n; + sp.stride = n > 70 ? 1 + (n + 1)/70 : 1; + sp.max = max; + + for (i = 0; i < n; i += sp.stride) + printf("."); + printf("\r"); + fflush(stdout); + + isl_basic_set_scan(context, &sp.callback); + + printf("\n"); + + isl_basic_set_free(bset); +} + +int main(int argc, char **argv) +{ + struct isl_ctx *ctx; + struct isl_basic_set *context, *bset, *copy, *context_copy; + struct isl_set *set = NULL; + struct isl_set *empty; + isl_pw_multi_aff *pma = NULL; + int neg_one; + char s[1024]; + int urs_parms = 0; + int urs_unknowns = 0; + int max = 0; + int rational = 0; + int n; + int nparam; + struct options *options; + + options = options_new_with_defaults(); + assert(options); + argc = options_parse(options, argc, argv, ISL_ARG_ALL); + + ctx = isl_ctx_alloc_with_options(&options_args, options); + + context = isl_basic_set_read_from_file(ctx, stdin); + assert(context); + n = fscanf(stdin, "%d", &neg_one); + assert(n == 1); + assert(neg_one == -1); + bset = isl_basic_set_read_from_file(ctx, stdin); + + while (fgets(s, sizeof(s), stdin)) { + if (strncasecmp(s, "Maximize", 8) == 0) + max = 1; + if (strncasecmp(s, "Rational", 8) == 0) { + rational = 1; + bset = isl_basic_set_set_rational(bset); + } + if (strncasecmp(s, "Urs_parms", 9) == 0) + urs_parms = 1; + if (strncasecmp(s, "Urs_unknowns", 12) == 0) + urs_unknowns = 1; + } + if (!urs_parms) + context = isl_basic_set_intersect(context, + isl_basic_set_positive_orthant(isl_basic_set_get_space(context))); + context = to_parameter_domain(context); + nparam = isl_basic_set_dim(context, isl_dim_param); + if (nparam != isl_basic_set_dim(bset, isl_dim_param)) { + int dim = isl_basic_set_dim(bset, isl_dim_set); + bset = isl_basic_set_move_dims(bset, isl_dim_param, 0, + isl_dim_set, dim - nparam, nparam); + } + if (!urs_unknowns) + bset = isl_basic_set_intersect(bset, + isl_basic_set_positive_orthant(isl_basic_set_get_space(bset))); + + if (options->verify) { + copy = isl_basic_set_copy(bset); + context_copy = isl_basic_set_copy(context); + } + + if (options->format == FORMAT_AFF) { + if (max) + pma = isl_basic_set_partial_lexmax_pw_multi_aff(bset, + context, &empty); + else + pma = isl_basic_set_partial_lexmin_pw_multi_aff(bset, + context, &empty); + } else { + if (max) + set = isl_basic_set_partial_lexmax(bset, + context, &empty); + else + set = isl_basic_set_partial_lexmin(bset, + context, &empty); + } + + if (options->verify) { + assert(!rational); + if (options->format == FORMAT_AFF) + set = isl_set_from_pw_multi_aff(pma); + check_solution(copy, context_copy, set, empty, max); + isl_set_free(set); + } else { + isl_printer *p; + p = isl_printer_to_file(ctx, stdout); + if (options->format == FORMAT_AFF) + p = isl_printer_print_pw_multi_aff(p, pma); + else + p = isl_printer_print_set(p, set); + p = isl_printer_end_line(p); + p = isl_printer_print_str(p, "no solution: "); + p = isl_printer_print_set(p, empty); + p = isl_printer_end_line(p); + isl_printer_free(p); + isl_set_free(set); + isl_pw_multi_aff_free(pma); + } + + isl_set_free(empty); + isl_ctx_free(ctx); + + return 0; +} Index: contrib/isl/pip_test.sh.in =================================================================== --- /dev/null +++ contrib/isl/pip_test.sh.in @@ -0,0 +1,31 @@ +#!/bin/sh + +EXEEXT=@EXEEXT@ +srcdir=@srcdir@ + +PIP_TESTS="\ + boulet.pip \ + brisebarre.pip \ + cg1.pip \ + esced.pip \ + ex2.pip \ + ex.pip \ + exist.pip \ + exist2.pip \ + fimmel.pip \ + max.pip \ + negative.pip \ + seghir-vd.pip \ + small.pip \ + sor1d.pip \ + square.pip \ + sven.pip \ + tobi.pip" + +for i in $PIP_TESTS; do + echo $i; + ./isl_pip$EXEEXT --format=set --context=gbr -T < $srcdir/test_inputs/$i || exit + ./isl_pip$EXEEXT --format=set --context=lexmin -T < $srcdir/test_inputs/$i || exit + ./isl_pip$EXEEXT --format=affine --context=gbr -T < $srcdir/test_inputs/$i || exit + ./isl_pip$EXEEXT --format=affine --context=lexmin -T < $srcdir/test_inputs/$i || exit +done Index: contrib/isl/polyhedron_detect_equalities.c =================================================================== --- /dev/null +++ contrib/isl/polyhedron_detect_equalities.c @@ -0,0 +1,30 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include + +int main(int argc, char **argv) +{ + struct isl_ctx *ctx = isl_ctx_alloc(); + struct isl_basic_set *bset; + isl_printer *p; + + bset = isl_basic_set_read_from_file(ctx, stdin); + bset = isl_basic_set_detect_equalities(bset); + + p = isl_printer_to_file(ctx, stdout); + p = isl_printer_set_output_format(p, ISL_FORMAT_POLYLIB); + p = isl_printer_print_basic_set(p, bset); + isl_printer_free(p); + + isl_basic_set_free(bset); + isl_ctx_free(ctx); + + return 0; +} Index: contrib/isl/polyhedron_minimize.c =================================================================== --- /dev/null +++ contrib/isl/polyhedron_minimize.c @@ -0,0 +1,105 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include +#include +#include +#include + +/* The input of this program is the same as that of the "polytope_minimize" + * program from the barvinok distribution. + * + * Constraints of set is PolyLib format. + * Linear or affine objective function in PolyLib format. + */ + +static struct isl_vec *isl_vec_lin_to_aff(struct isl_vec *vec) +{ + struct isl_vec *aff; + + if (!vec) + return NULL; + aff = isl_vec_alloc(vec->ctx, 1 + vec->size); + if (!aff) + goto error; + isl_int_set_si(aff->el[0], 0); + isl_seq_cpy(aff->el + 1, vec->el, vec->size); + isl_vec_free(vec); + return aff; +error: + isl_vec_free(vec); + return NULL; +} + +/* Rotate elements of vector right. + * In particular, move the constant term from the end of the + * vector to the start of the vector. + */ +static struct isl_vec *vec_ror(struct isl_vec *vec) +{ + int i; + + if (!vec) + return NULL; + for (i = vec->size - 2; i >= 0; --i) + isl_int_swap(vec->el[i], vec->el[i + 1]); + return vec; +} + +int main(int argc, char **argv) +{ + struct isl_ctx *ctx = isl_ctx_alloc(); + struct isl_basic_set *bset; + struct isl_vec *obj; + struct isl_vec *sol; + isl_int opt; + unsigned dim; + enum isl_lp_result res; + isl_printer *p; + + isl_int_init(opt); + bset = isl_basic_set_read_from_file(ctx, stdin); + assert(bset); + obj = isl_vec_read_from_file(ctx, stdin); + assert(obj); + dim = isl_basic_set_total_dim(bset); + assert(obj->size >= dim && obj->size <= dim + 1); + if (obj->size != dim + 1) + obj = isl_vec_lin_to_aff(obj); + else + obj = vec_ror(obj); + res = isl_basic_set_solve_ilp(bset, 0, obj->el, &opt, &sol); + switch (res) { + case isl_lp_error: + fprintf(stderr, "error\n"); + return -1; + case isl_lp_empty: + fprintf(stdout, "empty\n"); + break; + case isl_lp_unbounded: + fprintf(stdout, "unbounded\n"); + break; + case isl_lp_ok: + p = isl_printer_to_file(ctx, stdout); + p = isl_printer_print_vec(p, sol); + p = isl_printer_end_line(p); + p = isl_printer_print_isl_int(p, opt); + p = isl_printer_end_line(p); + isl_printer_free(p); + } + isl_basic_set_free(bset); + isl_vec_free(obj); + isl_vec_free(sol); + isl_ctx_free(ctx); + isl_int_clear(opt); + + return 0; +} Index: contrib/isl/polyhedron_sample.c =================================================================== --- /dev/null +++ contrib/isl/polyhedron_sample.c @@ -0,0 +1,36 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include "isl_sample.h" +#include + +int main(int argc, char **argv) +{ + struct isl_ctx *ctx = isl_ctx_alloc(); + struct isl_basic_set *bset; + struct isl_vec *sample; + isl_printer *p; + + bset = isl_basic_set_read_from_file(ctx, stdin); + sample = isl_basic_set_sample_vec(isl_basic_set_copy(bset)); + p = isl_printer_to_file(ctx, stdout); + p = isl_printer_print_vec(p, sample); + p = isl_printer_end_line(p); + isl_printer_free(p); + assert(sample); + if (isl_vec_size(sample) > 0) + assert(isl_basic_set_contains(bset, sample)); + isl_basic_set_free(bset); + isl_vec_free(sample); + isl_ctx_free(ctx); + + return 0; +} Index: contrib/isl/polytope_scan.c =================================================================== --- /dev/null +++ contrib/isl/polytope_scan.c @@ -0,0 +1,104 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#include +#include +#include "isl_equalities.h" +#include +#include "isl_scan.h" +#include +#include + +/* The input of this program is the same as that of the "polytope_scan" + * program from the barvinok distribution. + * + * Constraints of set is PolyLib format. + * + * The input set is assumed to be bounded. + */ + +struct scan_samples { + struct isl_scan_callback callback; + struct isl_mat *samples; +}; + +static isl_stat scan_samples_add_sample(struct isl_scan_callback *cb, + __isl_take isl_vec *sample) +{ + struct scan_samples *ss = (struct scan_samples *)cb; + + ss->samples = isl_mat_extend(ss->samples, ss->samples->n_row + 1, + ss->samples->n_col); + if (!ss->samples) + goto error; + + isl_seq_cpy(ss->samples->row[ss->samples->n_row - 1], + sample->el, sample->size); + + isl_vec_free(sample); + return isl_stat_ok; +error: + isl_vec_free(sample); + return isl_stat_error; +} + +static struct isl_mat *isl_basic_set_scan_samples(struct isl_basic_set *bset) +{ + isl_ctx *ctx; + unsigned dim; + struct scan_samples ss; + + ctx = isl_basic_set_get_ctx(bset); + dim = isl_basic_set_total_dim(bset); + ss.callback.add = scan_samples_add_sample; + ss.samples = isl_mat_alloc(ctx, 0, 1 + dim); + if (!ss.samples) + goto error; + + if (isl_basic_set_scan(bset, &ss.callback) < 0) { + isl_mat_free(ss.samples); + return NULL; + } + + return ss.samples; +error: + isl_basic_set_free(bset); + return NULL; +} + +static struct isl_mat *isl_basic_set_samples(struct isl_basic_set *bset) +{ + struct isl_mat *T; + struct isl_mat *samples; + + if (!bset) + return NULL; + + if (bset->n_eq == 0) + return isl_basic_set_scan_samples(bset); + + bset = isl_basic_set_remove_equalities(bset, &T, NULL); + samples = isl_basic_set_scan_samples(bset); + return isl_mat_product(samples, isl_mat_transpose(T)); +} + +int main(int argc, char **argv) +{ + struct isl_ctx *ctx = isl_ctx_alloc(); + struct isl_basic_set *bset; + struct isl_mat *samples; + + bset = isl_basic_set_read_from_file(ctx, stdin); + samples = isl_basic_set_samples(bset); + isl_mat_print_internal(samples, stdout, 0); + isl_mat_free(samples); + isl_ctx_free(ctx); + + return 0; +} Index: contrib/isl/print.c =================================================================== --- /dev/null +++ contrib/isl/print.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef BASE +#define BASE id +#include +#undef BASE +#define BASE val +#include +#undef BASE +#define BASE multi_val +#include +#undef BASE +#define BASE space +#include +#undef BASE +#define BASE local_space +#include +#undef BASE +#define BASE basic_set +#include +#undef BASE +#define BASE basic_map +#include +#undef BASE +#define BASE set +#include +#undef BASE +#define BASE map +#include +#undef BASE +#define BASE union_set +#include +#undef BASE +#define BASE union_map +#include +#undef BASE +#define BASE qpolynomial +#include +#undef BASE +#define BASE qpolynomial_fold +#include +#undef BASE +#define BASE pw_qpolynomial +#include +#undef BASE +#define BASE pw_qpolynomial_fold +#include +#undef BASE +#define BASE union_pw_qpolynomial +#include +#undef BASE +#define BASE union_pw_qpolynomial_fold +#include +#undef BASE +#define BASE constraint +#include +#undef BASE +#define BASE aff +#include +#undef BASE +#define BASE pw_aff +#include +#undef BASE +#define BASE multi_aff +#include +#undef BASE +#define BASE pw_multi_aff +#include +#undef BASE +#define BASE union_pw_multi_aff +#include +#undef BASE +#define BASE multi_pw_aff +#include +#undef BASE +#define BASE union_pw_aff +#include +#undef BASE +#define BASE multi_union_pw_aff +#include +#undef BASE +#define BASE point +#include +#undef BASE +#define BASE ast_expr +#include +#undef BASE +#define BASE ast_node +#include Index: contrib/isl/print_templ.c =================================================================== --- /dev/null +++ contrib/isl/print_templ.c @@ -0,0 +1,36 @@ +#include + +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef TYPE +#define TYPE CAT(isl_,BASE) +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +void FN(TYPE,dump)(__isl_keep TYPE *obj) +{ + isl_printer *p; + + if (!obj) + return; + p = isl_printer_to_file(FN(TYPE,get_ctx)(obj), stderr); + p = isl_printer_set_dump(p, 1); + p = FN(isl_printer_print,BASE)(p, obj); + p = isl_printer_end_line(p); + isl_printer_free(p); +} + +__isl_give char *FN(TYPE,to_str)(__isl_keep TYPE *obj) +{ + isl_printer *p; + char *s; + + if (!obj) + return NULL; + p = isl_printer_to_str(FN(TYPE,get_ctx)(obj)); + p = FN(isl_printer_print,BASE)(p, obj); + s = isl_printer_get_str(p); + isl_printer_free(p); + + return s; +} Index: contrib/isl/print_templ_yaml.c =================================================================== --- /dev/null +++ contrib/isl/print_templ_yaml.c @@ -0,0 +1,39 @@ +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef TYPE +#define TYPE CAT(isl_,BASE) +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +void FN(TYPE,dump)(__isl_keep TYPE *obj) +{ + isl_printer *p; + + if (!obj) + return; + + p = isl_printer_to_file(FN(TYPE,get_ctx)(obj), stderr); + p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK); + p = FN(isl_printer_print,BASE)(p, obj); + isl_printer_free(p); +} + +/* Return a string representation of "obj". + * Print the object in flow format. + */ +__isl_give char *FN(TYPE,to_str)(__isl_keep TYPE *obj) +{ + isl_printer *p; + char *s; + + if (!obj) + return NULL; + + p = isl_printer_to_str(FN(TYPE,get_ctx)(obj)); + p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW); + p = FN(isl_printer_print,BASE)(p, obj); + s = isl_printer_get_str(p); + isl_printer_free(p); + + return s; +} Index: contrib/isl/read_in_string_templ.c =================================================================== --- /dev/null +++ contrib/isl/read_in_string_templ.c @@ -0,0 +1,38 @@ +#include + +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef TYPE +#define TYPE CAT(isl_,BASE) +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +/* Read an object of type TYPE from "s", where the object may + * either be specified directly or as a string. + * + * First check if the next token in "s" is a string. If so, try and + * extract the object from the string. + * Otherwise, try and read the object directly from "s". + */ +static __isl_give TYPE *FN(read,BASE)(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int type; + + tok = isl_stream_next_token(s); + type = isl_token_get_type(tok); + if (type == ISL_TOKEN_STRING) { + char *str; + isl_ctx *ctx; + TYPE *res; + + ctx = isl_stream_get_ctx(s); + str = isl_token_get_str(ctx, tok); + res = FN(TYPE,read_from_str)(ctx, str); + free(str); + isl_token_free(tok); + return res; + } + isl_stream_push_token(s, tok); + return FN(isl_stream_read,BASE)(s); +} Index: contrib/isl/schedule.c =================================================================== --- /dev/null +++ contrib/isl/schedule.c @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege. + */ + +/* This program takes an isl_schedule_constraints object as input and + * prints a schedule that satisfies those constraints. + */ + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + isl_ctx *ctx; + isl_printer *p; + isl_schedule_constraints *sc; + isl_schedule *schedule; + struct isl_options *options; + + options = isl_options_new_with_defaults(); + argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL); + ctx = isl_ctx_alloc_with_options(&isl_options_args, options); + + sc = isl_schedule_constraints_read_from_file(ctx, stdin); + schedule = isl_schedule_constraints_compute_schedule(sc); + + p = isl_printer_to_file(ctx, stdout); + p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK); + p = isl_printer_print_schedule(p, schedule); + isl_printer_free(p); + + isl_schedule_free(schedule); + + isl_ctx_free(ctx); + + return p ? EXIT_SUCCESS : EXIT_FAILURE; +} Index: contrib/isl/schedule_cmp.c =================================================================== --- /dev/null +++ contrib/isl/schedule_cmp.c @@ -0,0 +1,85 @@ +/* + * Copyright 2017 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege. + */ + +#include + +#include +#include +#include + +struct options { + struct isl_options *isl; + char *schedule1; + char *schedule2; +}; + +ISL_ARGS_START(struct options, options_args) +ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options") +ISL_ARG_ARG(struct options, schedule1, "schedule1", NULL) +ISL_ARG_ARG(struct options, schedule2, "schedule2", NULL) +ISL_ARGS_END + +ISL_ARG_DEF(options, struct options, options_args) + +static void die(const char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(EXIT_FAILURE); +} + +static FILE *open_or_die(const char *filename) +{ + FILE *file; + + file = fopen(filename, "r"); + if (!file) { + fprintf(stderr, "Unable to open %s\n", filename); + exit(EXIT_FAILURE); + } + return file; +} + +/* Given two YAML descriptions of isl_schedule objects, check whether + * they are equivalent. + * Return EXIT_SUCCESS if they are and EXIT_FAILURE if they are not + * or if anything else went wrong. + */ +int main(int argc, char **argv) +{ + isl_ctx *ctx; + struct options *options; + FILE *input1, *input2; + isl_bool equal; + isl_schedule *s1, *s2; + + options = options_new_with_defaults(); + if (!options) + return EXIT_FAILURE; + + ctx = isl_ctx_alloc_with_options(&options_args, options); + argc = options_parse(options, argc, argv, ISL_ARG_ALL); + + input1 = open_or_die(options->schedule1); + input2 = open_or_die(options->schedule2); + s1 = isl_schedule_read_from_file(ctx, input1); + s2 = isl_schedule_read_from_file(ctx, input2); + + equal = isl_schedule_plain_is_equal(s1, s2); + if (equal < 0) + return EXIT_FAILURE; + if (!equal) + die("schedules differ"); + + isl_schedule_free(s1); + isl_schedule_free(s2); + fclose(input1); + fclose(input2); + isl_ctx_free(ctx); + + return EXIT_SUCCESS; +} Index: contrib/isl/schedule_test.sh.in =================================================================== --- /dev/null +++ contrib/isl/schedule_test.sh.in @@ -0,0 +1,21 @@ +#!/bin/sh + +EXEEXT=@EXEEXT@ +GREP=@GREP@ +SED=@SED@ +srcdir=@srcdir@ + +failed=0 + +for i in $srcdir/test_inputs/schedule/*.sc; do + echo $i; + base=`basename $i .sc` + test=test-$base.st + dir=`dirname $i` + ref=$dir/$base.st + options=`$GREP 'OPTIONS:' $i | $SED 's/.*://'` + (./isl_schedule$EXEEXT $options < $i > $test && + ./isl_schedule_cmp$EXEEXT $ref $test && rm $test) || failed=1 +done + +test $failed -eq 0 || exit Index: contrib/isl/set_from_map.c =================================================================== --- /dev/null +++ contrib/isl/set_from_map.c @@ -0,0 +1,8 @@ +#include + +/* Return the set that was treated as the map "map". + */ +static __isl_give isl_set *set_from_map(__isl_take isl_map *map) +{ + return (isl_set *) map; +} Index: contrib/isl/set_to_map.c =================================================================== --- /dev/null +++ contrib/isl/set_to_map.c @@ -0,0 +1,10 @@ +#include + +/* Treat "set" as a map. + * Internally, isl_set is defined to isl_map, so in practice, + * this function performs a redundant cast. + */ +static __isl_give isl_map *set_to_map(__isl_take isl_set *set) +{ + return (isl_map *) set; +} Index: contrib/isl/test_inputs/affine.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/affine.polylib @@ -0,0 +1,9 @@ +# the affine hull of {[a,b] : a=b && 1 <= a <= 163} ... +3 4 +0 1 -1 0 +1 1 0 -1 +1 -1 0 163 + +# ... is {[a,b] : a=b} (and not {[In_1,In_2]}, as Omega 1.2 claims) +1 4 +0 1 -1 0 Index: contrib/isl/test_inputs/affine2.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/affine2.polylib @@ -0,0 +1,9 @@ +5 5 +1 -2 0 1 0 +1 2 0 -1 1 +1 0 -2 1 0 +1 0 2 -1 1 +1 0 0 1 -1 + +1 5 +0 1 -1 0 0 Index: contrib/isl/test_inputs/affine3.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/affine3.polylib @@ -0,0 +1,7 @@ +3 4 +1 1 0 0 +1 -7 4 2 +1 5 -4 2 + +1 4 +0 3 -2 0 Index: contrib/isl/test_inputs/application.omega =================================================================== --- /dev/null +++ contrib/isl/test_inputs/application.omega @@ -0,0 +1,3 @@ +{[x]} +{[x] -> [y] : y = 2x} +{[y]: Exists ( alpha : 2alpha = y)} Index: contrib/isl/test_inputs/application2.omega =================================================================== --- /dev/null +++ contrib/isl/test_inputs/application2.omega @@ -0,0 +1,3 @@ +{[x] : x >= 0 && x <= 20 } +{[x] -> [y] : y = 2x} +{[y]: Exists ( alpha : 2alpha = y && 0 <= y && y <= 40)} Index: contrib/isl/test_inputs/basicLinear.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/basicLinear.pwqp @@ -0,0 +1 @@ +[P, Q] -> { [n, m] -> n : n >= 1 and m >= n and m <= P and m <= Q } Index: contrib/isl/test_inputs/basicLinear2.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/basicLinear2.pwqp @@ -0,0 +1 @@ +[P, Q] -> { [n, m] -> n : n >= 1 and m >= n and m <= P and n >= -1 + Q } Index: contrib/isl/test_inputs/basicTest.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/basicTest.pwqp @@ -0,0 +1 @@ +[p] -> { [n, m] -> (n + n^2) : n >= 1 and m >= n and m <= p } Index: contrib/isl/test_inputs/basicTestParameterPosNeg.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/basicTestParameterPosNeg.pwqp @@ -0,0 +1 @@ +[p] -> { [n, m] -> (n + n^3) : n >= -1 and m >= n and m <= p } Index: contrib/isl/test_inputs/boulet.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/boulet.pip @@ -0,0 +1,13 @@ +0 3 + +-1 + +5 6 +1 1 -1 2 0 0 +1 0 1 1 4 20 +1 0 -1 -1 0 0 +1 0 1 -1 2 10 +1 0 -1 1 2 10 + +Urs_parms +Urs_unknowns Index: contrib/isl/test_inputs/brisebarre.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/brisebarre.pip @@ -0,0 +1,34 @@ +# ---------------------- CONTEXT ---------------------- +1 2 +1 0 + +-1 + +# ----------------------- DOMAIN ---------------------- +26 6 +1 3 0 0 0 -98300 +1 -3 0 0 0 98308 +1 432 36 6 1 -14757611 +1 -432 -36 -6 -1 14758510 +1 54 9 3 1 -1923190 +1 -54 -9 -3 -1 1923303 +1 48 12 6 3 -1782238 +1 -48 -12 -6 -3 1782339 +1 27 9 6 4 -1045164 +1 -27 -9 -6 -4 1045221 +1 432 180 150 125 -17434139 +1 -432 -180 -150 -125 17435038 +1 6 3 3 3 -252443 +1 -6 -3 -3 -3 252456 +1 432 252 294 343 -18949275 +1 -432 -252 -294 -343 18950174 +1 27 18 24 32 -1234720 +1 -27 -18 -24 -32 1234777 +1 48 36 54 81 -2288453 +1 -48 -36 -54 -81 2288554 +1 54 45 75 125 -2684050 +1 -54 -45 -75 -125 2684163 +1 432 396 726 1331 -22386005 +1 -432 -396 -726 -1331 22386904 +1 3 3 6 12 -162072 +1 -3 -3 -6 -12 162080 Index: contrib/isl/test_inputs/cg1.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/cg1.pip @@ -0,0 +1,15 @@ +2 4 + 1 1 0 -1 + 1 -1 1 0 + +-1 + +8 7 + 1 0 1 0 -1 0 0 + 1 0 -1 0 1 0 0 + 1 1 0 0 0 -1 0 + 1 -1 0 0 0 1 0 + 1 0 1 0 0 0 -1 + 1 0 -1 0 0 1 0 + 1 0 -1 1 0 0 -1 + 1 0 0 -1 0 1 0 Index: contrib/isl/test_inputs/codegen/atomic.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 <= 10; c0 += 1) { + if (c0 <= 9) + a(c0); + if (c0 >= 1) + b(c0 - 1); +} Index: contrib/isl/test_inputs/codegen/atomic.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic.in @@ -0,0 +1,3 @@ +{ a[i] -> [i, 0] : 0 <= i < 10; b[i] -> [i+1, 1] : 0 <= i < 10 } +{ : } +{ [i, d] -> atomic[x] } Index: contrib/isl/test_inputs/codegen/atomic.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic.st @@ -0,0 +1,8 @@ +domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }" +child: + schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]" + options: "{ atomic[x] }" + child: + sequence: + - filter: "{ a[i] }" + - filter: "{ b[i] }" Index: contrib/isl/test_inputs/codegen/atomic2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic2.c @@ -0,0 +1,2 @@ +for (int c0 = ((b0 + 32767) % 32768) + 1; c0 <= 65534; c0 += 32768) + A(c0); Index: contrib/isl/test_inputs/codegen/atomic2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic2.in @@ -0,0 +1,4 @@ +# Check that isl properly handles atomic domains that are unions. +[nn, b0] -> { A[a] -> [a, 0, b0] : exists (e0 = [(b0 - a)/32768]: 32768e0 = b0 - a and a >= 1 and b0 >= 0 and b0 <= 32767 and a <= 65534) } +[nn, b0] -> { : b0 >= 0 and b0 <= 32767 } +[nn, b0] -> { [a, b, c] -> atomic[2] : c >= 1; [a, 0, c] -> atomic[2] } Index: contrib/isl/test_inputs/codegen/atomic3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic3.c @@ -0,0 +1,9 @@ +for (int c0 = 0; c0 <= 64; c0 += 1) { + if (c0 >= 63) { + sync(); + } else if (c0 >= 1) { + sync(); + } else { + sync(); + } +} Index: contrib/isl/test_inputs/codegen/atomic3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic3.in @@ -0,0 +1,5 @@ +# Check that isl is not confused by inconsistent +# separation_class and atomic options. +{ sync[] -> [i, 0] : 0 <= i <= 64 } +{ : } +{ [i, 0] -> separation_class[[1] -> [0]] : 1 <= i <= 62; [i, 0] -> atomic[1]} Index: contrib/isl/test_inputs/codegen/atomic4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic4.c @@ -0,0 +1,2 @@ +for (int c0 = 0; c0 <= 64; c0 += 1) + sync(); Index: contrib/isl/test_inputs/codegen/atomic4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/atomic4.in @@ -0,0 +1,4 @@ +# Check that isl is not confused by inconsistent separate and atomic options. +{ sync[] -> [i, 0] : 0 <= i <= 64 } +{ : } +{ [i, 0] -> separate[1] : 1 <= i <= 62; [i, 0] -> atomic[1] : i <= 10 or i >= 20 } Index: contrib/isl/test_inputs/codegen/cholesky.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cholesky.c @@ -0,0 +1,4 @@ +for (int c0 = 3993; c0 <= 63893; c0 += 1) + if (2 * c0 - 3993 * ((3 * c0 + 5990) / 5990) >= 0) + for (int c4 = -c0 + 1997 * ((3 * c0 + 5990) / 5990) + 1; c4 <= 12; c4 += 1) + S_3(c4, -c0 + 1997 * ((3 * c0 + 5990) / 5990), 2 * c0 - 3993 * ((3 * c0 + 5990) / 5990)); Index: contrib/isl/test_inputs/codegen/cholesky.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cholesky.st @@ -0,0 +1,9 @@ +# Earlier versions of isl would fail to produce an AST for this input +# due to a simplification bug. +domain: "{ S_3[i, j, k] : 0 <= i <= 12 and 0 <= j < i and 0 <= k < j }" +child: + schedule: "[{ S_3[i, j, k] -> [(3993j + 1997k)] }]" + child: + schedule: "[{ S_3[i, j, k] -> [(32*floor((2j + k)/32))] }, { S_3[i, j, k] -> [(32*floor((i)/32))] }]" + child: + schedule: "[{ S_3[i, j, k] -> [(2j + k - 32*floor((2j + k)/32))] }, { S_3[i, j, k] -> [(i)] }]" Index: contrib/isl/test_inputs/codegen/cloog/0D-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/0D-1.c @@ -0,0 +1 @@ +S1(); Index: contrib/isl/test_inputs/codegen/cloog/0D-1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/0D-1.st @@ -0,0 +1,3 @@ +domain: "{ S1[] }" +child: + context: "{ [] }" Index: contrib/isl/test_inputs/codegen/cloog/0D-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/0D-2.c @@ -0,0 +1,2 @@ +if (M >= 0) + S1(); Index: contrib/isl/test_inputs/codegen/cloog/0D-2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/0D-2.st @@ -0,0 +1,3 @@ +domain: "[M] -> { S1[] : M >= 0 }" +child: + context: "[M] -> { [] }" Index: contrib/isl/test_inputs/codegen/cloog/0D-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/0D-3.c @@ -0,0 +1 @@ +S1(); Index: contrib/isl/test_inputs/codegen/cloog/0D-3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/0D-3.st @@ -0,0 +1,3 @@ +domain: "[M] -> { S1[] : M >= 0 }" +child: + context: "[M] -> { [] : M >= 0 }" Index: contrib/isl/test_inputs/codegen/cloog/1point-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/1point-1.c @@ -0,0 +1 @@ +S1(2 * M, M); Index: contrib/isl/test_inputs/codegen/cloog/1point-1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/1point-1.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[2M, M] }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/1point-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/1point-2.c @@ -0,0 +1 @@ +S1(2 * M, N + 2); Index: contrib/isl/test_inputs/codegen/cloog/1point-2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/1point-2.st @@ -0,0 +1,6 @@ +domain: "[M, N] -> { S1[2M, 2 + N] }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/4-param.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/4-param.c @@ -0,0 +1,14 @@ +{ + for (int c0 = p; c0 <= min(m - 1, q); c0 += 1) + S2(c0); + for (int c0 = m; c0 <= min(n, p - 1); c0 += 1) + S1(c0); + for (int c0 = max(m, p); c0 <= min(n, q); c0 += 1) { + S1(c0); + S2(c0); + } + for (int c0 = max(max(m, n + 1), p); c0 <= q; c0 += 1) + S2(c0); + for (int c0 = max(max(m, p), q + 1); c0 <= n; c0 += 1) + S1(c0); +} Index: contrib/isl/test_inputs/codegen/cloog/4-param.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/4-param.st @@ -0,0 +1,10 @@ +domain: "[m, n, p, q] -> { S1[i0] : i0 >= m and i0 <= n; S2[i0] : i0 >= p and i0 <= q }" +child: + context: "[m, n, p, q] -> { [] }" + child: + schedule: "[m, n, p, q] -> [{ S2[i0] -> [(i0)]; S1[i0] -> [(i0)] }]" + options: "[m, n, p, q] -> { separate[i0] }" + child: + sequence: + - filter: "[m, n, p, q] -> { S1[i0] }" + - filter: "[m, n, p, q] -> { S2[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/README =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/README @@ -0,0 +1,2 @@ +The tests in this directory have been adapted from the corresponding CLooG +test cases. Index: contrib/isl/test_inputs/codegen/cloog/backtrack.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/backtrack.c @@ -0,0 +1 @@ +S1(0); Index: contrib/isl/test_inputs/codegen/cloog/backtrack.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/backtrack.st @@ -0,0 +1,6 @@ +domain: "{ S1[0] }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0] -> [(i0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-1.c @@ -0,0 +1,2 @@ +for (int c0 = 0; c0 <= 2; c0 += 1) + S1(c0); Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-1.st @@ -0,0 +1,6 @@ +domain: "{ S1[i0] : i0 >= 0 and i0 <= 2 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0] -> [(i0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-2.c @@ -0,0 +1 @@ +S1(0); Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-2.st @@ -0,0 +1,6 @@ +domain: "{ S1[0] }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0] -> [(i0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-3.c @@ -0,0 +1,2 @@ +for (int c0 = 0; c0 <= M; c0 += 1) + S1(c0); Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-3.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0] : i0 >= 0 and i0 <= M }" +child: + context: "[M] -> { [] : M >= 0 }" + child: + schedule: "[M] -> [{ S1[i0] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-4.c @@ -0,0 +1,2 @@ +for (int c0 = 0; c0 <= M + 1; c0 += 1) + S1(c0); Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-4.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-4.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0] : i0 >= 0 and i0 <= 1 + M }" +child: + context: "[M] -> { [] : M >= 0 }" + child: + schedule: "[M] -> [{ S1[i0] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-5.c @@ -0,0 +1 @@ +S1(1, floord(M + 1, 2)); Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-5.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-5.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[1, i1] : 2i1 >= M and 2i1 <= 1 + M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-6.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-6.c @@ -0,0 +1 @@ +S1(-1); Index: contrib/isl/test_inputs/codegen/cloog/basic-bounds-6.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/basic-bounds-6.st @@ -0,0 +1,6 @@ +domain: "{ S1[-1] }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0] -> [(i0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/block.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/block.c @@ -0,0 +1,6 @@ +{ + S1(); + S3(0); + S2(); + S3(1); +} Index: contrib/isl/test_inputs/codegen/cloog/block.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/block.st @@ -0,0 +1,10 @@ +domain: "{ S1[]; S3[i0] : i0 >= 0 and i0 <= 1; S2[] }" +child: + context: "{ [] }" + child: + schedule: "[{ S2[] -> [(1)]; S3[i0] -> [(i0)]; S1[] -> [(0)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[]; S2[] }" + - filter: "{ S3[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/block2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/block2.c @@ -0,0 +1,5 @@ +for (int c0 = 0; c0 <= 9; c0 += 1) { + S1(c0, 1); + S3(c0, 1); + S2(c0, 1); +} Index: contrib/isl/test_inputs/codegen/cloog/block2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/block2.st @@ -0,0 +1,11 @@ +domain: "{ S2[i0, 1] : i0 >= 0 and i0 <= 9; S1[i0, 1] : i0 >= 0 and i0 <= 9; S3[i0, 1] : i0 >= 0 and i0 <= 9 }" +child: + context: "{ [] }" + child: + schedule: "[{ S3[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S3[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1] }" + - filter: "{ S3[i0, i1] }" + - filter: "{ S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/block3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/block3.c @@ -0,0 +1,6 @@ +{ + S1(); + for (int c0 = 0; c0 <= 1; c0 += 1) + S3(c0); + S2(); +} Index: contrib/isl/test_inputs/codegen/cloog/block3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/block3.st @@ -0,0 +1,6 @@ +domain: "{ S1[]; S3[i0] : i0 >= 0 and i0 <= 1; S2[] }" +child: + context: "{ [] }" + child: + schedule: "[{ S2[] -> [(1)]; S3[i0] -> [(i0)]; S1[] -> [(0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/byu98-1-2-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/byu98-1-2-3.c @@ -0,0 +1,18 @@ +{ + for (int c0 = 2; c0 <= 3; c0 += 1) + for (int c1 = -c0 + 6; c1 <= 6; c1 += 1) + S1(c0, c1); + for (int c0 = 4; c0 <= 8; c0 += 1) { + if (c0 == 4) + for (int c1 = 3; c1 <= 4; c1 += 1) + S1(4, c1); + if (c0 <= 5) { + S1(c0, -c0 + 9); + S2(c0, -c0 + 9); + } else { + S2(c0, -c0 + 9); + } + for (int c1 = max(c0 - 1, -c0 + 10); c1 <= 6; c1 += 1) + S1(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/cloog/byu98-1-2-3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/byu98-1-2-3.st @@ -0,0 +1,10 @@ +domain: "{ S2[i0, 9 - i0] : i0 <= 8 and i0 >= 4; S1[i0, i1] : i1 >= 6 - i0 and i0 >= 2 and i1 >= 3 and i1 <= 6 and i1 >= -1 + i0 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1] }" + - filter: "{ S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/cholesky.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/cholesky.c @@ -0,0 +1,12 @@ +for (int c0 = 1; c0 <= n; c0 += 1) { + S1(c0); + for (int c1 = 1; c1 < c0; c1 += 1) + S2(c0, c1); + S3(c0); + for (int c1 = c0 + 1; c1 <= n; c1 += 1) { + S4(c0, c1); + for (int c2 = 1; c2 < c0; c2 += 1) + S5(c0, c1, c2); + S6(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/cloog/cholesky.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/cholesky.st @@ -0,0 +1,26 @@ +domain: "[n] -> { S2[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= -1 + i0; S1[i0] : i0 >= 1 and i0 <= n; S4[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n; S5[i0, i1, i2] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n and i2 >= 1 and i2 <= -1 + i0; S6[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n; S3[i0] : i0 >= 1 and i0 <= n }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S1[i0] -> [(i0)]; S4[i0, i1] -> [(i0)]; S6[i0, i1] -> [(i0)]; S3[i0] -> [(i0)]; S5[i0, i1, i2] -> [(i0)]; S2[i0, i1] -> [(i0)] }]" + options: "[n] -> { separate[i0] }" + child: + sequence: + - filter: "[n] -> { S1[i0] }" + - filter: "[n] -> { S2[i0, i1] }" + child: + schedule: "[n] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[n] -> { separate[i0] }" + - filter: "[n] -> { S3[i0] }" + - filter: "[n] -> { S4[i0, i1]; S5[i0, i1, i2]; S6[i0, i1] }" + child: + schedule: "[n] -> [{ S4[i0, i1] -> [(i1)]; S6[i0, i1] -> [(i1)]; S5[i0, i1, i2] -> [(i1)] }]" + options: "[n] -> { separate[i0] }" + child: + sequence: + - filter: "[n] -> { S4[i0, i1] }" + - filter: "[n] -> { S5[i0, i1, i2] }" + child: + schedule: "[n] -> [{ S5[i0, i1, i2] -> [(i2)] }]" + options: "[n] -> { separate[i0] }" + - filter: "[n] -> { S6[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/cholesky2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/cholesky2.c @@ -0,0 +1,17 @@ +{ + for (int c1 = 1; c1 <= M; c1 += 1) { + S1(c1); + for (int c2 = c1 + 1; c2 <= M; c2 += 1) + S4(c1, c2); + } + for (int c0 = 1; c0 < 3 * M - 1; c0 += 3) { + S3((c0 + 2) / 3); + for (int c1 = (c0 + 5) / 3; c1 <= M; c1 += 1) { + S6((c0 + 2) / 3, c1); + for (int c4 = (c0 + 5) / 3; c4 < c1; c4 += 1) + S5(c4, c1, (c0 + 2) / 3); + } + for (int c1 = (c0 + 5) / 3; c1 <= M; c1 += 1) + S2(c1, (c0 + 2) / 3); + } +} Index: contrib/isl/test_inputs/codegen/cloog/cholesky2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/cholesky2.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S4[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M; S5[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M and i2 >= 1 and i2 <= -1 + i0; S6[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M; S3[i0] : i0 >= 1 and i0 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= -1 + i0; S1[i0] : i0 >= 1 and i0 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0] -> [(0)]; S3[i0] -> [(-2 + 3i0)]; S4[i0, i1] -> [(0)]; S5[i0, i1, i2] -> [(-1 + 3i2)]; S2[i0, i1] -> [(3i1)]; S6[i0, i1] -> [(-1 + 3i0)] }, { S1[i0] -> [(i0)]; S3[i0] -> [(0)]; S4[i0, i1] -> [(i0)]; S5[i0, i1, i2] -> [(i1)]; S2[i0, i1] -> [(i0)]; S6[i0, i1] -> [(i1)] }, { S1[i0] -> [(0)]; S3[i0] -> [(0)]; S4[i0, i1] -> [(i1)]; S5[i0, i1, i2] -> [(i2)]; S2[i0, i1] -> [(0)]; S6[i0, i1] -> [(0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/christian.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/christian.c @@ -0,0 +1,6 @@ +for (int c0 = -N + 1; c0 <= N; c0 += 1) { + for (int c1 = max(0, c0); c1 < min(N, N + c0); c1 += 1) + S1(c1, -c0 + c1); + for (int c1 = max(0, c0 - 1); c1 < min(N, N + c0 - 1); c1 += 1) + S2(c1, -c0 + c1 + 1); +} Index: contrib/isl/test_inputs/codegen/cloog/christian.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/christian.st @@ -0,0 +1,6 @@ +domain: "[N] -> { S1[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N; S2[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N }" +child: + context: "[N] -> { [] }" + child: + schedule: "[N] -> [{ S1[i0, i1] -> [(i0 - i1)]; S2[i0, i1] -> [(1 + i0 - i1)] }]" + options: "[N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/classen.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/classen.c @@ -0,0 +1,86 @@ +if (m >= 1) { + if (m == 1) { + S1(0, 1, 1, 1); + S8(0, 1); + } else { + S1(0, 1, 1, 1); + S2(0, 1, 1, 1, 1, 1, 2, 1); + S3(0, 1, 1, 2, 1, 1, 1, 2); + S4(0, 1, 2, 2, 1, 1, 2, 2); + S8(0, 1); + } + for (int c0 = 1; c0 < 2 * m - 3; c0 += 1) { + if (c0 + 1 == m) { + S5(m - 2, 1, m - 1, 1, m - 1, 1, m, 1); + S1(m - 1, 1, m, 1); + S3(m - 1, 1, m, 2, m, 1, m, 2); + } else if (m >= c0 + 2) { + S5(c0 - 1, 1, c0, 1, c0, 1, c0 + 1, 1); + S1(c0, 1, c0 + 1, 1); + S2(c0, 1, c0 + 1, 1, c0 + 1, 1, c0 + 2, 1); + S4(c0, 1, c0 + 2, 2, c0 + 1, 1, c0 + 2, 2); + S3(c0, 1, c0 + 1, 2, c0 + 1, 1, c0 + 1, 2); + } else { + S5(c0 - 1, -m + c0 + 2, c0, -m + c0 + 2, m - 1, -m + c0 + 2, m, -m + c0 + 2); + S6(c0 - 1, -m + c0 + 1, c0, -m + c0 + 2, m, -m + c0 + 1, m, -m + c0 + 2); + S1(c0, -m + c0 + 2, m, -m + c0 + 2); + S3(c0, -m + c0 + 2, c0 + 1, -m + c0 + 3, m, -m + c0 + 2, m, -m + c0 + 3); + } + for (int c1 = max(2, -m + c0 + 3); c1 <= min(m - 1, c0); c1 += 1) { + S5(c0 - 1, c1, c0, c1, c0 - c1 + 1, c1, c0 - c1 + 2, c1); + S7(c0 - 1, c1 - 1, c0 + 1, c1, c0 - c1 + 2, c1 - 1, c0 - c1 + 3, c1); + S6(c0 - 1, c1 - 1, c0, c1, c0 - c1 + 2, c1 - 1, c0 - c1 + 2, c1); + S1(c0, c1, c0 - c1 + 2, c1); + S2(c0, c1, c0 + 1, c1, c0 - c1 + 2, c1, c0 - c1 + 3, c1); + S4(c0, c1, c0 + 2, c1 + 1, c0 - c1 + 2, c1, c0 - c1 + 3, c1 + 1); + S3(c0, c1, c0 + 1, c1 + 1, c0 - c1 + 2, c1, c0 - c1 + 2, c1 + 1); + } + if (c0 + 1 == m) { + S7(m - 2, m - 1, m, m, 1, m - 1, 2, m); + S6(m - 2, m - 1, m - 1, m, 1, m - 1, 1, m); + S1(m - 1, m, 1, m); + S2(m - 1, m, m, m, 1, m, 2, m); + } else if (c0 >= m) { + S5(c0 - 1, m, c0, m, -m + c0 + 1, m, -m + c0 + 2, m); + S7(c0 - 1, m - 1, c0 + 1, m, -m + c0 + 2, m - 1, -m + c0 + 3, m); + S6(c0 - 1, m - 1, c0, m, -m + c0 + 2, m - 1, -m + c0 + 2, m); + S1(c0, m, -m + c0 + 2, m); + S2(c0, m, c0 + 1, m, -m + c0 + 2, m, -m + c0 + 3, m); + } else { + S6(c0 - 1, c0, c0, c0 + 1, 1, c0, 1, c0 + 1); + S7(c0 - 1, c0, c0 + 1, c0 + 1, 1, c0, 2, c0 + 1); + S1(c0, c0 + 1, 1, c0 + 1); + S2(c0, c0 + 1, c0 + 1, c0 + 1, 1, c0 + 1, 2, c0 + 1); + S4(c0, c0 + 1, c0 + 2, c0 + 2, 1, c0 + 1, 2, c0 + 2); + S3(c0, c0 + 1, c0 + 1, c0 + 2, 1, c0 + 1, 1, c0 + 2); + } + for (int c2 = max(1, -m + c0 + 2); c2 <= min(m, c0 + 1); c2 += 1) + S8(c0, c2); + } + if (m >= 2) { + if (m >= 3) { + S5(2 * m - 4, m - 1, 2 * m - 3, m - 1, m - 1, m - 1, m, m - 1); + S6(2 * m - 4, m - 2, 2 * m - 3, m - 1, m, m - 2, m, m - 1); + S1(2 * m - 3, m - 1, m, m - 1); + S3(2 * m - 3, m - 1, 2 * m - 2, m, m, m - 1, m, m); + S5(2 * m - 4, m, 2 * m - 3, m, m - 2, m, m - 1, m); + S7(2 * m - 4, m - 1, 2 * m - 2, m, m - 1, m - 1, m, m); + S6(2 * m - 4, m - 1, 2 * m - 3, m, m - 1, m - 1, m - 1, m); + S1(2 * m - 3, m, m - 1, m); + } else { + S5(0, 1, 1, 1, 1, 1, 2, 1); + S1(1, 1, 2, 1); + S3(1, 1, 2, 2, 2, 1, 2, 2); + S7(0, 1, 2, 2, 1, 1, 2, 2); + S6(0, 1, 1, 2, 1, 1, 1, 2); + S1(1, 2, 1, 2); + } + S2(2 * m - 3, m, 2 * m - 2, m, m - 1, m, m, m); + for (int c2 = m - 1; c2 <= m; c2 += 1) + S8(2 * m - 3, c2); + S5(2 * m - 3, m, 2 * m - 2, m, m - 1, m, m, m); + S6(2 * m - 3, m - 1, 2 * m - 2, m, m, m - 1, m, m); + S1(2 * m - 2, m, m, m); + S8(2 * m - 2, m); + } +} Index: contrib/isl/test_inputs/codegen/cloog/classen.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/classen.st @@ -0,0 +1,24 @@ +domain: "[m] -> { S2[coordT1, coordP1, 1 + coordT1, coordP1, 2 + coordT1 - coordP1, coordP1, 3 + coordT1 - coordP1, coordP1] : m >= 1 and coordT1 <= -3 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= m and coordP1 >= 3 - m + coordT1 and coordP1 >= 1; S4[coordT1, coordP1, 2 + coordT1, 1 + coordP1, 2 + coordT1 - coordP1, coordP1, 3 + coordT1 - coordP1, 1 + coordP1] : m >= 1 and coordT1 <= -4 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= -1 + m and coordP1 >= 3 - m + coordT1 and coordP1 >= 1; S6[coordT1, coordP1, 1 + coordT1, 1 + coordP1, 2 + coordT1 - coordP1, coordP1, 2 + coordT1 - coordP1, 1 + coordP1] : m >= 1 and coordT1 <= -3 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= -1 + m and coordP1 >= 2 - m + coordT1 and coordP1 >= 1; S1[coordT1, coordP1, 2 + coordT1 - coordP1, coordP1] : m >= 1 and coordP1 >= 2 - m + coordT1 and coordP1 <= 1 + coordT1 and coordP1 <= m and coordP1 >= 1; S8[coordT1, coordP1] : coordT1 <= -2 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= m and coordP1 >= 2 - m + coordT1 and coordP1 >= 1; S5[coordT1, coordP1, 1 + coordT1, coordP1, 2 + coordT1 - coordP1, coordP1, 3 + coordT1 - coordP1, coordP1] : m >= 1 and coordT1 <= -3 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= m and coordP1 >= 3 - m + coordT1 and coordP1 >= 1; S7[coordT1, coordP1, 2 + coordT1, 1 + coordP1, 2 + coordT1 - coordP1, coordP1, 3 + coordT1 - coordP1, 1 + coordP1] : m >= 1 and coordT1 <= -4 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= -1 + m and coordP1 >= 3 - m + coordT1 and coordP1 >= 1; S3[coordT1, coordP1, 1 + coordT1, 1 + coordP1, 2 + coordT1 - coordP1, coordP1, 2 + coordT1 - coordP1, 1 + coordP1] : m >= 1 and coordT1 <= -3 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= -1 + m and coordP1 >= 2 - m + coordT1 and coordP1 >= 1 }" +child: + context: "[m] -> { [] : m >= 0 }" + child: + schedule: "[m] -> [{ S7[i0, i1, i2, i3, i4, i5, i6, i7] -> [(1 + i0)]; S4[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i0)]; S8[i0, i1] -> [(i0)]; S3[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i0)]; S1[i0, i1, i2, i3] -> [(i0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i0)]; S5[i0, i1, i2, i3, i4, i5, i6, i7] -> [(1 + i0)]; S6[i0, i1, i2, i3, i4, i5, i6, i7] -> [(1 + i0)] }]" + options: "[m] -> { separate[i0] }" + child: + sequence: + - filter: "[m] -> { S2[i0, i1, i2, i3, i4, i5, i6, i7]; S6[i0, i1, i2, i3, i4, i5, i6, i7]; S4[i0, i1, i2, i3, i4, i5, i6, i7]; S1[i0, i1, i2, i3]; S7[i0, i1, i2, i3, i4, i5, i6, i7]; S5[i0, i1, i2, i3, i4, i5, i6, i7]; S3[i0, i1, i2, i3, i4, i5, i6, i7] }" + child: + schedule: "[m] -> [{ S7[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i3)]; S4[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i1)]; S3[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i1)]; S1[i0, i1, i2, i3] -> [(i1)]; S2[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i1)]; S5[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i3)]; S6[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i3)] }]" + options: "[m] -> { separate[i0] }" + child: + sequence: + - filter: "[m] -> { S6[i0, i1, i2, i3, i4, i5, i6, i7]; S5[i0, i1, i2, i3, i4, i5, i6, i7]; S7[i0, i1, i2, i3, i4, i5, i6, i7] }" + child: + schedule: "[m] -> [{ S7[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)]; S5[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)]; S6[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)] }, { S7[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)]; S5[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)]; S6[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)] }]" + options: "[m] -> { separate[i0] }" + - filter: "[m] -> { S1[i0, i1, i2, i3] }" + - filter: "[m] -> { S2[i0, i1, i2, i3, i4, i5, i6, i7]; S4[i0, i1, i2, i3, i4, i5, i6, i7]; S3[i0, i1, i2, i3, i4, i5, i6, i7] }" + child: + schedule: "[m] -> [{ S4[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)]; S3[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)]; S2[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)] }, { S4[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)]; S3[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)]; S2[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)] }]" + options: "[m] -> { separate[i0] }" + - filter: "[m] -> { S8[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/classen2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/classen2.c @@ -0,0 +1,4 @@ +for (int c0 = max(max(max(max(max(max(4, 5 * outerTimeTileScatter), 5 * outerProcTileScatter1), 5 * outerProcTileScatter2 + 1), 5 * outerProcTileScatter1 + 5 * outerProcTileScatter2 - N), 10 * outerProcTileScatter2 - N + 1), 10 * outerProcTileScatter1 - 2 * N + 2); c0 <= min(min(min(min(min(min(5 * outerTimeTileScatter + 4, 10 * outerProcTileScatter1 + 4), 5 * outerProcTileScatter1 + 5 * outerProcTileScatter2 + 5), 5 * outerProcTileScatter1 + M + 2), 2 * M + 2 * N - 6), 5 * outerProcTileScatter2 + M + N), 10 * outerProcTileScatter2 + N + 3); c0 += 1) + for (int c1 = max(max(max(max(5 * outerProcTileScatter1, 5 * outerProcTileScatter2 + 1), -5 * outerProcTileScatter2 + c0 - 1), -M + c0 + 2), (c0 + 1) / 2 + 2); c1 <= min(min(min(min(5 * outerProcTileScatter1 + 4, 5 * outerProcTileScatter2 + N + 2), -5 * outerProcTileScatter2 + N + c0), c0), N + c0 / 2 - 1); c1 += 1) + for (int c2 = max(max(5 * outerProcTileScatter2, -N + c1 + 2), c0 - c1 + 3); c2 <= min(min(5 * outerProcTileScatter2 + 4, c1 - 1), N + c0 - c1); c2 += 1) + S1(c0 - c1 + 1, -c0 + c1 + c2 - 2, c1 - c2, c0, c1, c2); Index: contrib/isl/test_inputs/codegen/cloog/classen2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/classen2.st @@ -0,0 +1,6 @@ +domain: "[outerTimeTileScatter, outerProcTileScatter1, outerProcTileScatter2, M, N] -> { S1[compIter1, compIter2, compIter3, 2compIter1 + compIter2 + compIter3, 1 + compIter1 + compIter2 + compIter3, 1 + compIter1 + compIter2] : N >= 3 and compIter3 <= 3 + 5outerProcTileScatter1 - compIter1 - compIter2 and compIter2 >= -1 + 5outerProcTileScatter2 - compIter1 and M >= 2 and compIter3 <= 4 + 5outerTimeTileScatter - 2compIter1 - compIter2 and compIter2 <= 3 + 5outerProcTileScatter2 - compIter1 and compIter3 >= 1 and compIter3 <= -2 + N and compIter2 >= 1 and compIter2 <= -2 + N and compIter1 >= 1 and compIter1 <= -1 + M and compIter3 >= 5outerTimeTileScatter - 2compIter1 - compIter2 and compIter3 >= -1 + 5outerProcTileScatter1 - compIter1 - compIter2 }" +child: + context: "[outerTimeTileScatter, outerProcTileScatter1, outerProcTileScatter2, M, N] -> { [] }" + child: + schedule: "[outerTimeTileScatter, outerProcTileScatter1, outerProcTileScatter2, M, N] -> [{ S1[i0, i1, i2, i3, i4, i5] -> [(i3)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i4)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i5)] }]" + options: "[outerTimeTileScatter, outerProcTileScatter1, outerProcTileScatter2, M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/constant.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/constant.c @@ -0,0 +1,18 @@ +{ + for (int c1 = 0; c1 <= min(1023, M + 1024); c1 += 1) { + S1(c1); + S3(c1); + } + for (int c1 = max(0, M + 1025); c1 <= 1023; c1 += 1) { + S2(c1); + S3(c1); + } + for (int c0 = 0; c0 <= min(1023, M + 1024); c0 += 1) { + S4(c0); + S6(c0); + } + for (int c0 = max(0, M + 1025); c0 <= 1023; c0 += 1) { + S5(c0); + S6(c0); + } +} Index: contrib/isl/test_inputs/codegen/cloog/constant.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/constant.st @@ -0,0 +1,11 @@ +domain: "[M] -> { S4[i0] : i0 >= 0 and i0 <= 1023 and i0 <= 1024 + M; S5[i0] : i0 >= 0 and i0 <= 1023 and i0 >= 1025 + M; S3[i0] : i0 >= 0 and i0 <= 1023; S2[i0] : i0 >= 0 and i0 <= 1023 and i0 >= 1025 + M; S1[i0] : i0 >= 0 and i0 <= 1023 and i0 <= 1024 + M; S6[i0] : i0 >= 0 and i0 <= 1023 }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S2[i0] -> [(-1)]; S4[i0] -> [(i0)]; S1[i0] -> [(-1)]; S3[i0] -> [(-1)]; S6[i0] -> [(i0)]; S5[i0] -> [(i0)] }, { S2[i0] -> [(i0)]; S4[i0] -> [(0)]; S1[i0] -> [(i0)]; S3[i0] -> [(i0)]; S6[i0] -> [(0)]; S5[i0] -> [(0)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S4[i0]; S1[i0] }" + - filter: "[M] -> { S5[i0]; S2[i0] }" + - filter: "[M] -> { S3[i0]; S6[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/constbound.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/constbound.c @@ -0,0 +1,8 @@ +for (int c0 = 0; c0 <= 199; c0 += 1) { + for (int c1 = 50 * c0; c1 <= 50 * c0 + 24; c1 += 1) + for (int c2 = 0; c2 <= c1; c2 += 1) + S1(c0, c1, c2); + for (int c1 = 50 * c0 + 25; c1 <= 50 * c0 + 49; c1 += 1) + for (int c2 = 0; c2 <= c1; c2 += 1) + S2(c0, c1, c2); +} Index: contrib/isl/test_inputs/codegen/cloog/constbound.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/constbound.st @@ -0,0 +1,16 @@ +domain: "{ S2[i0, i1, i2] : i1 >= 0 and i1 <= 9999 and i2 >= 0 and i2 <= i1 and i1 >= 25 + 50i0 and i1 <= 49 + 50i0; S1[i0, i1, i2] : i1 >= 0 and i1 <= 9999 and i2 >= 0 and i2 <= i1 and i1 >= 50i0 and i1 <= 24 + 50i0 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1, i2] }" + child: + schedule: "[{ S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]" + options: "{ separate[i0] }" + - filter: "{ S2[i0, i1, i2] }" + child: + schedule: "[{ S2[i0, i1, i2] -> [(i1)] }, { S2[i0, i1, i2] -> [(i2)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/darte.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/darte.c @@ -0,0 +1,14 @@ +for (int c0 = -n + 1; c0 <= n; c0 += 1) { + if (c0 <= 0) + for (int c2 = -c0 + 4; c2 <= 2 * n - c0 + 2; c2 += 2) + S1(1, -c0 + 1, ((c0 + c2) / 2) - 1); + for (int c1 = max(c0 + 2, -c0 + 4); c1 <= min(2 * n - c0, 2 * n + c0); c1 += 2) { + for (int c2 = c1 + 2; c2 <= 2 * n + c1; c2 += 2) + S1((c0 + c1) / 2, (-c0 + c1) / 2, (-c1 + c2) / 2); + for (int c2 = 1; c2 <= n; c2 += 1) + S2(((c0 + c1) / 2) - 1, (-c0 + c1) / 2, c2); + } + if (c0 >= 1) + for (int c2 = 1; c2 <= n; c2 += 1) + S2(n, n - c0 + 1, c2); +} Index: contrib/isl/test_inputs/codegen/cloog/darte.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/darte.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[i0, i1, i2] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= n and i2 >= 1 and i2 <= n; S2[i0, i1, i2] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= n and i2 >= 1 and i2 <= n }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S1[i0, i1, i2] -> [(i0 - i1)]; S2[i0, i1, i2] -> [(1 + i0 - i1)] }, { S1[i0, i1, i2] -> [(i0 + i1)]; S2[i0, i1, i2] -> [(2 + i0 + i1)] }, { S1[i0, i1, i2] -> [(i0 + i1 + 2i2)]; S2[i0, i1, i2] -> [(i2)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/dealII.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/dealII.c @@ -0,0 +1,18 @@ +{ + for (int c0 = 0; c0 <= min(min(T_2 - 1, T_67 - 1), T_66); c0 += 1) { + S1(c0); + S2(c0); + } + for (int c0 = max(0, T_66 + 1); c0 < min(T_2, T_67); c0 += 1) + S1(c0); + for (int c0 = T_67; c0 <= min(T_2 - 1, T_66); c0 += 1) { + S1(c0); + S2(c0); + } + for (int c0 = max(T_67, T_66 + 1); c0 < T_2; c0 += 1) + S1(c0); + for (int c0 = T_2; c0 <= min(T_67 - 1, T_66); c0 += 1) + S2(c0); + if (T_2 == 0 && T_67 == 0) + S1(0); +} Index: contrib/isl/test_inputs/codegen/cloog/dealII.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/dealII.st @@ -0,0 +1,10 @@ +domain: "[T_2, T_67, T_66] -> { S1[scat_0] : (scat_0 >= 0 and scat_0 <= -1 + T_2) or (scat_0 <= -T_67 and scat_0 >= 0); S2[scat_0] : (scat_0 >= 0 and scat_0 <= T_66 and scat_0 <= -1 + T_2) or (scat_0 >= 0 and scat_0 <= T_66 and scat_0 <= -1 + T_67) }" +child: + context: "[T_2, T_67, T_66] -> { [] : T_2 <= 4 and T_2 >= 0 and T_67 <= 4 and T_67 >= 0 }" + child: + schedule: "[T_2, T_67, T_66] -> [{ S2[scat_0] -> [(scat_0)]; S1[scat_0] -> [(scat_0)] }]" + options: "[T_2, T_67, T_66] -> { separate[i0] }" + child: + sequence: + - filter: "[T_2, T_67, T_66] -> { S1[scat_0] }" + - filter: "[T_2, T_67, T_66] -> { S2[scat_0] }" Index: contrib/isl/test_inputs/codegen/cloog/donotsimp.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/donotsimp.c @@ -0,0 +1,6 @@ +for (int c0 = 1; c0 <= 10; c0 += 1) { + for (int c1 = 1; c1 <= c0; c1 += 1) + S1(c0, c1); + for (int c1 = 11; c1 <= M; c1 += 1) + S2(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/donotsimp.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/donotsimp.st @@ -0,0 +1,9 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= 10 and i1 >= 1 and i1 <= i0; S2[i0, i1] : i0 >= 1 and i0 <= 10 and i1 >= 11 and i1 <= M }" +child: + context: "[M] -> { [] : M >= 20 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/dot.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/dot.c @@ -0,0 +1,7 @@ +{ + for (int c1 = 1; c1 <= M; c1 += 1) + S1(0, c1); + for (int c0 = 1; c0 <= N; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/dot.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/dot.st @@ -0,0 +1,10 @@ +domain: "[M, N] -> { S1[0, i1] : i1 <= M and N >= 0 and i1 >= 1; S2[i0, i1] : i0 >= 1 and i1 <= M and i0 <= N and i1 >= 1 }" +child: + context: "[M, N] -> { [] : M >= 1 and N >= 1 }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1] }" + - filter: "[M, N] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/dot2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/dot2.c @@ -0,0 +1,12 @@ +{ + for (int c0 = 1; c0 <= min(M, N); c0 += 1) { + S1(c0); + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c0, c1); + } + for (int c0 = M + 1; c0 <= N; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c0, c1); + for (int c0 = N + 1; c0 <= M; c0 += 1) + S1(c0); +} Index: contrib/isl/test_inputs/codegen/cloog/dot2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/dot2.st @@ -0,0 +1,10 @@ +domain: "[M, N] -> { S1[i0] : i0 >= 1 and i0 <= M; S2[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M }" +child: + context: "[M, N] -> { [] : M >= 1 and N >= 1 }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0] }" + - filter: "[M, N] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/durbin_e_s.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/durbin_e_s.c @@ -0,0 +1,23 @@ +{ + S4(1, 0, 0); + S7(1, 0, 0); + S8(1, 0, 3); + for (int c0 = 2; c0 <= 9; c0 += 1) { + S2(c0, -7, 0); + for (int c1 = -7; c1 < c0 - 8; c1 += 1) + S3(c0, c1, 1); + S6(c0, c0 - 9, 2); + S8(c0, 0, 3); + for (int c1 = 1; c1 < c0; c1 += 1) + S5(c0, c1, 3); + } + S2(10, -7, 0); + for (int c1 = -7; c1 <= 1; c1 += 1) + S3(10, c1, 1); + S6(10, 1, 2); + for (int c1 = 1; c1 <= 9; c1 += 1) { + S5(10, c1, 3); + S1(10, c1, 4); + } + S1(10, 10, 4); +} Index: contrib/isl/test_inputs/codegen/cloog/durbin_e_s.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/durbin_e_s.st @@ -0,0 +1,16 @@ +domain: "{ S2[i0, -7, 0] : i0 >= 2 and i0 <= 10; S4[1, 0, 0]; S6[i0, -9 + i0, 2] : i0 >= 2 and i0 <= 10; S1[10, i1, 4] : i1 >= 1 and i1 <= 10; S5[i0, i1, 3] : i1 <= -1 + i0 and i0 <= 10 and i1 >= 1; S7[1, 0, 0]; S8[i0, 0, 3] : i0 >= 1 and i0 <= 9; S3[i0, i1, 1] : i1 >= -7 and i0 <= 10 and i1 <= -9 + i0 }" +child: + context: "{ [] }" + child: + schedule: "[{ S6[i0, i1, i2] -> [(i0)]; S8[i0, i1, i2] -> [(i0)]; S5[i0, i1, i2] -> [(i0)]; S4[i0, i1, i2] -> [(i0)]; S7[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }, { S6[i0, i1, i2] -> [(i1)]; S8[i0, i1, i2] -> [(i1)]; S5[i0, i1, i2] -> [(i1)]; S4[i0, i1, i2] -> [(i1)]; S7[i0, i1, i2] -> [(i1)]; S3[i0, i1, i2] -> [(i1)]; S1[i0, i1, i2] -> [(i1)]; S2[i0, i1, i2] -> [(i1)] }, { S6[i0, i1, i2] -> [(i2)]; S8[i0, i1, i2] -> [(i2)]; S5[i0, i1, i2] -> [(i2)]; S4[i0, i1, i2] -> [(i2)]; S7[i0, i1, i2] -> [(i2)]; S3[i0, i1, i2] -> [(i2)]; S1[i0, i1, i2] -> [(i2)]; S2[i0, i1, i2] -> [(i2)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1, i2] }" + - filter: "{ S2[i0, i1, i2] }" + - filter: "{ S3[i0, i1, i2] }" + - filter: "{ S4[i0, i1, i2] }" + - filter: "{ S5[i0, i1, i2] }" + - filter: "{ S6[i0, i1, i2] }" + - filter: "{ S7[i0, i1, i2] }" + - filter: "{ S8[i0, i1, i2] }" Index: contrib/isl/test_inputs/codegen/cloog/emploi.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/emploi.c @@ -0,0 +1,5 @@ +for (int c0 = 1; c0 <= n; c0 += 1) { + S1(c0); + for (int c1 = 1; c1 <= m; c1 += 1) + S2(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/emploi.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/emploi.st @@ -0,0 +1,10 @@ +domain: "[m, n] -> { S1[i0] : (i0 >= 1 and i0 <= n and i0 <= 2m) or (i0 >= m and i0 >= 1 and i0 <= n); S2[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= m }" +child: + context: "[m, n] -> { [] }" + child: + schedule: "[m, n] -> [{ S1[i0] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0] -> [(0)]; S2[i0, i1] -> [(i1)] }]" + options: "[m, n] -> { separate[i0] }" + child: + sequence: + - filter: "[m, n] -> { S1[i0] }" + - filter: "[m, n] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/equality.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/equality.c @@ -0,0 +1,7 @@ +for (int c0 = 0; c0 <= 5; c0 += 1) + for (int c1 = min(4, 2 * c0); c1 <= max(4, 2 * c0); c1 += 1) { + if (c1 == 2 * c0) + S1(c0, 2 * c0); + if (c1 == 4) + S2(c0, 4); + } Index: contrib/isl/test_inputs/codegen/cloog/equality.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/equality.st @@ -0,0 +1,10 @@ +domain: "{ S2[i0, 4] : i0 >= 0 and i0 <= 5; S1[i0, 2i0] : i0 >= 0 and i0 <= 5 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "{ atomic[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1] }" + - filter: "{ S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/equality2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/equality2.c @@ -0,0 +1,8 @@ +for (int c0 = 1; c0 <= 10000; c0 += 1) + for (int c1 = 1000; c1 <= 1016; c1 += 1) + for (int c2 = 1; c2 < 2 * c1 - 1998; c2 += 1) { + if (c1 <= 1008 && c2 + 1999 == 2 * c1) + S2(c0, c1, 2 * c1 - 1999, 1, c0, 2 * c1 - 1000, 1, 2, c0, c1 - 499, 2 * c1 - 1999, c0, 2 * c1 - 1999, c1 - 999, c1 - 999); + if (c2 == 1 && c1 % 2 == 0) + S1(c0, c1, 1, 2, c0, (c1 / 2) + 1, c1 - 999, c0, c1 - 999, (c1 / 2) - 499, (c1 / 2) - 499); + } Index: contrib/isl/test_inputs/codegen/cloog/equality2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/equality2.st @@ -0,0 +1,10 @@ +domain: "{ S1[i0, i1, 1, 2, i0, i5, -999 + i1, i0, -999 + i1, i9, i10] : 2i5 = 2 + i1 and 2i9 = -998 + i1 and 2i10 = -998 + i1 and i0 >= 1 and i0 <= 10000 and i1 >= 1000 and i1 <= 1016; S2[i0, i1, -1999 + 2i1, 1, i0, -1000 + 2i1, 1, 2, i0, -499 + i1, -1999 + 2i1, i0, -1999 + 2i1, -999 + i1, -999 + i1] : i0 >= 1 and i0 <= 10000 and i1 >= 1000 and i1 <= 1008 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i0)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i1)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i1)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i2)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i2)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i3)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i3)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i4)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i4)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i5)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i5)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i6)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i6)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i7)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i7)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i8)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i8)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i9)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i9)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i10)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i10)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i11)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i12)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i13)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i14)] }]" + options: "{ atomic[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] }" + - filter: "{ S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] }" Index: contrib/isl/test_inputs/codegen/cloog/esced.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/esced.c @@ -0,0 +1,5 @@ +for (int c0 = 1; c0 <= m; c0 += 1) { + S1(c0); + for (int c1 = 1; c1 <= n; c1 += 1) + S2(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/esced.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/esced.st @@ -0,0 +1,10 @@ +domain: "[n, m] -> { S1[i0] : i0 >= 1 and i0 <= m; S2[i0, i1] : i0 >= 1 and i0 <= m and i1 >= 1 and i1 <= n }" +child: + context: "[n, m] -> { [] }" + child: + schedule: "[n, m] -> [{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]" + options: "[n, m] -> { separate[i0] }" + child: + sequence: + - filter: "[n, m] -> { S1[i0] }" + - filter: "[n, m] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/ex1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/ex1.c @@ -0,0 +1,15 @@ +{ + for (int c0 = 0; c0 <= 14; c0 += 1) + for (int c1 = 0; c1 < n - 14; c1 += 1) + S1(c0, c1); + for (int c0 = 15; c0 <= n; c0 += 1) { + for (int c1 = 0; c1 <= 9; c1 += 1) + S1(c0, c1); + for (int c1 = 10; c1 < n - 14; c1 += 1) { + S1(c0, c1); + S2(c0, c1); + } + for (int c1 = n - 14; c1 <= n; c1 += 1) + S2(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/cloog/ex1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/ex1.st @@ -0,0 +1,10 @@ +domain: "[n] -> { S1[i0, i1] : i0 >= 0 and i0 <= n and i1 >= 0 and i1 <= -15 + n; S2[i0, i1] : i0 >= 15 and i0 <= n and i1 >= 10 and i1 <= n }" +child: + context: "[n] -> { [] : n >= 25 }" + child: + schedule: "[n] -> [{ S2[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)] }]" + options: "[n] -> { separate[i0] }" + child: + sequence: + - filter: "[n] -> { S1[i0, i1] }" + - filter: "[n] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/faber.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/faber.c @@ -0,0 +1,149 @@ +{ + for (int c0 = 0; c0 <= 36; c0 += 1) { + for (int c1 = -6; c1 < c0 / 14 - 5; c1 += 1) { + for (int c2 = -((-2 * c1 + 3) / 5) + 9; c2 <= c1 + 12; c2 += 1) + S6(c0, c1, c2); + for (int c2 = c1 + 24; c2 <= -2 * c1 + 24; c2 += 1) + S2(c0, c1, c2); + for (int c2 = -2 * c1 + 30; c2 <= c1 + 48; c2 += 1) + S1(c0, c1, c2); + } + for (int c1 = c0 / 14 - 5; c1 < 0; c1 += 1) { + if (c1 >= -3 && 2 * c0 >= 7 * c1 + 42) + S7(c0, c1, 6); + for (int c2 = max(c1 - (6 * c0 + 77) / 77 + 13, -((-2 * c1 + 3) / 5) + 9); c2 <= c1 + 12; c2 += 1) + S6(c0, c1, c2); + for (int c2 = c1 - (3 * c0 + 14) / 14 + 49; c2 <= c1 + 48; c2 += 1) + S1(c0, c1, c2); + } + S3(c0, 0, 0); + S10(c0, 0, 0); + for (int c2 = 1; c2 <= 5; c2 += 1) + S3(c0, 0, c2); + for (int c2 = 6; c2 <= 2 * c0 / 21 + 4; c2 += 1) { + S3(c0, 0, c2); + S7(c0, 0, c2); + } + for (int c2 = max(6, 2 * c0 / 21 + 5); c2 <= -((6 * c0 + 77) / 77) + 12; c2 += 1) + S3(c0, 0, c2); + for (int c2 = -((6 * c0 + 77) / 77) + 13; c2 <= 12; c2 += 1) { + S3(c0, 0, c2); + S6(c0, 0, c2); + } + for (int c2 = 13; c2 <= 24; c2 += 1) + S3(c0, 0, c2); + for (int c2 = -((3 * c0 + 14) / 14) + 49; c2 <= 48; c2 += 1) + S1(c0, 0, c2); + for (int c1 = 1; c1 <= 18; c1 += 1) { + for (int c2 = -8 * c1; c2 <= min(6, -8 * c1 + 24); c2 += 1) + S3(c0, c1, c2); + if (c1 == 2) { + S3(c0, 2, 7); + } else if (c0 <= 34 && c1 == 1) { + S3(c0, 1, 7); + } else if (c0 >= 35 && c1 == 1) { + S3(c0, 1, 7); + S7(c0, 1, 7); + } + for (int c2 = 8; c2 <= min(-8 * c1 + 24, c1 - (6 * c0 + 77) / 77 + 12); c2 += 1) + S3(c0, c1, c2); + for (int c2 = max(-8 * c1 + 25, c1 - (6 * c0 + 77) / 77 + 13); c2 <= c1 + 12; c2 += 1) + S6(c0, c1, c2); + if (c1 == 1) { + for (int c2 = -((6 * c0 + 77) / 77) + 14; c2 <= 13; c2 += 1) { + S3(c0, 1, c2); + S6(c0, 1, c2); + } + for (int c2 = 14; c2 <= 16; c2 += 1) + S3(c0, 1, c2); + } + for (int c2 = c1 - (3 * c0 + 14) / 14 + 49; c2 <= c1 + 48; c2 += 1) + S1(c0, c1, c2); + } + for (int c1 = 19; c1 <= 24; c1 += 1) { + for (int c2 = -8 * c1; c2 <= -8 * c1 + 24; c2 += 1) + S3(c0, c1, c2); + for (int c2 = c1 - (6 * c0 + 77) / 77 + 13; c2 <= 30; c2 += 1) + S6(c0, c1, c2); + } + } + for (int c0 = 37; c0 <= 218; c0 += 1) { + for (int c1 = (c0 + 5) / 14 - 8; c1 < min(0, c0 / 14 - 5); c1 += 1) { + if (c0 <= 46 && c1 == -3) + S7(c0, -3, 6); + if (77 * c1 + 77 * ((-2 * c1 - 2) / 5) + 524 >= 6 * c0) + S6(c0, c1, -((-2 * c1 + 3) / 5) + 9); + for (int c2 = c1 + 24; c2 <= -2 * c1 + 24; c2 += 1) + S2(c0, c1, c2); + for (int c2 = -2 * c1 + 30; c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1) + S1(c0, c1, c2); + } + for (int c1 = c0 / 14 - 5; c1 < 0; c1 += 1) { + if (7 * c1 + 114 >= 2 * c0) + S7(c0, c1, 6); + for (int c2 = max(8, c1 - (6 * c0 + 77) / 77 + 13); c2 <= c1 - (6 * c0 + 91) / 77 + 15; c2 += 1) + S6(c0, c1, c2); + for (int c2 = c1 - (3 * c0 + 14) / 14 + 49; c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1) + S1(c0, c1, c2); + } + if (c0 <= 148) + for (int c1 = max(0, (c0 + 5) / 14 - 8); c1 < c0 / 14 - 5; c1 += 1) { + if (c1 == 0) + S2(c0, 0, 24); + for (int c2 = max(c1 + 24, -2 * c1 + 30); c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1) + S1(c0, c1, c2); + } + if (c0 >= 70 && c0 % 14 >= 9) + for (int c2 = max(c0 / 14 + 19, -((3 * c0 + 14) / 14) + c0 / 14 + 44); c2 <= -((3 * c0 + 17) / 14) + c0 / 14 + 51; c2 += 1) + S1(c0, c0 / 14 - 5, c2); + for (int c1 = max(0, (c0 + 5) / 14 - 5); c1 < c0 / 14 - 2; c1 += 1) { + for (int c2 = max(c1, -2 * c1 + 6); c2 <= min(c1 + 5, -2 * c1 + 24); c2 += 1) + S9(c0, c1, c2); + for (int c2 = c1 + 6; c2 <= min((2 * c1 + 1) / 5 + 7, (2 * c0 - 7 * c1 - 10) / 21 + 1); c2 += 1) + S9(c0, c1, c2); + for (int c2 = max(c1 + 6, (2 * c0 - 7 * c1 - 10) / 21 + 2); c2 <= (2 * c1 + 1) / 5 + 7; c2 += 1) { + S7(c0, c1, c2); + S9(c0, c1, c2); + } + if (c1 <= 3) + S9(c0, c1, (2 * c1 + 1) / 5 + 8); + for (int c2 = (2 * c1 + 1) / 5 + 9; c2 <= c1 - (6 * c0 + 91) / 77 + 15; c2 += 1) { + S6(c0, c1, c2); + S9(c0, c1, c2); + } + for (int c2 = max(max(c1 + 6, c1 - (6 * c0 + 91) / 77 + 16), (2 * c1 + 1) / 5 + 9); c2 <= -2 * c1 + 24; c2 += 1) + S9(c0, c1, c2); + for (int c2 = max(c1, -2 * c1 + 30); c2 <= min(c1 + 24, c1 - (3 * c0 + 17) / 14 + 47); c2 += 1) + S8(c0, c1, c2); + for (int c2 = max(c1 + 24, c1 - (3 * c0 + 14) / 14 + 49); c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1) + S1(c0, c1, c2); + } + for (int c1 = c0 / 14 - 2; c1 <= 18; c1 += 1) { + for (int c2 = max(6, (c0 + 5) / 14 + 1); c2 <= min(min(c1, c0 / 14 + 3), -c1 + c1 / 2 + 18); c2 += 1) + S5(c0, c1, c2); + for (int c2 = max(c1 + (3 * c0 + 3) / 14 - 40, -c1 + (c1 + 1) / 2 + 21); c2 <= min(c1, c1 + 3 * c0 / 14 - 33); c2 += 1) + S4(c0, c1, c2); + for (int c2 = c1 + 6; c2 <= min((2 * c1 + 1) / 5 + 7, (2 * c0 - 7 * c1 + 63) / 21 + 1); c2 += 1) + S7(c0, c1, c2); + for (int c2 = max(max(c1 + 6, c1 - (6 * c0 + 77) / 77 + 13), (2 * c1 + 1) / 5 + 9); c2 <= c1 - (6 * c0 + 91) / 77 + 15; c2 += 1) + S6(c0, c1, c2); + for (int c2 = max(c1, c1 - (3 * c0 + 14) / 14 + 40); c2 <= min(c1 + 24, c1 - (3 * c0 + 17) / 14 + 47); c2 += 1) + S8(c0, c1, c2); + for (int c2 = max(c1 + 24, c1 - (3 * c0 + 14) / 14 + 49); c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1) + S1(c0, c1, c2); + } + for (int c1 = 19; c1 <= 24; c1 += 1) { + for (int c2 = max(c1 - 12, (c0 + 5) / 14 + 1); c2 <= min(c0 / 14 + 3, -c1 + c1 / 2 + 18); c2 += 1) + S5(c0, c1, c2); + for (int c2 = max(max(c1 - 12, c1 + (3 * c0 + 3) / 14 - 40), -c1 + (c1 + 1) / 2 + 21); c2 <= min(c1, c1 + 3 * c0 / 14 - 33); c2 += 1) + S4(c0, c1, c2); + for (int c2 = max(c1 + 6, c1 - (6 * c0 + 77) / 77 + 13); c2 <= min(30, c1 - (6 * c0 + 91) / 77 + 15); c2 += 1) + S6(c0, c1, c2); + for (int c2 = max(c1, c1 - (3 * c0 + 14) / 14 + 40); c2 <= min(c1 + 24, c1 - (3 * c0 + 17) / 14 + 47); c2 += 1) + S8(c0, c1, c2); + } + for (int c1 = 25; c1 <= min(42, -((3 * c0 + 17) / 14) + 71); c1 += 1) + for (int c2 = max(c1 - 12, c1 + (3 * c0 + 3) / 14 - 40); c2 <= min(min(30, c1), c1 + 3 * c0 / 14 - 33); c2 += 1) + S4(c0, c1, c2); + } +} Index: contrib/isl/test_inputs/codegen/cloog/faber.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/faber.st @@ -0,0 +1,18 @@ +domain: "{ S2[idx4, idx5, idx6] : 14idx5 <= -84 + idx4 and 14idx5 >= -120 + idx4 and idx6 >= 24 + idx5 and idx6 <= 48 + idx5 and idx5 >= -6 and idx5 <= 18 and idx6 <= 24 - 2idx5; S4[idx4, idx5, idx6] : 14idx6 <= -462 + 3idx4 + 14idx5 and 14idx6 >= -570 + 3idx4 + 14idx5 and idx6 <= idx5 and idx6 >= -12 + idx5 and idx6 >= 6 and idx6 <= 30 and 2idx6 >= 42 - idx5; S6[idx4, idx5, idx6] : 77idx6 >= 924 - 6idx4 + 77idx5 and 77idx6 <= 1140 - 6idx4 + 77idx5 and idx6 <= 12 + idx5 and idx6 >= 6 + idx5 and idx6 >= 6 and idx6 <= 30 and 5idx6 >= 42 + 2idx5; S1[idx4, idx5, idx6] : 14idx6 >= 672 - 3idx4 + 14idx5 and 14idx6 <= 780 - 3idx4 + 14idx5 and idx6 >= 24 + idx5 and idx6 <= 48 + idx5 and idx5 >= -6 and idx5 <= 18 and idx6 >= 30 - 2idx5; S5[idx4, idx5, idx6] : 14idx6 <= 42 + idx4 and 14idx6 >= 6 + idx4 and idx6 <= idx5 and idx6 >= -12 + idx5 and idx6 >= 6 and idx6 <= 30 and 2idx6 <= 36 - idx5; S7[idx4, idx5, idx6] : 21idx6 <= 84 + 2idx4 - 7idx5 and 21idx6 >= 12 + 2idx4 - 7idx5 and idx6 <= 12 + idx5 and idx6 >= 6 + idx5 and idx6 >= 6 and idx6 <= 30 and 5idx6 <= 36 + 2idx5; S8[idx4, idx5, idx6] : 14idx6 >= 546 - 3idx4 + 14idx5 and 14idx6 <= 654 - 3idx4 + 14idx5 and idx6 >= idx5 and idx6 <= 24 + idx5 and idx5 >= 0 and idx5 <= 24 and idx6 >= 30 - 2idx5; S3[idx4, idx5, idx6] : idx4 >= 0 and idx4 <= 36 and idx6 >= -8idx5 and idx6 <= 24 - 8idx5 and idx5 >= 0 and idx5 <= 24; S9[idx4, idx5, idx6] : 14idx5 <= -42 + idx4 and 14idx5 >= -78 + idx4 and idx6 >= idx5 and idx6 <= 24 + idx5 and idx5 >= 0 and idx5 <= 24 and idx6 <= 24 - 2idx5 and idx6 >= 6 - 2idx5; S10[idx4, idx5, idx6] : 7idx6 <= idx4 - 28idx5 and 7idx6 >= -36 + idx4 - 28idx5 and idx6 >= idx5 and idx6 <= 24 + idx5 and idx5 >= 0 and idx5 <= 24 and idx6 <= -2idx5 }" +child: + context: "{ [] }" + child: + schedule: "[{ S6[idx4, idx5, idx6] -> [(idx4)]; S8[idx4, idx5, idx6] -> [(idx4)]; S5[idx4, idx5, idx6] -> [(idx4)]; S9[idx4, idx5, idx6] -> [(idx4)]; S4[idx4, idx5, idx6] -> [(idx4)]; S10[idx4, idx5, idx6] -> [(idx4)]; S7[idx4, idx5, idx6] -> [(idx4)]; S3[idx4, idx5, idx6] -> [(idx4)]; S1[idx4, idx5, idx6] -> [(idx4)]; S2[idx4, idx5, idx6] -> [(idx4)] }, { S6[idx4, idx5, idx6] -> [(idx5)]; S8[idx4, idx5, idx6] -> [(idx5)]; S5[idx4, idx5, idx6] -> [(idx5)]; S9[idx4, idx5, idx6] -> [(idx5)]; S4[idx4, idx5, idx6] -> [(idx5)]; S10[idx4, idx5, idx6] -> [(idx5)]; S7[idx4, idx5, idx6] -> [(idx5)]; S3[idx4, idx5, idx6] -> [(idx5)]; S1[idx4, idx5, idx6] -> [(idx5)]; S2[idx4, idx5, idx6] -> [(idx5)] }, { S6[idx4, idx5, idx6] -> [(idx6)]; S8[idx4, idx5, idx6] -> [(idx6)]; S5[idx4, idx5, idx6] -> [(idx6)]; S9[idx4, idx5, idx6] -> [(idx6)]; S4[idx4, idx5, idx6] -> [(idx6)]; S10[idx4, idx5, idx6] -> [(idx6)]; S7[idx4, idx5, idx6] -> [(idx6)]; S3[idx4, idx5, idx6] -> [(idx6)]; S1[idx4, idx5, idx6] -> [(idx6)]; S2[idx4, idx5, idx6] -> [(idx6)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[idx4, idx5, idx6] }" + - filter: "{ S2[idx4, idx5, idx6] }" + - filter: "{ S3[idx4, idx5, idx6] }" + - filter: "{ S4[idx4, idx5, idx6] }" + - filter: "{ S5[idx4, idx5, idx6] }" + - filter: "{ S6[idx4, idx5, idx6] }" + - filter: "{ S7[idx4, idx5, idx6] }" + - filter: "{ S8[idx4, idx5, idx6] }" + - filter: "{ S9[idx4, idx5, idx6] }" + - filter: "{ S10[idx4, idx5, idx6] }" Index: contrib/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.c @@ -0,0 +1,9 @@ +{ + S3(1, 1); + for (int c0 = 2; c0 <= M; c0 += 1) { + S1(c0, 1); + for (int c1 = 2; c1 < c0; c1 += 1) + S2(c0, c1); + S4(c0, c0); + } +} Index: contrib/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.st @@ -0,0 +1,12 @@ +domain: "[M] -> { S4[i0, i0] : M >= 3 and i0 <= M and i0 >= 2; S1[i0, 1] : M >= 3 and i0 <= M and i0 >= 2; S3[1, 1] : M >= 3; S2[i0, i1] : i1 <= -1 + i0 and i1 >= 2 and i0 <= M }" +child: + context: "[M] -> { [] : M >= 3 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S4[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + - filter: "[M] -> { S2[i0, i1] }" + - filter: "[M] -> { S3[i0, i1] }" + - filter: "[M] -> { S4[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.c @@ -0,0 +1,10 @@ +{ + S3(1, 0); + for (int c2 = 2; c2 <= M; c2 += 1) + S1(1, 1, c2); + for (int c0 = 2; c0 <= M; c0 += 1) { + S4(c0, 0); + for (int c2 = c0 + 1; c2 <= M; c2 += 1) + S2(c0, 1, c2); + } +} Index: contrib/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.st @@ -0,0 +1,12 @@ +domain: "[M] -> { S4[i0, 0] : i0 >= 2 and M >= 3 and i0 <= M; S3[1, 0] : M >= 3; S2[i0, 1, i2] : i2 >= 1 + i0 and i0 >= 2 and i2 <= M; S1[1, 1, i2] : M >= 3 and i2 <= M and i2 >= 2 }" +child: + context: "[M] -> { [] : M >= 3 }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0)]; S4[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)]; S4[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)]; S2[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)]; S4[i0, i1] -> [(0)]; S3[i0, i1] -> [(0)]; S2[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1, i2] }" + - filter: "[M] -> { S2[i0, i1, i2] }" + - filter: "[M] -> { S3[i0, i1] }" + - filter: "[M] -> { S4[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.c @@ -0,0 +1,17 @@ +{ + S3(2, 1); + S1(3, 1); + for (int c0 = 4; c0 <= M + 1; c0 += 1) { + S1(c0, 1); + for (int c1 = 2; c1 < (c0 + 1) / 2; c1 += 1) + S2(c0, c1); + if (c0 % 2 == 0) + S4(c0, c0 / 2); + } + for (int c0 = M + 2; c0 <= 2 * M; c0 += 1) { + for (int c1 = -M + c0; c1 < (c0 + 1) / 2; c1 += 1) + S2(c0, c1); + if (c0 % 2 == 0) + S4(c0, c0 / 2); + } +} Index: contrib/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.st @@ -0,0 +1,12 @@ +domain: "[M] -> { S4[i0, i1] : 2i1 = i0 and M >= 3 and i0 <= 2M and i0 >= 4; S1[i0, 1] : M >= 3 and i0 <= 1 + M and i0 >= 3; S3[2, 1] : M >= 3; S2[i0, i1] : 2i1 <= -1 + i0 and i1 >= 2 and i1 >= -M + i0 }" +child: + context: "[M] -> { [] : M >= 3 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S4[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + - filter: "[M] -> { S2[i0, i1] }" + - filter: "[M] -> { S3[i0, i1] }" + - filter: "[M] -> { S4[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/gauss.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/gauss.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 < M; c0 += 1) + for (int c1 = c0 + 1; c1 <= M; c1 += 1) { + for (int c3 = 1; c3 < c0; c3 += 1) + S1(c0, c3, c1); + for (int c3 = c0 + 1; c3 <= M; c3 += 1) + S2(c0, c3, c1); + } Index: contrib/isl/test_inputs/codegen/cloog/gauss.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/gauss.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S2[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M and i2 >= 1 + i0 and i2 <= M; S1[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= -1 + i0 and i2 >= 1 + i0 and i2 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i2)]; S2[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/gesced.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/gesced.c @@ -0,0 +1,16 @@ +{ + for (int c0 = 1; c0 <= N; c0 += 1) + S1(c0); + for (int c0 = N + 1; c0 <= 2 * N; c0 += 1) + for (int c1 = 1; c1 <= N; c1 += 1) + S2(c1, -N + c0); + for (int c0 = 2 * N + 1; c0 <= M + N; c0 += 1) { + for (int c1 = 1; c1 <= N; c1 += 1) + S2(c1, -N + c0); + for (int c1 = 1; c1 <= N; c1 += 1) + S3(c1, -2 * N + c0); + } + for (int c0 = M + N + 1; c0 <= M + 2 * N; c0 += 1) + for (int c1 = 1; c1 <= N; c1 += 1) + S3(c1, -2 * N + c0); +} Index: contrib/isl/test_inputs/codegen/cloog/gesced.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/gesced.st @@ -0,0 +1,6 @@ +domain: "[M, N] -> { S3[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M; S1[i0] : i0 >= 1 and i0 <= N; S2[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M }" +child: + context: "[M, N] -> { [] : N <= M and M >= 2 and N >= 2 }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(N + i1)]; S3[i0, i1] -> [(2N + i1)]; S1[i0] -> [(i0)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/gesced2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/gesced2.c @@ -0,0 +1,20 @@ +{ + for (int c0 = 1; c0 <= 4; c0 += 1) + for (int c1 = 5; c1 < M - 9; c1 += 1) + S1(c0, c1); + for (int c0 = 5; c0 < M - 9; c0 += 1) { + for (int c1 = -c0 + 1; c1 <= 4; c1 += 1) + S2(c0 + c1, c0); + for (int c1 = 5; c1 <= min(M - 10, M - c0); c1 += 1) { + S2(c0 + c1, c0); + S1(c0, c1); + } + for (int c1 = M - c0 + 1; c1 < M - 9; c1 += 1) + S1(c0, c1); + for (int c1 = M - 9; c1 <= M - c0; c1 += 1) + S2(c0 + c1, c0); + } + for (int c0 = M - 9; c0 <= M; c0 += 1) + for (int c1 = 5; c1 < M - 9; c1 += 1) + S1(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/gesced2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/gesced2.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 5 and i1 <= -10 + M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 5 and i1 <= -10 + M }" +child: + context: "[M] -> { [] : M >= 16 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i1)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i0 - i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/gesced3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/gesced3.c @@ -0,0 +1,10 @@ +{ + for (int c0 = M + 1; c0 <= 2 * M; c0 += 1) + S1(-M + c0); + for (int c0 = 2 * M + 1; c0 <= M + N; c0 += 1) { + S2(-2 * M + c0); + S1(-M + c0); + } + for (int c0 = M + N + 1; c0 <= 2 * M + N; c0 += 1) + S2(-2 * M + c0); +} Index: contrib/isl/test_inputs/codegen/cloog/gesced3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/gesced3.st @@ -0,0 +1,6 @@ +domain: "[M, N] -> { S1[i0] : i0 >= 1 and i0 <= N; S2[i0] : i0 >= 1 and i0 <= N }" +child: + context: "[M, N] -> { [] : N >= M and M >= 2 }" + child: + schedule: "[M, N] -> [{ S2[i0] -> [(2M + i0)]; S1[i0] -> [(M + i0)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/guide.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/guide.c @@ -0,0 +1,6 @@ +{ + for (int c0 = 1; c0 <= N; c0 += 1) + S1(c0); + for (int c0 = N + 1; c0 <= 2 * N; c0 += 1) + S2(c0); +} Index: contrib/isl/test_inputs/codegen/cloog/guide.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/guide.st @@ -0,0 +1,10 @@ +domain: "[M, N] -> { S1[i0] : (i0 >= 1 and i0 <= N and i0 <= 2M) or (i0 >= M and i0 >= 1 and i0 <= N); S2[i0] : i0 >= 1 + N and i0 <= 2N }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S2[i0] -> [(i0)]; S1[i0] -> [(i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0] }" + - filter: "[M, N] -> { S2[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/iftest.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/iftest.c @@ -0,0 +1,2 @@ +for (int c0 = 1; c0 <= n; c0 += 1) + S1(c0); Index: contrib/isl/test_inputs/codegen/cloog/iftest.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/iftest.st @@ -0,0 +1,6 @@ +domain: "[m, n] -> { S1[i0] : (i0 >= m and i0 >= 1 and i0 <= n) or (i0 >= 1 and i0 <= n and i0 <= 2m) }" +child: + context: "[m, n] -> { [] }" + child: + schedule: "[m, n] -> [{ S1[i0] -> [(i0)] }]" + options: "[m, n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/iftest2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/iftest2.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= N; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S1(c0, c1); Index: contrib/isl/test_inputs/codegen/cloog/iftest2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/iftest2.st @@ -0,0 +1,6 @@ +domain: "[M, N] -> { S1[i0, i1] : (i0 >= M and i0 <= N and i1 >= 1 and i1 <= M) or (i0 >= 1 and i0 <= N and i0 <= 2M and i1 >= 1 and i1 <= M) }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/infinite2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/infinite2.c @@ -0,0 +1,9 @@ +{ + for (int c0 = 1; c0 <= N; c0 += 1) { + S1(c0); + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c0, c1); + } + for (int c0 = N + 1; 1; c0 += 1) + S1(c0); +} Index: contrib/isl/test_inputs/codegen/cloog/infinite2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/infinite2.st @@ -0,0 +1,10 @@ +domain: "[M, N] -> { S1[i0] : i0 >= 1; S2[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M }" +child: + context: "[M, N] -> { [] : M >= 1 and N >= 1 }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0] }" + - filter: "[M, N] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/jacobi-shared.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/jacobi-shared.c @@ -0,0 +1,3 @@ +if (((t1 + 31) % 32) + g2 >= 2 && N >= ((t1 + 31) % 32) + g2 + 2 && (h0 + 1) % 2 == 0) + for (int c0 = max(((t0 + 15) % 16) + 1, ((g1 + t0 + 13) % 16) - g1 + 3); c0 <= min(32, N - g1 - 1); c0 += 16) + S1(g1 + c0 - 1, -((g2 - t1 + 32) % 32) + g2 + 31); Index: contrib/isl/test_inputs/codegen/cloog/jacobi-shared.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/jacobi-shared.st @@ -0,0 +1,6 @@ +domain: "[T, N, h0, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { S1[i0, i1] : exists (e0 = floor((-1 + h0)/2), e1 = floor((-32b0 + g1)/2048), e2 = floor((-32b1 + g2)/1024), e3 = floor((-15 - t0 + i0)/16), e4 = floor((-31 - t1 + i1)/32): g0 = h0 and 2e0 = -1 + h0 and 2048e1 = -32b0 + g1 and 1024e2 = -32b1 + g2 and 16e3 = -15 - t0 + i0 and 32e4 = -31 - t1 + i1 and h0 >= 1 and h0 <= -1 + 2T and i0 >= 2 and i0 <= -2 + N and i1 >= 2 and i1 <= -2 + N and b1 <= 31 and b1 >= 0 and b0 <= 63 and b0 >= 0 and i1 <= 31 + g2 and i1 >= g2 and N >= 4 and i0 >= g1 and i0 <= 31 + g1 and g2 <= -2 + N and g2 >= -29 and g1 <= -2 + N and g1 >= -29 and g1 >= 32b0 and g2 >= 32b1 and 32b0 <= -2 + N and 32b1 <= -2 + N and t0 >= 0 and t0 <= 15 and t1 >= 0 and t1 <= 31) }" +child: + context: "[T, N, h0, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { [] : exists (e0 = floor((-32b0 + g1)/2048), e1 = floor((-32b1 + g2)/1024): g0 = h0 and 2048e0 = -32b0 + g1 and 1024e1 = -32b1 + g2 and g2 <= -2 + N and g2 >= -29 and g1 <= -2 + N and g1 >= -29 and b1 >= 0 and b1 <= 31 and b0 <= 63 and 32b1 <= -2 + N and 32b0 <= -2 + N and b0 >= 0 and N >= 4 and h0 >= 0 and h0 <= -1 + 2T and g2 >= 32b1 and g1 >= 32b0 and t0 >= 0 and t0 <= 15 and t1 >= 0 and t1 <= 31) }" + child: + schedule: "[T, N, h0, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> [{ S1[i0, i1] -> [(1 - g1 + i0)] }, { S1[i0, i1] -> [(1 - g2 + i1)] }, { S1[i0, i1] -> [(t0)] }, { S1[i0, i1] -> [(t1)] }]" + options: "[T, N, h0, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { separate[x] : x >= 3 }" Index: contrib/isl/test_inputs/codegen/cloog/largeur.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/largeur.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= c0; c1 += 1) + S1(c1, c0); Index: contrib/isl/test_inputs/codegen/cloog/largeur.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/largeur.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= i0 and i1 <= M }" +child: + context: "[M] -> { [] : M >= 0 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }, { S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.c @@ -0,0 +1,32 @@ +{ + S1(0, 0); + for (int c0 = 1; c0 <= N; c0 += 1) { + S2(c0, 0); + for (int c1 = 1; c1 < c0; c1 += 1) + S6(c0, c1); + S3(c0, c0); + } + S7(N + 1, 0); + for (int c1 = 1; c1 <= N; c1 += 1) { + S6(N + 1, c1); + S8(N + 1, c1); + } + for (int c0 = N + 2; c0 < 2 * M - N - 1; c0 += 1) { + S7(c0, -N + (N + c0 + 1) / 2 - 1); + if ((N + c0) % 2 == 0) { + S5(c0, (-N + c0) / 2); + S8(c0, (-N + c0) / 2); + } + for (int c1 = -N + (N + c0) / 2 + 1; c1 < (N + c0 + 1) / 2; c1 += 1) { + S6(c0, c1); + S8(c0, c1); + } + if ((N + c0) % 2 == 0) { + S4(c0, (N + c0) / 2); + S8(c0, (N + c0) / 2); + } + } + for (int c0 = 2 * M - N - 1; c0 < 2 * M - 1; c0 += 1) + for (int c1 = -M + c0 + 1; c1 < M; c1 += 1) + S6(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.st @@ -0,0 +1,16 @@ +domain: "[M, N] -> { S5[i0, i1] : 2i1 = -N + i0 and i0 >= 2 + N and i0 <= -2 + 2M - N and N >= 1; S3[i0, i0] : i0 >= 1 and i0 <= N and N <= -2 + M; S7[i0, i1] : i0 >= 1 + N and 2i1 <= -1 - N + i0 and i0 <= -2 + 2M - N and 2i1 >= -2 - N + i0 and N <= -2 + M and N >= 1; S6[i0, i1] : 2i1 <= -1 + N + i0 and i1 <= -1 + i0 and i1 >= 1 - M + i0 and 2i1 >= 1 - N + i0 and i1 >= 1 and i1 <= -1 + M and N <= -2 + M; S1[0, 0] : N <= -2 + M and N >= 1; S2[i0, 0] : i0 >= 1 and i0 <= N and N <= -2 + M; S4[i0, i1] : 2i1 = N + i0 and i0 >= 2 + N and i0 <= -2 + 2M - N and N >= 1; S8[i0, i1] : i0 >= 1 + N and 2i1 <= N + i0 and 2i1 >= -N + i0 and i0 <= -2 + 2M - N and N <= -2 + M and N >= 1 }" +child: + context: "[M, N] -> { [] : N <= -2 + M and N >= 1 }" + child: + schedule: "[M, N] -> [{ S7[i0, i1] -> [(i0)]; S5[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i0)]; S8[i0, i1] -> [(i0)]; S6[i0, i1] -> [(i0)] }, { S7[i0, i1] -> [(i1)]; S5[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)]; S4[i0, i1] -> [(i1)]; S8[i0, i1] -> [(i1)]; S6[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1] }" + - filter: "[M, N] -> { S2[i0, i1] }" + - filter: "[M, N] -> { S3[i0, i1] }" + - filter: "[M, N] -> { S4[i0, i1] }" + - filter: "[M, N] -> { S5[i0, i1] }" + - filter: "[M, N] -> { S6[i0, i1] }" + - filter: "[M, N] -> { S7[i0, i1] }" + - filter: "[M, N] -> { S8[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/lex.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lex.c @@ -0,0 +1,4 @@ +for (int c0 = 0; c0 <= 10; c0 += 1) { + S2(c0); + S1(c0); +} Index: contrib/isl/test_inputs/codegen/cloog/lex.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lex.st @@ -0,0 +1,10 @@ +domain: "{ S1[i0] : i0 >= 0 and i0 <= 10; S2[i0] : i0 >= 0 and i0 <= 10 }" +child: + context: "{ [] }" + child: + schedule: "[{ S2[i0] -> [(i0)]; S1[i0] -> [(i0)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S2[i0] }" + - filter: "{ S1[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/lineality-1-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lineality-1-2.c @@ -0,0 +1,8 @@ +for (int c0 = 1; c0 <= M; c0 += 1) { + for (int c1 = 1; c1 < c0; c1 += 1) + S1(c0, c1); + S1(c0, c0); + S2(c0, c0); + for (int c1 = c0 + 1; c1 <= M; c1 += 1) + S1(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/lineality-1-2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lineality-1-2.st @@ -0,0 +1,10 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i1 >= 1 and i0 <= M and i1 <= M; S2[i0, i0] : i0 >= 1 and i0 <= M }" +child: + context: "[M] -> { [] : M >= 2 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + - filter: "[M] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/lineality-2-1-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lineality-2-1-2.c @@ -0,0 +1,12 @@ +for (int c0 = 1; c0 <= M; c0 += 1) { + for (int c1 = 1; c1 <= min(M, c0 + 1); c1 += 1) + S1(c0, c1); + if (M >= c0 + 2) { + S1(c0, c0 + 2); + S2(c0, c0 + 2); + } + for (int c1 = c0 + 3; c1 <= M; c1 += 1) + S1(c0, c1); + if (c0 + 1 >= M) + S2(c0, c0 + 2); +} Index: contrib/isl/test_inputs/codegen/cloog/lineality-2-1-2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lineality-2-1-2.st @@ -0,0 +1,10 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i1 >= 1 and i0 <= M and i1 <= M; S2[i0, 2 + i0] : i0 >= 1 and i0 <= M }" +child: + context: "[M] -> { [] : M >= 2 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + - filter: "[M] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/logo.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/logo.c @@ -0,0 +1,17 @@ +{ + for (int c1 = 0; c1 <= 7; c1 += 1) + S1(1, c1); + for (int c0 = 2; c0 <= 6; c0 += 1) { + for (int c1 = 0; c1 < c0 - 1; c1 += 1) + S2(c0, c1); + for (int c1 = c0 - 1; c1 <= 4; c1 += 1) { + S1(c0, c1); + S2(c0, c1); + } + for (int c1 = 5; c1 <= 7; c1 += 1) + S1(c0, c1); + } + for (int c0 = 7; c0 <= 8; c0 += 1) + for (int c1 = c0 - 1; c1 <= 7; c1 += 1) + S1(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/logo.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/logo.st @@ -0,0 +1,10 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i1 <= 7 and i1 >= -1 + i0; S2[i0, i1] : i0 >= 2 and i0 <= 6 and i1 >= 0 and i1 <= 4 }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + - filter: "[M] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/logopar.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/logopar.c @@ -0,0 +1,17 @@ +{ + for (int c1 = 0; c1 <= m; c1 += 1) + S1(1, c1); + for (int c0 = 2; c0 <= n; c0 += 1) { + for (int c1 = 0; c1 < c0 - 1; c1 += 1) + S2(c0, c1); + for (int c1 = c0 - 1; c1 <= n; c1 += 1) { + S1(c0, c1); + S2(c0, c1); + } + for (int c1 = n + 1; c1 <= m; c1 += 1) + S1(c0, c1); + } + for (int c0 = n + 1; c0 <= m + 1; c0 += 1) + for (int c1 = c0 - 1; c1 <= m; c1 += 1) + S1(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/logopar.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/logopar.st @@ -0,0 +1,10 @@ +domain: "[m, n] -> { S1[i0, i1] : i0 >= 1 and i1 <= m and i1 >= -1 + i0; S2[i0, i1] : i0 >= 2 and i0 <= n and i1 >= 0 and i1 <= n }" +child: + context: "[m, n] -> { [] : n <= m and m >= 0 and n >= 2 }" + child: + schedule: "[m, n] -> [{ S2[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)] }]" + options: "[m, n] -> { separate[i0] }" + child: + sequence: + - filter: "[m, n] -> { S1[i0, i1] }" + - filter: "[m, n] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/lu.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lu.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 <= n; c0 += 1) { + for (int c1 = 2; c1 <= n; c1 += 1) + for (int c2 = 1; c2 < min(c0, c1); c2 += 1) + S2(c2, c1, c0); + for (int c3 = c0 + 1; c3 <= n; c3 += 1) + S1(c0, c3); +} Index: contrib/isl/test_inputs/codegen/cloog/lu.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lu.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n; S2[i0, i1, i2] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n and i2 >= 1 + i0 and i2 <= n }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S2[i0, i1, i2] -> [(i2)]; S1[i0, i1] -> [(i0)] }, { S2[i0, i1, i2] -> [(i1)]; S1[i0, i1] -> [(n)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/lu2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lu2.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 <= n; c0 += 1) { + for (int c1 = 2; c1 <= n; c1 += 1) + for (int c2 = 1; c2 < min(c0, c1); c2 += 1) + S2(c0, c1, c2, c1, c0); + for (int c3 = c0 + 1; c3 <= n; c3 += 1) + S1(c0, n, c0, c3); +} Index: contrib/isl/test_inputs/codegen/cloog/lu2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lu2.st @@ -0,0 +1,10 @@ +domain: "[n] -> { S2[i0, i1, i2, i1, i0] : i2 >= 1 and i2 <= n and i2 <= -1 + i1 and i1 <= n and i2 <= -1 + i0 and i0 <= n; S1[i0, n, i0, i3] : i0 >= 1 and i0 <= n and i3 >= 1 + i0 and i3 <= n }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S2[i0, i1, i2, i3, i4] -> [(i0)]; S1[i0, i1, i2, i3] -> [(i0)] }, { S2[i0, i1, i2, i3, i4] -> [(i1)]; S1[i0, i1, i2, i3] -> [(i1)] }, { S2[i0, i1, i2, i3, i4] -> [(i2)]; S1[i0, i1, i2, i3] -> [(i2)] }, { S2[i0, i1, i2, i3, i4] -> [(i3)]; S1[i0, i1, i2, i3] -> [(i3)] }, { S2[i0, i1, i2, i3, i4] -> [(i4)]; S1[i0, i1, i2, i3] -> [(0)] }]" + options: "[n] -> { separate[i0] }" + child: + sequence: + - filter: "[n] -> { S1[i0, i1, i2, i3] }" + - filter: "[n] -> { S2[i0, i1, i2, i3, i4] }" Index: contrib/isl/test_inputs/codegen/cloog/lux.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lux.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 <= M; c0 += 1) { + for (int c1 = 1; c1 < c0; c1 += 1) + for (int c2 = c1 + 1; c2 <= M; c2 += 1) + S2(c0, c1, c2, c2, c0); + for (int c3 = c0 + 1; c3 <= M; c3 += 1) + S1(c0, c0, M, c3); +} Index: contrib/isl/test_inputs/codegen/cloog/lux.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/lux.st @@ -0,0 +1,10 @@ +domain: "[M] -> { S1[i0, i0, M, i3] : i0 >= 1 and i0 <= M and i3 >= 1 + i0 and i3 <= M; S2[i0, i1, i2, i2, i0] : i1 >= 1 and i1 <= M and i2 >= 1 + i1 and i2 <= M and i1 <= -1 + i0 and i0 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i0)]; S2[i0, i1, i2, i3, i4] -> [(i0)] }, { S1[i0, i1, i2, i3] -> [(i1)]; S2[i0, i1, i2, i3, i4] -> [(i1)] }, { S1[i0, i1, i2, i3] -> [(i2)]; S2[i0, i1, i2, i3, i4] -> [(i2)] }, { S1[i0, i1, i2, i3] -> [(i3)]; S2[i0, i1, i2, i3, i4] -> [(i3)] }, { S1[i0, i1, i2, i3] -> [(0)]; S2[i0, i1, i2, i3, i4] -> [(i4)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1, i2, i3] }" + - filter: "[M] -> { S2[i0, i1, i2, i3, i4] }" Index: contrib/isl/test_inputs/codegen/cloog/merge.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/merge.c @@ -0,0 +1,8 @@ +{ + S1(0); + for (int c0 = 0; c0 <= 10; c0 += 1) { + if (c0 >= 2) + S2(c0); + S3(c0); + } +} Index: contrib/isl/test_inputs/codegen/cloog/merge.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/merge.st @@ -0,0 +1,11 @@ +domain: "{ S3[i0] : i0 >= 0 and i0 <= 10; S1[0]; S2[i0] : i0 >= 2 and i0 <= 10 }" +child: + context: "{ [] }" + child: + schedule: "[{ S2[i0] -> [(i0)]; S3[i0] -> [(i0)]; S1[i0] -> [(i0)] }]" + options: "{ atomic[i0] }" + child: + sequence: + - filter: "{ S1[i0] }" + - filter: "{ S2[i0] }" + - filter: "{ S3[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/min-1-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/min-1-1.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= N; c0 += 1) + for (int c1 = 0; c1 <= min(min(M, c0), N - c0); c1 += 1) + S1(c0, c1); Index: contrib/isl/test_inputs/codegen/cloog/min-1-1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/min-1-1.st @@ -0,0 +1,6 @@ +domain: "[M, N] -> { S1[i0, i1] : i0 >= 1 and i1 >= 0 and i1 <= M and i1 <= i0 and i1 <= N - i0 }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/min-2-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/min-2-1.c @@ -0,0 +1,4 @@ +for (int c0 = 1; c0 <= N; c0 += 1) + for (int c1 = 0; c1 <= min(min(M, c0), N - c0); c1 += 1) + for (int c2 = 0; c2 <= min(min(M, c0), N - c0); c2 += 1) + S1(c0, c1, c2); Index: contrib/isl/test_inputs/codegen/cloog/min-2-1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/min-2-1.st @@ -0,0 +1,6 @@ +domain: "[M, N] -> { S1[i0, i1, i2] : i0 >= 1 and i1 >= 0 and i1 <= M and i1 <= i0 and i1 <= N - i0 and i2 >= 0 and i2 <= M and i2 <= i0 and i2 <= N - i0 }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/min-3-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/min-3-1.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= min(10, M); c0 += 1) + for (int c1 = 0; c1 <= min(10, M); c1 += 1) + S1(c0, c1); Index: contrib/isl/test_inputs/codegen/cloog/min-3-1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/min-3-1.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 0 and i0 <= M and i0 <= 10 and i1 >= 0 and i1 <= M and i1 <= 10 }" +child: + context: "[M] -> { [] : M >= 0 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/min-4-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/min-4-1.c @@ -0,0 +1,2 @@ +for (int c0 = max(-M, -N); c0 <= min(N, O); c0 += 1) + S1(c0); Index: contrib/isl/test_inputs/codegen/cloog/min-4-1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/min-4-1.st @@ -0,0 +1,6 @@ +domain: "[M, N, O] -> { S1[i0] : i0 >= -M and i0 >= -N and i0 <= N and i0 <= O }" +child: + context: "[M, N, O] -> { [] }" + child: + schedule: "[M, N, O] -> [{ S1[i0] -> [(i0)] }]" + options: "[M, N, O] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/mod.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mod.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= 3; c0 += 1) + if ((c0 + 1) % 3 >= 1) + S1(c0); Index: contrib/isl/test_inputs/codegen/cloog/mod.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mod.st @@ -0,0 +1,6 @@ +domain: "{ S1[i0] : exists (e0 = floor((1 + i0)/3): 3e0 <= i0 and 3e0 >= -1 + i0 and i0 >= 0 and i0 <= 3) }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0] -> [(i0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/mod2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mod2.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= 3; c0 += 1) + if ((c0 + 1) % 3 >= 1) + S1(c0); Index: contrib/isl/test_inputs/codegen/cloog/mod2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mod2.st @@ -0,0 +1,6 @@ +domain: "{ S1[i] : exists (e0 = floor((1 + i)/3): 3e0 <= i and 3e0 >= -1 + i and i >= 0 and i <= 3) }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i] -> [(i)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/mod3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mod3.c @@ -0,0 +1,4 @@ +for (int c0 = max(0, 32 * h0 - 1991); c0 <= min(999, 32 * h0 + 31); c0 += 1) + if ((32 * h0 - c0 + 32) % 64 >= 1) + for (int c1 = 0; c1 <= 999; c1 += 1) + S1(c0, c1); Index: contrib/isl/test_inputs/codegen/cloog/mod3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mod3.st @@ -0,0 +1,6 @@ +domain: "[h0] -> { S1[i0, i1] : exists (e0 = floor((32 + 32h0 - i0)/64): 64e0 <= 31 + 32h0 - i0 and 64e0 >= -31 + 32h0 - i0 and i0 >= 0 and i0 <= 999 and i0 >= -2015 + 32h0 and 32e0 >= -999 + 32h0 - i0 and i1 >= 0 and i1 <= 999 and i0 <= 32 + 32h0) }" +child: + context: "[h0] -> { [] : h0 <= 93 and h0 >= 0 }" + child: + schedule: "[h0] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[h0] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/mod4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mod4.c @@ -0,0 +1,5 @@ +for (int c0 = 2; c0 <= 10; c0 += 3) { + S1(c0, (c0 + 1) / 3, (c0 + 1) / 3, 2, (c0 - 2) / 3); + S2(c0, (c0 + 1) / 3, (c0 + 1) / 3, 2, (c0 - 2) / 3); + S3(c0, (c0 + 1) / 3, (c0 + 1) / 3, 2, (c0 - 2) / 3); +} Index: contrib/isl/test_inputs/codegen/cloog/mod4.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mod4.st @@ -0,0 +1,11 @@ +domain: "{ S1[j, div41, div42, 2, mod6_a] : 3mod6_a = -2 + j and j >= 1 and j <= 10 and 3div41 >= j and 3div42 >= -1 + j and 3div42 <= 1 + j and 3div41 <= 2 + j; S2[j, div41, div42, 2, mod6_a] : 3div42 = 1 + j and 3mod6_a = -2 + j and 3div41 >= 1 + j and 3div41 <= 2 + j and j >= 1 and j <= 10; S3[j, div41, div42, 2, mod6_a] : 3mod6_a = -2 + j and j >= 1 and j <= 10 and 3div41 >= j and 3div42 >= -1 + j and 3div42 <= 1 + j and 3div41 <= 2 + j }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[j, div41, div42, mod6, mod6_a] -> [(j)]; S3[j, div41, div42, mod6, mod6_a] -> [(j)]; S2[j, div41, div42, mod6, mod6_a] -> [(j)] }, { S1[j, div41, div42, mod6, mod6_a] -> [(div41)]; S3[j, div41, div42, mod6, mod6_a] -> [(div41)]; S2[j, div41, div42, mod6, mod6_a] -> [(div41)] }, { S1[j, div41, div42, mod6, mod6_a] -> [(div42)]; S3[j, div41, div42, mod6, mod6_a] -> [(div42)]; S2[j, div41, div42, mod6, mod6_a] -> [(div42)] }, { S1[j, div41, div42, mod6, mod6_a] -> [(mod6)]; S3[j, div41, div42, mod6, mod6_a] -> [(mod6)]; S2[j, div41, div42, mod6, mod6_a] -> [(mod6)] }, { S1[j, div41, div42, mod6, mod6_a] -> [(mod6_a)]; S3[j, div41, div42, mod6, mod6_a] -> [(mod6_a)]; S2[j, div41, div42, mod6, mod6_a] -> [(mod6_a)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[j, div41, div42, mod6, mod6_a] }" + - filter: "{ S2[j, div41, div42, mod6, mod6_a] }" + - filter: "{ S3[j, div41, div42, mod6, mod6_a] }" Index: contrib/isl/test_inputs/codegen/cloog/mode.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mode.c @@ -0,0 +1,10 @@ +for (int c0 = 0; c0 <= M; c0 += 1) { + for (int c1 = 0; c1 <= min(N, c0); c1 += 1) { + S1(c0, c1); + S2(c0, c1); + } + for (int c1 = c0 + 1; c1 <= N; c1 += 1) + S2(c0, c1); + for (int c1 = max(0, N + 1); c1 <= c0; c1 += 1) + S1(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/mode.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mode.st @@ -0,0 +1,10 @@ +domain: "[M, N] -> { S1[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= i0; S2[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= N }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1] }" + - filter: "[M, N] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/multi-mm-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/multi-mm-1.c @@ -0,0 +1,8 @@ +for (int c0 = 0; c0 <= M; c0 += 1) { + for (int c1 = 0; c1 <= min(N, c0); c1 += 1) { + S1(c0, c1); + S2(c0, c1); + } + for (int c1 = N + 1; c1 <= c0; c1 += 1) + S1(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/multi-mm-1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/multi-mm-1.st @@ -0,0 +1,10 @@ +domain: "[M, N] -> { S1[i0, i1] : i1 >= 0 and i1 <= i0 and i0 <= M; S2[i0, i1] : i1 >= 0 and i1 <= i0 and i0 <= M and i1 <= N }" +child: + context: "[M, N] -> { [] : N <= M and N >= 1 }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1] }" + - filter: "[M, N] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/multi-stride.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/multi-stride.c @@ -0,0 +1,2 @@ +{ +} Index: contrib/isl/test_inputs/codegen/cloog/multi-stride.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/multi-stride.st @@ -0,0 +1,6 @@ +domain: "{ S1[i0, i1, i2] : 2i1 = -1 + i0 and 6i2 = -2 + i0 and i0 >= 0 and i0 <= 100 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/multi-stride2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/multi-stride2.c @@ -0,0 +1,2 @@ +for (int c0 = 5; c0 <= 100; c0 += 6) + S1(c0, (c0 - 1) / 2, (c0 - 2) / 3); Index: contrib/isl/test_inputs/codegen/cloog/multi-stride2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/multi-stride2.st @@ -0,0 +1,6 @@ +domain: "{ S1[i0, i1, i2] : 2i1 = -1 + i0 and 3i2 = -2 + i0 and i0 >= 0 and i0 <= 100 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/mxm-shared.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mxm-shared.c @@ -0,0 +1,3 @@ +if (N >= g0 + t1 + 1 && t1 <= 7 && g4 % 4 == 0) + for (int c0 = t0; c0 <= min(127, N - g1 - 1); c0 += 16) + S1(g0 + t1, g1 + c0); Index: contrib/isl/test_inputs/codegen/cloog/mxm-shared.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/mxm-shared.st @@ -0,0 +1,6 @@ +domain: "[N, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { S1[g0 + t1, i1] : (exists (e0 = floor((g1)/128), e1 = floor((128b1 - g1)/4096), e2 = floor((-8b0 + g0)/128), e3 = floor((-t0 + i1)/16): g3 = 128b1 and g4 = 0 and g2 = 8b0 and 128e0 = g1 and 4096e1 = 128b1 - g1 and 128e2 = -8b0 + g0 and 16e3 = -t0 + i1 and b0 <= 15 and b0 >= 0 and b1 <= 31 and b1 >= 0 and g0 >= 8b0 and g1 >= 128b1 and t0 <= 15 and t0 >= 0 and t1 <= 7 and t1 >= 0 and t1 <= -1 + N - g0 and i1 >= g1 and i1 <= 127 + g1 and i1 <= -1 + N)) or (exists (e0 = floor((g1)/128), e1 = floor((128b1 - g1)/4096), e2 = floor((g4)/4), e3 = floor((-8b0 + g0)/128), e4 = floor((-t0 + i1)/16): g3 = 128b1 and g2 = 8b0 and 128e0 = g1 and 4096e1 = 128b1 - g1 and 4e2 = g4 and 128e3 = -8b0 + g0 and 16e4 = -t0 + i1 and b0 <= 15 and b0 >= 0 and b1 <= 31 and b1 >= 0 and g0 >= 8b0 and g1 >= 128b1 and g4 >= 0 and g4 <= -1 + N and t0 <= 15 and t0 >= 0 and t1 <= 7 and t1 >= 0 and t1 <= -1 + N - g0 and i1 >= g1 and i1 <= 127 + g1 and i1 <= -1 + N)) }" +child: + context: "[N, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { [] : exists (e0 = floor((g0)/8), e1 = floor((-128b1 + g1)/4096), e2 = floor((8b0 - g0)/128): g2 = 8b0 and g3 = 128b1 and 8e0 = g0 and 4096e1 = -128b1 + g1 and 128e2 = 8b0 - g0 and b0 >= 0 and g4 <= -1 + N and b0 <= 15 and g1 <= -1 + N and g4 >= 0 and b1 <= 31 and g0 <= -1 + N and g1 >= 128b1 and b1 >= 0 and g0 >= 8b0 and t0 >= 0 and t0 <= 15 and t1 >= 0 and t1 <= 15) }" + child: + schedule: "[N, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> [{ S1[i0, i1] -> [(-g1 + i1)] }, { S1[i0, i1] -> [(t1)] }, { S1[i0, i1] -> [(t0)] }, { S1[i0, i1] -> [(t1)] }]" + options: "[N, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/no_lindep.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/no_lindep.c @@ -0,0 +1 @@ +S1(N + 2); Index: contrib/isl/test_inputs/codegen/cloog/no_lindep.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/no_lindep.st @@ -0,0 +1,6 @@ +domain: "[M, N] -> { S1[2 + N] }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0] -> [(1 + M)] }, { S1[i0] -> [(N)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/nul_basic1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/nul_basic1.c @@ -0,0 +1,2 @@ +for (int c0 = 0; c0 <= M; c0 += 2) + S1(c0, c0 / 2); Index: contrib/isl/test_inputs/codegen/cloog/nul_basic1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/nul_basic1.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0, i1] : 2i1 = i0 and i0 >= 0 and i0 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/nul_basic2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/nul_basic2.c @@ -0,0 +1,5 @@ +for (int c0 = 2; c0 <= n; c0 += 2) { + if (c0 % 4 == 0) + S2(c0, c0 / 4); + S1(c0, c0 / 2); +} Index: contrib/isl/test_inputs/codegen/cloog/nul_basic2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/nul_basic2.st @@ -0,0 +1,10 @@ +domain: "[n] -> { S1[i0, i1] : 2i1 = i0 and i0 >= 1 and i0 <= n; S2[i0, i1] : 4i1 = i0 and i0 >= 1 and i0 <= n }" +child: + context: "[n] -> { [] : n >= 2 }" + child: + schedule: "[n] -> [{ S2[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)] }]" + options: "[n] -> { separate[i0] }" + child: + sequence: + - filter: "[n] -> { S1[i0, i1] }" + - filter: "[n] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/nul_complex1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/nul_complex1.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= 5 * n; c0 += 1) + for (int c1 = max(-((5 * n - c0 + 1) % 2) - n + c0 + 1, 2 * ((c0 + 2) / 3)); c1 <= min(c0, n + c0 - (n + c0 + 2) / 3); c1 += 2) + S1((3 * c1 / 2) - c0, c0 - c1); Index: contrib/isl/test_inputs/codegen/cloog/nul_complex1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/nul_complex1.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[i0, i1] : i0 >= 0 and i0 <= n and i1 >= 0 and i1 <= n }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S1[i0, i1] -> [(2i0 + 3i1)] }, { S1[i0, i1] -> [(2i0 + 2i1)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/nul_lcpc.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/nul_lcpc.c @@ -0,0 +1,13 @@ +{ + for (int c0 = 1; c0 <= 6; c0 += 2) { + for (int c2 = 1; c2 <= c0; c2 += 1) { + S1(c0, (c0 - 1) / 2, c2); + S2(c0, (c0 - 1) / 2, c2); + } + for (int c2 = c0 + 1; c2 <= p; c2 += 1) + S1(c0, (c0 - 1) / 2, c2); + } + for (int c0 = 7; c0 <= m; c0 += 2) + for (int c2 = 1; c2 <= p; c2 += 1) + S1(c0, (c0 - 1) / 2, c2); +} Index: contrib/isl/test_inputs/codegen/cloog/nul_lcpc.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/nul_lcpc.st @@ -0,0 +1,10 @@ +domain: "[m, n, p] -> { S1[i, k, j] : 2k = -1 + i and i >= 1 and i <= m and j >= 1 and j <= p; S2[i, k, j] : 2k = -1 + i and i >= 1 and i <= n and j >= 1 and j <= i }" +child: + context: "[m, n, p] -> { [] : n = 6 and m >= 7 and p >= 7 }" + child: + schedule: "[m, n, p] -> [{ S1[i, k, j] -> [(i)]; S2[i, k, j] -> [(i)] }, { S1[i, k, j] -> [(k)]; S2[i, k, j] -> [(k)] }, { S1[i, k, j] -> [(j)]; S2[i, k, j] -> [(j)] }]" + options: "[m, n, p] -> { separate[i0] }" + child: + sequence: + - filter: "[m, n, p] -> { S1[i, k, j] }" + - filter: "[m, n, p] -> { S2[i, k, j] }" Index: contrib/isl/test_inputs/codegen/cloog/orc.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/orc.c @@ -0,0 +1,16 @@ +{ + for (int c0 = 0; c0 <= 2; c0 += 1) { + S1(c0); + for (int c1 = 0; c1 <= -c0 + 11; c1 += 1) { + S2(c0, c1); + S3(c0, c1); + } + S4(c0); + } + for (int c0 = 0; c0 <= 14; c0 += 1) { + S5(c0); + for (int c1 = 0; c1 <= 9; c1 += 1) + S6(c0, c1); + S7(c0); + } +} Index: contrib/isl/test_inputs/codegen/cloog/orc.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/orc.st @@ -0,0 +1,13 @@ +domain: "{ S5[i] : i >= 0 and i <= 14; S6[i, j] : i >= 0 and i <= 14 and j >= 0 and j <= 9; S7[i] : i >= 0 and i <= 14; S4[i] : i >= 0 and i <= 2; S2[i, j] : i >= 0 and i <= 2 and j >= 0 and j <= 11 - i; S1[i] : i >= 0 and i <= 2; S3[i, j] : i >= 0 and i <= 2 and j >= 0 and j <= 11 - i }" +child: + context: "{ [] }" + child: + sequence: + - filter: "{ S4[i0]; S2[i0, i1]; S1[i0]; S3[i0, i1] }" + child: + schedule: "[{ S3[i0, i1] -> [(1 + 3i0)]; S2[i0, i1] -> [(1 + 3i0)]; S1[i0] -> [(3i0)]; S4[i0] -> [(2 + 3i0)] }, { S3[i0, i1] -> [(1 + 2i1)]; S2[i0, i1] -> [(2i1)]; S1[i0] -> [(0)]; S4[i0] -> [(0)] }]" + options: "{ separate[i0] }" + - filter: "{ S5[i0]; S6[i0, i1]; S7[i0] }" + child: + schedule: "[{ S6[i0, i1] -> [(1 + 3i0)]; S7[i0] -> [(2 + 3i0)]; S5[i0] -> [(3i0)] }, { S6[i0, i1] -> [(i1)]; S7[i0] -> [(0)]; S5[i0] -> [(0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/otl.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/otl.c @@ -0,0 +1,7 @@ +if (M >= 3 && N >= 4) + for (int c0 = 1; c0 < (2 * M + 2 * N - 2) / 5; c0 += 1) + for (int c1 = max(c0 - (M + 2) / 5, (c0 + 1) / 2); c1 <= min(min(c0, (M + 2 * N) / 5 - 1), (2 * N + 5 * c0 + 1) / 10); c1 += 1) + for (int c2 = max(max(max(max(0, c0 - c1 - 1), c1 - (N + 6) / 5 + 1), c0 - (M + N + 4) / 5 + 1), floord(-N + 5 * c0 - 3, 10) + 1); c2 <= min(min(min(c1, (M + N - 2) / 5), c0 - c1 + (N - 1) / 5 + 1), (N + 5 * c0 + 3) / 10); c2 += 1) + for (int c3 = max(max(max(c0, 2 * c1 - (2 * N + 5) / 5 + 1), c1 + c2 - (N + 3) / 5), 2 * c2 - (N + 2) / 5); c3 <= min(min(min(min(min(c0 + 1, c1 + c2 + 1), c1 + (M - 2) / 5 + 1), 2 * c2 + (N - 2) / 5 + 1), (2 * M + 2 * N - 1) / 5 - 1), c2 + (M + N) / 5); c3 += 1) + for (int c4 = max(max(max(max(c1, c0 - c2), c0 - (M + 6) / 5 + 1), c3 - (M + 2) / 5), (c3 + 1) / 2); c4 <= min(min(min(min(min(min(min(c0, c1 + 1), -c2 + c3 + (N - 1) / 5 + 1), c0 - c2 + N / 5 + 1), (M + 2 * N + 1) / 5 - 1), c2 + (N + 2) / 5), (2 * N + 5 * c0 + 3) / 10), (2 * N + 5 * c3 + 2) / 10); c4 += 1) + S1(c0, c1, c2, c3, c4, c2); Index: contrib/isl/test_inputs/codegen/cloog/otl.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/otl.st @@ -0,0 +1,6 @@ +domain: "[M, N] -> { S1[outerTimeTileIter, outerProcTileIter1, outerProcTileIter2, innerTimeTileIter, innerProcTileIter1, outerProcTileIter2] : 5outerTimeTileIter <= -7 + 2M + 2N and innerProcTileIter1 >= outerTimeTileIter - outerProcTileIter2 and 10outerProcTileIter2 >= -2 - N + 5outerTimeTileIter and outerProcTileIter2 >= -1 + outerTimeTileIter - outerProcTileIter1 and 2innerProcTileIter1 >= outerTimeTileIter and outerTimeTileIter >= 1 and outerProcTileIter1 >= 1 and 2outerProcTileIter1 >= outerTimeTileIter and outerProcTileIter2 >= 0 and 5outerProcTileIter2 >= 1 - M - N + 5outerTimeTileIter and 5innerProcTileIter1 >= -1 - M + 5outerTimeTileIter and innerTimeTileIter >= outerTimeTileIter and 5outerProcTileIter1 >= -2 - M + 5outerTimeTileIter and innerTimeTileIter >= 1 and 5innerTimeTileIter >= -3 - N + 5outerProcTileIter1 + 5outerProcTileIter2 and 5outerProcTileIter2 <= 4 + N + 5outerTimeTileIter - 5outerProcTileIter1 and innerProcTileIter1 >= 1 and outerProcTileIter2 <= outerTimeTileIter and 5innerTimeTileIter >= -2N + 10outerProcTileIter1 and 5outerProcTileIter1 <= -5 + M + 2N and 10outerProcTileIter1 <= 1 + 2N + 5outerTimeTileIter and 5outerProcTileIter2 >= -1 - N + 5outerProcTileIter1 and innerProcTileIter1 >= outerProcTileIter1 and innerTimeTileIter >= outerProcTileIter1 and outerProcTileIter2 <= outerProcTileIter1 and outerProcTileIter1 <= outerTimeTileIter and 5innerProcTileIter1 <= 4 + N - 5outerProcTileIter2 + 5innerTimeTileIter and 5innerProcTileIter1 <= 5 + N + 5outerTimeTileIter - 5outerProcTileIter2 and 5innerTimeTileIter >= -2 - N + 10outerProcTileIter2 and 5outerProcTileIter2 <= -2 + M + N and 10outerProcTileIter2 <= 3 + N + 5outerTimeTileIter and N >= 4 and innerProcTileIter1 >= outerProcTileIter2 and innerTimeTileIter >= outerProcTileIter2 and M >= 3 and innerProcTileIter1 <= outerTimeTileIter and 5innerTimeTileIter <= -6 + 2M + 2N and innerProcTileIter1 >= -1 - outerProcTileIter2 + innerTimeTileIter and 5innerTimeTileIter <= 3 + N + 10outerProcTileIter2 and innerTimeTileIter <= 1 + outerProcTileIter1 + outerProcTileIter2 and innerProcTileIter1 <= 1 + outerProcTileIter1 and 2innerProcTileIter1 >= innerTimeTileIter and 5innerProcTileIter1 <= 2 + N + 5outerProcTileIter2 and innerTimeTileIter <= 1 + 2outerProcTileIter1 and innerProcTileIter1 <= innerTimeTileIter and 5innerTimeTileIter <= M + N + 5outerProcTileIter2 and 5innerProcTileIter1 >= -2 - M + 5innerTimeTileIter and 10innerProcTileIter1 <= 3 + 2N + 5outerTimeTileIter and innerTimeTileIter <= 1 + outerTimeTileIter and 5innerTimeTileIter <= 3 + M + 5outerProcTileIter1 and 5innerProcTileIter1 <= -4 + M + 2N and 10innerProcTileIter1 <= 2 + 2N + 5innerTimeTileIter }" +child: + context: "[M, N] -> { [] : M >= 1 and N >= 1 }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2, i3, i4, i5] -> [(i0)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i1)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i2)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i3)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i4)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i5)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/param-split.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/param-split.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 <= max(0, M); c0 += 1) { + if (M >= c0) + S1(c0); + if (c0 == 0) + S2(0); +} Index: contrib/isl/test_inputs/codegen/cloog/param-split.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/param-split.st @@ -0,0 +1,10 @@ +domain: "[M] -> { S2[0]; S1[i0] : i0 >= 0 and i0 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S2[i0] -> [(i0)]; S1[i0] -> [(i0)] }]" + options: "[M] -> { atomic[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0] }" + - filter: "[M] -> { S2[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/pouchet.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/pouchet.c @@ -0,0 +1,12 @@ +for (int c0 = 1; c0 <= floord(Ny, 2) + 2; c0 += 1) + for (int c1 = max(c0 - 1, c0 / 2 + 1); c1 <= min(c0, (Ny + 2 * c0) / 4); c1 += 1) { + if (Ny + 2 * c0 >= 4 * c1 + 1) { + for (int c2 = 1; c2 <= 2; c2 += 1) { + S1(c0 - c1, c1, 2 * c0 - 2 * c1, -2 * c0 + 4 * c1, c2); + S2(c0 - c1, c1, 2 * c0 - 2 * c1, -2 * c0 + 4 * c1 - 1, c2); + } + } else { + for (int c2 = 1; c2 <= 2; c2 += 1) + S2((-Ny + 2 * c0) / 4, (Ny + 2 * c0) / 4, (-Ny / 2) + c0, Ny - 1, c2); + } + } Index: contrib/isl/test_inputs/codegen/cloog/pouchet.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/pouchet.st @@ -0,0 +1,6 @@ +domain: "[Ny] -> { S1[i0, i1, 2i0, -2i0 + 2i1, i4] : i0 >= 0 and i0 <= 1 and i1 >= 1 + i0 and 2i1 <= -1 + Ny + 2i0 and i4 >= 1 and i4 <= 2; S2[i0, i1, 2i0, -1 - 2i0 + 2i1, i4] : i0 >= 0 and i0 <= 1 and i1 >= 1 + i0 and 2i1 <= Ny + 2i0 and i4 >= 1 and i4 <= 2 }" +child: + context: "[Ny] -> { [] }" + child: + schedule: "[Ny] -> [{ S1[i0, i1, i2, i3, i4] -> [(i0 + i1)]; S2[i0, i1, i2, i3, i4] -> [(i0 + i1)] }, { S1[i0, i1, i2, i3, i4] -> [(i1)]; S2[i0, i1, i2, i3, i4] -> [(i1)] }, { S1[i0, i1, i2, i3, i4] -> [(i4)]; S2[i0, i1, i2, i3, i4] -> [(i4)] }, { S1[i0, i1, i2, i3, i4] -> [(i2)]; S2[i0, i1, i2, i3, i4] -> [(i2)] }, { S1[i0, i1, i2, i3, i4] -> [(i3)]; S2[i0, i1, i2, i3, i4] -> [(1 + i3)] }, { S1[i0, i1, i2, i3, i4] -> [(i4)]; S2[i0, i1, i2, i3, i4] -> [(1 + i4)] }]" + options: "[Ny] -> { separate[x] : x >= 2 }" Index: contrib/isl/test_inputs/codegen/cloog/rectangle.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/rectangle.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= 2 * n; c0 += 1) + for (int c1 = max(0, -n + c0); c1 <= min(n, c0); c1 += 1) + S1(c1, c0 - c1); Index: contrib/isl/test_inputs/codegen/cloog/rectangle.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/rectangle.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[i0, i1] : i0 >= 0 and i0 <= n and i1 >= 0 and i1 <= n }" +child: + context: "[n] -> { [] : n >= 0 }" + child: + schedule: "[n] -> [{ S1[i0, i1] -> [(i0 + i1)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-QR.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-QR.c @@ -0,0 +1,54 @@ +if (N >= 1) { + S1(0); + if (N == 1) { + for (int c1 = 0; c1 < M; c1 += 1) + S2(0, c1); + S3(0); + for (int c1 = 0; c1 < M; c1 += 1) + S4(0, c1); + S10(0); + S5(0); + } else { + for (int c1 = 0; c1 < M; c1 += 1) + S2(0, c1); + S3(0); + for (int c1 = 0; c1 < M; c1 += 1) + S4(0, c1); + S10(0); + S1(1); + S5(0); + } + for (int c0 = 2; c0 < N; c0 += 1) { + for (int c1 = c0 - 1; c1 < N; c1 += 1) { + S6(c0 - 2, c1); + for (int c2 = c0 - 2; c2 < M; c2 += 1) + S7(c0 - 2, c1, c2); + S8(c0 - 2, c1); + for (int c2 = c0 - 2; c2 < M; c2 += 1) + S9(c0 - 2, c1, c2); + } + for (int c1 = c0 - 1; c1 < M; c1 += 1) + S2(c0 - 1, c1); + S3(c0 - 1); + for (int c1 = c0 - 1; c1 < M; c1 += 1) + S4(c0 - 1, c1); + S10(c0 - 1); + S1(c0); + S5(c0 - 1); + } + if (N >= 2) { + S6(N - 2, N - 1); + for (int c2 = N - 2; c2 < M; c2 += 1) + S7(N - 2, N - 1, c2); + S8(N - 2, N - 1); + for (int c2 = N - 2; c2 < M; c2 += 1) + S9(N - 2, N - 1, c2); + for (int c1 = N - 1; c1 < M; c1 += 1) + S2(N - 1, c1); + S3(N - 1); + for (int c1 = N - 1; c1 < M; c1 += 1) + S4(N - 1, c1); + S10(N - 1); + S5(N - 1); + } +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-QR.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-QR.st @@ -0,0 +1,36 @@ +domain: "[M, N] -> { S5[i0] : i0 >= 0 and i0 <= -1 + N; S1[i0] : i0 >= 0 and i0 <= -1 + N; S3[i0] : i0 >= 0 and i0 <= -1 + N; S2[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= i0 and i1 <= -1 + M; S6[i0, i1] : i0 >= 0 and i1 >= 1 + i0 and i1 <= -1 + N; S9[i0, i1, i2] : i0 >= 0 and i1 >= 1 + i0 and i1 <= -1 + N and i2 >= i0 and i2 <= -1 + M; S4[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= i0 and i1 <= -1 + M; S8[i0, i1] : i0 >= 0 and i1 >= 1 + i0 and i1 <= -1 + N; S10[i0] : i0 >= 0 and i0 <= -1 + N; S7[i0, i1, i2] : i0 >= 0 and i1 >= 1 + i0 and i1 <= -1 + N and i2 >= i0 and i2 <= -1 + M }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S3[i0] -> [(1 + i0)]; S10[i0] -> [(1 + i0)]; S5[i0] -> [(1 + i0)]; S7[i0, i1, i2] -> [(2 + i0)]; S9[i0, i1, i2] -> [(2 + i0)]; S2[i0, i1] -> [(1 + i0)]; S4[i0, i1] -> [(1 + i0)]; S8[i0, i1] -> [(2 + i0)]; S1[i0] -> [(i0)]; S6[i0, i1] -> [(2 + i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S6[i0, i1]; S9[i0, i1, i2]; S8[i0, i1]; S7[i0, i1, i2] }" + child: + schedule: "[M, N] -> [{ S7[i0, i1, i2] -> [(i1)]; S9[i0, i1, i2] -> [(i1)]; S8[i0, i1] -> [(i1)]; S6[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S6[i0, i1] }" + - filter: "[M, N] -> { S7[i0, i1, i2] }" + child: + schedule: "[M, N] -> [{ S7[i0, i1, i2] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S8[i0, i1] }" + - filter: "[M, N] -> { S9[i0, i1, i2] }" + child: + schedule: "[M, N] -> [{ S9[i0, i1, i2] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S2[i0, i1] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S3[i0] }" + - filter: "[M, N] -> { S4[i0, i1] }" + child: + schedule: "[M, N] -> [{ S4[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S10[i0] }" + - filter: "[M, N] -> { S1[i0] }" + - filter: "[M, N] -> { S5[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-bastoul3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-bastoul3.c @@ -0,0 +1,3 @@ +for (int c0 = 3; c0 <= 9; c0 += 1) + for (int c1 = max(c0 - 6, -(c0 % 2) + 2); c1 <= min(3, c0 - 2); c1 += 2) + S1(c0, c1, (c0 - c1) / 2); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-bastoul3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-bastoul3.st @@ -0,0 +1,6 @@ +domain: "{ S1[i0, i1, i2] : 2i2 = i0 - i1 and i1 >= 1 and i1 <= 3 and i1 <= -2 + i0 and i1 >= -6 + i0 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-cholesky2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-cholesky2.c @@ -0,0 +1,9 @@ +for (int c0 = 2; c0 < 3 * M; c0 += 1) { + if ((c0 + 1) % 3 == 0) + S1((c0 + 1) / 3); + for (int c1 = (c0 + 1) / 3 + 1; c1 <= min(M, c0 - 2); c1 += 1) + for (int c2 = -c1 + (c0 + c1 + 1) / 2 + 1; c2 <= min(c1, c0 - c1); c2 += 1) + S3(c0 - c1 - c2 + 1, c1, c2); + for (int c1 = -c0 + 2 * ((2 * c0 + 1) / 3) + 2; c1 <= min(M, c0); c1 += 2) + S2(((c0 - c1) / 2) + 1, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-cholesky2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-cholesky2.st @@ -0,0 +1,20 @@ +domain: "[M] -> { S3[i0, i1, i2] : i0 >= 1 and i1 <= M and i2 >= 1 + i0 and i2 <= i1; S2[i0, i1] : i0 >= 1 and i1 >= 1 + i0 and i1 <= M; S1[i0] : i0 >= 1 and i0 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0] -> [(-1 + 3i0)]; S3[i0, i1, i2] -> [(-1 + i0 + i1 + i2)]; S2[i0, i1] -> [(-2 + 2i0 + i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0] }" + - filter: "[M] -> { S3[i0, i1, i2] }" + child: + schedule: "[M] -> [{ S3[i0, i1, i2] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S3[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-fusion1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-fusion1.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 0; c0 <= M; c0 += 1) + S1(c0); + for (int c0 = 1; c0 <= M; c0 += 1) + S2(c0); + for (int c0 = 0; c0 <= M; c0 += 1) + S3(c0); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-fusion1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-fusion1.st @@ -0,0 +1,17 @@ +domain: "[M] -> { S3[i0] : i0 >= 0 and i0 <= M; S2[i0] : i0 >= 1 and i0 <= M; S1[i0] : i0 >= 0 and i0 <= M }" +child: + context: "[M] -> { [] : M >= 1 }" + child: + sequence: + - filter: "[M] -> { S1[i0] }" + child: + schedule: "[M] -> [{ S1[i0] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0] }" + child: + schedule: "[M] -> [{ S2[i0] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S3[i0] }" + child: + schedule: "[M] -> [{ S3[i0] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-fusion2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-fusion2.c @@ -0,0 +1,12 @@ +if (N >= 1) { + for (int c1 = 1; c1 <= M; c1 += 1) + S1(1, c1); + for (int c0 = 2; c0 <= N; c0 += 1) { + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c0 - 1, c1); + for (int c1 = 1; c1 <= M; c1 += 1) + S1(c0, c1); + } + for (int c1 = 1; c1 <= M; c1 += 1) + S2(N, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-fusion2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-fusion2.st @@ -0,0 +1,16 @@ +domain: "[M, N] -> { S1[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(1 + i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S2[i0, i1] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S1[i0, i1] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-jacobi2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-jacobi2.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 < M; c0 += 1) + for (int c1 = 0; c1 < M; c1 += 1) + S1(c0, c1); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-jacobi2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-jacobi2.st @@ -0,0 +1,9 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 0 and i0 <= -1 + M and i1 >= 0 and i1 <= -1 + M }" +child: + context: "[M] -> { [] : M >= 1 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-jacobi3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-jacobi3.c @@ -0,0 +1,8 @@ +for (int c0 = 1; c0 <= M; c0 += 1) { + for (int c2 = 2; c2 < N; c2 += 1) + for (int c3 = 2; c3 < N; c3 += 1) + S1(c0, c2, c3); + for (int c2 = 2; c2 < N; c2 += 1) + for (int c3 = 2; c3 < N; c3 += 1) + S2(c0, c2, c3); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-jacobi3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-jacobi3.st @@ -0,0 +1,22 @@ +domain: "[M, N] -> { S2[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + N; S1[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + N }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(2i0)]; S2[i0, i1, i2] -> [(1 + 2i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1, i2] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S2[i0, i1, i2] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1, i2] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1, i2] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.c @@ -0,0 +1,10 @@ +for (int c0 = -99; c0 <= 100; c0 += 1) { + if (c0 <= 0) + S1(1, -c0 + 1); + for (int c1 = max(1, -2 * c0 + 3); c1 <= min(199, -2 * c0 + 199); c1 += 2) { + S2(((c1 - 1) / 2) + c0, (c1 + 1) / 2); + S1(((c1 + 1) / 2) + c0, (c1 + 1) / 2); + } + if (c0 >= 1) + S2(100, -c0 + 101); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.st @@ -0,0 +1,13 @@ +domain: "{ S2[i0, i1] : i0 >= 1 and i0 <= 100 and i1 >= 1 and i1 <= 100; S1[i0, i1] : i0 >= 1 and i0 <= 100 and i1 >= 1 and i1 <= 100 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1] -> [(i0 - i1)]; S2[i0, i1] -> [(1 + i0 - i1)] }]" + options: "{ separate[i0] }" + child: + schedule: "[{ S1[i0, i1] -> [(2i1)]; S2[i0, i1] -> [(-1 + 2i1)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1] }" + - filter: "{ S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.c @@ -0,0 +1,10 @@ +{ + for (int c0 = 1; c0 <= M; c0 += 1) + S1(c0); + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 2; c1 <= N; c1 += 1) + S2(c0, c1); + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 < N; c1 += 1) + S3(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.st @@ -0,0 +1,23 @@ +domain: "[M, N] -> { S3[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= -1 + N; S1[i0] : i0 >= 1 and i0 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= N }" +child: + context: "[M, N] -> { [] : M >= 1 and N >= 1 }" + child: + sequence: + - filter: "[M, N] -> { S1[i0] }" + child: + schedule: "[M, N] -> [{ S1[i0] -> [(i0)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S2[i0, i1] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S3[i0, i1] }" + child: + schedule: "[M, N] -> [{ S3[i0, i1] -> [(i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S3[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.c @@ -0,0 +1,11 @@ +for (int c0 = 5; c0 <= 5 * M; c0 += 1) { + for (int c1 = max(2, floord(-M + c0, 4)); c1 < min(-((5 * M - c0 + 1) % 2) + M, (c0 + 1) / 3 - 2); c1 += 1) + for (int c2 = max(1, -M - c1 + (M + c0) / 2 - 2); c2 < min(c1, -2 * c1 + (c0 + c1) / 2 - 2); c2 += 1) + S1(c0 - 2 * c1 - 2 * c2 - 5, c1, c2); + for (int c1 = max(1, floord(-M + c0, 4)); c1 < (c0 + 1) / 5; c1 += 1) + S2(c0 - 4 * c1 - 3, c1); + if (c0 % 5 == 0) + S4(c0 / 5); + for (int c1 = max(-3 * M - c0 + 3 * ((M + c0) / 2) + 1, -((c0 - 1) % 3) + 3); c1 < (c0 + 1) / 5; c1 += 3) + S3((c0 - 2 * c1 - 1) / 3, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.st @@ -0,0 +1,23 @@ +domain: "[M] -> { S4[i0] : i0 >= 1 and i0 <= M; S3[i0, i1] : i0 <= M and i1 >= 1 and i1 <= -1 + i0; S2[i0, i1] : i0 <= M and i1 >= 1 and i1 <= -1 + i0; S1[i0, i1, i2] : i0 <= M and i1 <= -1 + i0 and i2 >= 1 and i2 <= -1 + i1 }" +child: + context: "[M] -> { [] : M >= 1 }" + child: + schedule: "[M] -> [{ S4[i0] -> [(5i0)]; S1[i0, i1, i2] -> [(5 + i0 + 2i1 + 2i2)]; S3[i0, i1] -> [(1 + 3i0 + 2i1)]; S2[i0, i1] -> [(3 + i0 + 4i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1, i2] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S4[i0]; S3[i0, i1] }" + child: + schedule: "[M] -> [{ S4[i0] -> [(0)]; S3[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.c @@ -0,0 +1,10 @@ +for (int c0 = 1; c0 < 2 * M - 1; c0 += 1) { + for (int c1 = max(-M + 1, -c0 + 1); c1 < 0; c1 += 1) { + for (int c3 = max(1, -M + c0 + 1); c3 <= min(M - 1, c0 + c1); c3 += 1) + S1(c3, c0 + c1 - c3, -c1); + for (int c2 = max(-M + c0 + 1, -c1); c2 < min(M, c0); c2 += 1) + S2(c0 - c2, c1 + c2, c2); + } + for (int c3 = max(1, -M + c0 + 1); c3 <= min(M - 1, c0); c3 += 1) + S1(c3, c0 - c3, 0); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.st @@ -0,0 +1,19 @@ +domain: "[M] -> { S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + M and i1 >= 0 and i2 >= 1 + i1 and i2 <= -1 + M; S1[i0, i1, i2] : i0 >= 1 and i0 <= -1 + M and i1 >= 0 and i2 >= 0 and i2 <= -1 + M - i1 }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0 + i1 + i2)]; S2[i0, i1, i2] -> [(i0 + i2)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(-i2)]; S2[i0, i1, i2] -> [(i1 - i2)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1, i2] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1, i2] }" + child: + schedule: "[M] -> [{ S2[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.c @@ -0,0 +1,11 @@ +{ + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S1(c0, c1); + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c0, c1); + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S3(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.st @@ -0,0 +1,26 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S3[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M }" +child: + context: "[M] -> { [] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S3[i0, i1] }" + child: + schedule: "[M] -> [{ S3[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S3[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 0; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S1(c0, c1); + for (int c0 = 0; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c1, c0); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.st @@ -0,0 +1,19 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 0 and i1 <= M }" +child: + context: "[M] -> { [] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.c @@ -0,0 +1,19 @@ +if (M >= 0 && N >= 0) + for (int c0 = -4; c0 <= 3 * M + N; c0 += 1) { + if (c0 >= 3 * M) { + S2(M, -3 * M + c0); + } else if (3 * M >= c0 + 4 && (c0 + 1) % 3 == 0) { + S1((c0 + 4) / 3, 0); + } + for (int c1 = max(-3 * M + c0 + 3, (c0 + 6) % 3); c1 <= min(N - 1, c0); c1 += 3) { + S2((c0 - c1) / 3, c1); + S1(((c0 - c1) / 3) + 1, c1 + 1); + } + if (3 * M + N >= c0 + 3 && c0 >= N && (N - c0) % 3 == 0) { + S2((-N + c0) / 3, N); + } else if (N >= c0 + 4 && c0 >= -3) { + S1(0, c0 + 4); + } + for (int c1 = max(-3 * M + c0, (c0 + 6) % 3); c1 <= min(N, c0); c1 += 3) + S3((c0 - c1) / 3, c1); + } Index: contrib/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.st @@ -0,0 +1,16 @@ +domain: "[M, N] -> { S3[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= N; S1[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= N; S2[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= N }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(-4 + 3i0 + i1)]; S2[i0, i1] -> [(3i0 + i1)]; S3[i0, i1] -> [(3i0 + i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1]; S2[i0, i1] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S3[i0, i1] }" + child: + schedule: "[M, N] -> [{ S3[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-loechner3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-loechner3.c @@ -0,0 +1,4 @@ +for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 2; c1 <= M + c0; c1 += 1) + for (int c2 = max(1, -c0 + c1); c2 <= min(M, c1 - 1); c2 += 1) + S1(c0, c2, c1 - c2); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-loechner3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-loechner3.st @@ -0,0 +1,12 @@ +domain: "[M] -> { S1[i0, i1, i2] : i0 <= M and i1 >= 1 and i1 <= M and i2 >= 1 and i2 <= i0 }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i1 + i2)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-loechner4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-loechner4.c @@ -0,0 +1,5 @@ +for (int c0 = 2; c0 <= 2 * M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + for (int c2 = 1; c2 <= M; c2 += 1) + for (int c3 = max(1, -M + c0); c3 <= min(M, c0 - 1); c3 += 1) + S1(c2, c1, c3, c0 - c3); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-loechner4.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-loechner4.st @@ -0,0 +1,15 @@ +domain: "[M] -> { S1[i0, i1, i2, i3] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M and i2 >= 1 and i2 <= M and i3 >= 1 and i3 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i2 + i3)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-loechner5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-loechner5.c @@ -0,0 +1,5 @@ +for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + for (int c2 = 1; c2 <= M; c2 += 1) + for (int c3 = 1; c3 <= M; c3 += 1) + S1(c1, c2, c0, c3); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-loechner5.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-loechner5.st @@ -0,0 +1,15 @@ +domain: "[M] -> { S1[i0, i1, i2, i3] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M and i2 >= 1 and i2 <= M and i3 >= 1 and i3 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i3)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-long.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-long.c @@ -0,0 +1,14 @@ +for (int c0 = 1; c0 < O; c0 += 1) { + for (int c1 = Q; c1 < N; c1 += 1) { + for (int c2 = P; c2 < M; c2 += 1) + S1(c0, c1, c2); + for (int c2 = 1; c2 < M; c2 += 1) + S2(c0, c1, c2); + } + for (int c1 = 1; c1 < N; c1 += 1) { + for (int c2 = P; c2 < M; c2 += 1) + S3(c0, c1, c2); + for (int c2 = 1; c2 < M; c2 += 1) + S4(c0, c1, c2); + } +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-long.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-long.st @@ -0,0 +1,36 @@ +domain: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S3[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S4[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M }" +child: + context: "[M, N, O, P, Q, R, S, T, U] -> { [] : M >= 10 and N >= 10 and O >= 10 and P >= 1 and P <= 2 and Q >= 1 and Q <= 2 and R >= 1 and R <= 2 and S >= 0 and S <= 1 and T >= 0 and T <= 1 and U >= 0 and U <= 1 }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2]; S2[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i1)]; S1[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S2[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S3[i0, i1, i2]; S4[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i1)]; S3[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S3[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S4[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-interp.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-interp.c @@ -0,0 +1,85 @@ +{ + if (N >= 2) + for (int c0 = 1; c0 < O; c0 += 1) { + for (int c3 = 1; c3 <= M; c3 += 1) + S1(c0, 1, c3); + for (int c3 = 1; c3 < M; c3 += 1) { + S6(c0, 1, c3); + S7(c0, 1, c3); + } + if (N >= 3) { + for (int c3 = 1; c3 <= M; c3 += 1) + S3(c0, 1, c3); + for (int c3 = 1; c3 <= M; c3 += 1) + S1(c0, 2, c3); + for (int c3 = 1; c3 < M; c3 += 1) { + S6(c0, 2, c3); + S7(c0, 2, c3); + } + for (int c3 = 1; c3 < M; c3 += 1) + S11(c0, 1, c3); + } else { + for (int c3 = 1; c3 <= M; c3 += 1) + S3(c0, 1, c3); + for (int c3 = 1; c3 < M; c3 += 1) + S11(c0, 1, c3); + } + for (int c1 = 3; c1 < 2 * N - 4; c1 += 2) { + for (int c3 = 1; c3 < M; c3 += 1) + S10(c0, (c1 - 1) / 2, c3); + for (int c3 = 1; c3 <= M; c3 += 1) + S3(c0, (c1 + 1) / 2, c3); + for (int c3 = 1; c3 <= M; c3 += 1) + S1(c0, (c1 + 3) / 2, c3); + for (int c3 = 1; c3 < M; c3 += 1) { + S6(c0, (c1 + 3) / 2, c3); + S7(c0, (c1 + 3) / 2, c3); + } + for (int c3 = 1; c3 < M; c3 += 1) + S11(c0, (c1 + 1) / 2, c3); + } + if (N >= 3) { + for (int c3 = 1; c3 < M; c3 += 1) + S10(c0, N - 2, c3); + for (int c3 = 1; c3 <= M; c3 += 1) + S3(c0, N - 1, c3); + for (int c3 = 1; c3 < M; c3 += 1) + S11(c0, N - 1, c3); + } + for (int c3 = 1; c3 < M; c3 += 1) + S10(c0, N - 1, c3); + } + for (int c0 = 1; c0 < O; c0 += 1) + for (int c1 = 1; c1 < N; c1 += 1) { + for (int c3 = 1; c3 <= M; c3 += 1) + S2(c0, c1, c3); + for (int c3 = 1; c3 < M; c3 += 1) + S8(c0, c1, c3); + for (int c3 = 1; c3 < M; c3 += 1) + S9(c0, c1, c3); + } + for (int c0 = 1; c0 < O; c0 += 1) + for (int c1 = 1; c1 < N; c1 += 1) + for (int c2 = 1; c2 < M; c2 += 1) + S4(c0, c1, c2); + for (int c0 = 1; c0 < O; c0 += 1) + for (int c1 = 1; c1 < N; c1 += 1) + for (int c2 = 1; c2 < M; c2 += 1) + S5(c0, c1, c2); + for (int c0 = R; c0 < O; c0 += 1) + for (int c1 = Q; c1 < N; c1 += 1) + for (int c2 = P; c2 < M; c2 += 1) + S12(c0, c1, c2); + for (int c0 = R; c0 < O; c0 += 1) + for (int c1 = Q; c1 < N; c1 += 1) + for (int c2 = 1; c2 < M; c2 += 1) + S13(c0, c1, c2); + for (int c0 = R; c0 < O; c0 += 1) + for (int c1 = 1; c1 < N; c1 += 1) + for (int c2 = P; c2 < M; c2 += 1) + S14(c0, c1, c2); + for (int c0 = R; c0 < O; c0 += 1) + for (int c1 = 1; c1 < N; c1 += 1) + for (int c2 = 1; c2 < M; c2 += 1) + S15(c0, c1, c2); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-interp.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-interp.st @@ -0,0 +1,115 @@ +domain: "[M, N, O, P, Q, R, S, T, U] -> { S8[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S12[i0, i1, i2] : i0 >= R and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S5[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S10[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S6[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S1[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S3[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S4[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S15[i0, i1, i2] : i0 >= R and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S11[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S7[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S9[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S14[i0, i1, i2] : i0 >= R and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S13[i0, i1, i2] : i0 >= R and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M }" +child: + context: "[M, N, O, P, Q, R, S, T, U] -> { [] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S10[i0, i1, i2]; S6[i0, i1, i2]; S3[i0, i1, i2]; S1[i0, i1, i2]; S11[i0, i1, i2]; S7[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S11[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)]; S6[i0, i1, i2] -> [(i0)]; S10[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)]; S7[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S11[i0, i1, i2] -> [(2i1)]; S1[i0, i1, i2] -> [(-3 + 2i1)]; S6[i0, i1, i2] -> [(-2 + 2i1)]; S10[i0, i1, i2] -> [(1 + 2i1)]; S3[i0, i1, i2] -> [(-1 + 2i1)]; S7[i0, i1, i2] -> [(-2 + 2i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S10[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S10[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S3[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S6[i0, i1, i2]; S1[i0, i1, i2]; S7[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i2)]; S6[i0, i1, i2] -> [(i2)]; S7[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S6[i0, i1, i2]; S1[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S7[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S11[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S11[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S2[i0, i1, i2]; S9[i0, i1, i2]; S8[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i0)]; S8[i0, i1, i2] -> [(i0)]; S9[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(2i1)]; S8[i0, i1, i2] -> [(2i1)]; S9[i0, i1, i2] -> [(1 + 2i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S2[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S8[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S8[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S9[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S9[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S4[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S5[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S5[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S5[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S5[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S12[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S12[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S12[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S12[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S13[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S13[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S13[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S13[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S14[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S14[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S14[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S14[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S15[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S15[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S15[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S15[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.c @@ -0,0 +1,18 @@ +{ + for (int c0 = 1; c0 < O; c0 += 1) + for (int c1 = Q; c1 < N; c1 += 1) + for (int c2 = P; c2 < M; c2 += 1) + S1(c0, c1, c2); + for (int c0 = 1; c0 < O; c0 += 1) + for (int c1 = Q; c1 < N; c1 += 1) + for (int c2 = 1; c2 < M; c2 += 1) + S2(c0, c1, c2); + for (int c0 = 1; c0 < O; c0 += 1) + for (int c1 = 1; c1 < N; c1 += 1) + for (int c2 = P; c2 < M; c2 += 1) + S3(c0, c1, c2); + for (int c0 = 1; c0 < O; c0 += 1) + for (int c1 = 1; c1 < N; c1 += 1) + for (int c2 = 1; c2 < M; c2 += 1) + S4(c0, c1, c2); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.st @@ -0,0 +1,45 @@ +domain: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S3[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S4[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M }" +child: + context: "[M, N, O, P, Q, R, S, T, U] -> { [] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S2[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S3[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R, S, T, U] -> { S4[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.c @@ -0,0 +1,9 @@ +for (int c0 = 2; c0 < O; c0 += 1) + for (int c1 = 3; c1 < 2 * N - 2; c1 += 2) { + for (int c3 = 1; c3 <= M; c3 += 1) { + S1(c0, (c1 + 1) / 2, c3); + S2(c0, (c1 + 1) / 2, c3); + } + for (int c3 = 2; c3 < M; c3 += 1) + S3(c0, (c1 + 1) / 2, c3); + } Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.st @@ -0,0 +1,23 @@ +domain: "[M, N, O] -> { S3[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S1[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 1 and i2 <= M }" +child: + context: "[M, N, O] -> { [] }" + child: + schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O] -> { separate[i0] }" + child: + schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(2i1)]; S2[i0, i1, i2] -> [(-1 + 2i1)]; S1[i0, i1, i2] -> [(-1 + 2i1)] }]" + options: "[M, N, O] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O] -> { S2[i0, i1, i2]; S1[i0, i1, i2] }" + child: + schedule: "[M, N, O] -> [{ S2[i0, i1, i2] -> [(i2)]; S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O] -> { S1[i0, i1, i2] }" + - filter: "[M, N, O] -> { S2[i0, i1, i2] }" + - filter: "[M, N, O] -> { S3[i0, i1, i2] }" + child: + schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-resid.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-resid.c @@ -0,0 +1,9 @@ +for (int c0 = 2; c0 < O; c0 += 1) + for (int c1 = 3; c1 < 2 * N - 2; c1 += 2) { + for (int c3 = 1; c3 <= M; c3 += 1) { + S1(c0, (c1 + 1) / 2, c3); + S2(c0, (c1 + 1) / 2, c3); + } + for (int c3 = 2; c3 < M; c3 += 1) + S3(c0, (c1 + 1) / 2, c3); + } Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-resid.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-resid.st @@ -0,0 +1,23 @@ +domain: "[M, N, O] -> { S3[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S1[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 1 and i2 <= M }" +child: + context: "[M, N, O] -> { [] }" + child: + schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O] -> { separate[i0] }" + child: + schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(2i1)]; S2[i0, i1, i2] -> [(-1 + 2i1)]; S1[i0, i1, i2] -> [(-1 + 2i1)] }]" + options: "[M, N, O] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O] -> { S2[i0, i1, i2]; S1[i0, i1, i2] }" + child: + schedule: "[M, N, O] -> [{ S2[i0, i1, i2] -> [(i2)]; S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O] -> { S1[i0, i1, i2] }" + - filter: "[M, N, O] -> { S2[i0, i1, i2] }" + - filter: "[M, N, O] -> { S3[i0, i1, i2] }" + child: + schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.c @@ -0,0 +1,35 @@ +if (M >= 2 && N >= 3) + for (int c0 = 2; c0 < O; c0 += 1) { + for (int c2 = 2; c2 <= M; c2 += 1) + S1(c0, 2, c2); + for (int c1 = 3; c1 < N; c1 += 1) { + for (int c2 = 2; c2 <= M; c2 += 1) + S2(c0, c1 - 1, c2); + if (M >= 3) + S4(c0, c1 - 1, 2); + for (int c2 = 2; c2 < M - 1; c2 += 1) { + S3(c0, c1 - 1, c2); + S5(c0, c1 - 1, c2); + S4(c0, c1 - 1, c2 + 1); + } + if (M >= 3) { + S3(c0, c1 - 1, M - 1); + S5(c0, c1 - 1, M - 1); + } + for (int c2 = 2; c2 <= M; c2 += 1) + S1(c0, c1, c2); + } + for (int c2 = 2; c2 <= M; c2 += 1) + S2(c0, N - 1, c2); + if (M >= 3) + S4(c0, N - 1, 2); + for (int c2 = 2; c2 < M - 1; c2 += 1) { + S3(c0, N - 1, c2); + S5(c0, N - 1, c2); + S4(c0, N - 1, c2 + 1); + } + if (M >= 3) { + S3(c0, N - 1, M - 1); + S5(c0, N - 1, M - 1); + } + } Index: contrib/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.st @@ -0,0 +1,28 @@ +domain: "[M, N, O, P, Q, R] -> { S2[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= M; S4[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M; S1[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= M; S5[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M; S3[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M }" +child: + context: "[M, N, O, P, Q, R] -> { [] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S5[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)]; S4[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S5[i0, i1, i2] -> [(1 + i1)]; S3[i0, i1, i2] -> [(1 + i1)]; S4[i0, i1, i2] -> [(1 + i1)]; S1[i0, i1, i2] -> [(i1)]; S2[i0, i1, i2] -> [(1 + i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S2[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S2[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S4[i0, i1, i2]; S5[i0, i1, i2]; S3[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S5[i0, i1, i2] -> [(i2)]; S3[i0, i1, i2] -> [(i2)]; S4[i0, i1, i2] -> [(-1 + i2)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S3[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S5[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S4[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S1[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali1.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 < 2 * N; c1 += 1) { + for (int c2 = max(1, -N + c1); c2 < (c1 + 1) / 2; c2 += 1) + S1(c0, c1 - c2, c2); + if ((c1 + 1) % 2 == 0) + S2(c0, (c1 + 1) / 2); + } Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali1.st @@ -0,0 +1,16 @@ +domain: "[M, N] -> { S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= N; S1[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 <= N and i2 >= 1 and i2 <= -1 + i1 }" +child: + context: "[M, N] -> { [] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0)]; S1[i0, i1, i2] -> [(i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(-1 + 2i1)]; S1[i0, i1, i2] -> [(i1 + i2)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1, i2] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali2.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S1(c0, c1); + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali2.st @@ -0,0 +1,19 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M }" +child: + context: "[M] -> { [] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali3.c @@ -0,0 +1,9 @@ +{ + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S1(c0, c1); + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + for (int c2 = 1; c2 <= M; c2 += 1) + S2(c0, c1, c2); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali3.st @@ -0,0 +1,22 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M and i2 >= 1 and i2 <= M }" +child: + context: "[M] -> { [] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1, i2] }" + child: + schedule: "[M] -> [{ S2[i0, i1, i2] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S2[i0, i1, i2] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S2[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali4.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S1(c0, c1); + for (int c0 = 1; c0 <= M; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali4.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali4.st @@ -0,0 +1,19 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M }" +child: + context: "[M] -> { [] : M >= 2 }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali5.c @@ -0,0 +1,10 @@ +for (int c0 = 3; c0 < 2 * M; c0 += 1) { + for (int c1 = c0 / 2 + 2; c1 <= M; c1 += 1) + for (int c3 = c0 / 2 + 1; c3 < min(c0, c1); c3 += 1) + S1(c3, c0 - c3, c1); + for (int c1 = max(1, -M + c0); c1 < (c0 + 1) / 2; c1 += 1) + S2(c0 - c1, c1); + for (int c1 = c0 / 2 + 2; c1 <= M; c1 += 1) + for (int c3 = c0 / 2 + 1; c3 < min(c0, c1); c3 += 1) + S3(c3, c0 - c3, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali5.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali5.st @@ -0,0 +1,26 @@ +domain: "[M] -> { S3[i0, i1, i2] : i1 >= 1 and i1 <= -1 + i0 and i2 >= 1 + i0 and i2 <= M; S2[i0, i1] : i0 <= M and i1 >= 1 and i1 <= -1 + i0; S1[i0, i1, i2] : i1 >= 1 and i1 <= -1 + i0 and i2 >= 1 + i0 and i2 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0 + i1)]; S3[i0, i1, i2] -> [(i0 + i1)]; S2[i0, i1] -> [(i0 + i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1, i2] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S2[i0, i1] }" + child: + schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + - filter: "[M] -> { S3[i0, i1, i2] }" + child: + schedule: "[M] -> [{ S3[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" + child: + schedule: "[M] -> [{ S3[i0, i1, i2] -> [(i2)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali6.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali6.c @@ -0,0 +1,8 @@ +for (int c0 = 1; c0 <= M; c0 += 1) { + for (int c2 = 2; c2 < N; c2 += 1) + for (int c3 = 2; c3 < N; c3 += 1) + S1(c0, c2, c3); + for (int c2 = 2; c2 < N; c2 += 1) + for (int c3 = 2; c3 < N; c3 += 1) + S2(c0, c2, c3); +} Index: contrib/isl/test_inputs/codegen/cloog/reservoir-pingali6.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-pingali6.st @@ -0,0 +1,22 @@ +domain: "[M, N] -> { S2[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + N; S1[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + N }" +child: + context: "[M, N] -> { [] : M >= 1 and N >= 1 }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(2i0)]; S2[i0, i1, i2] -> [(1 + 2i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1, i2] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" + - filter: "[M, N] -> { S2[i0, i1, i2] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1, i2] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1, i2] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-stride.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-stride.c @@ -0,0 +1,2 @@ +for (int c0 = 2; c0 <= M; c0 += 7) + S1(c0, (c0 - 2) / 7); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-stride.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-stride.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0, i1] : 7i1 = -2 + i0 and i0 >= 2 and i0 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-stride2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-stride2.c @@ -0,0 +1,2 @@ +for (int c0 = 2; c0 <= M; c0 += 7) + S1(c0, (c0 - 2) / 7); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-stride2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-stride2.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0, i1] : 7i1 = -2 + i0 and i0 >= 0 and i0 <= M }" +child: + context: "[M] -> { [] }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.c @@ -0,0 +1,5 @@ +for (int c0 = 0; c0 <= 9; c0 += 2) + for (int c1 = 0; c1 <= min(4, c0 + 3); c1 += 2) + for (int c2 = max(1, c0); c2 <= min(c0 + 1, c0 - c1 + 4); c2 += 1) + for (int c3 = max(1, -c0 + c1 + c2); c3 <= min(4, -c0 + c1 + c2 + 1); c3 += 1) + S1(c0 / 2, (-c0 + c1) / 2, -c0 + c2, -c1 + c3); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.st @@ -0,0 +1,15 @@ +domain: "{ S1[i0, i1, i2, i3] : i3 <= 4 - 2i0 - 2i1 and i3 >= i2 and i2 <= 9 - 2i0 and i2 >= 0 and i2 >= 1 - 2i0 and i3 <= 1 + i2 and i2 <= 1 and i3 >= 1 - 2i0 - 2i1 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1, i2, i3] -> [(2i0)] }]" + options: "{ separate[i0] }" + child: + schedule: "[{ S1[i0, i1, i2, i3] -> [(2i0 + 2i1)] }]" + options: "{ separate[i0] }" + child: + schedule: "[{ S1[i0, i1, i2, i3] -> [(2i0 + i2)] }]" + options: "{ separate[i0] }" + child: + schedule: "[{ S1[i0, i1, i2, i3] -> [(2i0 + 2i1 + i3)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/reservoir-two.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-two.c @@ -0,0 +1 @@ +S1(1, 1, 5); Index: contrib/isl/test_inputs/codegen/cloog/reservoir-two.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/reservoir-two.st @@ -0,0 +1,6 @@ +domain: "{ S1[i0, i1, i2] : 2i1 = 3 - i0 and 2i2 = 9 + i0 and i0 >= 0 and i0 <= 1 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/singleton.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/singleton.c @@ -0,0 +1,4 @@ +{ + S2(); + S1(); +} Index: contrib/isl/test_inputs/codegen/cloog/singleton.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/singleton.st @@ -0,0 +1,7 @@ +domain: "{ S1[]; S2[] }" +child: + context: "{ [] }" + child: + sequence: + - filter: "{ S2[] }" + - filter: "{ S1[] }" Index: contrib/isl/test_inputs/codegen/cloog/sor1d.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/sor1d.c @@ -0,0 +1,13 @@ +if (M >= 1 && N >= 3) + for (int c0 = -1; c0 <= (3 * M + N - 5) / 100; c0 += 1) { + for (int c1 = max(max(0, c0 - (2 * M + N + 95) / 100 + 1), floord(-N + 100 * c0 + 106, 300)); c1 <= min(min(c0, M / 100), (c0 + 1) / 3); c1 += 1) + for (int c2 = max(200 * c1 - 3, 100 * c0 - 100 * c1); c2 <= min(min(2 * M + N - 5, 100 * c0 - 100 * c1 + 99), N + 200 * c1 + 193); c2 += 1) { + if (c1 >= 1 && N + 200 * c1 >= c2 + 7) + S3(c0 - c1, c1 - 1, c1, 100 * c1 - 1, -200 * c1 + c2 + 6); + for (int c3 = max(max(1, 100 * c1), -N + (N + c2) / 2 + 3); c3 <= min(min(M, 100 * c1 + 99), c2 / 2 + 1); c3 += 1) + S1(c0 - c1, c1, c3, c2 - 2 * c3 + 4); + if (M >= 100 * c1 + 100 && c2 >= 200 * c1 + 197) + S2(c0 - c1, c1, c1 + 1, 100 * c1 + 99, -200 * c1 + c2 - 194); + } + S4(c0); + } Index: contrib/isl/test_inputs/codegen/cloog/sor1d.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/sor1d.st @@ -0,0 +1,24 @@ +domain: "[M, N] -> { S2[i0, i1, 1 + i1, 99 + 100i1, i4] : i4 >= 3 and i4 >= -193 - 200i1 and i4 >= -194 + 100i0 - 200i1 and 100i0 >= -284 - 3N and i4 <= -1 + N and i4 <= -201 + 2M + N - 200i1 and i4 <= -95 + 100i0 - 200i1 and 100i0 >= -94 - N and 50i0 >= -45 - N and 3N >= -134 - M and i1 >= 0 and N >= 4 and 200i1 >= -192 - N and 200i1 >= -193 - N + 100i0 and 100i0 <= -7 + 2M + N and 7N >= -463 - 2M and 100i1 <= -100 + M and i0 >= 0 and 200i1 <= -204 + 2M + N and 2i1 <= -1 + i0 and 5N >= -75 - 2M and N >= 8 - 2M and 50i0 <= -6 + M + N and 50i0 <= 89 + M + 2N and 100i0 <= -15 + 2M + 3N and M >= 2 and 100i1 <= -5 + M + N and 2N >= -39 - M and 200i1 <= 96 + N + 100i0 and 3N >= 16 - 2M and 100i1 >= -94 - N + 50i0 and N >= 6 - M and 100i1 >= -94 - N; S3[i0, i1, 1 + i1, 99 + 100i1, i4] : i4 >= 3 and i4 >= -193 - 200i1 and i4 >= -194 + 100i0 - 200i1 and 100i0 >= -284 - 3N and i4 <= -1 + N and i4 <= -201 + 2M + N - 200i1 and i4 <= -95 + 100i0 - 200i1 and 100i0 >= -94 - N and 50i0 >= -45 - N and 3N >= -134 - M and i1 >= 0 and N >= 4 and 200i1 >= -192 - N and 200i1 >= -193 - N + 100i0 and 100i0 <= -7 + 2M + N and 7N >= -463 - 2M and 100i1 <= -100 + M and i0 >= 0 and 200i1 <= -204 + 2M + N and 2i1 <= -1 + i0 and 5N >= -75 - 2M and N >= 8 - 2M and 50i0 <= -6 + M + N and 50i0 <= 89 + M + 2N and 100i0 <= -15 + 2M + 3N and M >= 2 and 100i1 <= -5 + M + N and 2N >= -39 - M and 200i1 <= 96 + N + 100i0 and 3N >= 16 - 2M and 100i1 >= -94 - N + 50i0 and N >= 6 - M and 100i1 >= -94 - N; S4[i0] : 200i0 >= -781 - 3N and 200i0 >= -391 - N and 50i0 >= -268 - N and 100i0 >= -392 - N and i0 >= -1 and 200i0 <= 377 + 6M + 5N and 100i0 <= 335 + 3M + 3N and 100i0 <= 190 + 3M + 2N and 200i0 <= -13 + 6M + 3N and 100i0 <= -5 + 3M + N and 3N >= -484 - 2M and N >= -95 - M and N >= -192 - 3M and 5N >= -873 - 3M and 2N >= -189 - 3M and 7N >= -1062 - 6M and 5N >= -771 - 6M and 4N >= -579 - 3M and N >= 3 and N >= 5 - 2M and M >= 1; S1[i0, i1, i2, i3] : i3 >= 4 + 100i0 - 2i2 and i3 >= 2 and i3 <= 103 + 100i0 - 2i2 and i3 <= -1 + N and i2 >= 1 and i2 >= 100i1 and 2i2 >= 5 - N + 100i0 and i2 <= M and i2 <= 99 + 100i1 and i2 <= 50 + 50i0 and i1 >= 0 and 200i1 >= -193 - N + 100i0 and 100i1 <= M and 2i1 <= 1 + i0 and i0 >= 0 and 100i0 <= -5 + 2M + N and N >= 3 and N >= -94 - 2M and M >= 1 }" +child: + context: "[M, N] -> { [] : M >= 0 and N >= 0 }" + child: + schedule: "[M, N] -> [{ S2[i0, i1, i2, i3, i4] -> [(i0 + i1)]; S1[i0, i1, i2, i3] -> [(i0 + i1)]; S3[i0, i1, i2, i3, i4] -> [(1 + i0 + i1)]; S4[i0] -> [(i0)] }]" + options: "[M, N] -> { atomic[i0] }" + child: + sequence: + - filter: "[M, N] -> { S2[i0, i1, i2, i3, i4]; S3[i0, i1, i2, i3, i4]; S1[i0, i1, i2, i3] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1, i2, i3, i4] -> [(i1)]; S1[i0, i1, i2, i3] -> [(i1)]; S3[i0, i1, i2, i3, i4] -> [(i2)] }, { S2[i0, i1, i2, i3, i4] -> [(-4 + 2i3 + i4)]; S1[i0, i1, i2, i3] -> [(-4 + 2i2 + i3)]; S3[i0, i1, i2, i3, i4] -> [(-4 + 2i3 + i4)] }, { S2[i0, i1, i2, i3, i4] -> [(i3)]; S1[i0, i1, i2, i3] -> [(i2)]; S3[i0, i1, i2, i3, i4] -> [(i3)] }]" + options: "[M, N] -> { atomic[i0] }" + child: + sequence: + - filter: "[M, N] -> { S3[i0, i1, i2, i3, i4] }" + child: + schedule: "[M, N] -> [{ S3[i0, i1, i2, i3, i4] -> [(i1)] }, { S3[i0, i1, i2, i3, i4] -> [(i4)] }]" + options: "[M, N] -> { atomic[i0] }" + - filter: "[M, N] -> { S1[i0, i1, i2, i3] }" + - filter: "[M, N] -> { S2[i0, i1, i2, i3, i4] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1, i2, i3, i4] -> [(i2)] }, { S2[i0, i1, i2, i3, i4] -> [(i4)] }]" + options: "[M, N] -> { atomic[i0] }" + - filter: "[M, N] -> { S4[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.c @@ -0,0 +1,9 @@ +for (int c0 = 1; c0 <= M; c0 += 1) { + S1(c0, 1); + for (int c1 = 2; c1 <= c0; c1 += 1) { + S1(c0, c1); + S2(c0, c1); + } + for (int c1 = c0 + 1; c1 <= M; c1 += 1) + S1(c0, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.st @@ -0,0 +1,10 @@ +domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i1 >= 2 and i1 <= i0 and i0 <= M }" +child: + context: "[M] -> { [] : M >= 1 }" + child: + schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M] -> { separate[i0] }" + child: + sequence: + - filter: "[M] -> { S1[i0, i1] }" + - filter: "[M] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/stride.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/stride.c @@ -0,0 +1,7 @@ +{ + for (int c0 = 3; c0 <= 24; c0 += 3) + S2(c0, c0 / 3); + S1(25); + for (int c0 = 27; c0 <= 100; c0 += 3) + S2(c0, c0 / 3); +} Index: contrib/isl/test_inputs/codegen/cloog/stride.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/stride.st @@ -0,0 +1,6 @@ +domain: "{ S2[i0, i1] : 3i1 = i0 and i0 >= 3 and i0 <= 100; S1[25] }" +child: + context: "{ [] }" + child: + schedule: "[{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/stride2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/stride2.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 3; c0 <= 26; c0 += 3) + S2(c0, c0 / 3); + S1(27); + S2(27, 9); + for (int c0 = 30; c0 <= 100; c0 += 3) + S2(c0, c0 / 3); +} Index: contrib/isl/test_inputs/codegen/cloog/stride2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/stride2.st @@ -0,0 +1,6 @@ +domain: "{ S2[i0, i1] : 3i1 = i0 and i0 >= 3 and i0 <= 100; S1[27] }" +child: + context: "{ [] }" + child: + schedule: "[{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]" + options: "{ separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/stride3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/stride3.c @@ -0,0 +1,2 @@ +for (int c0 = max(1, m); c0 <= n; c0 += 1) + S1(c0); Index: contrib/isl/test_inputs/codegen/cloog/stride3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/stride3.st @@ -0,0 +1,6 @@ +domain: "[m, n] -> { S1[i] : i >= 1 and i <= n and i >= m }" +child: + context: "[m, n] -> { [] }" + child: + schedule: "[m, n] -> [{ S1[i0] -> [(50i0)] }]" + options: "[m, n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/stride4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/stride4.c @@ -0,0 +1,3 @@ +if (t >= 0 && t <= 15) + for (int c0 = t; c0 <= 99; c0 += 16) + S1(c0, t); Index: contrib/isl/test_inputs/codegen/cloog/stride4.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/stride4.st @@ -0,0 +1,6 @@ +domain: "[t] -> { S1[i0, t] : exists (e0 = floor((t - i0)/16): 16e0 = t - i0 and i0 >= 0 and i0 <= 99 and t >= 0 and t <= 15) }" +child: + context: "[t] -> { [] }" + child: + schedule: "[t] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]" + options: "[t] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/swim.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/swim.c @@ -0,0 +1,159 @@ +if (M == 1) { + S1(); + S2(); + S3(); + S4(); + S5(); + S6(); + S7(); + S8(); + S9(); + S10(); + S11(); + S12(); + S13(); + S14(); + S15(); + S16(); + S17(); + S18(); + S19(); + S20(); + S21(); + S22(); + S23(); + S24(); + S25(); + S26(); + S27(); + for (int c0 = 1; c0 <= N; c0 += 1) { + for (int c1 = 1; c1 <= N; c1 += 1) { + S28(c0, c1); + S29(c0, c1); + S30(c0, c1); + } + S31(c0); + } + S32(); + S33(); + S34(); + if (O <= 1) + S35(); + S36(); + S37(); + for (int c0 = 2; c0 <= P; c0 += 1) { + S38(c0); + S39(c0); + for (int c1 = 1; c1 <= Q; c1 += 1) + for (int c2 = 1; c2 <= R; c2 += 1) { + S40(c0, c1, c2); + S41(c0, c1, c2); + S42(c0, c1, c2); + S43(c0, c1, c2); + } + for (int c1 = 1; c1 <= Q; c1 += 1) { + S44(c0, c1); + S45(c0, c1); + S46(c0, c1); + S47(c0, c1); + } + for (int c1 = 1; c1 <= R; c1 += 1) { + S48(c0, c1); + S49(c0, c1); + S50(c0, c1); + S51(c0, c1); + } + S52(c0); + S53(c0); + S54(c0); + S55(c0); + S56(c0); + S57(c0); + S58(c0); + for (int c1 = 1; c1 <= Q; c1 += 1) + for (int c2 = 1; c2 <= R; c2 += 1) { + S59(c0, c1, c2); + S60(c0, c1, c2); + S61(c0, c1, c2); + } + for (int c1 = 1; c1 <= Q; c1 += 1) { + S62(c0, c1); + S63(c0, c1); + S64(c0, c1); + } + for (int c1 = 1; c1 <= R; c1 += 1) { + S65(c0, c1); + S66(c0, c1); + S67(c0, c1); + } + S68(c0); + S69(c0); + S70(c0); + S71(c0); + S72(c0); + S73(c0); + S74(c0); + S75(c0); + S76(c0); + S77(c0); + S78(c0); + S79(c0); + S80(c0); + S81(c0); + S82(c0); + S83(c0); + S84(c0); + S85(c0); + S86(c0); + S87(c0); + S88(c0); + S89(c0); + S90(c0); + S91(c0); + S92(c0); + S93(c0); + S94(c0); + for (int c1 = 1; c1 <= N; c1 += 1) { + for (int c2 = 1; c2 <= N; c2 += 1) { + S95(c0, c1, c2); + S96(c0, c1, c2); + S97(c0, c1, c2); + } + S98(c0, c1); + } + S99(c0); + S100(c0); + S101(c0); + for (int c1 = 1; c1 <= Q; c1 += 1) + for (int c2 = 1; c2 <= R; c2 += 1) { + S102(c0, c1, c2); + S103(c0, c1, c2); + S104(c0, c1, c2); + S105(c0, c1, c2); + S106(c0, c1, c2); + S107(c0, c1, c2); + } + for (int c1 = 1; c1 <= Q; c1 += 1) { + S108(c0, c1); + S109(c0, c1); + S110(c0, c1); + S111(c0, c1); + S112(c0, c1); + S113(c0, c1); + } + for (int c1 = 1; c1 <= R; c1 += 1) { + S114(c0, c1); + S115(c0, c1); + S116(c0, c1); + S117(c0, c1); + S118(c0, c1); + S119(c0, c1); + } + S120(c0); + S121(c0); + S122(c0); + S123(c0); + S124(c0); + S125(c0); + } +} Index: contrib/isl/test_inputs/codegen/cloog/swim.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/swim.st @@ -0,0 +1,223 @@ +domain: "[M, N, O, P, Q, R] -> { S40[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S106[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S99[i0] : M = 1 and i0 >= 2 and i0 <= P; S83[i0] : M = 1 and i0 >= 2 and i0 <= P; S86[i0] : M = 1 and i0 >= 2 and i0 <= P; S56[i0] : M = 1 and i0 >= 2 and i0 <= P; S124[i0] : M = 1 and i0 >= 2 and i0 <= P; S66[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S46[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S64[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S22[] : M = 1; S15[] : M = 1; S30[i0, i1] : M = 1 and i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= N; S14[] : M = 1; S12[] : M = 1; S87[i0] : M = 1 and i0 >= 2 and i0 <= P; S110[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S73[i0] : M = 1 and i0 >= 2 and i0 <= P; S44[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S31[i0] : M = 1 and i0 >= 1 and i0 <= N; S118[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S8[] : M = 1; S125[i0] : M = 1 and i0 >= 2 and i0 <= P; S63[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S25[] : M = 1; S51[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S91[i0] : M = 1 and i0 >= 2 and i0 <= P; S84[i0] : M = 1 and i0 >= 2 and i0 <= P; S35[] : M = 1 and O <= 1; S97[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= N and i2 >= 1 and i2 <= N; S75[i0] : M = 1 and i0 >= 2 and i0 <= P; S19[] : M = 1; S50[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S114[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S13[] : M = 1; S72[i0] : M = 1 and i0 >= 2 and i0 <= P; S78[i0] : M = 1 and i0 >= 2 and i0 <= P; S39[i0] : M = 1 and i0 >= 2 and i0 <= P; S102[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S107[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S68[i0] : M = 1 and i0 >= 2 and i0 <= P; S32[] : M = 1; S41[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S69[i0] : M = 1 and i0 >= 2 and i0 <= P; S3[] : M = 1; S100[i0] : M = 1 and i0 >= 2 and i0 <= P; S11[] : M = 1; S76[i0] : M = 1 and i0 >= 2 and i0 <= P; S88[i0] : M = 1 and i0 >= 2 and i0 <= P; S49[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S45[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S10[] : M = 1; S80[i0] : M = 1 and i0 >= 2 and i0 <= P; S61[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S67[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S70[i0] : M = 1 and i0 >= 2 and i0 <= P; S29[i0, i1] : M = 1 and i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= N; S60[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S21[] : M = 1; S92[i0] : M = 1 and i0 >= 2 and i0 <= P; S47[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S24[] : M = 1; S16[] : M = 1; S105[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S18[] : M = 1; S48[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S5[] : M = 1; S113[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S7[] : M = 1; S38[i0] : M = 1 and i0 >= 2 and i0 <= P; S54[i0] : M = 1 and i0 >= 2 and i0 <= P; S109[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S23[] : M = 1; S82[i0] : M = 1 and i0 >= 2 and i0 <= P; S59[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S77[i0] : M = 1 and i0 >= 2 and i0 <= P; S101[i0] : M = 1 and i0 >= 2 and i0 <= P; S37[] : M = 1; S71[i0] : M = 1 and i0 >= 2 and i0 <= P; S121[i0] : M = 1 and i0 >= 2 and i0 <= P; S115[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S104[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S94[i0] : M = 1 and i0 >= 2 and i0 <= P; S6[] : M = 1; S43[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S1[] : M = 1; S98[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= N; S55[i0] : M = 1 and i0 >= 2 and i0 <= P; S58[i0] : M = 1 and i0 >= 2 and i0 <= P; S42[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S89[i0] : M = 1 and i0 >= 2 and i0 <= P; S53[i0] : M = 1 and i0 >= 2 and i0 <= P; S111[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S52[i0] : M = 1 and i0 >= 2 and i0 <= P; S85[i0] : M = 1 and i0 >= 2 and i0 <= P; S26[] : M = 1; S79[i0] : M = 1 and i0 >= 2 and i0 <= P; S81[i0] : M = 1 and i0 >= 2 and i0 <= P; S57[i0] : M = 1 and i0 >= 2 and i0 <= P; S4[] : M = 1; S123[i0] : M = 1 and i0 >= 2 and i0 <= P; S36[] : M = 1; S65[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S34[] : M = 1; S119[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S9[] : M = 1; S28[i0, i1] : M = 1 and i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= N; S20[] : M = 1; S117[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S112[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S103[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S17[] : M = 1; S96[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= N and i2 >= 1 and i2 <= N; S95[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= N and i2 >= 1 and i2 <= N; S62[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S90[i0] : M = 1 and i0 >= 2 and i0 <= P; S120[i0] : M = 1 and i0 >= 2 and i0 <= P; S116[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S108[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S74[i0] : M = 1 and i0 >= 2 and i0 <= P; S93[i0] : M = 1 and i0 >= 2 and i0 <= P; S2[] : M = 1; S27[] : M = 1; S122[i0] : M = 1 and i0 >= 2 and i0 <= P; S33[] : M = 1 }" +child: + context: "[M, N, O, P, Q, R] -> { [] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S1[] }" + - filter: "[M, N, O, P, Q, R] -> { S2[] }" + - filter: "[M, N, O, P, Q, R] -> { S3[] }" + - filter: "[M, N, O, P, Q, R] -> { S4[] }" + - filter: "[M, N, O, P, Q, R] -> { S5[] }" + - filter: "[M, N, O, P, Q, R] -> { S6[] }" + - filter: "[M, N, O, P, Q, R] -> { S7[] }" + - filter: "[M, N, O, P, Q, R] -> { S8[] }" + - filter: "[M, N, O, P, Q, R] -> { S9[] }" + - filter: "[M, N, O, P, Q, R] -> { S10[] }" + - filter: "[M, N, O, P, Q, R] -> { S11[] }" + - filter: "[M, N, O, P, Q, R] -> { S12[] }" + - filter: "[M, N, O, P, Q, R] -> { S13[] }" + - filter: "[M, N, O, P, Q, R] -> { S14[] }" + - filter: "[M, N, O, P, Q, R] -> { S15[] }" + - filter: "[M, N, O, P, Q, R] -> { S16[] }" + - filter: "[M, N, O, P, Q, R] -> { S17[] }" + - filter: "[M, N, O, P, Q, R] -> { S18[] }" + - filter: "[M, N, O, P, Q, R] -> { S19[] }" + - filter: "[M, N, O, P, Q, R] -> { S20[] }" + - filter: "[M, N, O, P, Q, R] -> { S21[] }" + - filter: "[M, N, O, P, Q, R] -> { S22[] }" + - filter: "[M, N, O, P, Q, R] -> { S23[] }" + - filter: "[M, N, O, P, Q, R] -> { S24[] }" + - filter: "[M, N, O, P, Q, R] -> { S25[] }" + - filter: "[M, N, O, P, Q, R] -> { S26[] }" + - filter: "[M, N, O, P, Q, R] -> { S27[] }" + - filter: "[M, N, O, P, Q, R] -> { S30[i0, i1]; S28[i0, i1]; S31[i0]; S29[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S31[i0] -> [(i0)]; S29[i0, i1] -> [(i0)]; S30[i0, i1] -> [(i0)]; S28[i0, i1] -> [(i0)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S30[i0, i1]; S28[i0, i1]; S29[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S29[i0, i1] -> [(i1)]; S30[i0, i1] -> [(i1)]; S28[i0, i1] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S28[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S29[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S30[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S31[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S32[] }" + - filter: "[M, N, O, P, Q, R] -> { S33[] }" + - filter: "[M, N, O, P, Q, R] -> { S34[] }" + - filter: "[M, N, O, P, Q, R] -> { S35[] }" + - filter: "[M, N, O, P, Q, R] -> { S36[] }" + - filter: "[M, N, O, P, Q, R] -> { S37[] }" + - filter: "[M, N, O, P, Q, R] -> { S58[i0]; S116[i0, i1]; S120[i0]; S106[i0, i1, i2]; S102[i0, i1, i2]; S114[i0, i1]; S113[i0, i1]; S122[i0]; S83[i0]; S103[i0, i1, i2]; S71[i0]; S50[i0, i1]; S98[i0, i1]; S65[i0, i1]; S82[i0]; S109[i0, i1]; S51[i0, i1]; S60[i0, i1, i2]; S91[i0]; S78[i0]; S101[i0]; S123[i0]; S111[i0, i1]; S97[i0, i1, i2]; S67[i0, i1]; S117[i0, i1]; S88[i0]; S79[i0]; S46[i0, i1]; S56[i0]; S45[i0, i1]; S74[i0]; S49[i0, i1]; S75[i0]; S115[i0, i1]; S119[i0, i1]; S42[i0, i1, i2]; S57[i0]; S62[i0, i1]; S99[i0]; S107[i0, i1, i2]; S100[i0]; S104[i0, i1, i2]; S70[i0]; S89[i0]; S125[i0]; S44[i0, i1]; S93[i0]; S90[i0]; S84[i0]; S105[i0, i1, i2]; S95[i0, i1, i2]; S66[i0, i1]; S77[i0]; S38[i0]; S41[i0, i1, i2]; S92[i0]; S87[i0]; S47[i0, i1]; S108[i0, i1]; S54[i0]; S76[i0]; S112[i0, i1]; S80[i0]; S55[i0]; S39[i0]; S59[i0, i1, i2]; S121[i0]; S86[i0]; S110[i0, i1]; S48[i0, i1]; S68[i0]; S53[i0]; S72[i0]; S85[i0]; S52[i0]; S69[i0]; S61[i0, i1, i2]; S43[i0, i1, i2]; S124[i0]; S73[i0]; S81[i0]; S63[i0, i1]; S118[i0, i1]; S96[i0, i1, i2]; S40[i0, i1, i2]; S94[i0]; S64[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S99[i0] -> [(i0)]; S97[i0, i1, i2] -> [(i0)]; S53[i0] -> [(i0)]; S101[i0] -> [(i0)]; S60[i0, i1, i2] -> [(i0)]; S40[i0, i1, i2] -> [(i0)]; S103[i0, i1, i2] -> [(i0)]; S55[i0] -> [(i0)]; S89[i0] -> [(i0)]; S56[i0] -> [(i0)]; S87[i0] -> [(i0)]; S115[i0, i1] -> [(i0)]; S123[i0] -> [(i0)]; S88[i0] -> [(i0)]; S70[i0] -> [(i0)]; S59[i0, i1, i2] -> [(i0)]; S52[i0] -> [(i0)]; S54[i0] -> [(i0)]; S63[i0, i1] -> [(i0)]; S92[i0] -> [(i0)]; S93[i0] -> [(i0)]; S119[i0, i1] -> [(i0)]; S76[i0] -> [(i0)]; S57[i0] -> [(i0)]; S44[i0, i1] -> [(i0)]; S79[i0] -> [(i0)]; S61[i0, i1, i2] -> [(i0)]; S69[i0] -> [(i0)]; S117[i0, i1] -> [(i0)]; S121[i0] -> [(i0)]; S84[i0] -> [(i0)]; S83[i0] -> [(i0)]; S43[i0, i1, i2] -> [(i0)]; S98[i0, i1] -> [(i0)]; S78[i0] -> [(i0)]; S114[i0, i1] -> [(i0)]; S66[i0, i1] -> [(i0)]; S77[i0] -> [(i0)]; S109[i0, i1] -> [(i0)]; S42[i0, i1, i2] -> [(i0)]; S58[i0] -> [(i0)]; S71[i0] -> [(i0)]; S68[i0] -> [(i0)]; S116[i0, i1] -> [(i0)]; S81[i0] -> [(i0)]; S125[i0] -> [(i0)]; S80[i0] -> [(i0)]; S73[i0] -> [(i0)]; S110[i0, i1] -> [(i0)]; S72[i0] -> [(i0)]; S51[i0, i1] -> [(i0)]; S122[i0] -> [(i0)]; S38[i0] -> [(i0)]; S39[i0] -> [(i0)]; S90[i0] -> [(i0)]; S113[i0, i1] -> [(i0)]; S46[i0, i1] -> [(i0)]; S47[i0, i1] -> [(i0)]; S96[i0, i1, i2] -> [(i0)]; S45[i0, i1] -> [(i0)]; S49[i0, i1] -> [(i0)]; S118[i0, i1] -> [(i0)]; S50[i0, i1] -> [(i0)]; S102[i0, i1, i2] -> [(i0)]; S112[i0, i1] -> [(i0)]; S86[i0] -> [(i0)]; S124[i0] -> [(i0)]; S41[i0, i1, i2] -> [(i0)]; S100[i0] -> [(i0)]; S104[i0, i1, i2] -> [(i0)]; S75[i0] -> [(i0)]; S62[i0, i1] -> [(i0)]; S85[i0] -> [(i0)]; S105[i0, i1, i2] -> [(i0)]; S82[i0] -> [(i0)]; S111[i0, i1] -> [(i0)]; S48[i0, i1] -> [(i0)]; S65[i0, i1] -> [(i0)]; S120[i0] -> [(i0)]; S107[i0, i1, i2] -> [(i0)]; S106[i0, i1, i2] -> [(i0)]; S95[i0, i1, i2] -> [(i0)]; S108[i0, i1] -> [(i0)]; S91[i0] -> [(i0)]; S67[i0, i1] -> [(i0)]; S74[i0] -> [(i0)]; S64[i0, i1] -> [(i0)]; S94[i0] -> [(i0)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S38[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S39[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S40[i0, i1, i2]; S41[i0, i1, i2]; S43[i0, i1, i2]; S42[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S43[i0, i1, i2] -> [(i1)]; S41[i0, i1, i2] -> [(i1)]; S40[i0, i1, i2] -> [(i1)]; S42[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S43[i0, i1, i2] -> [(i2)]; S41[i0, i1, i2] -> [(i2)]; S40[i0, i1, i2] -> [(i2)]; S42[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S40[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S41[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S42[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S43[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S46[i0, i1]; S45[i0, i1]; S44[i0, i1]; S47[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S47[i0, i1] -> [(i1)]; S46[i0, i1] -> [(i1)]; S44[i0, i1] -> [(i1)]; S45[i0, i1] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S44[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S45[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S46[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S47[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S51[i0, i1]; S49[i0, i1]; S50[i0, i1]; S48[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S51[i0, i1] -> [(i1)]; S49[i0, i1] -> [(i1)]; S48[i0, i1] -> [(i1)]; S50[i0, i1] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S48[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S49[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S50[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S51[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S52[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S53[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S54[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S55[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S56[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S57[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S58[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S60[i0, i1, i2]; S59[i0, i1, i2]; S61[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S61[i0, i1, i2] -> [(i1)]; S59[i0, i1, i2] -> [(i1)]; S60[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S61[i0, i1, i2] -> [(i2)]; S59[i0, i1, i2] -> [(i2)]; S60[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S59[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S60[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S61[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S62[i0, i1]; S63[i0, i1]; S64[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S64[i0, i1] -> [(i1)]; S62[i0, i1] -> [(i1)]; S63[i0, i1] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S62[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S63[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S64[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S65[i0, i1]; S66[i0, i1]; S67[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S66[i0, i1] -> [(i1)]; S65[i0, i1] -> [(i1)]; S67[i0, i1] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S65[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S66[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S67[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S68[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S69[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S70[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S71[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S72[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S73[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S74[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S75[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S76[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S77[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S78[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S79[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S80[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S81[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S82[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S83[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S84[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S85[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S86[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S87[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S88[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S89[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S90[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S91[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S92[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S93[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S94[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S96[i0, i1, i2]; S98[i0, i1]; S97[i0, i1, i2]; S95[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S98[i0, i1] -> [(i1)]; S95[i0, i1, i2] -> [(i1)]; S96[i0, i1, i2] -> [(i1)]; S97[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S96[i0, i1, i2]; S97[i0, i1, i2]; S95[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S95[i0, i1, i2] -> [(i2)]; S96[i0, i1, i2] -> [(i2)]; S97[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S95[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S96[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S97[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S98[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S99[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S100[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S101[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S107[i0, i1, i2]; S105[i0, i1, i2]; S102[i0, i1, i2]; S104[i0, i1, i2]; S106[i0, i1, i2]; S103[i0, i1, i2] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S102[i0, i1, i2] -> [(i1)]; S103[i0, i1, i2] -> [(i1)]; S104[i0, i1, i2] -> [(i1)]; S107[i0, i1, i2] -> [(i1)]; S106[i0, i1, i2] -> [(i1)]; S105[i0, i1, i2] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S102[i0, i1, i2] -> [(i2)]; S103[i0, i1, i2] -> [(i2)]; S104[i0, i1, i2] -> [(i2)]; S107[i0, i1, i2] -> [(i2)]; S106[i0, i1, i2] -> [(i2)]; S105[i0, i1, i2] -> [(i2)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S102[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S103[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S104[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S105[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S106[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S107[i0, i1, i2] }" + - filter: "[M, N, O, P, Q, R] -> { S113[i0, i1]; S112[i0, i1]; S108[i0, i1]; S111[i0, i1]; S110[i0, i1]; S109[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S110[i0, i1] -> [(i1)]; S112[i0, i1] -> [(i1)]; S111[i0, i1] -> [(i1)]; S113[i0, i1] -> [(i1)]; S109[i0, i1] -> [(i1)]; S108[i0, i1] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S108[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S109[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S110[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S111[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S112[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S113[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S119[i0, i1]; S114[i0, i1]; S117[i0, i1]; S115[i0, i1]; S118[i0, i1]; S116[i0, i1] }" + child: + schedule: "[M, N, O, P, Q, R] -> [{ S115[i0, i1] -> [(i1)]; S116[i0, i1] -> [(i1)]; S118[i0, i1] -> [(i1)]; S117[i0, i1] -> [(i1)]; S119[i0, i1] -> [(i1)]; S114[i0, i1] -> [(i1)] }]" + options: "[M, N, O, P, Q, R] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N, O, P, Q, R] -> { S114[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S115[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S116[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S117[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S118[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S119[i0, i1] }" + - filter: "[M, N, O, P, Q, R] -> { S120[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S121[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S122[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S123[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S124[i0] }" + - filter: "[M, N, O, P, Q, R] -> { S125[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/test.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/test.c @@ -0,0 +1,17 @@ +{ + for (int c0 = 1; c0 <= 2; c0 += 1) + for (int c1 = 1; c1 <= M; c1 += 1) + S1(c0, c1); + for (int c0 = 3; c0 <= N; c0 += 1) { + for (int c1 = 1; c1 <= min(M, c0 - 1); c1 += 1) + S1(c0, c1); + if (c0 >= M + 1) { + S2(c0, c0); + } else { + S1(c0, c0); + S2(c0, c0); + } + for (int c1 = c0 + 1; c1 <= M; c1 += 1) + S1(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/cloog/test.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/test.st @@ -0,0 +1,10 @@ +domain: "[M, N] -> { S1[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M; S2[i0, i0] : i0 >= 3 and i0 <= N }" +child: + context: "[M, N] -> { [] : N >= M and M >= 4 }" + child: + schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S1[i0, i1] }" + - filter: "[M, N] -> { S2[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/thomasset.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/thomasset.c @@ -0,0 +1,9 @@ +{ + for (int c0 = 0; c0 <= floord(n - 1, 3); c0 += 1) + for (int c2 = 3 * c0 + 1; c2 <= min(n, 3 * c0 + 3); c2 += 1) + S1(c2, c0); + for (int c0 = floord(n, 3); c0 <= 2 * floord(n, 3); c0 += 1) + for (int c1 = 0; c1 < n; c1 += 1) + for (int c3 = max(1, (n % 3) - n + 3 * c0); c3 <= min(n, (n % 3) - n + 3 * c0 + 2); c3 += 1) + S2(c1 + 1, c3, 0, n / 3, c0 - n / 3); +} Index: contrib/isl/test_inputs/codegen/cloog/thomasset.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/thomasset.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[i, j] : i <= n and i >= 1 and 3j <= -1 + i and 3j >= -3 + i; S2[i, j, 0, p, q] : i <= n and j <= n and j >= 1 and i >= 1 and 3q <= j and 3q >= -2 + j and 3p <= n and 3p >= -2 + n }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S2[i0, i1, i2, i3, i4] -> [(i2 + i3 + i4)]; S1[i0, i1] -> [(i1)] }, { S2[i0, i1, i2, i3, i4] -> [(-1 + i0)]; S1[i0, i1] -> [(0)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/tiling.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/tiling.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= n / 10; c0 += 1) + for (int c1 = 10 * c0; c1 <= min(n, 10 * c0 + 9); c1 += 1) + S1(c0, c1); Index: contrib/isl/test_inputs/codegen/cloog/tiling.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/tiling.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[ii, i] : i >= 0 and i <= n and i <= 9 + 10ii and i >= 10ii }" +child: + context: "[n] -> { [] : n >= 0 }" + child: + schedule: "[n] -> [{ S1[ii, i] -> [(ii)] }, { S1[ii, i] -> [(i)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/uday_scalars.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/uday_scalars.c @@ -0,0 +1,6 @@ +{ + for (int c0 = 0; c0 <= n; c0 += 1) + S1(c0, 0, 0); + for (int c0 = 0; c0 <= n; c0 += 1) + S2(0, c0, 0); +} Index: contrib/isl/test_inputs/codegen/cloog/uday_scalars.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/uday_scalars.st @@ -0,0 +1,13 @@ +domain: "[n] -> { S1[j, 0, 0] : j >= 0 and j <= n; S2[0, l, 0] : l >= 0 and l <= n }" +child: + context: "[n] -> { [] }" + child: + sequence: + - filter: "[n] -> { S1[i0, i1, i2] }" + child: + schedule: "[n] -> [{ S1[i0, i1, i2] -> [(i0)] }]" + options: "[n] -> { separate[i0] }" + - filter: "[n] -> { S2[i0, i1, i2] }" + child: + schedule: "[n] -> [{ S2[i0, i1, i2] -> [(i1)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/union.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/union.c @@ -0,0 +1,7 @@ +if (M >= 11) { + for (int c0 = -100; c0 <= 0; c0 += 1) + S1(-c0); +} else { + for (int c0 = 0; c0 <= 100; c0 += 1) + S1(c0); +} Index: contrib/isl/test_inputs/codegen/cloog/union.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/union.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S1[i0] : i0 >= 0 and i0 <= 100 }" +child: + context: "[M] -> { [] : M >= 1 or M <= -1 }" + child: + schedule: "[M] -> [{ S1[i0] -> [(i0)] : M <= 10; S1[i0] -> [(-i0)] : M >= 11 }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/unroll.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/unroll.c @@ -0,0 +1,13 @@ +{ + S1(0); + S1(1); + S1(2); + S1(3); + S1(4); + S1(5); + S1(6); + S1(7); + S1(8); + S1(9); + S1(10); +} Index: contrib/isl/test_inputs/codegen/cloog/unroll.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/unroll.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[i] : i >= 0 and i <= 10 }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S1[i] -> [(i)] }]" + options: "[n] -> { unroll[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/unroll2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/unroll2.c @@ -0,0 +1,5 @@ +if (n >= -1 && n <= 9) { + if (n >= 0) + S1(n); + S1(n + 1); +} Index: contrib/isl/test_inputs/codegen/cloog/unroll2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/unroll2.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[i] : i >= n and i <= 1 + n and n <= 9 and i >= 0 }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S1[i] -> [(i)] }]" + options: "[n] -> { unroll[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/usvd_e_t.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/usvd_e_t.c @@ -0,0 +1,348 @@ +{ + for (int c0 = 0; c0 <= 2; c0 += 1) { + S1(c0, 0, 0); + for (int c1 = 0; c1 <= 4; c1 += 1) + S2(c0, c1, 0); + } + S1(3, 0, 0); + for (int c1 = 0; c1 <= 4; c1 += 1) + S2(3, c1, 0); + for (int c1 = 7; c1 <= 11; c1 += 1) + S8(3, c1, 0); + S1(4, 0, 0); + S2(4, 0, 0); + S3(4, 0, 0); + S5(4, 0, 0); + for (int c1 = 1; c1 <= 4; c1 += 1) { + S2(4, c1, 0); + S5(4, c1, 0); + } + for (int c1 = 7; c1 <= 11; c1 += 1) + S8(4, c1, 0); + for (int c0 = 5; c0 <= 6; c0 += 1) { + for (int c1 = -4; c1 < c0 - 8; c1 += 1) + S6(c0, c1, 0); + for (int c1 = c0 - 9; c1 < 0; c1 += 1) + S7(c0, c1, 0); + S3(c0, 0, 0); + S7(c0, 0, 0); + for (int c1 = 1; c1 < c0 - 3; c1 += 1) + S4(c0, c1, -1); + for (int c1 = c0 - 4; c1 <= 4; c1 += 1) + S5(c0, c1, 0); + for (int c1 = 7; c1 <= 11; c1 += 1) + S8(c0, c1, 0); + } + for (int c1 = -4; c1 < -1; c1 += 1) + S6(7, c1, 0); + for (int c1 = -2; c1 < 0; c1 += 1) + S7(7, c1, 0); + S3(7, 0, 0); + S7(7, 0, 0); + for (int c1 = 1; c1 <= 3; c1 += 1) + S4(7, c1, -1); + for (int c1 = 3; c1 <= 4; c1 += 1) + S5(7, c1, 0); + S9(7, 4, 0); + S10(7, 4, 0); + S11(7, 4, 0); + S21(7, 4, 0); + S23(7, 4, 0); + S11(7, 4, 1); + S16(7, 4, 1); + S17(7, 4, 1); + for (int c2 = 2; c2 <= 4; c2 += 1) + S11(7, 4, c2); + S12(7, 5, 0); + S21(7, 5, 0); + S22(7, 5, 0); + S23(7, 5, 0); + S12(7, 5, 1); + S16(7, 5, 1); + S17(7, 5, 1); + for (int c2 = 2; c2 <= 4; c2 += 1) + S12(7, 5, c2); + S21(7, 6, 0); + S22(7, 6, 0); + S23(7, 6, 0); + for (int c1 = 7; c1 <= 8; c1 += 1) { + S8(7, c1, 0); + S21(7, c1, 0); + S22(7, c1, 0); + S23(7, c1, 0); + } + S8(7, 9, 0); + S22(7, 9, 0); + for (int c1 = 10; c1 <= 11; c1 += 1) + S8(7, c1, 0); + for (int c1 = -4; c1 < 0; c1 += 1) + S6(8, c1, 0); + S7(8, -1, 0); + S3(8, 0, 0); + S7(8, 0, 0); + S19(8, 1, -2); + S4(8, 1, -1); + S19(8, 1, -1); + S19(8, 1, 0); + S15(8, 1, 4); + S18(8, 1, 4); + for (int c2 = -4; c2 < -2; c2 += 1) { + S14(8, 2, c2); + S20(8, 2, c2); + } + S14(8, 2, -2); + S19(8, 2, -2); + S20(8, 2, -2); + S4(8, 2, -1); + S14(8, 2, -1); + S19(8, 2, -1); + S20(8, 2, -1); + S14(8, 2, 0); + S19(8, 2, 0); + S20(8, 2, 0); + S15(8, 2, 4); + S18(8, 2, 4); + for (int c2 = -4; c2 < -1; c2 += 1) { + S14(8, 3, c2); + S20(8, 3, c2); + } + S4(8, 3, -1); + S14(8, 3, -1); + S20(8, 3, -1); + S14(8, 3, 0); + S20(8, 3, 0); + S15(8, 3, 4); + S18(8, 3, 4); + for (int c2 = -4; c2 < -1; c2 += 1) { + S14(8, 4, c2); + S20(8, 4, c2); + } + S4(8, 4, -1); + S14(8, 4, -1); + S20(8, 4, -1); + S5(8, 4, 0); + S9(8, 4, 0); + S10(8, 4, 0); + S14(8, 4, 0); + S20(8, 4, 0); + S23(8, 4, 0); + S13(8, 4, 1); + S21(8, 4, 1); + S23(8, 4, 1); + S24(8, 4, 1); + S13(8, 4, 2); + S16(8, 4, 2); + S17(8, 4, 2); + S24(8, 4, 2); + S13(8, 4, 3); + S24(8, 4, 3); + S13(8, 4, 4); + S15(8, 4, 4); + S23(8, 5, 0); + S11(8, 5, 1); + S21(8, 5, 1); + S22(8, 5, 1); + S23(8, 5, 1); + S24(8, 5, 1); + S11(8, 5, 2); + S16(8, 5, 2); + S17(8, 5, 2); + S24(8, 5, 2); + S11(8, 5, 3); + S24(8, 5, 3); + S11(8, 5, 4); + S15(8, 5, 4); + S23(8, 6, 0); + S12(8, 6, 1); + S21(8, 6, 1); + S22(8, 6, 1); + S23(8, 6, 1); + S24(8, 6, 1); + S12(8, 6, 2); + S16(8, 6, 2); + S17(8, 6, 2); + S24(8, 6, 2); + S12(8, 6, 3); + S24(8, 6, 3); + S12(8, 6, 4); + for (int c1 = 7; c1 <= 8; c1 += 1) { + S23(8, c1, 0); + S21(8, c1, 1); + S22(8, c1, 1); + S23(8, c1, 1); + for (int c2 = 1; c2 <= 3; c2 += 1) + S24(8, c1, c2); + } + S22(8, 9, 1); + S7(9, 0, 0); + for (int c1 = 1; c1 <= 2; c1 += 1) { + for (int c2 = -1; c2 <= 0; c2 += 1) + S19(9, c1, c2); + for (int c2 = 4; c2 <= 5; c2 += 1) { + S15(9, c1, c2); + S18(9, c1, c2); + } + } + S20(9, 3, -4); + for (int c2 = -3; c2 < -1; c2 += 1) { + S14(9, 3, c2); + S20(9, 3, c2); + } + for (int c2 = -1; c2 <= 0; c2 += 1) { + S14(9, 3, c2); + S19(9, 3, c2); + S20(9, 3, c2); + } + for (int c2 = 4; c2 <= 5; c2 += 1) { + S15(9, 3, c2); + S18(9, 3, c2); + } + S20(9, 4, -4); + for (int c2 = -3; c2 < 0; c2 += 1) { + S14(9, 4, c2); + S20(9, 4, c2); + } + S9(9, 4, 0); + S10(9, 4, 0); + S14(9, 4, 0); + S20(9, 4, 0); + for (int c2 = 0; c2 <= 1; c2 += 1) + S23(9, 4, c2); + S13(9, 4, 2); + S21(9, 4, 2); + S23(9, 4, 2); + S24(9, 4, 2); + S13(9, 4, 3); + S16(9, 4, 3); + S17(9, 4, 3); + S24(9, 4, 3); + S13(9, 4, 4); + for (int c2 = 4; c2 <= 5; c2 += 1) { + S15(9, 4, c2); + S18(9, 4, c2); + } + for (int c2 = 0; c2 <= 1; c2 += 1) + S23(9, 5, c2); + S13(9, 5, 2); + S21(9, 5, 2); + S22(9, 5, 2); + S23(9, 5, 2); + S24(9, 5, 2); + S13(9, 5, 3); + S16(9, 5, 3); + S17(9, 5, 3); + S24(9, 5, 3); + S13(9, 5, 4); + for (int c2 = 4; c2 <= 5; c2 += 1) + S15(9, 5, c2); + for (int c2 = 0; c2 <= 1; c2 += 1) + S23(9, 6, c2); + S11(9, 6, 2); + S21(9, 6, 2); + S22(9, 6, 2); + S23(9, 6, 2); + S24(9, 6, 2); + S11(9, 6, 3); + S16(9, 6, 3); + S17(9, 6, 3); + S24(9, 6, 3); + S11(9, 6, 4); + for (int c2 = 0; c2 <= 1; c2 += 1) + S23(9, 7, c2); + S12(9, 7, 2); + S21(9, 7, 2); + S22(9, 7, 2); + S23(9, 7, 2); + S24(9, 7, 2); + S12(9, 7, 3); + S16(9, 7, 3); + S17(9, 7, 3); + S24(9, 7, 3); + S12(9, 7, 4); + for (int c2 = 0; c2 <= 1; c2 += 1) + S23(9, 8, c2); + S21(9, 8, 2); + S22(9, 8, 2); + S23(9, 8, 2); + for (int c2 = 2; c2 <= 3; c2 += 1) + S24(9, 8, c2); + S22(9, 9, 2); + for (int c1 = 1; c1 <= 3; c1 += 1) { + S19(10, c1, 0); + S26(10, c1, 3); + S15(10, c1, 4); + S18(10, c1, 4); + S25(10, c1, 4); + for (int c2 = 5; c2 <= 6; c2 += 1) { + S15(10, c1, c2); + S18(10, c1, c2); + } + } + for (int c2 = -4; c2 < -2; c2 += 1) + S20(10, 4, c2); + for (int c2 = -2; c2 < 0; c2 += 1) { + S14(10, 4, c2); + S20(10, 4, c2); + } + S9(10, 4, 0); + S10(10, 4, 0); + S14(10, 4, 0); + S19(10, 4, 0); + S20(10, 4, 0); + S13(10, 4, 3); + S21(10, 4, 3); + S24(10, 4, 3); + S26(10, 4, 3); + S13(10, 4, 4); + S15(10, 4, 4); + S16(10, 4, 4); + S17(10, 4, 4); + S18(10, 4, 4); + S25(10, 4, 4); + for (int c2 = 5; c2 <= 6; c2 += 1) { + S15(10, 4, c2); + S18(10, 4, c2); + } + S13(10, 5, 3); + S21(10, 5, 3); + S22(10, 5, 3); + S24(10, 5, 3); + S26(10, 5, 3); + S13(10, 5, 4); + S15(10, 5, 4); + S16(10, 5, 4); + S17(10, 5, 4); + S18(10, 5, 4); + S25(10, 5, 4); + for (int c2 = 5; c2 <= 6; c2 += 1) { + S15(10, 5, c2); + S18(10, 5, c2); + } + S13(10, 6, 3); + S21(10, 6, 3); + S22(10, 6, 3); + S24(10, 6, 3); + S13(10, 6, 4); + S16(10, 6, 4); + S17(10, 6, 4); + S11(10, 7, 3); + S21(10, 7, 3); + S22(10, 7, 3); + S24(10, 7, 3); + S11(10, 7, 4); + S16(10, 7, 4); + S17(10, 7, 4); + S12(10, 8, 3); + S21(10, 8, 3); + S22(10, 8, 3); + S24(10, 8, 3); + S12(10, 8, 4); + S16(10, 8, 4); + S17(10, 8, 4); + S22(10, 9, 3); + for (int c0 = 11; c0 <= 14; c0 += 1) + for (int c1 = 1; c1 <= 5; c1 += 1) { + S26(c0, c1, 3); + S25(c0, c1, 4); + } +} Index: contrib/isl/test_inputs/codegen/cloog/usvd_e_t.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/usvd_e_t.st @@ -0,0 +1,34 @@ +domain: "{ S22[i0, i1, -7 + i0] : i0 >= 7 and i1 >= 5 and i1 <= 9 and i0 <= 10; S21[i0, i1, -7 + i0] : i0 <= 10 and i1 >= 4 and i1 <= 8 and i0 >= 7; S4[i0, i1, -1] : i0 <= 8 and i1 >= 1 and i1 <= -4 + i0; S8[i0, i1, 0] : i0 >= 3 and i0 <= 7 and i1 >= 7 and i1 <= 11; S25[i0, i1, 4] : i0 >= 10 and i0 <= 14 and i1 >= 1 and i1 <= 5; S15[i0, i1, i2] : i0 <= 10 and i1 >= 1 and i1 <= 5 and i2 >= 4 and i2 <= -4 + i0; S6[i0, i1, 0] : i0 <= 8 and i1 >= -4 and i1 <= -9 + i0; S16[i0, i1, -6 + i0] : i0 <= 10 and i1 >= 4 and i0 >= 7 and i1 <= -2 + i0; S7[i0, i1, 0] : i0 >= 5 and i1 <= 0 and i1 >= -9 + i0; S1[i0, 0, 0] : i0 >= 0 and i0 <= 4; S2[i0, i1, 0] : i0 >= 0 and i0 <= 4 and i1 >= 0 and i1 <= 4; S26[i0, i1, 3] : i0 >= 10 and i0 <= 14 and i1 >= 1 and i1 <= 5; S10[i0, 4, 0] : i0 >= 7 and i0 <= 10; S12[i0, -2 + i0, i2] : i0 >= 7 and i0 <= 10 and i2 <= 4 and i2 >= -7 + i0; S23[i0, i1, i2] : i0 <= 9 and i1 >= 4 and i1 <= 8 and i2 >= 0 and i2 <= -7 + i0; S13[i0, i1, i2] : i0 <= 10 and i1 >= 4 and i2 <= 4 and i2 >= -7 + i0 and i1 <= -4 + i0; S20[i0, i1, i2] : i0 >= 8 and i1 <= 4 and i2 >= -4 and i2 <= 0 and i1 >= -6 + i0; S24[i0, i1, i2] : i0 >= 8 and i1 >= 4 and i1 <= 8 and i2 <= 3 and i2 >= -7 + i0; S19[i0, i1, i2] : i0 >= 8 and i1 >= 1 and i2 <= 0 and i2 >= -10 + i0 and i1 <= -6 + i0; S11[i0, -3 + i0, i2] : i0 <= 10 and i0 >= 7 and i2 <= 4 and i2 >= -7 + i0; S14[i0, i1, i2] : i0 >= 8 and i1 <= 4 and i2 <= 0 and i2 >= -12 + i0 and i1 >= -6 + i0; S3[i0, 0, 0] : i0 >= 4 and i0 <= 8; S9[i0, 4, 0] : i0 >= 7 and i0 <= 10; S18[i0, i1, i2] : i0 <= 10 and i1 >= 1 and i2 >= 4 and i2 <= -4 + i0 and i1 <= -5 + i0; S5[i0, i1, 0] : i0 >= 4 and i1 <= 4 and i1 >= -4 + i0; S17[i0, i1, -6 + i0] : i0 >= 7 and i1 >= 4 and i0 <= 10 and i1 <= -2 + i0 }" +child: + context: "{ [] }" + child: + schedule: "[{ S8[i0, i1, i2] -> [(i0)]; S21[i0, i1, i2] -> [(i0)]; S9[i0, i1, i2] -> [(i0)]; S10[i0, i1, i2] -> [(i0)]; S24[i0, i1, i2] -> [(i0)]; S15[i0, i1, i2] -> [(i0)]; S12[i0, i1, i2] -> [(i0)]; S7[i0, i1, i2] -> [(i0)]; S6[i0, i1, i2] -> [(i0)]; S23[i0, i1, i2] -> [(i0)]; S22[i0, i1, i2] -> [(i0)]; S16[i0, i1, i2] -> [(i0)]; S17[i0, i1, i2] -> [(i0)]; S25[i0, i1, i2] -> [(i0)]; S18[i0, i1, i2] -> [(i0)]; S26[i0, i1, i2] -> [(i0)]; S5[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)]; S4[i0, i1, i2] -> [(i0)]; S13[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)]; S14[i0, i1, i2] -> [(i0)]; S19[i0, i1, i2] -> [(i0)]; S20[i0, i1, i2] -> [(i0)]; S11[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)] }, { S8[i0, i1, i2] -> [(i1)]; S21[i0, i1, i2] -> [(i1)]; S9[i0, i1, i2] -> [(i1)]; S10[i0, i1, i2] -> [(i1)]; S24[i0, i1, i2] -> [(i1)]; S15[i0, i1, i2] -> [(i1)]; S12[i0, i1, i2] -> [(i1)]; S7[i0, i1, i2] -> [(i1)]; S6[i0, i1, i2] -> [(i1)]; S23[i0, i1, i2] -> [(i1)]; S22[i0, i1, i2] -> [(i1)]; S16[i0, i1, i2] -> [(i1)]; S17[i0, i1, i2] -> [(i1)]; S25[i0, i1, i2] -> [(i1)]; S18[i0, i1, i2] -> [(i1)]; S26[i0, i1, i2] -> [(i1)]; S5[i0, i1, i2] -> [(i1)]; S2[i0, i1, i2] -> [(i1)]; S4[i0, i1, i2] -> [(i1)]; S13[i0, i1, i2] -> [(i1)]; S3[i0, i1, i2] -> [(i1)]; S14[i0, i1, i2] -> [(i1)]; S19[i0, i1, i2] -> [(i1)]; S20[i0, i1, i2] -> [(i1)]; S11[i0, i1, i2] -> [(i1)]; S1[i0, i1, i2] -> [(i1)] }, { S8[i0, i1, i2] -> [(i2)]; S21[i0, i1, i2] -> [(i2)]; S9[i0, i1, i2] -> [(i2)]; S10[i0, i1, i2] -> [(i2)]; S24[i0, i1, i2] -> [(i2)]; S15[i0, i1, i2] -> [(i2)]; S12[i0, i1, i2] -> [(i2)]; S7[i0, i1, i2] -> [(i2)]; S6[i0, i1, i2] -> [(i2)]; S23[i0, i1, i2] -> [(i2)]; S22[i0, i1, i2] -> [(i2)]; S16[i0, i1, i2] -> [(i2)]; S17[i0, i1, i2] -> [(i2)]; S25[i0, i1, i2] -> [(i2)]; S18[i0, i1, i2] -> [(i2)]; S26[i0, i1, i2] -> [(i2)]; S5[i0, i1, i2] -> [(i2)]; S2[i0, i1, i2] -> [(i2)]; S4[i0, i1, i2] -> [(i2)]; S13[i0, i1, i2] -> [(i2)]; S3[i0, i1, i2] -> [(i2)]; S14[i0, i1, i2] -> [(i2)]; S19[i0, i1, i2] -> [(i2)]; S20[i0, i1, i2] -> [(i2)]; S11[i0, i1, i2] -> [(i2)]; S1[i0, i1, i2] -> [(i2)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1, i2] }" + - filter: "{ S2[i0, i1, i2] }" + - filter: "{ S3[i0, i1, i2] }" + - filter: "{ S4[i0, i1, i2] }" + - filter: "{ S5[i0, i1, i2] }" + - filter: "{ S6[i0, i1, i2] }" + - filter: "{ S7[i0, i1, i2] }" + - filter: "{ S8[i0, i1, i2] }" + - filter: "{ S9[i0, i1, i2] }" + - filter: "{ S10[i0, i1, i2] }" + - filter: "{ S11[i0, i1, i2] }" + - filter: "{ S12[i0, i1, i2] }" + - filter: "{ S13[i0, i1, i2] }" + - filter: "{ S14[i0, i1, i2] }" + - filter: "{ S15[i0, i1, i2] }" + - filter: "{ S16[i0, i1, i2] }" + - filter: "{ S17[i0, i1, i2] }" + - filter: "{ S18[i0, i1, i2] }" + - filter: "{ S19[i0, i1, i2] }" + - filter: "{ S20[i0, i1, i2] }" + - filter: "{ S21[i0, i1, i2] }" + - filter: "{ S22[i0, i1, i2] }" + - filter: "{ S23[i0, i1, i2] }" + - filter: "{ S24[i0, i1, i2] }" + - filter: "{ S25[i0, i1, i2] }" + - filter: "{ S26[i0, i1, i2] }" Index: contrib/isl/test_inputs/codegen/cloog/vasilache.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/vasilache.c @@ -0,0 +1,24 @@ +{ + S1(); + S2(); + for (int c0 = 0; c0 < N; c0 += 1) + for (int c1 = 0; c1 < N; c1 += 1) { + S4(c0, c1); + S5(c0, c1); + } + for (int c0 = 0; c0 < N; c0 += 1) + for (int c1 = 0; c1 < N; c1 += 1) + for (int c2 = 0; c2 <= (N - 1) / 32; c2 += 1) { + S7(c0, c1, c2, 32 * c2); + for (int c3 = 32 * c2 + 1; c3 <= min(N - 1, 32 * c2 + 31); c3 += 1) { + S6(c0, c1, c2, c3 - 1); + S7(c0, c1, c2, c3); + } + if (32 * c2 + 31 >= N) { + S6(c0, c1, c2, N - 1); + } else { + S6(c0, c1, c2, 32 * c2 + 31); + } + } + S8(); +} Index: contrib/isl/test_inputs/codegen/cloog/vasilache.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/vasilache.st @@ -0,0 +1,37 @@ +domain: "[M, N] -> { S5[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N; S8[]; S2[]; S7[i0, i1, i2, i3] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N and i3 >= 0 and i3 <= -1 + N and i3 >= 32i2 and i3 <= 31 + 32i2; S4[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N; S1[]; S3[] : M >= 79; S6[i0, i1, i2, i3] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N and i3 >= 0 and i3 <= -1 + N and i3 >= 32i2 and i3 <= 31 + 32i2 }" +child: + context: "[M, N] -> { [] : M <= 3 and N >= 100 }" + child: + sequence: + - filter: "[M, N] -> { S1[] }" + - filter: "[M, N] -> { S2[] }" + - filter: "[M, N] -> { S3[] }" + - filter: "[M, N] -> { S5[i0, i1]; S4[i0, i1] }" + child: + schedule: "[M, N] -> [{ S5[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S5[i0, i1] -> [(i1)]; S4[i0, i1] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S4[i0, i1] }" + - filter: "[M, N] -> { S5[i0, i1] }" + - filter: "[M, N] -> { S7[i0, i1, i2, i3]; S6[i0, i1, i2, i3] }" + child: + schedule: "[M, N] -> [{ S7[i0, i1, i2, i3] -> [(i0)]; S6[i0, i1, i2, i3] -> [(i0)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S7[i0, i1, i2, i3] -> [(i1)]; S6[i0, i1, i2, i3] -> [(i1)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S7[i0, i1, i2, i3] -> [(i2)]; S6[i0, i1, i2, i3] -> [(i2)] }]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S7[i0, i1, i2, i3] -> [(i3)]; S6[i0, i1, i2, i3] -> [(1 + i3)] }]" + options: "[M, N] -> { separate[i0] }" + child: + sequence: + - filter: "[M, N] -> { S6[i0, i1, i2, i3] }" + - filter: "[M, N] -> { S7[i0, i1, i2, i3] }" + - filter: "[M, N] -> { S8[] }" Index: contrib/isl/test_inputs/codegen/cloog/vivien.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/vivien.c @@ -0,0 +1,88 @@ +{ + for (int c0 = -27 * n + 2; c0 <= 1; c0 += 1) + S1(c0 - 1); + for (int c0 = 2; c0 <= min(2 * n, n + 29); c0 += 1) { + if (c0 >= 3) { + if (2 * n >= c0 + 1) { + S4(c0 - c0 / 2 - 1, c0 / 2 + 1); + if (c0 + 2 >= 2 * n) { + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } else if (c0 >= 5) { + S4(c0 - c0 / 2 - 2, c0 / 2 + 2); + for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1) + S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2); + } + } + for (int c1 = -c0 + c0 / 2 + 3; c1 <= min(-1, n - c0); c1 += 1) { + S6(-c1 + 2, c0 + c1 - 2); + S4(-c1, c0 + c1); + for (int c2 = 1; c2 <= -c1; c2 += 1) + S5(-c1 + 1, c0 + c1 - 1, c2); + } + if (2 * n >= c0 + 3 && c0 >= n + 2) { + S6(-n + c0 + 1, n - 1); + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } + if (n >= 3 && c0 == n + 2) { + S1(n + 1); + S6(2, n); + } else { + if (c0 >= n + 3 && 2 * n >= c0 + 1) + S6(-n + c0, n); + if (c0 >= n + 3) { + S1(c0 - 1); + } else { + if (n + 1 >= c0 && c0 <= 4) { + S1(c0 - 1); + } else if (c0 >= 5 && n + 1 >= c0) { + S1(c0 - 1); + S6(2, c0 - 2); + } + if (n + 1 >= c0) + S6(1, c0 - 1); + } + } + if (n == 2 && c0 == 4) + S1(3); + } else { + S1(1); + } + if (c0 % 2 == 0) + S3(c0 / 2); + for (int c1 = max(1, -n + c0); c1 < (c0 + 1) / 2; c1 += 1) + S2(c0 - c1, c1); + } + for (int c0 = max(2 * n + 1, -27 * n + 2); c0 <= n + 29; c0 += 1) + S1(c0 - 1); + for (int c0 = n + 30; c0 <= 2 * n; c0 += 1) { + if (2 * n >= c0 + 1) { + S4(c0 - c0 / 2 - 1, c0 / 2 + 1); + if (c0 + 2 >= 2 * n) { + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } else { + S4(c0 - c0 / 2 - 2, c0 / 2 + 2); + for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1) + S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2); + } + for (int c1 = -c0 + c0 / 2 + 3; c1 <= n - c0; c1 += 1) { + S6(-c1 + 2, c0 + c1 - 2); + S4(-c1, c0 + c1); + for (int c2 = 1; c2 <= -c1; c2 += 1) + S5(-c1 + 1, c0 + c1 - 1, c2); + } + if (2 * n >= c0 + 3) { + S6(-n + c0 + 1, n - 1); + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } + S6(-n + c0, n); + } + if (c0 % 2 == 0) + S3(c0 / 2); + for (int c1 = -n + c0; c1 < (c0 + 1) / 2; c1 += 1) + S2(c0 - c1, c1); + } +} Index: contrib/isl/test_inputs/codegen/cloog/vivien.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/vivien.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S2[i, j] : 29j >= 1 - i and i <= n and j >= 1 and j <= -1 + i; S1[i] : i >= 1 - 27n and i <= 28 + n; S4[i, j] : i >= 1 and i <= n and j >= 1 + i and j <= n; S5[i, j, k] : i >= 1 and i <= n and j >= 1 + i and j <= n and k >= 1 and k <= -1 + i; S6[i, j] : i >= 1 and i <= n and j >= 1 + i and j <= n; S3[i] : i >= 1 and i <= n }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S1[i0] -> [(2 + 2i0)]; S4[i0, i1] -> [(2i0 + 2i1)]; S6[i0, i1] -> [(2i0 + 2i1)]; S3[i0] -> [(1 + 4i0)]; S5[i0, i1, i2] -> [(2i0 + 2i1)]; S2[i0, i1] -> [(1 + 2i0 + 2i1)] }, { S1[i0] -> [(0)]; S4[i0, i1] -> [(-i0)]; S6[i0, i1] -> [(2 - i0)]; S3[i0] -> [(0)]; S5[i0, i1, i2] -> [(1 - i0)]; S2[i0, i1] -> [(i1)] }, { S1[i0] -> [(0)]; S4[i0, i1] -> [(0)]; S6[i0, i1] -> [(0)]; S3[i0] -> [(0)]; S5[i0, i1, i2] -> [(i2)]; S2[i0, i1] -> [(0)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/vivien2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/vivien2.c @@ -0,0 +1,80 @@ +{ + for (int c0 = -27 * n + 2; c0 <= 1; c0 += 1) + S1(c0 - 1); + for (int c0 = 2; c0 <= n + 29; c0 += 1) { + if (c0 >= 3) { + S4(c0 - c0 / 2 - 1, c0 / 2 + 1); + if (c0 >= 5 && 2 * n >= c0 + 3) { + S4(c0 - c0 / 2 - 2, c0 / 2 + 2); + for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1) + S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2); + } + for (int c1 = -c0 + c0 / 2 + 3; c1 <= min(-1, n - c0); c1 += 1) { + S6(-c1 + 2, c0 + c1 - 2); + S4(-c1, c0 + c1); + for (int c2 = 1; c2 <= -c1; c2 += 1) + S5(-c1 + 1, c0 + c1 - 1, c2); + } + if (2 * n >= c0 + 3 && c0 >= n + 2) { + S6(-n + c0 + 1, n - 1); + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + if (c0 == n + 2) { + S1(n + 1); + S6(2, n); + } + } else if (c0 + 2 >= 2 * n) { + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } + if (c0 >= n + 3) { + S6(-n + c0, n); + S1(c0 - 1); + } else { + if (c0 >= 5 && n + 1 >= c0) { + S1(c0 - 1); + S6(2, c0 - 2); + } else if (c0 <= 4) { + S1(c0 - 1); + } + if (n + 1 >= c0) + S6(1, c0 - 1); + } + } else { + S1(1); + } + if (c0 % 2 == 0) + S3(c0 / 2); + for (int c1 = max(1, -n + c0); c1 < (c0 + 1) / 2; c1 += 1) + S2(c0 - c1, c1); + } + for (int c0 = n + 30; c0 <= 2 * n; c0 += 1) { + if (2 * n >= c0 + 1) { + S4(c0 - c0 / 2 - 1, c0 / 2 + 1); + if (c0 + 2 >= 2 * n) { + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } else { + S4(c0 - c0 / 2 - 2, c0 / 2 + 2); + for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1) + S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2); + } + for (int c1 = -c0 + c0 / 2 + 3; c1 <= n - c0; c1 += 1) { + S6(-c1 + 2, c0 + c1 - 2); + S4(-c1, c0 + c1); + for (int c2 = 1; c2 <= -c1; c2 += 1) + S5(-c1 + 1, c0 + c1 - 1, c2); + } + if (2 * n >= c0 + 3) { + S6(-n + c0 + 1, n - 1); + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } + S6(-n + c0, n); + } + if (c0 % 2 == 0) + S3(c0 / 2); + for (int c1 = -n + c0; c1 < (c0 + 1) / 2; c1 += 1) + S2(c0 - c1, c1); + } +} Index: contrib/isl/test_inputs/codegen/cloog/vivien2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/vivien2.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S2[i, j] : 29j >= 1 - i and i <= n and j >= 1 and j <= -1 + i; S1[i] : i >= 1 - 27n and i <= 28 + n; S4[i, j] : i >= 1 and i <= n and j >= 1 + i and j <= n; S5[i, j, k] : i >= 1 and i <= n and j >= 1 + i and j <= n and k >= 1 and k <= -1 + i; S6[i, j] : i >= 1 and i <= n and j >= 1 + i and j <= n; S3[i] : i >= 1 and i <= n }" +child: + context: "[n] -> { [] : n >= 30 }" + child: + schedule: "[n] -> [{ S1[i0] -> [(2 + 2i0)]; S4[i0, i1] -> [(2i0 + 2i1)]; S6[i0, i1] -> [(2i0 + 2i1)]; S3[i0] -> [(1 + 4i0)]; S5[i0, i1, i2] -> [(2i0 + 2i1)]; S2[i0, i1] -> [(1 + 2i0 + 2i1)] }, { S1[i0] -> [(0)]; S4[i0, i1] -> [(-i0)]; S6[i0, i1] -> [(2 - i0)]; S3[i0] -> [(0)]; S5[i0, i1, i2] -> [(1 - i0)]; S2[i0, i1] -> [(i1)] }, { S1[i0] -> [(0)]; S4[i0, i1] -> [(0)]; S6[i0, i1] -> [(0)]; S3[i0] -> [(0)]; S5[i0, i1, i2] -> [(i2)]; S2[i0, i1] -> [(0)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/walters.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/walters.c @@ -0,0 +1,16 @@ +{ + S2(1, 0, 1, 0); + S4(1, 0, 1, 0); + S3(2, 0, 1, 1); + S4(2, 0, 1, 1); + for (int c0 = 3; c0 <= 10; c0 += 1) { + if ((c0 + 1) % 3 == 0) { + S3(c0, (c0 - 2) / 3, (c0 + 1) / 3, (c0 + 1) / 3); + } else if (c0 % 3 == 0) { + S1(c0, c0 / 3, c0 / 3, c0 / 3); + } else { + S2(c0, (c0 - 1) / 3, (c0 + 2) / 3, (c0 - 1) / 3); + } + S4(c0, c0 / 3, (c0 - 1) / 3 + 1, c0 - (c0 - 1) / 3 - c0 / 3 - 1); + } +} Index: contrib/isl/test_inputs/codegen/cloog/walters.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/walters.st @@ -0,0 +1,12 @@ +domain: "{ S2[i, div36, div37, div38] : 3div37 = 2 + i and i >= 1 and i <= 10 and 3div36 >= -2 + i and 3div38 <= 1 + i and 3div38 >= -1 + i and 3div36 <= i; S4[i, div36, div37, div38] : i >= 1 and i <= 10 and 3div36 <= i and 3div36 >= -2 + i and 3div37 <= 2 + i and 3div37 >= i and 3div38 <= 1 + i and 3div38 >= -1 + i; S1[i, div36, div37, div38] : 3div36 = i and i >= 3 and i <= 10 and 3div37 >= i and 3div38 <= 1 + i and 3div37 <= 2 + i and 3div38 >= -1 + i; S3[i, div36, div37, div38] : 3div38 = 1 + i and i <= 10 and i >= 2 and 3div36 >= -2 + i and 3div37 <= 2 + i and 3div36 <= i and 3div37 >= i }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[i, div36, div37, div38] -> [(i)]; S4[i, div36, div37, div38] -> [(i)]; S3[i, div36, div37, div38] -> [(i)]; S2[i, div36, div37, div38] -> [(i)] }, { S1[i, div36, div37, div38] -> [(div36)]; S4[i, div36, div37, div38] -> [(div36)]; S3[i, div36, div37, div38] -> [(div36)]; S2[i, div36, div37, div38] -> [(div36)] }, { S1[i, div36, div37, div38] -> [(div37)]; S4[i, div36, div37, div38] -> [(div37)]; S3[i, div36, div37, div38] -> [(div37)]; S2[i, div36, div37, div38] -> [(div37)] }, { S1[i, div36, div37, div38] -> [(div38)]; S4[i, div36, div37, div38] -> [(div38)]; S3[i, div36, div37, div38] -> [(div38)]; S2[i, div36, div37, div38] -> [(div38)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[i, div36, div37, div38] }" + - filter: "{ S2[i, div36, div37, div38] }" + - filter: "{ S3[i, div36, div37, div38] }" + - filter: "{ S4[i, div36, div37, div38] }" Index: contrib/isl/test_inputs/codegen/cloog/walters2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/walters2.c @@ -0,0 +1,12 @@ +{ + for (int c1 = 0; c1 <= 51; c1 += 1) + S2(0, c1); + for (int c0 = 1; c0 <= 24; c0 += 1) { + S2(c0, 0); + for (int c1 = 1; c1 <= 50; c1 += 1) + S1(c0, c1); + S2(c0, 51); + } + for (int c1 = 0; c1 <= 51; c1 += 1) + S2(25, c1); +} Index: contrib/isl/test_inputs/codegen/cloog/walters2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/walters2.st @@ -0,0 +1,10 @@ +domain: "{ S2[j, 51] : j <= 24 and j >= 1; S2[25, i] : i <= 51 and i >= 1; S2[j, 0] : j <= 25 and j >= 1; S2[0, i] : i <= 51 and i >= 0; S1[j, i] : j >= 1 and j <= 24 and i >= 1 and i <= 50 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[j, i] -> [(j)]; S2[j, i] -> [(j)] }, { S1[j, i] -> [(i)]; S2[j, i] -> [(i)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[j, i] }" + - filter: "{ S2[j, i] }" Index: contrib/isl/test_inputs/codegen/cloog/walters3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/walters3.c @@ -0,0 +1,7 @@ +{ + for (int c0 = 2; c0 <= 8; c0 += 2) { + S1(c0, c0 / 2, c0 / 2); + S2(c0, c0 / 2, c0 / 2); + } + S2(10, 5, 5); +} Index: contrib/isl/test_inputs/codegen/cloog/walters3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/walters3.st @@ -0,0 +1,10 @@ +domain: "{ S2[j, a, b] : 2a = j and j >= 1 and j <= 10 and 2b <= j and 2b >= -1 + j; S1[j, a, b] : 2a = j and 2b = j and j <= 8 and j >= 2 }" +child: + context: "{ [] }" + child: + schedule: "[{ S1[j, a, b] -> [(j)]; S2[j, a, b] -> [(j)] }, { S1[j, a, b] -> [(a)]; S2[j, a, b] -> [(a)] }, { S1[j, a, b] -> [(b)]; S2[j, a, b] -> [(b)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[j, a, b] }" + - filter: "{ S2[j, a, b] }" Index: contrib/isl/test_inputs/codegen/cloog/wavefront.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/wavefront.c @@ -0,0 +1,3 @@ +for (int c0 = 2; c0 <= n + m; c0 += 1) + for (int c1 = max(1, -m + c0); c1 <= min(n, c0 - 1); c1 += 1) + S1(c1, c0 - c1); Index: contrib/isl/test_inputs/codegen/cloog/wavefront.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/wavefront.st @@ -0,0 +1,6 @@ +domain: "[n, m] -> { S1[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= m }" +child: + context: "[n, m] -> { [] }" + child: + schedule: "[n, m] -> [{ S1[i0, i1] -> [(i0 + i1)] }, { S1[i0, i1] -> [(i0)] }]" + options: "[n, m] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/yosr.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/yosr.c @@ -0,0 +1,12 @@ +{ + for (int c0 = 1; c0 < n; c0 += 1) { + for (int c2 = c0 + 1; c2 <= n; c2 += 1) + S1(c0, c2); + for (int c1 = 1; c1 < c0; c1 += 1) + for (int c2 = c1 + 1; c2 <= n; c2 += 1) + S2(c1, c2, c0); + } + for (int c1 = 1; c1 < n; c1 += 1) + for (int c2 = c1 + 1; c2 <= n; c2 += 1) + S2(c1, c2, n); +} Index: contrib/isl/test_inputs/codegen/cloog/yosr.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/yosr.st @@ -0,0 +1,6 @@ +domain: "[n] -> { S1[i0, i1] : i0 >= 1 and i0 <= -1 + n and i1 >= 1 + i0 and i1 <= n; S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + n and i1 >= 1 + i0 and i1 <= n and i2 >= 1 + i0 and i2 <= n }" +child: + context: "[n] -> { [] }" + child: + schedule: "[n] -> [{ S2[i0, i1, i2] -> [(i2)]; S1[i0, i1] -> [(i0)] }]" + options: "[n] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/yosr2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/yosr2.c @@ -0,0 +1,13 @@ +{ + for (int c1 = 1; c1 <= M; c1 += 1) + S2(c1); + for (int c0 = 2; c0 <= M; c0 += 1) { + for (int c2 = 1; c2 < c0; c2 += 1) + S1(c0, c2); + for (int c1 = 1; c1 < c0; c1 += 1) + S4(c1, c0); + for (int c2 = c0 + 1; c2 <= M; c2 += 1) + for (int c3 = 1; c3 < c0; c3 += 1) + S3(c0, c2, c3); + } +} Index: contrib/isl/test_inputs/codegen/cloog/yosr2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/yosr2.st @@ -0,0 +1,6 @@ +domain: "[M] -> { S4[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M; S3[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M and i2 >= 1 and i2 <= -1 + i0; S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= -1 + i0; S2[i0] : i0 >= 1 and i0 <= M }" +child: + context: "[M] -> { [] : M >= 2 }" + child: + schedule: "[M] -> [{ S2[i0] -> [(0)]; S1[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i1)]; S3[i0, i1, i2] -> [(i0)] }]" + options: "[M] -> { separate[i0] }" Index: contrib/isl/test_inputs/codegen/cloog/youcef.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/youcef.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 <= 5; c0 += 1) { + S1(c0, c0); + for (int c1 = c0; c1 <= 5; c1 += 1) + S2(c0, c1); + S3(c0, 5); +} Index: contrib/isl/test_inputs/codegen/cloog/youcef.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/youcef.st @@ -0,0 +1,11 @@ +domain: "{ S2[i0, i1] : i0 >= 0 and i0 <= 5 and i1 >= i0 and i1 <= 5; S1[i0, i0] : i0 >= 0 and i0 <= 5; S3[i0, 5] : i0 >= 0 and i0 <= 5 }" +child: + context: "{ [] }" + child: + schedule: "[{ S3[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S3[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]" + options: "{ separate[i0] }" + child: + sequence: + - filter: "{ S1[i0, i1] }" + - filter: "{ S2[i0, i1] }" + - filter: "{ S3[i0, i1] }" Index: contrib/isl/test_inputs/codegen/cloog/youcefn.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/youcefn.c @@ -0,0 +1,10 @@ +{ + for (int c0 = 1; c0 <= n; c0 += 1) { + S1(c0, c0); + for (int c1 = c0; c1 <= n; c1 += 1) + S2(c0, c1); + S3(c0, n); + } + for (int c0 = n + 1; c0 <= m; c0 += 1) + S3(c0, n); +} Index: contrib/isl/test_inputs/codegen/cloog/youcefn.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/cloog/youcefn.st @@ -0,0 +1,11 @@ +domain: "[n, m] -> { S1[i0, i0] : i0 >= 1 and i0 <= n; S3[i0, n] : i0 >= 1 and i0 <= m; S2[i0, i1] : i0 >= 1 and i0 <= n and i1 >= i0 and i1 <= n }" +child: + context: "[n, m] -> { [] : n >= 2 and m >= n }" + child: + schedule: "[n, m] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)] }]" + options: "[n, m] -> { separate[i0] }" + child: + sequence: + - filter: "[n, m] -> { S1[i0, i1] }" + - filter: "[n, m] -> { S2[i0, i1] }" + - filter: "[n, m] -> { S3[i0, i1] }" Index: contrib/isl/test_inputs/codegen/component0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component0.c @@ -0,0 +1,5 @@ +{ + A(); + for (int c0 = 0; c0 <= 9; c0 += 1) + B(c0); +} Index: contrib/isl/test_inputs/codegen/component0.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component0.st @@ -0,0 +1,3 @@ +domain: "{ A[]; B[i] : 0 <= i < 10 }" +child: + schedule: "[{ A[] -> [0]; B[i] -> [i] }]" Index: contrib/isl/test_inputs/codegen/component1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component1.c @@ -0,0 +1,5 @@ +{ + A(); + for (int c0 = 0; c0 <= 9; c0 += 1) + B(c0); +} Index: contrib/isl/test_inputs/codegen/component1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component1.st @@ -0,0 +1,7 @@ +domain: "{ A[]; B[i] : 0 <= i < 10 }" +child: + schedule: "[{ A[] -> [0]; B[i] -> [i] }]" + child: + sequence: + - filter: "{ A[] }" + - filter: "{ B[i] }" Index: contrib/isl/test_inputs/codegen/component2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component2.c @@ -0,0 +1,5 @@ +for (int c0 = 0; c0 <= 9; c0 += 1) { + B(c0); + if (c0 == 0) + A(); +} Index: contrib/isl/test_inputs/codegen/component2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component2.st @@ -0,0 +1,7 @@ +domain: "{ A[]; B[i] : 0 <= i < 10 }" +child: + schedule: "[{ A[] -> [0]; B[i] -> [i] }]" + child: + sequence: + - filter: "{ B[i] }" + - filter: "{ A[] }" Index: contrib/isl/test_inputs/codegen/component3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component3.c @@ -0,0 +1,5 @@ +{ + A(); + for (int c0 = 0; c0 <= 9; c0 += 1) + B(c0); +} Index: contrib/isl/test_inputs/codegen/component3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component3.st @@ -0,0 +1,7 @@ +domain: "{ A[]; B[i] : 0 <= i < 10 }" +child: + schedule: "[{ A[] -> [0]; B[i] -> [i] }]" + child: + set: + - filter: "{ B[i] }" + - filter: "{ A[] }" Index: contrib/isl/test_inputs/codegen/component4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component4.c @@ -0,0 +1,7 @@ +{ + for (int c1 = 0; c1 <= 9; c1 += 1) + A(c1); + for (int c0 = 0; c0 <= 9; c0 += 1) + for (int c2 = 0; c2 <= 9; c2 += 1) + B(c0, c2); +} Index: contrib/isl/test_inputs/codegen/component4.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component4.st @@ -0,0 +1,7 @@ +domain: "{ A[i] : 0 <= i < 10; B[i,j] : 0 <= i,j < 10 }" +child: + schedule: "[{ A[i] -> [0]; B[i,j] -> [i] }]" + child: + sequence: + - filter: "{ A[i] }" + - filter: "{ B[i,j] }" Index: contrib/isl/test_inputs/codegen/component5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component5.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 <= 9; c0 += 1) + for (int c1 = 0; c1 <= 9; c1 += 1) { + if (c0 == 0) + A(c1); + B(c0, c1); + } Index: contrib/isl/test_inputs/codegen/component5.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component5.st @@ -0,0 +1,9 @@ +domain: "{ A[i] : 0 <= i < 10; B[i,j] : 0 <= i,j < 10 }" +child: + schedule: "[{ A[i] -> [0]; B[i,j] -> [i] }]" + child: + schedule: "[{ A[i] -> [i]; B[i,j] -> [j] }]" + child: + sequence: + - filter: "{ A[i] }" + - filter: "{ B[i,j] }" Index: contrib/isl/test_inputs/codegen/component6.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component6.c @@ -0,0 +1,5 @@ +{ + A(); + for (int c0 = 0; c0 <= 9; c0 += 1) + B(c0); +} Index: contrib/isl/test_inputs/codegen/component6.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/component6.st @@ -0,0 +1,10 @@ +# Check that components are still detected in presence of nested context node +domain: "{ A[]; B[i] : 0 <= i < 10 }" +child: + schedule: "[{ A[] -> [0]; B[i] -> [i] }]" + child: + context: "[n] -> { [i] : 0 <= n <= i }" + child: + sequence: + - filter: "{ A[] }" + - filter: "{ B[i] }" Index: contrib/isl/test_inputs/codegen/correlation.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/correlation.c @@ -0,0 +1,45 @@ +for (int c0 = 0; c0 < m; c0 += 32) + for (int c1 = (n >= 32 && m >= c0 + 2) || (m == 1 && c0 == 0) ? 0 : 32 * n - 32 * floord(31 * n + 31, 32); c1 <= ((n <= -1 && c0 == 0) || (m == 1 && n >= 0 && c0 == 0) ? max(0, n - 1) : n); c1 += 32) + for (int c2 = c0; c2 <= (m >= 2 && c0 + 31 >= m && n >= c1 && c1 + 31 >= n ? 2 * m - 3 : (m >= 2 * c0 + 63 && c1 <= -32 && n >= c1 && c1 + 31 >= n) || (m >= c0 + 32 && 2 * c0 + 62 >= m && n >= c1 && c1 + 31 >= n) || (n >= 0 && c0 >= 32 && m >= 2 * c0 + 63 && c1 == n) || (m >= 63 && n >= 32 && c0 == 0 && c1 == n) ? 2 * c0 + 61 : m - 1); c2 += 32) { + if (n >= c1 + 32 && c1 >= 0 && 2 * c0 >= c2 + 32) { + for (int c4 = 0; c4 <= 31; c4 += 1) + for (int c5 = max(0, c0 - c2 + 1); c5 <= min(31, m - c2 - 1); c5 += 1) + S_27(c0, c2 + c5, c1 + c4); + } else if (c0 >= 32 && c1 >= 0 && c2 >= 2 * c0) { + for (int c4 = 0; c4 <= min(31, n - c1 - 1); c4 += 1) + for (int c5 = 0; c5 <= min(31, m - c2 - 1); c5 += 1) + S_27(c0, c2 + c5, c1 + c4); + } else if (c0 == 0 && c1 >= 0) { + for (int c4 = 0; c4 <= min(31, n - c1 - 1); c4 += 1) + for (int c5 = 0; c5 <= min(31, m - c2 - 1); c5 += 1) { + if (c1 == 0 && c4 == 0) + S_14(c2 + c5); + S_19(c1 + c4, c2 + c5); + if (c2 + c5 >= 1) + S_27(0, c2 + c5, c1 + c4); + } + } + if (c1 >= 0) { + for (int c3 = 1; c3 <= min(31, (c2 / 2) - c0); c3 += 1) + for (int c4 = 0; c4 <= min(31, n - c1 - 1); c4 += 1) + for (int c5 = 0; c5 <= min(31, m - c2 - 1); c5 += 1) + S_27(c0 + c3, c2 + c5, c1 + c4); + if (n >= c1 + 32) { + for (int c3 = max(1, (c2 / 2) - c0 + 1); c3 <= min(min(31, m - c0 - 2), -c0 + c2 + 30); c3 += 1) + for (int c4 = 0; c4 <= 31; c4 += 1) + for (int c5 = max(0, c0 - c2 + c3 + 1); c5 <= min(31, m - c2 - 1); c5 += 1) + S_27(c0 + c3, c2 + c5, c1 + c4); + } else if (n <= 0 && c0 == 0 && c1 == 0) { + for (int c5 = 0; c5 <= min(31, m - c2 - 1); c5 += 1) + S_14(c2 + c5); + } + } + if (n >= c1 && c1 + 31 >= n) + for (int c3 = max(0, (c2 / 2) - c0 + 1); c3 <= min(31, m - c0 - 1); c3 += 1) { + for (int c4 = max(0, -c1); c4 < n - c1; c4 += 1) + for (int c5 = max(0, c0 - c2 + c3 + 1); c5 <= min(31, m - c2 - 1); c5 += 1) + S_27(c0 + c3, c2 + c5, c1 + c4); + for (int c5 = max(0, c0 - c2 + c3); c5 <= min(31, 2 * c0 - c2 + 2 * c3 - 1); c5 += 1) + S_29(-c0 + c2 - c3 + c5, c0 + c3); + } + } Index: contrib/isl/test_inputs/codegen/correlation.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/correlation.st @@ -0,0 +1,18 @@ +domain: "[m, n] -> { S_14[j] : 0 <= j < m; S_19[i, j] : 0 <= i < n and 0 <= j < m; S_27[i, j, k] : i >= 0 and i < j < m and 0 <= k < n; S_29[i, j] : i >= 0 and i < j < m }" +child: + context: "[m, n] -> { [] : 0 < m <= 2147483647 and -2147483648 <= n <= 2147483647 }" + child: + schedule: "[m, n] -> [{ S_19[i, j] -> [(0)]; S_29[i, j] -> [(32*floor((j)/32))]; S_27[i, j, k] -> [(32*floor((i)/32))]; S_14[j] -> [(0)] }, { S_19[i, j] -> [(32*floor((i)/32))]; S_29[i, j] -> [(32*floor((n)/32))]; S_27[i, j, k] -> [(32*floor((k)/32))]; S_14[j] -> [(0)] }, { S_19[i, j] -> [(32*floor((j)/32))]; S_29[i, j] -> [(32*floor((i + j)/32))]; S_27[i, j, k] -> [(32*floor((j)/32))]; S_14[j] -> [(32*floor((j)/32))] }]" + permutable: 1 + coincident: [ 1, 1, 1 ] + options: "{ atomic[i0] : 0 <= i0 <= 2 }" + child: + schedule: "[m, n] -> [{ S_19[i, j] -> [(0)]; S_29[i, j] -> [(j - 32*floor((j)/32))]; S_27[i, j, k] -> [(i - 32*floor((i)/32))]; S_14[j] -> [(0)] }, { S_19[i, j] -> [(i - 32*floor((i)/32))]; S_29[i, j] -> [(n - 32*floor((n)/32))]; S_27[i, j, k] -> [(k - 32*floor((k)/32))]; S_14[j] -> [(0)] }, { S_19[i, j] -> [(j - 32*floor((j)/32))]; S_29[i, j] -> [(i + j - 32*floor((i + j)/32))]; S_27[i, j, k] -> [(j - 32*floor((j)/32))]; S_14[j] -> [(j - 32*floor((j)/32))] }]" + permutable: 1 + coincident: [ 1, 1, 1 ] + child: + sequence: + - filter: "[m, n] -> { S_29[i, j] }" + - filter: "[m, n] -> { S_14[j] }" + - filter: "[m, n] -> { S_19[i, j] }" + - filter: "[m, n] -> { S_27[i, j, k] }" Index: contrib/isl/test_inputs/codegen/disjuncts.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/disjuncts.c @@ -0,0 +1,10 @@ +for (int c0 = 0; c0 <= n; c0 += 1) + for (int c1 = 0; c1 <= n; c1 += 1) + if (c1 == n || c0 == n || c1 == 0 || c0 == 0) { + for (int c3 = 0; c3 <= n; c3 += 1) + for (int c4 = 0; c4 <= n; c4 += 1) + a(c0, c1, c3, c4); + for (int c3 = 0; c3 <= n; c3 += 1) + for (int c4 = 0; c4 <= n; c4 += 1) + b(c0, c1, c3, c4); + } Index: contrib/isl/test_inputs/codegen/disjuncts.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/disjuncts.in @@ -0,0 +1,7 @@ +# Check that conditions are hoisted up from the innermost loop +[n] -> { a[i,j,k,l] -> [i,j,0,k,l] : + 0 <= i,j,k,l <= n and (i = 0 or j = 0 or i = n or j = n); + b[i,j,k,l] -> [i,j,1,k,l] : + 0 <= i,j,k,l <= n and (i = 0 or j = 0 or i = n or j = n) } +{ : } +{ [i,j,t,k,l] -> atomic[x] } Index: contrib/isl/test_inputs/codegen/disjuncts2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/disjuncts2.c @@ -0,0 +1,3 @@ +if (P >= Q + 1 || Q >= P + 1) + for (int c0 = 0; c0 < N; c0 += 1) + S(c0); Index: contrib/isl/test_inputs/codegen/disjuncts2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/disjuncts2.st @@ -0,0 +1,4 @@ +# Check that the loop is generated only once with an outer disjunctive condition +domain: "[N, Q, P] -> { S[i0] : 0 <= i0 < N and (P > Q or P < Q) }" +child: + schedule: "[N, Q, P] -> [{ S[i0] -> [(i0)] }]" Index: contrib/isl/test_inputs/codegen/dwt.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/dwt.c @@ -0,0 +1,9 @@ +for (int c0 = 0; c0 < Ncl; c0 += 1) { + if (Ncl >= c0 + 2 && c0 >= 1) { + S(c0, 28); + } else if (c0 == 0) { + S(0, 26); + } else { + S(Ncl - 1, 27); + } +} Index: contrib/isl/test_inputs/codegen/dwt.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/dwt.in @@ -0,0 +1,3 @@ +[Ncl] -> { S[j, 28] -> [j] : j <= -2 + Ncl and Ncl <= 256 and Ncl >= 40 and j >= 1; S[0, 26] -> [0] : Ncl <= 256 and Ncl >= 40; S[-1 + Ncl, 27] -> [-1 + Ncl] : Ncl <= 256 and Ncl >= 40 } +[Ncl] -> { : Ncl >= 40 and Ncl <= 256 } +{ } Index: contrib/isl/test_inputs/codegen/empty.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/empty.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 <= 10; c0 += 1) { + S0(c0); + S1(c0); + if (c0 == 5) + S2(); +} Index: contrib/isl/test_inputs/codegen/empty.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/empty.in @@ -0,0 +1,5 @@ +# Earlier versions of isl would end up with an empty partial +# executed relation and fail to detect this emptiness. +[M] -> { S0[i] -> [i, -M] : 0 <= i <= 10; S1[i] -> [i, 0] : 0 <= i <= 10; S2[] -> [5, 0] } +[M] -> { : M >= 1 } +{ } Index: contrib/isl/test_inputs/codegen/filter.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/filter.c @@ -0,0 +1,9 @@ +if (n >= m + 1) { + for (int c0 = 0; c0 < n; c0 += 1) + for (int c2 = 0; c2 < n; c2 += 1) + A(c0, c2); +} else { + for (int c0 = 0; c0 < n; c0 += 1) + for (int c2 = 0; c2 < n; c2 += 1) + A(c0, c2); +} Index: contrib/isl/test_inputs/codegen/filter.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/filter.st @@ -0,0 +1,18 @@ +# Check proper handling of filters that turn out to be empty on their paths +domain: "[n,m] -> { A[i,j] : 0 <= i,j < n }" +child: + set: + - filter: "[n,m] -> { A[i,j] : m < n }" + child: + schedule: "[{ A[i,j] -> [i] }]" + child: + set: + - filter: "[n,m] -> { A[i,j] : m < n }" + - filter: "[n,m] -> { A[i,j] : m >= n }" + - filter: "[n,m] -> { A[i,j] : m >= n }" + child: + schedule: "[{ A[i,j] -> [i] }]" + child: + set: + - filter: "[n,m] -> { A[i,j] : m < n }" + - filter: "[n,m] -> { A[i,j] : m >= n }" Index: contrib/isl/test_inputs/codegen/gemm.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/gemm.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 < ni; c0 += 1) + for (int c1 = 0; c1 < nj; c1 += 1) { + S_2(c0, c1); + for (int c2 = 0; c2 < nk; c2 += 1) + S_4(c0, c1, c2); + } Index: contrib/isl/test_inputs/codegen/gemm.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/gemm.st @@ -0,0 +1,12 @@ +domain: "[ni, nj, nk] -> { S_4[i, j, k] : k <= -1 + nk and k >= 0 and j <= -1 + nj and j >= 0 and i <= -1 + ni and i >= 0; S_2[i, j] : j <= -1 + nj and j >= 0 and i <= -1 + ni and i >= 0 }" +child: + set: + - filter: "[ni, nj, nk] -> { S_4[i, j, k]; S_2[i, j] }" + child: + schedule: "[ni, nj, nk] -> [{ S_4[i, j, k] -> [(i)]; S_2[i, j] -> [(i)] }, { S_4[i, j, k] -> [(j)]; S_2[i, j] -> [(j)] }, { S_4[i, j, k] -> [(k)]; S_2[i, j] -> [(0)] }]" + permutable: 1 + coincident: [ 1, 1, 0 ] + child: + sequence: + - filter: "[ni, nj, nk] -> { S_2[i, j] }" + - filter: "[ni, nj, nk] -> { S_4[i, j, k] }" Index: contrib/isl/test_inputs/codegen/hoist.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/hoist.c @@ -0,0 +1,45 @@ +if (ni >= t0 + 1 && nj >= t1 + 1) + for (int c2 = 0; c2 <= min(15, nk - 1); c2 += 1) { + S_1(t0, t1, c2); + if (nj >= t1 + 17) { + S_1(t0, t1 + 16, c2); + if (nj >= t1 + 33) { + S_1(t0, t1 + 32, c2); + if (nj >= t1 + 49) + S_1(t0, t1 + 48, c2); + } + } + if (ni >= t0 + 17) { + S_1(t0 + 16, t1, c2); + if (nj >= t1 + 17) { + S_1(t0 + 16, t1 + 16, c2); + if (nj >= t1 + 33) { + S_1(t0 + 16, t1 + 32, c2); + if (nj >= t1 + 49) + S_1(t0 + 16, t1 + 48, c2); + } + } + if (ni >= t0 + 33) { + S_1(t0 + 32, t1, c2); + if (nj >= t1 + 17) { + S_1(t0 + 32, t1 + 16, c2); + if (nj >= t1 + 33) { + S_1(t0 + 32, t1 + 32, c2); + if (nj >= t1 + 49) + S_1(t0 + 32, t1 + 48, c2); + } + } + if (ni >= t0 + 49) { + S_1(t0 + 48, t1, c2); + if (nj >= t1 + 17) { + S_1(t0 + 48, t1 + 16, c2); + if (nj >= t1 + 33) { + S_1(t0 + 48, t1 + 32, c2); + if (nj >= t1 + 49) + S_1(t0 + 48, t1 + 48, c2); + } + } + } + } + } + } Index: contrib/isl/test_inputs/codegen/hoist.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/hoist.in @@ -0,0 +1,10 @@ +# check that the shared conditions ni >= t0 + 1 and nj >= t1 + 1 +# are hoisted out of the loop +[ni, nj, nk, t0, t1] -> { S_1[i, j, k] -> [t0, t1, k, i, j] : + exists (e0 = [(-t0 + i)/16], e1 = [(-t1 + j)/16]: + 16e0 = -t0 + i and 16e1 = -t1 + j and k >= 0 and j >= 0 and + j <= -1 + nj and i >= 0 and i <= -1 + ni and k <= -1 + nk and + ni >= 1 and nj >= 1 and nk >= 1 and j <= 63 and t1 >= 0 and + i <= 63 and k <= 15 and t0 >= 0 and t1 <= 15 and t0 <= 15) } +[t0, t1] -> { : 0 <= t0, t1 <= 15 } +{ [t0, t1, i5, i6, i7] -> unroll[x] : x >= 3} Index: contrib/isl/test_inputs/codegen/hoist2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/hoist2.c @@ -0,0 +1,5 @@ +for (int c0 = 1; c0 <= 5; c0 += 1) + if (c0 <= 3 || (b == 1 && t1 + c0 >= 10) || (t1 == 5 && b == 1 && c0 == 4)) + for (int c1 = t1 - 64 * b + 64; c1 <= min(70, -c0 + 73); c1 += 64) + if (c0 <= 3 || (t1 + c0 >= 10 && c1 == t1) || c1 == 5) + A(c0, 64 * b + c1 - 8); Index: contrib/isl/test_inputs/codegen/hoist2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/hoist2.in @@ -0,0 +1,5 @@ +# Check that the constraints hoisted from the inner loop +# do not end up involving the inner loop iterator. +[t1, b] -> { A[i1, i2] -> [i1, 8 - 64b + i2] : exists (e0, e1 = [(-8 + t1 - i2)/64]: 64e1 = -8 + t1 - i2 and i2 >= 1 and i2 <= 127 and 2e0 >= -3 + i1 and 2e0 >= -1 - i1 and 2e0 <= 8 - i1 and 2e0 <= 6 + i1 and 2e0 >= -65 - 64b + i2 and 2e0 >= -1 + 64b - i2 and e0 <= 1 and e0 >= 0 and 2e0 <= 62 + 64b - i2 and b <= 1 and b >= 0 and i1 >= 1 and i1 <= 2046 and t1 >= 5 and t1 <= 8) } +[t1, b] -> { : b >= 0 and b <= 1 and t1 >= 5 and t1 <= 8 } +[t1] -> { [i0, i1, i5, a] -> atomic[x]} Index: contrib/isl/test_inputs/codegen/isolate1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate1.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 0; c0 <= 3; c0 += 1) + A(c0); + for (int c0 = 4; c0 <= 6; c0 += 1) + A(c0); + for (int c0 = 7; c0 <= 99; c0 += 1) + A(c0); +} Index: contrib/isl/test_inputs/codegen/isolate1.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate1.st @@ -0,0 +1,5 @@ +# Check that the isolate option is adjusted by schedule space scaling +domain: "{ A[i] : 0 <= i < 100 }" +child: + schedule: "[{ A[i] -> [3i] }]" + options: "{ isolate[[] -> [x]] : 10 <= x <= 20 }" Index: contrib/isl/test_inputs/codegen/isolate2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate2.c @@ -0,0 +1,9 @@ +for (int c0 = 0; c0 <= 99; c0 += 1) { + if (c0 >= 4 && c0 <= 6) { + for (int c1 = 0; c1 <= 99; c1 += 1) + A(c0, c1); + } else { + for (int c1 = 0; c1 <= 99; c1 += 1) + A(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/isolate2.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate2.st @@ -0,0 +1,7 @@ +# Check that the isolate option is adjusted by schedule space scaling +domain: "{ A[i,j] : 0 <= i,j < 100 }" +child: + schedule: "[{ A[i,j] -> [3i] }]" + child: + schedule: "[{ A[i,j] -> [3j] }]" + options: "{ isolate[[x] -> [y]] : 10 <= x <= 20 }" Index: contrib/isl/test_inputs/codegen/isolate3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate3.c @@ -0,0 +1,17 @@ +{ + for (int c0 = 0; c0 <= 9; c0 += 1) + A(c0); + A(10); + A(11); + A(12); + A(13); + A(14); + A(15); + A(16); + A(17); + A(18); + A(19); + A(20); + for (int c0 = 21; c0 <= 99; c0 += 1) + A(c0); +} Index: contrib/isl/test_inputs/codegen/isolate3.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate3.st @@ -0,0 +1,5 @@ +# Check use of options specific to isolated part +domain: "{ A[i] : 0 <= i < 100 }" +child: + schedule: "[{ A[i] -> [i] }]" + options: "{ isolate[[] -> [x]] : 10 <= x <= 20; [isolate[] -> unroll[x]] }" Index: contrib/isl/test_inputs/codegen/isolate4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate4.c @@ -0,0 +1,13 @@ +{ + A(0); + A(1); + A(2); + A(3); + A(4); + for (int c0 = 5; c0 <= 15; c0 += 1) + A(c0); + A(16); + A(17); + A(18); + A(19); +} Index: contrib/isl/test_inputs/codegen/isolate4.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate4.st @@ -0,0 +1,5 @@ +# Check that generic options are not applied to isolated part +domain: "{ A[i] : 0 <= i < 20 }" +child: + schedule: "[{ A[i] -> [i] }]" + options: "{ isolate[[] -> [x]] : 5 <= x <= 15; unroll[x] }" Index: contrib/isl/test_inputs/codegen/isolate5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate5.c @@ -0,0 +1,29 @@ +{ + for (int c0 = 0; c0 <= 9; c0 += 1) { + if ((c0 + 1) % 2 == 0) { + for (int c1 = 0; c1 <= 1; c1 += 1) + B((c0 - 1) / 2, c1); + } else { + for (int c1 = 0; c1 <= 1; c1 += 1) + A(c0 / 2, c1); + } + } + for (int c0 = 10; c0 <= 89; c0 += 1) { + if ((c0 + 1) % 2 == 0) { + for (int c1 = 0; c1 <= 1; c1 += 1) + B((c0 - 1) / 2, c1); + } else { + for (int c1 = 0; c1 <= 1; c1 += 1) + A(c0 / 2, c1); + } + } + for (int c0 = 90; c0 <= 199; c0 += 1) { + if ((c0 + 1) % 2 == 0) { + for (int c1 = 0; c1 <= 1; c1 += 1) + B((c0 - 1) / 2, c1); + } else { + for (int c1 = 0; c1 <= 1; c1 += 1) + A(c0 / 2, c1); + } + } +} Index: contrib/isl/test_inputs/codegen/isolate5.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate5.st @@ -0,0 +1,5 @@ +# Check that use of isolate option prevents shifted stride detection +domain: "{ A[i,j] : 0 <= i < 100 and 0 <= j < 2; B[i,j] : 0 <= i < 100 and 0 <= j < 2 }" +child: + schedule: "[{ A[i,j] -> [2i]; B[i,j] -> [2i+1] }, { A[i,j] -> [j]; B[i,j] -> [j]}]" + options: "{ isolate[[] -> [x, y]] : 10 <= x < 90 }" Index: contrib/isl/test_inputs/codegen/isolate6.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate6.c @@ -0,0 +1,26 @@ +{ + for (int c0 = 0; c0 <= 8; c0 += 1) { + for (int c1 = 0; c1 <= -c0 + 8; c1 += 1) + for (int c2 = 10 * c0; c2 <= 10 * c0 + 9; c2 += 1) { + A(c2, 10 * c1); + A(c2, 10 * c1 + 1); + A(c2, 10 * c1 + 2); + A(c2, 10 * c1 + 3); + A(c2, 10 * c1 + 4); + A(c2, 10 * c1 + 5); + A(c2, 10 * c1 + 6); + A(c2, 10 * c1 + 7); + A(c2, 10 * c1 + 8); + A(c2, 10 * c1 + 9); + } + for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); + } + for (int c0 = 9; c0 <= 10; c0 += 1) + for (int c1 = 0; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); +} Index: contrib/isl/test_inputs/codegen/isolate6.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate6.st @@ -0,0 +1,8 @@ +# Example from the manual +domain: "{ A[i,j] : 0 <= i,j and i + j <= 100 }" +child: + schedule: "[{ A[i,j] -> [floor(i/10)] }, \ + { A[i,j] -> [floor(j/10)] }, \ + { A[i,j] -> [i] }, { A[i,j] -> [j] }]" + options: "{ isolate[[] -> [a,b,c,d]] : 0 <= 10a,10b and \ + 10a+9+10b+9 <= 100; [isolate[] -> unroll[3]] }" Index: contrib/isl/test_inputs/codegen/isolate7.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate7.c @@ -0,0 +1,29 @@ +{ + for (int c0 = 0; c0 < n - 31; c0 += 32) + for (int c1 = 0; c1 <= n; c1 += 32) { + if (n >= c1 + 32) { + for (int c2 = 0; c2 <= 31; c2 += 1) + for (int c3 = 0; c3 <= 31; c3 += 1) + S_1(c0 + c2, c1 + c3); + } else { + for (int c2 = 0; c2 <= 31; c2 += 1) { + for (int c3 = 0; c3 < n - c1; c3 += 1) + S_1(c0 + c2, c1 + c3); + S_2(c0 + c2); + } + } + } + for (int c1 = 0; c1 < n; c1 += 32) { + if (n >= c1 + 32) { + for (int c2 = 0; c2 < (n + 32) % 32; c2 += 1) + for (int c3 = 0; c3 <= 31; c3 += 1) + S_1(-((n + 32) % 32) + n + c2, c1 + c3); + } else { + for (int c2 = 0; c2 < n - c1; c2 += 1) { + for (int c3 = 0; c3 < n - c1; c3 += 1) + S_1(c1 + c2, c1 + c3); + S_2(c1 + c2); + } + } + } +} Index: contrib/isl/test_inputs/codegen/isolate7.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/isolate7.st @@ -0,0 +1,16 @@ +# Check that no expressions of the form ((-n + 2147483648) % 32) are produced. +domain: "[n] -> { S_2[i] : i >= 0 and i <= -1 + n; S_1[i, j] : j >= 0 and j <= -1 + n and i >= 0 and i <= -1 + n }" +child: + context: "[n] -> { [] : n <= 2147483647 and n >= 0 }" + child: + schedule: "[n] -> [{ S_1[i, j] -> [(32*floor((i)/32))]; S_2[i] -> [(32*floor((i)/32))] }, { S_1[i, j] -> [(32*floor((j)/32))]; S_2[i] -> [(32*floor((n)/32))] }]" + permutable: 1 + options: "[n] -> { atomic[i0] : i0 >= 0 and i0 <= 1; isolate[[] -> [i0, i1]] : (exists (e0 = floor((i0)/32), e1 = floor((i1)/32): 32e0 = i0 and 32e1 = i1 and i0 >= 0 and i0 <= -32 + n and i1 >= 0 and i1 <= n)) or (exists (e0 = floor((i0)/32), e1 = floor((i1)/32): 32e0 = i0 and 32e1 = i1 and i0 >= 0 and i0 <= -32 + n and i1 >= -31 + n and i1 <= -31 + 2n)) }" + child: + schedule: "[n] -> [{ S_1[i, j] -> [(i - 32*floor((i)/32))]; S_2[i] -> [(i - 32*floor((i)/32))] }, { S_1[i, j] -> [(j - 32*floor((j)/32))]; S_2[i] -> [(n - 32*floor((n)/32))] }]" + permutable: 1 + options: "{ separate[i0] : i0 >= 0 and i0 <= 1 }" + child: + sequence: + - filter: "[n] -> { S_1[i, j] }" + - filter: "[n] -> { S_2[i] }" Index: contrib/isl/test_inputs/codegen/jacobi_kernel4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/jacobi_kernel4.c @@ -0,0 +1,2 @@ +if (8 * a + 64 * b >= t0 + 2 * t + 512 * floord(-t0 - 8 * a + 64 * b + 2 * t - 1, 512) + 512 && t0 + 512 * floord(-t0 - 8 * a + 64 * b + 2 * t - 1, 512) >= -511 && t0 + 512 * floord(-t0 - 8 * a + 64 * b + 2 * t - 1, 512) <= 1310206) + S_0(t, -((-t0 - 8 * a + 64 * b + 2 * t + 511) % 512) - 8 * a + 64 * b + 2 * t + 511); Index: contrib/isl/test_inputs/codegen/jacobi_kernel4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/jacobi_kernel4.in @@ -0,0 +1,4 @@ +# Check that an affine value is extracted for the final dimension +[t0,a,b,t] -> { S_0[t, i] -> [i, t0] : exists (e0 = [(t0 - i)/512]: 512e0 = t0 - i and 64b >= 2t + i - 8a and 64b <= -2t + i + 8a and 4a <= 3 + t and 4a >= t and t >= 0 and t <= 1999 and i >= 1 and i <= 1310718 and a >= 0 and a <= 500 and 8b <= 163839 + a and b <= 20480 and 8b >= 1 - a and b >= 0 and 32b <= 655359 - t + 4a and 32b >= 1 + t - 4a and t0 >= 0 and t0 <= 511) } +[t0,a,b,t] -> { : t <= -1 + 4a + 32b and t >= 0 and t <= 4a and t >= -3 + 4a and t <= 1999 and t <= 655359 + 4a - 32b and t0 >= 0 and t0 <= 511 } +[t0] -> { } Index: contrib/isl/test_inputs/codegen/lu.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/lu.c @@ -0,0 +1,18 @@ +for (int c0 = 0; c0 < n - 1; c0 += 32) + for (int c1 = c0; c1 < n; c1 += 32) + for (int c2 = c0; c2 < n; c2 += 32) { + if (c1 >= c0 + 32) { + for (int c3 = c0; c3 <= min(c0 + 31, c2 + 30); c3 += 1) + for (int c4 = c1; c4 <= min(n - 1, c1 + 31); c4 += 1) + for (int c5 = max(c2, c3 + 1); c5 <= min(n - 1, c2 + 31); c5 += 1) + S_6(c3, c4, c5); + } else { + for (int c3 = c0; c3 <= min(min(n - 2, c0 + 31), c2 + 30); c3 += 1) { + for (int c5 = max(c2, c3 + 1); c5 <= min(n - 1, c2 + 31); c5 += 1) + S_2(c3, c5); + for (int c4 = c3 + 1; c4 <= min(n - 1, c0 + 31); c4 += 1) + for (int c5 = max(c2, c3 + 1); c5 <= min(n - 1, c2 + 31); c5 += 1) + S_6(c3, c4, c5); + } + } + } Index: contrib/isl/test_inputs/codegen/lu.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/lu.in @@ -0,0 +1,4 @@ +# Check that the stride of the second loop is properly detected +[n] -> { S_2[k, j] -> [o0, o0, o2, k, k, j, 1] : exists (e0 = floor((o2)/32), e1 = floor((o0)/32): 32e0 = o2 and 32e1 = o0 and o0 <= k and o0 >= -31 + k and k >= 0 and j <= -1 + n and o2 <= j and o2 >= -31 + j and j >= 1 + k); S_6[k, i, j] -> [o0, o1, o2, k, i, j, 0] : exists (e0 = floor((o0)/32), e1 = floor((o1)/32), e2 = floor((o2)/32): 32e0 = o0 and 32e1 = o1 and 32e2 = o2 and o0 <= k and o0 >= -31 + k and o1 <= i and o1 >= -31 + i and o2 <= j and o2 >= -31 + j and k >= 0 and i >= 1 + k and j <= -1 + n and j >= 1 + k and i <= -1 + n) } +{ : } +{ [a,b,c,d,e,f,g] -> atomic[x] : x < 3; [a,b,c,d,e,f,g] -> separate[x] : x >= 3 } Index: contrib/isl/test_inputs/codegen/mod.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/mod.c @@ -0,0 +1,2 @@ +if (2 * (n % 100) == 3 * (m % 200)) + A(); Index: contrib/isl/test_inputs/codegen/mod.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/mod.in @@ -0,0 +1,4 @@ +# check that modulo constraint is generated correctly +[n, m] -> { A[] -> [] : 2 * (n % 100) = 3 * (m % 200) } +[n, m] -> { : m, n >= 0 } +{} Index: contrib/isl/test_inputs/codegen/omega/README =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/README @@ -0,0 +1,5 @@ +The tests in this directory have been adapted from the corresponding omega+ +test cases. +The options have been derived semi-automatically and may not always +correspond to the intended meaning of the specified "effort" in the omega+ +test cases. Index: contrib/isl/test_inputs/codegen/omega/basics-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/basics-0.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 5; c0 <= 8; c0 += 1) + s0(c0); + for (int c0 = 10; c0 <= 16; c0 += 2) + s0(c0); + for (int c0 = 20; c0 <= 25; c0 += 1) + s0(c0); +} Index: contrib/isl/test_inputs/codegen/omega/basics-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/basics-0.in @@ -0,0 +1,3 @@ +{ s0[In_1] -> [In_1] : (In_1 >= 5 and In_1 <= 8) or (exists (e0 = [(In_1)/2]: 2e0 = In_1 and In_1 >= 10 and In_1 <= 16)) or (In_1 >= 20 and In_1 <= 25) } +{ : } +{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/basics-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/basics-1.c @@ -0,0 +1,3 @@ +for (int c0 = -9; c0 <= 9; c0 += 1) + for (int c1 = max(1, -c0 + 1); c1 <= min(10, -c0 + 10); c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/basics-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/basics-1.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : In_2 >= 1 - In_1 and In_2 >= 1 and In_2 <= 10 - In_1 and In_2 <= 10 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/chosol-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/chosol-0.c @@ -0,0 +1,9 @@ +{ + for (int c1 = 2; c1 <= n; c1 += 1) + s0(c1); + for (int c1 = 1; c1 < n; c1 += 1) { + for (int c3 = c1 + 1; c3 <= n; c3 += 1) + s1(c3, c1); + s2(c1 + 1); + } +} Index: contrib/isl/test_inputs/codegen/omega/chosol-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/chosol-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[i] -> [0, i, 0, 0] : i >= 2 and i <= n; s1[i, j] -> [1, j, 0, i] : j >= 1 and j <= -1 + i and i <= n; s2[i] -> [1, -1 + i, 1, 0] : i >= 2 and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/chosol-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/chosol-1.c @@ -0,0 +1,9 @@ +{ + for (int c1 = 2; c1 <= n; c1 += 1) + s0(c1); + for (int c1 = 1; c1 < n; c1 += 1) { + for (int c3 = c1 + 1; c3 <= n; c3 += 1) + s1(c3, c1); + s2(c1 + 1); + } +} Index: contrib/isl/test_inputs/codegen/omega/chosol-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/chosol-1.in @@ -0,0 +1,3 @@ +[n] -> { s0[i] -> [0, i, 0, 0] : i >= 2 and i <= n; s1[i, j] -> [1, j, 0, i] : j >= 1 and j <= -1 + i and i <= n; s2[i] -> [1, -1 + i, 1, 0] : i >= 2 and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/code_gen-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/code_gen-0.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 <= 8; c0 += 1) + for (int c1 = 0; c1 <= 7; c1 += 1) { + if (c0 >= 2 && c0 <= 6 && c1 <= 4) + s1(c0, c1); + if (c1 + 1 >= c0) + s0(c0, c1); + } Index: contrib/isl/test_inputs/codegen/omega/code_gen-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/code_gen-0.in @@ -0,0 +1,3 @@ +{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 6 and In_2 >= 0 and In_2 <= 4; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_2 >= -1 + In_1 and In_2 <= 7 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 1; [i0, i1] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/code_gen-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/code_gen-1.c @@ -0,0 +1,16 @@ +for (int c0 = 1; c0 <= 8; c0 += 1) { + if (c0 >= 2) { + if (c0 <= 6) + for (int c1 = 0; c1 < c0 - 1; c1 += 1) + s1(c0, c1); + for (int c1 = c0 - 1; c1 <= 4; c1 += 1) { + s1(c0, c1); + s0(c0, c1); + } + for (int c1 = max(5, c0 - 1); c1 <= 7; c1 += 1) + s0(c0, c1); + } else { + for (int c1 = 0; c1 <= 7; c1 += 1) + s0(1, c1); + } +} Index: contrib/isl/test_inputs/codegen/omega/code_gen-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/code_gen-1.in @@ -0,0 +1,3 @@ +{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 6 and In_2 >= 0 and In_2 <= 4; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_2 >= -1 + In_1 and In_2 <= 7 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/code_gen-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/code_gen-2.c @@ -0,0 +1,17 @@ +{ + for (int c1 = 0; c1 <= 7; c1 += 1) + s0(1, c1); + for (int c0 = 2; c0 <= 6; c0 += 1) { + for (int c1 = 0; c1 < c0 - 1; c1 += 1) + s1(c0, c1); + for (int c1 = c0 - 1; c1 <= 4; c1 += 1) { + s1(c0, c1); + s0(c0, c1); + } + for (int c1 = 5; c1 <= 7; c1 += 1) + s0(c0, c1); + } + for (int c0 = 7; c0 <= 8; c0 += 1) + for (int c1 = c0 - 1; c1 <= 7; c1 += 1) + s0(c0, c1); +} Index: contrib/isl/test_inputs/codegen/omega/code_gen-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/code_gen-2.in @@ -0,0 +1,3 @@ +{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 6 and In_2 >= 0 and In_2 <= 4; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_2 >= -1 + In_1 and In_2 <= 7 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= -1; [i0, i1] -> separate[o0] : o0 >= 0 } Index: contrib/isl/test_inputs/codegen/omega/collard-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/collard-0.c @@ -0,0 +1,16 @@ +{ + for (int c4 = 1; c4 <= n; c4 += 1) + s2(c4); + for (int c1 = 1; c1 < n; c1 += 1) { + for (int c4 = 0; c4 < n - c1; c4 += 1) + s0(c1, n - c4); + for (int c3 = 0; c3 < n - c1; c3 += 1) + for (int c4 = c1 + 1; c4 <= n; c4 += 1) + s1(c1, n - c3, c4); + } + for (int c1 = 1; c1 <= n; c1 += 1) { + s4(c1); + for (int c3 = c1 + 1; c3 <= n; c3 += 1) + s3(c3, c1); + } +} Index: contrib/isl/test_inputs/codegen/omega/collard-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/collard-0.in @@ -0,0 +1,3 @@ +[n] -> { s1[i, j, k] -> [1, i, 1, n - j, k] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n; s2[i] -> [0, 0, 0, 0, i] : i >= 1 and i <= n; s4[i] -> [2, i, 0, 0, 0] : i >= 1 and i <= n; s0[i, j] -> [1, i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s3[i, j] -> [2, j, 1, i, j] : j >= 1 and j <= -1 + i and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 4; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 3 } Index: contrib/isl/test_inputs/codegen/omega/dagstuhl1-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/dagstuhl1-0.c @@ -0,0 +1,2 @@ +for (int c0 = 0; c0 <= 99; c0 += 1) + s0(c0 % 10, c0 / 10); Index: contrib/isl/test_inputs/codegen/omega/dagstuhl1-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/dagstuhl1-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [i + 10j] : i >= 0 and i <= 9 and j >= 0 and j <= 9 } +{ : } +{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/dagstuhl1-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/dagstuhl1-1.c @@ -0,0 +1,2 @@ +for (int c0 = 0; c0 <= 99; c0 += 1) + s0(c0, c0 % 10, c0 / 10); Index: contrib/isl/test_inputs/codegen/omega/dagstuhl1-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/dagstuhl1-1.in @@ -0,0 +1,3 @@ +{s0[p,i,j] -> [p,i,j] : 0 <= i,j <= 9 && p = i+10j} +{ : } +{ [p,i,j] -> separate[o0] : o0 >= 2; [p,i,j] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/fc1-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc1-0.c @@ -0,0 +1,7 @@ +for (int c0 = 0; c0 < n - 1; c0 += 1) { + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + s0(c0 + 1, n - c3); + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + for (int c6 = c0 + 2; c6 <= n; c6 += 1) + s1(c0 + 1, n - c3, c6); +} Index: contrib/isl/test_inputs/codegen/omega/fc1-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc1-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/fc1-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc1-1.c @@ -0,0 +1,17 @@ +{ + for (int c3 = 1; c3 <= n; c3 += 1) + s2(c3); + for (int c0 = 0; c0 < n - 1; c0 += 1) { + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + s0(c0 + 1, n - c3); + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + for (int c6 = c0 + 2; c6 <= n; c6 += 1) + s1(c0 + 1, n - c3, c6); + } + for (int c0 = n - 1; c0 < 2 * n - 1; c0 += 1) { + if (c0 >= n) + for (int c2 = -n + c0 + 2; c2 <= n; c2 += 1) + s3(c2, -n + c0 + 1); + s4(-n + c0 + 2); + } +} Index: contrib/isl/test_inputs/codegen/omega/fc1-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc1-1.in @@ -0,0 +1,3 @@ +[n] -> { s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n; s3[i, j] -> [-1 + n + j, 0, i, j] : j >= 1 and j <= -1 + i and i <= n; s4[i] -> [-2 + n + i, 1, 0, 0] : i >= 1 and i <= n; s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s2[i] -> [0, 0, 0, i] : i >= 1 and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/fc1-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc1-2.c @@ -0,0 +1,17 @@ +{ + for (int c3 = 1; c3 <= n; c3 += 1) + s2(c3); + for (int c0 = 0; c0 < n - 1; c0 += 1) { + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + s0(c0 + 1, n - c3); + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + for (int c6 = c0 + 2; c6 <= n; c6 += 1) + s1(c0 + 1, n - c3, c6); + } + for (int c0 = n - 1; c0 < 2 * n - 1; c0 += 1) { + if (c0 >= n) + for (int c2 = -n + c0 + 2; c2 <= n; c2 += 1) + s3(c2, -n + c0 + 1); + s4(-n + c0 + 2); + } +} Index: contrib/isl/test_inputs/codegen/omega/fc1-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc1-2.in @@ -0,0 +1,3 @@ +[n] -> { s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n; s3[i, j] -> [-1 + n + j, 0, i, j] : j >= 1 and j <= -1 + i and i <= n; s4[i] -> [-2 + n + i, 1, 0, 0] : i >= 1 and i <= n; s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s2[i] -> [0, 0, 0, i] : i >= 1 and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/fc2-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc2-0.c @@ -0,0 +1,7 @@ +for (int c0 = 0; c0 < n - 1; c0 += 1) { + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + s0(c0 + 1, n - c3); + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + for (int c6 = c0 + 2; c6 <= n; c6 += 1) + s1(c0 + 1, n - c3, c6); +} Index: contrib/isl/test_inputs/codegen/omega/fc2-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc2-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/fc2-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc2-1.c @@ -0,0 +1,17 @@ +{ + for (int c3 = 1; c3 <= n; c3 += 1) + s2(c3); + for (int c0 = 0; c0 < n - 1; c0 += 1) { + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + s0(c0 + 1, n - c3); + for (int c3 = 0; c3 < n - c0 - 1; c3 += 1) + for (int c6 = c0 + 2; c6 <= n; c6 += 1) + s1(c0 + 1, n - c3, c6); + } + for (int c0 = n - 1; c0 < 2 * n - 1; c0 += 1) { + if (c0 >= n) + for (int c2 = -n + c0 + 2; c2 <= n; c2 += 1) + s3(c2, -n + c0 + 1); + s4(-n + c0 + 2); + } +} Index: contrib/isl/test_inputs/codegen/omega/fc2-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/fc2-1.in @@ -0,0 +1,3 @@ +[n] -> { s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n; s3[i, j] -> [-1 + n + j, 0, i, j] : j >= 1 and j <= -1 + i and i <= n; s4[i] -> [-2 + n + i, 1, 0, 0] : i >= 1 and i <= n; s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s2[i] -> [0, 0, 0, i] : i >= 1 and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/floor_bound-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-0.c @@ -0,0 +1,2 @@ +for (int c0 = 4 * floord(m - 1, 12) + 4; c0 <= floord(n, 3); c0 += 4) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/floor_bound-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-0.in @@ -0,0 +1,3 @@ +[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(In_1)/4]: 4e0 = In_1 and 3In_1 >= m and 3In_1 <= n) } +{ : } +[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/floor_bound-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-1.c @@ -0,0 +1,2 @@ +for (int c0 = floord(m, 4); c0 <= n; c0 += 1) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/floor_bound-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-1.in @@ -0,0 +1,3 @@ +[m, n] -> { s0[In_1] -> [In_1] : 4In_1 >= -3 + m and In_1 <= n } +{ : } +[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/floor_bound-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-2.c @@ -0,0 +1,2 @@ +for (int c0 = 4 * floord(m, 4); c0 <= n; c0 += 1) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/floor_bound-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-2.in @@ -0,0 +1,3 @@ +[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(m)/4]: 4e0 <= m and 4e0 >= -3 + m and 4e0 <= In_1 and In_1 <= n) } +{ : } +[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/floor_bound-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-3.c @@ -0,0 +1,2 @@ +for (int c0 = 3 * floord(m, 3) + 4 * floord(m, 4); c0 <= n; c0 += 1) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/floor_bound-3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-3.in @@ -0,0 +1,3 @@ +[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(m)/3], e1 = [(m)/4]: 4e1 <= m and 3e0 <= m and 4e1 >= -3 + m and 3e0 >= -2 + m and In_1 <= n and 4e1 <= In_1 - 3e0) } +{ : } +[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/floor_bound-4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-4.c @@ -0,0 +1,3 @@ +if (n >= 3 * floord(n + 1, 3)) + for (int c0 = m; c0 <= 5 * floord(n + 1, 3); c0 += 1) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/floor_bound-4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-4.in @@ -0,0 +1,3 @@ +[n, m] -> { s0[In_1] -> [In_1] : exists (e0 = [(1 + n)/3]: In_1 >= m and 5e0 >= In_1 and 3e0 <= n and 3e0 >= -1 + n) } +{ : } +[n, m] -> { [i0] -> atomic[o0] : o0 <= -1; [i0] -> separate[o0] : o0 >= 0 } Index: contrib/isl/test_inputs/codegen/omega/floor_bound-5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-5.c @@ -0,0 +1,2 @@ +for (int c0 = 4 * floord(m, 32); c0 <= n; c0 += 1) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/floor_bound-5.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-5.in @@ -0,0 +1,3 @@ +[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(m)/32]: 32e0 <= m and 32e0 >= -31 + m and 4e0 <= In_1 and In_1 <= n) } +{ : } +[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/floor_bound-6.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-6.c @@ -0,0 +1,3 @@ +if (m >= 8 * floord(m + 1, 8)) + for (int c0 = 4 * floord(m + 1, 32); c0 <= n; c0 += 1) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/floor_bound-6.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/floor_bound-6.in @@ -0,0 +1,3 @@ +[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(1 + m)/8], e1 = [(e0)/4]: 8e0 <= m and 8e0 >= -6 + m and 4e1 <= In_1 and In_1 <= n and 32e1 <= 1 + m and 32e1 >= -30 + m) } +{ : } +[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/gc-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gc-0.c @@ -0,0 +1,2 @@ +for (int c0 = 2; c0 <= 8; c0 += 2) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/gc-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gc-0.in @@ -0,0 +1,3 @@ +{ s0[In_1] -> [In_1] : exists (e0 = [(In_1)/2]: 2e0 = In_1 and In_1 >= 2 and In_1 <= 8) } +{ : } +{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/ge-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ge-0.c @@ -0,0 +1,7 @@ +for (int c0 = 2; c0 <= n; c0 += 1) + for (int c1 = 1; c1 <= n; c1 += 1) { + for (int c3 = 1; c3 < min(c0, c1); c3 += 1) + s1(c3, c0, c1); + if (c0 >= c1 + 1) + s0(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/ge-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ge-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[k, i] -> [i, k, 1, 0] : k >= 1 and i >= 1 + k and i <= n; s1[k, i, j] -> [i, j, 0, k] : i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/ge-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ge-1.c @@ -0,0 +1,7 @@ +for (int c0 = 2; c0 <= n; c0 += 1) + for (int c1 = 1; c1 <= n; c1 += 1) { + for (int c3 = 1; c3 < min(c0, c1); c3 += 1) + s1(c3, c0, c1); + if (c0 >= c1 + 1) + s0(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/ge-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ge-1.in @@ -0,0 +1,3 @@ +[n] -> { s0[k, i] -> [i, k, 1, 0] : k >= 1 and i >= 1 + k and i <= n; s1[k, i, j] -> [i, j, 0, k] : i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/gist-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-0.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= n; c0 += 4) + for (int c1 = c0; c1 <= n; c1 += 3) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/gist-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/4], e1 = [(-3 - In_1 + 4In_2)/12]: 4e0 = -1 + In_1 and 12e1 = -3 - In_1 + 4In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/gist-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-1.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= n; c0 += 4) + for (int c1 = c0; c1 <= n; c1 += 8) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/gist-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-1.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/4], e1 = [(-In_1 + In_2)/8]: 4e0 = -1 + In_1 and 8e1 = -In_1 + In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/gist-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-2.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= n; c0 += 256) + for (int c1 = c0; c1 <= n; c1 += 8) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/gist-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-2.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/256], e1 = [(-1 + In_2)/8]: 256e0 = -1 + In_1 and 8e1 = -1 + In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/gist-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-3.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 < n; c0 += 4) + for (int c1 = c0 + 1; c1 <= n; c1 += 6) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/gist-3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-3.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/4], e1 = [(-1 - In_1 + In_2)/6]: 4e0 = -1 + In_1 and 6e1 = -1 - In_1 + In_2 and In_1 >= 1 and In_2 >= 1 + In_1 and In_2 <= n) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/gist-4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-4.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= n; c0 += 6) + for (int c1 = c0; c1 <= n; c1 += 4) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/gist-4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-4.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/6], e1 = [(-2 - In_1 + 3In_2)/12]: 6e0 = -1 + In_1 and 12e1 = -2 - In_1 + 3In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/gist-5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-5.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= n; c0 += 12) + for (int c1 = c0; c1 <= n; c1 += 8) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/gist-5.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/gist-5.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/12], e1 = [(-2 - In_1 + 3In_2)/24]: 12e0 = -1 + In_1 and 24e1 = -2 - In_1 + 3In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/guard1-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/guard1-0.c @@ -0,0 +1,2 @@ +if ((n - m - 1) % 3 == 0) + s0(n, m); Index: contrib/isl/test_inputs/codegen/omega/guard1-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/guard1-0.in @@ -0,0 +1,3 @@ +[n, m] -> { s0[n, m] -> [n, m] : exists (e0 = [(-2 - n + m)/3]: 3e0 = -2 - n + m) } +{ : } +[n, m] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/guard1-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/guard1-1.c @@ -0,0 +1,2 @@ +if ((n + m + 1) % 2 == 0) + s0(n, m); Index: contrib/isl/test_inputs/codegen/omega/guard1-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/guard1-1.in @@ -0,0 +1,3 @@ +[n, m] -> { s0[n, m] -> [n, m] : exists (e0 = [(-1 - n + m)/2]: 2e0 = -1 - n + m) } +{ : } +[n, m] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/hpf-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/hpf-0.c @@ -0,0 +1,4 @@ +if (P2 >= 0 && P2 <= 3 && P1 == P2) + for (int c0 = 0; c0 <= min(2, -P2 + 4); c0 += 1) + for (int c2 = (-P2 - c0 + 6) % 3; c2 <= 3; c2 += 3) + s0(c0, c0, c2, c2); Index: contrib/isl/test_inputs/codegen/omega/hpf-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/hpf-0.in @@ -0,0 +1,3 @@ +[P1, P2] -> { s0[In_1, In_1, In_3, In_3] -> [In_1, In_1, In_3, In_3] : exists (e0 = [(-2P2 - 2In_1 + In_3)/3]: P1 = P2 and 3e0 = -2P2 - 2In_1 + In_3 and P2 >= 0 and P2 <= 3 and In_1 <= 4 - P2 and In_1 >= 0 and In_1 <= 2 and In_3 >= 0 and In_3 <= 3) } +{ : } +[P2, P1] -> { [i0, i1, i2, i3] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/if_then-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-0.c @@ -0,0 +1,13 @@ +if (m <= 1) { + for (int c0 = 1; c0 <= n; c0 += 1) + for (int c1 = 1; c1 <= n; c1 += 1) + s2(c0, c1); +} else if (n >= m + 1) { + for (int c0 = 1; c0 <= n; c0 += 1) + for (int c1 = 1; c1 <= n; c1 += 1) + s0(c0, c1); +} else { + for (int c0 = 1; c0 <= n; c0 += 1) + for (int c1 = 1; c1 <= n; c1 += 1) + s1(c0, c1); +} Index: contrib/isl/test_inputs/codegen/omega/if_then-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-0.in @@ -0,0 +1,3 @@ +[n, m] -> { s2[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= n and In_2 >= 1 and In_2 <= n and m <= 1; s0[In_1, In_2] -> [In_1, In_2] : m >= 2 and m <= -1 + n and In_1 >= 1 and In_1 <= n and In_2 >= 1 and In_2 <= n; s1[In_1, In_2] -> [In_1, In_2] : In_1 <= n and In_2 <= n and m >= n and In_1 >= 1 and In_2 >= 1 and m >= 2 } +{ : } +[n, m] -> { [i0, i1] -> atomic[o0] : o0 <= 1; [i0, i1] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/if_then-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-1.c @@ -0,0 +1,9 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) { + if (n >= 2) + s0(c0); + for (int c1 = 1; c1 <= 100; c1 += 1) { + s2(c0, c1); + if (n >= 2) + s1(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/omega/if_then-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-1.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1] -> [In_1,0] : In_1 >= 1 and In_1 <= 100 and n >= 2; s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and n >= 2; s2[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 } +{ : } +[n] -> { [i0,i1] -> separate[o0] : o0 >= 2; [i0,i1] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/if_then-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-2.c @@ -0,0 +1,12 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) { + if (n >= 2) { + s0(c0); + for (int c1 = 1; c1 <= 100; c1 += 1) { + s2(c0, c1); + s1(c0, c1); + } + } else { + for (int c1 = 1; c1 <= 100; c1 += 1) + s2(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/omega/if_then-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-2.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1] -> [In_1,0] : In_1 >= 1 and In_1 <= 100 and n >= 2; s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and n >= 2; s2[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 } +{ : } +[n] -> { [i0,i1] -> separate[o0] : o0 >= 1; [i0,i1] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/if_then-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-3.c @@ -0,0 +1,13 @@ +if (n >= 2) { + for (int c0 = 1; c0 <= 100; c0 += 1) { + s0(c0); + for (int c1 = 1; c1 <= 100; c1 += 1) { + s2(c0, c1); + s1(c0, c1); + } + } +} else { + for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + s2(c0, c1); +} Index: contrib/isl/test_inputs/codegen/omega/if_then-3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-3.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1] -> [In_1,0] : In_1 >= 1 and In_1 <= 100 and n >= 2; s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and n >= 2; s2[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 } +{ : } +[n] -> { [i0,i1] -> separate[o0] : o0 >= 0; [i0,i1] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/if_then-4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-4.c @@ -0,0 +1,7 @@ +for (int c0 = 4; c0 <= 100; c0 += 4) { + for (int c1 = 1; c1 <= 100; c1 += 1) + s0(c0, c1); + if (c0 >= 8 && c0 <= 96) + for (int c1 = 10; c1 <= 100; c1 += 1) + s1(c0 + 2, c1); +} Index: contrib/isl/test_inputs/codegen/omega/if_then-4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-4.in @@ -0,0 +1,3 @@ +{ s1[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-2 + In_1)/4]: 4e0 = -2 + In_1 and In_1 >= 10 and In_1 <= 98 and In_2 >= 10 and In_2 <= 100); s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/4]: 4e0 = In_1 and In_1 >= 4 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100) } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 1; [i0, i1] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/if_then-5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-5.c @@ -0,0 +1,7 @@ +for (int c0 = 4; c0 <= 100; c0 += 4) { + for (int c1 = 1; c1 <= 100; c1 += 1) + s0(c0, c1); + if (c0 >= 8 && c0 <= 96) + for (int c1 = 10; c1 <= 100; c1 += 1) + s1(c0 + 2, c1); +} Index: contrib/isl/test_inputs/codegen/omega/if_then-5.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/if_then-5.in @@ -0,0 +1,3 @@ +{ s1[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-2 + In_1)/4]: 4e0 = -2 + In_1 and In_1 >= 10 and In_1 <= 98 and In_2 >= 10 and In_2 <= 100); s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/4]: 4e0 = In_1 and In_1 >= 4 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100) } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/iter1-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter1-0.c @@ -0,0 +1,2 @@ +for (int c0 = 2; c0 <= 9; c0 += 1) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/iter1-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter1-0.in @@ -0,0 +1,3 @@ +{ s0[In_1] -> [In_1] : In_1 >= 2 and In_1 <= 9 } +{ : } +{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/iter2-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter2-0.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= 10; c0 += 1) + for (int c1 = 10; c1 <= 100; c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/iter2-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter2-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 10 and In_2 >= 10 and In_2 <= 100 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/iter3-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter3-0.c @@ -0,0 +1,3 @@ +for (int c0 = 2; c0 <= 8; c0 += 1) + for (int c1 = c0 + 1; c1 <= 9; c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/iter3-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter3-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_2 >= 1 + In_1 and In_2 <= 9 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/iter4-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter4-0.c @@ -0,0 +1,3 @@ +for (int c0 = 2; c0 <= 9; c0 += 1) + for (int c1 = c0 + 1; c1 <= 2 * c0; c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/iter4-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter4-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_2 >= 1 + In_1 and In_2 <= 2In_1 and In_1 <= 9 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/iter5-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter5-0.c @@ -0,0 +1,3 @@ +for (int c0 = 2; c0 <= 9; c0 += 1) + for (int c1 = c0 + 1; c1 <= min(16, 2 * c0); c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/iter5-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter5-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_2 >= 1 + In_1 and In_2 <= 2In_1 and In_2 <= 16 and In_1 <= 9 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/iter6-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter6-0.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= 5; c0 += 1) + for (int c1 = 12; c1 <= 17; c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/iter6-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter6-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 5 and In_2 >= 12 and In_2 <= 17 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/iter6-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter6-1.c @@ -0,0 +1,2 @@ +for (int c0 = 46; c0 <= 70; c0 += 12) + s0(c0, (17 * c0 - 170) / 12); Index: contrib/isl/test_inputs/codegen/omega/iter6-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter6-1.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, o1] : 12In_2 = -170 + 17In_1 and 12o1 = -170 + 17In_1 and In_1 >= 46 and In_1 <= 70 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/iter7-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter7-0.c @@ -0,0 +1,2 @@ +for (int c0 = 1; c0 <= 3; c0 += 2) + s0(c0, (-3 * c0 + 15) / 2); Index: contrib/isl/test_inputs/codegen/omega/iter7-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter7-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, o1] : 2In_2 = 15 - 3In_1 and 2o1 = 15 - 3In_1 and In_1 <= 3 and In_1 >= 1 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/iter8-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter8-0.c @@ -0,0 +1,2 @@ +for (int c0 = max(exprVar2 + 1, exprVar2 + 8 * floord(-exprVar2 + exprVar1 - 1, 8) + 9); c0 <= 16; c0 += 8) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/iter8-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter8-0.in @@ -0,0 +1,3 @@ +[exprVar2, exprVar3, exprVar1] -> { s0[In_1] -> [In_1] : exists (e0 = [(-1 - exprVar2 + In_1)/8]: exprVar3 = 0 and 8e0 = -1 - exprVar2 + In_1 and exprVar1 >= 1 and In_1 >= 1 + exprVar1 and In_1 <= 16 and In_1 >= 1 + exprVar2) } +[exprVar3, exprVar2, exprVar1] -> { : exists (e0: exprVar3 = 0 and 8e0 >= -15 + exprVar2 and exprVar2 <= 15 and exprVar1 >= 1 and 8e0 <= exprVar2 - exprVar1) } +[exprVar2, exprVar3, exprVar1] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/iter9-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter9-0.c @@ -0,0 +1,11 @@ +for (int c0 = 1; c0 <= 15; c0 += 1) { + if (((-exprVar1 + 15) % 8) + c0 <= 15) { + s1(c0); + s3(c0); + s2(c0); + s0(c0); + s4(c0); + } + if (((-exprVar1 + 15) % 8) + c0 <= 15 || (exprVar1 - c0 + 1) % 8 == 0) + s5(c0); +} Index: contrib/isl/test_inputs/codegen/omega/iter9-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/iter9-0.in @@ -0,0 +1,3 @@ +[exprVar2, exprVar1] -> { s3[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1); s4[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1); s1[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1); s5[In_1] -> [In_1] : (exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1)) or (exists (e0 = [(-1 - exprVar1 + In_1)/8]: exprVar2 = 0 and 8e0 = -1 - exprVar1 + In_1 and In_1 >= 1 + exprVar1 and In_1 >= 1 and In_1 <= 15)); s0[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1); s2[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1) } +[exprVar2, exprVar1] -> { : exprVar2 = 0 and exprVar1 <= 15 } +[exprVar2, exprVar1] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/lefur00-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur00-0.c @@ -0,0 +1,5 @@ +for (int c0 = 0; c0 <= 15; c0 += 1) + for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1) + for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1) + for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1) + s0(c0, c1, c2, c3); Index: contrib/isl/test_inputs/codegen/omega/lefur00-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur00-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4] -> [In_1, In_2, In_3, In_4] : In_3 >= 1 and In_4 >= In_3 and In_4 <= 1 + 2In_3 and In_3 <= 1000 and In_4 >= 200In_1 - In_3 and In_4 <= 199 + 200In_1 - In_3 and 2In_4 >= 200In_2 + In_3 and 2In_4 <= 199 + 200In_2 + In_3 } +{ : } +{ [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/lefur01-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur01-0.c @@ -0,0 +1,5 @@ +for (int c0 = 0; c0 <= 15; c0 += 1) + for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1) + for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1) + for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1) + s0(c0, c1, c2, c3); Index: contrib/isl/test_inputs/codegen/omega/lefur01-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur01-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4] -> [In_1, In_2, In_3, In_4] : In_3 >= 1 and In_4 >= In_3 and In_4 <= 1 + 2In_3 and In_3 <= 1000 and In_4 >= 200In_1 - In_3 and In_4 <= 199 + 200In_1 - In_3 and 2In_4 >= 200In_2 + In_3 and 2In_4 <= 199 + 200In_2 + In_3 } +{ : } +{ [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/lefur01-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur01-1.c @@ -0,0 +1,5 @@ +for (int c0 = 0; c0 <= 15; c0 += 1) + for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1) + for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1) + for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1) + s0(c0, c1, c2, c3); Index: contrib/isl/test_inputs/codegen/omega/lefur01-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur01-1.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4] -> [In_1, In_2, In_3, In_4] : In_3 >= 1 and In_4 >= In_3 and In_4 <= 1 + 2In_3 and In_3 <= 1000 and In_4 >= 200In_1 - In_3 and In_4 <= 199 + 200In_1 - In_3 and 2In_4 >= 200In_2 + In_3 and 2In_4 <= 199 + 200In_2 + In_3 } +{ : } +{ [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/lefur03-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur03-0.c @@ -0,0 +1,7 @@ +for (int c0 = 0; c0 <= 3; c0 += 1) + for (int c1 = max(0, 2 * c0 - 3); c1 <= min(3, c0 + 1); c1 += 1) + for (int c2 = c0; c2 <= min(min(3, 2 * c0 - c1 + 1), 3 * c1 + 2); c2 += 1) + for (int c3 = max(max(max(0, c1 - (-c1 + 3) / 3), c0 - (-c2 + 3) / 3), c2 + floord(3 * c1 - c2 - 1, 6)); c3 <= min(3, c0 + 1); c3 += 1) + for (int c4 = max(max(max(max(-200 * c1 + 400 * c3 - 199, 250 * c3 + 1), 667 * c0 - 333 * c1 - (c0 + c1 + 3) / 3 - 332), 333 * c1 + c1 / 3), 333 * c2 + (c2 + 1) / 3); c4 <= min(min(min(min(1000, 500 * c0 + 499), -200 * c1 + 400 * c3 + 400), 333 * c2 - (-c2 + 3) / 3 + 333), 333 * c3 - (-c3 + 3) / 3 + 334); c4 += 1) + for (int c5 = max(max(max(c4, 1000 * c0 - c4), 1000 * c3 - 2 * c4 + 2), 500 * c1 + (c4 + 1) / 2); c5 <= min(min(min(2 * c4 + 1, 1000 * c0 - c4 + 999), 1000 * c3 - 2 * c4 + 1001), 500 * c1 + (c4 + 1) / 2 + 499); c5 += 1) + s0(c0, c1, c2, c3, c4, c5); Index: contrib/isl/test_inputs/codegen/omega/lefur03-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur03-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5, In_6] -> [In_1, In_2, In_3, In_4, In_5, In_6] : In_6 >= In_5 and In_6 <= 1 + 2In_5 and In_5 <= 1000 and In_6 >= 1000In_1 - In_5 and In_6 <= 999 + 1000In_1 - In_5 and In_6 >= 2 + 1000In_4 - 2In_5 and In_6 <= 1001 + 1000In_4 - 2In_5 and In_4 >= 0 and 2In_6 >= 1000In_2 + In_5 and 2In_6 <= 999 + 1000In_2 + In_5 and 3In_5 >= -1 + 1000In_3 and 3In_5 <= 998 + 1000In_3 } +{ : } +{ [i0, i1, i2, i3, i4, i5] -> separate[o0] : o0 >= 5; [i0, i1, i2, i3, i4, i5] -> atomic[o0] : o0 <= 4 } Index: contrib/isl/test_inputs/codegen/omega/lefur04-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur04-0.c @@ -0,0 +1,8 @@ +for (int c0 = 0; c0 <= 3; c0 += 1) + for (int c1 = max(0, 2 * c0 - 3); c1 <= min(c0 + 1, -c0 + 6); c1 += 1) + for (int c2 = c0; c2 <= min(min(3, 2 * c0 - c1 + 1), 3 * c1 + 2); c2 += 1) + for (int c3 = max(max(max(0, c1 - (-c1 + 3) / 3), c0 - (-c2 + 3) / 3), c2 + floord(3 * c1 - c2 - 1, 6)); c3 <= min(3, c0 + 1); c3 += 1) + for (int c5 = max(max(max(max(0, 2 * c3 - 4), c1 - (-c1 + 3) / 3), c2 - (c2 + 3) / 3), c3 - (c3 + 3) / 3); c5 <= min(min(c1 + 1, c3), -c2 + 2 * c3 - (c2 + 3) / 3 + 2); c5 += 1) + for (int c6 = max(max(max(max(max(-200 * c1 + 400 * c3 - 199, 250 * c3 + 1), 1000 * c0 - 500 * c5 - 501), 667 * c0 - 333 * c1 - (c0 + c1 + 3) / 3 - 332), 333 * c1 + c1 / 3), 333 * c2 + (c2 + 1) / 3); c6 <= min(min(min(min(min(min(1000, 500 * c0 + 499), -200 * c1 + 400 * c3 + 400), 500 * c5 + 501), 1000 * c0 - 500 * c5 + 997), 333 * c2 - (-c2 + 3) / 3 + 333), 333 * c3 - (-c3 + 3) / 3 + 334); c6 += 1) + for (int c7 = max(max(max(max(500 * c5 + 2, c6), 1000 * c0 - c6), 1000 * c3 - 2 * c6 + 2), 500 * c1 + (c6 + 1) / 2); c7 <= min(min(min(min(500 * c5 + 501, 2 * c6 + 1), 1000 * c0 - c6 + 999), 1000 * c3 - 2 * c6 + 1001), 500 * c1 + (c6 + 1) / 2 + 499); c7 += 1) + s0(c0, c1, c2, c3, c2 / 3, c5, c6, c7); Index: contrib/isl/test_inputs/codegen/omega/lefur04-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lefur04-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5, In_6, In_7, In_8] -> [In_1, In_2, In_3, In_4, In_5, In_6, In_7, In_8] : In_7 >= 1000In_5 and In_8 >= In_7 and In_8 <= 501 + 500In_6 and In_8 <= 1 + 2In_7 and In_7 <= 999 + 1000In_5 and In_7 <= 1000 and In_8 >= 1000In_1 - In_7 and In_8 <= 999 + 1000In_1 - In_7 and 2In_8 >= 1000In_2 + In_7 and 2In_8 <= 999 + 1000In_2 + In_7 and 3In_7 >= -1 + 1000In_3 and 3In_7 <= 998 + 1000In_3 and In_8 >= 2 + 500In_6 and In_6 >= 0 and In_8 >= 2 + 1000In_4 - 2In_7 and In_8 <= 1001 + 1000In_4 - 2In_7 } +{ : } +{ [i0, i1, i2, i3, i4, i5, i6, i7] -> atomic[o0] : o0 <= 6; [i0, i1, i2, i3, i4, i5, i6, i7] -> separate[o0] : o0 >= 7 } Index: contrib/isl/test_inputs/codegen/omega/lift1-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-0.c @@ -0,0 +1,9 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + if (c0 <= 60) + s0(c0, c1, c2, c3, c4); + } Index: contrib/isl/test_inputs/codegen/omega/lift1-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 5; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 4 } Index: contrib/isl/test_inputs/codegen/omega/lift1-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-1.c @@ -0,0 +1,14 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) { + if (c0 >= 61) { + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else { + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + } + } Index: contrib/isl/test_inputs/codegen/omega/lift1-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-1.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 4; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 3 } Index: contrib/isl/test_inputs/codegen/omega/lift1-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-2.c @@ -0,0 +1,15 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) { + if (c0 >= 61) { + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else { + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + } + } Index: contrib/isl/test_inputs/codegen/omega/lift1-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-2.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/lift1-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-3.c @@ -0,0 +1,16 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) { + if (c0 >= 61) { + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else { + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + } + } Index: contrib/isl/test_inputs/codegen/omega/lift1-3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-3.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 2; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/lift1-4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-4.c @@ -0,0 +1,17 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) { + if (c0 >= 61) { + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else { + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + } +} Index: contrib/isl/test_inputs/codegen/omega/lift1-4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-4.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 1; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/lift1-5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-5.c @@ -0,0 +1,16 @@ +{ + for (int c0 = 1; c0 <= 60; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + for (int c0 = 61; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); +} Index: contrib/isl/test_inputs/codegen/omega/lift1-5.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift1-5.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 0; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/lift2-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-0.c @@ -0,0 +1,9 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + if (c0 >= 5 && c0 <= 60) + s0(c0, c1, c2, c3, c4); + } Index: contrib/isl/test_inputs/codegen/omega/lift2-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 5; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 4 } Index: contrib/isl/test_inputs/codegen/omega/lift2-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-1.c @@ -0,0 +1,17 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) { + if (c0 >= 61) { + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else if (c0 <= 4) { + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else { + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + } + } Index: contrib/isl/test_inputs/codegen/omega/lift2-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-1.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 4; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 3 } Index: contrib/isl/test_inputs/codegen/omega/lift2-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-2.c @@ -0,0 +1,19 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) { + if (c0 >= 61) { + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else if (c0 <= 4) { + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else { + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + } + } Index: contrib/isl/test_inputs/codegen/omega/lift2-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-2.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/lift2-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-3.c @@ -0,0 +1,21 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) { + if (c0 >= 61) { + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else if (c0 <= 4) { + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else { + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + } + } Index: contrib/isl/test_inputs/codegen/omega/lift2-3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-3.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 2; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/lift2-4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-4.c @@ -0,0 +1,23 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) { + if (c0 >= 61) { + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else if (c0 <= 4) { + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + } else { + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + } +} Index: contrib/isl/test_inputs/codegen/omega/lift2-4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-4.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 1; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/lift2-5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-5.c @@ -0,0 +1,22 @@ +{ + for (int c0 = 1; c0 <= 4; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); + for (int c0 = 5; c0 <= 60; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) { + s1(c0, c1, c2, c3, c4); + s0(c0, c1, c2, c3, c4); + } + for (int c0 = 61; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + for (int c2 = 1; c2 <= 100; c2 += 1) + for (int c3 = 1; c3 <= 100; c3 += 1) + for (int c4 = 1; c4 <= 100; c4 += 1) + s1(c0, c1, c2, c3, c4); +} Index: contrib/isl/test_inputs/codegen/omega/lift2-5.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lift2-5.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 } +{ : } +{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 0; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/lu-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu-0.c @@ -0,0 +1,10 @@ +for (int c0 = 1; c0 < n; c0 += 64) + for (int c1 = c0 - 1; c1 <= n; c1 += 64) + for (int c2 = c0; c2 <= n; c2 += 1) { + for (int c3 = c0; c3 <= min(min(c0 + 63, c1 + 62), c2 - 1); c3 += 1) + for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s1(c3, c4, c2); + if (c0 + 63 >= c2) + for (int c4 = max(c1, c2 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s0(c2, c4); + } Index: contrib/isl/test_inputs/codegen/omega/lu-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu-0.in @@ -0,0 +1,3 @@ +[n] -> { s1[k, i, j] -> [t1, t2, j, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n); s0[k, i] -> [t1, t2, k, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and k >= 1 and i >= 1 + k and i <= n) } +{ : } +[n] -> { [t1, t2, i2, i3, i4] -> separate[o0] : o0 >= 5; [t1, t2, i2, i3, i4] -> atomic[o0] : o0 <= 4 } Index: contrib/isl/test_inputs/codegen/omega/lu-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu-1.c @@ -0,0 +1,10 @@ +for (int c0 = 1; c0 < n; c0 += 64) + for (int c1 = c0 - 1; c1 <= n; c1 += 64) + for (int c2 = c0; c2 <= n; c2 += 1) { + for (int c3 = c0; c3 <= min(min(c0 + 63, c1 + 62), c2 - 1); c3 += 1) + for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s1(c3, c4, c2); + if (c0 + 63 >= c2) + for (int c4 = max(c1, c2 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s0(c2, c4); + } Index: contrib/isl/test_inputs/codegen/omega/lu-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu-1.in @@ -0,0 +1,3 @@ +[n] -> { s1[k, i, j] -> [t1, t2, j, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n); s0[k, i] -> [t1, t2, k, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and k >= 1 and i >= 1 + k and i <= n) } +{ : } +[n] -> { [t1, t2, i2, i3, i4] -> separate[o0] : o0 >= 4; [t1, t2, i2, i3, i4] -> atomic[o0] : o0 <= 3 } Index: contrib/isl/test_inputs/codegen/omega/lu-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu-2.c @@ -0,0 +1,10 @@ +for (int c0 = 1; c0 < n; c0 += 64) + for (int c1 = c0 - 1; c1 <= n; c1 += 64) + for (int c2 = c0; c2 <= n; c2 += 1) { + for (int c3 = c0; c3 <= min(min(c0 + 63, c1 + 62), c2 - 1); c3 += 1) + for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s1(c3, c4, c2); + if (c0 + 63 >= c2) + for (int c4 = max(c1, c2 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s0(c2, c4); + } Index: contrib/isl/test_inputs/codegen/omega/lu-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu-2.in @@ -0,0 +1,3 @@ +[n] -> { s1[k, i, j] -> [t1, t2, j, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n); s0[k, i] -> [t1, t2, k, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and k >= 1 and i >= 1 + k and i <= n) } +{ : } +[n] -> { [t1, t2, i2, i3, i4] -> separate[o0] : o0 >= 3; [t1, t2, i2, i3, i4] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/lu-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu-3.c @@ -0,0 +1,14 @@ +for (int c0 = 1; c0 < n; c0 += 64) + for (int c1 = c0 - 1; c1 <= n; c1 += 64) { + for (int c2 = c0; c2 <= min(n, c0 + 63); c2 += 1) { + for (int c3 = c0; c3 <= min(c1 + 62, c2 - 1); c3 += 1) + for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s1(c3, c4, c2); + for (int c4 = max(c1, c2 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s0(c2, c4); + } + for (int c2 = c0 + 64; c2 <= n; c2 += 1) + for (int c3 = c0; c3 <= min(c0 + 63, c1 + 62); c3 += 1) + for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1) + s1(c3, c4, c2); + } Index: contrib/isl/test_inputs/codegen/omega/lu-3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu-3.in @@ -0,0 +1,3 @@ +[n] -> { s1[k, i, j] -> [t1, t2, j, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n); s0[k, i] -> [t1, t2, k, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and k >= 1 and i >= 1 + k and i <= n) } +{ : } +[n] -> { [t1, t2, i2, i3, i4] -> separate[o0] : o0 >= 2; [t1, t2, i2, i3, i4] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/lu_ijk-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_ijk-0.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 <= n; c0 += 1) + for (int c1 = 2; c1 <= n; c1 += 1) { + for (int c3 = 1; c3 < min(c0, c1); c3 += 1) + s1(c3, c1, c0); + if (c1 >= c0 + 1) + s0(c0, c1); + } Index: contrib/isl/test_inputs/codegen/omega/lu_ijk-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_ijk-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[k, j] -> [k, j, 1, 0] : k >= 1 and j >= 1 + k and j <= n; s1[k, j, i] -> [i, j, 0, k] : j >= 1 + k and i >= 1 + k and k >= 1 and j <= n and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/lu_ijk-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_ijk-1.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 <= n; c0 += 1) + for (int c1 = 2; c1 <= n; c1 += 1) { + for (int c3 = 1; c3 < min(c0, c1); c3 += 1) + s1(c3, c1, c0); + if (c1 >= c0 + 1) + s0(c0, c1); + } Index: contrib/isl/test_inputs/codegen/omega/lu_ijk-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_ijk-1.in @@ -0,0 +1,3 @@ +[n] -> { s0[k, j] -> [k, j, 1, 0] : k >= 1 and j >= 1 + k and j <= n; s1[k, j, i] -> [i, j, 0, k] : j >= 1 + k and i >= 1 + k and k >= 1 and j <= n and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/lu_ijk-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_ijk-2.c @@ -0,0 +1,11 @@ +if (n >= 2) + for (int c0 = 1; c0 <= n; c0 += 1) { + for (int c1 = 2; c1 <= c0; c1 += 1) + for (int c3 = 1; c3 < c1; c3 += 1) + s1(c3, c1, c0); + for (int c1 = c0 + 1; c1 <= n; c1 += 1) { + for (int c3 = 1; c3 < c0; c3 += 1) + s1(c3, c1, c0); + s0(c0, c1); + } + } Index: contrib/isl/test_inputs/codegen/omega/lu_ijk-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_ijk-2.in @@ -0,0 +1,3 @@ +[n] -> { s0[k, j] -> [k, j, 1, 0] : k >= 1 and j >= 1 + k and j <= n; s1[k, j, i] -> [i, j, 0, k] : j >= 1 + k and i >= 1 + k and k >= 1 and j <= n and i <= n } +{ : } +[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 0; [i0, i1, i2, i3] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/lu_spmd-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_spmd-0.c @@ -0,0 +1,13 @@ +if (ub >= lb) + for (int c0 = 1; c0 <= ub; c0 += 1) + for (int c1 = c0; c1 <= n; c1 += 1) { + if (c0 >= lb && c1 >= c0 + 1) { + s0(c0, c1); + if (n >= ub + 1) + s2(c0, c1); + } else if (lb >= c0 + 1) { + s3(c0, c1, lb, c0, c1); + } + for (int c3 = max(lb, c0); c3 <= ub; c3 += 1) + s1(c0, c1, c3); + } Index: contrib/isl/test_inputs/codegen/omega/lu_spmd-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_spmd-0.in @@ -0,0 +1,3 @@ +[n, lb, ub] -> { s1[k, i, j] -> [k, i, 1, j, 0, 0, 0, 0] : k >= 1 and j >= k and j <= n and j <= ub and i >= k and i <= n and j >= lb; s3[k, i, lb, k, i] -> [k, i, 1, lb, -1, k, i, 0] : k >= 1 and k <= -1 + lb and lb <= n and ub >= lb and i >= k and i <= n; s0[k, i] -> [k, i, 0, 0, 0, 0, 0, 0] : k >= 1 and k >= lb and i >= 1 + k and i <= n and k <= ub; s2[k, i] -> [k, i, 0, 0, 1, 0, 0, 0] : k >= 1 and k >= lb and k <= ub and ub <= -1 + n and i >= 1 + k and i <= n } +[lb, n, ub] -> { : ub <= n and lb >= 1 } +[n, lb, ub] -> { [i0, i1, i2, i3, i4, i5, i6, i7] -> atomic[o0] : o0 <= 7; [i0, i1, i2, i3, i4, i5, i6, i7] -> separate[o0] : o0 >= 8 } Index: contrib/isl/test_inputs/codegen/omega/lu_spmd-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_spmd-1.c @@ -0,0 +1,13 @@ +if (ub >= lb) + for (int c0 = 1; c0 <= ub; c0 += 1) + for (int c1 = c0; c1 <= n; c1 += 1) { + if (c0 >= lb && c1 >= c0 + 1) { + s0(c0, c1); + if (n >= ub + 1) + s2(c0, c1); + } else if (lb >= c0 + 1) { + s3(c0, c1, lb, c0, c1); + } + for (int c3 = max(lb, c0); c3 <= ub; c3 += 1) + s1(c0, c1, c3); + } Index: contrib/isl/test_inputs/codegen/omega/lu_spmd-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/lu_spmd-1.in @@ -0,0 +1,3 @@ +[n, lb, ub] -> { s1[k, i, j] -> [k, i, 1, j, 0, 0, 0, 0] : k >= 1 and j >= k and j <= n and j <= ub and i >= k and i <= n and j >= lb; s3[k, i, lb, k, i] -> [k, i, 1, lb, -1, k, i, 0] : k >= 1 and k <= -1 + lb and lb <= n and ub >= lb and i >= k and i <= n; s0[k, i] -> [k, i, 0, 0, 0, 0, 0, 0] : k >= 1 and k >= lb and i >= 1 + k and i <= n and k <= ub; s2[k, i] -> [k, i, 0, 0, 1, 0, 0, 0] : k >= 1 and k >= lb and k <= ub and ub <= -1 + n and i >= 1 + k and i <= n } +[lb, n, ub] -> { : ub <= n and lb >= 1 } +[n, lb, ub] -> { [i0, i1, i2, i3, i4, i5, i6, i7] -> atomic[o0] : o0 <= 6; [i0, i1, i2, i3, i4, i5, i6, i7] -> separate[o0] : o0 >= 7 } Index: contrib/isl/test_inputs/codegen/omega/m1-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m1-0.c @@ -0,0 +1,6 @@ +for (int c0 = 1; c0 <= 9; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(c0, c1); + if (c0 == 5) + s1(5, c1); + } Index: contrib/isl/test_inputs/codegen/omega/m1-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m1-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [i, j, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[5, j] -> [5, j, 1] : j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/m1-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m1-1.c @@ -0,0 +1,14 @@ +for (int c0 = 1; c0 <= 9; c0 += 1) { + if (c0 >= 6) { + for (int c1 = 1; c1 <= 9; c1 += 1) + s0(c0, c1); + } else if (c0 <= 4) { + for (int c1 = 1; c1 <= 9; c1 += 1) + s0(c0, c1); + } else { + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(5, c1); + s1(5, c1); + } + } +} Index: contrib/isl/test_inputs/codegen/omega/m1-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m1-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [i, j, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[5, j] -> [5, j, 1] : j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/m10-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m10-0.c @@ -0,0 +1,7 @@ +for (int c0 = 1; c0 <= 18; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) { + if (c0 % 2 == 0) + s0(c1, c0 / 2); + if (c0 <= 9) + s1(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/m10-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m10-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [4j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [2j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/m10-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m10-1.c @@ -0,0 +1,15 @@ +for (int c0 = 1; c0 <= 18; c0 += 1) { + if (c0 >= 2 && c0 <= 9) { + for (int c1 = 1; c1 <= 9; c1 += 1) { + if (c0 % 2 == 0) + s0(c1, c0 / 2); + s1(c1, c0); + } + } else if (c0 == 1) { + for (int c1 = 1; c1 <= 9; c1 += 1) + s1(c1, 1); + } else if (c0 % 2 == 0) { + for (int c1 = 1; c1 <= 9; c1 += 1) + s0(c1, c0 / 2); + } +} Index: contrib/isl/test_inputs/codegen/omega/m10-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m10-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [4j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [2j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/m11-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m11-0.c @@ -0,0 +1,6 @@ +for (int c0 = 1; c0 <= min(4, floord(2 * m - 1, 17) + 1); c0 += 1) + for (int c1 = 1; c1 <= min(2, -2 * c0 + (2 * m + 3 * c0 - 4) / 10 + 3); c1 += 1) + for (int c2 = 0; c2 <= min(2, -c0 - c1 + (2 * m + 3 * c0 + 10 * c1 + 6) / 20 + 1); c2 += 1) + for (int c3 = 8 * c0 + (c0 + 1) / 2 - 8; c3 <= min(min(30, m - 5 * c1 - 10 * c2 + 5), 8 * c0 + c0 / 2); c3 += 1) + for (int c4 = 5 * c1 + 10 * c2 - 4; c4 <= min(5 * c1 + 10 * c2, m - c3 + 1); c4 += 1) + s0(c0, c1, c2, c3, c4, -9 * c0 + c3 + c0 / 2 + 9, -5 * c1 - 5 * c2 + c4 + 5); Index: contrib/isl/test_inputs/codegen/omega/m11-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m11-0.in @@ -0,0 +1,3 @@ +[m] -> { s0[In_1, In_2, In_3, In_4, In_5, In_6, 5 - 5In_2 - 5In_3 + In_5] -> [In_1, In_2, In_3, In_4, In_5, In_6, 5 - 5In_2 - 5In_3 + In_5] : In_2 >= 1 and 2In_3 >= 1 - In_2 and In_2 <= 2 and 2In_3 <= 6 - In_2 and In_4 <= 30 and In_1 >= 1 and 2In_6 <= 18 - 17In_1 + 2In_4 and 2In_6 >= 17 - 17In_1 + 2In_4 and In_5 <= 5In_2 + 10In_3 and In_5 >= -4 + 5In_2 + 10In_3 and 2In_4 <= 17In_1 and 2In_4 >= -16 + 17In_1 and In_5 <= 1 + m - In_4 } +{ : } +[m] -> { [i0, i1, i2, i3, i4, i5, i6] -> atomic[o0] : o0 <= 5; [i0, i1, i2, i3, i4, i5, i6] -> separate[o0] : o0 >= 6 } Index: contrib/isl/test_inputs/codegen/omega/m12-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m12-0.c @@ -0,0 +1,3 @@ +for (int c1 = 1; c1 <= n; c1 += 1) + for (int c2 = 1; c2 <= m; c2 += 1) + s0(1, c1, c2, 0); Index: contrib/isl/test_inputs/codegen/omega/m12-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m12-0.in @@ -0,0 +1,3 @@ +[m, n] -> { s0[1, In_2, In_3, 0] -> [1, In_2, In_3, 0] : In_3 >= 1 and In_3 <= m and In_2 >= 1 and In_2 <= n } +{ : } +[m, n] -> { [i0, i1, i2, i3] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/m12-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m12-1.c @@ -0,0 +1,25 @@ +{ + for (int c1 = 1; c1 <= n; c1 += 1) + for (int c2 = 1; c2 <= m; c2 += 1) { + s0(1, c1, c2, 0); + s1(1, c1, c2, 0); + } + for (int c1 = 1; c1 <= n; c1 += 1) { + s3(2, c1, 0, 0); + s2(2, c1, 0, 0); + } + for (int c1 = 1; c1 <= m; c1 += 1) { + for (int c3 = 1; c3 <= n; c3 += 1) { + s4(3, c1, 1, c3); + s5(3, c1, 1, c3); + } + for (int c3 = 1; c3 <= n; c3 += 1) { + s7(3, c1, 2, c3); + s6(3, c1, 2, c3); + } + } + for (int c1 = 1; c1 <= m; c1 += 1) { + s8(4, c1, 0, 0); + s9(4, c1, 0, 0); + } +} Index: contrib/isl/test_inputs/codegen/omega/m12-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m12-1.in @@ -0,0 +1,3 @@ +[m, n] -> { s1[1, In_2, In_3, 0] -> [1, In_2, In_3, 0] : In_3 >= 1 and In_3 <= m and In_2 >= 1 and In_2 <= n; s2[2, In_2, 0, 0] -> [2, In_2, 0, 0] : In_2 >= 1 and In_2 <= n; s3[2, In_2, 0, 0] -> [2, In_2, 0, 0] : In_2 >= 1 and In_2 <= n; s8[4, In_2, 0, 0] -> [4, In_2, 0, 0] : In_2 >= 1 and In_2 <= m; s0[1, In_2, In_3, 0] -> [1, In_2, In_3, 0] : In_3 >= 1 and In_3 <= m and In_2 >= 1 and In_2 <= n; s7[3, In_2, 2, In_4] -> [3, In_2, 2, In_4] : In_4 >= 1 and In_4 <= n and In_2 >= 1 and In_2 <= m; s4[3, In_2, 1, In_4] -> [3, In_2, 1, In_4] : In_4 >= 1 and In_4 <= n and In_2 >= 1 and In_2 <= m; s6[3, In_2, 2, In_4] -> [3, In_2, 2, In_4] : In_4 >= 1 and In_4 <= n and In_2 >= 1 and In_2 <= m; s9[4, In_2, 0, 0] -> [4, In_2, 0, 0] : In_2 >= 1 and In_2 <= m; s5[3, In_2, 1, In_4] -> [3, In_2, 1, In_4] : In_4 >= 1 and In_4 <= n and In_2 >= 1 and In_2 <= m } +{ : } +[m, n] -> { [i0, i1, i2, i3] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/m2-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m2-0.c @@ -0,0 +1,12 @@ +for (int c0 = 2; c0 <= 9; c0 += 1) { + if (c0 >= 5) { + s1(c0, 1); + for (int c1 = 2; c1 <= 9; c1 += 1) { + s1(c0, c1); + s0(c0, c1); + } + } else { + for (int c1 = 2; c1 <= 9; c1 += 1) + s0(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/omega/m2-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m2-0.in @@ -0,0 +1,3 @@ +{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 5 and In_1 <= 9 and In_2 >= 1 and In_2 <= 9; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 9 and In_2 >= 2 and In_2 <= 9 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/m2-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m2-1.c @@ -0,0 +1,12 @@ +{ + for (int c0 = 2; c0 <= 4; c0 += 1) + for (int c1 = 2; c1 <= 9; c1 += 1) + s0(c0, c1); + for (int c0 = 5; c0 <= 9; c0 += 1) { + s1(c0, 1); + for (int c1 = 2; c1 <= 9; c1 += 1) { + s1(c0, c1); + s0(c0, c1); + } + } +} Index: contrib/isl/test_inputs/codegen/omega/m2-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m2-1.in @@ -0,0 +1,3 @@ +{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 5 and In_1 <= 9 and In_2 >= 1 and In_2 <= 9; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 9 and In_2 >= 2 and In_2 <= 9 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= -1; [i0, i1] -> separate[o0] : o0 >= 0 } Index: contrib/isl/test_inputs/codegen/omega/m3-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m3-0.c @@ -0,0 +1,3 @@ +for (int c0 = -9; c0 <= 9; c0 += 1) + for (int c1 = max(1, -c0 + 1); c1 <= min(10, -c0 + 10); c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/m3-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m3-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : In_2 >= 1 - In_1 and In_2 >= 1 and In_2 <= 10 - In_1 and In_2 <= 10 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/m4-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m4-0.c @@ -0,0 +1,5 @@ +for (int c0 = 1; c0 <= 9; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(c1, c0); + s1(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/m4-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m4-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/m4-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m4-1.c @@ -0,0 +1,5 @@ +for (int c0 = 1; c0 <= 9; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(c1, c0); + s1(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/m4-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m4-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/m7-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m7-0.c @@ -0,0 +1,6 @@ +for (int c0 = 1; c0 <= 9; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(c1, c0); + if (c0 % 2 == 0) + s1(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/m7-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m7-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : exists (e0 = [(j)/2]: 2e0 = j and i >= 1 and i <= 9 and j >= 2 and j <= 8) } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/m7-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m7-1.c @@ -0,0 +1,11 @@ +for (int c0 = 1; c0 <= 9; c0 += 1) { + if ((c0 + 1) % 2 == 0) { + for (int c1 = 1; c1 <= 9; c1 += 1) + s0(c1, c0); + } else { + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(c1, c0); + s1(c1, c0); + } + } +} Index: contrib/isl/test_inputs/codegen/omega/m7-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m7-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : exists (e0 = [(j)/2]: 2e0 = j and i >= 1 and i <= 9 and j >= 2 and j <= 8) } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/m8-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m8-0.c @@ -0,0 +1,6 @@ +for (int c0 = 2; c0 <= 8; c0 += 2) + for (int c1 = 1; c1 <= 9; c1 += 1) { + if (c0 % 4 == 0) + s0(c1, c0); + s1(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/m8-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m8-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [j, i, 0] : exists (e0 = [(j)/4]: 4e0 = j and i >= 1 and i <= 9 and j >= 4 and j <= 8); s1[i, j] -> [j, i, 1] : exists (e0 = [(j)/2]: 2e0 = j and i >= 1 and i <= 9 and j >= 2 and j <= 8) } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/m8-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m8-1.c @@ -0,0 +1,11 @@ +for (int c0 = 2; c0 <= 8; c0 += 2) { + if ((c0 + 2) % 4 == 0) { + for (int c1 = 1; c1 <= 9; c1 += 1) + s1(c1, c0); + } else { + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(c1, c0); + s1(c1, c0); + } + } +} Index: contrib/isl/test_inputs/codegen/omega/m8-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m8-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [j, i, 0] : exists (e0 = [(j)/4]: 4e0 = j and i >= 1 and i <= 9 and j >= 4 and j <= 8); s1[i, j] -> [j, i, 1] : exists (e0 = [(j)/2]: 2e0 = j and i >= 1 and i <= 9 and j >= 2 and j <= 8) } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/m9-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m9-0.c @@ -0,0 +1,5 @@ +for (int c0 = 1; c0 <= 9; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(c1, c0); + s1(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/m9-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m9-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [2j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [2j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/m9-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m9-1.c @@ -0,0 +1,5 @@ +for (int c0 = 1; c0 <= 9; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) { + s0(c1, c0); + s1(c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/m9-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/m9-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [2j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [2j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/olda-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/olda-0.c @@ -0,0 +1,8 @@ +for (int c0 = 1; c0 <= morb; c0 += 1) + for (int c1 = 1; c1 <= np; c1 += 1) + for (int c2 = 1; c2 <= np; c2 += 1) { + if (c2 >= c1) + s0(c2, c1, c0); + if (c1 >= c2) + s1(c1, c2, c0); + } Index: contrib/isl/test_inputs/codegen/omega/olda-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/olda-0.in @@ -0,0 +1,3 @@ +[np, morb] -> { s0[mp, mq, mi] -> [mi, mq, mp, 0] : mq >= 1 and mq <= mp and mp <= np and mi >= 1 and mi <= morb; s1[mp, mq, mi] -> [mi, mp, mq, 1] : mq >= 1 and mq <= mp and mp <= np and mi >= 1 and mi <= morb } +{ : } +[np, morb] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 } Index: contrib/isl/test_inputs/codegen/omega/olda-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/olda-1.c @@ -0,0 +1,9 @@ +for (int c0 = 1; c0 <= morb; c0 += 1) + for (int c1 = 1; c1 <= np; c1 += 1) { + for (int c2 = 1; c2 < c1; c2 += 1) + s1(c1, c2, c0); + s0(c1, c1, c0); + s1(c1, c1, c0); + for (int c2 = c1 + 1; c2 <= np; c2 += 1) + s0(c2, c1, c0); + } Index: contrib/isl/test_inputs/codegen/omega/olda-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/olda-1.in @@ -0,0 +1,3 @@ +[np, morb] -> { s0[mp, mq, mi] -> [mi, mq, mp, 0] : mq >= 1 and mq <= mp and mp <= np and mi >= 1 and mi <= morb; s1[mp, mq, mi] -> [mi, mp, mq, 1] : mq >= 1 and mq <= mp and mp <= np and mi >= 1 and mi <= morb } +{ : } +[np, morb] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/p.delft-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/p.delft-0.c @@ -0,0 +1,4 @@ +if (P2 >= 0 && P2 <= 3 && P1 == P2) + for (int c0 = 0; c0 <= min(2, -P2 + 4); c0 += 1) + for (int c2 = (-P2 - c0 + 6) % 3; c2 <= 3; c2 += 3) + s0(c0, c0, c2, c2); Index: contrib/isl/test_inputs/codegen/omega/p.delft-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/p.delft-0.in @@ -0,0 +1,3 @@ +[P2, P1] -> { s0[In_1, In_1, In_3, In_3] -> [In_1, In_1, In_3, In_3] : exists (e0 = [(-2P2 - 2In_1 + In_3)/3]: P1 = P2 and 3e0 = -2P2 - 2In_1 + In_3 and P2 >= 0 and P2 <= 3 and In_1 <= 4 - P2 and In_1 >= 0 and In_1 <= 2 and In_3 >= 0 and In_3 <= 3) } +{ : } +[P2, P1] -> { [i0, i1, i2, i3] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/p.delft2-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/p.delft2-0.c @@ -0,0 +1,11 @@ +if (P1 >= 0 && P1 <= 3 && P2 >= 0 && P2 <= 3) + for (int c0 = P1 - 1; c0 <= 3; c0 += 1) + for (int c2 = 0; c2 <= 7; c2 += 1) + for (int c3 = 0; c3 <= 7; c3 += 1) + if (4 * P2 >= 2 * c3 + 9 * floord(4 * P2 - 2 * c3 - 1, 9) + 6) { + if (P1 >= 1 && c0 + 1 == P1 && 4 * P1 >= 2 * c2 + 9 * floord(4 * P1 - 2 * c2 - 1, 9) + 7) { + s0(P1 - 1, P2, c2, c3, ((-4 * P1 + 2 * c2 + 9) % 9) + 1, -4 * P2 + 2 * c3 - 9 * floord(-4 * P2 + 2 * c3, 9)); + } else if (P1 == 0 && c0 == 3 && c2 % 4 == 0) { + s0(3, P2, c2, c3, (-c2 / 4) + 3, -4 * P2 + 2 * c3 - 9 * floord(-4 * P2 + 2 * c3, 9)); + } + } Index: contrib/isl/test_inputs/codegen/omega/p.delft2-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/p.delft2-0.in @@ -0,0 +1,3 @@ +[P1, P2] -> { s0[In_1, P2, In_3, In_4, In_5, In_6] -> [In_1, P2, In_3, In_4, In_5, In_6] : (exists (e0 = [(8 + 4In_1 + 16In_3 + In_5)/9], e1 = [(12 - 4P1 + 9e0)/16], e2 = [(-2In_1 - 2In_3 + In_5)/3], e3 = [(-5P2 - 2In_4 + In_6)/9]: 3e2 = -2In_1 - 2In_3 + In_5 and 9e3 = -5P2 - 2In_4 + In_6 and P1 >= 0 and In_1 >= 1 + P1 and In_1 <= 3 and P2 >= 0 and P2 <= 3 and In_6 >= 0 and In_6 <= 3 and In_5 >= 0 and In_5 <= 3 and In_5 >= 1 - 4In_1 - 16In_3 and In_5 <= 126 - 4In_1 - 16In_3 and In_6 <= 126 - 4P2 - 16In_4 and 16e1 <= -4P1 + 9e0 and 2In_6 <= P2 + 4In_4 and 9e0 <= 3 + 4In_1 + 16In_3 + In_5 and 9e0 >= 4In_1 + 16In_3 + In_5 and 16e1 >= -3 - 4P1 + 9e0)) or (exists (e0 = [(8 + 4In_1 + 16In_3 + In_5)/9], e1 = [(12 - 4P1 + 9e0)/16], e2 = [(-2In_1 - 2In_3 + In_5)/3], e3 = [(-5P2 - 2In_4 + In_6)/9]: 3e2 = -2In_1 - 2In_3 + In_5 and 9e3 = -5P2 - 2In_4 + In_6 and In_1 >= 0 and In_1 <= -1 + P1 and P1 <= 3 and In_6 >= 0 and In_6 <= 3 and In_6 <= 1 + 2In_4 and P2 >= 0 and P2 <= 3 and In_5 >= 0 and In_5 <= 3 and In_5 >= 1 - 4In_1 - 16In_3 and In_5 <= 126 - 4In_1 - 16In_3 and In_6 <= 126 - 4P2 - 16In_4 and 16e1 <= -4P1 + 9e0 and 9e0 <= 3 + 4In_1 + 16In_3 + In_5 and 9e0 >= 4In_1 + 16In_3 + In_5 and 16e1 >= -3 - 4P1 + 9e0)) } +{ : } +[P1, P2] -> { [i0, i1, i2, i3, i4, i5] -> atomic[o0] : o0 <= 4; [i0, i1, i2, i3, i4, i5] -> separate[o0] : o0 >= 5 } Index: contrib/isl/test_inputs/codegen/omega/p6-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/p6-0.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 5; c0 <= 8; c0 += 1) + s0(c0); + for (int c0 = 10; c0 <= 16; c0 += 2) + s0(c0); + for (int c0 = 20; c0 <= 25; c0 += 1) + s0(c0); +} Index: contrib/isl/test_inputs/codegen/omega/p6-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/p6-0.in @@ -0,0 +1,3 @@ +{ s0[In_1] -> [In_1] : (In_1 >= 5 and In_1 <= 8) or (exists (e0 = [(In_1)/2]: 2e0 = In_1 and In_1 >= 10 and In_1 <= 16)) or (In_1 >= 20 and In_1 <= 25) } +{ : } +{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/p6-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/p6-1.c @@ -0,0 +1,3 @@ +for (int c0 = -9; c0 <= 9; c0 += 1) + for (int c1 = max(1, -c0 + 1); c1 <= min(10, -c0 + 10); c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/p6-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/p6-1.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : In_2 >= 1 - In_1 and In_2 >= 1 and In_2 <= 10 - In_1 and In_2 <= 10 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/stride1-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride1-0.c @@ -0,0 +1,2 @@ +for (int c0 = 3; c0 <= 9; c0 += 3) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/stride1-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride1-0.in @@ -0,0 +1,3 @@ +{ s0[In_1] -> [In_1] : exists (e0 = [(In_1)/3]: 3e0 = In_1 and In_1 >= 3 and In_1 <= 9) } +{ : } +{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/stride2-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride2-0.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= n; c0 += 32) + for (int c1 = c0; c1 <= min(n, c0 + 31); c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/stride2-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride2-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/32]: 32e0 = In_1 and In_2 <= 31 + In_1 and In_1 >= 0 and In_2 >= In_1 and In_2 <= n) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/stride3-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride3-0.c @@ -0,0 +1,3 @@ +for (int c0 = 3; c0 <= n; c0 += 32) + for (int c1 = c0; c1 <= min(n, c0 + 31); c1 += 1) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/stride3-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride3-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-3 + In_1)/32]: 32e0 = -3 + In_1 and In_2 <= 31 + In_1 and In_1 >= 3 and In_2 >= In_1 and In_2 <= n) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/stride4-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride4-0.c @@ -0,0 +1,2 @@ +for (int c0 = 18; c0 <= 98; c0 += 5) + s0(c0); Index: contrib/isl/test_inputs/codegen/omega/stride4-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride4-0.in @@ -0,0 +1,3 @@ +{ s0[In_1] -> [In_1] : exists (e0 = [(-3 + In_1)/5]: 5e0 = -3 + In_1 and In_1 >= 18 and In_1 <= 98) } +{ : } +{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/stride5-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride5-0.c @@ -0,0 +1,3 @@ +for (int c0 = 2; c0 <= min(100, -2 * n + 400); c0 += 2) + for (int c1 = 2 * n + c0; c1 <= 400; c1 += 2) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/stride5-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride5-0.in @@ -0,0 +1,3 @@ +[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/2], e1 = [(In_2)/2]: 2e0 = In_1 and 2e1 = In_2 and In_1 >= 2 and In_1 <= 100 and In_2 <= 400 and In_2 >= 2n + In_1) } +{ : } +[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/stride6-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride6-0.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= 101; c0 += 1) + for (int c1 = -((c0 - 1) % 2) + c0 + 1; c1 <= 400; c1 += 2) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/stride6-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride6-0.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_2)/2]: 2e0 = In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= 400 and In_1 <= 101) } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/stride6-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride6-1.c @@ -0,0 +1,3 @@ +for (int c0 = 2; c0 <= 100; c0 += 2) + for (int c1 = c0; c1 <= 400; c1 += 2) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/stride6-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride6-1.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/2], e1 = [(In_2)/2]: 2e0 = In_1 and 2e1 = In_2 and In_1 >= 2 and In_2 >= In_1 and In_2 <= 400 and In_1 <= 100) } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/stride6-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride6-2.c @@ -0,0 +1,3 @@ +for (int c0 = 2; c0 <= 100; c0 += 2) + for (int c1 = c0; c1 <= 400; c1 += 2) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/omega/stride6-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride6-2.in @@ -0,0 +1,3 @@ +{ s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/2], e1 = [(In_2)/2]: 2e0 = In_1 and 2e1 = In_2 and In_1 >= 2 and In_2 >= In_1 and In_2 <= 400 and In_1 <= 100) } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/stride7-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride7-0.c @@ -0,0 +1,15 @@ +for (int c0 = 1; c0 <= 36; c0 += 1) { + if (c0 <= 3) { + for (int c1 = 1; c1 <= 9; c1 += 1) + s1(c1, c0); + } else if (c0 <= 9) { + for (int c1 = 1; c1 <= 9; c1 += 1) { + if (c0 % 4 == 0) + s0(c1, c0 / 4); + s1(c1, c0); + } + } else if (c0 % 4 == 0) { + for (int c1 = 1; c1 <= 9; c1 += 1) + s0(c1, c0 / 4); + } +} Index: contrib/isl/test_inputs/codegen/omega/stride7-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride7-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [4j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/stride7-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride7-1.c @@ -0,0 +1,14 @@ +{ + for (int c0 = 1; c0 <= 3; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) + s1(c1, c0); + for (int c0 = 4; c0 <= 9; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) { + if (c0 % 4 == 0) + s0(c1, c0 / 4); + s1(c1, c0); + } + for (int c0 = 3; c0 <= 9; c0 += 1) + for (int c1 = 1; c1 <= 9; c1 += 1) + s0(c1, c0); +} Index: contrib/isl/test_inputs/codegen/omega/stride7-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/stride7-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [4j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 0; [i0, i1, i2] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/substitution-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-0.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= 10; c0 += 1) + for (int c1 = max(2 * c0 - 4, c0); c1 <= min(2 * c0, c0 + 6); c1 += 1) + s0(2 * c0 - c1, -c0 + c1); Index: contrib/isl/test_inputs/codegen/omega/substitution-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [i + j, i + 2j] : i >= 0 and i <= 4 and j >= 0 and j <= 6 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/substitution-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-1.c @@ -0,0 +1,3 @@ +for (int c0 = 0; c0 <= 14; c0 += 1) + for (int c1 = max(2 * c0 - 12, -c0 + 3 * ((c0 + 1) / 2)); c1 <= min(2 * c0, c0 / 2 + 9); c1 += 3) + s0((2 * c0 - c1) / 3, (-c0 + 2 * c1) / 3); Index: contrib/isl/test_inputs/codegen/omega/substitution-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [2i + j, i + 2j] : i >= 0 and i <= 4 and j >= 0 and j <= 6 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/substitution-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-2.c @@ -0,0 +1,2 @@ +for (int c0 = -3; c0 <= 96; c0 += 1) + s0(c0, c0 + 4); Index: contrib/isl/test_inputs/codegen/omega/substitution-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-2.in @@ -0,0 +1,3 @@ +{ s0[i, 4 + i] -> [i, 4 + i] : i >= -3 and i <= 96 } +{ : } +{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/substitution-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-3.c @@ -0,0 +1 @@ +s0(n + 19); Index: contrib/isl/test_inputs/codegen/omega/substitution-3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-3.in @@ -0,0 +1,3 @@ +[n] -> { s0[19 + n] -> [19 + n] } +{ : } +[n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/substitution-4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-4.c @@ -0,0 +1 @@ +s0(n + 1); Index: contrib/isl/test_inputs/codegen/omega/substitution-4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/substitution-4.in @@ -0,0 +1,3 @@ +[n] -> { s0[i] -> [i] : exists (e0 = [(-1 - n + i)/18]: 18e0 = -1 - n + i and i <= 16 + n and i >= 1 + n) } +{ : } +[n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/syr2k-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/syr2k-0.c @@ -0,0 +1,4 @@ +for (int c0 = 1; c0 <= min(n, 2 * b - 1); c0 += 1) + for (int c1 = max(-n + 1, -b + 1); c1 <= min(b - c0, n - c0); c1 += 1) + for (int c2 = max(1, c0 + c1); c2 <= min(n, n + c1); c2 += 1) + s0(-c0 - c1 + c2 + 1, -c1 + c2, c2); Index: contrib/isl/test_inputs/codegen/omega/syr2k-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/syr2k-0.in @@ -0,0 +1,3 @@ +[n, b] -> { s0[i, j, k] -> [1 - i + j, -j + k, k] : i >= 1 and j >= i and j <= n and k >= 1 and k <= n and k <= -1 + b + i and k >= 1 - b + j } +{ : } +[n, b] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/syr2k-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/syr2k-1.c @@ -0,0 +1,4 @@ +for (int c0 = 1; c0 <= min(n, 2 * b - 1); c0 += 1) + for (int c1 = -b + 1; c1 <= b - c0; c1 += 1) + for (int c2 = max(1, c0 + c1); c2 <= min(n, n + c1); c2 += 1) + s0(-c0 - c1 + c2 + 1, -c1 + c2, c2); Index: contrib/isl/test_inputs/codegen/omega/syr2k-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/syr2k-1.in @@ -0,0 +1,3 @@ +[n, b] -> { s0[i, j, k] -> [1 - i + j, -j + k, k] : i >= 1 and j >= i and j <= n and k >= 1 and k <= n and k <= -1 + b + i and k >= 1 - b + j } +[b, n] -> { : b >= 1 and n >= b } +[n, b] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/syr2k-2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/syr2k-2.c @@ -0,0 +1,4 @@ +for (int c0 = 1; c0 <= min(n, 2 * b - 1); c0 += 1) + for (int c1 = max(-n + 1, -b + 1); c1 <= min(b - c0, n - c0); c1 += 1) + for (int c2 = max(1, c0 + c1); c2 <= min(n, n + c1); c2 += 1) + s0(-c0 - c1 + c2 + 1, -c1 + c2, c2); Index: contrib/isl/test_inputs/codegen/omega/syr2k-2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/syr2k-2.in @@ -0,0 +1,3 @@ +[n, b] -> { s0[i, j, k] -> [1 - i + j, -j + k, k] : i >= 1 and j >= i and j <= n and k >= 1 and k <= n and k <= -1 + b + i and k >= 1 - b + j } +{ : } +[n, b] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/syr2k-3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/syr2k-3.c @@ -0,0 +1,4 @@ +for (int c0 = 1; c0 <= min(n, 2 * b - 1); c0 += 1) + for (int c1 = -b + 1; c1 <= b - c0; c1 += 1) + for (int c2 = max(1, c0 + c1); c2 <= min(n, n + c1); c2 += 1) + s0(-c0 - c1 + c2 + 1, -c1 + c2, c2); Index: contrib/isl/test_inputs/codegen/omega/syr2k-3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/syr2k-3.in @@ -0,0 +1,3 @@ +[n, b] -> { s0[i, j, k] -> [1 - i + j, -j + k, k] : i >= 1 and j >= i and j <= n and k >= 1 and k <= n and k <= -1 + b + i and k >= 1 - b + j } +[b, n] -> { : b >= 1 and n >= b } +[n, b] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 } Index: contrib/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.c @@ -0,0 +1,15 @@ +{ + for (int c1 = 0; c1 <= 1; c1 += 1) { + if (c1 == 1) { + s0(1, 1, 1, 0, 0); + s0(1, 1, 1, N - 1, 0); + } else { + for (int c3 = 0; c3 < N; c3 += 1) + s0(1, 0, 1, c3, 0); + } + } + for (int c1 = 0; c1 <= floord(T - 1, 1000); c1 += 1) + for (int c2 = 1000 * c1 + 1; c2 <= min(N + T - 3, N + 1000 * c1 + 997); c2 += 1) + for (int c3 = max(0, -N - 1000 * c1 + c2 + 2); c3 <= min(min(999, T - 1000 * c1 - 1), -1000 * c1 + c2 - 1); c3 += 1) + s1(2, 1000 * c1 + c3, 1, -1000 * c1 + c2 - c3, 1); +} Index: contrib/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.in @@ -0,0 +1,3 @@ +[T, N] -> { s1[2, t, 1, i, 1] -> [2, tb, t + i, t - 1000tb, 0] : 1000tb <= t and 1000tb >= -999 + t and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s0[1, 0, 1, In_4, 0] -> [1, 0, 1, In_4, 0] : In_4 >= 0 and In_4 <= -1 + N; s0[1, 1, 1, 0, 0] -> [1, 1, 1, 0, 0]; s0[1, 1, 1, -1 + N, 0] -> [1, 1, 1, -1 + N, 0] } +[T, N] -> { : T >= 0 and N >= 4 } +[N] -> { [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/ts1d-check0-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ts1d-check0-0.c @@ -0,0 +1,13 @@ +{ + for (int c1 = 0; c1 < N; c1 += 1) + s0(1, c1, 1, 0, 0); + for (int c1 = 0; c1 <= floord(T - 1, 500); c1 += 1) + for (int c2 = 1000 * c1; c2 <= min(N + 2 * T - 3, N + 1000 * c1 + 997); c2 += 1) { + for (int c3 = max(0, -((N + c2) % 2) - N - 1000 * c1 + c2 + 2); c3 <= min(min(998, 2 * T - 1000 * c1 - 2), -1000 * c1 + c2 - 2); c3 += 2) { + s1(2, 1000 * c1 + c3, 0, -1000 * c1 + c2 - c3, 1); + s2(2, 1000 * c1 + c3 + 1, 0, -1000 * c1 + c2 - c3 - 1, 1); + } + if (2 * T >= c2 + 1 && 1000 * c1 + 999 >= c2) + s1(2, ((c2 + 1) % 2) + c2 - 1, 0, -((c2 + 1) % 2) + 1, 1); + } +} Index: contrib/isl/test_inputs/codegen/omega/ts1d-check0-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ts1d-check0-0.in @@ -0,0 +1,3 @@ +[T, N] -> { s1[2, t, 0, i, 1] -> [2, tb, t + i, t - 1000tb, 1] : exists (e0 = [(t - 1000tb)/2]: 2e0 = t - 1000tb and 1000tb <= t and 1000tb >= -999 + t and i >= 0 and i <= -1 + N and t >= 0 and t <= -2 + 2T); s0[1, In_2, 1, 0, 0] -> [1, In_2, 1, 0, 0] : In_2 >= 0 and In_2 <= -1 + N; s2[2, t, 0, i, 1] -> [2, tb, t + i, t - 1000tb, 1] : exists (e0 = [(-1 + t - 1000tb)/2]: 2e0 = -1 + t - 1000tb and 1000tb <= t and 1000tb >= -999 + t and i >= 1 and i <= -2 + N and t >= 1 and t <= -1 + 2T) } +[T, N] -> { : T >= 0 and N >= 4 } +[N] -> { [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 2 } Index: contrib/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.c @@ -0,0 +1,36 @@ +{ + for (int c1 = -1; c1 < T; c1 += 1) + for (int c2 = 0; c2 < N; c2 += 1) { + if (c1 == -1) { + s0(1, -1, c2, 0, 0); + } else if (c2 == 0) { + s0(1, c1, 0, 0, 0); + } else if (c2 + 1 == N) { + s0(1, c1, N - 1, 0, 0); + } + } + for (int c1 = 0; c1 <= floord(T - 1, 500); c1 += 1) { + for (int c3 = -((c1 + 9) / 8) + 2; c3 <= floord(N - 500 * c1 - 3, 4000) + 1; c3 += 1) + for (int c4 = max(500 * c1 + 1, 1000 * c1 + 4000 * c3 - 3999); c4 <= min(min(N + T - 3, 1000 * c1 + 4000 * c3 - 3000), 2 * N - 4000 * c3 + 3995); c4 += 1) + for (int c5 = max(0, -N - 500 * c1 + c4 + 2); c5 <= min(min(T - 500 * c1 - 1, -500 * c1 + c4 - 1), -500 * c1 - 2000 * c3 + (c4 + 1) / 2 + 1999); c5 += 1) + s1(2, 500 * c1 + c5, 1, -500 * c1 + c4 - c5, 1); + for (int c3 = max(-((T + 4000) / 4000) + 2, -((c1 + 9) / 8) + 2); c3 <= floord(N - 500 * c1 - 3, 4000) + 1; c3 += 1) + for (int c4 = max(1000 * c1 + 4000 * c3 - 3999, -4000 * c3 + 4000); c4 <= min(min(2 * T + 4000 * c3 - 4000, 1000 * c1 + 4000 * c3 - 3000), 2 * N - 4000 * c3 + 3995); c4 += 1) + s2(2, -2000 * c3 + (c4 + 1) / 2 + 1999, 1, 2000 * c3 + c4 - (c4 + 1) / 2 - 1999, 1); + for (int c3 = -((c1 + 7) / 8) + 1; c3 <= min(floord(N + T - 1000 * c1 - 1004, 4000) + 1, floord(N - 500 * c1 - 504, 4000) + 1); c3 += 1) + for (int c4 = max(500 * c1 + 1, 1000 * c1 + 4000 * c3 - 2999); c4 <= min(min(N + T - 3, N + 500 * c1 + 497), 1000 * c1 + 4000 * c3); c4 += 1) + for (int c5 = max(0, -N - 500 * c1 + c4 + 2); c5 <= min(min(499, T - 500 * c1 - 1), -500 * c1 + c4 - 1); c5 += 1) + s3(2, 500 * c1 + c5, 1, -500 * c1 + c4 - c5, 1); + for (int c3 = max(-((T + 4000) / 4000) + 1, -((c1 + 9) / 8) + 1); c3 <= floord(N - 500 * c1 - 3, 4000); c3 += 1) + for (int c4 = max(-4000 * c3, 1000 * c1 + 4000 * c3 + 1); c4 <= min(min(2 * N - 4000 * c3 - 5, 2 * T + 4000 * c3), 1000 * c1 + 4000 * c3 + 1000); c4 += 1) + s4(2, -2000 * c3 + (c4 + 1) / 2 - 1, 1, 2000 * c3 + c4 - (c4 + 1) / 2 + 1, 1); + for (int c3 = -((c1 + 8) / 8) + 1; c3 <= min(floord(N + T - 1000 * c1 - 4, 4000), floord(N - 500 * c1 + 496, 4000)); c3 += 1) + for (int c4 = max(1000 * c1 + 4000 * c3 + 1, -4000 * c3 + 2); c4 <= min(min(min(N + T - 3, N + 500 * c1 + 497), 2 * T + 4000 * c3 - 2), 1000 * c1 + 4000 * c3 + 998); c4 += 1) + for (int c5 = max(-N - 500 * c1 + c4 + 2, -500 * c1 - 2000 * c3 + (c4 + 1) / 2); c5 <= min(min(499, T - 500 * c1 - 1), -500 * c1 + c4 - 1); c5 += 1) + s5(2, 500 * c1 + c5, 1, -500 * c1 + c4 - c5, 1); + } + if (T >= 1) + for (int c3 = -((T + 3998) / 4000) + 1; c3 <= floord(N - T - 2, 4000) + 1; c3 += 1) + for (int c4 = max(T, 2 * T + 4000 * c3 - 4001); c4 < min(N + T - 2, 2 * T + 4000 * c3 - 1); c4 += 1) + s6(2, T - 1, 1, -T + c4 + 1, 1); +} Index: contrib/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.in @@ -0,0 +1,3 @@ +[T, N] -> { s1[2, t, 1, i, 1] -> [2, tb, 1, proc, t + i, t - 500tb, 0] : 4000proc >= 3000 + t + i - 1000tb and 500tb <= t and 4000proc <= 3999 - t + i and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s0[1, -1, c, 0, 0] -> [1, -1, c, 0, 0, 0, 0] : c >= 0 and c <= -1 + N; s0[1, b, 0, 0, 0] -> [1, b, 0, 0, 0, 0, 0] : b >= 0 and b <= -1 + T; s0[1, b, -1 + N, 0, 0] -> [1, b, -1 + N, 0, 0, 0, 0] : b >= 0 and b <= -1 + T; s6[2, -1 + T, 1, i, 1] -> [3, tb, 7, proc, -1 + T + i, -1 + T - 500tb, 0] : 500tb <= -1 + T and 500tb >= -500 + T and 4000proc >= 1 - T + i and 4000proc <= 4000 - T + i and i >= 1 and i <= -2 + N and T >= 1; s3[2, t, 1, i, 1] -> [2, tb, 3, proc, t + i, t - 500tb, 0] : 500tb <= t and 500tb >= -499 + t and 4000proc <= 2999 + t + i - 1000tb and 4000proc >= t + i - 1000tb and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s2[2, t, 1, i, 1] -> [2, tb, 2, proc, t + i, t - 500tb, 0] : 500tb <= t and 500tb >= -499 + t and 4000proc <= 3999 - t + i and 4000proc >= 3998 - t + i and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s4[2, t, 1, i, 1] -> [2, tb, 4, Out_4, t + i, t - 500tb, 0] : 500tb <= t and 500tb >= -499 + t and 4000Out_4 <= -1 - t + i and 4000Out_4 >= -2 - t + i and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s5[2, t, 1, i, 1] -> [2, tb, 5, proc, t + i, t - 500tb, 0] : 500tb >= -499 + t and 4000proc <= -1 + t + i - 1000tb and 4000proc >= -t + i and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T } +[T, N] -> { : T >= 0 and N >= 4 } +[N, T] -> { [i0, i1, i2, i3, i4, i5, i6] -> atomic[o0] : o0 <= 5; [i0, i1, i2, i3, i4, i5, i6] -> separate[o0] : o0 >= 6 } Index: contrib/isl/test_inputs/codegen/omega/ts1d-orig0-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ts1d-orig0-0.c @@ -0,0 +1,10 @@ +{ + for (int c1 = 0; c1 < N; c1 += 1) + s0(1, c1, 1, 0, 0); + for (int c1 = 0; c1 < T; c1 += 1) { + for (int c3 = 0; c3 < N; c3 += 1) + s1(2, c1, 0, c3, 1); + for (int c3 = 1; c3 < N - 1; c3 += 1) + s2(2, c1, 1, c3, 1); + } +} Index: contrib/isl/test_inputs/codegen/omega/ts1d-orig0-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/ts1d-orig0-0.in @@ -0,0 +1,3 @@ +[T, N] -> { s1[2, In_2, 0, In_4, 1] -> [2, In_2, 0, In_4, 1] : In_4 >= 0 and In_4 <= -1 + N and In_2 >= 0 and In_2 <= -1 + T; s0[1, In_2, 1, 0, 0] -> [1, In_2, 1, 0, 0] : In_2 >= 0 and In_2 <= -1 + N; s2[2, In_2, 1, In_4, 1] -> [2, In_2, 1, In_4, 1] : In_4 >= 1 and In_4 <= -2 + N and In_2 >= 0 and In_2 <= -1 + T } +[T, N] -> { : T >= 0 and N >= 4 } +[N] -> { [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 4; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 3 } Index: contrib/isl/test_inputs/codegen/omega/wak1-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak1-0.c @@ -0,0 +1,27 @@ +{ + for (int c0 = a3; c0 <= min(min(a1 - 1, b3), a2 - 1); c0 += 1) + s2(c0); + for (int c0 = a1; c0 <= min(b1, a2 - 1); c0 += 1) { + s0(c0); + if (c0 >= a3 && b3 >= c0) + s2(c0); + } + for (int c0 = max(max(a1, b1 + 1), a3); c0 <= min(b3, a2 - 1); c0 += 1) + s2(c0); + for (int c0 = a2; c0 <= b2; c0 += 1) { + if (c0 >= a1 && b1 >= c0) + s0(c0); + s1(c0); + if (c0 >= a3 && b3 >= c0) + s2(c0); + } + for (int c0 = max(max(a3, a2), b2 + 1); c0 <= min(a1 - 1, b3); c0 += 1) + s2(c0); + for (int c0 = max(max(a1, a2), b2 + 1); c0 <= b1; c0 += 1) { + s0(c0); + if (c0 >= a3 && b3 >= c0) + s2(c0); + } + for (int c0 = max(max(max(max(a1, b1 + 1), a3), a2), b2 + 1); c0 <= b3; c0 += 1) + s2(c0); +} Index: contrib/isl/test_inputs/codegen/omega/wak1-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak1-0.in @@ -0,0 +1,3 @@ +[a3, b3, a2, b2, a1, b1] -> { s2[i] -> [i, 2] : i >= a3 and i <= b3; s0[i] -> [i, 0] : i >= a1 and i <= b1; s1[i] -> [i, 1] : i >= a2 and i <= b2 } +{ : } +[a1, b1] -> { [i0, i1] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/wak1-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak1-1.c @@ -0,0 +1,55 @@ +{ + for (int c0 = a2; c0 <= min(min(a1 - 1, a3 - 1), b2); c0 += 1) + s1(c0); + for (int c0 = a3; c0 <= min(min(a1 - 1, b3), a2 - 1); c0 += 1) + s2(c0); + for (int c0 = max(a3, a2); c0 <= min(min(a1 - 1, b3), b2); c0 += 1) { + s1(c0); + s2(c0); + } + for (int c0 = max(max(a3, b3 + 1), a2); c0 <= min(a1 - 1, b2); c0 += 1) + s1(c0); + for (int c0 = a1; c0 <= min(min(b1, a3 - 1), a2 - 1); c0 += 1) + s0(c0); + for (int c0 = max(a1, a2); c0 <= min(min(b1, a3 - 1), b2); c0 += 1) { + s0(c0); + s1(c0); + } + for (int c0 = max(a1, a3); c0 <= min(min(b1, b3), a2 - 1); c0 += 1) { + s0(c0); + s2(c0); + } + for (int c0 = max(max(a1, a3), b3 + 1); c0 <= min(b1, a2 - 1); c0 += 1) + s0(c0); + for (int c0 = max(max(a1, a3), a2); c0 <= min(min(b1, b3), b2); c0 += 1) { + s0(c0); + s1(c0); + s2(c0); + } + for (int c0 = max(max(max(a1, a3), b3 + 1), a2); c0 <= min(b1, b2); c0 += 1) { + s0(c0); + s1(c0); + } + for (int c0 = max(max(a1, a2), b2 + 1); c0 <= min(b1, a3 - 1); c0 += 1) + s0(c0); + for (int c0 = max(max(a3, a2), b2 + 1); c0 <= min(a1 - 1, b3); c0 += 1) + s2(c0); + for (int c0 = max(max(max(a1, a3), a2), b2 + 1); c0 <= min(b1, b3); c0 += 1) { + s0(c0); + s2(c0); + } + for (int c0 = max(max(max(max(a1, a3), b3 + 1), a2), b2 + 1); c0 <= b1; c0 += 1) + s0(c0); + for (int c0 = max(max(a1, b1 + 1), a2); c0 <= min(a3 - 1, b2); c0 += 1) + s1(c0); + for (int c0 = max(max(a1, b1 + 1), a3); c0 <= min(b3, a2 - 1); c0 += 1) + s2(c0); + for (int c0 = max(max(max(a1, b1 + 1), a3), a2); c0 <= min(b3, b2); c0 += 1) { + s1(c0); + s2(c0); + } + for (int c0 = max(max(max(max(a1, b1 + 1), a3), b3 + 1), a2); c0 <= b2; c0 += 1) + s1(c0); + for (int c0 = max(max(max(max(a1, b1 + 1), a3), a2), b2 + 1); c0 <= b3; c0 += 1) + s2(c0); +} Index: contrib/isl/test_inputs/codegen/omega/wak1-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak1-1.in @@ -0,0 +1,3 @@ +[a3, b3, a2, b2, a1, b1] -> { s2[i] -> [i, 2] : i >= a3 and i <= b3; s0[i] -> [i, 0] : i >= a1 and i <= b1; s1[i] -> [i, 1] : i >= a2 and i <= b2 } +{ : } +[a1, b1] -> { [i0, i1] -> separate[o0] : o0 >= 0 } Index: contrib/isl/test_inputs/codegen/omega/wak2-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak2-0.c @@ -0,0 +1,25 @@ +if (c2 >= d2 + 1) { + for (int c0 = a1; c0 <= b1; c0 += 1) + for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1) + s0(c0, c1_0); +} else { + for (int c0 = a1; c0 <= min(b1, a2 - 1); c0 += 1) + for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1) + s0(c0, c1_0); + for (int c0 = a2; c0 <= b2; c0 += 1) { + if (c0 >= a1 && b1 >= c0) + for (int c1_0 = c1; c1_0 <= min(d1, c2 - 1); c1_0 += 1) + s0(c0, c1_0); + for (int c1_0 = c2; c1_0 <= d2; c1_0 += 1) { + if (c0 >= a1 && b1 >= c0 && c1_0 >= c1 && d1 >= c1_0) + s0(c0, c1_0); + s1(c0, c1_0); + } + if (c0 >= a1 && b1 >= c0) + for (int c1_0 = max(c1, d2 + 1); c1_0 <= d1; c1_0 += 1) + s0(c0, c1_0); + } + for (int c0 = max(max(a1, a2), b2 + 1); c0 <= b1; c0 += 1) + for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1) + s0(c0, c1_0); +} Index: contrib/isl/test_inputs/codegen/omega/wak2-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak2-0.in @@ -0,0 +1,3 @@ +[a2, b2, c2, d2, a1, b1, c1, d1] -> { s0[i, j] -> [i, j, 0] : i >= a1 and i <= b1 and j >= c1 and j <= d1; s1[i, j] -> [i, j, 1] : i >= a2 and i <= b2 and j >= c2 and j <= d2 } +{ : } +[a1, b1, c1, d1] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2 } Index: contrib/isl/test_inputs/codegen/omega/wak2-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak2-1.c @@ -0,0 +1,34 @@ +if (c2 >= d2 + 1) { + for (int c0 = a1; c0 <= b1; c0 += 1) + for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1) + s0(c0, c1_0); +} else { + for (int c0 = a1; c0 <= min(b1, a2 - 1); c0 += 1) + for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1) + s0(c0, c1_0); + for (int c0 = a2; c0 <= b2; c0 += 1) { + if (a1 >= c0 + 1) { + for (int c1_0 = c2; c1_0 <= d2; c1_0 += 1) + s1(c0, c1_0); + } else if (c0 >= b1 + 1) { + for (int c1_0 = c2; c1_0 <= d2; c1_0 += 1) + s1(c0, c1_0); + } else { + for (int c1_0 = c2; c1_0 <= min(c1 - 1, d2); c1_0 += 1) + s1(c0, c1_0); + for (int c1_0 = c1; c1_0 <= min(d1, c2 - 1); c1_0 += 1) + s0(c0, c1_0); + for (int c1_0 = max(c1, c2); c1_0 <= min(d1, d2); c1_0 += 1) { + s0(c0, c1_0); + s1(c0, c1_0); + } + for (int c1_0 = max(max(c1, d1 + 1), c2); c1_0 <= d2; c1_0 += 1) + s1(c0, c1_0); + for (int c1_0 = max(c1, d2 + 1); c1_0 <= d1; c1_0 += 1) + s0(c0, c1_0); + } + } + for (int c0 = max(max(a1, a2), b2 + 1); c0 <= b1; c0 += 1) + for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1) + s0(c0, c1_0); +} Index: contrib/isl/test_inputs/codegen/omega/wak2-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak2-1.in @@ -0,0 +1,3 @@ +[a2, b2, c2, d2, a1, b1, c1, d1] -> { s0[i, j] -> [i, j, 0] : i >= a1 and i <= b1 and j >= c1 and j <= d1; s1[i, j] -> [i, j, 1] : i >= a2 and i <= b2 and j >= c2 and j <= d2 } +{ : } +[a1, b1, c1, d1] -> { [i0, i1, i2] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/wak3-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak3-0.c @@ -0,0 +1,8 @@ +for (int c0 = a; c0 <= b + 20; c0 += 1) { + if (b >= c0) + s0(c0); + if (c0 >= a + 10 && b + 10 >= c0) + s1(c0); + if (c0 >= a + 20) + s2(c0); +} Index: contrib/isl/test_inputs/codegen/omega/wak3-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak3-0.in @@ -0,0 +1,3 @@ +[a, b] -> { s2[i] -> [i, 2] : i >= 20 + a and i <= 20 + b; s0[i] -> [i, 0] : i >= a and i <= b; s1[i] -> [i, 1] : i >= 10 + a and i <= 10 + b } +{ : } +[a, b] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 } Index: contrib/isl/test_inputs/codegen/omega/wak3-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak3-1.c @@ -0,0 +1,21 @@ +{ + for (int c0 = a; c0 <= min(a + 9, b); c0 += 1) + s0(c0); + for (int c0 = a + 10; c0 <= min(a + 19, b); c0 += 1) { + s0(c0); + s1(c0); + } + for (int c0 = max(a + 10, b + 1); c0 <= min(a + 19, b + 10); c0 += 1) + s1(c0); + for (int c0 = a + 20; c0 <= b; c0 += 1) { + s0(c0); + s1(c0); + s2(c0); + } + for (int c0 = max(a + 20, b + 1); c0 <= b + 10; c0 += 1) { + s1(c0); + s2(c0); + } + for (int c0 = max(a + 20, b + 11); c0 <= b + 20; c0 += 1) + s2(c0); +} Index: contrib/isl/test_inputs/codegen/omega/wak3-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak3-1.in @@ -0,0 +1,3 @@ +[a, b] -> { s2[i] -> [i, 2] : i >= 20 + a and i <= 20 + b; s0[i] -> [i, 0] : i >= a and i <= b; s1[i] -> [i, 1] : i >= 10 + a and i <= 10 + b } +{ : } +[a, b] -> { [i0, i1] -> atomic[o0] : o0 <= -1; [i0, i1] -> separate[o0] : o0 >= 0 } Index: contrib/isl/test_inputs/codegen/omega/wak4-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak4-0.c @@ -0,0 +1,4 @@ +for (int c0 = max(max(max(max(a1, a2), a3), a4), a5); c0 <= min(min(min(min(b1, b2), b3), b4), b5); c0 += 1) { + s0(c0); + s1(c0); +} Index: contrib/isl/test_inputs/codegen/omega/wak4-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak4-0.in @@ -0,0 +1,3 @@ +[a1, a2, a3, a4, a5, b1, b2, b3, b4, b5] -> { s0[i] -> [i, 0] : i >= a1 and i >= a2 and i >= a3 and i >= a4 and i >= a5 and i <= b1 and i <= b2 and i <= b3 and i <= b4 and i <= b5; s1[i] -> [i, 1] : i >= a1 and i >= a2 and i >= a3 and i >= a4 and i >= a5 and i <= b1 and i <= b2 and i <= b3 and i <= b4 and i <= b5 } +{ : } +[a1, a2, a3, a4, a5, b1, b2, b3, b4, b5] -> { [i0, i1] -> separate[o0] : o0 >= 1; [i0, i1] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/wak4-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak4-1.c @@ -0,0 +1,4 @@ +for (int c0 = max(max(max(max(a1, a2), a3), a4), a5); c0 <= min(min(min(min(b1, b2), b3), b4), b5); c0 += 1) { + s0(c0); + s1(c0); +} Index: contrib/isl/test_inputs/codegen/omega/wak4-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/wak4-1.in @@ -0,0 +1,3 @@ +[a1, a2, a3, a4, a5, b1, b2, b3, b4, b5] -> { s0[i] -> [i, 0] : i >= a1 and i >= a2 and i >= a3 and i >= a4 and i >= a5 and i <= b1 and i <= b2 and i <= b3 and i <= b4 and i <= b5; s1[i] -> [i, 1] : i >= a1 and i >= a2 and i >= a3 and i >= a4 and i >= a5 and i <= b1 and i <= b2 and i <= b3 and i <= b4 and i <= b5 } +{ : } +[a1, a2, a3, a4, a5, b1, b2, b3, b4, b5] -> { [i0, i1] -> separate[o0] : o0 >= 0; [i0, i1] -> atomic[o0] : o0 <= -1 } Index: contrib/isl/test_inputs/codegen/omega/x-0.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/x-0.c @@ -0,0 +1,14 @@ +for (int c0 = 1; c0 <= 11; c0 += 1) { + for (int c1 = max(1, c0 - 3); c1 <= min(c0, -c0 + 8); c1 += 1) + s1(c1, c0 - c1 + 1); + for (int c1 = max(1, -c0 + 9); c1 <= min(c0 - 4, -c0 + 12); c1 += 1) + s0(c1, c0 + c1 - 8); + for (int c1 = max(c0 - 3, -c0 + 9); c1 <= min(c0, -c0 + 12); c1 += 1) { + s0(c1, c0 + c1 - 8); + s1(c1, c0 - c1 + 1); + } + for (int c1 = max(c0 - 3, -c0 + 13); c1 <= min(8, c0); c1 += 1) + s1(c1, c0 - c1 + 1); + for (int c1 = max(c0 + 1, -c0 + 9); c1 <= min(8, -c0 + 12); c1 += 1) + s0(c1, c0 + c1 - 8); +} Index: contrib/isl/test_inputs/codegen/omega/x-0.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/x-0.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [8 - i + j, i, 0] : i >= 1 and i <= 8 and j >= 1 and j <= 4; s1[i, j] -> [-1 + i + j, i, 1] : i >= 1 and i <= 8 and j >= 1 and j <= 4 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/omega/x-1.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/x-1.c @@ -0,0 +1,14 @@ +for (int c0 = 1; c0 <= 11; c0 += 1) { + for (int c1 = max(1, c0 - 3); c1 <= min(c0, -c0 + 8); c1 += 1) + s1(c1, c0 - c1 + 1); + for (int c1 = max(1, -c0 + 9); c1 <= min(c0 - 4, -c0 + 12); c1 += 1) + s0(c1, c0 + c1 - 8); + for (int c1 = max(c0 - 3, -c0 + 9); c1 <= min(c0, -c0 + 12); c1 += 1) { + s0(c1, c0 + c1 - 8); + s1(c1, c0 - c1 + 1); + } + for (int c1 = max(c0 - 3, -c0 + 13); c1 <= min(8, c0); c1 += 1) + s1(c1, c0 - c1 + 1); + for (int c1 = max(c0 + 1, -c0 + 9); c1 <= min(8, -c0 + 12); c1 += 1) + s0(c1, c0 + c1 - 8); +} Index: contrib/isl/test_inputs/codegen/omega/x-1.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/omega/x-1.in @@ -0,0 +1,3 @@ +{ s0[i, j] -> [8 - i + j, i, 0] : i >= 1 and i <= 8 and j >= 1 and j <= 4; s1[i, j] -> [-1 + i + j, i, 1] : i >= 1 and i <= 8 and j >= 1 and j <= 4 } +{ : } +{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 } Index: contrib/isl/test_inputs/codegen/pldi2012/README =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/README @@ -0,0 +1,2 @@ +These examples are taken from the "Polyhedra Scanning Revisited" paper +by Chun Chen. Index: contrib/isl/test_inputs/codegen/pldi2012/figure7_b.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure7_b.c @@ -0,0 +1,9 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) { + if (n >= 2) + s0(c0); + for (int c1 = 1; c1 <= 100; c1 += 1) { + s2(c0, c1); + if (n >= 2) + s1(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/pldi2012/figure7_b.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure7_b.in @@ -0,0 +1,5 @@ +[n] -> { s0[i] -> [i,0] : 1 <= i <= 100 and n > 1; + s1[i,j] -> [i,j] : 1 <= i,j <= 100 and n > 1; + s2[i,j] -> [i,j] : 1 <= i,j <= 100 } +[n] -> { : } +[n] -> { [i,j] -> separate[x] : x >= 2 } Index: contrib/isl/test_inputs/codegen/pldi2012/figure7_c.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure7_c.c @@ -0,0 +1,12 @@ +for (int c0 = 1; c0 <= 100; c0 += 1) { + if (n >= 2) { + s0(c0); + for (int c1 = 1; c1 <= 100; c1 += 1) { + s2(c0, c1); + s1(c0, c1); + } + } else { + for (int c1 = 1; c1 <= 100; c1 += 1) + s2(c0, c1); + } +} Index: contrib/isl/test_inputs/codegen/pldi2012/figure7_c.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure7_c.in @@ -0,0 +1,5 @@ +[n] -> { s0[i] -> [i,0] : 1 <= i <= 100 and n > 1; + s1[i,j] -> [i,j] : 1 <= i,j <= 100 and n > 1; + s2[i,j] -> [i,j] : 1 <= i,j <= 100 } +[n] -> { : } +[n] -> { [i,j] -> separate[x] : x >= 1 } Index: contrib/isl/test_inputs/codegen/pldi2012/figure7_d.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure7_d.c @@ -0,0 +1,13 @@ +if (n >= 2) { + for (int c0 = 1; c0 <= 100; c0 += 1) { + s0(c0); + for (int c1 = 1; c1 <= 100; c1 += 1) { + s2(c0, c1); + s1(c0, c1); + } + } +} else { + for (int c0 = 1; c0 <= 100; c0 += 1) + for (int c1 = 1; c1 <= 100; c1 += 1) + s2(c0, c1); +} Index: contrib/isl/test_inputs/codegen/pldi2012/figure7_d.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure7_d.in @@ -0,0 +1,5 @@ +[n] -> { s0[i] -> [i,0] : 1 <= i <= 100 and n > 1; + s1[i,j] -> [i,j] : 1 <= i,j <= 100 and n > 1; + s2[i,j] -> [i,j] : 1 <= i,j <= 100 } +[n] -> { : } +[n] -> { [i,j] -> separate[x] : x >= 0 } Index: contrib/isl/test_inputs/codegen/pldi2012/figure8_a.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure8_a.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 <= n; c0 += 4) + for (int c1 = c0; c1 <= n; c1 += 3) + s0(c0, c1); Index: contrib/isl/test_inputs/codegen/pldi2012/figure8_a.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure8_a.in @@ -0,0 +1,4 @@ +[n] -> { s0[i,j] -> [i,j] : exists alpha, beta: 1 <= i <= n and i <= j <= n and + i = 1 + 4 alpha and j = i + 3 beta} +[n] -> { : } +[n] -> {} Index: contrib/isl/test_inputs/codegen/pldi2012/figure8_b.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure8_b.c @@ -0,0 +1,8 @@ +{ + for (int c0 = 2; c0 < n - 1; c0 += 4) { + s1(c0); + s0(c0 + 2); + } + if (n >= 1 && n % 4 >= 2) + s1(-(n % 4) + n + 2); +} Index: contrib/isl/test_inputs/codegen/pldi2012/figure8_b.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/pldi2012/figure8_b.in @@ -0,0 +1,4 @@ +[n] -> { s0[i] -> [i] : exists alpha: 1 <= i <= n and i = 4 alpha; + s1[i] -> [i] : exists alpha: 1 <= i <= n and i = 4 alpha + 2 } +[n] -> { : } +[n] -> { } Index: contrib/isl/test_inputs/codegen/redundant.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/redundant.c @@ -0,0 +1,11 @@ +for (int c0 = 0; c0 <= 2; c0 += 1) + for (int c1 = max(0, b0 - 4 * c0 - 1); c1 <= 1; c1 += 1) { + if (b0 >= 1 && 4 * c0 + c1 >= 1) + for (int c2 = 1; c2 <= 2; c2 += 1) + for (int c3 = 1; c3 <= 14; c3 += 1) + write(c0, c1, 8 * b0 + c2 - 5, c3); + for (int c2 = max(max(3, -8 * b0 + 6), 8 * c0 - 12); c2 <= min(min(7, -8 * b0 + 17), 8 * c0 + 6); c2 += 1) + if (4 * c0 + c1 + 1 >= 2 * ((2 * c1 + c2 - 1) / 4) && 2 * ((2 * c1 + c2 - 1) / 4) + 7 >= 4 * c0 + c1 && (2 * c1 + c2 - 1) % 4 >= 1 && ((2 * c1 + c2 - 1) % 4) + 11 >= 2 * c2) + for (int c3 = 1; c3 <= 14; c3 += 1) + write(c0, c1, 8 * b0 + c2 - 5, c3); + } Index: contrib/isl/test_inputs/codegen/redundant.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/redundant.st @@ -0,0 +1,6 @@ +# Check that b1 >= 1 is not dropped by mistake in 4 * c0 + c1 >= 1 part +domain: "[b0] -> { write[i0, o1, o2, o3] : ((exists (e0 = floor((4 + o2)/8), e1 = floor((5 + o2)/8), e2 = floor((4 + o2)/262144), e3, e4: o1 <= 1 and o1 >= 0 and o2 <= 12 and o2 >= 1 and o3 <= 14 and o3 >= 1 and 8e0 <= 4 + o2 and 8e1 <= 5 + o2 and 262144e2 <= 4 - 8b0 + o2 and 262144e2 >= -262139 + o2 and 262144e2 <= 4 + o2 and 262144e2 >= -3 - 8b0 + o2 and 4e4 <= 1 - 8i0 + 2o1 - o2 + 8e0 and 4e4 <= 4 - 8i0 + 2o1 + o2 - 8e0 and 4e4 >= 2o1 + o2 - 8e1 - 8e3 and 4e4 >= -3 + 2o1 + o2 - 8e0 - 8e3 and 4e4 >= -6 + 2o1 - o2 + 8e0 - 8e3 and 2e4 >= -9 + o1 and 2e4 <= -1 + o1 and 4e4 <= -6 + 2o1 - o2 + 8e1 - 8e3 and 4e4 >= -3 - 8i0 + 2o1 + o2 - 8e0 and 4e4 >= -6 - 8i0 + 2o1 - o2 + 8e0)) or (exists (e0 = floor((4 + o2)/8), e1 = floor((5 + o2)/8), e2 = floor((4 + o2)/262144), e3, e4: o1 <= 1 and o1 >= 0 and o2 <= 12 and o2 >= 1 and o3 <= 14 and o3 >= 1 and 8e0 <= 4 + o2 and 8e1 >= -2 + o2 and 262144e2 <= 4 - 8b0 + o2 and 262144e2 >= -262139 + o2 and 262144e2 <= 4 + o2 and 262144e2 >= -3 - 8b0 + o2 and 4e4 <= 1 - 8i0 + 2o1 - o2 + 8e0 and 4e4 <= 4 - 8i0 + 2o1 + o2 - 8e0 and 4e4 >= -3 + 2o1 + o2 - 8e0 - 8e3 and 4e4 >= -6 + 2o1 - o2 + 8e0 - 8e3 and 2e4 >= -9 + o1 and 2e4 <= -1 + o1 and 4e4 <= 1 + 2o1 - o2 + 8e0 - 8e3 and 4e4 <= 4 + 2o1 + o2 - 8e0 - 8e3 and 4e4 <= -1 + 2o1 + o2 - 8e1 - 8e3 and 4e4 >= -3 - 8i0 + 2o1 + o2 - 8e0 and 4e4 >= -6 - 8i0 + 2o1 - o2 + 8e0)) or (exists (e0 = floor((2 + o2)/8), e1 = floor((4 + o2)/8), e2 = floor((4 + o2)/262144), e3, e4: o1 <= 1 and o1 >= 0 and o2 <= 13 and o2 >= 3 and o3 <= 14 and o3 >= 1 and 8e0 >= -5 + o2 and 8e1 <= 4 + o2 and 262144e2 <= 4 - 8b0 + o2 and 262144e2 >= -262139 + o2 and 262144e2 <= 4 + o2 and 262144e2 >= -3 - 8b0 + o2 and 4e4 <= 1 - 8i0 + 2o1 - o2 + 8e1 and 4e4 <= 4 - 8i0 + 2o1 + o2 - 8e1 and 4e4 >= -3 + 2o1 + o2 - 8e1 - 8e3 and 4e4 >= -6 + 2o1 - o2 + 8e1 - 8e3 and 2e4 >= -9 + o1 and 2e4 <= -1 + o1 and 4e4 <= 1 + 2o1 - o2 + 8e1 - 8e3 and 4e4 <= -4 + 2o1 + o2 - 8e0 - 8e3 and 4e4 <= 4 + 2o1 + o2 - 8e1 - 8e3 and 4e4 >= -3 - 8i0 + 2o1 + o2 - 8e1 and 4e4 >= -6 - 8i0 + 2o1 - o2 + 8e1))) and b0 >= 0 and i0 <= 2 and i0 >= 0 and b0 <= 2 }" +child: + context: "[b0] -> { [] : b0 <= 2 and b0 >= 0 }" + child: + schedule: "[b0] -> [{ write[i0, o1, o2, o3] -> [i0] }, { write[i0, i1, i2, i3] -> [(i1)] }, { write[i0, i1, i2, i3] -> [(5 - 8b0 + i2)] }, { write[i0,i1, i2, i3] -> [(i3)] }]" Index: contrib/isl/test_inputs/codegen/roman.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/roman.c @@ -0,0 +1,32 @@ +{ + for (int c1 = 0; c1 <= min(np1 - i, -i + 1); c1 += 1) { + S_9(c1); + S_12(c1); + } + for (int c1 = max(0, -i + 2); c1 <= -((-np1 + i + 4294967295) % 4294967296) + 4294967295; c1 += 1) { + S_9(c1); + S_10(c1); + for (int c3 = 0; c3 <= min(19, i + c1 - 3); c3 += 1) { + S_15(c1, c3); + for (int c5 = 0; c5 < c3; c5 += 1) { + S_16(c1, c3, c5); + S_17(c1, c3, c5); + } + S_16(c1, c3, c3); + S_18(c1, c3); + S_24(c1, c3); + S_19(c1, c3); + } + if (i + c1 <= 21) { + S_15(c1, i + c1 - 2); + for (int c5 = 0; c5 < i + c1 - 2; c5 += 1) { + S_16(c1, i + c1 - 2, c5); + S_17(c1, i + c1 - 2, c5); + } + S_16(c1, i + c1 - 2, i + c1 - 2); + S_18(c1, i + c1 - 2); + S_24(c1, i + c1 - 2); + } + S_12(c1); + } +} Index: contrib/isl/test_inputs/codegen/roman.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/roman.in @@ -0,0 +1,5 @@ +# Older versions of isl would get confused on this input due to disappearing +# div constraints. +[np1, i] -> { S_17[i0, i1, i2] -> [0, i0, 2, i1, 1, i2, 1] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296], e2 = [(i1)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i2 >= 0 and 4294967296e2 <= i1 and 4294967296e2 >= -4294967295 + i1 and 4294967296e2 <= i1 - i2 and i2 <= 19 and i0 >= 2 - i and i2 <= -1 + i1); S_18[i0, i1] -> [0, i0, 2, i1, 2, 0, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i0 >= 2 - i); S_24[i0, i1] -> [0, i0, 2, i1, 3, 0, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i0 >= 2 - i); S_15[i0, i1] -> [0, i0, 2, i1, 0, 0, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i0 >= 2 - i); S_9[i0] -> [0, i0, 0, 0, 0, 0, 0] : exists (e0 = [(np1 - i)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20); S_10[i0] -> [0, i0, 1, 0, 0, 0, 0] : exists (e0 = [(np1 - i)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i0 >= 2 - i); S_19[i0, i1] -> [0, i0, 2, i1, 4, 0, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i0 >= 2 - i and i1 <= -3 + i + i0); S_12[i0] -> [0, i0, 3, 0, 0, 0, 0] : exists (e0 = [(np1 - i)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20); S_16[i0, i1, i2] -> [0, i0, 2, i1, 1, i2, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296], e2 = [(i1)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i2 >= 0 and 4294967296e2 <= i1 and 4294967296e2 >= -4294967295 + i1 and 4294967296e2 <= i1 - i2 and i2 <= 19 and i0 >= 2 - i) } +[np1, i] -> { : exists (e0 = [(np1 - i)/4294967296]: 4294967296e0 <= np1 - i and 4294967296e0 >= -20 + np1 - i and np1 >= -2147483648 and np1 <= 2147483647 and i >= -2147483648 and i <= 2147483647) } +[np1, i] -> { [i0, i1, i2, i3, i4, i5, i6] -> separate[o0] } Index: contrib/isl/test_inputs/codegen/separate.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separate.c @@ -0,0 +1,8 @@ +{ + a(0); + for (int c0 = 1; c0 <= 9; c0 += 1) { + a(c0); + b(c0 - 1); + } + b(9); +} Index: contrib/isl/test_inputs/codegen/separate.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separate.in @@ -0,0 +1,3 @@ +{ a[i] -> [i, 0] : 0 <= i < 10; b[i] -> [i+1, 1] : 0 <= i < 10 } +{ : } +{ [i, d] -> separate[x] } Index: contrib/isl/test_inputs/codegen/separate.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separate.st @@ -0,0 +1,8 @@ +domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }" +child: + schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]" + options: "{ separate[x] }" + child: + sequence: + - filter: "{ a[i] }" + - filter: "{ b[i] }" Index: contrib/isl/test_inputs/codegen/separate2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separate2.c @@ -0,0 +1,8 @@ +for (int c0 = 0; c0 <= 1; c0 += 1) + for (int c5 = 0; c5 <= 31; c5 += 1) + for (int c6 = max(0, 2 * (length % 16) + 2 * c5 - 62); c6 <= 30; c6 += 1) { + if (2 * length + c6 >= 2 * (length % 16) + 2 && c6 + 62 >= 2 * (length % 16) + 2 * c5 && 2 * (length % 16) >= c6 + 2 && 2 * (length % 16) + 2 * c5 >= c6 && 2 * (length % 32) + c6 == 2 * (length % 16) + 2 * c5 && (2 * c5 - c6) % 32 == 0) + S_3(c0, 0, (c6 / 2) - (length % 16) + length); + if (length <= 15 && length >= c5 + 1 && c6 >= 1 && length >= c6) + S_0(c0, c5, c6 - 1); + } Index: contrib/isl/test_inputs/codegen/separate2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separate2.in @@ -0,0 +1,4 @@ +# Check that rational affine expressions are printer properly. +[tsteps, length] -> { S_0[iter, i, j] -> [iter, 0, o2, o3, 0, o5, o6, 4] : exists (e0 = [(o2)/32], e1 = [(o3)/32], e2 = [(-i + o5)/32], e3 = [(-31 + j - o6)/32]: tsteps = 2 and 32e0 = o2 and 32e1 = o3 and 32e2 = -i + o5 and 32e3 = -31 + j - o6 and o2 <= i and o2 >= -31 + i and o3 <= 1 + j and o3 >= -30 + j and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 31 and i <= -1 + length and i >= 0 and iter >= 0 and iter <= 1 and j <= -1 + length and j >= 0 and o2 >= -31 + length and o3 >= -30 + 2length); S_3[iter, 0, j] -> [iter, 0, o2, o3, o4, o5, o6, 2] : exists (e0 = [(o2)/32], e1 = [(o3)/32], e2 = [(o4)/32], e3 = [(-2o5 + o6)/32], e4 = [(j - o5)/32]: tsteps = 2 and 32e0 = o2 and 32e1 = o3 and 32e2 = o4 and 32e3 = -2o5 + o6 and 32e4 = j - o5 and iter <= 1 and j <= -1 + length and o2 <= j and o2 >= -31 + j and o3 <= 2j and o3 >= -30 + 2j and o4 >= 0 and o4 <= 31 and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 30 and j >= 1 and iter >= 0 and o2 >= -31 + length and o3 >= -30 + 2length) } +[tsteps, length] -> { : length >= 1 and length <= 1024 and tsteps = 2 } +{ [o0,o1,o2,o3,o4,o5,o6,o7] -> separate[x] } Index: contrib/isl/test_inputs/codegen/separation_class.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separation_class.c @@ -0,0 +1,17 @@ +{ + for (int c0 = 0; c0 <= 8; c0 += 1) { + for (int c1 = 0; c1 <= -c0 + 8; c1 += 1) + for (int c2 = 10 * c0; c2 <= 10 * c0 + 9; c2 += 1) + for (int c3 = 10 * c1; c3 <= 10 * c1 + 9; c3 += 1) + A(c2, c3); + for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); + } + for (int c0 = 9; c0 <= 10; c0 += 1) + for (int c1 = 0; c1 <= -c0 + 10; c1 += 1) + for (int c2 = 10 * c0; c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1) + for (int c3 = 10 * c1; c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1) + A(c2, c3); +} Index: contrib/isl/test_inputs/codegen/separation_class.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separation_class.in @@ -0,0 +1,6 @@ +{ A[i,j] -> [([i/10]),[j/10],i,j] : 0 <= i,j and i + j <= 100 } +{ : } +{ [a,b,c,d] -> separation_class[[0]->[0]] : + exists b': 0 <= 10a,10b' and 10a+9+10b'+9 <= 100; + [a,b,c,d] -> separation_class[[1]->[0]] : + 0 <= 10a,10b and 10a+9+10b+9 <= 100 } Index: contrib/isl/test_inputs/codegen/separation_class2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separation_class2.c @@ -0,0 +1,15 @@ +{ + for (int c0 = 0; c0 < -(n % 8) + n; c0 += 8) { + for (int c1 = 0; c1 < -(n % 8) + n; c1 += 8) + for (int c2 = 0; c2 <= 7; c2 += 1) + for (int c3 = 0; c3 <= 7; c3 += 1) + A(c0 + c2, c1 + c3); + for (int c2 = 0; c2 <= 7; c2 += 1) + for (int c3 = 0; c3 < n % 8; c3 += 1) + A(c0 + c2, -(n % 8) + n + c3); + } + for (int c1 = 0; c1 < n; c1 += 8) + for (int c2 = 0; c2 < n % 8; c2 += 1) + for (int c3 = 0; c3 <= min(7, n - c1 - 1); c3 += 1) + A(-(n % 8) + n + c2, c1 + c3); +} Index: contrib/isl/test_inputs/codegen/separation_class2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separation_class2.in @@ -0,0 +1,3 @@ +[n] -> { A[i,j] -> [it,jt, ip, jp] : 0 <= i,j < n and ip = i % 8 and it = i - ip and jp = j % 8 and jt = j - jp} +[n] -> { : n >= 10} +[n] -> { [it, jt, ip, jp] -> separation_class[[x]->[1]]: (exists id, jd: 0 <= x <= 3 and it < n - id and jt < n - jd and id = n %8 and jd = n %8)} Index: contrib/isl/test_inputs/codegen/separation_class3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separation_class3.c @@ -0,0 +1,31 @@ +for (int c0 = 0; c0 <= 4; c0 += 1) { + if (c0 == 0) { + S_0(0, 4); + } else { + S_0(2 * c0 - 1, 1); + if (c0 == 4) { + for (int c6 = 3; c6 <= 5; c6 += 1) + S_0(7, c6); + } else { + for (int c4 = 2 * c0 - 1; c4 <= 2 * c0; c4 += 1) + for (int c6 = -2 * c0 + c4 + 4; c6 <= 2 * c0 - c4 + 4; c6 += 1) + S_0(c4, c6); + } + } + for (int c4 = max(0, 2 * c0 - 1); c4 <= min(7, 2 * c0); c4 += 1) + for (int c6 = -2 * c0 + c4 + 8; c6 <= 8; c6 += 1) + S_0(c4, c6); + if (c0 >= 1 && c0 <= 3) { + for (int c2 = 0; c2 <= 1; c2 += 1) + for (int c4 = 2 * c0 - 1; c4 <= 2 * c0; c4 += 1) + for (int c6 = 2 * c0 + 4 * c2 - c4 + 1; c6 <= -2 * c0 + 4 * c2 + c4 + 3; c6 += 1) + S_0(c4, c6); + } else if (c0 == 4) { + for (int c2 = 0; c2 <= 1; c2 += 1) + S_0(7, 4 * c2 + 2); + } else { + for (int c2 = 0; c2 <= 1; c2 += 1) + for (int c6 = 4 * c2 + 1; c6 <= 4 * c2 + 3; c6 += 1) + S_0(0, c6); + } +} Index: contrib/isl/test_inputs/codegen/separation_class3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separation_class3.in @@ -0,0 +1,4 @@ +{ S_0[t, i] -> [o0, 1, o2, 0, t, 0, i] : 4o2 >= -4 + t + i - 2o0 and 4o2 >= -3 - t + i + 2o0 and 2o0 <= 1 + t and 2o0 >= t and 4o2 <= -1 + t + i - 2o0 and t >= 0 and t <= 7 and i >= 1 and i <= 8; S_0[t, i] -> [o0, 0, o2, 0, t, 0, i] : 4o2 >= t + i - 2o0 and 4o2 <= -t + i + 2o0 and 2o0 <= 1 + t and 2o0 >= t and t >= 0 and t <= 7 and i >= 1 and i <= 8 } +{:} +{ [i0, 1, i2, i3, i4, i5, i6] -> separation_class[[2] -> [0]] : i2 <= 1 and i2 >= 0 and i0 <= 3 and i0 >= 1; [i0, 0, 1, i3, i4, i5, i6] -> separation_class[[2] -> [0]] : i0 <= 3 and i0 >= 1; [i0, i1, i2, i3, i4, i5, i6] -> unroll[1] } + Index: contrib/isl/test_inputs/codegen/separation_class4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separation_class4.c @@ -0,0 +1,22 @@ +for (int c0 = 0; c0 <= 128; c0 += 1) { + if (c0 <= 127) { + if (c0 == 0) { + for (int c3 = 0; c3 <= 1; c3 += 1) + for (int c5 = c3 + 58; c5 <= -c3 + 61; c5 += 1) + S_0(c3, c5); + } else { + for (int c2 = 1; c2 <= 2; c2 += 1) + for (int c3 = max(4 * c0 - 2, 4 * c0 + 6 * c2 - 12); c3 <= min(4 * c0 + 1, 4 * c0 + 6 * c2 - 7); c3 += 1) + for (int c5 = max(4 * c0 - c3 + 57, -4 * c0 + c3 + 58); c5 <= min(4 * c0 - c3 + 61, -4 * c0 + c3 + 62); c5 += 1) + S_0(c3, c5); + } + for (int c2 = 1; c2 <= 2; c2 += 1) + for (int c3 = max(4 * c0, 4 * c0 + 6 * c2 - 10); c3 <= min(4 * c0 + 3, 4 * c0 + 6 * c2 - 5); c3 += 1) + for (int c5 = max(-4 * c0 + c3 + 59, 4 * c0 - c3 + 62); c5 <= min(-4 * c0 + c3 + 63, 4 * c0 - c3 + 66); c5 += 1) + S_0(c3, c5); + } else { + for (int c3 = 510; c3 <= 511; c3 += 1) + for (int c5 = -c3 + 569; c5 < c3 - 449; c5 += 1) + S_0(c3, c5); + } +} Index: contrib/isl/test_inputs/codegen/separation_class4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/separation_class4.in @@ -0,0 +1,10 @@ +# Check that isl is not confused by the combination of separation classes +# and unroll. +{ S_0[t, i] -> [o0, 1, o9, t] : 4o0 >= -3 + t and 4o0 <= t and i >= 60 and i <= 65 and 6o9 >= 5 + t - 4o0 and 6o9 <= 10 + t - 4o0 and 4o0 <= -62 + t + i and 4o0 >= 59 + t - i and o0 >= 0 and o0 <= 127 and t <= 511 and t >= 0 and 4o0 >= -66 + t + i and 4o0 <= 63 + t - i; +S_0[t, i] -> [o0, 0, o9, t] : 4o0 >= -1 + t and 4o0 <= 2 + t and i >= 57 and i <= 62 and 6o9 >= 7 + t - 4o0 and 6o9 <= 12 + t - 4o0 and t >= 0 and t <= 511 and 4o0 <= -57 + t + i and 4o0 >= 58 + t - i and o0 >= 0 and o0 <= 128 and 4o0 >= -61 + t + i and 4o0 <= 62 + t - i } +{ : } +{ [i0, i1, i2, t] -> unroll[1]; +[i0, 1, i2, t] -> separation_class[[1] -> [0]] + : 0 <= i0 <= 127; +[i0, 0, i2, t] -> separation_class[[1] -> [0]] + : 1 <= i0 <= 127} Index: contrib/isl/test_inputs/codegen/shift.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/shift.c @@ -0,0 +1,4 @@ +for (int c0 = 0; c0 <= 9; c0 += 1) { + A(c0); + B(c0); +} Index: contrib/isl/test_inputs/codegen/shift.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/shift.in @@ -0,0 +1,3 @@ +{ A[i] -> [2i]: 0 <= i < 10; B[i] -> [2i+1] : 0 <= i < 10 } +{ : } +{ } Index: contrib/isl/test_inputs/codegen/shift2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/shift2.c @@ -0,0 +1,56 @@ +for (int c0 = 0; c0 <= 1; c0 += 1) { + for (int c1 = 0; c1 < length - 1; c1 += 32) { + for (int c2 = c1; c2 < length; c2 += 32) { + if (c1 == 0) + for (int c3 = 0; c3 <= min(length, 2 * c2 - 31); c3 += 32) + for (int c5 = 0; c5 <= min(31, length - c2 - 1); c5 += 1) + for (int c6 = max(0, -c3 + 1); c6 <= min(31, length - c3); c6 += 1) + S_0(c0, c2 + c5, c3 + c6 - 1); + for (int c3 = 2 * c2; c3 <= min(2 * length - 2, 2 * c2 + 62); c3 += 32) + for (int c4 = 0; c4 <= min(min(31, length - c1 - 2), (c3 / 2) - c1 + 14); c4 += 1) { + if (c1 == 0 && c2 == 0 && c4 == 0) + for (int c6 = max(0, -c3 + 1); c6 <= min(31, length - c3); c6 += 1) + S_0(c0, 0, c3 + c6 - 1); + if (c1 == 0 && c3 == 2 * c2 + 32 && c4 == 0) + for (int c5 = max(0, -c2 + 1); c5 <= 15; c5 += 1) + for (int c6 = 0; c6 <= min(31, length - 2 * c2 - 32); c6 += 1) + S_0(c0, c2 + c5, 2 * c2 + c6 + 31); + for (int c5 = max((c3 / 2) - c2, c1 - c2 + c4 + 1); c5 <= min(length - c2 - 1, (c3 / 2) - c2 + 15); c5 += 1) { + if (c1 == 0 && c4 == 0) + for (int c6 = max(0, -c3 + 1); c6 <= min(length - c3, 2 * c2 - c3 + 2 * c5 - 1); c6 += 1) + S_0(c0, c2 + c5, c3 + c6 - 1); + S_3(c0, c1 + c4, c2 + c5); + if (c1 == 0 && c4 == 0 && length >= 2 * c2 + 2 * c5) + S_0(c0, c2 + c5, 2 * c2 + 2 * c5 - 1); + if (c1 == 0 && c4 == 0) + for (int c6 = 2 * c2 - c3 + 2 * c5 + 1; c6 <= min(31, length - c3); c6 += 1) + S_0(c0, c2 + c5, c3 + c6 - 1); + } + if (c1 == 0 && c3 == 2 * c2 && c4 == 0) + for (int c5 = 16; c5 <= min(31, length - c2 - 1); c5 += 1) + for (int c6 = max(0, -2 * c2 + 1); c6 <= min(31, length - 2 * c2); c6 += 1) + S_0(c0, c2 + c5, 2 * c2 + c6 - 1); + if (c1 == 0 && c3 + 30 >= 2 * length && c4 == 0) + S_4(c0); + } + if (c1 == 0) { + for (int c3 = 2 * c2 + 64; c3 <= length; c3 += 32) + for (int c5 = 0; c5 <= 31; c5 += 1) + for (int c6 = 0; c6 <= min(31, length - c3); c6 += 1) + S_0(c0, c2 + c5, c3 + c6 - 1); + if (c2 + 16 == length) + S_4(c0); + } + } + if (c1 == 0 && length % 32 == 0) + S_4(c0); + } + if (length <= 1) + for (int c5 = 0; c5 <= length; c5 += 1) { + if (c5 == length) { + S_4(c0); + } else { + S_0(c0, 0, 0); + } + } +} Index: contrib/isl/test_inputs/codegen/shift2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/shift2.in @@ -0,0 +1,5 @@ +# Check that the shifting code is not confused by domains that +# have a non-obviously fixed value. +[tsteps, length] -> { S_4[iter] -> [iter, 0, o2, o3, 0, o5, o6, 3] : exists (e0 = [(o2)/32], e1 = [(o3)/32], e2 = [(-length + o5)/32], e3 = [(-2length + o6)/32]: tsteps = 2 and 32e0 = o2 and 32e1 = o3 and 32e2 = -length + o5 and 32e3 = -2length + o6 and o2 <= length and o2 >= -31 + length and o3 <= 2length and o3 >= -30 + 2length and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 30 and iter <= 1 and iter >= 0); S_3[iter, i, j] -> [iter, o1, o2, o3, o4, o5, o6, 2] : exists (e0 = [(o1)/32], e1 = [(o2)/32], e2 = [(o3)/32], e3 = [(-i + o4)/32], e4 = [(-j + o5)/32], e5 = [(-2j + o6)/32]: tsteps = 2 and 32e0 = o1 and 32e1 = o2 and 32e2 = o3 and 32e3 = -i + o4 and 32e4 = -j + o5 and 32e5 = -2j + o6 and o1 <= i and o1 >= -31 + i and o2 <= j and o2 >= -31 + j and o3 <= 2j and o3 >= -30 + 2j and o4 >= 0 and o4 <= 31 and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 30 and j >= 1 + i and i >= 0 and iter <= 1 and iter >= 0 and j <= -1 + length); S_0[iter, i, j] -> [iter, 0, o2, o3, 0, o5, o6, 4] : exists (e0 = [(o2)/32], e1 = [(o3)/32], e2 = [(-i + o5)/32], e3 = [(-31 + j - o6)/32]: tsteps = 2 and 32e0 = o2 and 32e1 = o3 and 32e2 = -i + o5 and 32e3 = -31 + j - o6 and o2 <= i and o2 >= -31 + i and o3 <= 1 + j and o3 >= -30 + j and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 31 and i <= -1 + length and i >= 0 and iter >= 0 and iter <= 1 and j <= -1 + length and j >= 0) } +[tsteps, length] -> { : length >= 0 and length <= 1024 and tsteps = 2 } +{ } Index: contrib/isl/test_inputs/codegen/shift_unroll.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/shift_unroll.c @@ -0,0 +1,14 @@ +for (int c0 = 0; c0 <= 9; c0 += 1) { + A(c0, 0); + A(c0, 1); + A(c0, 2); + A(c0, 3); + A(c0, 4); + A(c0, 5); + A(c0, 6); + A(c0, 7); + A(c0, 8); + A(c0, 9); + for (int c2 = 0; c2 <= 9; c2 += 1) + B(c0, c2); +} Index: contrib/isl/test_inputs/codegen/shift_unroll.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/shift_unroll.in @@ -0,0 +1,3 @@ +{ A[i,j] -> [2i,0,j]: 0 <= i,j < 10; B[i,j] -> [2i+1,1,j] : 0 <= i,j < 10 } +{ : } +{ [i,0,j] -> unroll[2] } Index: contrib/isl/test_inputs/codegen/single_valued.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/single_valued.c @@ -0,0 +1,2 @@ +if (2 * ((t1 - 1) % 64) + 8 >= t1) + S(-(2 * ((t1 - 1) % 64)) + t1 + 126); Index: contrib/isl/test_inputs/codegen/single_valued.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/single_valued.in @@ -0,0 +1,5 @@ +# Check that isl recognizes that the inverse schedule is single-valued +# and does not end up in an infinite recursion. +[t1] -> {S[c2] -> [c2]: t1 <= c2 <= 134 and (c2+t1) % 128 = 0 and c2 > 0} +[t1] -> {: t1 > 0} +[t1] -> {} Index: contrib/isl/test_inputs/codegen/sor1d-part.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/sor1d-part.c @@ -0,0 +1,3 @@ +for (int c0 = 1; c0 < max((6 * M + 3 * N + 188) / 200 - 2, (N + 93) / 100 + 3 * ((2 * M + N - 4) / 200) - 1); c0 += 1) + for (int c1 = max(0, floord(-N + 100 * c0 + 106, 300)); c1 <= min((2 * M + N - 4) / 200 - 1, (c0 - 1) / 3); c1 += 1) + S2(c0 - c1, c1); Index: contrib/isl/test_inputs/codegen/sor1d-part.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/sor1d-part.st @@ -0,0 +1,10 @@ +# Check that a proper upper bound is generated for the outer loop. +# Earlier versions of isl would generate an incorrect bound. +domain: "[M, N] -> { S2[i0, i1] : i1 >= 0 and 200i1 >= -193 - N + 100i0 and i0 >= 0 and 200i1 <= -204 + 2M + N and 2i1 <= -1 + i0 and 100i1 >= -94 - N + 50i0 and 100i1 >= -94 - N }" +child: + context: "[M, N] -> { [] : M >= 0 and N >= 4 }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0 + i1)]}]" + options: "[M, N] -> { separate[i0] }" + child: + schedule: "[M, N] -> [{ S2[i0, i1] -> [(i1)]}]" Index: contrib/isl/test_inputs/codegen/stride.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/stride.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 <= 100; c0 += 2) { + for (int c3 = 0; c3 <= 100; c3 += 1) + A(c0, c3); + for (int c2 = 0; c2 <= 100; c2 += 1) + B(c0, c2); +} Index: contrib/isl/test_inputs/codegen/stride.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/stride.in @@ -0,0 +1,6 @@ +# Check that we find a common stride on the first dimension +# even if it is imposed by different inner dimensions +{ A[i,k] -> [i,0,j,k] : 0 <= i,k <= 100 and i = 2 j; + B[i,k] -> [i,1,k,j] : 0 <= i,k <= 100 and i = 2 j } +{ : } +{ } Index: contrib/isl/test_inputs/codegen/stride5.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/stride5.c @@ -0,0 +1,3 @@ +if (n % 2 == 0) + for (int c0 = (-n / 2) + 2 * floord(n - 1, 4) + 2; c0 <= 100; c0 += 2) + S(c0); Index: contrib/isl/test_inputs/codegen/stride5.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/stride5.in @@ -0,0 +1,3 @@ +[n] -> { S[t] -> [t] : exists e : 2 t - n = 4e and 0 <= t <= 100 } +[n] -> { : } +{ } Index: contrib/isl/test_inputs/codegen/stride6.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/stride6.c @@ -0,0 +1,4 @@ +for (int c1 = -1024; c1 <= 0; c1 += 32) + for (int c2 = max(-((niter - 1) % 32) + niter - 1, -((niter - c1) % 32) + niter - c1 - 32); c2 <= min(niter + 1022, niter - c1 - 1); c2 += 32) + for (int c5 = max(max(0, -c1 - 1023), niter - c1 - c2 - 32); c5 <= min(min(31, -c1), niter - c1 - c2 - 1); c5 += 1) + S_4(niter - 1, -c1 - c5); Index: contrib/isl/test_inputs/codegen/stride6.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/stride6.in @@ -0,0 +1,3 @@ +[niter] -> { S_4[-1 + niter, i] -> [o0, o1, o2, o3, o4, o5, o6, o7, 4] : exists (e0 = [(o0)/32], e1 = [(o1)/32], e2 = [(o2)/32], e3 = [(o3)/32], e4 = [(-31i + o5)/32], e5 = [(-i - o4 + o6)/32], e6 = [(-o4 + o7)/32], e7 = [(-1 + niter - o4)/32]: 32e0 = o0 and 32e1 = o1 and 32e2 = o2 and 32e3 = o3 and 32e4 = -31i + o5 and 32e5 = -i - o4 + o6 and 32e6 = -o4 + o7 and 32e7 = -1 + niter - o4 and o0 <= -1 + niter and o0 >= -32 + niter and o1 <= -i and o1 >= -31 - i and o2 <= -1 + niter + i and o2 >= -32 + niter + i and o3 <= 1023 + niter and o3 >= 992 + niter and o4 >= 0 and o4 <= 31 and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 31 and o7 >= 0 and o7 <= 31 and i <= 1023 and i >= 0 and niter >= 1) } +[niter] -> { : niter <= 8192 and niter >= 1 } +[niter] -> { } Index: contrib/isl/test_inputs/codegen/stride7.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/stride7.c @@ -0,0 +1,6 @@ +for (int c0 = 2; c0 <= 200; c0 += 64) { + for (int c2 = c0 - 1; c2 <= 120; c2 += 1) + s2(c0, c2); + for (int c2 = 122; c2 <= c0 + 62; c2 += 1) + s4(c0, c2); +} Index: contrib/isl/test_inputs/codegen/stride7.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/stride7.in @@ -0,0 +1,7 @@ +# Check that no redundant guards are introduced +{ s4[a, b] -> [a, 2, b] : exists (e0 = floor((-2 + a)/64): + 64e0 = -2 + a and a <= 200 and b <= 62 + a and b >= 122); + s2[a, b] -> [a, 2, b] : exists (e0 = floor((-2 + a)/64): + 64e0 = -2 + a and a >= 2 and b <= 120 and b >= -1 + a and a <= 100) } +{ : } +{ } Index: contrib/isl/test_inputs/codegen/unroll.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll.c @@ -0,0 +1,5 @@ +{ + A(0); + A(100000000); + A(200000000); +} Index: contrib/isl/test_inputs/codegen/unroll.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll.in @@ -0,0 +1,5 @@ +# Test that unrolling takes into account stride constraints. +# If it didn't, it would run essentially forever on this example. +[n] -> { A[i] -> [i] : exists a : i = 100000000 a and 0 <= a <= 2 } +{:} +{ [i] -> unroll[0] } Index: contrib/isl/test_inputs/codegen/unroll10.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll10.c @@ -0,0 +1,29 @@ +if (m >= 1 && n >= 1) { + A(0); + if (m >= 2 && n >= 2) { + A(1); + if (m >= 3 && n >= 3) { + A(2); + if (m >= 4 && n >= 4) { + A(3); + if (m >= 5 && n >= 5) { + A(4); + if (m >= 6 && n >= 6) { + A(5); + if (m >= 7 && n >= 7) { + A(6); + if (m >= 8 && n >= 8) { + A(7); + if (m >= 9 && n >= 9) { + A(8); + if (m >= 10 && n >= 10) + A(9); + } + } + } + } + } + } + } + } +} Index: contrib/isl/test_inputs/codegen/unroll10.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll10.in @@ -0,0 +1,4 @@ +# Check that all information is taken into account while trying to unroll +[m,n] -> { A[i] -> [i] : 0 <= i < n,m } +[m,n] -> { : m <= 10 or n <= 10 } +{ [i] -> unroll[x] } Index: contrib/isl/test_inputs/codegen/unroll10.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll10.st @@ -0,0 +1,7 @@ +# Check that all information is taken into account while trying to unroll +domain: "[m,n] -> { A[i] : 0 <= i < n,m }" +child: + context: "[m,n] -> { [] : m <= 10 or n <= 10 }" + child: + schedule: "[{ A[i] -> [i] }]" + options: "{ unroll[x] }" Index: contrib/isl/test_inputs/codegen/unroll11.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll11.c @@ -0,0 +1,8 @@ +{ + if (t1 >= 126) + S(0, t1 - 384); + S(0, t1 - 256); + if (t1 >= 126) + S(1, t1 - 384); + S(1, t1 - 256); +} Index: contrib/isl/test_inputs/codegen/unroll11.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll11.in @@ -0,0 +1,10 @@ +# Check that the most appropriate lower bound is selected +[t1,t2]->{ S[i,j] -> [i,j] : exists (alpha, beta : + 0 <= i <= 1 && + t1 = j+128alpha && + 0 <= j+2beta < 128 && + 510 <= t2+2beta <= 514 && + 0 <= 2beta - t2 <= 5 +)} +[t1,t2] -> {: 125 <= t1 <= 127 and 254 <= t2 < 257} +{[i,j] -> unroll[x]} Index: contrib/isl/test_inputs/codegen/unroll2.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll2.c @@ -0,0 +1,11 @@ +{ + A(0); + A(1); + A(2); + A(3); + for (int c0 = 4; c0 <= 99996; c0 += 1) + A(c0); + A(99997); + A(99998); + A(99999); +} Index: contrib/isl/test_inputs/codegen/unroll2.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll2.in @@ -0,0 +1,5 @@ +# Check that the different disjuncts in the unroll option +# are handled separately. +{ A[i] -> [i] : 0 <= i < 100000 } +{ : } +{ [i] -> unroll[0] : i < 4 or i > 99996 } Index: contrib/isl/test_inputs/codegen/unroll3.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll3.c @@ -0,0 +1,2 @@ +if ((t1 + 121) % 128 <= 123) + write_shared_A(((t1 + 121) % 128) + 1); Index: contrib/isl/test_inputs/codegen/unroll3.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll3.in @@ -0,0 +1,6 @@ +# Check that the entire schedule is completely unrolled and +# in particular that no spurious loop is introduced. +[t1] -> { write_shared_A[i2] -> [1, 3, 6 + i2, 0, t1] : (exists (e0 = [(-6 + t1 - i2)/128]: 128e0 = -6 + t1 - i2 and i2 <= 122 and i2 >= 1 and t1 >= 0 and t1 <= 127)) or (exists (e0 = [(-6 + t1 - i2)/128]: 128e0 = -6 + t1 - i2 and i2 >= 123 and i2 <= 124 and t1 <= 127 and t1 >= 0 )) } +[t1] -> { : t1 >= 0 and t1 <= 127 } +[t1] -> { [i0, i1, i2, i3, i4] -> unroll[o0] } + Index: contrib/isl/test_inputs/codegen/unroll4.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll4.c @@ -0,0 +1,16 @@ +{ + write_shared_A(3, ((t1 + 3) % 4) + 1, ((t2 + 31) % 32) + 1); + if (t2 >= 1 && t2 <= 2 && t1 % 3 == 0) + write_shared_A(3, (-t1 / 3) + 4, t2 + 32); + if (((-((t1 + 3) % 4) + t2 + 30) % 32) + t1 >= ((t1 + 3) % 4) + ((t2 + 1) % 2) - 4 * ((-t1 + 4) / 4) + 1) + write_shared_A(3, ((t1 + 3) % 4) + 5, -((((t1 + 3) % 4) - t2 + 33) % 32) + t1 + 4 * ((-t1 + 4) / 4) + 32); + if (t1 >= 1 && t2 >= t1 + 1 && t2 <= 4) + write_shared_A(3, t1 + 4, t2 + 32); + write_shared_A(4, ((t1 + 3) % 4) + 1, ((t2 + 31) % 32) + 1); + if (t2 >= 1 && t2 <= 2 && t1 % 3 == 0) + write_shared_A(4, (-t1 / 3) + 4, t2 + 32); + if (((-((t1 + 3) % 4) + t2 + 30) % 32) + t1 >= ((t1 + 3) % 4) + ((t2 + 1) % 2) - 4 * ((-t1 + 4) / 4) + 1) + write_shared_A(4, ((t1 + 3) % 4) + 5, -((((t1 + 3) % 4) - t2 + 33) % 32) + t1 + 4 * ((-t1 + 4) / 4) + 32); + if (t1 >= 1 && t2 >= t1 + 1 && t2 <= 4) + write_shared_A(4, t1 + 4, t2 + 32); +} Index: contrib/isl/test_inputs/codegen/unroll4.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll4.in @@ -0,0 +1,5 @@ +# Check that the generated code does not contain two declarations +# of the same variable in the same scope. +[t1, t2, g] -> { write_shared_A[a, b, c] -> [0, a, b, c] : exists (e0, e1 = [(-t1 + b)/4], e2 = [(-t2 + c)/32]: 4e1 = -t1 + b and 32e2 = -t2 + c and e0 <= 2 + 3g and e0 >= 3g and a <= 4 and a >= 3 and t2 >= 0 and t1 <= 3 and 2e0 >= 5 - c + 6g and 2e0 <= 36 - c + 6g and 2e0 >= 5 - b + 6g and 2e0 <= 8 - b + 6g and 2e0 <= 638 - c and 2e0 <= 638 - b and 2e0 >= 2 - a + 6g and 2e0 >= -8 + a + 6g and 2e0 <= 1 + a + 6g and 2e0 <= 11 - a + 6g and e0 >= 0 and e0 <= 254 and t1 >= 0 and t2 <= 31 and b >= 1 and b <= 126 and c >= 1 and c <= 126 and g <= 3 and g >= 0) } +[t1, t2, g] -> { : g <= 3 and g >= 0 and t1 >= 0 and t1 <= 3 and t2 >= 0 and t2 <= 5 } +[t1, t2] -> { [i0, i1, i2, i3] -> unroll[x] } Index: contrib/isl/test_inputs/codegen/unroll6.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll6.c @@ -0,0 +1,8 @@ +{ + if (g >= 0 && nn >= 128 * g + 6 && nn >= ((t1 + 127) % 128) + 128 * g + 3) + for (int c1 = 393214; c1 < nn - 1; c1 += 393216) + A(c1, ((t1 + 127) % 128) + 128 * g + 1, ((t1 + 127) % 128) + 1); + if (t1 >= 1 && t1 <= 2 && nn >= t1 + 128 * g + 130 && t1 + 128 * g >= -127) + for (int c1 = 393214; c1 < nn - 1; c1 += 393216) + A(c1, t1 + 128 * g + 128, t1 + 128); +} Index: contrib/isl/test_inputs/codegen/unroll6.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll6.in @@ -0,0 +1,7 @@ +# Check that the right lower bound is chosen for unrolling. +# Older versions of isl would pick a lower bound that resulted +# in a number of slices that exceeds the maximal value of an integer +# and then only generated code for a truncated number (zero) of slices. +[nn, t1, g] -> { A[a, b, c] -> [c] : exists (e0 = [(2 + a)/393216], e1 = [(t1 - c)/128]: 128g = b - c and 393216e0 = 2 + a and 128e1 = t1 - c and c <= 130 and c >= 6 - nn + b and c <= 128 + b and nn >= 137 and t1 >= 0 and c >= 1 and a <= -2 + nn and a >= 1 and nn <= 9223372036854775807 and b >= 1 and b <= -2 + nn and t1 <= 127) } +[nn, t1, g] -> { : nn <= 9223372036854775807 and nn >= 137 and t1 >= 0 and t1 <= 127 } +{ [c] -> unroll[x] } Index: contrib/isl/test_inputs/codegen/unroll7.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll7.c @@ -0,0 +1,10 @@ +{ + S(0, 0); + S(0, 3); + S(0, 4); + S(1, 1); + S(1, 4); + S(2, 2); + S(3, 3); + S(4, 4); +} Index: contrib/isl/test_inputs/codegen/unroll7.in =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll7.in @@ -0,0 +1,5 @@ +# Check that some code is generated. +# Older versions of isl would abort on unknown divs. +{ S[i,j] -> [i,j]: exists (alpha, beta: j=i+4alpha +3beta and 0 <= alpha < 24 and 0 <= beta and 0 <= i,j < 5) } +{ : } +{ [i,j] -> unroll[x] } Index: contrib/isl/test_inputs/codegen/unroll8.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll8.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 <= 99; c0 += 1) { + A(c0, 0); + A(c0, 1); + B(c0, 0); + B(c0, 1); +} Index: contrib/isl/test_inputs/codegen/unroll8.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll8.st @@ -0,0 +1,5 @@ +# Check that options are adjusted by shifted stride detection +domain: "{ A[i,j] : 0 <= i < 100 and 0 <= j < 2; B[i,j] : 0 <= i < 100 and 0 <= j < 2 }" +child: + schedule: "[{ A[i,j] -> [2i]; B[i,j] -> [2i+1] }, { A[i,j] -> [j]; B[i,j] -> [j]}]" + options: "{ unroll[1] }" Index: contrib/isl/test_inputs/codegen/unroll9.c =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll9.c @@ -0,0 +1,7 @@ +for (int c0 = 0; c0 <= 99; c0 += 1) + for (int c1 = 0; c1 <= 99; c1 += 1) { + A(c1, 0, c0); + A(c1, 1, c0); + B(c1, 0, c0); + B(c1, 1, c0); + } Index: contrib/isl/test_inputs/codegen/unroll9.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/codegen/unroll9.st @@ -0,0 +1,7 @@ +# Check that options are interpreted locally +domain: "{ A[i,j,k] : 0 <= i,k < 100 and 0 <= j < 2; B[i,j,k] : 0 <= i,k < 100 and 0 <= j < 2 }" +child: + schedule: "[{ A[i,j,k] -> [k]; B[i,j,k] -> [k] }]" + child: + schedule: "[{ A[i,j,k] -> [2i]; B[i,j,k] -> [2i+1] }, { A[i,j,k] -> [j]; B[i,j,k] -> [j]}]" + options: "{ unroll[1] }" Index: contrib/isl/test_inputs/convex0.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex0.polylib @@ -0,0 +1,11 @@ +2 3 +1 1 0 +1 -1 1 + +2 3 +1 1 -1 +1 -1 2 + +2 3 +1 1 0 +1 -1 2 Index: contrib/isl/test_inputs/convex1.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex1.polylib @@ -0,0 +1,17 @@ +# {j,N | 0<=j<=N-1; 2<=N} +4 4 +1 1 0 0 +1 -1 1 -1 +1 0 1 -2 +1 0 0 1 +# {j, N | 1<=j<=N; 1<=N} +4 4 +1 1 0 -1 +1 -1 1 0 +1 0 1 -1 +1 0 0 1 +# {j,N | 0<=j<=N; 2<=j+N} +3 4 + 1 1 1 -2 + 1 1 0 0 + 1 -1 1 0 Index: contrib/isl/test_inputs/convex10.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex10.polylib @@ -0,0 +1,17 @@ +3 4 +1 54 1 -4 +1 2 -1 58 +1 0 -1 6 + +4 4 +1 54 1 -4 +1 2 -1 58 +1 0 1 -7 +1 -4 1 0 + +4 4 +1 54 1 -4 +1 2 -1 58 +1 0 -1 116 +1 0 0 1 + Index: contrib/isl/test_inputs/convex11.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex11.polylib @@ -0,0 +1,14 @@ +3 4 +1 0 -1 6 +1 -1 1 1 +1 1 1 -10 + +3 4 +1 1 0 -4 +1 -1 -1 8 +1 -1 1 1 + +3 4 +1 0 -1 6 +1 1 0 -4 +1 -1 1 1 Index: contrib/isl/test_inputs/convex12.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex12.polylib @@ -0,0 +1,12 @@ +3 5 +1 0 0 1 1 +1 0 1 0 1 +1 -1 -1 0 -2 + +3 5 +1 0 0 1 2 +1 1 -1 0 0 +1 1 0 0 -1 + +1 5 +1 0 0 1 2 Index: contrib/isl/test_inputs/convex13.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex13.polylib @@ -0,0 +1,17 @@ +3 5 +1 0 0 -1 3 +1 0 -1 0 2 +1 1 1 1 -4 + +3 5 +1 0 0 1 0 +1 1 0 0 -1 +1 1 2 0 1 + +6 5 +1 3 2 0 -1 +1 3 0 2 -3 +1 1 0 1 -1 +1 1 1 1 0 +1 1 1 0 0 +1 1 0 0 1 Index: contrib/isl/test_inputs/convex14.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex14.polylib @@ -0,0 +1,14 @@ +3 4 +0 1 0 2 +1 0 1 0 +1 0 -1 2 + +3 4 +1 1 0 0 +1 0 1 0 +1 0 -1 2 + +3 4 +1 1 0 2 +1 0 1 0 +1 0 -1 2 Index: contrib/isl/test_inputs/convex15.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex15.polylib @@ -0,0 +1,66 @@ +17 8 +1 -1 -8 0 16 0 0 37 +1 1 0 -48 0 2 0 -3 +1 0 -16 -32 16 1 0 14 +1 -1 24 0 0 1 0 18 +1 -1 8 16 0 0 1 21 +1 0 0 -16 0 1 1 -2 +1 1 32 16 -32 0 0 -1 +1 -1 16 16 0 0 0 28 +1 1 -8 -32 0 1 0 -1 +1 0 0 0 0 1 0 -1 +1 0 16 16 -16 0 1 -1 +1 1 8 0 -16 0 0 0 +1 0 3 2 -2 0 0 0 +1 0 1 2 -1 0 0 0 +1 0 -1 -1 1 0 0 0 +1 -1 8 0 0 1 2 4 +1 -1 -24 -32 32 1 0 36 + +13 8 +1 -1 0 0 0 1 3 -4 +1 1 0 -48 0 2 0 -2 +1 0 0 0 0 1 0 -1 +1 0 -8 0 0 0 1 -1 +1 0 3 2 -2 0 0 0 +1 1 -16 -16 0 0 0 0 +1 1 -24 0 0 0 0 0 +1 0 1 0 0 0 0 0 +1 0 -3 -2 2 0 0 1 +1 -1 0 16 0 0 2 13 +1 -1 24 0 0 1 0 20 +1 -1 16 16 0 0 0 29 +1 -1 0 48 0 0 0 45 + +31 8 + 1 0 1 0 0 0 0 0 + 1 0 0 -16 0 1 1 -2 + 1 0 0 0 0 1 0 -1 + 1 -1 8 0 0 1 2 4 + 1 0 3 2 -2 0 0 0 + 1 -1 24 0 0 1 0 20 + 1 1 0 -48 0 2 0 -2 + 1 -1 -24 -32 32 1 0 36 + 1 0 0 0 0 0 1 -1 + 1 -1 24 64 -16 0 0 45 + 1 -15 120 112 0 15 38 52 + 1 1 24 32 -32 0 0 0 + 1 0 -2 -2 2 0 0 1 + 1 -1 8 16 0 0 1 21 + 1 -15 120 352 0 0 23 307 + 1 1 -8 -32 0 1 0 -1 + 1 1 -8 0 0 0 0 0 + 1 1 -8 -16 0 0 0 0 + 1 0 16 16 -16 0 1 -1 + 1 -1 16 16 0 0 0 29 + 1 -1 -8 0 16 0 0 37 + 1 -1 8 32 0 0 0 37 + 1 1 8 0 -16 0 0 0 + 1 -15 360 592 -240 0 23 307 + 1 -1 -6 2 14 0 2 20 + 1 -15 360 352 -240 15 38 52 + 1 -1 8 48 0 0 0 45 + 1 0 -16 -32 16 1 0 14 + 1 -1 -6 -14 14 1 3 3 + 1 1 -38 -78 30 2 0 13 + 1 1 -3 -50 2 2 0 -1 Index: contrib/isl/test_inputs/convex2.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex2.polylib @@ -0,0 +1,24 @@ +# {i,j,N | 1<=i<=N; 0<=j<=N-1; 2<=N} +6 5 +1 1 0 0 -1 +1 -1 0 1 0 +1 0 1 0 0 +1 0 -1 1 -1 +1 0 0 1 -2 +1 0 0 0 1 +# {i,j,N | 1<=i<=N; 1<=j<=N; 2<=N} +6 5 +1 1 0 0 -1 +1 -1 0 1 0 +1 0 1 0 -1 +1 0 -1 1 0 +1 0 0 1 -2 +1 0 0 0 1 +# {i,j,N | 1<=i<=N; 0<=j<=N; 2<=N} +6 5 + 1 0 0 1 -2 + 1 -1 0 1 0 + 1 0 -1 1 0 + 1 1 0 0 -1 + 1 0 1 0 0 + 1 0 0 0 1 Index: contrib/isl/test_inputs/convex3.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex3.polylib @@ -0,0 +1,10 @@ +1 4 +1 1 1 -6 + +3 4 +1 1 1 -3 +1 1 0 -5 +1 -1 0 10 + +1 4 +1 1 1 -3 Index: contrib/isl/test_inputs/convex4.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex4.polylib @@ -0,0 +1,9 @@ +1 4 +1 1 1 -6 + +2 4 +0 1 0 -1 +0 0 1 -4 + +1 4 +1 1 1 -5 Index: contrib/isl/test_inputs/convex5.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex5.polylib @@ -0,0 +1,12 @@ +2 4 +0 1 0 -2 +0 0 1 -6 + +2 4 +0 1 0 -1 +0 0 1 -4 + +3 4 +0 -2 1 -2 +1 1 0 -1 +1 -1 0 2 Index: contrib/isl/test_inputs/convex6.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex6.polylib @@ -0,0 +1,17 @@ +3 4 +1 1 1 -2 +1 -1 1 2 +1 0 -1 2 + +3 4 +1 0 1 -1 +1 1 -1 1 +1 -1 -1 5 + +6 4 +1 -1 0 4 +1 1 0 0 +1 1 2 -2 +1 -1 2 2 +1 1 -2 4 +1 -1 -2 8 Index: contrib/isl/test_inputs/convex7.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex7.polylib @@ -0,0 +1,9 @@ +1 4 +0 0 1 0 + +2 4 +1 1 -1 1 +1 -1 -1 1 + +1 4 +1 0 -1 1 Index: contrib/isl/test_inputs/convex8.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex8.polylib @@ -0,0 +1,24 @@ +4 5 +1 1 1 1 0 +1 0 -1 0 0 +1 -1 0 0 2 +1 1 1 -1 0 + +4 5 +1 -1 1 0 2 +1 1 -2 -2 -1 +1 -1 0 2 3 +1 1 0 0 -1 + +10 5 +1 1 0 1 0 +1 1 1 0 0 +1 0 1 1 2 +1 -3 1 -1 8 +1 -3 1 1 8 +1 0 1 -1 2 +1 1 0 -1 0 +1 1 -2 -1 0 +1 -1 -3 2 6 +1 1 -5 -2 2 + Index: contrib/isl/test_inputs/convex9.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/convex9.polylib @@ -0,0 +1,14 @@ +4 4 +1 1 0 0 +1 -1 0 1 +1 0 1 0 +1 0 -1 10 + +2 4 +1 1 0 -10 +0 0 -1 5 + +3 4 +1 1 0 0 +1 0 1 0 +1 0 -1 10 Index: contrib/isl/test_inputs/devos.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/devos.pwqp @@ -0,0 +1 @@ +[U] -> { [i0] -> ((1/3 * U + 2/3 * i0) - [(U + 2i0)/3]) : 2i0 >= -3 - U and 2i0 <= -U and U >= 0 and U <= 10 } Index: contrib/isl/test_inputs/equality1.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/equality1.pwqp @@ -0,0 +1 @@ +[n] -> { [x] -> 1 + [(x+1)/3] : exists a : x = 3a +1 && 0 <= x <= n } Index: contrib/isl/test_inputs/equality2.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/equality2.pwqp @@ -0,0 +1 @@ +[n] -> { [x,y] -> x^2 * y : n = 2x + 4y and 0 <= x,y <= 10 } Index: contrib/isl/test_inputs/equality3.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/equality3.pwqp @@ -0,0 +1 @@ +[m,n] -> { [x,y] -> x^2 * y : n = 2x + 4y and 0 <= x,y <= 10 and 3 n = 5 m } Index: contrib/isl/test_inputs/equality4.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/equality4.pwqp @@ -0,0 +1 @@ +[m,n] -> { [x,y] -> x^2 * y + m + 13 * n: n = 2x + 4y and 0 <= x,y <= 10 and 3 n = 5 m } Index: contrib/isl/test_inputs/equality5.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/equality5.pwqp @@ -0,0 +1 @@ +[m,n] -> { [x,y,z] -> x^2 * y + z + m + 13 * n: n = 2x + 4y and 0 <= x,y <= 10 and 3 n = 5 m and z = x + y } Index: contrib/isl/test_inputs/esced.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/esced.pip @@ -0,0 +1,27 @@ +0 2 + +-1 + +16 18 +1 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 + + +0 0 0 0 -1 0 0 0 0 1 -1 0 0 0 0 0 0 0 +0 0 0 0 0 -1 0 0 0 0 0 1 0 0 0 0 0 0 + +0 -1 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 + +0 0 0 0 0 0 -1 0 0 0 0 0 1 -1 0 -1 0 0 +0 0 0 0 0 0 0 -1 0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 1 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 +0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 + +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 +1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 Index: contrib/isl/test_inputs/ex.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/ex.pip @@ -0,0 +1,9 @@ +1 5 +1 -1 1 1 0 + +-1 + +3 7 +1 0 -1 0 1 0 0 +1 -1 0 0 0 1 0 +1 1 1 -1 0 0 0 Index: contrib/isl/test_inputs/ex2.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/ex2.pip @@ -0,0 +1,9 @@ +1 5 +1 -1 1 1 0 + +-1 + +3 7 +1 0 -1 0 1 0 0 +1 -1 0 0 0 1 0 +1 1 1 -1 0 0 0 Index: contrib/isl/test_inputs/exist.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/exist.pip @@ -0,0 +1,5 @@ +[n] -> { : n mod 2 = 0 } + +-1 + +[n] -> { [i] : n <= i } Index: contrib/isl/test_inputs/exist2.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/exist2.pip @@ -0,0 +1,5 @@ +[n, a, b] -> { : exists e : 1 <= a <= 7e and 9e <= b <= n } + +-1 + +[n, a, b] -> { [i] : n <= 2i } Index: contrib/isl/test_inputs/faddeev.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/faddeev.pwqp @@ -0,0 +1 @@ +[N] -> { [i, j, k] -> (((4 + 6 * N + 2 * N^2) + (-2 - 2 * N) * j) + ((-2 - N) + j) * k) : j = 1 + i and k = 1 + i and i >= 3 and N <= 100 and i <= N and N >= 10 } Index: contrib/isl/test_inputs/fimmel.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/fimmel.pip @@ -0,0 +1,12 @@ +0 4 + +-1 + +7 6 +1 2 6 0 0 -9 +1 5 -3 0 0 0 +1 2 -10 0 0 15 +1 -2 6 0 0 -3 +1 -2 -6 0 0 17 +1 0 1 -1 0 0 +1 1 0 0 -1 0 Index: contrib/isl/test_inputs/flow/kill_loop-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop-tree.ai @@ -0,0 +1,11 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[i] -> a[] : 0 <= i <= 9 }" +kill: "{ T[9] -> a[] }" +schedule: + domain: "{ T[i]; S[] }" + child: + sequence: + - filter: "{ T[i] }" + child: + schedule: "[{ T[i] -> [(i)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/kill_loop-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_loop.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +must_source: { T[i] -> a[] : 0 <= i < 10 } +kill: { T[9] -> a[] } +schedule_map: { T[i] -> [0,i]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/kill_loop.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop.flow @@ -0,0 +1,4 @@ +must_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_loop2-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop2-tree.ai @@ -0,0 +1,11 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[i] -> a[] : 0 <= i <= 9 }" +kill: "{ K[] -> a[] }" +schedule: + domain: "{ T[i]; S[]; K[] }" + child: + sequence: + - filter: "{ T[i]; K[] }" + child: + schedule: "[{ T[i] -> [(i)]; K[] -> [(10)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/kill_loop2-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop2-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_loop2.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop2.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +must_source: { T[i] -> a[] : 0 <= i < 10 } +kill: { K[] -> a[] } +schedule_map: { T[i] -> [0,i]; K[] -> [0,10]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/kill_loop2.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop2.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_loop3-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop3-tree.ai @@ -0,0 +1,11 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[i] -> a[] : 0 <= i <= 9 }" +kill: "{ K[] -> a[] }" +schedule: + domain: "{ T[i]; S[]; K[] }" + child: + sequence: + - filter: "{ T[i]; K[] }" + child: + schedule: "[{ T[i] -> [(i)]; K[] -> [(9)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/kill_loop3-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop3-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_loop3.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop3.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +must_source: { T[i] -> a[] : 0 <= i < 10 } +kill: { K[] -> a[] } +schedule_map: { T[i] -> [0,i]; K[] -> [0,9]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/kill_loop3.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_loop3.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_may_loop-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop-tree.ai @@ -0,0 +1,11 @@ +sink: "{ S[] -> a[] }" +may_source: "{ T[i] -> a[] : 0 <= i <= 9 }" +kill: "{ T[4] -> a[] }" +schedule: + domain: "{ T[i]; S[] }" + child: + sequence: + - filter: "{ T[i] }" + child: + schedule: "[{ T[i] -> [(i)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/kill_may_loop-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i] -> [S[] -> a[]] : 4 <= i <= 9 }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_may_loop.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +may_source: { T[i] -> a[] : 0 <= i < 10 } +kill: { T[4] -> a[] } +schedule_map: { T[i] -> [0,i]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/kill_may_loop.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i] -> [S[] -> a[]] : 4 <= i <= 9 }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_may_loop2-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop2-tree.ai @@ -0,0 +1,11 @@ +sink: "{ S[] -> a[] }" +may_source: "{ T[i] -> a[] : 0 <= i <= 9 }" +kill: "{ T[9] -> a[] }" +schedule: + domain: "{ T[i]; S[] }" + child: + sequence: + - filter: "{ T[i] }" + child: + schedule: "[{ T[i] -> [(i)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/kill_may_loop2-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop2-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_may_loop2.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop2.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +may_source: { T[i] -> a[] : 0 <= i < 10 } +kill: { T[9] -> a[] } +schedule_map: { T[i] -> [0,i]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/kill_may_loop2.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop2.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_may_loop3-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop3-tree.ai @@ -0,0 +1,11 @@ +sink: "{ S[] -> a[] }" +may_source: "{ T[i] -> a[] : 0 <= i <= 9 }" +kill: "{ K[] -> a[] }" +schedule: + domain: "{ T[i]; S[]; K[] }" + child: + sequence: + - filter: "{ T[i]; K[] }" + child: + schedule: "[{ T[i] -> [(i)]; K[] -> [(4)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/kill_may_loop3-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop3-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i] -> [S[] -> a[]] : 4 <= i <= 9 }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/kill_may_loop3.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop3.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +may_source: { T[i] -> a[] : 0 <= i < 10 } +kill: { K[] -> a[] } +schedule_map: { T[i] -> [0,i]; K[] -> [0,4]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/kill_may_loop3.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/kill_may_loop3.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i] -> [S[] -> a[]] : 4 <= i <= 9 }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/loop-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/loop-tree.ai @@ -0,0 +1,10 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[i] -> a[] : 0 <= i <= 9 }" +schedule: + domain: "{ T[i]; S[] }" + child: + sequence: + - filter: "{ T[i] }" + child: + schedule: "[{ T[i] -> [(i)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/loop-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/loop-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/loop.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/loop.ai @@ -0,0 +1,3 @@ +sink: { S[] -> a[] } +must_source: { T[i] -> a[] : 0 <= i < 10 } +schedule_map: { T[i] -> [0,i]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/loop.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/loop.flow @@ -0,0 +1,4 @@ +must_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/may_loop-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/may_loop-tree.ai @@ -0,0 +1,10 @@ +sink: "{ S[] -> a[] }" +may_source: "{ T[i] -> a[] : 0 <= i <= 9 }" +schedule: + domain: "{ T[i]; S[] }" + child: + sequence: + - filter: "{ T[i] }" + child: + schedule: "[{ T[i] -> [(i)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/may_loop-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/may_loop-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i] -> [S[] -> a[]] : 0 <= i <= 9 }" +must_no_source: "{ }" +may_no_source: "{ S[] -> a[] }" Index: contrib/isl/test_inputs/flow/may_loop.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/may_loop.ai @@ -0,0 +1,3 @@ +sink: { S[] -> a[] } +may_source: { T[i] -> a[] : 0 <= i < 10 } +schedule_map: { T[i] -> [0,i]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/may_loop.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/may_loop.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i] -> [S[] -> a[]] : 0 <= i <= 9 }" +must_no_source: "{ }" +may_no_source: "{ S[] -> a[] }" Index: contrib/isl/test_inputs/flow/mixed_loop-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/mixed_loop-tree.ai @@ -0,0 +1,11 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[i] -> a[] : 2*floor((i)/2) = i and 0 <= i <= 9 }" +may_source: "{ T[i] -> a[] : 2*floor((1 + i)/2) = 1 + i and 0 <= i <= 9 }" +schedule: + domain: "{ T[i]; S[] }" + child: + sequence: + - filter: "{ T[i] }" + child: + schedule: "[{ T[i] -> [(i)] }]" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/mixed_loop-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/mixed_loop-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]]; T[i = 8] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/mixed_loop.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/mixed_loop.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +must_source: { T[i] -> a[] : 0 <= i < 10 and i mod 2 = 0 } +may_source: { T[i] -> a[] : 0 <= i < 10 and i mod 2 = 1 } +schedule_map: { T[i] -> [0,i]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/mixed_loop.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/mixed_loop.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[i = 9] -> [S[] -> a[]]; T[i = 8] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi.ai @@ -0,0 +1,10 @@ +sink: "{ [S_2[] -> __pet_ref_4[]] -> a[] }" +must_source: "{ [S_0[] -> __pet_ref_0[]] -> a[]; [S_2[] -> __pet_ref_3[]] -> b[]; [S_1[] -> __pet_ref_1[]] -> a[]; [S_1[] -> __pet_ref_2[]] -> a[] }" +may_source: "{ [S_1[] -> __pet_ref_2[]] -> a[]; [S_1[] -> __pet_ref_1[]] -> a[]; [S_2[] -> __pet_ref_3[]] -> b[]; [S_0[] -> __pet_ref_0[]] -> a[] }" +schedule: + domain: "{ [S_1[] -> __pet_ref_1[]]; [S_1[] -> __pet_ref_2[]]; [S_2[] -> __pet_ref_3[]]; [S_0[] -> __pet_ref_0[]]; [S_2[] -> __pet_ref_4[]] }" + child: + sequence: + - filter: "{ [S_0[] -> __pet_ref_0[]] }" + - filter: "{ [S_1[] -> __pet_ref_1[]]; [S_1[] -> __pet_ref_2[]] }" + - filter: "{ [S_2[] -> __pet_ref_3[]]; [S_2[] -> __pet_ref_4[]] }" Index: contrib/isl/test_inputs/flow/multi.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ [S_1[] -> __pet_ref_2[]] -> [[S_2[] -> __pet_ref_4[]] -> a[]]; [S_1[] -> __pet_ref_1[]] -> [[S_2[] -> __pet_ref_4[]] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi_source-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source-tree.ai @@ -0,0 +1,8 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[] -> a[]; U[] -> a[] }" +schedule: + domain: "{ U[]; S[]; T[] }" + child: + sequence: + - filter: "{ T[]; U[] }" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/multi_source-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi_source.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source.ai @@ -0,0 +1,3 @@ +sink: { S[] -> a[] } +must_source: { T[] -> a[]; U[] -> a[] } +schedule_map: { T[] -> [0]; U[] -> [0]; S[] -> [1] } Index: contrib/isl/test_inputs/flow/multi_source.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi_source2-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source2-tree.ai @@ -0,0 +1,9 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[] -> a[] }" +may_source: "{ U[] -> a[] }" +schedule: + domain: "{ U[]; S[]; T[] }" + child: + sequence: + - filter: "{ T[]; U[] }" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/multi_source2-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source2-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi_source2.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source2.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +must_source: { T[] -> a[] } +may_source: { U[] -> a[] } +schedule_map: { T[] -> [0]; U[] -> [0]; S[] -> [1] } Index: contrib/isl/test_inputs/flow/multi_source2.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source2.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi_source3-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source3-tree.ai @@ -0,0 +1,13 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[] -> a[]; U[] -> a[] }" +may_source: "{ V[] -> a[] }" +schedule: + domain: "{ S[]; U[]; T[]; V[] }" + child: + sequence: + - filter: "{ U[]; T[]; V[] }" + child: + sequence: + - filter: "{ T[]; U[] }" + - filter: "{ V[] }" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/multi_source3-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source3-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]]; V[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi_source3.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source3.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +must_source: { T[] -> a[]; U[] -> a[] } +may_source: { V[] -> a[] } +schedule_map: { T[] -> [0,0]; U[] -> [0,0]; V[] -> [0,1]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/multi_source3.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source3.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]]; V[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi_source4-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source4-tree.ai @@ -0,0 +1,13 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[] -> a[]; U[] -> a[] }" +may_source: "{ V[] -> a[] }" +schedule: + domain: "{ S[]; U[]; T[]; V[] }" + child: + sequence: + - filter: "{ U[]; T[]; V[] }" + child: + sequence: + - filter: "{ U[] }" + - filter: "{ V[]; T[] }" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/multi_source4-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source4-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]]; V[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/multi_source4.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source4.ai @@ -0,0 +1,4 @@ +sink: { S[] -> a[] } +must_source: { T[] -> a[]; U[] -> a[] } +may_source: { V[] -> a[] } +schedule_map: { T[] -> [0,1]; U[] -> [0,0]; V[] -> [0,1]; S[] -> [1,0] } Index: contrib/isl/test_inputs/flow/multi_source4.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/multi_source4.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]]; V[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/no_source-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/no_source-tree.ai @@ -0,0 +1,3 @@ +sink: "{ S[] -> a[] }" +schedule: + domain: "{ S[] }" Index: contrib/isl/test_inputs/flow/no_source-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/no_source-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ }" +must_no_source: "{ S[] -> a[] }" +may_no_source: "{ S[] -> a[] }" Index: contrib/isl/test_inputs/flow/no_source.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/no_source.ai @@ -0,0 +1,2 @@ +sink: { S[] -> a[] } +schedule_map: { S[] -> [] } Index: contrib/isl/test_inputs/flow/no_source.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/no_source.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ }" +must_no_source: "{ S[] -> a[] }" +may_no_source: "{ S[] -> a[] }" Index: contrib/isl/test_inputs/flow/no_source2-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/no_source2-tree.ai @@ -0,0 +1,8 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[] -> a[] }" +schedule: + domain: "{ S[]; T[] }" + child: + sequence: + - filter: "{ S[] }" + - filter: "{ T[] }" Index: contrib/isl/test_inputs/flow/no_source2-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/no_source2-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ }" +must_no_source: "{ S[] -> a[] }" +may_no_source: "{ S[] -> a[] }" Index: contrib/isl/test_inputs/flow/no_source2.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/no_source2.ai @@ -0,0 +1,3 @@ +sink: { S[] -> a[] } +must_source: { T[] -> a[] } +schedule_map: { T[] -> [1]; S[] -> [0] } Index: contrib/isl/test_inputs/flow/no_source2.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/no_source2.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ }" +must_no_source: "{ S[] -> a[] }" +may_no_source: "{ S[] -> a[] }" Index: contrib/isl/test_inputs/flow/single_may_source-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/single_may_source-tree.ai @@ -0,0 +1,8 @@ +sink: "{ S[] -> a[] }" +may_source: "{ T[] -> a[] }" +schedule: + domain: "{ S[]; T[] }" + child: + sequence: + - filter: "{ T[] }" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/single_may_source-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/single_may_source-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ S[] -> a[] }" Index: contrib/isl/test_inputs/flow/single_may_source.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/single_may_source.ai @@ -0,0 +1,3 @@ +sink: { S[] -> a[] } +may_source: { T[] -> a[] } +schedule_map: { T[] -> [0]; S[] -> [1] } Index: contrib/isl/test_inputs/flow/single_may_source.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/single_may_source.flow @@ -0,0 +1,4 @@ +must_dependence: "{ }" +may_dependence: "{ T[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ S[] -> a[] }" Index: contrib/isl/test_inputs/flow/single_source-tree.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/single_source-tree.ai @@ -0,0 +1,8 @@ +sink: "{ S[] -> a[] }" +must_source: "{ T[] -> a[] }" +schedule: + domain: "{ S[]; T[] }" + child: + sequence: + - filter: "{ T[] }" + - filter: "{ S[] }" Index: contrib/isl/test_inputs/flow/single_source-tree.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/single_source-tree.flow @@ -0,0 +1,4 @@ +must_dependence: "{ T[] -> [S[] -> a[]] }" +may_dependence: "{ T[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/flow/single_source.ai =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/single_source.ai @@ -0,0 +1,3 @@ +sink: { S[] -> a[] } +must_source: { T[] -> a[] } +schedule_map: { T[] -> [0]; S[] -> [1] } Index: contrib/isl/test_inputs/flow/single_source.flow =================================================================== --- /dev/null +++ contrib/isl/test_inputs/flow/single_source.flow @@ -0,0 +1,4 @@ +must_dependence: "{ T[] -> [S[] -> a[]] }" +may_dependence: "{ T[] -> [S[] -> a[]] }" +must_no_source: "{ }" +may_no_source: "{ }" Index: contrib/isl/test_inputs/gist1.polylib =================================================================== --- /dev/null +++ contrib/isl/test_inputs/gist1.polylib @@ -0,0 +1,14 @@ +4 5 +0 1 0 0 -1 +0 0 1 0 1 +0 0 0 1 -3 +1 0 0 0 1 + +4 5 +0 1 0 0 -1 +0 0 1 1 -2 +1 0 0 1 0 +1 0 0 -1 3 + +1 5 +0 0 1 0 1 Index: contrib/isl/test_inputs/linearExample.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/linearExample.pwqp @@ -0,0 +1 @@ +[N, M, L] -> { [i, j, k] -> ((1/2 * i + 5 * j) + 1/7 * k) : i >= 0 and k >= -N + i and k >= -M - j and j <= L + i and L >= 0 and L >= -M } Index: contrib/isl/test_inputs/max.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/max.pip @@ -0,0 +1,9 @@ +0 3 + +-1 + +4 5 +1 -1 0 1 0 +1 0 -1 1 0 +1 -1 3 -2 12 +1 2 -1 -1 3 Index: contrib/isl/test_inputs/neg.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/neg.pwqp @@ -0,0 +1 @@ +[n] -> { [i0] -> i0^2 : i0 >= -20 - n and i0 <= n and i0 <= -1 and n >= 0 } Index: contrib/isl/test_inputs/negative.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/negative.pip @@ -0,0 +1,9 @@ +1 3 +# n 1 +1 1 -1 # n >= 1 +-1 + +2 4 +# i n 1 +1 1 0 1 # i >= -1 +1 -1 1 0 # i <= n Index: contrib/isl/test_inputs/philippe.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/philippe.pwqp @@ -0,0 +1 @@ +[N] -> { [i, j] -> ((1/2 * i + 1/2 * i^2) + j) : i <= N and j >= 0 and j <= i } Index: contrib/isl/test_inputs/philippe3vars.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/philippe3vars.pwqp @@ -0,0 +1 @@ +[N] -> { [i, j, k] -> (((1/2 * i + 1/2 * i^2) + j) + k^3) : i >= 0 and k >= -N + i and k >= -j and j <= i } Index: contrib/isl/test_inputs/philippe3vars3pars.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/philippe3vars3pars.pwqp @@ -0,0 +1 @@ +[N, M, L] -> { [i, j, k] -> (((1/2 * i + 1/2 * i^2) + j) + k^3) : i >= 0 and k >= -N + i and k >= -M - j and j <= L + i and L >= 0 and L >= -M } Index: contrib/isl/test_inputs/philippeNeg.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/philippeNeg.pwqp @@ -0,0 +1 @@ +[N] -> { [i, j] -> ((1/2 * i + 1/2 * i^2) + j) : i <= N and j >= -1 and j <= i } Index: contrib/isl/test_inputs/philippePolynomialCoeff.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/philippePolynomialCoeff.pwqp @@ -0,0 +1 @@ +[N, M] -> { [i, j] -> ((N * i + (1/5 * N + N^2) * i^2) + 5 * j) : i <= N and j >= 0 and j <= i and M >= 0 } Index: contrib/isl/test_inputs/philippePolynomialCoeff1P.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/philippePolynomialCoeff1P.pwqp @@ -0,0 +1 @@ +[N] -> { [i, j] -> ((N * i + (1/5 * N + N^2) * i^2) + 5 * j) : i <= N and j >= 0 and j <= i } Index: contrib/isl/test_inputs/product.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/product.pwqp @@ -0,0 +1 @@ +[N] -> { [i0, i1, i2] -> (i0^3 * i1^2 + N * i1 * i2) : i0 >= 0 and i0 <= N and i1 >= 0 and i1 <= N and i2 >= 0 and i2 <= N } Index: contrib/isl/test_inputs/schedule/disjunctive_domain.sc =================================================================== --- /dev/null +++ contrib/isl/test_inputs/schedule/disjunctive_domain.sc @@ -0,0 +1,4 @@ +# Check that the size computation used for loop coalescing avoidance +# does not get confused by disjunctive domains. +domain: [N] -> { S_9[k, i, j = k] : 0 < k <= -3 + N and k < i < N; S_9[k, k, j] : 0 < k <= -3 + N and k <= j < N; S_9[-2 + N, i, j] : N >= 3 and -2 + N <= i < N and -2 + N <= j < N } +validity: [N] -> { S_9[k, 1 + N, j] -> S_9[1 + k, -1 + N, j'] : 0 < k <= -3 + N and j < N and j' > k and -1 + j <= j' <= j; S_9[-2 + N, i, -2 + N] -> S_9[-2 + N, i, -1 + N] : N >= 3 and -2 + N <= i < N} Index: contrib/isl/test_inputs/schedule/disjunctive_domain.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/schedule/disjunctive_domain.st @@ -0,0 +1,5 @@ +domain: "[N] -> { S_9[k, i, j = k] : 0 < k <= -3 + N and k < i < N; S_9[k, i = k, j] : 0 < k <= -3 + N and k <= j < N; S_9[k = -2 + N, i, j] : N >= 3 and -2 + N <= i < N and -2 + N <= j < N }" +child: + schedule: "[N] -> [{ S_9[k, i, j] -> [(k)] }, { S_9[k, i, j] -> [(2k + i)] }, { S_9[k, i, j] -> [(k + j)] }]" + permutable: 1 + coincident: [ 1, 1, 1 ] Index: contrib/isl/test_inputs/schedule/feautrier_compressed.sc =================================================================== --- /dev/null +++ contrib/isl/test_inputs/schedule/feautrier_compressed.sc @@ -0,0 +1,5 @@ +# Check that the Feautrier schedule is not confused by +# compressed nodes in a subgraph of the original dependence graph. +# OPTIONS: --schedule-algorithm=feautrier +domain: { A[]; B[0]; C[] } +validity: { A[] -> B[0] } Index: contrib/isl/test_inputs/schedule/feautrier_compressed.st =================================================================== --- /dev/null +++ contrib/isl/test_inputs/schedule/feautrier_compressed.st @@ -0,0 +1,7 @@ +domain: "{ B[0]; C[]; A[] }" +child: + set: + - filter: "{ B[i0]; A[] }" + child: + schedule: "[{ B[i0] -> [(1)]; A[] -> [(0)] }]" + - filter: "{ C[] }" Index: contrib/isl/test_inputs/seghir-vd.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/seghir-vd.pip @@ -0,0 +1,17 @@ +0 6 + +-1 + +9 8 + 0 0 0 1 1 0 0 2 + 1 2 1 0 0 1 0 0 + 1 0 1 0 -1 0 0 -1 + 1 -2 -1 0 0 0 0 -1 + 1 7 3 0 0 0 0 -1 + 1 -6 -4 0 1 0 3 1 + 1 -7 -3 0 0 1 6 4 + 1 0 0 0 0 0 1 0 + 1 0 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/test_inputs/set.omega =================================================================== --- /dev/null +++ contrib/isl/test_inputs/set.omega @@ -0,0 +1 @@ +{[y]: Exists ( alpha : 2alpha = y)} Index: contrib/isl/test_inputs/small.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/small.pip @@ -0,0 +1,9 @@ +0 2 + +-1 + +4 4 +1 1 0 0 +1 0 1 0 +1 1 -3 12 +1 -2 1 3 Index: contrib/isl/test_inputs/sor1d.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/sor1d.pip @@ -0,0 +1,28 @@ +2 4 + 1 1 0 0 + 1 0 1 0 + +-1 + +20 8 + + 0 -1 0 0 0 0 0 2 + 0 0 -1 0 0 0 0 1 + 0 0 0 -1 0 0 0 2 + 0 0 0 0 -1 0 0 4 + 1 0 0 0 1 0 0 -2 + 1 -2 0 2 1 0 0 -4 + 1 0 0 0 -1 0 1 -1 + 1 2 0 -2 -1 0 0 5 + 1 0 0 1 0 0 0 -1 + 1 0 -2 1 0 0 0 0 + 1 -2 0 2 0 0 1 -5 + 1 0 0 -1 0 1 0 0 + 1 0 2 -1 0 0 0 1 + 1 2 0 -2 0 0 0 3 + 1 0 1 0 0 0 0 0 + 1 -2 4 0 0 0 1 -3 + 1 0 -2 0 0 1 0 0 + 1 2 -4 0 0 0 0 3 + 1 2 0 0 0 0 0 1 + 1 -2 0 0 0 2 1 -5 Index: contrib/isl/test_inputs/split.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/split.pwqp @@ -0,0 +1 @@ +[n] -> { [x] -> -1 + [(x+5)/7] : -n - 20 <= x <= n } Index: contrib/isl/test_inputs/square.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/square.pip @@ -0,0 +1,9 @@ +0 3 + +-1 + +4 5 +1 1 0 0 0 +1 -1 0 1 0 +1 0 1 0 0 +1 0 -1 1 0 Index: contrib/isl/test_inputs/sven.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/sven.pip @@ -0,0 +1,7 @@ +0 3 + +-1 + +2 3 +1 1 -4 +1 -1 10 Index: contrib/isl/test_inputs/test3Deg3Var.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/test3Deg3Var.pwqp @@ -0,0 +1 @@ +[p] -> { [n, m] -> (n + n^3) : n >= 1 and m >= n and m <= p } Index: contrib/isl/test_inputs/tobi.pip =================================================================== --- /dev/null +++ contrib/isl/test_inputs/tobi.pip @@ -0,0 +1,15 @@ +2 3 +1 1 -281 +1 -1 14000 + +-1 + +6 6 +0 -392 0 8 -1 0 +0 392 8 0 1 0 +1 -1 0 0 0 0 +1 1 0 0 0 35 +1 392 0 0 1 0 +1 -392 0 0 -1 280 + +Urs_unknowns Index: contrib/isl/test_inputs/toplas.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/toplas.pwqp @@ -0,0 +1 @@ +[n] -> { [i0, i1] -> (((4 * n - n^2) + (-3/2 + 2 * n) * i0 - 1/2 * i0^2) - i1) : i1 >= -1 + 3n - i0 and i1 >= -1 + 2n - i0 and i0 >= 0 and i1 <= -2 + 4n - i0 and i0 <= -2 + 4n and i0 <= -1 + 3n and i1 >= 0 and i1 <= -1 + n } Index: contrib/isl/test_inputs/unexpanded.pwqp =================================================================== --- /dev/null +++ contrib/isl/test_inputs/unexpanded.pwqp @@ -0,0 +1 @@ +{ [x, y] -> ((x - x^2) * y + (-x + x^2) * y^2) : x >= 0 and x <= 2 and y >= 0 and y <= 2 } Index: contrib/isl/testsets/pip/bouleti.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/bouleti.pip @@ -0,0 +1,30 @@ +1 8 +1 0 -1 1 0 0 0 -1 + +-1 + +24 17 +1 0 0 0 -1 0 0 0 0 0 1 -1 1 0 0 0 0 +1 0 0 0 0 0 0 -1 0 0 1 -1 1 0 0 0 0 +1 0 0 0 0 -1 0 0 0 0 1 -1 1 0 0 0 0 +1 0 0 0 0 0 0 0 -1 0 1 -1 1 0 0 0 0 +1 0 0 0 0 0 1 0 0 0 -1 1 0 -1 0 0 0 +1 -1 0 0 0 0 0 0 0 0 1 -1 0 1 0 0 0 +1 0 -1 0 0 0 0 0 0 0 1 -1 0 0 1 0 0 +1 0 0 1 0 0 0 0 0 0 -1 1 0 0 0 -1 -1 +1 0 0 0 1 0 0 0 0 0 -1 0 0 0 0 0 -1 +1 0 0 0 1 1 -1 0 0 0 -1 0 0 0 0 0 0 +1 0 0 -1 0 0 0 2 0 0 -1 0 0 0 0 0 0 +1 0 0 0 0 0 0 1 0 0 -1 0 0 0 0 0 -1 +1 0 0 0 0 0 0 1 1 -1 -1 0 0 0 0 0 0 +1 0 0 0 0 1 0 0 0 0 -1 0 0 0 0 0 -1 +1 0 0 0 0 0 0 0 1 0 -1 0 0 0 0 0 -1 +1 0 0 0 0 0 1 0 0 0 -1 0 0 0 0 0 -1 +1 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 -1 +1 1 1 0 0 0 0 0 0 0 -2 2 0 -1 -1 0 0 +1 0 0 0 2 0 0 0 0 0 -2 1 0 0 0 -1 0 +1 0 -1 0 0 0 0 0 4 3 -6 0 0 0 0 0 0 +1 0 0 0 0 4 3 0 0 0 -7 1 0 0 -1 0 0 +1 1 1 1 0 0 0 -2 -4 -4 7 0 0 0 0 0 0 +1 0 0 0 -2 -4 -4 0 0 0 10 -3 0 1 1 1 0 +1 -1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 Index: contrib/isl/testsets/pip/cnt_sum2.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/cnt_sum2.pip @@ -0,0 +1,54 @@ +0 20 + +-1 + +47 39 +1 0 0 0 0 0 0 1 0 0 0 0 1 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 1 0 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 -1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 -1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 -1 0 0 0 0 -1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 -1 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 -1 0 0 -1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 -1 -1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 1 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 -1 0 0 0 0 0 0 -1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 -1 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 -1 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 +1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 +1 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 +1 -1 20 20 20 20 20 20 20 20 20 20 20 30 10 10 10 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +Maximize Index: contrib/isl/testsets/pip/difficult.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/difficult.pip @@ -0,0 +1,14 @@ +0 5 + +-1 + +9 8 +0 -2 -3 -5 1 0 0 -4 +1 0 -1 0 0 2 0 3 +1 0 0 -1 0 1 0 0 +1 0 1 0 0 -1 0 0 +1 0 0 3 0 -1 2 0 +1 1 0 -1 0 0 0 5 +1 1 0 0 0 0 0 0 +1 -1 0 0 0 0 1 2 +1 0 0 1 0 0 0 -1 Index: contrib/isl/testsets/pip/jcomplex.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/jcomplex.pip @@ -0,0 +1,47 @@ +0 17 + +-1 + +40 33 +1 0 0 0 0 0 0 0 1 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 1 0 0 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 1 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 1 1 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 1 1 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 1 1 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 -1 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 -1 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 -1 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 -1 -1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 -1 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 -1 -1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 -1 -1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 -1 -1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 +1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 +1 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 +1 -1 30 20 20 20 20 20 40 10 10 10 10 10 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +Maximize Index: contrib/isl/testsets/pip/phideo.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/phideo.pip @@ -0,0 +1,35 @@ +4 4 +1 -1 0 8 +1 1 0 -1 +1 0 -1 128 +1 0 1 -1 + +-1 + +24 14 +1 0 1 2 4 8 16 32 64 128 256 0 3 574 +1 0 -1 -2 -4 -8 -16 -32 -64 -128 -256 0 -3 -574 +1 1 0 0 0 0 0 0 0 0 0 1 0 0 +1 -1 0 0 0 0 0 0 0 0 0 -1 0 0 +1 1 0 0 0 0 0 0 0 0 0 0 0 8 +1 -1 0 0 0 0 0 0 0 0 0 0 0 -1 +1 0 1 0 0 0 0 0 0 0 0 0 0 2 +1 0 -1 0 0 0 0 0 0 0 0 0 0 -1 +1 0 0 1 0 0 0 0 0 0 0 0 0 2 +1 0 0 -1 0 0 0 0 0 0 0 0 0 -1 +1 0 0 0 1 0 0 0 0 0 0 0 0 2 +1 0 0 0 -1 0 0 0 0 0 0 0 0 -1 +1 0 0 0 0 1 0 0 0 0 0 0 0 2 +1 0 0 0 0 -1 0 0 0 0 0 0 0 -1 +1 0 0 0 0 0 1 0 0 0 0 0 0 2 +1 0 0 0 0 0 -1 0 0 0 0 0 0 -1 +1 0 0 0 0 0 0 1 0 0 0 0 0 2 +1 0 0 0 0 0 0 -1 0 0 0 0 0 -1 +1 0 0 0 0 0 0 0 1 0 0 0 0 2 +1 0 0 0 0 0 0 0 -1 0 0 0 0 -1 +1 0 0 0 0 0 0 0 0 1 0 0 0 2 +1 0 0 0 0 0 0 0 0 -1 0 0 0 -1 +1 0 0 0 0 0 0 0 0 0 1 0 0 2 +1 0 0 0 0 0 0 0 0 0 -1 0 0 -1 + +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-e1.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-e1.pip @@ -0,0 +1,20 @@ +0 6 + +-1 + +12 8 + 0 0 0 1 0 1 0 -4 + 1 2 5 0 2 1 0 3 + 1 0 -1 0 1 0 0 0 + 1 -2 -5 0 -1 -1 0 0 + 1 0 3 0 -1 0 2 0 + 1 3 4 0 0 1 0 5 + 1 3 5 0 0 1 0 0 + 1 -3 -5 0 0 -1 1 2 + 1 0 1 0 0 0 0 -1 + 1 0 0 0 1 0 1 -2 + 1 0 0 0 1 0 0 -2 + 1 0 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-e3.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-e3.pip @@ -0,0 +1,17 @@ +0 6 + +-1 + +9 8 + 0 0 0 1 2 0 0 2 + 1 2 2 0 1 1 0 0 + 1 0 1 0 0 0 0 -1 + 1 -2 -2 0 -1 0 0 -1 + 1 7 6 0 3 0 0 -1 + 1 -6 -7 0 -3 0 3 1 + 1 -7 -6 0 -3 1 6 4 + 1 0 0 0 0 0 1 0 + 1 0 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-e4.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-e4.pip @@ -0,0 +1,18 @@ +0 5 + +-1 + +10 8 + 0 0 0 0 1 1 0 -1 + 1 7 -4 -10 0 -2 0 -1 + 1 -4 2 5 0 1 0 -1 + 1 4 -2 -5 0 -1 0 5 + 1 0 1 0 0 0 0 -1 + 1 0 -1 0 0 0 2 0 + 1 0 0 1 0 0 0 -1 + 1 0 0 -1 0 0 3 2 + 1 -98 56 140 0 28 1 1 + 1 0 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-e5.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-e5.pip @@ -0,0 +1,17 @@ +0 5 + +-1 + +9 7 + 0 0 0 1 1 0 -4 + 1 0 1 0 0 0 -1 + 1 0 1 0 0 1 0 + 1 2 -6 0 -1 0 0 + 1 -3 5 0 1 0 0 + 1 3 -5 0 -1 1 2 + 1 -2 11 0 1 4 3 + 1 -3 4 0 1 0 5 + 1 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-e6.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-e6.pip @@ -0,0 +1,17 @@ +0 5 + +-1 + +9 7 + 0 0 0 1 1 0 -4 + 1 2 4 0 1 0 0 + 1 -2 -3 0 -1 0 -1 + 1 5 6 0 2 0 0 + 1 -2 -3 0 -1 1 0 + 1 -5 -6 0 -2 1 2 + 1 -12 -19 0 -6 4 3 + 1 7 9 0 3 0 5 + 1 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-e7.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-e7.pip @@ -0,0 +1,17 @@ +0 6 + +-1 + +9 8 + 0 0 0 1 1 0 0 0 + 1 4 2 0 1 0 1 1 + 1 1 0 0 0 0 0 -1 + 1 -1 0 0 0 2 1 0 + 1 -15 -11 0 -5 1 0 2 + 1 -3 -2 0 -1 0 0 -5 + 1 3 3 0 1 0 0 0 + 1 0 0 0 0 2 1 -2 + 1 0 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-e8.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-e8.pip @@ -0,0 +1,19 @@ +0 5 + +-1 + +11 8 + 0 0 0 0 1 1 0 2 + 1 3 -4 -3 0 1 0 -1 + 1 0 0 -1 0 0 1 0 + 1 0 -1 0 0 0 1 0 + 1 -3 4 3 0 -1 1 0 + 1 2 -4 -3 0 1 1 0 + 1 0 1 0 0 0 0 -1 + 1 -2 4 3 0 -1 0 -1 + 1 0 0 1 0 0 0 -1 + 1 0 0 0 0 0 1 -2 + 1 0 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-e9.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-e9.pip @@ -0,0 +1,22 @@ +0 7 + +-1 + +14 10 + 0 0 0 0 1 0 1 0 0 2 + 0 0 0 0 0 1 1 1 0 0 + 1 -2 8 -5 0 0 1 -1 0 -1 + 1 2 -8 5 0 0 -1 1 1 0 + 1 3 -8 5 0 0 -1 1 0 -1 + 1 -3 8 -5 0 0 1 -1 1 0 + 1 1 -4 2 0 0 0 1 0 -1 + 1 -1 4 -2 0 0 0 -1 1 0 + 1 0 3 -2 0 0 0 -1 0 -1 + 1 0 -3 2 0 0 0 1 1 0 + 1 0 0 1 0 0 0 0 0 -1 + 1 0 0 -1 0 0 0 0 1 0 + 1 0 0 0 0 0 0 0 1 -2 + 1 0 0 0 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns Index: contrib/isl/testsets/pip/seghir-vd.pip =================================================================== --- /dev/null +++ contrib/isl/testsets/pip/seghir-vd.pip @@ -0,0 +1,17 @@ +0 6 + +-1 + +9 8 + 0 0 0 1 1 0 0 2 + 1 2 1 0 0 1 0 0 + 1 0 1 0 -1 0 0 -1 + 1 -2 -1 0 0 0 0 -1 + 1 7 3 0 0 0 0 -1 + 1 -6 -4 0 1 0 3 1 + 1 -7 -3 0 0 1 6 4 + 1 0 0 0 0 0 1 0 + 1 0 0 0 0 0 0 1 + +Urs_parms +Urs_unknowns